4 * Licensed to CiviCRM under the Academic Free License version 3.0.
6 * Written and contributed by Ideal Solution, LLC (http://www.idealso.com)
13 * @author Marshal Newrock <marshal@idealso.com>
18 * When looking up response codes in the Authorize.Net API, they
19 * begin at one, so always delete one from the "Position in Response"
21 class CRM_Core_Payment_AuthorizeNet
extends CRM_Core_Payment
{
22 const CHARSET
= 'iso-8859-1';
23 const AUTH_APPROVED
= 1;
24 const AUTH_DECLINED
= 2;
26 const AUTH_REVIEW
= 4;
27 const TIMEZONE
= 'America/Denver';
29 protected $_mode = NULL;
31 protected $_params = array();
34 * We only need one instance of this object. So we use the singleton
35 * pattern and cache the instance in this variable
39 static private $_singleton = NULL;
45 * The mode of operation: live or test.
47 * @param $paymentProcessor
49 * @return \CRM_Core_Payment_AuthorizeNet
51 public function __construct($mode, &$paymentProcessor) {
53 $this->_paymentProcessor
= $paymentProcessor;
54 $this->_processorName
= ts('Authorize.net');
56 $this->_setParam('apiLogin', $paymentProcessor['user_name']);
57 $this->_setParam('paymentKey', $paymentProcessor['password']);
58 $this->_setParam('paymentType', 'AIM');
59 $this->_setParam('md5Hash', CRM_Utils_Array
::value('signature', $paymentProcessor));
61 $this->_setParam('timestamp', time());
63 $this->_setParam('sequence', rand(1, 1000));
67 * Should the first payment date be configurable when setting up back office recurring payments.
68 * In the case of Authorize.net this is an option
71 protected function supportsFutureRecurStartDate() {
76 * Can recurring contributions be set against pledges.
78 * In practice all processors that use the baseIPN function to finish transactions or
79 * call the completetransaction api support this by looking up previous contributions in the
80 * series and, if there is a prior contribution against a pledge, and the pledge is not complete,
81 * adding the new payment to the pledge.
83 * However, only enabling for processors it has been tested against.
87 protected function supportsRecurContributionsForPledges() {
92 * Submit a payment using Advanced Integration Method.
94 * @param array $params
95 * Assoc array of input parameters for this transaction.
98 * the result in a nice formatted array (or an error object)
100 public function doDirectPayment(&$params) {
101 if (!defined('CURLOPT_SSLCERT')) {
102 return self
::error(9001, 'Authorize.Net requires curl with SSL support');
106 * recurpayment function does not compile an array & then process it -
107 * - the tpl does the transformation so adding call to hook here
108 * & giving it a change to act on the params array
110 $newParams = $params;
111 if (!empty($params['is_recur']) && !empty($params['contributionRecurID'])) {
112 CRM_Utils_Hook
::alterPaymentProcessorParams($this,
117 foreach ($newParams as $field => $value) {
118 $this->_setParam($field, $value);
121 if (!empty($params['is_recur']) && !empty($params['contributionRecurID'])) {
122 $result = $this->doRecurPayment();
123 if (is_a($result, 'CRM_Core_Error')) {
129 $postFields = array();
130 $authorizeNetFields = $this->_getAuthorizeNetFields();
132 // Set up our call for hook_civicrm_paymentProcessor,
133 // since we now have our parameters as assigned for the AIM back end.
134 CRM_Utils_Hook
::alterPaymentProcessorParams($this,
139 foreach ($authorizeNetFields as $field => $value) {
140 // CRM-7419, since double quote is used as enclosure while doing csv parsing
141 $value = ($field == 'x_description') ?
str_replace('"', "'", $value) : $value;
142 $postFields[] = $field . '=' . urlencode($value);
145 // Authorize.Net will not refuse duplicates, so we should check if the user already submitted this transaction
146 if ($this->checkDupe($authorizeNetFields['x_invoice_num'], CRM_Utils_Array
::value('contributionID', $params))) {
147 return self
::error(9004, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipt from Authorize.net. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.');
150 $submit = curl_init($this->_paymentProcessor
['url_site']);
153 return self
::error(9002, 'Could not initiate connection to payment gateway');
156 curl_setopt($submit, CURLOPT_POST
, TRUE);
157 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, TRUE);
158 curl_setopt($submit, CURLOPT_POSTFIELDS
, implode('&', $postFields));
159 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, Civi
::settings()->get('verifySSL'));
161 $response = curl_exec($submit);
164 return self
::error(curl_errno($submit), curl_error($submit));
169 $response_fields = $this->explode_csv($response);
170 // check gateway MD5 response
171 if (!$this->checkMD5($response_fields[37], $response_fields[6], $response_fields[9])) {
172 return self
::error(9003, 'MD5 Verification failed');
175 // check for application errors
177 // AVS, CVV2, CAVV, and other verification results
178 $contributionStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
179 switch ($response_fields[0]) {
180 case self
::AUTH_REVIEW
:
181 $params['payment_status_id'] = array_search('Pending', $contributionStatus);
184 case self
::AUTH_ERROR
:
185 $params['payment_status_id'] = array_search('Failed', $contributionStatus);
188 case self
::AUTH_DECLINED
:
189 $errormsg = $response_fields[2] . ' ' . $response_fields[3];
190 return self
::error($response_fields[1], $errormsg);
195 // test mode always returns trxn_id = 0
196 // also live mode in CiviCRM with test mode set in
197 // Authorize.Net return $response_fields[6] = 0
198 // hence treat that also as test mode transaction
200 if (($this->_mode
== 'test') ||
$response_fields[6] == 0) {
201 $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id RLIKE 'test[0-9]+'";
203 $trxn_id = strval(CRM_Core_DAO
::singleValueQuery($query, $p));
204 $trxn_id = str_replace('test', '', $trxn_id);
205 $trxn_id = intval($trxn_id) +
1;
206 $params['trxn_id'] = sprintf('test%08d', $trxn_id);
209 $params['trxn_id'] = $response_fields[6];
211 $params['gross_amount'] = $response_fields[9];
214 // TODO: include authorization code?
220 * Submit an Automated Recurring Billing subscription.
222 public function doRecurPayment() {
223 $template = CRM_Core_Smarty
::singleton();
225 $intervalLength = $this->_getParam('frequency_interval');
226 $intervalUnit = $this->_getParam('frequency_unit');
227 if ($intervalUnit == 'week') {
228 $intervalLength *= 7;
229 $intervalUnit = 'days';
231 elseif ($intervalUnit == 'year') {
232 $intervalLength *= 12;
233 $intervalUnit = 'months';
235 elseif ($intervalUnit == 'day') {
236 $intervalUnit = 'days';
238 elseif ($intervalUnit == 'month') {
239 $intervalUnit = 'months';
242 // interval cannot be less than 7 days or more than 1 year
243 if ($intervalUnit == 'days') {
244 if ($intervalLength < 7) {
245 return self
::error(9001, 'Payment interval must be at least one week');
247 elseif ($intervalLength > 365) {
248 return self
::error(9001, 'Payment interval may not be longer than one year');
251 elseif ($intervalUnit == 'months') {
252 if ($intervalLength < 1) {
253 return self
::error(9001, 'Payment interval must be at least one week');
255 elseif ($intervalLength > 12) {
256 return self
::error(9001, 'Payment interval may not be longer than one year');
260 $template->assign('intervalLength', $intervalLength);
261 $template->assign('intervalUnit', $intervalUnit);
263 $template->assign('apiLogin', $this->_getParam('apiLogin'));
264 $template->assign('paymentKey', $this->_getParam('paymentKey'));
265 $template->assign('refId', substr($this->_getParam('invoiceID'), 0, 20));
267 //for recurring, carry first contribution id
268 $template->assign('invoiceNumber', $this->_getParam('contributionID'));
269 $firstPaymentDate = $this->_getParam('receive_date');
270 if (!empty($firstPaymentDate)) {
271 //allow for post dated payment if set in form
272 $startDate = date_create($firstPaymentDate);
275 $startDate = date_create();
277 /* Format start date in Mountain Time to avoid Authorize.net error E00017
278 * we do this only if the day we are setting our start time to is LESS than the current
279 * day in mountaintime (ie. the server time of the A-net server). A.net won't accept a date
280 * earlier than the current date on it's server so if we are in PST we might need to use mountain
281 * time to bring our date forward. But if we are submitting something future dated we want
282 * the date we entered to be respected
284 $minDate = date_create('now', new DateTimeZone(self
::TIMEZONE
));
285 if (strtotime($startDate->format('Y-m-d')) < strtotime($minDate->format('Y-m-d'))) {
286 $startDate->setTimezone(new DateTimeZone(self
::TIMEZONE
));
289 $template->assign('startDate', $startDate->format('Y-m-d'));
291 $installments = $this->_getParam('installments');
293 // for open ended subscription totalOccurrences has to be 9999
294 $installments = empty($installments) ?
9999 : $installments;
295 $template->assign('totalOccurrences', $installments);
297 $template->assign('amount', $this->_getParam('amount'));
299 $template->assign('cardNumber', $this->_getParam('credit_card_number'));
300 $exp_month = str_pad($this->_getParam('month'), 2, '0', STR_PAD_LEFT
);
301 $exp_year = $this->_getParam('year');
302 $template->assign('expirationDate', $exp_year . '-' . $exp_month);
304 // name rather than description is used in the tpl - see http://www.authorize.net/support/ARB_guide.pdf
305 $template->assign('name', $this->_getParam('description', TRUE));
307 $template->assign('email', $this->_getParam('email'));
308 $template->assign('contactID', $this->_getParam('contactID'));
309 $template->assign('billingFirstName', $this->_getParam('billing_first_name'));
310 $template->assign('billingLastName', $this->_getParam('billing_last_name'));
311 $template->assign('billingAddress', $this->_getParam('street_address', TRUE));
312 $template->assign('billingCity', $this->_getParam('city', TRUE));
313 $template->assign('billingState', $this->_getParam('state_province'));
314 $template->assign('billingZip', $this->_getParam('postal_code', TRUE));
315 $template->assign('billingCountry', $this->_getParam('country'));
317 $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
318 // submit to authorize.net
320 $submit = curl_init($this->_paymentProcessor
['url_recur']);
322 return self
::error(9002, 'Could not initiate connection to payment gateway');
324 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, 1);
325 curl_setopt($submit, CURLOPT_HTTPHEADER
, array("Content-Type: text/xml"));
326 curl_setopt($submit, CURLOPT_HEADER
, 1);
327 curl_setopt($submit, CURLOPT_POSTFIELDS
, $arbXML);
328 curl_setopt($submit, CURLOPT_POST
, 1);
329 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, Civi
::settings()->get('verifySSL'));
331 $response = curl_exec($submit);
334 return self
::error(curl_errno($submit), curl_error($submit));
338 $responseFields = $this->_ParseArbReturn($response);
340 if ($responseFields['resultCode'] == 'Error') {
341 return self
::error($responseFields['code'], $responseFields['text']);
344 // update recur processor_id with subscriptionId
345 CRM_Core_DAO
::setFieldValue('CRM_Contribute_DAO_ContributionRecur', $this->_getParam('contributionRecurID'),
346 'processor_id', $responseFields['subscriptionId']
348 //only impact of assigning this here is is can be used to cancel the subscription in an automated test
349 // if it isn't cancelled a duplicate transaction error occurs
350 if (!empty($responseFields['subscriptionId'])) {
351 $this->_setParam('subscriptionId', $responseFields['subscriptionId']);
358 public function _getAuthorizeNetFields() {
359 $amount = $this->_getParam('total_amount');//Total amount is from the form contribution field
360 if (empty($amount)) {//CRM-9894 would this ever be the case??
361 $amount = $this->_getParam('amount');
364 $fields['x_login'] = $this->_getParam('apiLogin');
365 $fields['x_tran_key'] = $this->_getParam('paymentKey');
366 $fields['x_email_customer'] = $this->_getParam('emailCustomer');
367 $fields['x_first_name'] = $this->_getParam('billing_first_name');
368 $fields['x_last_name'] = $this->_getParam('billing_last_name');
369 $fields['x_address'] = $this->_getParam('street_address');
370 $fields['x_city'] = $this->_getParam('city');
371 $fields['x_state'] = $this->_getParam('state_province');
372 $fields['x_zip'] = $this->_getParam('postal_code');
373 $fields['x_country'] = $this->_getParam('country');
374 $fields['x_customer_ip'] = $this->_getParam('ip_address');
375 $fields['x_email'] = $this->_getParam('email');
376 $fields['x_invoice_num'] = substr($this->_getParam('invoiceID'), 0, 20);
377 $fields['x_amount'] = $amount;
378 $fields['x_currency_code'] = $this->_getParam('currencyID');
379 $fields['x_description'] = $this->_getParam('description');
380 $fields['x_cust_id'] = $this->_getParam('contactID');
381 if ($this->_getParam('paymentType') == 'AIM') {
382 $fields['x_relay_response'] = 'FALSE';
383 // request response in CSV format
384 $fields['x_delim_data'] = 'TRUE';
385 $fields['x_delim_char'] = ',';
386 $fields['x_encap_char'] = '"';
388 $fields['x_card_num'] = $this->_getParam('credit_card_number');
389 $fields['x_card_code'] = $this->_getParam('cvv2');
390 $exp_month = str_pad($this->_getParam('month'), 2, '0', STR_PAD_LEFT
);
391 $exp_year = $this->_getParam('year');
392 $fields['x_exp_date'] = "$exp_month/$exp_year";
395 if ($this->_mode
!= 'live') {
396 $fields['x_test_request'] = 'TRUE';
406 * @param string $data
409 * the HMAC_MD5 encoding string
411 public function hmac($key, $data) {
412 if (function_exists('mhash')) {
413 // Use PHP mhash extension
414 return (bin2hex(mhash(MHASH_MD5
, $data, $key)));
417 // RFC 2104 HMAC implementation for php.
418 // Creates an md5 HMAC.
419 // Eliminates the need to install mhash to compute a HMAC
420 // Hacked by Lance Rushing
421 // byte length for md5
423 if (strlen($key) > $b) {
424 $key = pack("H*", md5($key));
426 $key = str_pad($key, $b, chr(0x00));
427 $ipad = str_pad('', $b, chr(0x36));
428 $opad = str_pad('', $b, chr(0x5c));
429 $k_ipad = $key ^
$ipad;
430 $k_opad = $key ^
$opad;
431 return md5($k_opad . pack("H*", md5($k_ipad . $data)));
436 * Check the gateway MD5 response to make sure that this is a proper
439 * @param string $responseMD5
440 * MD5 hash generated by the gateway.
441 * @param string $transaction_id
442 * Transaction id generated by the gateway.
443 * @param string $amount
450 public function checkMD5($responseMD5, $transaction_id, $amount, $ipn = FALSE) {
451 // cannot check if no MD5 hash
452 $md5Hash = $this->_getParam('md5Hash');
453 if (empty($md5Hash)) {
456 $loginid = $this->_getParam('apiLogin');
457 $hashString = $ipn ?
($md5Hash . $transaction_id . $amount) : ($md5Hash . $loginid . $transaction_id . $amount);
458 $result = strtoupper(md5($hashString));
460 if ($result == $responseMD5) {
469 * Calculate and return the transaction fingerprint.
474 public function CalculateFP() {
475 $x_tran_key = $this->_getParam('paymentKey');
476 $loginid = $this->_getParam('apiLogin');
477 $sequence = $this->_getParam('sequence');
478 $timestamp = $this->_getParam('timestamp');
479 $amount = $this->_getParam('amount');
480 $currency = $this->_getParam('currencyID');
481 $transaction = "$loginid^$sequence^$timestamp^$amount^$currency";
482 return $this->hmac($x_tran_key, $transaction);
486 * Split a CSV file. Requires , as delimiter and " as enclosure.
487 * Based off notes from http://php.net/fgetcsv
489 * @param string $data
495 public function explode_csv($data) {
497 //make it easier to parse fields with quotes in them
498 $data = str_replace('""', "''", $data);
501 while ($data != '') {
503 if ($data[0] == '"') {
504 // handle quoted fields
505 preg_match('/^"(([^"]|\\")*?)",?(.*)$/', $data, $matches);
507 $fields[] = str_replace("''", '"', $matches[1]);
511 preg_match('/^([^,]*),?(.*)$/', $data, $matches);
513 $fields[] = $matches[1];
521 * Extract variables from returned XML.
523 * Function is from Authorize.Net sample code, and used
524 * to prevent the requirement of XML functions.
526 * @param string $content
527 * XML reply from Authorize.Net.
530 * refId, resultCode, code, text, subscriptionId
532 public function _parseArbReturn($content) {
533 $refId = $this->_substring_between($content, '<refId>', '</refId>');
534 $resultCode = $this->_substring_between($content, '<resultCode>', '</resultCode>');
535 $code = $this->_substring_between($content, '<code>', '</code>');
536 $text = $this->_substring_between($content, '<text>', '</text>');
537 $subscriptionId = $this->_substring_between($content, '<subscriptionId>', '</subscriptionId>');
540 'resultCode' => $resultCode,
543 'subscriptionId' => $subscriptionId,
548 * Helper function for _parseArbReturn.
550 * Function is from Authorize.Net sample code, and used to avoid using
553 * @param string $haystack
554 * @param string $start
557 * @return bool|string
559 public function _substring_between(&$haystack, $start, $end) {
560 if (strpos($haystack, $start) === FALSE ||
strpos($haystack, $end) === FALSE) {
564 $start_position = strpos($haystack, $start) +
strlen($start);
565 $end_position = strpos($haystack, $end);
566 return substr($haystack, $start_position, $end_position - $start_position);
571 * Get the value of a field if set.
573 * @param string $field
576 * @param bool $xmlSafe
578 * value of the field, or empty string if the field is
581 public function _getParam($field, $xmlSafe = FALSE) {
582 $value = CRM_Utils_Array
::value($field, $this->_params
, '');
584 $value = str_replace(array('&', '"', "'", '<', '>'), '', $value);
590 * @param null $errorCode
591 * @param null $errorMessage
595 public function &error($errorCode = NULL, $errorMessage = NULL) {
596 $e = CRM_Core_Error
::singleton();
598 $e->push($errorCode, 0, array(), $errorMessage);
601 $e->push(9001, 0, array(), 'Unknown System Error.');
607 * Set a field to the specified value. Value must be a scalar (int,
608 * float, string, or boolean)
610 * @param string $field
611 * @param mixed $value
614 * false if value is not a scalar, true if successful
616 public function _setParam($field, $value) {
617 if (!is_scalar($value)) {
621 $this->_params
[$field] = $value;
626 * This function checks to see if we have the right config values.
629 * the error message if any
631 public function checkConfig() {
633 if (empty($this->_paymentProcessor
['user_name'])) {
634 $error[] = ts('APILogin is not set for this payment processor');
637 if (empty($this->_paymentProcessor
['password'])) {
638 $error[] = ts('Key is not set for this payment processor');
641 if (!empty($error)) {
642 return implode('<p>', $error);
652 public function accountLoginURL() {
653 return ($this->_mode
== 'test') ?
'https://test.authorize.net' : 'https://authorize.net';
657 * @param string $message
658 * @param array $params
660 * @return bool|object
662 public function cancelSubscription(&$message = '', $params = array()) {
663 $template = CRM_Core_Smarty
::singleton();
665 $template->assign('subscriptionType', 'cancel');
667 $template->assign('apiLogin', $this->_getParam('apiLogin'));
668 $template->assign('paymentKey', $this->_getParam('paymentKey'));
669 $template->assign('subscriptionId', CRM_Utils_Array
::value('subscriptionId', $params));
671 $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
673 // submit to authorize.net
674 $submit = curl_init($this->_paymentProcessor
['url_recur']);
676 return self
::error(9002, 'Could not initiate connection to payment gateway');
679 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, 1);
680 curl_setopt($submit, CURLOPT_HTTPHEADER
, array("Content-Type: text/xml"));
681 curl_setopt($submit, CURLOPT_HEADER
, 1);
682 curl_setopt($submit, CURLOPT_POSTFIELDS
, $arbXML);
683 curl_setopt($submit, CURLOPT_POST
, 1);
684 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, Civi
::settings()->get('verifySSL'));
686 $response = curl_exec($submit);
689 return self
::error(curl_errno($submit), curl_error($submit));
694 $responseFields = $this->_ParseArbReturn($response);
695 $message = "{$responseFields['code']}: {$responseFields['text']}";
697 if ($responseFields['resultCode'] == 'Error') {
698 return self
::error($responseFields['code'], $responseFields['text']);
704 * @param string $message
705 * @param array $params
707 * @return bool|object
709 public function updateSubscriptionBillingInfo(&$message = '', $params = array()) {
710 $template = CRM_Core_Smarty
::singleton();
711 $template->assign('subscriptionType', 'updateBilling');
713 $template->assign('apiLogin', $this->_getParam('apiLogin'));
714 $template->assign('paymentKey', $this->_getParam('paymentKey'));
715 $template->assign('subscriptionId', $params['subscriptionId']);
717 $template->assign('cardNumber', $params['credit_card_number']);
718 $exp_month = str_pad($params['month'], 2, '0', STR_PAD_LEFT
);
719 $exp_year = $params['year'];
720 $template->assign('expirationDate', $exp_year . '-' . $exp_month);
722 $template->assign('billingFirstName', $params['first_name']);
723 $template->assign('billingLastName', $params['last_name']);
724 $template->assign('billingAddress', $params['street_address']);
725 $template->assign('billingCity', $params['city']);
726 $template->assign('billingState', $params['state_province']);
727 $template->assign('billingZip', $params['postal_code']);
728 $template->assign('billingCountry', $params['country']);
730 $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
732 // submit to authorize.net
733 $submit = curl_init($this->_paymentProcessor
['url_recur']);
735 return self
::error(9002, 'Could not initiate connection to payment gateway');
738 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, 1);
739 curl_setopt($submit, CURLOPT_HTTPHEADER
, array("Content-Type: text/xml"));
740 curl_setopt($submit, CURLOPT_HEADER
, 1);
741 curl_setopt($submit, CURLOPT_POSTFIELDS
, $arbXML);
742 curl_setopt($submit, CURLOPT_POST
, 1);
743 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, Civi
::settings()->get('verifySSL'));
745 $response = curl_exec($submit);
748 return self
::error(curl_errno($submit), curl_error($submit));
753 $responseFields = $this->_ParseArbReturn($response);
754 $message = "{$responseFields['code']}: {$responseFields['text']}";
756 if ($responseFields['resultCode'] == 'Error') {
757 return self
::error($responseFields['code'], $responseFields['text']);
763 * Process incoming notification.
765 static public function handlePaymentNotification() {
766 $ipnClass = new CRM_Core_Payment_AuthorizeNetIPN(array_merge($_GET, $_REQUEST));
771 * @param string $message
772 * @param array $params
774 * @return bool|object
776 public function changeSubscriptionAmount(&$message = '', $params = array()) {
777 $template = CRM_Core_Smarty
::singleton();
779 $template->assign('subscriptionType', 'update');
781 $template->assign('apiLogin', $this->_getParam('apiLogin'));
782 $template->assign('paymentKey', $this->_getParam('paymentKey'));
784 $template->assign('subscriptionId', $params['subscriptionId']);
786 // for open ended subscription totalOccurrences has to be 9999
787 $installments = empty($params['installments']) ?
9999 : $params['installments'];
788 $template->assign('totalOccurrences', $installments);
790 $template->assign('amount', $params['amount']);
792 $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
794 // submit to authorize.net
795 $submit = curl_init($this->_paymentProcessor
['url_recur']);
797 return self
::error(9002, 'Could not initiate connection to payment gateway');
800 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, 1);
801 curl_setopt($submit, CURLOPT_HTTPHEADER
, array("Content-Type: text/xml"));
802 curl_setopt($submit, CURLOPT_HEADER
, 1);
803 curl_setopt($submit, CURLOPT_POSTFIELDS
, $arbXML);
804 curl_setopt($submit, CURLOPT_POST
, 1);
805 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, Civi
::settings()->get('verifySSL'));
807 $response = curl_exec($submit);
810 return self
::error(curl_errno($submit), curl_error($submit));
815 $responseFields = $this->_ParseArbReturn($response);
816 $message = "{$responseFields['code']}: {$responseFields['text']}";
818 if ($responseFields['resultCode'] == 'Error') {
819 return self
::error($responseFields['code'], $responseFields['text']);