forked from thenbrent/paypal-digital-goods
-
Notifications
You must be signed in to change notification settings - Fork 0
/
paypal-digital-goods.class.php
404 lines (326 loc) · 14 KB
/
paypal-digital-goods.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
<?php
/**
* An interface for the PayPal Digital Goods with Express Checkout API with an emphasis on being friendly to humans.
*
* @package PayPal
*
* @license GPLv3 see license.txt
* @copyright 2011 Leonard's Ego Pty. Ltd.
*/
require_once( 'paypal-configuration.class.php' );
abstract class PayPal_Digital_Goods {
/**
* A array of name value pairs representing the seller's API Username, Password & Signature.
*
* These are passed to the class via the parameters in the constructor.
*/
private $api_credentials;
/**
* The PayPal API Version.
* Must be 65.1 or newer for Digital Goods. Defaults to 76
*/
private $version;
/**
* The PayPal API URL Defaults to https://api-3t.sandbox.paypal.com/nvp when in
* sandbox mode and https://api-3t.paypal.com/nvp when live.
*/
private $endpoint;
/**
* The PayPal URL for initialing the popup payment process.
*
* Defaults to https://www.sandbox.paypal.com/incontext?token=**** for sandbox mode
* and https://www.paypal.com/incontext?token=**** in live mode.
*/
private $checkout_url;
/**
* Stores the token once it has been acquired from PayPal
*/
protected $token;
/**
* The URL on your site that the purchaser is sent to upon completing checkout.
*/
public $return_url;
/**
* The URL on your site that the purchaser is sent to when cancelling a payment during the checkout process.
*/
public $cancel_url;
/**
* Creates a PayPal Digital Goods Object configured according to the parameters in the args associative array.
*
* Available $args parameters:
* - cancel_url, string, required. The URL on your site that the purchaser is sent to when cancelling a payment during the checkout process.
* - return_url, string, required. The URL on your site that the purchaser is sent to upon completing checkout.
* - notify_url, string, optional. The URL for receiving Instant Payment Notification (IPN) about this transaction.
* - sandbox, boolean. Flag to indicate whether to use the PayPal Sandbox or live PayPal site. Default true - use sandbox.
* - currency, string. The ISO 4217 currency code for the transaction. Default USD.
* - callback, string. URL to which the callback request from PayPal is sent. It must start with HTTPS for production integration. It can start with HTTPS or HTTP for sandbox testing
* - business_name, string. A label that overrides the business name in the PayPal account on the PayPal hosted checkout pages.
* - version, string. The PayPal API version. Must be a minimum of 65.1. Default 76.0
*
* @param api_credentials, required, a name => value array containing your API username, password and signature.
* @param args, named parameters to customise the subscription and checkout process. See description for available parameters.
*/
public function __construct( $args = array() ){
if( '' == PayPal_Digital_Goods_Configuration::username() || '' == PayPal_Digital_Goods_Configuration::password() || '' == PayPal_Digital_Goods_Configuration::signature() )
exit( 'You must specify your PayPal API username, password & signature in the $api_credentials array. For details of how to ' );
elseif( ( empty( $args['return_url'] ) && '' == PayPal_Digital_Goods_Configuration::username() ) || ( empty( $args['cancel_url'] ) && '' == PayPal_Digital_Goods_Configuration::cancel_url() ) )
exit( 'You must specify a return_url & cancel_url.' );
$defaults = array(
'sandbox' => true,
'version' => '76.0',
'currency' => 'USD',
'callback' => '',
'business_name' => '',
'return_url' => PayPal_Digital_Goods_Configuration::return_url(),
'cancel_url' => PayPal_Digital_Goods_Configuration::cancel_url(),
'notify_url' => ''
);
$args = array_merge( $defaults, $args );
$this->currency = $args['currency'];
$this->callback = $args['callback'];
$this->business_name = $args['business_name'];
$this->return_url = $args['return_url'];
$this->cancel_url = $args['cancel_url'];
$this->notify_url = $args['notify_url'];
}
/**
* Map this object's API credentials to the PayPal NVP format for posting to the API.
*
* Abstracted from @see get_payment_details_url for readability.
*/
protected function get_api_credentials_url(){
return 'USER=' . urlencode( PayPal_Digital_Goods_Configuration::username() )
. '&PWD=' . urlencode( PayPal_Digital_Goods_Configuration::password() )
. '&SIGNATURE=' . urlencode( PayPal_Digital_Goods_Configuration::signature() )
. '&VERSION='. urlencode( PayPal_Digital_Goods_Configuration::version() );
}
/**
* Map this object's transaction details to the PayPal NVP format for posting to PayPal.
*
* @param $action, string. The PayPal NVP API action to create the URL for. One of SetExpressCheckout, CreateRecurringPaymentsProfile or GetRecurringPaymentsProfileDetails.
* @param $profile_id, (optional) string. A PayPal Recurrent Payment Profile ID, required for GetRecurringPaymentsProfileDetails operation.
* @return string A URL which can be called with the @see call_paypal() method to perform the appropriate API operation.
*/
protected function get_payment_details_url( $action, $profile_or_transaction_id = '' ){
if( empty( $this->token ) && isset( $_GET['token'] ) )
$this->token = $_GET['token'];
// Setup the Payment Details
$api_request = $this->get_api_credentials_url();
// Parameters to Request Recurring Payment Token
if( 'SetExpressCheckout' == $action ) {
$api_request .= '&METHOD=SetExpressCheckout'
. '&RETURNURL=' . urlencode( $this->return_url )
. '&CANCELURL=' . urlencode( $this->cancel_url );
if( ! empty( $this->notify_url ) )
$api_request .= '&PAYMENTREQUEST_0_NOTIFYURL=' . urlencode( $this->notify_url );
if( ! empty( $this->callback ) )
$api_request .= '&CALLBACK=' . urlencode( $this->callback );
if( ! empty( $this->business_name ) )
$api_request .= '&BRANDNAME=' . urlencode( $this->business_name );
} elseif ( 'GetExpressCheckoutDetails' == $action ) {
$api_request .= '&METHOD=GetExpressCheckoutDetails'
. '&TOKEN=' . $this->token;
}
return $api_request;
}
/**
* Creates a payment profile with PayPal represented by the token it returns.
*
* When a buyer clicks the Pay with PayPal button, this function calls the PayPal SetExpressCheckout API operation.
*
* It passes payment details of the items purchased and therefore, set_payment_details() must have been called
* before this function.
*
* Return:
*
*/
public function request_checkout_token(){
$response = $this->call_paypal( 'SetExpressCheckout' );
$this->token = $response['TOKEN'];
return $response;
}
/**
* Calls the PayPal GetExpressCheckoutDetails methods and returns a more nicely formatted response
*
* Called internally on return from set_express_checkout(). Can be called anytime to get details of
* a transaction for which you have the Token.
*/
public function get_checkout_details(){
return $this->call_paypal( 'GetExpressCheckoutDetails' );
}
/**
* Post to PayPal
*
* Makes an API call using an NVP String and an Endpoint. Based on code available here: https://www.x.com/blogs/Nate/2011/01/07/digital-goods-with-express-checkout-in-php
*
* @param action, string, required. The API operation to be performed, eg. GetExpressCheckoutDetails. The action is abstracted from you (the developer) by the appropriate helper function eg. GetExpressCheckoutDetails via get_checkout_details()
*/
protected function call_paypal( $action, $profile_id = '' ){
// Use the one function for all PayPal API operations
$api_parameters = $this->get_payment_details_url( $action, $profile_id );
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, PayPal_Digital_Goods_Configuration::endpoint() );
curl_setopt( $ch, CURLOPT_VERBOSE, 1 );
// Turn off server and peer verification
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_POST, 1 );
// Set the API parameters for this transaction
curl_setopt( $ch, CURLOPT_POSTFIELDS, $api_parameters );
// Request response from PayPal
$response = curl_exec( $ch );
// If no response was received from PayPal there is no point parsing the response
if( ! $response )
exit( $action . ' failed: ' . curl_error( $ch ) . '(' . curl_errno( $ch ) . ')' );
curl_close( $ch );
// An associative array is more usable than a parameter string
parse_str( $response, $parsed_response );
if( ( 0 == sizeof( $parsed_response ) ) || ! array_key_exists( 'ACK', $parsed_response ) )
exit( "Invalid HTTP Response for POST request($api_parameters) to " . PayPal_Digital_Goods_Configuration::endpoint() );
if( $parsed_response['ACK'] == 'Failure' )
exit( "Calling PayPal with action $action has Failed: " . $parsed_response['L_LONGMESSAGE0'] );
return $parsed_response;
}
/**
* Returns this instance of the class's token.
*/
public function token(){
if( empty( $this->token ) )
$this->request_checkout_token();
return $this->token;
}
/**
* The Javascript to invoke the digital goods in context checkout process.
*
* No need to call this function manually, required scripts are automatically printed with @see print_buy_buttion().
* If you do print this script manually, print it after the button in the DOM to ensure the
* click event is properly hooked.
*/
public function get_script( $args = array() ){
if( empty( $args['element_id'] ) )
$args['element_id'] = 'paypal-submit';
$dg_script = '<script src ="https://www.paypalobjects.com/js/external/dg.js" type="text/javascript"></script>'
. '<script>'
. 'var dg = new PAYPAL.apps.DGFlow({'
. 'trigger: "' . $args['element_id'] . '"' // the ID of the HTML element which calls setExpressCheckout
. '}); </script>';
return $dg_script;
}
/**
* Create and return the Buy (or Subscribe) button for your page.
*
* The button can be output either as a link to a image submit button, link to a page
* or link directly to PayPal (default).
*
* The simplest method is to pass no parameters and have the button be a link directly to
* PayPal; however, the drawback of this approach is a slower load time for the page on which
* the button is included.
*
* @param args array. Name => value parameters to customise the buy button.
* 'id' string. The id of the submit element. Defaults to 'paypal-submit'.
* 'element' string. The type of element to use as the button. Either anchor or submit. Default 'anchor'.
* 'href' string. The URL for 'anchor' tag. Ignored when 'element' is 'submit'. Default $this->checkout_url.
* 'get_token' boolean. Whether to include a token with the href. Overridden by 'element' when it is 'submit'.
* 'type' string. Type of element to output, either anchor or image/submit. Defaults to 'anchor'.
*/
public function get_buy_button( $args = array() ){
$defaults = array( 'id' => 'paypal-submit',
'type' => 'anchor',
'href' => PayPal_Digital_Goods_Configuration::checkout_url(),
'alt' => 'Submit',
'get_token' => true
);
$args = array_merge( $defaults, $args );
if( $args['type'] == 'anchor' ) {
if( $args['get_token'] == true && empty( $this->token ) )
$this->request_checkout_token();
// Include the token in the href if the default href is not overridden
if( $args['href'] == PayPal_Digital_Goods_Configuration::checkout_url() )
$args['href'] .= $this->token;
$button = '<a href="' . $args['href'] . '" id="' . $args['id'] . '" alt="' . $args['alt'] . '"><img src="https://www.paypal.com/en_US/i/btn/btn_dg_pay_w_paypal.gif" border="0" /></a>';
} else {
$button = '<input type="image" id="' . $args['id'] . '" alt="' . $args['alt'] . '" src="https://www.paypal.com/en_US/i/btn/btn_dg_pay_w_paypal.gif">';
}
return $button;
}
/**
* Print the Buy (or Subscribe) button for this API object as well as the scripts
* required by the button.
*
* If you want to manually insert the script at a different position in your page,
* you can manually call @see get_buy_button() & @see get_script().
*
* @uses get_buy_button()
* @uses get_script()
*/
public function print_buy_button( $args = array() ){
echo $this->get_buy_button( $args );
echo $this->get_script( $args );
}
/**
* Returns the Checkout URL including a token for this transaction.
*/
public function get_checkout_url() {
if( empty( $this->token ) )
$this->request_checkout_token();
// Include the token in the href if the default href is not overridden
return PayPal_Digital_Goods_Configuration::checkout_url() . $this->token;
}
/**
* Get the symbol associated with a currency, optionally specified with '$currency_code' parameter.
*
* Will always return the symbol and can optionally also print the symbol.
*
* @param $currency_code, string, optional, the ISO 4217 Code of the currency for which you want the Symbol, default the currency code of this object
* @param $echo bool, Optionally print the symbol before returning it.
**/
public function get_currency_symbol( $currency_code = '', $echo = false ){
if( empty( $currency_code ) )
$currency_code = PayPal_Digital_Goods_Configuration::currency();
switch( $currency_code ) {
case 'AUD' :
case 'CAD' :
case 'NZD' :
case 'SGD' :
case 'HKD' :
case 'TWD' :
case 'USD' :
$currency_symbol = '$';
break;
case 'DKK' :
case 'NOK' :
case 'SEK' :
$currency_symbol = 'kr';
break;
case 'EUR' :
$currency_symbol = '€';
break;
case 'GBP' :
$currency_symbol = '£';
break;
case 'JPY' :
$currency_symbol = '¥';
break;
case 'CZK' :
$currency_symbol = 'Kč';
break;
case 'HUF' :
$currency_symbol = 'Ft';
break;
case 'PLN' :
$currency_symbol = 'zł';
break;
case 'CHF' :
$currency_symbol = 'CHF';
break;
}
if( $echo )
echo $currency_symbol;
return $currency_symbol;
}
/**
* Get the description of this payment
*/
abstract public function get_description();
}