PluginProbe
Gravity Forms Eway / 1.5.12
Gravity Forms Eway v1.5.12
2.7.0 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.8.0 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 All 56 releases
gravityforms-eway / class.GFEwayRecurringPayment.php

class.GFEwayRecurringPayment.php in Gravity Forms Eway 1.5.12, at class.GFEwayRecurringPayment.php

439 lines 13.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Classes for dealing with eWAY recurring payments
4 *
5 * NB: for testing, the only account number recognised is '87654321' and the only card number seen as valid is '4444333322221111'
6 */
7
8 /**
9 * Class for dealing with an eWAY recurring payment request
10 */
11 class GFEwayRecurringPayment {
12 // environment / website specific members
13 /**
14 * default FALSE, use eWAY sandbox unless set to TRUE
15 * @var boolean
16 */
17 public $isLiveSite;
18
19 /**
20 * default TRUE, whether to validate the remote SSL certificate
21 * @var boolean
22 */
23 public $sslVerifyPeer;
24
25 // payment specific members
26 /**
27 * account name / email address at eWAY
28 * @var string max. 8 characters
29 */
30 public $accountID;
31
32 /**
33 * customer's title
34 * @var string max. 20 characters
35 */
36 public $title;
37
38 /**
39 * customer's first name
40 * @var string max. 50 characters
41 */
42 public $firstName;
43
44 /**
45 * customer's last name
46 * @var string max. 50 characters
47 */
48 public $lastName;
49
50 /**
51 * customer's email address
52 * @var string max. 50 characters
53 */
54 public $emailAddress;
55
56 /**
57 * customer's address
58 * @var string max. 255 characters
59 */
60 public $address;
61
62 /**
63 * customer's suburb/city/town
64 * @var string max. 50 characters
65 */
66 public $suburb;
67
68 /**
69 * customer's state/province
70 * @var string max. 50 characters
71 */
72 public $state;
73
74 /**
75 * customer's postcode
76 * @var string max. 6 characters
77 */
78 public $postcode;
79
80 /**
81 * customer's country
82 * @var string max. 50 characters
83 */
84 public $country;
85
86 /**
87 * customer's phone number
88 * @var string max. 20 characters
89 */
90 public $phone;
91
92 /**
93 * customer's comments
94 * @var string max. 255 characters
95 */
96 public $customerComments;
97
98 /**
99 * an customer reference to track by (NB: see also invoiceReference)
100 * @var string max. 20 characters
101 */
102 public $customerReference;
103
104 /**
105 * an invoice reference to track by
106 * @var string max. 50 characters
107 */
108 public $invoiceReference;
109
110 /**
111 * description of what is being purchased / paid for
112 * @var string max. 10000 characters
113 */
114 public $invoiceDescription;
115
116 /**
117 * name on credit card
118 * @var string max. 50 characters
119 */
120 public $cardHoldersName;
121
122 /**
123 * credit card number, with no spaces
124 * @var string max. 20 characters
125 */
126 public $cardNumber;
127
128 /**
129 * month of expiry, numbered from 1=January
130 * @var integer max. 2 digits
131 */
132 public $cardExpiryMonth;
133
134 /**
135 * year of expiry
136 * @var integer will be truncated to 2 digits, can accept 4 digits
137 */
138 public $cardExpiryYear;
139
140 /**
141 * total amount of intial payment, in dollars and cents as a floating-point number (will be converted to just cents for transmission)
142 * may be 0 (i.e. nothing upfront, only on recurring billings)
143 * @var float
144 */
145 public $amountInit;
146
147 /**
148 * total amount of recurring payment, in dollars and cents as a floating-point number (will be converted to just cents for transmission)
149 * @var float
150 */
151 public $amountRecur;
152
153 /**
154 * the date of the initial payment (e.g. today, when the customer signed up)
155 * @var DateTime
156 */
157 public $dateInit;
158
159 /**
160 * the date of the first recurring payment
161 * @var DateTime
162 */
163 public $dateStart;
164
165 /**
166 * the date of the last recurring payment
167 * @var DateTime
168 */
169 public $dateEnd;
170
171 /**
172 * size of the interval between recurring payments (be it days, months, years, etc.) in range 1-31
173 * @var integer
174 */
175 public $intervalSize;
176
177 /**
178 * type of interval (see interval type constants below)
179 * @var integer
180 */
181 public $intervalType;
182
183 /** interval type Days */
184 const DAYS = 1;
185 /** interval type Weeks */
186 const WEEKS = 2;
187 /** interval type Months */
188 const MONTHS = 3;
189 /** interval type Years */
190 const YEARS = 4;
191
192 /** host for the eWAY Real Time API in the developer sandbox environment */
193 const REALTIME_API_SANDBOX = 'https://www.eway.com.au/gateway/rebill/test/Upload_test.aspx';
194 /** host for the eWAY Real Time API in the production environment */
195 const REALTIME_API_LIVE = 'https://www.eway.com.au/gateway/rebill/upload.aspx';
196
197 /**
198 * populate members with defaults, and set account and environment information
199 *
200 * @param string $accountID eWAY account ID
201 * @param boolean $isLiveSite running on the live (production) website
202 */
203 public function __construct($accountID, $isLiveSite = FALSE) {
204 $this->sslVerifyPeer = TRUE;
205 $this->isLiveSite = $isLiveSite;
206 $this->accountID = $accountID;
207 }
208
209 /**
210 * process a payment against eWAY; throws exception on error with error described in exception message.
211 */
212 public function processPayment() {
213 $this->validate();
214 $xml = $this->getPaymentXML();
215 return $this->sendPayment($xml);
216 }
217
218 /**
219 * validate the data members to ensure that sufficient and valid information has been given
220 */
221 private function validate() {
222 $errmsg = '';
223
224 if (strlen($this->accountID) === 0)
225 $errmsg .= "accountID cannot be empty.\n";
226 if (strlen($this->cardHoldersName) === 0)
227 $errmsg .= "card holder's name cannot be empty.\n";
228 if (strlen($this->cardNumber) === 0)
229 $errmsg .= "card number cannot be empty.\n";
230
231 // make sure that card expiry month is a number from 1 to 12
232 if (gettype($this->cardExpiryMonth) != 'integer') {
233 if (strlen($this->cardExpiryMonth) === 0)
234 $errmsg .= "card expiry month cannot be empty.\n";
235 else if (!is_numeric($this->cardExpiryMonth))
236 $errmsg .= "card expiry month must be a number between 1 and 12.\n";
237 else
238 $this->cardExpiryMonth = intval($this->cardExpiryMonth);
239 }
240 if (gettype($this->cardExpiryMonth) == 'integer') {
241 if ($this->cardExpiryMonth < 1 || $this->cardExpiryMonth > 12)
242 $errmsg .= "card expiry month must be a number between 1 and 12.\n";
243 }
244
245 // make sure that card expiry year is a 2-digit or 4-digit year >= this year
246 if (gettype($this->cardExpiryYear) != 'integer') {
247 if (strlen($this->cardExpiryYear) === 0)
248 $errmsg .= "card expiry year cannot be empty.\n";
249 else if (!preg_match('/^\d\d(?:\d\d)?$/', $this->cardExpiryYear))
250 $errmsg .= "card expiry year must be a two or four digit year.\n";
251 else
252 $this->cardExpiryYear = intval($this->cardExpiryYear);
253 }
254 if (gettype($this->cardExpiryYear) == 'integer') {
255 $thisYear = intval(date_create()->format('Y'));
256 if ($this->cardExpiryYear < 0 || $this->cardExpiryYear >= 100 && $this->cardExpiryYear < 2000 || $this->cardExpiryYear > $thisYear + 20)
257 $errmsg .= "card expiry year must be a two or four digit year.\n";
258 else {
259 if ($this->cardExpiryYear > 100 && $this->cardExpiryYear < $thisYear)
260 $errmsg .= "card expiry year can't be in the past.\n";
261 else if ($this->cardExpiryYear < 100 && $this->cardExpiryYear < ($thisYear - 2000))
262 $errmsg .= "card expiry year can't be in the past.\n";
263 }
264 }
265
266 // ensure that amounts are numeric and positive, and that recurring amount > 0
267 if (!is_numeric($this->amountInit) || $this->amountInit < 0) // NB: initial amount can be 0
268 $errmsg .= "initial amount must be given as a number in dollars and cents, or 0.\n";
269 else if (!is_float($this->amountInit))
270 $this->amountInit = (float) $this->amountInit;
271 if (!is_numeric($this->amountRecur) || $this->amountRecur <= 0)
272 $errmsg .= "recurring amount must be given as a number in dollars and cents.\n";
273 else if (!is_float($this->amountRecur))
274 $this->amountRecur = (float) $this->amountRecur;
275
276 // ensure that interval is numeric and within range, and interval type is valid
277 if (!is_numeric($this->intervalSize) || $this->intervalSize < 1 || $this->intervalSize > 31)
278 $errmsg .= "interval must be numeric and between 1 and 31.\n";
279 if (!is_numeric($this->intervalType) || !in_array(intval($this->intervalType), array(self::DAYS, self::WEEKS, self::MONTHS, self::YEARS)))
280 $errmsg .= "interval type is invalid.\n";
281
282 // ensure that dates are DateTime objects
283 if (empty($this->dateInit))
284 $this->dateInit = date_create();
285 if (!(is_object($this->dateInit) && get_class($this->dateInit) == 'DateTime'))
286 $errmsg .= "initial payment date must be a date.\n";
287 if (!(is_object($this->dateStart) && get_class($this->dateStart) == 'DateTime'))
288 $errmsg .= "recurring payment start date must be a date.\n";
289 if (!(is_object($this->dateEnd) && get_class($this->dateEnd) == 'DateTime'))
290 $errmsg .= "recurring payment end date must be a date.\n";
291
292 if (strlen($errmsg) > 0) {
293 throw new GFEwayException($errmsg);
294 }
295 }
296
297 /**
298 * create XML request document for payment parameters
299 *
300 * @return string
301 */
302 public function getPaymentXML() {
303 $xml = new XMLWriter();
304 $xml->openMemory();
305 $xml->startDocument('1.0', 'UTF-8');
306 $xml->startElement('RebillUpload');
307 $xml->startElement('NewRebill');
308 $xml->writeElement('eWayCustomerID', $this->accountID);
309
310 // customer data
311 $xml->startElement('Customer');
312 $xml->writeElement('CustomerRef', $this->customerReference); // req?
313 $xml->writeElement('CustomerTitle', $this->title);
314 $xml->writeElement('CustomerFirstName', $this->firstName); // req
315 $xml->writeElement('CustomerLastName', $this->lastName); // req
316 $xml->writeElement('CustomerCompany', '');
317 $xml->writeElement('CustomerJobDesc', '');
318 $xml->writeElement('CustomerEmail', $this->emailAddress);
319 $xml->writeElement('CustomerAddress', $this->address);
320 $xml->writeElement('CustomerSuburb', $this->suburb);
321 $xml->writeElement('CustomerState', $this->state); // req
322 $xml->writeElement('CustomerPostCode', $this->postcode); // req
323 $xml->writeElement('CustomerCountry', $this->country); // req
324 $xml->writeElement('CustomerPhone1', $this->phone);
325 $xml->writeElement('CustomerPhone2', '');
326 $xml->writeElement('CustomerFax', '');
327 $xml->writeElement('CustomerURL', '');
328 $xml->writeElement('CustomerComments', $this->customerComments);
329 $xml->endElement(); // Customer
330
331 // billing data
332 $xml->startElement('RebillEvent');
333 $xml->writeElement('RebillInvRef', $this->invoiceReference);
334 $xml->writeElement('RebillInvDesc', $this->invoiceDescription);
335 $xml->writeElement('RebillCCName', $this->cardHoldersName);
336 $xml->writeElement('RebillCCNumber', $this->cardNumber);
337 $xml->writeElement('RebillCCExpMonth', sprintf('%02d', $this->cardExpiryMonth));
338 $xml->writeElement('RebillCCExpYear', sprintf('%02d', $this->cardExpiryYear % 100));
339 $xml->writeElement('RebillInitAmt', number_format($this->amountInit * 100, 0, '', ''));
340 $xml->writeElement('RebillInitDate', $this->dateInit->format('d/m/Y'));
341 $xml->writeElement('RebillRecurAmt', number_format($this->amountRecur * 100, 0, '', ''));
342 $xml->writeElement('RebillStartDate', $this->dateStart->format('d/m/Y'));
343 $xml->writeElement('RebillInterval', $this->intervalSize);
344 $xml->writeElement('RebillIntervalType', $this->intervalType);
345 $xml->writeElement('RebillEndDate', $this->dateEnd->format('d/m/Y'));
346 $xml->endElement(); // RebillEvent
347
348 $xml->endElement(); // NewRebill
349 $xml->endElement(); // RebillUpload
350
351 return $xml->outputMemory();
352 }
353
354 /**
355 * send the eWAY payment request and retrieve and parse the response
356 *
357 * @return GFEwayRecurringResponse
358 * @param string $xml eWAY payment request as an XML document, per eWAY specifications
359 */
360 private function sendPayment($xml) {
361 // use sandbox if not from live website
362 $url = $this->isLiveSite ? self::REALTIME_API_LIVE : self::REALTIME_API_SANDBOX;
363
364 // execute the cURL request, and retrieve the response
365 try {
366 $responseXML = GFEwayPlugin::curlSendRequest($url, $xml, $this->sslVerifyPeer);
367 }
368 catch (GFEwayCurlException $e) {
369 throw new GFEwayException("Error posting eWAY recurring payment to $url: " . $e->getMessage());
370 }
371
372 $response = new GFEwayRecurringResponse();
373 $response->loadResponseXML($responseXML);
374 return $response;
375 }
376 }
377
378 /**
379 * Class for dealing with an eWAY recurring payment response
380 */
381 class GFEwayRecurringResponse {
382 /**
383 * For a successful transaction "True" is passed and for a failed transaction "False" is passed.
384 * @var boolean
385 */
386 public $status;
387
388 /**
389 * the error severity, either Error or Warning
390 * @var string max. 16 characters
391 */
392 public $errorType;
393
394 /**
395 * the error response returned by the bank
396 * @var string max. 255 characters
397 */
398 public $error;
399
400 /**
401 * load eWAY response data as XML string
402 *
403 * @param string $response eWAY response as a string (hopefully of XML data)
404 */
405 public function loadResponseXML($response) {
406 try {
407 // prevent XML injection attacks, and handle errors without warnings
408 $oldDisableEntityLoader = libxml_disable_entity_loader(TRUE);
409 $oldUseInternalErrors = libxml_use_internal_errors(TRUE);
410
411 //~ error_log(__METHOD__ . "\n" . $response);
412
413 $xml = simplexml_load_string($response);
414 if ($xml === false) {
415 $errmsg = '';
416 foreach (libxml_get_errors() as $error) {
417 $errmsg .= $error->message;
418 }
419 throw new Exception($errmsg);
420 }
421
422 $this->status = (strcasecmp((string) $xml->Result, 'success') === 0);
423 $this->errorType = (string) $xml->ErrorSeverity;
424 $this->error = (string) $xml->ErrorDetails;
425
426 // restore old libxml settings
427 libxml_disable_entity_loader($oldDisableEntityLoader);
428 libxml_use_internal_errors($oldUseInternalErrors);
429 }
430 catch (Exception $e) {
431 // restore old libxml settings
432 libxml_disable_entity_loader($oldDisableEntityLoader);
433 libxml_use_internal_errors($oldUseInternalErrors);
434
435 throw new GFEwayException('Error parsing eWAY recurring payments response: ' . $e->getMessage());
436 }
437 }
438 }
439