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>
17 * When looking up response codes in the Authorize.Net API, they
18 * begin at one, so always delete one from the "Position in Response"
20 class CRM_Core_Payment_AuthorizeNet
extends CRM_Core_Payment
{
21 CONST CHARSET
= 'iso-8859-1';
22 CONST AUTH_APPROVED
= 1;
23 CONST AUTH_DECLINED
= 2;
25 CONST TIMEZONE
= 'America/Denver';
27 protected $_mode = NULL;
29 protected $_params = array();
32 * We only need one instance of this object. So we use the singleton
33 * pattern and cache the instance in this variable
38 static private $_singleton = NULL;
43 * @param string $mode the mode of operation: live or test
47 function __construct($mode, &$paymentProcessor) {
49 $this->_paymentProcessor
= $paymentProcessor;
50 $this->_processorName
= ts('Authorize.net');
52 $config = CRM_Core_Config
::singleton();
53 $this->_setParam('apiLogin', $paymentProcessor['user_name']);
54 $this->_setParam('paymentKey', $paymentProcessor['password']);
55 $this->_setParam('paymentType', 'AIM');
56 $this->_setParam('md5Hash', $paymentProcessor['signature']);
58 $this->_setParam('emailCustomer', 'TRUE');
59 $this->_setParam('timestamp', time());
61 $this->_setParam('sequence', rand(1, 1000));
65 * singleton function used to manage this object
67 * @param string $mode the mode of operation: live or test
68 * @param object $paymentProcessor the details of the payment processor being invoked
69 * @param object $paymentForm reference to the form object if available
70 * @param boolean $force should we force a reload of this payment object
76 static function &singleton($mode, &$paymentProcessor, &$paymentForm = NULL, $force = FALSE) {
77 $processorName = $paymentProcessor['name'];
78 if (!isset(self
::$_singleton[$processorName]) || self
::$_singleton[$processorName] === NULL) {
79 self
::$_singleton[$processorName] = new CRM_Core_Payment_AuthorizeNet($mode, $paymentProcessor);
81 return self
::$_singleton[$processorName];
85 * Submit a payment using Advanced Integration Method
87 * @param array $params assoc array of input parameters for this transaction
89 * @return array the result in a nice formatted array (or an error object)
92 function doDirectPayment(&$params) {
93 if (!defined('CURLOPT_SSLCERT')) {
94 return self
::error(9001, 'Authorize.Net requires curl with SSL support');
98 * recurpayment function does not compile an array & then proces it -
99 * - the tpl does the transformation so adding call to hook here
100 * & giving it a change to act on the params array
102 $newParams = $params;
103 if (!empty($params['is_recur']) &&
104 $params['contributionRecurID']
106 CRM_Utils_Hook
::alterPaymentProcessorParams($this,
111 foreach ($newParams as $field => $value) {
112 $this->_setParam($field, $value);
115 if (!empty($params['is_recur']) &&
116 $params['contributionRecurID']
118 $result = $this->doRecurPayment();
119 if (is_a($result, 'CRM_Core_Error')) {
125 $postFields = array();
126 $authorizeNetFields = $this->_getAuthorizeNetFields();
128 // Set up our call for hook_civicrm_paymentProcessor,
129 // since we now have our parameters as assigned for the AIM back end.
130 CRM_Utils_Hook
::alterPaymentProcessorParams($this,
135 foreach ($authorizeNetFields as $field => $value) {
136 // CRM-7419, since double quote is used as enclosure while doing csv parsing
137 $value = ($field == 'x_description') ?
str_replace('"', "'", $value) : $value;
138 $postFields[] = $field . '=' . urlencode($value);
141 // Authorize.Net will not refuse duplicates, so we should check if the user already submitted this transaction
142 if ($this->_checkDupe($authorizeNetFields['x_invoice_num'])) {
143 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.');
146 $submit = curl_init($this->_paymentProcessor
['url_site']);
149 return self
::error(9002, 'Could not initiate connection to payment gateway');
152 curl_setopt($submit, CURLOPT_POST
, TRUE);
153 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, TRUE);
154 curl_setopt($submit, CURLOPT_POSTFIELDS
, implode('&', $postFields));
155 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'verifySSL'));
157 $response = curl_exec($submit);
160 return self
::error(curl_errno($submit), curl_error($submit));
165 $response_fields = $this->explode_csv($response);
167 // check gateway MD5 response
168 if (!$this->checkMD5($response_fields[37], $response_fields[6], $response_fields[9])) {
169 return self
::error(9003, 'MD5 Verification failed');
172 // check for application errors
174 // AVS, CVV2, CAVV, and other verification results
175 if ($response_fields[0] != self
::AUTH_APPROVED
) {
176 $errormsg = $response_fields[2] . ' ' . $response_fields[3];
177 return self
::error($response_fields[1], $errormsg);
182 // test mode always returns trxn_id = 0
183 // also live mode in CiviCRM with test mode set in
184 // Authorize.Net return $response_fields[6] = 0
185 // hence treat that also as test mode transaction
187 if (($this->_mode
== 'test') ||
$response_fields[6] == 0) {
188 $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id RLIKE 'test[0-9]+'";
190 $trxn_id = strval(CRM_Core_Dao
::singleValueQuery($query, $p));
191 $trxn_id = str_replace('test', '', $trxn_id);
192 $trxn_id = intval($trxn_id) +
1;
193 $params['trxn_id'] = sprintf('test%08d', $trxn_id);
196 $params['trxn_id'] = $response_fields[6];
198 $params['gross_amount'] = $response_fields[9];
199 // TODO: include authorization code?
205 * Submit an Automated Recurring Billing subscription
209 function doRecurPayment() {
210 $template = CRM_Core_Smarty
::singleton();
212 $intervalLength = $this->_getParam('frequency_interval');
213 $intervalUnit = $this->_getParam('frequency_unit');
214 if ($intervalUnit == 'week') {
215 $intervalLength *= 7;
216 $intervalUnit = 'days';
218 elseif ($intervalUnit == 'year') {
219 $intervalLength *= 12;
220 $intervalUnit = 'months';
222 elseif ($intervalUnit == 'day') {
223 $intervalUnit = 'days';
225 elseif ($intervalUnit == 'month') {
226 $intervalUnit = 'months';
229 // interval cannot be less than 7 days or more than 1 year
230 if ($intervalUnit == 'days') {
231 if ($intervalLength < 7) {
232 return self
::error(9001, 'Payment interval must be at least one week');
234 elseif ($intervalLength > 365) {
235 return self
::error(9001, 'Payment interval may not be longer than one year');
238 elseif ($intervalUnit == 'months') {
239 if ($intervalLength < 1) {
240 return self
::error(9001, 'Payment interval must be at least one week');
242 elseif ($intervalLength > 12) {
243 return self
::error(9001, 'Payment interval may not be longer than one year');
247 $template->assign('intervalLength', $intervalLength);
248 $template->assign('intervalUnit', $intervalUnit);
250 $template->assign('apiLogin', $this->_getParam('apiLogin'));
251 $template->assign('paymentKey', $this->_getParam('paymentKey'));
252 $template->assign('refId', substr($this->_getParam('invoiceID'), 0, 20));
254 //for recurring, carry first contribution id
255 $template->assign('invoiceNumber', $this->_getParam('contributionID'));
256 $firstPaymentDate = $this->_getParam('receive_date');
257 if (!empty($firstPaymentDate)) {
258 //allow for post dated payment if set in form
259 $startDate = date_create($firstPaymentDate);
262 $startDate = date_create();
264 /* Format start date in Mountain Time to avoid Authorize.net error E00017
265 * we do this only if the day we are setting our start time to is LESS than the current
266 * day in mountaintime (ie. the server time of the A-net server). A.net won't accept a date
267 * earlier than the current date on it's server so if we are in PST we might need to use mountain
268 * time to bring our date forward. But if we are submitting something future dated we want
269 * the date we entered to be respected
271 $minDate = date_create('now', new DateTimeZone(self
::TIMEZONE
));
272 if(strtotime($startDate->format('Y-m-d')) < strtotime($minDate->format('Y-m-d'))){
273 $startDate->setTimezone(new DateTimeZone(self
::TIMEZONE
));
276 $template->assign( 'startDate', $startDate->format('Y-m-d') );
278 $installments = $this->_getParam('installments');
280 // for open ended subscription totalOccurrences has to be 9999
281 $installments = empty($installments) ?
9999 : $installments;
282 $template->assign('totalOccurrences', $installments);
284 $template->assign('amount', $this->_getParam('amount'));
286 $template->assign('cardNumber', $this->_getParam('credit_card_number'));
287 $exp_month = str_pad($this->_getParam('month'), 2, '0', STR_PAD_LEFT
);
288 $exp_year = $this->_getParam('year');
289 $template->assign('expirationDate', $exp_year . '-' . $exp_month);
291 // name rather than description is used in the tpl - see http://www.authorize.net/support/ARB_guide.pdf
292 $template->assign('name', $this->_getParam('description', TRUE));
294 $template->assign('email', $this->_getParam('email'));
295 $template->assign('contactID', $this->_getParam('contactID'));
296 $template->assign('billingFirstName', $this->_getParam('billing_first_name'));
297 $template->assign('billingLastName', $this->_getParam('billing_last_name'));
298 $template->assign('billingAddress', $this->_getParam('street_address', TRUE));
299 $template->assign('billingCity', $this->_getParam('city', TRUE));
300 $template->assign('billingState', $this->_getParam('state_province'));
301 $template->assign('billingZip', $this->_getParam('postal_code', TRUE));
302 $template->assign('billingCountry', $this->_getParam('country'));
304 $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
305 // submit to authorize.net
307 $submit = curl_init($this->_paymentProcessor
['url_recur']);
309 return self
::error(9002, 'Could not initiate connection to payment gateway');
311 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, 1);
312 curl_setopt($submit, CURLOPT_HTTPHEADER
, array("Content-Type: text/xml"));
313 curl_setopt($submit, CURLOPT_HEADER
, 1);
314 curl_setopt($submit, CURLOPT_POSTFIELDS
, $arbXML);
315 curl_setopt($submit, CURLOPT_POST
, 1);
316 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'verifySSL'));
318 $response = curl_exec($submit);
321 return self
::error(curl_errno($submit), curl_error($submit));
325 $responseFields = $this->_ParseArbReturn($response);
327 if ($responseFields['resultCode'] == 'Error') {
328 return self
::error($responseFields['code'], $responseFields['text']);
331 // update recur processor_id with subscriptionId
332 CRM_Core_DAO
::setFieldValue('CRM_Contribute_DAO_ContributionRecur', $this->_getParam('contributionRecurID'),
333 'processor_id', $responseFields['subscriptionId']
335 //only impact of assigning this here is is can be used to cancel the subscription in an automated test
336 // if it isn't cancelled a duplicate transaction error occurs
337 if (!empty($responseFields['subscriptionId'])) {
338 $this->_setParam('subscriptionId', $responseFields['subscriptionId']);
342 function _getAuthorizeNetFields() {
343 $amount = $this->_getParam('total_amount');//Total amount is from the form contribution field
344 if(empty($amount)){//CRM-9894 would this ever be the case??
345 $amount = $this->_getParam('amount');
348 $fields['x_login'] = $this->_getParam('apiLogin');
349 $fields['x_tran_key'] = $this->_getParam('paymentKey');
350 $fields['x_email_customer'] = $this->_getParam('emailCustomer');
351 $fields['x_first_name'] = $this->_getParam('billing_first_name');
352 $fields['x_last_name'] = $this->_getParam('billing_last_name');
353 $fields['x_address'] = $this->_getParam('street_address');
354 $fields['x_city'] = $this->_getParam('city');
355 $fields['x_state'] = $this->_getParam('state_province');
356 $fields['x_zip'] = $this->_getParam('postal_code');
357 $fields['x_country'] = $this->_getParam('country');
358 $fields['x_customer_ip'] = $this->_getParam('ip_address');
359 $fields['x_email'] = $this->_getParam('email');
360 $fields['x_invoice_num'] = substr($this->_getParam('invoiceID'), 0, 20);
361 $fields['x_amount'] = $amount;
362 $fields['x_currency_code'] = $this->_getParam('currencyID');
363 $fields['x_description'] = $this->_getParam('description');
364 $fields['x_cust_id'] = $this->_getParam('contactID');
365 if ($this->_getParam('paymentType') == 'AIM') {
366 $fields['x_relay_response'] = 'FALSE';
367 // request response in CSV format
368 $fields['x_delim_data'] = 'TRUE';
369 $fields['x_delim_char'] = ',';
370 $fields['x_encap_char'] = '"';
372 $fields['x_card_num'] = $this->_getParam('credit_card_number');
373 $fields['x_card_code'] = $this->_getParam('cvv2');
374 $exp_month = str_pad($this->_getParam('month'), 2, '0', STR_PAD_LEFT
);
375 $exp_year = $this->_getParam('year');
376 $fields['x_exp_date'] = "$exp_month/$exp_year";
379 if ($this->_mode
!= 'live') {
380 $fields['x_test_request'] = 'TRUE';
387 * Checks to see if invoice_id already exists in db
389 * @param int $invoiceId The ID to check
391 * @return bool True if ID exists, else false
393 function _checkDupe($invoiceId) {
394 $contribution = new CRM_Contribute_DAO_Contribution();
395 $contribution->invoice_id
= $invoiceId;
396 return $contribution->find();
403 * @param string $data
405 * @return string the HMAC_MD5 encoding string
407 function hmac($key, $data) {
408 if (function_exists('mhash')) {
409 // Use PHP mhash extension
410 return (bin2hex(mhash(MHASH_MD5
, $data, $key)));
413 // RFC 2104 HMAC implementation for php.
414 // Creates an md5 HMAC.
415 // Eliminates the need to install mhash to compute a HMAC
416 // Hacked by Lance Rushing
417 // byte length for md5
419 if (strlen($key) > $b) {
420 $key = pack("H*", md5($key));
422 $key = str_pad($key, $b, chr(0x00));
423 $ipad = str_pad('', $b, chr(0x36));
424 $opad = str_pad('', $b, chr(0x5c));
425 $k_ipad = $key ^
$ipad;
426 $k_opad = $key ^
$opad;
427 return md5($k_opad . pack("H*", md5($k_ipad . $data)));
432 * Check the gateway MD5 response to make sure that this is a proper
435 * @param string $responseMD5 MD5 hash generated by the gateway
436 * @param string $transaction_id Transaction id generated by the gateway
437 * @param string $amount Purchase amount
441 function checkMD5($responseMD5, $transaction_id, $amount, $ipn = FALSE) {
442 // cannot check if no MD5 hash
443 $md5Hash = $this->_getParam('md5Hash');
444 if (empty($md5Hash)) {
447 $loginid = $this->_getParam('apiLogin');
448 $hashString = $ipn ?
($md5Hash . $transaction_id . $amount) : ($md5Hash . $loginid . $transaction_id . $amount);
449 $result = strtoupper(md5($hashString));
451 if ($result == $responseMD5) {
460 * Calculate and return the transaction fingerprint
462 * @return string fingerprint
464 function CalculateFP() {
465 $x_tran_key = $this->_getParam('paymentKey');
466 $loginid = $this->_getParam('apiLogin');
467 $sequence = $this->_getParam('sequence');
468 $timestamp = $this->_getParam('timestamp');
469 $amount = $this->_getParam('amount');
470 $currency = $this->_getParam('currencyID');
471 $transaction = "$loginid^$sequence^$timestamp^$amount^$currency";
472 return $this->hmac($x_tran_key, $transaction);
476 * Split a CSV file. Requires , as delimiter and " as enclosure.
477 * Based off notes from http://php.net/fgetcsv
479 * @param string $data a single CSV line
481 * @return array CSV fields
483 function explode_csv($data) {
485 //make it easier to parse fields with quotes in them
486 $data = str_replace('""', "''", $data);
489 while ($data != '') {
491 if ($data[0] == '"') {
492 // handle quoted fields
493 preg_match('/^"(([^"]|\\")*?)",?(.*)$/', $data, $matches);
495 $fields[] = str_replace("''", '"', $matches[1]);
499 preg_match('/^([^,]*),?(.*)$/', $data, $matches);
501 $fields[] = $matches[1];
509 * Extract variables from returned XML
511 * Function is from Authorize.Net sample code, and used
512 * to prevent the requirement of XML functions.
514 * @param string $content XML reply from Authorize.Net
516 * @return array refId, resultCode, code, text, subscriptionId
518 function _parseArbReturn($content) {
519 $refId = $this->_substring_between($content, '<refId>', '</refId>');
520 $resultCode = $this->_substring_between($content, '<resultCode>', '</resultCode>');
521 $code = $this->_substring_between($content, '<code>', '</code>');
522 $text = $this->_substring_between($content, '<text>', '</text>');
523 $subscriptionId = $this->_substring_between($content, '<subscriptionId>', '</subscriptionId>');
526 'resultCode' => $resultCode,
529 'subscriptionId' => $subscriptionId,
534 * Helper function for _parseArbReturn
536 * Function is from Authorize.Net sample code, and used to avoid using
539 function _substring_between(&$haystack, $start, $end) {
540 if (strpos($haystack, $start) === FALSE ||
strpos($haystack, $end) === FALSE) {
544 $start_position = strpos($haystack, $start) +
strlen($start);
545 $end_position = strpos($haystack, $end);
546 return substr($haystack, $start_position, $end_position - $start_position);
551 * Get the value of a field if set
553 * @param string $field the field
555 * @return mixed value of the field, or empty string if the field is
558 function _getParam($field, $xmlSafe = FALSE) {
559 $value = CRM_Utils_Array
::value($field, $this->_params
, '');
561 $value = str_replace(array( '&', '"', "'", '<', '>' ), '', $value);
566 function &error($errorCode = NULL, $errorMessage = NULL) {
567 $e = CRM_Core_Error
::singleton();
569 $e->push($errorCode, 0, array( ), $errorMessage);
572 $e->push(9001, 0, array( ), 'Unknown System Error.');
578 * Set a field to the specified value. Value must be a scalar (int,
579 * float, string, or boolean)
581 * @param string $field
582 * @param mixed $value
584 * @return bool false if value is not a scalar, true if successful
586 function _setParam($field, $value) {
587 if (!is_scalar($value)) {
591 $this->_params
[$field] = $value;
596 * This function checks to see if we have the right config values
598 * @return string the error message if any
601 function checkConfig() {
603 if (empty($this->_paymentProcessor
['user_name'])) {
604 $error[] = ts('APILogin is not set for this payment processor');
607 if (empty($this->_paymentProcessor
['password'])) {
608 $error[] = ts('Key is not set for this payment processor');
611 if (!empty($error)) {
612 return implode('<p>', $error);
619 function accountLoginURL() {
620 return ($this->_mode
== 'test') ?
'https://test.authorize.net' : 'https://authorize.net';
623 function cancelSubscription(&$message = '', $params = array(
625 $template = CRM_Core_Smarty
::singleton();
627 $template->assign('subscriptionType', 'cancel');
629 $template->assign('apiLogin', $this->_getParam('apiLogin'));
630 $template->assign('paymentKey', $this->_getParam('paymentKey'));
631 $template->assign('subscriptionId', CRM_Utils_Array
::value('subscriptionId', $params));
633 $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
635 // submit to authorize.net
636 $submit = curl_init($this->_paymentProcessor
['url_recur']);
638 return self
::error(9002, 'Could not initiate connection to payment gateway');
641 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, 1);
642 curl_setopt($submit, CURLOPT_HTTPHEADER
, array("Content-Type: text/xml"));
643 curl_setopt($submit, CURLOPT_HEADER
, 1);
644 curl_setopt($submit, CURLOPT_POSTFIELDS
, $arbXML);
645 curl_setopt($submit, CURLOPT_POST
, 1);
646 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'verifySSL'));
648 $response = curl_exec($submit);
651 return self
::error(curl_errno($submit), curl_error($submit));
656 $responseFields = $this->_ParseArbReturn($response);
657 $message = "{$responseFields['code']}: {$responseFields['text']}";
659 if ($responseFields['resultCode'] == 'Error') {
660 return self
::error($responseFields['code'], $responseFields['text']);
665 function updateSubscriptionBillingInfo(&$message = '', $params = array(
667 $template = CRM_Core_Smarty
::singleton();
668 $template->assign('subscriptionType', 'updateBilling');
670 $template->assign('apiLogin', $this->_getParam('apiLogin'));
671 $template->assign('paymentKey', $this->_getParam('paymentKey'));
672 $template->assign('subscriptionId', $params['subscriptionId']);
674 $template->assign('cardNumber', $params['credit_card_number']);
675 $exp_month = str_pad($params['month'], 2, '0', STR_PAD_LEFT
);
676 $exp_year = $params['year'];
677 $template->assign('expirationDate', $exp_year . '-' . $exp_month);
679 $template->assign('billingFirstName', $params['first_name']);
680 $template->assign('billingLastName', $params['last_name']);
681 $template->assign('billingAddress', $params['street_address']);
682 $template->assign('billingCity', $params['city']);
683 $template->assign('billingState', $params['state_province']);
684 $template->assign('billingZip', $params['postal_code']);
685 $template->assign('billingCountry', $params['country']);
687 $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
689 // submit to authorize.net
690 $submit = curl_init($this->_paymentProcessor
['url_recur']);
692 return self
::error(9002, 'Could not initiate connection to payment gateway');
695 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, 1);
696 curl_setopt($submit, CURLOPT_HTTPHEADER
, array("Content-Type: text/xml"));
697 curl_setopt($submit, CURLOPT_HEADER
, 1);
698 curl_setopt($submit, CURLOPT_POSTFIELDS
, $arbXML);
699 curl_setopt($submit, CURLOPT_POST
, 1);
700 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'verifySSL'));
702 $response = curl_exec($submit);
705 return self
::error(curl_errno($submit), curl_error($submit));
710 $responseFields = $this->_ParseArbReturn($response);
711 $message = "{$responseFields['code']}: {$responseFields['text']}";
713 if ($responseFields['resultCode'] == 'Error') {
714 return self
::error($responseFields['code'], $responseFields['text']);
719 function changeSubscriptionAmount(&$message = '', $params = array(
721 $template = CRM_Core_Smarty
::singleton();
723 $template->assign('subscriptionType', 'update');
725 $template->assign('apiLogin', $this->_getParam('apiLogin'));
726 $template->assign('paymentKey', $this->_getParam('paymentKey'));
728 $template->assign('subscriptionId', $params['subscriptionId']);
729 $template->assign('totalOccurrences', $params['installments']);
730 $template->assign('amount', $params['amount']);
732 $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
734 // submit to authorize.net
735 $submit = curl_init($this->_paymentProcessor
['url_recur']);
737 return self
::error(9002, 'Could not initiate connection to payment gateway');
740 curl_setopt($submit, CURLOPT_RETURNTRANSFER
, 1);
741 curl_setopt($submit, CURLOPT_HTTPHEADER
, array("Content-Type: text/xml"));
742 curl_setopt($submit, CURLOPT_HEADER
, 1);
743 curl_setopt($submit, CURLOPT_POSTFIELDS
, $arbXML);
744 curl_setopt($submit, CURLOPT_POST
, 1);
745 curl_setopt($submit, CURLOPT_SSL_VERIFYPEER
, CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'verifySSL'));
747 $response = curl_exec($submit);
750 return self
::error(curl_errno($submit), curl_error($submit));
755 $responseFields = $this->_ParseArbReturn($response);
756 $message = "{$responseFields['code']}: {$responseFields['text']}";
758 if ($responseFields['resultCode'] == 'Error') {
759 return self
::error($responseFields['code'], $responseFields['text']);