<?php 
/*
Plugin Name: PayFast Payment GeoDirectory Add-on
Plugin URI: https://wpgeodirectory.com
Description: Adds PayFast as a payment on GeoDirectory Payment Manager plugin.
Version: 1.0.0
Author: GeoDirectory
Author URI: https://wpgeodirectory.com
*/

define("GEODIRPAYFAST_VERSION", "1.0.0");
if (!defined('GEODIRPAYFAST_TEXTDOMAIN')) define('GEODIRPAYFAST_TEXTDOMAIN', 'geodir_payfast');
if(is_admin()){
    if(!class_exists('GD_Plugin_Updater')) {//only load the update file if needed
        require_once('gd_update.php'); // require update script
    }
    /*
     * Checks for updates to this addon.
     *
     * @param string $textdomain The textdomain of the addon.
     * @param string $name The name of the addon shown on update screen.
     * @param string $version The addon version number.
     * @param string $download_id The GD download id.
     * @param string $slug The slug of the addon file.
     * @param string $notes Notes, these appear under the licence text box on update screen.
     */
    gd_add_plugin_to_update_list(GEODIRPAYFAST_TEXTDOMAIN,'PayFast Gateway',GEODIRPAYFAST_VERSION,65863,__FILE__,'');
}
///GEODIRECTORY CORE ALIVE CHECK START
if(is_admin()){
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
if(!is_plugin_active('geodirectory/geodirectory.php')){
return;
}
//check payment manager is installed, if not bail.
    if(!is_plugin_active('geodir_payment_manager/geodir_payment_manager.php')){
        return;
    }
}

/**
 * Localisation
 **/

add_action('plugins_loaded','geodir_load_translation_geodir_payfast');
function geodir_load_translation_geodir_payfast()
{
    $locale = apply_filters('plugin_locale', get_locale(), 'geodir_payfast');
    load_textdomain('geodir_payfast', WP_LANG_DIR . '/' . 'geodir_payfast' . '/' . 'geodir_payfast' . '-' . $locale . '.mo');
    load_plugin_textdomain('geodir_payfast', false, dirname(plugin_basename(__FILE__)) . '/gdpayfast-languages');
}

/*
 * This is the code that runs our activation and deactivation functions.
 * This adds/removes the new settings to the payment manager when the plugin is activated/deactivated or uninstalled.
 */
if ( is_admin() ) {

    register_activation_hook(__FILE__, 'geodir_payfast_activation');
    register_deactivation_hook(__FILE__, 'geodir_payfast_uninstall');
    register_uninstall_hook(__FILE__, 'geodir_payfast_uninstall');
}

/*
 * Installs the payment gateway settings.
 *
 * Runs via the activation hook and installs the payment settings in the payment manager.
 *
 * @since 1.0.0
 * @package PayFast_Payment_GeoDirectory_Add-on
 */
function geodir_payfast_activation() {

	$payfastCheck = get_option('payment_method_payfast');
	
	if ( false === $payfastCheck ) {
		global $wpdb;
		
		$order = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->options WHERE option_name LIKE %s ORDER BY option_id", array('payment_method_%') ) );
		
		$payOpts = array();

        $payOpts[] = array(
            "field_type" => "text",
            "title"			=>	__("Username", 'geodir_payfast'),
            "fieldname"		=>	"username",
            "value"			=>	"sbtm02@payfast.co.za",
            "description"	=>	__("Example : sbtm02@payfast.co.za", 'geodir_payfast'),
        );

        $payOpts[] = array(
            "field_type" => "text",
            "title"			=>	__("Merchant ID", 'geodir_payfast'),
            "fieldname"		=>	"merchantid",
            "value"			=>	"10000103",
            "description"	=>	__("Example : 10000103", 'geodir_payfast'),
        );

        $payOpts[] = array(
            "field_type" => "text",
            "title"			=>	__("Merchant Key", 'geodir_payfast'),
            "fieldname"		=>	"merchantkey",
            "value"			=>	"479f49451e829",
            "description"	=>	__("Example : 479f49451e829", 'geodir_payfast'),
        );

        $payOpts[] = array(
            "field_type" => "text",
            "title"			=>	__("Pass Phrase", 'geodir_payfast'),
            "fieldname"		=>	"passphrase",
            "value"			=>	"",
            "description"	=>	__("If you have a pass phrase set in your PyaFast settings then it MUST be set here, otherwise it MUST be blank.", 'geodir_payfast'),
        );

		
		$payOpts[] = array(
			'field_type' 	=> 'text',
			'title' 		=> 'ITN',
			'fieldname' 	=> 'notify_url',
			'value' 		=> geodir_info_url(array('pay_action'=>'ipn','pmethod'=>'payfast')),
			'description' 	=> 'This is for information only and should not be changed.'
		);
		
		$paymenthodinfo = array(
			'name' 			 => 'PayFast',
			'key' 			 => 'payfast',
			'isactive' 		 => 1,
			'display_order'  => ( (integer) count($order) + 2 ),
			'payment_mode' 	 => 'live',
			'payOpts' 		 => apply_filters('geodir_payment_payfast_options' ,$payOpts),
		);
		
		add_option( 'payment_method_payfast' , $paymenthodinfo );
	}
}

/*
 * Removes the payment gateway settings.
 *
 * Runs via the deactivation and uninstall hooks and deletes the payment settings.
 *
 * @since 1.0.0
 * @package PayFast_Payment_GeoDirectory_Add-on
 */
function geodir_payfast_uninstall() {
	delete_option( 'payment_method_payfast' );
}

/*
 * Adds settings to the checkout page for PayFast.
 *
 * @since 1.0.0
 * @package PayFast_Payment_GeoDirectory_Add-on
 */
function geodir_payfast_checkout_extras($name){
    if($name=='payfast') {
        $current_user = wp_get_current_user();
        $user_first_name	= $current_user->user_firstname;
        $user_last_name	= $current_user->user_lasttname;
        $user_email	= $current_user->user_email;
        ?>
        <table class="table" style="margin-left:50px; margin-top:10px;" id="payfastoptions">
            <tr>
                <td>
                    <div class="geodir_form_row clearfix required_field">
                        <label style="width:150px;"><?php _e('First Name :', 'geodir_payfast');?></label>
                        <input type="text" value="<?php echo $user_first_name;?>" size="25" id="payfast_first_name" name="payfast_first_name" class="textfield required" />
                    </div>
                </td>
            </tr>

            <tr>
                <td>
                    <div class="geodir_form_row clearfix required_field">
                        <label style="width:150px;"><?php _e('Last Name :', 'geodir_payfast');?></label>
                        <input type="text" value="<?php echo $user_last_name;?>" size="25" id="payfast_last_name" name="payfast_last_name" class="textfield required" />
                    </div>
                </td>
            </tr>

            <tr>
                <td>
                    <div class="geodir_form_row clearfix required_field">
                        <label style="width:150px;"><?php _e('Email :', 'geodir_payfast');?></label>
                        <input type="email" value="<?php echo $user_email;?>" size="25" id="payfast_email" name="payfast_email" class="textfield required" />
                    </div>
                </td>
            </tr>

        </table>
        <script>
            jQuery( document ).ready(function() {

                jQuery('#gd_checkout_paynow', '#gd_checkout_form').on('click', function(e) {
                    var form = jQuery(this).closest('#gd_checkout_form');
                    var pmethod = jQuery('input[name="gd_payment_method"]:checked', form).val();

                    if (pmethod === 'payfast') {
                        if (jQuery('#payfast_first_name').val() == '') {
                            alert("<?php _e('Please fill out all fields','geodir_payfast');?>");
                            return false;
                        }
                        if (jQuery('#payfast_last_name').val() == '') {
                            alert("<?php _e('Please fill out all fields','geodir_payfast');?>");
                            return false;
                        }
                        if (jQuery('#payfast_email').val() == '' ) {
                            alert("<?php _e('Please fill out all fields','geodir_payfast');?>");
                            return false;
                        }


                    }

                });
            });
        </script>
    <?php
    }
}

add_action('geodir_payment_method_fields','geodir_payfast_checkout_extras',10,1);

/*
 * Changes the checkout button text when PayFast is selected.
 *
 * @since 1.0.0
 * @package PayFast_Payment_GeoDirectory_Add-on
 */
function geodire_payfast_checkout_button_text($button_title, $name){
    if($name=='payfast'){
        $button_title = __("Proceed to PayFast", 'geodir_payfast');
    }

    return $button_title;// we must always return a filtered value
}

add_filter('geodir_payment_cart_button_text','geodire_payfast_checkout_button_text',10,2);



/*
 * Processes the submitted checkout page and sends the user to the PayFast website for payment.
 *
 * @since 1.0.0
 * @package PayFast_Payment_GeoDirectory_Add-on
 */
function geodir_payment_form_payfast( $invoice_id ) {
	$invoice_info 	= geodir_get_invoice( $invoice_id );
	$payment_method	= get_payment_options( 'payfast' );
	
	$post_id 		= $invoice_info->post_id;
	$item_name 		= $invoice_info->post_title;
	$item_name 		= apply_filters( 'geodir_payfast_item_name', $item_name, $invoice_id );
	$payable_amount	= $invoice_info->paied_amount;
    $paymode        = $payment_method['payment_mode'];
    $passPhrase     = $payment_method['passphrase'];

	$return_url	    = geodir_info_url( array( 'pay_action' => 'success', 'inv' => $invoice_id, 'pmethod' => 'payfast', 'pid' => $post_id ));
    $cancel_url		= geodir_info_url( array( 'pay_action' => 'cancel', 'inv' => $invoice_id, 'pmethod' => 'payfast', 'pid' => $post_id ));
    $notify_url		= geodir_info_url( array( 'pay_action' => 'ipn','pmethod' => 'payfast' ));

	//////////////
    // Construct variables
    $data = array(
        // Merchant details
        'merchant_id' => $payment_method['merchantid'],
        'merchant_key' => $payment_method['merchantkey'],
        'return_url' => $return_url,
        'cancel_url' => $cancel_url,
        'notify_url' => $notify_url,
        'name_first' => esc_attr($_POST['payfast_first_name']),
        'name_last'  => esc_attr($_POST['payfast_last_name']),
        'email_address'=> esc_attr($_POST['payfast_email']),
        'm_payment_id' => $invoice_id, //Unique payment ID to pass through to notify_url
        'amount' => $payable_amount, // payment must be in ZAR
        'item_name' => esc_attr( $item_name ),
        'item_description' => esc_attr( $item_name ),
        'custom_int1' => $post_id, //custom integer, post id
        'custom_str1' => 'custom string to be passed through with the transaction to the notify_url page'
    );

    // Create GET string
    $pfOutput ='';
    foreach( $data as $key => $val )
    {
        if(!empty($val))
        {
            $pfOutput .= $key .'='. urlencode( trim( $val ) ) .'&';
        }
    }
    // Remove last ampersand
    $getString = substr( $pfOutput, 0, -1 );
    if( isset( $passPhrase ) && $paymode!='sandbox' )
    {
        $getString .= '&passphrase='.$passPhrase;
    }
    $data['signature'] = md5( $getString );
    
    /////////////
    // If in testing mode use the sandbox domain ?  sandbox.payfast.co.za else www.payfast.co.za
    if ( $paymode == 'sandbox') {
        $pfHost = 'sandbox.payfast.co.za';
    } else {
        $pfHost = 'www.payfast.co.za';
    }

    $htmlForm = '<form name="frm_payment_method" action="https://'.$pfHost.'/eng/process" method="post">';
    foreach($data as $name=> $value)
    {
        $htmlForm .= '<input type="hidden" name="'.$name.'" value="'.$value.'">';
    }
    $htmlForm .= '</form>';
    echo $htmlForm;
    ?>
    <div class="wrapper">
		<div class="clearfix container_message">
			<center><h1 class="head2"><?php _e("Processing for PayFast, Please wait...", 'geodir_payfast'); ?></h1></center>
		</div>
	</div>
	<script type="text/javascript">setTimeout("document.frm_payment_method.submit()",50);</script>
	<?php
	exit;

    /////////////
}
add_action( 'geodir_payment_form_handler_payfast' , 'geodir_payment_form_payfast' );


/*
 * Handles the PayFast ITN notification.
 *
 * Checks the ITN notifications is valid and if so it will mark the invoice paid and send paid notifications to user and admin.
 *
 * @since 1.0.0
 * @package PayFast_Payment_GeoDirectory_Add-on
 */
function geodir_ipn_handler_payfast() {

    $payment_method = get_payment_options( 'payfast' );

    $paymode 		= $payment_method['payment_mode'] == 'sandbox' ? true : false;
    $passPhrase     = $payment_method['passphrase'];
    /**
     * Notes:
     * - All lines with the suffix "// DEBUG" are for debugging purposes and
     *   can safely be removed from live code.
     * - Remember to set PAYFAST_SERVER to LIVE for production/live site
     */
    // General defines
    if($paymode=='sandbox'){
        define( 'PAYFAST_SERVER', 'TEST' );
    }else{
        define( 'PAYFAST_SERVER', 'LIVE' );
    }
    // Whether to use "sandbox" test server or live server
    define( 'USER_AGENT', 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)' );
    // User Agent for cURL

    // Messages
    // Error
    define( 'PF_ERR_AMOUNT_MISMATCH', 'Amount mismatch' );
    define( 'PF_ERR_BAD_SOURCE_IP', 'Bad source IP address' );
    define( 'PF_ERR_CONNECT_FAILED', 'Failed to connect to PayFast' );
    define( 'PF_ERR_BAD_ACCESS', 'Bad access of page' );
    define( 'PF_ERR_INVALID_SIGNATURE', 'Security signature mismatch' );
    define( 'PF_ERR_CURL_ERROR', 'An error occurred executing cURL' );
    define( 'PF_ERR_INVALID_DATA', 'The data received is invalid' );
    define( 'PF_ERR_UKNOWN', 'Unkown error occurred' );

    // General
    define( 'PF_MSG_OK', 'Payment was successful' );
    define( 'PF_MSG_FAILED', 'Payment has failed' );


    // Notify PayFast that information has been received
    header( 'HTTP/1.0 200 OK' );
    flush();

    // Variable initialization
    $pfError = false;
    $pfErrMsg = '';
    $output = ''; // DEBUG
    $pfParamString = '';
    $pfHost = ( PAYFAST_SERVER == 'LIVE' ) ? 'www.payfast.co.za' : 'sandbox.payfast.co.za';
    $pfData = array();
    $res = '';
    $lines = array();

    //// Dump the submitted variables and calculate security signature
    if( !$pfError )
    {
        $output = "Posted Variables:\n\n"; // DEBUG

        // Strip any slashes in data
        foreach( $_POST as $key => $val )
            $pfData[$key] = stripslashes( $val );

        // Dump the submitted variables and calculate security signature
        foreach( $pfData as $key => $val )
        {
            if( $key != 'signature' )
                $pfParamString .= sanitize_text_field($key) .'='. urlencode( $val ) .'&';
        }

        // Remove the last '&' from the parameter string
        $pfParamString = substr( $pfParamString, 0, -1 );
        $pfTempParamString = $pfParamString;

        // If a passphrase has been set in the PayFast Settings, then it needs to be included in the signature string.
        if( !empty( $passPhrase ) && PAYFAST_SERVER == 'LIVE' )
        {
            $pfTempParamString .= '&passphrase='.urlencode( $passPhrase );
        }
        $signature = md5( $pfTempParamString );

        $result = ( $_POST['signature'] == $signature );

        $output .= "Security Signature:\n\n"; // DEBUG
        $output .= "- posted     = ". $_POST['signature'] ."\n"; // DEBUG
        $output .= "- calculated = ". $signature ."\n"; // DEBUG
        $output .= "- result     = ". ( $result ? 'SUCCESS' : 'FAILURE' ) ."\n"; // DEBUG
    }

    //// Verify source IP
    if( !$pfError )
    {
        $validHosts = array(
            'www.payfast.co.za',
            'sandbox.payfast.co.za',
            'w1w.payfast.co.za',
            'w2w.payfast.co.za',
        );

        $validIps = array();

        foreach( $validHosts as $pfHostname )
        {
            $ips = gethostbynamel( $pfHostname );

            if( $ips !== false )
                $validIps = array_merge( $validIps, $ips );
        }

        // Remove duplicates
        $validIps = array_unique( $validIps );

        if( !in_array( $_SERVER['REMOTE_ADDR'], $validIps ) )
        {
            $pfError = true;
            $pfErrMsg = PF_ERR_BAD_SOURCE_IP;
        }
    }


    $invoice_info 	= geodir_get_invoice( $_POST['m_payment_id']);
    $cartTotal = $invoice_info->paied_amount;
    if( abs( floatval( $cartTotal ) - floatval($_POST['amount_gross'] ) ) > 0.01 )
    {
        $pfError = true;
        $pfErrMsg = 'Amounts Mismatch';
    }

    //// Connect to server to validate data received
    if( !$pfError )
    {
        // Use cURL (If it's available)
        if( function_exists( 'curl_init' ) )
        {
            $output .= "\n\nUsing cURL\n\n"; // DEBUG

            // Create default cURL object
            $ch = curl_init();

            // Base settings
            $curlOpts = array(
                // Base options
                CURLOPT_USERAGENT => USER_AGENT, // Set user agent
                CURLOPT_RETURNTRANSFER => true,  // Return output as string rather than outputting it
                CURLOPT_HEADER => false,         // Don't include header in output
                CURLOPT_SSL_VERIFYHOST => true,
                CURLOPT_SSL_VERIFYPEER => false,

                // Standard settings
                CURLOPT_URL => 'https://'. $pfHost . '/eng/query/validate',
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => $pfParamString,
            );
            curl_setopt_array( $ch, $curlOpts );

            // Execute CURL
            $res = curl_exec( $ch );
            curl_close( $ch );

            if( $res === false )
            {
                $pfError = true;
                $pfErrMsg = PF_ERR_CURL_ERROR;
            }
        }
        // Use fsockopen
        else
        {
            $output .= "\n\nUsing fsockopen\n\n"; // DEBUG

            // Construct Header
            $header = "POST /eng/query/validate HTTP/1.0\r\n";
            $header .= "Host: ". $pfHost ."\r\n";
            $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
            $header .= "Content-Length: " . strlen( $pfParamString ) . "\r\n\r\n";

            // Connect to server
            $socket = fsockopen( 'ssl://'. $pfHost, 443, $errno, $errstr, 10 );

            // Send command to server
            fputs( $socket, $header . $pfParamString );

            // Read the response from the server
            $res = '';
            $headerDone = false;

            while( !feof( $socket ) )
            {
                $line = fgets( $socket, 1024 );

                // Check if we are finished reading the header yet
                if( strcmp( $line, "\r\n" ) == 0 )
                {
                    // read the header
                    $headerDone = true;
                }
                // If header has been processed
                else if( $headerDone )
                {
                    // Read the main response
                    $res .= $line;
                }
            }
        }
    }

    //// Get data from server
    if( !$pfError )
    {
        // Parse the returned data
        $lines = explode( "\n", $res );

        $output .= "\n\nValidate response from server:\n\n"; // DEBUG

        foreach( $lines as $line ) // DEBUG
            $output .= $line ."\n"; // DEBUG
    }

    //// Interpret the response from server
    if( !$pfError || PAYFAST_SERVER == 'TEST')
    {
        // Get the response from PayFast (VALID or INVALID)
        $result = trim( $lines[0] );

        $output .= "\nResult = ". $result; // DEBUG

        // If the transaction was valid
        if( strcmp( $result, 'VALID' ) == 0 || PAYFAST_SERVER == 'TEST')
        {   ###########################
            // Process as required
            $itn = $_REQUEST;

            // This will send receipts on succesful invoices


                $event_type = $itn['payment_status'];
                $transaction_id = $itn['pf_payment_id'];

                $invoice_id	= $itn['m_payment_id'];
                $post_id 	= $itn['custom_int1'];

                $invoice_info 	= geodir_get_invoice( $invoice_id );
                $user_id		= !empty( $invoice_info ) ? $invoice_info->user_id : '1';
                $item_name 		= $itn['item_name'];
                $item_name 		= apply_filters( 'geodir_payfast_item_name', $item_name, $invoice_id );

                $payable_amount = geodir_payment_price( $invoice_info->paied_amount );

                $payment_type = 'single payment';

                $transaction_details = '';
                $transaction_details .= "--------------------------------------------------<br />";
                $transaction_details .= sprintf(__("Payment Details for Invoice ID #%s", 'geodir_payfast'), $invoice_id ) ."<br />";
                $transaction_details .= "--------------------------------------------------<br />";
                $transaction_details .= sprintf(__("Listing Title: %s", 'geodir_payfast'),$item_name)."<br />";
                $transaction_details .= "--------------------------------------------------<br />";
                $transaction_details .= sprintf(__("Trans ID: %s", 'geodir_payfast'), $transaction_id)."<br />";
                $transaction_details .= sprintf(__("Status: %s", 'geodir_payfast'), $event_type)."<br />";
                $transaction_details .= sprintf(__("Amount: %s", 'geodir_payfast'), $payable_amount )."<br />";
                $transaction_details .= sprintf(__("Type: %s", 'geodir_payfast'), $payment_type )."<br />";
                $transaction_details .= sprintf(__("Date: %s", 'geodir_payfast'), date_i18n( "Y-m-d H:i:s", current_time( 'timestamp' ) ) )."<br />";
                $transaction_details .= sprintf(__("Method: %s", 'geodir_payfast'), 'PayFast')."<br />";
                $transaction_details .= "--------------------------------------------------<br />";

                if ( $event_type == 'COMPLETE'  ) {

                    /*############ SET THE INVOICE STATUS START ############*/
                    // update invoice status and transaction details
                    geodir_update_invoice_status( $invoice_id, 'confirmed', false );
                    geodir_update_invoice_transaction_details( $invoice_id, $transaction_details );
                    /*############ SET THE INVOICE STATUS END ############*/

                    // send notification to admin
                    geodir_payment_adminEmail( $post_id, $user_id, 'payment_success', $transaction_details );

                    // send notification to client
                    geodir_payment_clientEmail( $post_id, $user_id, 'payment_success', $transaction_details );
                }elseif ( $event_type == 'FAILED'  ) {

                    /*############ SET THE INVOICE STATUS START ############*/
                    // update invoice status and transaction details
                    geodir_update_invoice_status( $invoice_id, 'failed', false );
                    geodir_update_invoice_transaction_details( $invoice_id, $transaction_details );
                    /*############ SET THE INVOICE STATUS END ############*/

                }elseif ( $event_type == 'PENDING'  ) {

                    /*############ SET THE INVOICE STATUS START ############*/
                    // update invoice status and transaction details
                    geodir_update_invoice_status( $invoice_id, 'onhold', false );
                    geodir_update_invoice_transaction_details( $invoice_id, $transaction_details );
                    /*############ SET THE INVOICE STATUS END ############*/

                }


            ################

        }
        // If the transaction was NOT valid
        else
        {
            // Log for investigation
            $pfError = true;
            $pfErrMsg = PF_ERR_INVALID_DATA;
        }
    }

    // If an error occurred
    if( $pfError )
    {
        $output .= "\n\nAn error occurred!";
        $output .= "\nError = ". $pfErrMsg;
        wp_mail( get_option('admin_email'), 'PayFast IPN ERROR LOG', $output );

    }


	header("HTTP/1.0 200 OK");//report that the ITN was recived ok and exit
	exit;
}
add_action( 'geodir_ipn_handler_payfast', 'geodir_ipn_handler_payfast' );

