1 | <?php |
||
14 | class PurchaseResponse extends AbstractResponse |
||
15 | { |
||
16 | /** |
||
17 | * @var HttpResponse HTTP response object |
||
18 | */ |
||
19 | public $response; |
||
20 | |||
21 | /** |
||
22 | * @var bool Flag indicating whether the HTTP response object returned a '200 OK' HTTP header |
||
23 | */ |
||
24 | protected $isHttpSuccess = false; |
||
25 | |||
26 | /** |
||
27 | * @var string Status code from the response that determines success |
||
28 | */ |
||
29 | protected $successStatus = 'S'; |
||
30 | |||
31 | /** |
||
32 | * Constructor |
||
33 | * |
||
34 | * Also verifies that signature supplied in the response is valid |
||
35 | * |
||
36 | * @param PurchaseRequest $request The initiating request |
||
37 | * @param HttpResponse $response HTTP response object |
||
38 | */ |
||
39 | 9 | public function __construct(PurchaseRequest $request, $response) |
|
40 | { |
||
41 | 9 | $this->response = $response; |
|
42 | |||
43 | 9 | $code = $this->response->getStatusCode(); |
|
44 | 9 | $this->isHttpSuccess = $code == 200; |
|
45 | |||
46 | 9 | $data = $response->getBody(true); |
|
47 | |||
48 | 9 | if ($this->isHttpSuccess) { |
|
49 | 7 | $data = json_decode($data, true); |
|
50 | // case of 'results' node is inconsistent between documentation and experimentation, so handle both |
||
51 | 7 | if (isset($data['results'])) { |
|
52 | 1 | $data = $data['results']; |
|
53 | 6 | } elseif (isset($data['Results'])) { |
|
54 | 7 | $data = $data['Results']; |
|
55 | } |
||
56 | } else { |
||
57 | 2 | $data = json_decode(json_encode($response->xml()->children('http://wso2.org/apimanager/security')), true); |
|
58 | } |
||
59 | |||
60 | 9 | parent::__construct($request, $data); |
|
61 | |||
62 | 9 | if ($this->isHttpSuccess) { |
|
63 | // Build and validate signature |
||
64 | // 'Merchant Transaction Password' |
||
65 | 7 | $merchantPassword = $request->getPassword(); |
|
66 | // 'Merchant Account No' |
||
67 | 7 | $merchantAccountNo = $request->getMerchantId(); |
|
68 | // 'Merchant Transaction ID' |
||
69 | 7 | $merchantTransactionId = null; |
|
70 | // 'Transaction Amount' |
||
71 | 7 | $transactionAmount = $request->getAmount(); |
|
72 | // 'Transaction ID' |
||
73 | 7 | $transactionId = null; |
|
74 | // 'Transaction Status' |
||
75 | 7 | $transactionStatus = null; |
|
76 | // 'Response Code' |
||
77 | 7 | $responseCode = null; |
|
78 | |||
79 | // make sure keys to build signature are in response |
||
80 | $response_keys = array( |
||
81 | 7 | 'merchantTransactionId' => 'merchantTranId', |
|
82 | 'transactionId' => 'transactionId', |
||
83 | 'transactionStatus' => 'txnStatus', |
||
84 | 'responseCode' => 'responseCode', |
||
85 | ); |
||
86 | 7 | foreach ($response_keys as $variable => $key) { |
|
87 | 7 | if (isset($data[$key])) { |
|
88 | 7 | ${$variable} = $data[$key]; |
|
89 | } |
||
90 | 7 | if (${$variable} === null) { |
|
91 | 7 | throw new InvalidResponseException('Invalid response from payment gateway (missing data)'); |
|
92 | } |
||
93 | } |
||
94 | // make sure variables to build signature were correctly fetched from the request |
||
95 | $request_variables = array( |
||
96 | 6 | 'merchantPassword', |
|
97 | 'merchantAccountNo', |
||
98 | 'transactionAmount', |
||
99 | ); |
||
100 | 6 | foreach ($request_variables as $variable) { |
|
101 | 6 | if (${$variable} === null) { |
|
102 | 6 | throw new InvalidRequestException('Invalid request from merchant (missing data)'); |
|
103 | } |
||
104 | } |
||
105 | $signature_data = $merchantPassword |
||
106 | 5 | .$merchantAccountNo |
|
107 | 5 | .$merchantTransactionId |
|
108 | 5 | .$transactionAmount |
|
109 | 5 | .$transactionId |
|
110 | 5 | .$transactionStatus |
|
111 | 5 | .$responseCode; |
|
112 | |||
113 | 5 | $signature = strtoupper(openssl_digest(strtoupper($signature_data), 'sha512')); |
|
114 | |||
115 | 5 | if (!isset($this->data['txnSignature2']) || $signature != $this->data['txnSignature2']) { |
|
116 | 1 | throw new InvalidResponseException('Invalid response from payment gateway (signature mismatch)'); |
|
117 | } |
||
118 | } |
||
119 | 6 | } |
|
120 | |||
121 | /** |
||
122 | * Is the response successful? |
||
123 | * |
||
124 | * Based on both HTTP status code and body content, since 200-level responses are JSON and 400/500-level are XML |
||
125 | * For example see tests/Mock/ResponseSuccess.txt |
||
126 | * |
||
127 | * @return bool |
||
128 | */ |
||
129 | 5 | public function isSuccessful() |
|
141 | |||
142 | /** |
||
143 | * What is the relevant description of the transaction response? |
||
144 | * |
||
145 | * @return string|null |
||
146 | */ |
||
147 | 6 | public function getMessage() |
|
166 | |||
167 | /** |
||
168 | * @return string|null |
||
169 | */ |
||
170 | 5 | public function getCode() |
|
179 | |||
180 | /** |
||
181 | * @return string|null |
||
182 | */ |
||
183 | 4 | public function getTransactionId() |
|
189 | |||
190 | /** |
||
191 | * @return string|null |
||
192 | */ |
||
193 | 5 | public function getTransactionReference() |
|
199 | } |
||
200 |