<?php
/*
Plugin Name: Gateway Relay
Plugin URI: http://premium.wpmudev.org/project/classifieds
Description: Forwards IPN from Paypal and Silent Posts from Authorizenet to multiple new urls based on a prefix in certain fields.
Version: 1.0
Author: Arnold Bailey (Incsub)
Author URI: http://premium.wpmudev.org
License: GNU General Public License (Version 2 - GPLv2)
Network: true
*/

/**
* You must include a prefix in one of the custom fields to forward it on correctly.
* Multiple url destinations per prefix can be registered.
*
* For Paypal 'PROFILEREFERENCE' (rp_invoice_id), 'custom','INVNUM' (invoice), 'item_number' (for subscriptions) will be checked in the IPN response.
*
* For Authorize Net 'x_invoice_num', 'x_po_num', 'x_cust_id' will be checked for the prefix.
*
* @register_gateway_relay($prefix, $url, $password) registers a prefix, the url to send to and a password you can use to authenticate. Duplicate combinations of the prefix and url are forbidden.
*
* @unregister_gateway_relay($prefix, $url, $password) removes a prefix, an url and password combination.
*/

if( ! defined('GATEWAY_RELAY_SETTINGS_NAME') ):

define('GATEWAY_RELAY_SETTINGS_NAME', 'gr_settings' );
define('GATEWAY_RELAY_QUEUE_NAME', 'gr_queue' );

class Gateway_Relay{

	const PAYPAL_LIVE = "https://www.paypal.com/cgi-bin/webscr";
	const PAYPAL_SANDBOX = "https://www.sandbox.paypal.com/cgi-bin/webscr";

	public $settings = null;
	public $settings_name = GATEWAY_RELAY_SETTINGS_NAME;

	public $queue = null;
	public $queue_name = GATEWAY_RELAY_QUEUE_NAME;

	public $postdata = '';
	public $source = '';

	function __construct(){

		add_action( 'wp_ajax_nopriv_gateway_relay', array( &$this, 'process' ) );
		add_action( 'wp_ajax_gateway_relay', array( &$this, 'process' ) );

	}

	function process(){

		//identify the source
		if (isset($_POST['txn_id']) ) $this->source = 'paypal';
		elseif (isset($_POST['x_trans_id']) ) $this->source = 'authnet';
		else return;

		$this->postdata = http_build_query($_POST);

		switch ($this->source){
			//PAYPAL
			case'paypal': {

				//Check if from sandbox Class C IPs
				$url = ( strpos($_SERVER['REMOTE_ADDR'], '173.0.82.') === 0 ) ? self::PAYPAL_SANDBOX : self::PAYPAL_LIVE;

				$args =  array('timeout' => 90, 'sslverify' => false );

				$response = wp_remote_get( $url . "?" . $this->postdata, $args );

				if(is_wp_error($response) ){
					$this->write_to_log(print_r($response, true));
				}	else {
					$response = $response['body'];
				}

				if ( $response != "VERIFIED" ) {
					$this->write_to_log(print_r($response, true) );
					die( 'not VERIFIED' );
				}

				//Verified add to queue
				$this->add_to_queue($this->source, $this->postdata);

				break;
			}

			//AUTHORIZE NET
			case 'authnet': {
				$this->add_to_queue($this->source, $this->postdata);
				break;
			}

			//UNKNOWN
			default: {
				break;
			}
		}

		$this->write_to_log( $this->postdata, $this->source);

		for($i=0;$i <= count($this->queue); $i++){
			$this->process_queue();
		}

		exit;

	}

	function add_to_queue($source, $postdata, $retries = 5 ){
		$this->settings = get_site_option($this->settings_name);

		parse_str($postdata, $params);
		$apps = array();
		//Get the apps that match
		foreach($this->settings['apps'] as $key => $app){
			$found = false;
			if($source == 'paypal'){
				$found = (strpos($params['rp_invoice_id'], $app['prefix']) === 0
				|| strpos($params['custom'], $app['prefix']) === 0
				|| strpos($params['item_number'], $app['prefix']) === 0
				|| strpos($params['invoice'], $app['prefix']) === 0);
			}
			elseif($source == 'authnet'){
				$found = (strpos($params['x_invoice_num'], $app['prefix']) === 0
				|| strpos($params['x_po_num'], $app['prefix']) === 0
				|| strpos($params['x_cust_id'], $app['prefix']) === 0);
			}
			if($found) $apps[] = $app;
		}
		$this->queue = get_site_option($this->queue_name);
		$item = array('source' => $source, 'postdata' => $postdata, 'retries' => $retries, 'apps' => $apps );
		$this->queue[] = $item;
		update_site_option($this->queue_name, $this->queue);
		$this->queue = get_site_option($this->queue_name);
	}

	function process_queue(){
		$this->settings = get_site_option($this->settings_name);

		$this->queue = get_site_option($this->queue_name);
		if(empty($this->queue) ) return;
		$q = array_shift($this->queue);
		update_site_option($this->queue_name, $this->queue);

		foreach($q['apps'] as $key => $app){

			$args =  array('timeout' => 90, 'sslverify' => false, 'body' => $q['postdata'] . "&relay_pass={$app['password']}" );

			$response = wp_remote_post( $app['url'], $args );

			if(is_wp_error($response) ){
				$this->write_to_log(print_r($response, true));
			}	else {
				if($response['response']['code'] == 200) unset($q['apps'][$key]);
			}
		}
		$q['retries']--;
		if($q['retries'] > 0 && ! empty($q['apps']) ) {
			$this->queue = get_site_option($this->queue_name);
			$this->queue[] = $q;
			update_site_option($this->queue_name, $this->queue);
		}
	}

	function write_to_log($error, $log = 'error') {

		//create filename for each month
		$filename = __DIR__ . "/logs/{$log}_" . date('Y_m') . '.log';

		//add timestamp to error
		$message = gmdate('[Y-m-d H:i:s] ') . $error;

		//write to file
		file_put_contents($filename, $message . "\n", FILE_APPEND);
	}

}


function register_gateway_relay($prefix = '', $url='', $password=''){
	$settings = get_site_option(GATEWAY_RELAY_SETTINGS_NAME);

	$item = array('prefix' => $prefix, 'url' => $url, 'password' => $password );

	foreach($settings['apps'] as $key => $value) {
		if($value['prefix'] == $item['prefix'] && $value['url'] == $item['url']) return false;
	}
	$settings['apps'][] = $item;
	update_site_option(GATEWAY_RELAY_SETTINGS_NAME, $settings);
	return true;
}

function unregister_gateway_relay($prefix = '', $url='', $password=''){
	$settings = get_site_option(GATEWAY_RELAY_SETTINGS_NAME);
	$item = array('prefix' => $prefix, 'url' => $url);

	foreach($settings['apps'] as $key => $value) {
		if($value == $item) {
			unset($settings['apps'][$key]);
			update_site_option(GATEWAY_RELAY_SETTINGS_NAME, $settings);
			return true;
		}
	}
	return false;
}

new Gateway_Relay;

endif;