/** * Handles Authorize.Net IPN URL processing. * * @package s2Member\AuthNet * @since 1.5 * * @attaches-to ``add_action('init');`` */ public static function authnet_notify() { global $current_site, $current_blog; // For Multisite support. if (!empty($_GET['s2member_pro_authnet_notify']) && $GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_authnet_api_login_id']) { @ignore_user_abort(TRUE); // Continue processing even if/when connection is broken by the sender. if (is_array($authnet = c_ws_plugin__s2member_pro_authnet_utilities::authnet_postvars()) && ($_authnet = $authnet)) { $processing = $processed = FALSE; // Initialize these flags. $authnet['s2member_log'][] = 'IPN received on: ' . date('D M j, Y g:i:s a T'); $authnet['s2member_log'][] = 's2Member POST vars verified with Authorize.Net.'; if ($authnet['x_subscription_id'] && $authnet['x_subscription_paynum'] && $authnet['x_response_code'] === '1') { if (($_authnet = c_ws_plugin__s2member_pro_authnet_utilities::authnet_parse_arb_desc($authnet)) && ($authnet = $_authnet)) { $authnet['s2member_log'][] = 'Authorize.Net transaction identified as (`ARB / PAYMENT #' . $authnet['x_subscription_paynum'] . '`).'; if ($user_id = c_ws_plugin__s2member_utils_users::get_user_id_with($authnet['x_subscription_id'])) { delete_user_option($user_id, 's2member_authnet_payment_failures'); $authnet['s2member_log'][] = 'Successful payment. Resetting payment failures to `0` for this subscription.'; } $authnet['s2member_log'][] = 'IPN reformulated. Piping through s2Member\'s core/standard PayPal processor as `txn_type` (`subscr_payment`).'; $authnet['s2member_log'][] = 'Please check PayPal IPN logs for further processing details.'; $processing = $processed = TRUE; $ipn = array(); // Reset. $ipn['txn_type'] = 'subscr_payment'; $ipn['subscr_id'] = $authnet['x_subscription_id']; $ipn['txn_id'] = $authnet['x_trans_id']; $ipn['custom'] = $authnet['s2_custom']; $ipn['mc_gross'] = number_format($authnet['x_amount'], 2, '.', ''); $ipn['mc_currency'] = strtoupper(!empty($authnet['s2_currency']) ? $authnet['s2_currency'] : 'USD'); $ipn['tax'] = number_format($authnet['x_tax'], 2, '.', ''); $ipn['payer_email'] = $authnet['x_email']; $ipn['first_name'] = $authnet['x_first_name']; $ipn['last_name'] = $authnet['x_last_name']; $ipn['option_name1'] = 'Referencing Customer ID'; $ipn['option_selection1'] = $authnet['x_subscription_id']; $ipn['option_name2'] = 'Customer IP Address'; $ipn['option_selection2'] = NULL; $ipn['item_number'] = $authnet['s2_invoice']; $ipn['item_name'] = $authnet['x_description']; $ipn['s2member_paypal_proxy'] = 'authnet'; $ipn['s2member_paypal_proxy_use'] = 'pro-emails'; $ipn['s2member_paypal_proxy_verification'] = c_ws_plugin__s2member_paypal_utilities::paypal_proxy_key_gen(); c_ws_plugin__s2member_utils_urls::remote(home_url('/?s2member_paypal_notify=1'), $ipn, array('timeout' => 20)); } else { $authnet['s2member_log'][] = 'Authorize.Net transaction identified as (`ARB / PAYMENT #' . $authnet['x_subscription_paynum'] . '`).'; $authnet['s2member_log'][] = 'Ignoring this IPN. The transaction does NOT contain a valid reference value/desc.'; } } else { if ($authnet['x_subscription_id'] && $authnet['x_subscription_paynum'] && preg_match('/^(2|3)$/', $authnet['x_response_code'])) { if (($_authnet = c_ws_plugin__s2member_pro_authnet_utilities::authnet_parse_arb_desc($authnet)) && ($authnet = $_authnet)) { if ($user_id = c_ws_plugin__s2member_utils_users::get_user_id_with($authnet['x_subscription_id'])) { if ($GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_authnet_max_payment_failures'] && ($current_payment_failures = get_user_option('s2member_authnet_payment_failures', $user_id)) + 1 >= $GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_authnet_max_payment_failures']) { $authnet['s2member_log'][] = 'Authorize.Net transaction identified as (`ARB / FAILED PAYMENT`).'; $authnet['s2member_log'][] = 'This subscription has `' . $GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_authnet_max_payment_failures'] . '` or more failed payments.'; $authnet['s2member_log'][] = 'Max failed payments. IPN reformulated. Piping through s2Member\'s core/standard PayPal processor as `txn_type` (`subscr_eot`).'; $authnet['s2member_log'][] = 'Please check PayPal IPN logs for further processing details.'; $processing = $processed = TRUE; $ipn = array(); // Reset. $ipn['txn_type'] = 'subscr_eot'; $ipn['subscr_id'] = $authnet['x_subscription_id']; $ipn['custom'] = $authnet['s2_custom']; $ipn['period1'] = $authnet['s2_p1']; $ipn['period3'] = $authnet['s2_p3']; $ipn['payer_email'] = $authnet['x_email']; $ipn['first_name'] = $authnet['x_first_name']; $ipn['last_name'] = $authnet['x_last_name']; $ipn['option_name1'] = 'Referencing Customer ID'; $ipn['option_selection1'] = $authnet['x_subscription_id']; $ipn['option_name2'] = 'Customer IP Address'; $ipn['option_selection2'] = NULL; $ipn['item_number'] = $authnet['s2_invoice']; $ipn['item_name'] = $authnet['x_description']; $ipn['s2member_paypal_proxy'] = 'authnet'; $ipn['s2member_paypal_proxy_use'] = 'pro-emails'; $ipn['s2member_paypal_proxy_verification'] = c_ws_plugin__s2member_paypal_utilities::paypal_proxy_key_gen(); c_ws_plugin__s2member_utils_urls::remote(home_url('/?s2member_paypal_notify=1'), $ipn, array('timeout' => 20)); c_ws_plugin__s2member_pro_authnet_utilities::authnet_arb_response(array('x_method' => 'cancel', 'x_subscription_id' => $authnet['x_subscription_id'])); } else { $current_payment_failures = get_user_option('s2member_authnet_payment_failures', $user_id); update_user_option($user_id, 's2member_authnet_payment_failures', $current_payment_failures + 1); $authnet['s2member_log'][] = 'Bumping payment failures for subscription: `' . $authnet['x_subscription_id'] . '`, to: `' . ($current_payment_failures + 1) . '`'; $authnet['s2member_log'][] = 'Recording number of payment failures only. This does not require any action (at the moment) on the part of s2Member.'; } } else { $authnet['s2member_log'][] = 'Authorize.Net transaction identified as (`ARB / FAILED PAYMENT`).'; $authnet['s2member_log'][] = 'Ignoring this IPN. The transaction does NOT contain a valid reference to an existing user/member.'; } } else { $authnet['s2member_log'][] = 'Authorize.Net transaction identified as (`ARB / FAILED PAYMENT`).'; $authnet['s2member_log'][] = 'Ignoring this IPN. The transaction does NOT contain a valid reference value/desc.'; } } else { if (!$processed) { // If nothing was processed, here we add a message to the logs indicating the IPN was ignored. $authnet['s2member_log'][] = 'Ignoring this IPN. The transaction does NOT require any action on the part of s2Member.'; } } } } else { $authnet['s2member_log'][] = 'Unable to verify POST vars. This is most likely related to an invalid Authorize.Net configuration. Please check: s2Member → Authorize.Net Options.'; $authnet['s2member_log'][] = 'If you\'re absolutely SURE that your Authorize.Net configuration is valid, you may want to run some tests on your server, just to be sure \\$_POST variables are populated, and that your server is able to connect to Authorize.Net over an HTTPS connection.'; $authnet['s2member_log'][] = 's2Member uses the WP_Http class for remote connections; which will try to use cURL first, and then fall back on the FOPEN method when cURL is not available. On a Windows server, you may have to disable your cURL extension. Instead, set allow_url_fopen = yes in your php.ini file. The cURL extension (usually) does NOT support SSL connections on a Windows server.'; $authnet['s2member_log'][] = var_export($_REQUEST, TRUE); // Recording _POST + _GET vars for analysis and debugging. } /* If debugging/logging is enabled; we need to append $authnet to the log file. Logging now supports Multisite Networking as well. */ $logt = c_ws_plugin__s2member_utilities::time_details(); $logv = c_ws_plugin__s2member_utilities::ver_details(); $logm = c_ws_plugin__s2member_utilities::mem_details(); $log4 = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . "\n" . 'User-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-ipn-4-' . trim(preg_replace('/[^a-z0-9]/i', '-', !empty($_log4) ? $_log4 : ''), '-') . '.log' : 'authnet-ipn.log'; 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()) { file_put_contents($logs_dir . '/' . $log2, 'LOG ENTRY: ' . $logt . "\n" . $logv . "\n" . $logm . "\n" . $log4 . "\n" . c_ws_plugin__s2member_utils_logs::conceal_private_info(var_export($authnet, TRUE)) . "\n\n", FILE_APPEND); } } } status_header(200); // Send a 200 OK status header. header('Content-Type: text/plain; charset=UTF-8'); // Content-Type text/plain with UTF-8. while (@ob_end_clean()) { } // Clean any existing output buffers. exit; // Exit now. } }
/** * Handles Authorize.Net® IPN URL processing. * * @package s2Member\AuthNet * @since 1.5 * * @attaches-to ``add_action("init");`` * * @return null Or exits script execution after handling IPN processing. */ public static function authnet_notify() { global $current_site, $current_blog; /* For Multisite support. */ /**/ if (!empty($_GET["s2member_pro_authnet_notify"]) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["pro_authnet_api_login_id"]) { @ignore_user_abort(true); /* Continue processing even if/when connection is broken by the sender. */ /**/ if (is_array($authnet = c_ws_plugin__s2member_pro_authnet_utilities::authnet_postvars()) && ($_authnet = $authnet)) { $authnet["s2member_log"][] = "IPN received on: " . date("D M j, Y g:i:s a T"); $authnet["s2member_log"][] = "s2Member POST vars verified with Authorize.Net®."; /**/ if ($authnet["x_subscription_id"] && $authnet["x_subscription_paynum"] && $authnet["x_response_code"] === "1") { if (($_authnet = c_ws_plugin__s2member_pro_authnet_utilities::authnet_parse_arb_desc($authnet)) && ($authnet = $_authnet)) { $authnet["s2member_log"][] = "Authorize.Net® transaction identified as ( `ARB / PAYMENT #" . $authnet["x_subscription_paynum"] . "` )."; $authnet["s2member_log"][] = "IPN reformulated. Piping through s2Member's core/standard PayPal® processor as `txn_type` ( `subscr_payment` )."; $authnet["s2member_log"][] = "Please check PayPal® IPN logs for further processing details."; /**/ $processing = $processed = true; $ipn = array(); /* Reset. */ /**/ $ipn["txn_type"] = "subscr_payment"; $ipn["subscr_id"] = $authnet["x_subscription_id"]; $ipn["txn_id"] = $authnet["x_trans_id"]; /**/ $ipn["custom"] = $authnet["s2_custom"]; /**/ $ipn["mc_gross"] = number_format($authnet["x_amount"], 2, ".", ""); $ipn["mc_currency"] = strtoupper("USD"); /* Auth.Net® uses USD. */ $ipn["tax"] = number_format($authnet["x_tax"], 2, ".", ""); /**/ $ipn["payer_email"] = $authnet["x_email"]; $ipn["first_name"] = $authnet["x_first_name"]; $ipn["last_name"] = $authnet["x_last_name"]; /**/ $ipn["option_name1"] = "Referencing Customer ID"; $ipn["option_selection1"] = $authnet["x_subscription_id"]; /**/ $ipn["option_name2"] = "Customer IP Address"; $ipn["option_selection2"] = null; /**/ $ipn["item_number"] = $authnet["s2_invoice"]; $ipn["item_name"] = $authnet["x_description"]; /**/ $ipn_q = "&s2member_paypal_proxy=authnet&s2member_paypal_proxy_use=pro-emails"; $ipn_q .= "&s2member_paypal_proxy_verification=" . urlencode(c_ws_plugin__s2member_paypal_utilities::paypal_proxy_key_gen()); /**/ c_ws_plugin__s2member_utils_urls::remote(site_url("/?s2member_paypal_notify=1" . $ipn_q), $ipn, array("timeout" => 20)); } else { $authnet["s2member_log"][] = "Authorize.Net® transaction identified as ( `ARB / PAYMENT #" . $authnet["x_subscription_paynum"] . "` )."; $authnet["s2member_log"][] = "Ignoring this IPN. The transaction does NOT contain a valid reference value/desc."; } } else { if ($authnet["x_subscription_id"] && $authnet["x_subscription_paynum"] && preg_match("/^(2|3)\$/", $authnet["x_response_code"])) { if (($_authnet = c_ws_plugin__s2member_pro_authnet_utilities::authnet_parse_arb_desc($authnet)) && ($authnet = $_authnet)) { $authnet["s2member_log"][] = "Authorize.Net® transaction identified as ( `ARB / FAILED PAYMENT` )."; $authnet["s2member_log"][] = "s2Member does NOT respond to individual failed payment notifications."; $authnet["s2member_log"][] = "When multiple consecutive payments fail, s2Member is notified via ARB services."; $authnet["s2member_log"][] = "This does not require any action ( at the moment ) on the part of s2Member."; } else { $authnet["s2member_log"][] = "Authorize.Net® transaction identified as ( `ARB / FAILED PAYMENT` )."; $authnet["s2member_log"][] = "Ignoring this IPN. The transaction does NOT contain a valid reference value/desc."; } } else { if (!$processed) { /* If nothing was processed, here we add a message to the logs indicating the IPN was ignored. */ $authnet["s2member_log"][] = "Ignoring this IPN. The transaction does NOT require any action on the part of s2Member."; } } } } else { $authnet["s2member_log"][] = "Unable to verify POST vars. This is most likely related to an invalid Authorize.Net® configuration. Please check: s2Member -> Authorize.Net® Options."; $authnet["s2member_log"][] = "If you're absolutely SURE that your Authorize.Net® configuration is valid, you may want to run some tests on your server, just to be sure \$_POST variables are populated, and that your server is able to connect to Authorize.Net® over an HTTPS connection."; $authnet["s2member_log"][] = "s2Member uses the WP_Http class for remote connections; which will try to use cURL first, and then fall back on the FOPEN method when cURL is not available. On a Windows® server, you may have to disable your cURL extension. Instead, set allow_url_fopen = yes in your php.ini file. The cURL extension (usually) does NOT support SSL connections on a Windows® server."; $authnet["s2member_log"][] = var_export($_REQUEST, true); /* Recording _POST + _GET vars for analysis and debugging. */ } /* If debugging/logging is enabled; we need to append $authnet to the 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-ipn-4-" . trim(preg_replace("/[^a-z0-9]/i", "-", $_log4), "-") . ".log" : "authnet-ipn.log"; /**/ 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()) { file_put_contents($logs_dir . "/" . $log2, $logv . "\n" . $logm . "\n" . $log4 . "\n" . var_export($authnet, true) . "\n\n", FILE_APPEND); } } } /**/ status_header(200); /* Send a 200 OK status header. */ header("Content-Type: text/plain; charset=utf-8"); /* Content-Type text/plain with UTF-8. */ eval('while (@ob_end_clean ());'); /* End/clean all output buffers that may or may not exist. */ /**/ exit; /* Exit now. */ } }