View difference between Paste ID: zAN1YEnn and m8j4VTxr
SHOW: | | - or go back to the newest paste.
1
<?php
2
/*
3
Plugin Name: EDD PayFast Payment Gateway
4
Plugin URI: http://www.mesaneweb,com
5
Description: Accept payments through PayFast for your Digital Store powered by Easy Digital Downloads, a payment gateway for South Africans.
6
Version: 1.0.1
7
Author: Dane A. Mesane
8
Author URI: http://www.mesaneweb.com
9
License: GPL version 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10
*/
11
/*  Copyright 2014  Dane A. Mesane (www.mesaneweb.com)  ( email : support@mesaneweb.com )
12
13
    This program is free software; you can redistribute it and/or modify
14
    it under the terms of the GNU General Public License, version 2, as 
15
    published by the Free Software Foundation.
16
17
    This program is distributed in the hope that it will be useful,
18
    but WITHOUT ANY WARRANTY; without even the implied warranty of
19
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
    GNU General Public License for more details.
21
22
    You should have received a copy of the GNU General Public License
23
    along with this program; if not, write to the Free Software
24
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
25
*/
26
27
//check the existensi of our class and Easy_Digital_Downloads,
28
if( ! class_exists( 'EDD_Payfast' ) ) :
29
30
class EDD_Payfast {
31
	
32
	/**
33
	 * @var instance The one true EDD_Payfast class
34
	 * singleton
35
	 */
36
	private static $instance;
37
	
38
	// Our file of this plugin
39
	public $file;
40
	
41
	// Our plugin path
42
	public $plugin_path;
43
	
44
	// Our plugin url
45
	public $plugin_url;
46
	
47
	// the version of this plugin
48
	public $version;
49
	
50
	/**
51
	 * Main EDD_Payfast Instance
52
	 * singleton implementation
53
	 */
54
	public static function instance() {
55
		if ( ! isset( self::$instance ) ) {
56
			self::$instance = new EDD_Payfast(__FILE__);
57
		}
58
		return self::$instance;
59
	}
60
	/**
61
	 * Constructor
62
	 * @since  1.0.0
63
	 * @return  void
64
	 */
65
	private function __construct( $file ) {
66
		
67
		//set up our data
68
		$this->version = '1.0.0';
69
		$this->file = $file;
70
		$this->plugin_url = trailingslashit( plugins_url( '', $plugin = $file ) );
71
		$this->plugin_path = trailingslashit( dirname( $file ) );
72
		
73
		if ( ! function_exists( 'json_decode' ) ) {
74
			if ( is_admin() )
75
				add_action( 'admin_notices', array( &$this, 'initialization_warning' ) );
76
			return;
77
		}
78
		//hooks for admin
79
		if( is_admin() ) 
80
			add_filter( 'edd_settings_gateways', array( &$this, 'add_settings_gateways' ) );
81
		
82
		// hooks
83
		add_filter( 'edd_currencies', array( &$this, 'rand_currencies' )); //add South African  currency, R or ZAR
84
		add_filter( 'edd_accepted_payment_icons', array( &$this, 'payfast_payment_icon' ) );
85
		add_filter( 'edd_payment_gateways', array( &$this, 'register_gateway' ) );
86
		add_action( 'edd_payfast_cc_form', array( &$this, 'gateway_cc_form' ) );
87
        add_action( 'edd_gateway_payfast', array( &$this, 'process_payment' ) );
88
		add_action( 'init', array( &$this, 'validate_report_back' ) ); // trying to get notify from payfast
89
		add_action( 'edd_payfast_check', array( &$this, 'process_payfast_notify' ) );
90
		
91
	} //end __construct
92
	
93
	/**
94
	 * Yeah, Because we need json_docode() function to retrieve session ID from Payfast
95
	 * So if the function don't exists we should throw a warning
96
	 *
97
	 * @since 1.0
98
	 */
99
	public function initialization_warning() {
100
		echo '<div id="edd-payfast-warning" class="updated fade"><p><strong>' . sprintf( __( '%s PHP library not installed.', 'edd-payfast' ), 'JSON' ) . '</strong> ';
101
		echo sprintf( __('EDD Payfast Payment Gateway plugin will not function without <a href="%s">PHP JSON functions</a> enabled. Please update your version of WordPress for improved compatibility and/or enable native JSON support for PHP.'), 'http://php.net/manual/book.json.php' );
102
		echo '</p></div>';
103
	}
104
	
105
	/*	in order to disable credit card form that registered by Easy Digital Downloads by default. I return to blank value
106
	*	on other words, we just registered that. we don't need that for our gateway..
107
	*/
108
	public static function gateway_cc_form() {
109
        return;
110
	} //end gateway_cc_form()
111
	
112
	/*
113
	*	add our icon on checkout page
114
	*	
115
	*	@return void
116
	*	@access public
117
	*	
118
	*/
119
	
120
	public function payfast_payment_icon( $icons ) {
121
		$icons[$this->plugin_url . 'assets/images/PayFast.png'] = 'Payfast';
122
		return $icons;
123
	} //end payfast_payment_icon()
124
	
125
	/* 
126
	*	add our currency, sadly South African Rand ( R ) not support on the core of Easy Digital Downloads
127
	*	but the plugin allow to filter that function
128
	*
129
	*	I don't know why other people called our currency is ZAR, but we familiar with R as our currency
130
	*	because of that, I set both here...
131
	*/
132
	function rand_currencies( $currencies ) {
133
		
134
		$currencies['R'] = __('South African Rand ( R )', 'edd_payfast');
135
		 
136
		return $currencies;
137
		
138
	} //end rand_currencies()
139
	
140
	// Remote get and retrieve respon body..
141
    private function remote_get( $url, $headers = array() ) {
142
			
143
		$response = wp_remote_get( $url,
144
			array(
145
				'redirection' => 1,
146
				'httpversion' => '1.1',
147
				'user-agent'  => 'EDD Payfast' . $this->version . '; WordPress (' . home_url( '/' ) . ')',
148
				'timeout'     => 15,
149
				'headers'     => $headers
150
			)
151
		);
152
153
		if ( !is_wp_error( $response ) && $response['response']['code'] == 200 ) {
154
			return $response['body'];
155
		} else {
156
			return false;
157
		}
158
	} //end remote_get()
159
	
160
	// Lets register our gateway, we can use $gateways object because this run during hooks
161
	public function register_gateway( $gateways ) {
162
	
163
		$gateways['payfast'] = array( 'admin_label' => __( 'Payfast', 'edd_payfast' ), 'checkout_label' => __('Payfast', 'edd_payfast'));
164
		
165
		return $gateways;
166
	}
167
	
168
	/*
169
	* Easy Digital Downloads have settings method that allow other developer filter that to add additional settings
170
	* So because this plugin is an extension/add on for EDD, we don't need create settings from scratch or create
171
	* tradional setting on Wordpress, beautifull..
172
	*
173
	* @access public
174
	* @return void
175
	* @since 0.0.1
176
	*/
177
	public function add_settings_gateways( $settings ) {
178
		
179
		$edd_payfast_settings = array(
180
		
181
		array(
182
			'id' => '_edd_payfast_gateway_settings',
183
			'name' => '<strong>' . __('Payfast Gateway Settings', 'edd_payfast') . '</strong>',
184
			'desc' => __('Configure the gateway settings', 'edd_payfast'),
185
			'type' => 'header'
186
		),
187
		array(
188
			'id' => 'edd_payfast_merchant_id',
189
			'name' => __('Merchant ID', 'pw_edd'),
190
			'desc' => __('Enter your Payfast Merchant ID, you can finf it under settings in your PayFast account. Please click <a https://www.payfast.co.za/acc/integration>here</a>.', 'edd_payfast'),
191
			'type' => 'text',
192
			'size' => 'regular'
193
		), 
194
		array(
195
			'id' => 'edd_payfast_merchant_key',
196
			'name' => __('Merchant Key', 'pw_edd'),
197
			'desc' => __('Enter your Payfast Merchant Key, you can finf it under settings in your PayFast account. Please click <a https://www.payfast.co.za/acc/integration >here</a>.', 'edd_payfast'),
198
			'type' => 'text',
199
			'size' => 'regular'
200
		)
201
	);
202
 
203
		return array_merge( $settings, $edd_payfast_settings );
204
	} //end add_settings_gateways()
205
	
206
	public function process_payment( $purchase_data ) {
207
		
208
		global $edd_options;
209
		
210
		// Check there is a gateway name
211
		if ( ! isset( $purchase_data['post_data']['edd-gateway'] ) )
212
    	return;
213
		
214
		$errors = edd_get_errors();
215
		
216
		if( !$errors ) {
217
		
218
			$payment_data = array( 
219
				'price' => $purchase_data['price'], 
220
				'date' => $purchase_data['date'], 
221
				'user_email' => $purchase_data['user_email'],
222
				'purchase_key' => $purchase_data['purchase_key'],
223
				'currency' => $edd_options['currency'],
224
				'downloads' => $purchase_data['downloads'],
225
				'user_info' => $purchase_data['user_info'],
226
				'cart_details' => $purchase_data['cart_details'],
227
				'status' => 'pending'
228
			);
229
230
			// record the pending payment
231
			$payment = edd_insert_payment( $payment_data );
232
			
233
			if ( ! $payment ) {
234
				// Record the error
235
				edd_record_gateway_error( __( 'Payment Error', 'edd_payfast' ), sprintf( __( 'Payment creation failed before sending buyer to Payfast. Payment data: %s', 'edd_payfast' ), json_encode( $payment_data ) ), $payment );
236
				// Problems? send back
237
				edd_send_back_to_checkout( '?payment-mode=' . $purchase_data['post_data']['edd-gateway'] );
238
			
239
			} else {
240
			
241
				$return_url = add_query_arg( 'payment-confirmation', 'payfast', get_permalink( $edd_options['success_page'] ) );
242
				$listener_url = trailingslashit( home_url() ).'?payfast=notify';
243
				$cancel_url = add_query_arg( 'payment-cancel', 'payfast', edd_get_failed_transaction_uri() );
244
				
245
				$summary = edd_get_purchase_summary( $purchase_data, false );
246
				$quantity = edd_get_cart_quantity();
247-
				if ( is_ssl() || ! $ssl_check ) {
247+
248
				function edd_get_payfast_redirect( $ssl_check = false ) {
249
    global $edd_options;
250
				if ( is_ssl() || ! $ssl_check) {
251
					$protocal = 'https://';
252
				} else {
253
					$protocal = 'http://';
254-
					$url_to_send = $protocal . 'https://sandbox.payfast.co.za/eng/process';
254+
255
				
256-
					$url_to_send = $protocal . 'https://www.payfast.co.za/eng/process';
256+
257
					$url_to_send = $protocal . 'http://sandbox.payfast.co.za/eng/process';
258
				} else {
259
					$url_to_send = $protocal . 'http://www.payfast.co.za/eng/process';
260
				}
261
			
262
				$payfast_args = array(
263
					'key'      => $edd_options['edd_payfast_api_key'], // API Key Merchant / Penjual
264
					'action'   => 'payment',
265
					'product'  => stripslashes_deep( html_entity_decode( wp_strip_all_tags( $summary ), ENT_COMPAT, 'UTF-8' ) ),
266
					'price'    => round( $purchase_data['price'] - $purchase_data['tax'], 2 ), //
267
					'quantity' => $quantity,
268
					'comments' => $payment, // Optional for Payfast, but this is the payment ID, we need it to verify payment
269
					'ureturn'  => $return_url,
270
					'unotify'  => $listener_url,
271
					'ucancel'  => $cancel_url, //if cancel back to check out
272
					'format'   => 'json' // Format: xml / json. Default: xml
273
				);
274
			
275
				//var_dump( add_query_arg( $payfast_args, $url_to_send ) ); exit;
276
				$url_to_send .= http_build_query( $payfast_args );
277
				//remote get and retrieve a session id from payfast
278
                $response = $this->remote_get( $url_to_send );
279
				
280
				if ( $response == null || $response == 'null' )
281
					return false;
282
					
283
				$payfast = json_decode( $response );
284
				//get the session from payfast, we are ready to send the buyer
285
				$session_id = $payfast->sessionID;
286
				
287
				//save to database first, we will need it
288
				add_post_meta( $payment, '_payfast_session_id', $session_id );
289
290
				//get rid of cart contents
291
				edd_empty_cart();
292
				
293
				//build an query againt, but we just need session id
294
				$params = array( 'sessionID'	=> $session_id,  );	
295
				$redirecting_to = add_query_arg( $params, 'https://www.payfast.co.za/' );
296
				//redirect to payfast
297-
			} //end statement payment 
297+
298
				exit;	
299
				
300-
		} //end statement error
300+
			 } //end statement payment
301-
		else {
301+
                     
302-
			$fail = true; // errors were detected
302+
                       
303
                } //end statement error
304
               else {
305-
		if( $fail !== false ) {
305+
                        $fail = true; // errors were detected
306-
			// if errors are present, send the user back to the purchase page so they can be corrected
306+
                } //end statement
307-
			edd_send_back_to_checkout('?payment-mode=' . $purchase_data['post_data']['edd-gateway']);
307+
               
308
                if( $fail !== false ) {
309
                        // if errors are present, send the user back to the purchase page so they can be corrected
310
                        edd_send_back_to_checkout('?payment-mode=' . $purchase_data['post_data']['edd-gateway']);
311
                } //end statement
312
		
313
	} //end process_payment()
314
	
315
	public function validate_report_back() {
316
		global $edd_options;
317
318
		// Regular Payfast notify
319
		if ( isset( $_GET['payfast'] ) && $_GET['payfast'] == 'notify' ) {
320
			do_action( 'edd_payfast_check' );
321
		} //end statement
322
	} //end validate_report_back()
323
	
324
	/**
325
	 * Extract the site's host domain for referer notify from payfast.
326
	 *
327
	 * @since 1.0
328
	 * @param string $url URL to extract
329
	 * @return host of url that given on param, or false if failed extract url
330
	 * @access private
331
	 */
332
	public function check_referer_notify( $url ) {
333
	
334
		if ( ! ( is_string( $url ) && $url ) )
335
			return false;
336
			
337
		if ( ! function_exists('parse_url') )
338
			return false;
339
			
340
		// PHP 5.3.3 or newer can throw a warning
341
		try {
342
			if ( version_compare( PHP_VERSION, '5.1.2', '>=') ) {
343
				$ref = parse_url ( $url, PHP_URL_HOST );
344
			} else {
345
				$parse_ref = parse_url( $url );
346
				if ( $parse_ref !== false && isset( $parse_ref['host'] ) )
347
					$ref	= $parse_ref['host'];
348
			}
349
		} catch (Exception $e){}
350
		
351
		// Check $ref is not empty or null, is so return that.
352
		if( empty( $ref ) || $ref = null )
353
			return false;
354
		else 
355
			return $ref;
356
	}
357
	
358
	/* 
359
	* process_payfast_notify() function
360
	* process notify that send by payfast after we send the buyer on payment
361
	*
362
	* if buyer complete the payment, we need update the payment to complete too
363
	* @since 1.0
364
	*/
365
	public function process_payfast_notify() {
366
	
367
		global $edd_options;
368
369
		// Check the request method is POST
370
		if ( isset( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] != 'POST' ) {
371
			return;
372
		} //end statement
373
		
374
			
375
		if ( isset( $_POST['status'] ) && isset( $_POST['trx_id'] ) && isset( $_POST['sid'] ) && isset( $_POST['product'] ) && isset( $_POST['quantity'] ) && isset( $_POST['total'] ) && isset( $_POST['comments'] ) ) {
376
									
377
			// setup each of the variables from payfast
378
			$payment_id = $_POST['comments'] ? $_POST['comments'] : null;
379
			$payfast_status = strtolower( $_POST['status'] ) ? strtolower( $_POST['status'] ) : null;
380
			$payfast_session = $_POST['sid'] ? $_POST['sid'] : null;
381
			$payfast_product = $_POST['product'] ? $_POST['product'] : null;
382
			$payfast_quantity = $_POST['quantity'] ? $_POST['quantity'] : null;
383
			$payfast_amount = $_POST['total'] ? $_POST['total'] : null;
384
			
385
			// retrieve the meta info for this payment
386
			$payment_meta 		= get_post_meta( $payment_id, '_edd_payment_meta', true );
387
			$payment_session	= get_post_meta( $payment_id, '_payfast_session_id', true );
388
			$payment_amount 	= edd_format_amount( $payment_meta['amount'] );
389
			
390
			
391
			// check url referrer..
392
			if( ! function_exists( 'wp_get_referer' ) )
393
				include_once( ABSPATH . 'wp-includes/functions.php' );
394
				$referer = wp_get_referer();
395
			if( empty( $referer ) )
396
				return;
397
			
398
			$ref = $this->check_referer_notify( $referer );			
399
			if ( $ref != 'payfast.co.za' )
400
				return; // referrer from payfast? if not return that.
401
			
402
			if( get_post_status( $payment_id ) == 'complete' )
403
				return; // Only complete payments once
404
			
405
			if ( edd_get_payment_gateway( $payment_id ) != 'payfast' )
406
				return; // this isn't from payfast	
407
			
408
			if( $payfast_amount != $payment_amount )
409
				return; // the prices don't match
410
			
411
			//	check the session id, this session is an unique key. generating by payfast
412
			// if this don't match, this is not from payfast or other payment
413
			if( $payfast_session != $payment_session ) 
414
				return;
415
								
416
			/* everything has been verified, update the payment to "complete"
417
			*  berhasil is Indonesian language that mean success.
418
			*/
419
			if( $payfast_status == 'berhasil' ) :
420
				edd_update_payment_status( $payment_id, 'publish' );
421
				delete_post_meta( $payment_id, '_payfast_session_id', $payment_session );
422
			endif;
423
424
			
425
		}//end statement
426
		
427
	} //end process_payfast_notify()
428
	
429
	
430
} // end EDD_Payfast Class
431
endif; // end check
432
433
/**
434
 * Throw an error if Easy Digital Download is not installed.
435
 *
436
 * @since 0.2
437
 */
438
function syaiful_payfast_missing_error_edd() {
439
	echo '<div class="error"><p>' . sprintf( __( 'Please %sinstall &amp; activate Easy Digital Downloads%s to allow this plugin to work.' ), '<a href="' . admin_url( 'plugin-install.php?tab=search&type=term&s=easy+digital+downloads&plugin-search-input=Search+Plugins' ) . '">', '</a>' ) . '</p></div>';
440
} // end syaiful_payfast_missing_error_edd()
441
442
// Throw an error if Wordpress version is below 3.4
443
function syaiful_missing_error_wordpress_version() {
444
	echo '<div class="error"><p>' . __( 'Please upgrade WordPress to the latest version to allow WordPress and this plugin to work properly.', 'edd_payfast' ) . '</p></div>';
445
} // end syaiful_missing_error_wordpress_version()
446
447
// the instance of our plugin,
448
function edd_payfast() {
449
	return EDD_Payfast::instance();
450
}
451
452
// Loader function for the plugin
453
function syaiful_edd_payfast_init() {
454
	global $wp_version;
455
456
	if ( !version_compare( $wp_version, '3.4', '>=' ) ) {
457
		add_action( 'all_admin_notices', 'syaiful_missing_error_wordpress_version' );
458
	} else if ( class_exists( 'Easy_Digital_Downloads') ) {
459
			edd_payfast(); //load our plugin
460
		} else {
461
			add_action( 'all_admin_notices', 'syaiful_payfast_missing_error_edd' );
462
		}
463
} // end syaiful_edd_payfast_init()
464
465
// tap... tap .... hi Wordpress, load our plugin please...
466
add_action( 'plugins_loaded', 'syaiful_edd_payfast_init', 20 ); //lower because waiting Easy Digital Downloads running..