-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathConnect2PayClient.php
2505 lines (2162 loc) · 65.3 KB
/
Connect2PayClient.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
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/**
* Client class for the connect2pay payment page.
* The normal workflow is as follow:
* - Instantiate the class
* - Set all the required parameters of the transaction
* - Call prepareTransaction() to create the transaction
* - Call getCustomerRedirectURL() and redirect the customer to this URL
* - If receiving result via callback, use handleCallbackStatus to initialize the status from the POST request
* - If receiving result via customer redirection, use handleRedirectStatus to initialize the status from the POST data
*
* This class does not do any sanitization on received data.
* This must be done externally.
* Every text must be encoded as UTF-8 when passed to this class.
*
* PHP dependencies:
* PHP >= 5.2.0
* PHP CURL module
* PHP Mcrypt module
*
* @version 2.0.4 (20140702)
* @author Jérôme Schell <[email protected]>
* @author Yann Finck <[email protected]>
* @copyright 2011-2014 Payxpert
*
*/
class Connect2PayClient {
/**
* Payment types constants
*/
const _PAYMENT_TYPE_CREDITCARD = "CreditCard";
const _PAYMENT_TYPE_TODITOCASH = "ToditoCash";
/**
* Payment modes constants
*/
const _PAYMENT_MODE_SINGLE = "Single";
const _PAYMENT_MODE_ONSHIPPING = "OnShipping";
const _PAYMENT_MODE_RECURRENT = "Recurrent";
const _PAYMENT_MODE_INSTALMENTS = "InstalmentsPayments";
/**
* Shipping types constants
*/
const _SHIPPING_TYPE_PHYSICAL = "Physical";
const _SHIPPING_TYPE_ACCESS = "Access";
const _SHIPPING_TYPE_VIRTUAL = "Virtual";
/**
* Subscription types constants
*/
const _SUBSCRIPTION_TYPE_NORMAL = "normal";
const _SUBSCRIPTION_TYPE_LIFETIME = "lifetime";
const _SUBSCRIPTION_TYPE_ONETIME = "onetime";
const _SUBSCRIPTION_TYPE_INFINITE = "infinite";
/**
* Lang constants
*/
const _LANG_EN = "en";
const _LANG_FR = "fr";
const _LANG_ES = "es";
const _LANG_IT = "it";
/**
* ~~~~
* Subscription cancel reasons
* ~~~~
*/
/**
* Bank denial
*/
const _SUBSCRIPTION_CANCEL_BANK_DENIAL = 1000;
/**
* Canceled due to refund
*/
const _SUBSCRIPTION_CANCEL_REFUNDED = 1001;
/**
* Canceled due to retrieval request
*/
const _SUBSCRIPTION_CANCEL_RETRIEVAL = 1002;
/**
* Cancellation letter sent by bank
*/
const _SUBSCRIPTION_CANCEL_BANK_LETTER = 1003;
/**
* Chargeback
*/
const _SUBSCRIPTION_CANCEL_CHARGEBACK = 1004;
/**
* Company account closed
*/
const _SUBSCRIPTION_CANCEL_COMPANY_ACCOUNT_CLOSED = 1005;
/**
* Site account closed
*/
const _SUBSCRIPTION_CANCEL_WEBSITE_ACCOUNT_CLOSED = 1006;
/**
* Didn't like the site
*/
const _SUBSCRIPTION_CANCEL_DID_NOT_LIKE = 1007;
/**
* Disagree ('Did not do it' or 'Do not recognize the transaction')
*/
const _SUBSCRIPTION_CANCEL_DISAGREE = 1008;
/**
* Fraud from webmaster
*/
const _SUBSCRIPTION_CANCEL_WEBMASTER_FRAUD = 1009;
/**
* I could not get in to the site
*/
const _SUBSCRIPTION_CANCEL_COULD_NOT_GET_INTO = 1010;
/**
* No problem, just moving on
*/
const _SUBSCRIPTION_CANCEL_NO_PROBLEM = 1011;
/**
* Not enough updates
*/
const _SUBSCRIPTION_CANCEL_NOT_UPDATED = 1012;
/**
* Problems with the movies/videos
*/
const _SUBSCRIPTION_CANCEL_TECH_PROBLEM = 1013;
/**
* Site was too slow
*/
const _SUBSCRIPTION_CANCEL_TOO_SLOW = 1014;
/**
* The site did not work
*/
const _SUBSCRIPTION_CANCEL_DID_NOT_WORK = 1015;
/**
* Too expensive
*/
const _SUBSCRIPTION_CANCEL_TOO_EXPENSIVE = 1016;
/**
* Un-authorized signup by family member
*/
const _SUBSCRIPTION_CANCEL_UNAUTH_FAMILLY = 1017;
/**
* Undetermined reasons
*/
const _SUBSCRIPTION_CANCEL_UNDETERMINED = 1018;
/**
* Webmaster requested to cancel
*/
const _SUBSCRIPTION_CANCEL_WEBMASTER_REQUESTED = 1019;
/**
* I haven't received my item
*/
const _SUBSCRIPTION_CANCEL_NOTHING_RECEIVED = 1020;
/**
* The item was damaged or defective
*/
const _SUBSCRIPTION_CANCEL_DAMAGED = 1021;
/**
* The box was empty
*/
const _SUBSCRIPTION_CANCEL_EMPTY_BOX = 1022;
/**
* The order was incomplete
*/
const _SUBSCRIPTION_CANCEL_INCOMPLETE_ORDER = 1023;
/**
* Field content constant
*/
const _UNAVAILABLE = "NA";
const _UNAVAILABLE_COUNTRY = "ZZ";
private static $API_ROUTES = array(/* */
"TRANS_PREPARE" => "/transaction/prepare", /* */
"TRANS_STATUS" => "/transaction/:merchantToken/status", /* */
"TRANS_DOPAY" => "/transaction/:customerToken", /* */
"SUB_CANCEL" => "/subscription/:subscriptionID/cancel");
protected $fieldsRequired = array('orderID', 'currency', 'amount', 'shippingType', 'paymentMode');
protected $fieldsSize = array('afPassword' => 64, 'currency' => 3, 'ctrlRedirectURL' => 2048, 'ctrlCallbackURL' => 2048, 'ctrlCustomData' => 2048);
protected $fieldsValidate = array('afClientId' => 'isInt', 'afPassword' => 'isString', 'shopperID' => 'isInt', 'shopperEmail' => 'isEmail',
'shipToCountryCode' => 'isCountryName', 'shopperCountryCode' => 'isCountryName', 'orderID' => 'isString', 'orderDescription' => 'isString',
'currency' => 'isString', 'amount' => 'isInt', 'orderTotalWithoutShipping' => 'isInt', 'orderShippingPrice' => 'isInt', 'orderDiscount' => 'isInt',
'orderFOLanguage' => 'isString', 'shippingType' => 'isShippingType', 'shippingName' => 'isString', 'paymentType' => 'isPayment',
'paymentMode' => 'isPaymentMode', 'offerID' => 'isInt', 'subscriptionType' => 'isSubscriptionType', 'trialPeriod' => 'isString', 'rebillAmount' => 'isInt',
'rebillPeriod' => 'isString', 'rebillMaxIteration' => 'isInt', 'ctrlRedirectURL' => 'isAbsoluteUrl', 'ctrlCallbackURL' => 'isAbsoluteUrl',
'timeOut' => 'isString', 'merchantNotification' => 'isBool', 'merchantNotificationTo' => 'isEmail', 'merchantNotificationLang' => 'isString',
'themeID' => 'isInt');
protected $fieldsJSON = array('afClientId', 'afPassword', 'apiVersion', 'shopperID', 'shopperEmail', 'shipToFirstName', 'shipToLastName', 'shipToCompany',
'shipToPhone', 'shipToAddress', 'shipToState', 'shipToZipcode', 'shipToCity', 'shipToCountryCode', 'shopperFirstName', 'shopperLastName', 'shopperPhone',
'shopperAddress', 'shopperState', 'shopperZipcode', 'shopperCity', 'shopperCountryCode', 'shopperCompany', 'shopperLoyaltyProgram', 'orderID',
'orderDescription', 'currency', 'amount', 'orderTotalWithoutShipping', 'orderShippingPrice', 'orderDiscount', 'orderFOLanguage', 'orderCartContent',
'shippingType', 'shippingName', 'paymentType', 'paymentMode', 'secure3d', 'offerID', 'subscriptionType', 'trialPeriod', 'rebillAmount', 'rebillPeriod',
'rebillMaxIteration', 'ctrlCustomData', 'ctrlRedirectURL', 'ctrlCallbackURL', 'timeOut', 'merchantNotification', 'merchantNotificationTo',
'merchantNotificationLang', 'themeID');
private $apiVersion = "002.01";
/**
* URL of the connect2pay application
*
* @var string
*/
private $url;
/**
* Login for the connect2pay application
*
* @var string
*/
private $merchant;
/**
* Password for the connect2pay application
*
* @var string
*/
private $password;
// ~~~~
// Transaction related data
// ~~~~
// Authentication Fields
/**
* Client ID for the antifraud sytem
*
* @var integer
*/
private $afClientId;
/**
* Password for the antifraud system
*
* @var string
*/
private $afPassword;
/**
* Force the transaction to use Secure 3D
*
* @var Boolean
*/
private $secure3d;
// Customer fields
/**
* Merchant unique customer numeric id
*
* @var integer
*/
private $shopperID;
/**
* Customer email address
*
* @var string
*/
private $shopperEmail;
/**
* Customer first name for shipping
*
* @var string
*/
private $shipToFirstName;
/**
* Customer last name for shipping
*
* @var string
*/
private $shipToLastName;
/**
* Customer company name for shipping
*
* @var string
*/
private $shipToCompany;
/**
* Customer phone for shipping ; if many, separate by ";"
*
* @var string
*/
private $shipToPhone;
/**
* Customer address for shipping
*
* @var string
*/
private $shipToAddress;
/**
* Customer state for shipping
*
* @var string
*/
private $shipToState;
/**
* Customer ZIP Code for shipping
*
* @var string
*/
private $shipToZipcode;
/**
* Customer city for shipping
*
* @var string
*/
private $shipToCity;
/**
* Customer country for shipping
*
* @var string
*/
private $shipToCountryCode;
/**
* Customer first name for invoicing
*
* @var string
*/
private $shopperFirstName;
/**
* Customer last name for invoicing
*
* @var string
*/
private $shopperLastName;
/**
* Customer phone for invoicing ; if many, separate by ";"
*
* @var string
*/
private $shopperPhone;
/**
* Customer address for invoicing
*
* @var string
*/
private $shopperAddress;
/**
* Customer state for invoicing
*
* @var string
*/
private $shopperState;
/**
* Customer ZIP Code for invoicing
*
* @var string
*/
private $shopperZipcode;
/**
* Customer city for invoicing
*
* @var string
*/
private $shopperCity;
/**
* Customer country for invoicing
*
* @var string
*/
private $shopperCountryCode;
/**
* Customer company name for invoicing
*
* @var string
*/
private $shopperCompany;
/**
* Customer Loyalty Program name
*
* @var string
*/
private $shopperLoyaltyProgram;
// Order Fields
/**
* Merchant internal unique order ID
*
* @var string
*/
private $orderID;
/**
* Sum up of the order to display on the payment page
*
* @var string
*/
private $orderDescription;
/**
* Currency for the current order
*
* @var string
*/
private $currency;
/**
* The transaction amount in cents (for 1€ => 100)
*
* @var integer
*/
private $amount;
/**
* The transaction amount in cents, without shipping fee
*
* @var integer
*/
private $orderTotalWithoutShipping;
/**
* The shipping amount in cents (for 1€ => 100)
*
* @var integer
*/
private $orderShippingPrice;
/**
* The discount amount in cents (for 1€ => 100)
*
* @var integer
*/
private $orderDiscount;
/**
* Language of the Front Office used to validate the order
*
* @var string
*/
private $orderFOLanguage;
/**
* Product or service bought - see details below
*
* @var array[](integer CartProductId, string CartProductName, float
* CartProductUnitPrice,
* integer CartProductQuantity, string CartProductBrand, string
* CartProductMPN,
* string CartProductCategoryName, integer CartProductCategoryID)
*/
private $orderCartContent;
// Shipping Fields
/**
* Type can be either : Physical (for physical goods), Virtual (for
* dematerialized goods), Access (for protected content)
*
* @var string
*/
private $shippingType;
/**
* In case of Physical shipping type, name of the shipping company
*
* @var string
*/
private $shippingName;
// Payment Detail Fields
/**
* Can be CreditCard (default) or ToditoCash.
* This will change the type of the payment page displayed.
*
* @var string
*/
private $paymentType;
/**
* Can be either : Single, OnShipping, Recurrent, InstalmentsPayments
*
* @var string
*/
private $paymentMode;
/**
* Predefined price point with initial and rebill period (for Recurrent,
* InstalmentsPayments payment types)
*
* @var integer
*/
private $offerID;
/**
* Type of subscription.
*
* @var string
*/
private $subscriptionType;
/**
* Number of days in the initial period (for Recurrent, InstalmentsPayments
* payment types)
*
* @var integer
*/
private $trialPeriod;
/**
* Number in minor unit, amount to be rebilled after the initial period (for
* Recurrent, InstalmentsPayments payment types)
*
* @var integer
*/
private $rebillAmount;
/**
* Number of days next re-billing transaction will be settled in (for
* Recurrent, InstalmentsPayments payment types)
*
* @var integer
*/
private $rebillPeriod;
/**
* Number of re-billing transactions that will be settled (for Recurrent,
* InstalmentsPayments payment types)
*
* @var integer
*/
private $rebillMaxIteration;
// Template and Control Fields
/**
* The URL where to redirect the customer after the transaction processing
*
* @var string
*/
private $ctrlRedirectURL;
/**
* A URL that will be notified of the status of the transaction
*
* @var string
*/
private $ctrlCallbackURL;
/**
* Custom data that will be returned back with the status of the transaction
*
* @var string
*/
private $ctrlCustomData;
/**
* Validity for the payment link in ISO 8601 duration format.
* See http://en.wikipedia.org/wiki/ISO_8601.
* For example: 2 days => P2D, 1 month => P1M
*
* @var string
*/
private $timeOut;
/**
* Whether or not to send notification to the merchant after payment
* processing
*
* @var boolean
*/
private $merchantNotification;
/**
* Mail address to send merchant notification to
*
* @var string
*/
private $merchantNotificationTo;
/**
* Lang to use in merchant notification (defaults to the customer lang)
*
* @var string
*/
private $merchantNotificationLang;
/**
* Select a predefined payment page template
*
* @var integer
*/
private $themeID;
// Data returned from prepare call
private $returnCode;
private $returnMessage;
private $merchantToken;
private $customerToken;
// Data returned from status call
private $status;
// Internal data
private $clientErrorMessage;
// HTTP Proxy data
private $proxy_host = null;
private $proxy_port = null;
private $proxy_username = null;
private $proxy_password = null;
// Internal Currency Helper
private $currencyHelper = null;
// Path to the certificates file for SSL verification
private $sslCAFile = null;
private $extraCurlOptions = array();
/**
* Instantiate a new connect2pay client
*
* @param string $url
* The URL of the connect2pay application
* @param string $merchant
* The login of the merchant on connect2pay
* @param string $password
* The password of the merchant on connect2pay
* @param array $data
* Data for the transaction to create (optional)
*/
public function __construct($url, $merchant, $password, $data = null) {
$this->url = preg_replace('/\/*$/', '', $url);
$this->merchant = $merchant;
$this->password = $password;
if ($data != null && is_array($data)) {
foreach ($data as $var => $value) {
if (property_exists($this, $var)) {
$this->$var = $value;
}
}
}
}
/**
* Set the parameter in the case of the use of an outgoing proxy
*
* @param string $host
* The proxy host.
* @param int $port
* The proxy port.
* @param string $username
* The proxy username.
* @param string $password
* The proxy password.
*/
public function useProxy($host, $port, $username = null, $password = null) {
$this->proxy_host = $host;
$this->proxy_port = $port;
$this->proxy_username = $username;
$this->proxy_password = $password;
}
/**
* Force the validation of the Connect2Pay SSL certificate.
*
* @param string $certFilePath
* The path to the PEM file containing the certification chain.
* If not set, defaults to
* "_current-dir_/ssl/connect2pay-signing-ca-cert.pem"
*/
public function forceSSLValidation($certFilePath = null) {
$this->sslCAFile = ($certFilePath != null) ? $certFilePath : dirname(__FILE__) . "/ssl/connect2pay-signing-ca-cert.pem";
}
/**
* Add extra curl options
*/
public function setExtraCurlOption($name, $value) {
$this->extraCurlOptions[$name] = $value;
}
/**
* Prepare a new transaction on connect2pay application.
* This method will validate the transaction data and call
* the connect2pay application to create a new transaction.
* The fields returnCode, returnMessage, merchantToken and
* customerToken will be populated according to the call result.
*
* @return boolean true if creation is successful, false otherwise
*/
public function prepareTransaction() {
if ($this->validate()) {
$trans = array();
if (isset($this->afClientId) && (!is_array($this->orderCartContent) || sizeof($this->orderCartContent) <= 0)) {
$this->setDefaultOrderCartContent();
}
foreach ($this->fieldsJSON as $fieldName) {
if (is_array($this->{$fieldName}) || !C2PValidate::isEmpty($this->{$fieldName})) {
$trans[$fieldName] = $this->{"get" . ucfirst($fieldName)}();
}
}
// Only PHP >= 5.4 has JSON_UNESCAPED_SLASHES option
$post_data = str_replace('\\/', '/', json_encode($trans));
$url = $this->url . Connect2PayClient::$API_ROUTES['TRANS_PREPARE'];
$result = $this->doPost($url, $post_data);
if ($result != null && is_array($result)) {
$this->returnCode = $result["code"];
$this->returnMessage = $result["message"];
if ($this->returnCode == "200") {
$this->merchantToken = $result["merchantToken"];
$this->customerToken = $result["customerToken"];
return true;
} else {
$this->clientErrorMessage = $this->returnMessage;
}
}
} else {
$this->clientErrorMessage = "The transaction is not valid.";
}
return false;
}
/**
* Do a transaction status request on the connect2pay application.
*
* @param string $merchantToken
* The merchant token related to this transaction
* @return The TransactionStatus object of the transaction or null on error
*/
public function getTransactionStatus($merchantToken) {
if ($merchantToken != null && strlen(trim($merchantToken)) > 0) {
$url = $this->url . str_replace(":merchantToken", $merchantToken, Connect2PayClient::$API_ROUTES['TRANS_STATUS']);
$result = $this->doGet($url, array(), false);
if ($result != null && is_object($result)) {
$this->initStatus($result);
if (isset($this->status)) {
return $this->status;
}
}
}
return null;
}
/**
* Do a subscription cancellation.
*
* @param int $subscriptionID
* Identifier of the subscription to cancel
* @param int $cancelReason
* Identifier of the cancelReason (see _SUBSCRIPTION_CANCEL_*
* constants)
* @return The result code of the operation (200 for success) or null on
* failure
*/
public function cancelSubscription($subscriptionID, $cancelReason) {
if ($subscriptionID != null && is_numeric($subscriptionID) && isset($cancelReason) && is_numeric($cancelReason)) {
$url = $this->url . str_replace(":subscriptionID", $subscriptionID, Connect2PayClient::$API_ROUTES['SUB_CANCEL']);
$trans = array();
$trans["apiVersion"] = $this->apiVersion;
$trans["cancelReason"] = intval($cancelReason);
$result = $this->doPost($url, json_encode($trans));
if ($result != null && is_array($result)) {
$this->clientErrorMessage = $result["message"];
return $result["code"];
}
} else {
$this->clientErrorMessage = "subscriptionID and cancelReason must be not null and numeric";
}
return null;
}
/**
* Handle the callback done by the connect2pay application after
* a transaction processing.
* This will populate the status field that can be retrieved by calling
* getStatus().
*
* @return true on succes or false on error
*/
public function handleCallbackStatus() {
// Read the body of the request
$body = @file_get_contents('php://input');
if ($body != null && strlen(trim($body)) > 0) {
$status = json_decode(trim($body), false);
if ($status != null && is_object($status)) {
$this->initStatus($status);
return true;
}
}
return false;
}
/**
* Handle the data received by the POST done when connect2pay redirects
* the customer to the merchant website.
* This will populate the status field that can be retrieved by calling
* getStatus().
*
* @param string $encryptedData
* The content of the 'data' field posted
* @param string $merchantToken
* The merchant token related to this transaction
* @return boolean True on success or false on error
*/
public function handleRedirectStatus($encryptedData, $merchantToken) {
$key = $this->urlsafe_base64_decode($merchantToken);
$binData = $this->urlsafe_base64_decode($encryptedData);
// Decrypting
$json = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $binData, MCRYPT_MODE_ECB);
if ($json) {
// Remove PKCS#5 padding
$json = $this->pkcs5_unpad($json);
$status = json_decode($json, false);
if ($status != null && is_object($status)) {
$this->initStatus($status);
return true;
}
}
return false;
}
/**
* Returns the URL to redirect the customer to after a transaction
* creation.
*
* @return string The URL to redirect the customer to.
*/
public function getCustomerRedirectURL() {
return $this->url . str_replace(":customerToken", $this->customerToken, Connect2PayClient::$API_ROUTES['TRANS_DOPAY']);
}
/**
* Validate the current transaction data.
*
* @return boolean True if transaction data are valid, false otherwise
*/
public function validate() {
$arrErrors = array();
$arrErrors = $this->validateFields();
if (sizeof($arrErrors) > 0) {
foreach ($arrErrors as $error) {
$this->clientErrorMessage .= $error . " * ";
}
return false;
}
return true;
}
private function doGet($url, $params, $assoc = true) {
return $this->doHTTPRequest("GET", $url, $params, $assoc);
}
private function doPost($url, $data, $assoc = true) {
return $this->doHTTPRequest("POST", $url, $data, $assoc);
}
private function doHTTPRequest($type, $url, $data, $assoc = true) {
$curl = curl_init();
if ($type === "GET") {
// In that case, $data is the array of params to add in the URL
if (is_array($data) && count($data) > 0) {
$urlParams = array();
foreach ($data as $param => $value) {
$urlParams[] = urlencode($param) . "=" . urlencode($value);
}
if (count($urlParams) > 0) {
$url .= "?" . implode("&", $urlParams);
}
}
} elseif ($type === "POST") {
// In that case, $data is the body of the request
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
} else {
$this->clientErrorMessage = "Bad HTTP method specified.";
return null;
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, $this->merchant . ":" . $this->password);
if ($this->sslCAFile != null) {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_CAINFO, $this->sslCAFile);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
} else {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
}
if ($this->proxy_host != null && $this->proxy_port != null) {
curl_setopt($curl, CURLOPT_PROXY, $this->proxy_host);
curl_setopt($curl, CURLOPT_PROXYPORT, $this->proxy_port);
if ($this->proxy_username != null && $this->proxy_password != null) {
curl_setopt($curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_PROXYUSERPWD, $this->proxy_username . ":" . $this->proxy_password);
}
}
// Extra Curl Options
foreach ($this->extraCurlOptions as $name => $value) {
curl_setopt($curl, $name, $value);
}
if (!isset($this->extraCurlOptions[CURLOPT_SSL_CIPHER_LIST])) {
// Enable the default RC4 ciphers as it is disabled in recent CURL
// releases
// See DEFAULT_CIPHER_SELECTION in lib/vtls/openssl.h in CURL sources
curl_setopt($curl, CURLOPT_SSL_CIPHER_LIST, "ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW");
}
$json = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($httpCode != 200) {
$this->clientErrorMessage = "Received HTTP code " . $httpCode . " from connect2pay.";
} else {
if ($json !== false) {
$result = json_decode($json, $assoc);
if ($result != null) {
return $result;
} else {
$this->clientErrorMessage = "JSON decoding error.";
}
} else {
$this->clientErrorMessage = "Error requesting " . $connect2pay;
}
}
return null;
}
private function initStatus($status) {
if ($status != null && is_object($status)) {
$this->status = new TransactionStatus();
$reflector = new ReflectionClass('TransactionStatus');
$properties = $reflector->getProperties();
foreach ($properties as $property) {
if (isset($status->{$property->getName()})) {
$this->status->{"set" . ucfirst($property->getName())}($status->{$property->getName()});
}
}
}
}
private function urlsafe_base64_decode($string) {
return base64_decode(strtr($string, '-_', '+/'));
}
private function pkcs5_unpad($text) {
$pad = ord($text{strlen($text) - 1});
if ($pad > strlen($text)) {
// The initial text was empty
return "";
}
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
// The length of the padding sequence is incorrect
return false;
}
return substr($text, 0, -1 * $pad);
}
public function getApiVersion() {
return $this->apiVersion;
}
public function getURL() {
return $this->url;
}
public function setURL($url) {
$this->url = $url;
return ($this);
}
public function getMerchant() {
return $this->merchant;
}
public function setMerchant($merchant) {
$this->merchant = $merchant;
return ($this);
}
public function getPassword() {
return $this->password;
}
public function setPassword($password) {
$this->password = $password;
return ($this);
}
public function getAfClientId() {
return $this->afClientId;
}
public function setAfClientId($afClientId) {
$this->afClientId = (int) $afClientId;
return ($this);
}
public function getAfPassword() {
return $this->afPassword;
}
public function setAfPassword($afPassword) {
$this->afPassword = (string) $afPassword;