/** * Calls upon Authorize.Net® ARB, and returns the response. * * @package s2Member\AuthNet * @since 1.5 * * @param array $post_vars An array of variables to send through the Authorize.Net® API call. * @return array An array of variables returned from the API call. * * @todo Continue optimizing this routine with ``empty()`` and ``isset()``. */ public static function authnet_arb_response($post_vars = FALSE) { global $current_site, $current_blog; /* For Multisite support. */ /**/ $url = "https://" . ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["pro_authnet_sandbox"] ? "apitest.authorize.net" : "api.authorize.net") . "/xml/v1/request.api"; /**/ $post_vars = is_array($post_vars) ? $post_vars : array(); /* Must be in array format. */ /**/ $post_vars["x_login"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["pro_authnet_api_login_id"]; $post_vars["x_tran_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["pro_authnet_api_trans_key"]; /**/ $post_vars["x_invoice_num"] = !empty($post_vars["x_invoice_num"]) ? substr($post_vars["x_invoice_num"], 0, 20) : ""; $post_vars["x_description"] = !empty($post_vars["x_description"]) ? substr($post_vars["x_description"], 0, 255) : ""; $post_vars["x_description"] = c_ws_plugin__s2member_utils_strings::strip_2_kb_chars($post_vars["x_description"]); /**/ $trial = !empty($post_vars["x_trial_occurrences"]) ? true : false; /* Indicates existence of trial. */ /**/ if (!empty($post_vars["x_method"]) && $post_vars["x_method"] === "create") { $xml = '<?xml version="1.0" encoding="utf-8"?>'; /**/ $xml .= '<ARBCreateSubscriptionRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">'; /**/ $xml .= '<merchantAuthentication>'; $xml .= '<name>' . esc_html($post_vars["x_login"]) . '</name>'; $xml .= '<transactionKey>' . esc_html($post_vars["x_tran_key"]) . '</transactionKey>'; $xml .= '</merchantAuthentication>'; /**/ $xml .= '<refId>' . esc_html($post_vars["x_invoice_num"]) . '</refId>'; /**/ $xml .= '<subscription>'; /**/ $xml .= '<name>' . esc_html($_SERVER["HTTP_HOST"]) . '</name>'; /**/ $xml .= '<paymentSchedule>'; $xml .= '<interval>'; $xml .= '<length>' . esc_html($post_vars["x_length"]) . '</length>'; $xml .= '<unit>' . esc_html($post_vars["x_unit"]) . '</unit>'; $xml .= '</interval>'; $xml .= '<startDate>' . esc_html($post_vars["x_start_date"]) . '</startDate>'; $xml .= '<totalOccurrences>' . esc_html($post_vars["x_total_occurrences"]) . '</totalOccurrences>'; $xml .= $trial ? '<trialOccurrences>' . esc_html($post_vars["x_trial_occurrences"]) . '</trialOccurrences>' : ''; $xml .= '</paymentSchedule>'; /**/ $xml .= '<amount>' . esc_html($post_vars["x_amount"]) . '</amount>'; $xml .= $trial ? '<trialAmount>' . esc_html($post_vars["x_trial_amount"]) . '</trialAmount>' : ''; /**/ $xml .= '<payment>'; $xml .= '<creditCard>'; $xml .= '<cardNumber>' . esc_html($post_vars["x_card_num"]) . '</cardNumber>'; $xml .= '<expirationDate>' . esc_html($post_vars["x_exp_date"]) . '</expirationDate>'; $xml .= '<cardCode>' . esc_html($post_vars["x_card_code"]) . '</cardCode>'; $xml .= '</creditCard>'; $xml .= '</payment>'; /**/ $xml .= '<order>'; $xml .= '<invoiceNumber>' . esc_html($post_vars["x_invoice_num"]) . '</invoiceNumber>'; $xml .= '<description>' . esc_html($post_vars["x_description"]) . '</description>'; $xml .= '</order>'; /**/ $xml .= '<customer>'; $xml .= '<email>' . esc_html($post_vars["x_email"]) . '</email>'; $xml .= '</customer>'; /**/ $xml .= '<billTo>'; $xml .= '<firstName>' . esc_html($post_vars["x_first_name"]) . '</firstName>'; $xml .= '<lastName>' . esc_html($post_vars["x_last_name"]) . '</lastName>'; $xml .= '<address>' . esc_html($post_vars["x_address"]) . '</address>'; $xml .= '<city>' . esc_html($post_vars["x_city"]) . '</city>'; $xml .= '<state>' . esc_html($post_vars["x_state"]) . '</state>'; $xml .= '<zip>' . esc_html($post_vars["x_zip"]) . '</zip>'; $xml .= '<country>' . esc_html($post_vars["x_country"]) . '</country>'; $xml .= '</billTo>'; /**/ $xml .= '</subscription>'; /**/ $xml .= '</ARBCreateSubscriptionRequest>'; } else { if (!empty($post_vars["x_method"]) && $post_vars["x_method"] === "update") { $xml = '<?xml version="1.0" encoding="utf-8"?>'; /**/ $xml .= '<ARBUpdateSubscriptionRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">'; /**/ $xml .= '<merchantAuthentication>'; $xml .= '<name>' . esc_html($post_vars["x_login"]) . '</name>'; $xml .= '<transactionKey>' . esc_html($post_vars["x_tran_key"]) . '</transactionKey>'; $xml .= '</merchantAuthentication>'; /**/ $xml .= '<subscriptionId>' . esc_html($post_vars["x_subscription_id"]) . '</subscriptionId>'; /**/ $xml .= '<subscription>'; /**/ $xml .= '<payment>'; $xml .= '<creditCard>'; $xml .= '<cardNumber>' . esc_html($post_vars["x_card_num"]) . '</cardNumber>'; $xml .= '<expirationDate>' . esc_html($post_vars["x_exp_date"]) . '</expirationDate>'; $xml .= '<cardCode>' . esc_html($post_vars["x_card_code"]) . '</cardCode>'; $xml .= '</creditCard>'; $xml .= '</payment>'; /**/ $xml .= '<customer>'; $xml .= '<email>' . esc_html($post_vars["x_email"]) . '</email>'; $xml .= '</customer>'; /**/ $xml .= '<billTo>'; $xml .= '<firstName>' . esc_html($post_vars["x_first_name"]) . '</firstName>'; $xml .= '<lastName>' . esc_html($post_vars["x_last_name"]) . '</lastName>'; $xml .= '<address>' . esc_html($post_vars["x_address"]) . '</address>'; $xml .= '<city>' . esc_html($post_vars["x_city"]) . '</city>'; $xml .= '<state>' . esc_html($post_vars["x_state"]) . '</state>'; $xml .= '<zip>' . esc_html($post_vars["x_zip"]) . '</zip>'; $xml .= '<country>' . esc_html($post_vars["x_country"]) . '</country>'; $xml .= '</billTo>'; /**/ $xml .= '</subscription>'; /**/ $xml .= '</ARBUpdateSubscriptionRequest>'; } else { if (!empty($post_vars["x_method"]) && $post_vars["x_method"] === "status") { $xml = '<?xml version="1.0" encoding="utf-8"?>'; /**/ $xml .= '<ARBGetSubscriptionStatusRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">'; /**/ $xml .= '<merchantAuthentication>'; $xml .= '<name>' . esc_html($post_vars["x_login"]) . '</name>'; $xml .= '<transactionKey>' . esc_html($post_vars["x_tran_key"]) . '</transactionKey>'; $xml .= '</merchantAuthentication>'; /**/ $xml .= '<subscriptionId>' . esc_html($post_vars["x_subscription_id"]) . '</subscriptionId>'; /**/ $xml .= '</ARBGetSubscriptionStatusRequest>'; } else { if (!empty($post_vars["x_method"]) && $post_vars["x_method"] === "cancel") { $xml = '<?xml version="1.0" encoding="utf-8"?>'; /**/ $xml .= '<ARBCancelSubscriptionRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">'; /**/ $xml .= '<merchantAuthentication>'; $xml .= '<name>' . esc_html($post_vars["x_login"]) . '</name>'; $xml .= '<transactionKey>' . esc_html($post_vars["x_tran_key"]) . '</transactionKey>'; $xml .= '</merchantAuthentication>'; /**/ $xml .= '<subscriptionId>' . esc_html($post_vars["x_subscription_id"]) . '</subscriptionId>'; /**/ $xml .= '</ARBCancelSubscriptionRequest>'; } } } } /**/ $req["headers"]["Accept"] = "application/xml; charset=UTF-8"; $req["headers"]["Content-Type"] = "application/xml; charset=UTF-8"; /**/ $input_time = date("D M j, Y g:i:s a T"); /* Record input time for logging. */ /**/ $xml = trim(c_ws_plugin__s2member_utils_urls::remote($url, $xml, array_merge($req, array("timeout" => 20)))); /**/ $output_time = date("D M j, Y g:i:s a T"); /* Now record after output time. */ /**/ $response = c_ws_plugin__s2member_pro_authnet_utilities::_authnet_parse_arb_response($xml); /**/ if (empty($response["response_code"]) || $response["response_code"] !== "I00001") { if (strlen($response["response_reason_code"]) || $response["response_reason_text"]) { /* translators: Exclude `%2$s`. This is an English error returned by Authorize.Net®. Please replace `%2$s` with: `Unable to process, please try again`, or something to that affect. Or, if you prefer, you could Filter ``$response["__error"]`` with `ws_plugin__s2member_pro_authnet_arb_response`. */ $response["__error"] = sprintf(_x('Error #%1$s. %2$s.', "s2member-front", "s2member"), $response["response_reason_code"], rtrim($response["response_reason_text"], ".")); } else { /* Else, generate an error messsage - so something is reported back to the Customer. */ $response["__error"] = _x("Error. Please contact Support for assistance.", "s2member-front", "s2member"); } } /* If debugging is enabled; we need to maintain a comprehensive log file. Logging now supports Multisite Networking as well. */ $logv = c_ws_plugin__s2member_utilities::ver_details(); $logm = c_ws_plugin__s2member_utilities::mem_details(); $log4 = $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] . "\nUser-Agent: " . $_SERVER["HTTP_USER_AGENT"]; $log4 = is_multisite() && !is_main_site() ? ($_log4 = $current_blog->domain . $current_blog->path) . "\n" . $log4 : $log4; $log2 = is_multisite() && !is_main_site() ? "authnet-api-4-" . trim(preg_replace("/[^a-z0-9]/i", "-", $_log4), "-") . ".log" : "authnet-api.log"; /**/ if (strlen($post_vars["x_card_num"]) > 4) { /* Only log last 4 digits for security. */ $post_vars["x_card_num"] = str_repeat("*", strlen($post_vars["x_card_num"]) - 4) . substr($post_vars["x_card_num"], -4); } /* Then display last 4 digits. */ /**/ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs"]) { if (is_dir($logs_dir = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"])) { if (is_writable($logs_dir) && c_ws_plugin__s2member_utils_logs::archive_oversize_log_files()) { if ($log = "-------- Input vars: ( " . $input_time . " ) --------\n" . var_export($post_vars, true) . "\n") { if ($log .= "-------- Output string/vars: ( " . $output_time . " ) --------\n" . $xml . "\n" . var_export($response, true)) { file_put_contents($logs_dir . "/" . $log2, $logv . "\n" . $logm . "\n" . $log4 . "\n" . $log . "\n\n", FILE_APPEND); } } } } } /**/ return apply_filters("ws_plugin__s2member_pro_authnet_arb_response", c_ws_plugin__s2member_pro_authnet_utilities::_authnet_arb_response_filters($response), get_defined_vars()); }