-
Notifications
You must be signed in to change notification settings - Fork 78
/
Copy pathAuthorizeRequest.php
345 lines (293 loc) · 10.4 KB
/
AuthorizeRequest.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
<?php
namespace Omnipay\SagePay\Message\Form;
/**
* Sage Pay Form Authorize Request.
*/
use Omnipay\SagePay\Message\DirectAuthorizeRequest;
use Omnipay\Common\Exception\InvalidRequestException;
class AuthorizeRequest extends DirectAuthorizeRequest
{
/**
* Fields accepted by the Form API.
* "true" fields are mandatory, "false" fields are optional.
* The DeliveryState is conditionally mandatory.
*/
protected $validFields = [
'AccountType' => false,
'VendorTxCode' => true,
'Amount' => true,
'Currency' => true,
'Description' => true,
'SuccessURL' => true,
'FailureURL' => true,
'CustomerName' => false,
'CustomerEMail' => false,
'VendorEMail' => false,
'SendEMail' => false,
'EmailMessage' => false,
'BillingSurname' => true,
'BillingFirstnames' => true,
'BillingAddress1' => true,
'BillingAddress2' => false,
'BillingCity' => true,
'BillingPostCode' => true,
'BillingCountry' => true,
'BillingState' => false,
'BillingPhone' => false,
'DeliverySurname' => true,
'DeliveryFirstnames' => true,
'DeliveryAddress1' => true,
'DeliveryAddress2' => false,
'DeliveryCity' => true,
'DeliveryPostCode' => true,
'DeliveryCountry' => true,
'DeliveryState' => false,
'DeliveryPhone' => false,
'Basket' => false,
'AllowGiftAid' => false,
'ApplyAVSCV2' => false,
'Apply3DSecure' => false,
'BillingAgreement' => false,
'BasketXML' => false,
'CustomerXML' => false,
'SurchargeXML' => false,
'VendorData' => false,
'ReferrerID' => false,
'Language' => false,
'Website' => false,
'FIRecipientAcctNumber' => false,
'FIRecipientSurname' => false,
'FIRecipientPostcode' => false,
'FIRecipientDoB' => false,
];
/**
* Get the full set of Sage Pay Form data, most of which is encrypted.
* TxType is only PAYMENT, DEFERRED or AUTHENTICATE
*
* @reurn array
*/
public function getData()
{
$this->validate('currency', 'description', 'encryptionKey', 'returnUrl');
// The test mode is included to determine the redirect URL.
return [
'VPSProtocol' => $this->VPSProtocol,
'TxType' => $this->getTxType(),
'Vendor' => $this->getVendor(),
'Crypt' => $this->generateCrypt($this->getCryptData()),
'TestMode' => $this->getTestMode(),
];
}
/**
* @return array the data required to be encoded into the form crypt field.
* @throws InvalidRequestException if any mandatory fields are missing
*/
public function getCryptData()
{
$data = $this->getBaseAuthorizeData();
// Some [optional] parameters specific to Sage Pay Form..
if ($this->getCustomerName() !== null) {
$data['CustomerName'] = $this->getCustomerName();
}
if ($this->getVendorEmail() !== null) {
$data['VendorEMail'] = $this->getVendorEmail();
}
if ($this->getEmailMessage() !== null) {
$data['EmailMessage'] = $this->getEmailMessage();
}
if ($this->getAllowGiftAid() !== null) {
$data['AllowGiftAid'] = (bool)$this->getAllowGiftAid()
? static::ALLOW_GIFT_AID_YES : static::ALLOW_GIFT_AID_NO;
}
if ($this->getWebsite() !== null) {
$data['Website'] = $this->getWebsite();
}
if ($sendEmail = $this->getSendEmail() !== null) {
if ($sendEmail != static::SEND_EMAIL_NONE
&& $sendEmail != static::SEND_EMAIL_BOTH
&& $sendEmail != static::SEND_EMAIL_VENDOR
) {
$sendEmail = static::SEND_EMAIL_BOTH;
}
$data['SendEMail'] = $this->getSendEmail();
}
$data['SuccessURL'] = $this->getReturnUrl();
$data['FailureURL'] = $this->getFailureUrl() ?: $this->getReturnUrl();
// Filter out any fields that are not accepted by the form API.
// Unexpected fields throw a general 5080 error which is very
// difficult to debug.
$data = array_intersect_key($data, $this->validFields);
// Throw exception if any mandatory fields are missing.
// We need to catch it here before sending the user to a
// generic (and useless) error on the gateway site.
foreach ($this->validFields as $fieldName => $mandatoryFlag) {
if ($mandatoryFlag && ! isset($data[$fieldName])) {
throw new InvalidRequestException(sprintf(
'The %s parameter is required',
$fieldName
));
}
}
// Two conditional checks on the "state" fields.
// We don't check if it is a valid two-character state code.
// Maybe this can be moved to the construction of the addresses
// in AbstractRequest.
if ($data['BillingCountry'] === 'US' && empty($data['BillingState'])
|| $data['DeliveryCountry'] === 'US' && empty($data['DeliveryState'])
) {
throw new InvalidRequestException(
'Missing state code for billing or shipping address'
);
}
return $data;
}
/**
* Generate the crypt field from the source data.
* @param array $data the name/value pairs to be encrypted
* @return string encrypted data
*/
public function generateCrypt(array $data)
{
// No data values should be null.
array_walk($data, function (&$value) {
if (! isset($value)) {
$value = '';
}
});
// Build the data in a query string.
// The encrypted data MUST be ISO8859-1 regardless of what encoding
// is used to submit the form, because that is how the gateway treats
// the data internally.
// This package assumes input data will be UTF-8 by default, and will
// comvert it accordingly. This can be disabled if the data is already
// ISO8859-1.
// For the Server and Direct gateway methods, the POST encoding type
// will tell the gateway how to interpret the character encoding, and
// the gateway will do any encoding conversions necessary.
// We cannot use http_build_query() because the gateway does
// not decode the string as any standard encoded query string.
// We just join the names and values with "=" and "&" and the
// gateway somehow decodes ambiguous strings.
$disableUtf8Decode = (bool)$this->getDisableUtf8Decode();
$query = [];
foreach ($data as $name => $value) {
$query[] = $name . '=' . ($disableUtf8Decode ? $value : mb_convert_encoding($value, 'ISO-8859-1', 'UTF-8'));
}
$query = implode('&', $query);
// Encrypted using AES(block size 128-bit) in CBC mode with PKCS#5 padding.
// AES encryption, CBC blocking with PKCS5 padding then HEX encoding.
$key = $this->getEncryptionKey();
// Normally IV (paramert 5, initialization vector) would be a kind of salt.
// That is more relevant when encrypting user details where multiple users
// could have identical passwords. But this is a one-off transport of a message
// that will always be unique, so no variable IV is needed.
$crypt = openssl_encrypt($query, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $key);
return '@' . strtoupper(bin2hex($crypt));
}
public function sendData($data)
{
// The result is always going to be a POST redirect.
return $this->createResponse($data);
}
/**
* Return the Response object, initialised with the parsed response data.
* @param array $data The data parsed from the response gateway body.
* @return Response
*/
protected function createResponse($data)
{
return $this->response = new Response($this, $data);
}
/**
* @param string|null $value The URL the Form gateway will return to on cancel or error.
* @return $this
*/
public function setFailureUrl($value)
{
return $this->setParameter('failureUrl', $value);
}
/**
* @return string|null The URL the Form gateway will return to on cancel or error.
*/
public function getFailureUrl()
{
return $this->getParameter('failureUrl');
}
/**
* @param string|null $value Customer's name will be included in the confirmation emails
* @return $this
*/
public function setCustomerName($value)
{
return $this->setParameter('customerName', $value);
}
/**
* @return string|null
*/
public function getCustomerName()
{
return $this->getParameter('customerName');
}
/**
* @param string|null $value An email will be sent to this address when each transaction completes
* @return $this
*/
public function setVendorEmail($value)
{
return $this->setParameter('vendorEmail', $value);
}
/**
* @return string|null
*/
public function getVendorEmail()
{
return $this->getParameter('vendorEmail');
}
/**
* @param string|null $value 0, 1, or 2, see constants SEND_EMAIL_*
* @return $this
*/
public function setSendEmail($value)
{
return $this->setParameter('sendEmail', $value);
}
/**
* @return string|null
*/
public function getSendEmail()
{
return $this->getParameter('sendEmail');
}
/**
* This message can be formatted using HTML, up to 1000 bytes.
*
* @param string|null $value A message to the customer, inserted into successful emails
* @return $this
*/
public function setEmailMessage($value)
{
return $this->setParameter('EmailMessage', $value);
}
/**
* @return string|null
*/
public function getEmailMessage()
{
return $this->getParameter('EmailMessage');
}
/**
* @param string|null $value
* @return $this
*/
public function setWebsite($value)
{
return $this->setParameter('website', $value);
}
/**
* @return string|null
*/
public function getWebsite()
{
return $this->getParameter('website');
}
}