function s2member_pro_clickbank_order($user_id = 0)
 {
     if (!$user_id) {
         $user_id = get_current_user_id();
     }
     if (!$user_id) {
         return array();
     }
     // Not possible.
     $subscr_id = get_user_option('s2member_subscr_id', $user_id);
     $subscr_gateway = get_user_option('s2member_subscr_gateway', $user_id);
     $ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars($user_id);
     if (!$subscr_id || $subscr_gateway !== 'clickbank') {
         return array();
     }
     // Not applicable.
     if (!$ipn_signup_vars || empty($ipn_signup_vars['txn_id'])) {
         return array();
     }
     // Not possible.
     return c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_api_order($ipn_signup_vars['txn_id']);
 }
 /**
  * Handles ClickBank® Return URL processing.
  *
  * @package s2Member\ClickBank
  * @since 1.5
  *
  * @attaches-to ``add_action("init");``
  *
  * @return null Or exits script execution after redirection.
  */
 public static function clickbank_return()
 {
     global $current_site, $current_blog;
     /**/
     if (!empty($_GET["s2member_pro_clickbank_return"]) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["pro_clickbank_username"]) {
         if (is_array($clickbank = c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_postvars()) && ($_clickbank = $clickbank)) {
             $clickbank["s2member_log"][] = "Return-Data received on: " . date("D M j, Y g:i:s a T");
             $clickbank["s2member_log"][] = "s2Member POST vars verified with ClickBank®.";
             /**/
             $clickbank["s2member_log"][] = "Sleeping for 5 seconds. Giving ClickBank® a chance to finalize processing.";
             sleep(5);
             $clickbank["s2member_log"][] = "Awake. It's " . date("D M j, Y g:i:s a T") . ". Processing will continue.";
             /**/
             if (is_array($order = json_decode(c_ws_plugin__s2member_utils_urls::remote("https://api.clickbank.com/rest/1.2/orders/" . $clickbank["cbreceipt"], false, array_merge(c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_api_headers(), array("timeout" => 20))), true)) && ($order = $order["orderData"])) {
                 $clickbank["s2member_log"][] = "Order API variables have been obtained from ClickBank®.";
                 /**/
                 $s2vars = c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_parse_s2vars(http_build_query($clickbank), $order["txnType"]);
                 /**/
                 if (isset($s2vars["s2_p1"], $s2vars["s2_p3"]) && $s2vars["s2_p1"] === "0 D") {
                     $s2vars["s2_p1"] = $s2vars["s2_p3"];
                 }
                 /**/
                 $clickbank["s2vars"] = $s2vars;
                 /**/
                 if (strcasecmp($order["firstName"] . " " . $order["lastName"], $order["customerDisplayName"]) !== 0 && preg_match("/([^ ]+)( +)([^ ]+)/", $order["customerDisplayName"])) {
                     list($order["firstName"], $order["lastName"]) = preg_split("/ +/", $order["customerDisplayName"], 2);
                 }
                 /**/
                 if (preg_match("/^(TEST_)?SALE\$/i", $order["txnType"]) && !isset($s2vars["s2_p1"], $s2vars["s2_p3"])) {
                     $clickbank["s2member_log"][] = "ClickBank® transaction identified as ( `SALE/STANDARD` ).";
                     $clickbank["s2member_log"][] = "Return-Data reformulated. Piping through s2Member's core/standard PayPal® processor as `txn_type` ( `web_accept` ).";
                     $clickbank["s2member_log"][] = "Please check PayPal® RTN logs for further processing details.";
                     /**/
                     $rtn = array();
                     /* Reset. */
                     /**/
                     $rtn["txn_type"] = "web_accept";
                     /**/
                     $rtn["txn_id"] = $order["receipt"];
                     $rtn["custom"] = $s2vars["s2_custom"];
                     /**/
                     $rtn["mc_gross"] = number_format($order["amount"], 2, ".", "");
                     $rtn["mc_currency"] = strtoupper($order["currency"]);
                     $rtn["tax"] = "0.00";
                     /* No tax. */
                     /**/
                     $rtn["payer_email"] = $order["email"];
                     $rtn["first_name"] = ucwords(strtolower($order["firstName"]));
                     $rtn["last_name"] = ucwords(strtolower($order["lastName"]));
                     /**/
                     $rtn["option_name1"] = $s2vars["s2_referencing"] ? "Referencing Customer ID" : "Originating Domain";
                     $rtn["option_selection1"] = $s2vars["s2_referencing"] ? $s2vars["s2_referencing"] : $_SERVER["HTTP_HOST"];
                     /**/
                     $rtn["option_name2"] = "Customer IP Address";
                     $rtn["option_selection2"] = $s2vars["s2_customer_ip"];
                     /**/
                     $rtn["item_number"] = $s2vars["s2_invoice"];
                     $rtn["item_name"] = $s2vars["s2_desc"];
                     /**/
                     $rtn_q = "&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-emails";
                     if (!empty($_GET["s2member_pro_clickbank_return_success"])) {
                         $rtn_q .= "&s2member_paypal_return_success=" . rawurlencode(trim(stripslashes($_GET["s2member_pro_clickbank_return_success"])));
                     }
                     /**/
                     $rtn_r = add_query_arg(urlencode_deep($rtn), site_url("/?s2member_pro_clickbank_return&s2member_paypal_return=1" . $rtn_q));
                     $rtn_r = c_ws_plugin__s2member_utils_urls::add_s2member_sig($rtn_r, "s2member_paypal_proxy_verification");
                     /**/
                     $clickbank["s2member_log"][] = $rtn_r;
                     /**/
                     wp_redirect($rtn_r);
                 } else {
                     if (preg_match("/^(TEST_)?SALE\$/i", $order["txnType"]) && isset($s2vars["s2_p1"], $s2vars["s2_p3"])) {
                         $clickbank["s2member_log"][] = "ClickBank® transaction identified as ( `SALE/RECURRING` ).";
                         $clickbank["s2member_log"][] = "Return-Data reformulated. Piping through s2Member's core/standard PayPal® processor as `txn_type` ( `subscr_signup` ).";
                         $clickbank["s2member_log"][] = "Please check PayPal® RTN logs for further processing details.";
                         /**/
                         $rtn = array();
                         /* Reset. */
                         /**/
                         $rtn["txn_type"] = "subscr_signup";
                         $rtn["subscr_id"] = $s2vars["s2_subscr_id"];
                         $rtn["recurring"] = $order["futurePayments"] > 1 ? "1" : "0";
                         /**/
                         $rtn["txn_id"] = $order["receipt"];
                         $rtn["custom"] = $s2vars["s2_custom"];
                         /**/
                         $rtn["period1"] = $s2vars["s2_p1"];
                         $rtn["period3"] = $s2vars["s2_p3"];
                         /**/
                         $rtn["mc_amount1"] = number_format($order["amount"], 2, ".", "");
                         $rtn["mc_amount3"] = number_format($order["rebillAmount"], 2, ".", "");
                         /**/
                         $rtn["mc_currency"] = strtoupper($order["currency"]);
                         $rtn["tax"] = "0.00";
                         /* No tax. */
                         /**/
                         $rtn["payer_email"] = $order["email"];
                         $rtn["first_name"] = ucwords(strtolower($order["firstName"]));
                         $rtn["last_name"] = ucwords(strtolower($order["lastName"]));
                         /**/
                         $rtn["option_name1"] = $s2vars["s2_referencing"] ? "Referencing Customer ID" : "Originating Domain";
                         $rtn["option_selection1"] = $s2vars["s2_referencing"] ? $s2vars["s2_referencing"] : $_SERVER["HTTP_HOST"];
                         /**/
                         $rtn["option_name2"] = "Customer IP Address";
                         $rtn["option_selection2"] = $s2vars["s2_customer_ip"];
                         /**/
                         $rtn["item_number"] = $s2vars["s2_invoice"];
                         $rtn["item_name"] = $s2vars["s2_desc"];
                         /**/
                         $rtn_q = "&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-emails";
                         if (!empty($_GET["s2member_pro_clickbank_return_success"])) {
                             $rtn_q .= "&s2member_paypal_return_success=" . rawurlencode(trim(stripslashes($_GET["s2member_pro_clickbank_return_success"])));
                         }
                         /**/
                         $rtn_r = add_query_arg(urlencode_deep($rtn), site_url("/?s2member_pro_clickbank_return&s2member_paypal_return=1" . $rtn_q));
                         $rtn_r = c_ws_plugin__s2member_utils_urls::add_s2member_sig($rtn_r, "s2member_paypal_proxy_verification");
                         /**/
                         $clickbank["s2member_log"][] = $rtn_r;
                         /**/
                         wp_redirect($rtn_r);
                     } else {
                         $clickbank["s2member_log"][] = "Unexpected txnType. The ClickBank® txnType did not match a required action.";
                         /**/
                         $clickbank["s2member_log"][] = "Redirecting Customer to the Home Page, due to an error that occurred.";
                         /**/
                         echo '<script type="text/javascript">' . "\n";
                         echo "alert('" . c_ws_plugin__s2member_utils_strings::esc_js_sq(_x("ERROR: Unexpected txnType. Please contact Support for assistance.\n\nThe ClickBank® txnType did not match a required action.", "s2member-front", "s2member")) . "');" . "\n";
                         echo "window.location = '" . c_ws_plugin__s2member_utils_strings::esc_js_sq(home_url("/")) . "';";
                         echo '</script>' . "\n";
                     }
                 }
             } else {
                 $clickbank["s2member_log"][] = "Unable to obtain API vars. The ClickBank® API may NOT have data for this order yet. Or, your ClickBank® API Keys are NOT configured properly under `s2Member -> ClickBank® Options`.";
                 $clickbank["s2member_log"][] = var_export($_REQUEST, true);
                 /* Recording ``$_POST`` + ``$_GET`` vars for analysis and debugging. */
                 /**/
                 $clickbank["s2member_log"][] = "Return-Data reformulated. Piping through s2Member's core/standard PayPal® processor with `proxy_use` ( `ty-email` ).";
                 $clickbank["s2member_log"][] = "Please check PayPal® RTN logs for further processing details.";
                 /**/
                 $rtn_q = "&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-emails,ty-email";
                 if (!empty($_GET["s2member_pro_clickbank_return_success"])) {
                     $rtn_q .= "&s2member_paypal_return_success=" . rawurlencode(trim(stripslashes($_GET["s2member_pro_clickbank_return_success"])));
                 }
                 /**/
                 $rtn_r = site_url("/?s2member_pro_clickbank_return&s2member_paypal_return=1" . $rtn_q);
                 $rtn_r = c_ws_plugin__s2member_utils_urls::add_s2member_sig($rtn_r, "s2member_paypal_proxy_verification");
                 /**/
                 $clickbank["s2member_log"][] = $rtn_r;
                 /**/
                 wp_redirect($rtn_r);
             }
         } else {
             $clickbank["s2member_log"][] = "Unable to verify POST vars. This is most likely related to an invalid ClickBank® configuration. Please check: s2Member -> ClickBank® Options.";
             $clickbank["s2member_log"][] = "If you're absolutely SURE that your ClickBank® 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 ClickBank® over an HTTPS connection.";
             $clickbank["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.";
             $clickbank["s2member_log"][] = var_export($_REQUEST, true);
             /* Recording _POST + _GET vars for analysis and debugging. */
             /**/
             $clickbank["s2member_log"][] = "Redirecting Customer to the Home Page, due to an error that occurred.";
             /**/
             echo '<script type="text/javascript">' . "\n";
             echo "alert('" . c_ws_plugin__s2member_utils_strings::esc_js_sq(_x("ERROR: Unable to verify POST vars. Please contact Support for assistance.\n\nThis is most likely related to an invalid ClickBank® configuration. If you are the site owner, please check: s2Member -> ClickBank® Options.", "s2member-front", "s2member")) . "');" . "\n";
             echo "window.location = '" . c_ws_plugin__s2member_utils_strings::esc_js_sq(home_url("/")) . "';";
             echo '</script>' . "\n";
         }
         /**/
         $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() ? "clickbank-rtn-4-" . trim(preg_replace("/[^a-z0-9]/i", "-", $_log4), "-") . ".log" : "clickbank-rtn.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($clickbank, true) . "\n\n", FILE_APPEND);
                 }
             }
         }
         /**/
         exit;
         /* Exit now. */
     }
 }
 /**
  * Handles ClickBank IPN URL processing.
  *
  * @package s2Member\ClickBank
  * @since 1.5
  *
  * @attaches-to ``add_action('init');``
  */
 public static function clickbank_notify()
 {
     global $current_site, $current_blog;
     // For Multisite support.
     if (!empty($_GET['s2member_pro_clickbank_notify']) && $GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_clickbank_username']) {
         @ignore_user_abort(TRUE);
         // Continue processing even if/when connection is broken by the sender.
         if (is_array($clickbank = c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_postvars_v2_1()) && ($_clickbank = $clickbank)) {
             $clickbank['s2member_log'][] = 'IPN received on: ' . date('D M j, Y g:i:s a T');
             $clickbank['s2member_log'][] = 's2Member POST vars verified with ClickBank.';
             $s2vars = c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_parse_s2vars_v2_1($clickbank['cvendthru'], $clickbank['ctransaction']);
             if (isset($s2vars['s2_p1'], $s2vars['s2_p3']) && $s2vars['s2_p1'] === '0 D') {
                 // No Trial defaults to Regular Period.
                 $s2vars['s2_p1'] = $s2vars['s2_p3'];
             }
             // Initial Period. No Trial defaults to Regular Period.
             $clickbank['s2vars'] = $s2vars;
             // So they appear in the log entry for this Notification.
             if (strcasecmp($clickbank['ccustfirstname'] . ' ' . $clickbank['ccustlastname'], $clickbank['ccustfullname']) !== 0 && preg_match('/(?:[^ ]+)(?: +)(?:[^ ]+)/', $clickbank['ccustfullname'])) {
                 list($clickbank['ccustfirstname'], $clickbank['ccustlastname']) = preg_split('/ +/', $clickbank['ccustfullname'], 2);
             }
             if (preg_match('/^(?:TEST_)?SALE$/i', $clickbank['ctransaction']) && preg_match('/^STANDARD$/i', $clickbank['cprodtype'])) {
                 $clickbank['s2member_log'][] = 'ClickBank transaction identified as ( `SALE/STANDARD` ).';
                 $clickbank['s2member_log'][] = 'IPN reformulated. Piping through s2Member\'s core/standard PayPal processor as `txn_type` ( `web_accept` ).';
                 $clickbank['s2member_log'][] = 'Please check PayPal IPN logs for further processing details.';
                 $processing = $processed = TRUE;
                 $ipn = array();
                 // Reset.
                 $ipn['txn_type'] = 'web_accept';
                 $ipn['txn_id'] = $clickbank['ctransreceipt'];
                 $ipn['custom'] = $s2vars['s2_custom'];
                 $ipn['mc_gross'] = number_format($clickbank['corderamount'] / 100, 2, '.', '');
                 $ipn['mc_currency'] = strtoupper($clickbank['ccurrency']);
                 $ipn['tax'] = number_format('0.00', 2, '.', '');
                 $ipn['payer_email'] = $clickbank['ccustemail'];
                 $ipn['first_name'] = ucwords(strtolower($clickbank['ccustfirstname']));
                 $ipn['last_name'] = ucwords(strtolower($clickbank['ccustlastname']));
                 $ipn['option_name1'] = $s2vars['s2_referencing'] ? 'Referencing Customer ID' : 'Originating Domain';
                 $ipn['option_selection1'] = $s2vars['s2_referencing'] ? $s2vars['s2_referencing'] : $_SERVER['HTTP_HOST'];
                 $ipn['option_name2'] = 'Customer IP Address';
                 $ipn['option_selection2'] = $s2vars['s2_customer_ip'];
                 $ipn['item_number'] = $s2vars['s2_invoice'];
                 $ipn['item_name'] = $s2vars['s2_desc'];
                 $ipn['s2member_paypal_proxy'] = 'clickbank';
                 $ipn['s2member_paypal_proxy_use'] = 'standard-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 {
                 if (preg_match('/^(?:TEST_)?SALE$/i', $clickbank['ctransaction']) && preg_match('/^RECURRING$/i', $clickbank['cprodtype'])) {
                     $clickbank['s2member_log'][] = 'ClickBank transaction identified as ( `SALE/RECURRING` ).';
                     $clickbank['s2member_log'][] = 'IPN reformulated. Piping through s2Member\'s core/standard PayPal processor as `txn_type` ( `subscr_signup` ).';
                     $clickbank['s2member_log'][] = 'Please check PayPal IPN logs for further processing details.';
                     $processing = $processed = TRUE;
                     $ipn = array();
                     // Reset.
                     $ipn['txn_type'] = 'subscr_signup';
                     $ipn['subscr_id'] = $s2vars['s2_subscr_id'];
                     $ipn['recurring'] = $clickbank['cfuturepayments'] > 1 ? '1' : '0';
                     $ipn['txn_id'] = $clickbank['ctransreceipt'];
                     $ipn['custom'] = $s2vars['s2_custom'];
                     $ipn['period1'] = $s2vars['s2_p1'];
                     $ipn['period3'] = $s2vars['s2_p3'];
                     $ipn['mc_amount1'] = number_format($clickbank['corderamount'] / 100, 2, '.', '');
                     $ipn['mc_amount3'] = number_format($clickbank['crebillamnt'] / 100, 2, '.', '');
                     $ipn['mc_gross'] = preg_match('/^[1-9]/', $ipn['period1']) ? $ipn['mc_amount1'] : $ipn['mc_amount3'];
                     $ipn['mc_currency'] = strtoupper($clickbank['ccurrency']);
                     $ipn['tax'] = number_format('0.00', 2, '.', '');
                     $ipn['payer_email'] = $clickbank['ccustemail'];
                     $ipn['first_name'] = ucwords(strtolower($clickbank['ccustfirstname']));
                     $ipn['last_name'] = ucwords(strtolower($clickbank['ccustlastname']));
                     $ipn['option_name1'] = $s2vars['s2_referencing'] ? 'Referencing Customer ID' : 'Originating Domain';
                     $ipn['option_selection1'] = $s2vars['s2_referencing'] ? $s2vars['s2_referencing'] : $_SERVER['HTTP_HOST'];
                     $ipn['option_name2'] = 'Customer IP Address';
                     $ipn['option_selection2'] = $s2vars['s2_customer_ip'];
                     $ipn['item_number'] = $s2vars['s2_invoice'];
                     $ipn['item_name'] = $s2vars['s2_desc'];
                     $ipn['s2member_paypal_proxy'] = 'clickbank';
                     $ipn['s2member_paypal_proxy_use'] = 'standard-emails';
                     $ipn['s2member_paypal_proxy_use'] .= $ipn['mc_gross'] > 0 ? ',subscr-signup-as-subscr-payment' : '';
                     $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 {
                     if (preg_match('/^(?:TEST_)?BILL$/i', $clickbank['ctransaction']) && preg_match('/^RECURRING$/i', $clickbank['cprodtype'])) {
                         $clickbank['s2member_log'][] = 'ClickBank transaction identified as ( `BILL/RECURRING` ).';
                         $clickbank['s2member_log'][] = 'IPN reformulated. Piping through s2Member\'s core/standard PayPal processor as `txn_type` ( `subscr_payment` ).';
                         $clickbank['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'] = $s2vars['s2_subscr_id'];
                         $ipn['txn_id'] = $clickbank['ctransreceipt'];
                         $ipn['custom'] = $s2vars['s2_custom'];
                         $ipn['mc_gross'] = number_format($clickbank['corderamount'] / 100, 2, '.', '');
                         $ipn['mc_currency'] = strtoupper($clickbank['ccurrency']);
                         $ipn['tax'] = number_format('0.00', 2, '.', '');
                         $ipn['payer_email'] = $clickbank['ccustemail'];
                         $ipn['first_name'] = ucwords(strtolower($clickbank['ccustfirstname']));
                         $ipn['last_name'] = ucwords(strtolower($clickbank['ccustlastname']));
                         $ipn['option_name1'] = $s2vars['s2_referencing'] ? 'Referencing Customer ID' : 'Originating Domain';
                         $ipn['option_selection1'] = $s2vars['s2_referencing'] ? $s2vars['s2_referencing'] : $_SERVER['HTTP_HOST'];
                         $ipn['option_name2'] = 'Customer IP Address';
                         $ipn['option_selection2'] = $s2vars['s2_customer_ip'];
                         $ipn['item_number'] = $s2vars['s2_invoice'];
                         $ipn['item_name'] = $s2vars['s2_desc'];
                         $ipn['s2member_paypal_proxy'] = 'clickbank';
                         $ipn['s2member_paypal_proxy_use'] = 'standard-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 {
                         if (preg_match('/^(?:TEST_)?(?:RFND|CGBK|INSF)$/i', $clickbank['ctransaction'])) {
                             $clickbank['s2member_log'][] = 'ClickBank transaction identified as ( `RFND|CGBK|INSF` ).';
                             $clickbank['s2member_log'][] = 'IPN reformulated. Piping through s2Member\'s core/standard PayPal processor as `payment_status` ( `refunded|reversed` ).';
                             $clickbank['s2member_log'][] = 'Please check PayPal IPN logs for further processing details.';
                             $processing = $processed = TRUE;
                             $ipn = array();
                             // Reset.
                             $ipn['payment_status'] = preg_match('/^(?:TEST_)?RFND$/', $clickbank['ctransaction']) ? 'refunded' : 'reversed';
                             $ipn['parent_txn_id'] = preg_match('/^RECURRING$/i', $clickbank['cprodtype']) && $s2vars['s2_subscr_id'] ? $s2vars['s2_subscr_id'] : $clickbank['ctransreceipt'];
                             $ipn['custom'] = $s2vars['s2_custom'];
                             $ipn['mc_fee'] = '-' . number_format('0.00', 2, '.', '');
                             $ipn['mc_gross'] = '-' . number_format(abs($clickbank['corderamount']) / 100, 2, '.', '');
                             $ipn['mc_currency'] = strtoupper($clickbank['ccurrency']);
                             $ipn['tax'] = '-' . number_format('0.00', 2, '.', '');
                             $ipn['payer_email'] = $clickbank['ccustemail'];
                             $ipn['first_name'] = ucwords(strtolower($clickbank['ccustfirstname']));
                             $ipn['last_name'] = ucwords(strtolower($clickbank['ccustlastname']));
                             $ipn['option_name1'] = $s2vars['s2_referencing'] ? 'Referencing Customer ID' : 'Originating Domain';
                             $ipn['option_selection1'] = $s2vars['s2_referencing'] ? $s2vars['s2_referencing'] : $_SERVER['HTTP_HOST'];
                             $ipn['option_name2'] = 'Customer IP Address';
                             $ipn['option_selection2'] = $s2vars['s2_customer_ip'];
                             $ipn['item_number'] = $s2vars['s2_invoice'];
                             $ipn['item_name'] = $s2vars['s2_desc'];
                             $ipn['s2member_paypal_proxy'] = 'clickbank';
                             $ipn['s2member_paypal_proxy_use'] = 'standard-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));
                         }
                     }
                 }
             }
             if (preg_match('/^(?:TEST_)?(?:SALE|BILL)$/i', $clickbank['ctransaction']) && preg_match('/^RECURRING$/i', $clickbank['cprodtype']) && (preg_match('/^COMPLETED$/i', $clickbank['crebillstatus']) || $clickbank['cfuturepayments'] <= 0) && apply_filters('c_ws_plugin__s2member_pro_clickbank_notify_handles_completions', TRUE, get_defined_vars()) || preg_match('/^(?:TEST_)?CANCEL-REBILL$/i', $clickbank['ctransaction']) && preg_match('/^RECURRING$/i', $clickbank['cprodtype'])) {
                 $clickbank['s2member_log'][] = 'ClickBank transaction identified as ( `RECURRING/COMPLETED` or `CANCEL-REBILL` ).';
                 $clickbank['s2member_log'][] = 'IPN reformulated. Piping through s2Member\'s core/standard PayPal processor as `txn_type` ( `subscr_cancel` ).';
                 $clickbank['s2member_log'][] = 'Please check PayPal IPN logs for further processing details.';
                 $processing = $processed = TRUE;
                 $ipn = array();
                 // Reset.
                 $ipn['txn_type'] = 'subscr_cancel';
                 $ipn['subscr_id'] = $s2vars['s2_subscr_id'];
                 $ipn['custom'] = $s2vars['s2_custom'];
                 $ipn['period1'] = $s2vars['s2_p1'];
                 $ipn['period3'] = $s2vars['s2_p3'];
                 $ipn['payer_email'] = $clickbank['ccustemail'];
                 $ipn['first_name'] = ucwords(strtolower($clickbank['ccustfirstname']));
                 $ipn['last_name'] = ucwords(strtolower($clickbank['ccustlastname']));
                 $ipn['option_name1'] = $s2vars['s2_referencing'] ? 'Referencing Customer ID' : 'Originating Domain';
                 $ipn['option_selection1'] = $s2vars['s2_referencing'] ? $s2vars['s2_referencing'] : $_SERVER['HTTP_HOST'];
                 $ipn['option_name2'] = 'Customer IP Address';
                 $ipn['option_selection2'] = $s2vars['s2_customer_ip'];
                 $ipn['item_number'] = $s2vars['s2_invoice'];
                 $ipn['item_name'] = $s2vars['s2_desc'];
                 $ipn['s2member_paypal_proxy'] = 'clickbank';
                 $ipn['s2member_paypal_proxy_use'] = 'standard-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));
             }
             if (empty($processed)) {
                 // If nothing was processed, here we add a message to the logs indicating the IPN was ignored.
                 $clickbank['s2member_log'][] = 'Ignoring this IPN request. The transaction does NOT require any action on the part of s2Member.';
             }
         } else {
             $clickbank['s2member_log'][] = 'Unable to verify POST vars. This is most likely related to an invalid ClickBank configuration. Please check: s2Member → ClickBank Options.';
             $clickbank['s2member_log'][] = 'If you\'re absolutely SURE that your ClickBank 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 ClickBank over an HTTPS connection.';
             $clickbank['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.';
             $clickbank['s2member_log'][] = var_export($_REQUEST, TRUE);
             // Recording _POST + _GET vars for analysis and debugging.
         }
         /*
         If debugging/logging is enabled; we need to append $clickbank 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() ? 'clickbank-ipn-4-' . trim(preg_replace('/[^a-z0-9]/i', '-', !empty($_log4) ? $_log4 : ''), '-') . '.log' : 'clickbank-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($clickbank, 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.
     }
 }
Example #4
0
 /**
  * Auto EOT time, else NPR (next payment time).
  *
  * @package s2Member\Utilities
  * @since 150713
  *
  * @param int|string $user_id Optional. Defaults to the current User's ID.
  * @param bool $check_gateway Defaults to a true value. If this is false, it is only possible to return a fixed EOT time.
  * 	In other words, if this is false and there is no EOT time, empty values will be returned. Be careful with this, because not checking
  * 	the payment gateway can result in an inaccurate return value. Only set to false if you want to limit the check to a fixed hard-coded EOT time.
  * @param string $favor Defaults to a value of `fixed`; i.e., if a fixed EOT time is available, that is returned in favor of a next payment time.
  * 	You can set this to `next` if you'd like to favor a next payment time (when applicable) instead of returning a fixed EOT time.
  *
  * @return array An associative array of EOT details; with the following elements.
  *
  * - `type` One of `fixed` (a fixed EOT time), `next` (next payment time; i.e., an ongoing recurring subscription); or an empty string if there is no EOT for the user.
  * - `time` The timestamp (UTC time) that represents the EOT (End Of Term); else `0` if there is no EOT time.
  * - `tense` If time is now (or earlier) this will be `past`. If time is in the future, this will be `future`. If there is no time, this is an empty string.
  * - `debug` A string of details that explain to a developer what was returned. For debugging only.
  */
 public static function get_user_eot($user_id = 0, $check_gateway = TRUE, $favor = 'fixed')
 {
     if (!($user_id = (int) $user_id)) {
         // Empty user ID in this call?
         $user_id = get_current_user_id();
     }
     // Assume current user.
     if (!$favor || !in_array($favor, array('fixed', 'next'), TRUE)) {
         $favor = 'fixed';
     }
     // Default behavior.
     $now = time();
     // Current timestamp.
     $grace_time = (int) $GLOBALS['WS_PLUGIN__']['s2member']['o']['eot_grace_time'];
     $grace_time = (int) apply_filters('ws_plugin__s2member_eot_grace_time', $grace_time);
     $demotion_role = c_ws_plugin__s2member_option_forces::force_demotion_role('subscriber');
     $empty_response = array('type' => '', 'time' => 0, 'tense' => '', 'debug' => '');
     if (!$user_id || !($user = new WP_User($user_id)) || !$user->ID) {
         return array_merge($empty_response, array('debug' => 'Invalid user ID.'));
     }
     $ipn_signup_vars = self::get_user_ipn_signup_vars($user->ID);
     $subscr_gateway = (string) get_user_option('s2member_subscr_gateway', $user->ID);
     $subscr_id = (string) get_user_option('s2member_subscr_id', $user->ID);
     $subscr_cid = (string) get_user_option('s2member_subscr_cid', $user->ID);
     $last_auto_eot_time = (int) get_user_option('s2member_last_auto_eot_time', $user->ID);
     $auto_eot_time = (int) get_user_option('s2member_auto_eot_time', $user->ID);
     if ($auto_eot_time) {
         // They have a hard-coded EOT time at present?
         return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', 'debug' => 'This is a fixed EOT time recorded by s2Member. It can be altered in the WordPress Dashboard for this user.');
     }
     if (!$subscr_gateway && !$subscr_id && !$subscr_cid && $last_auto_eot_time && (!user_can($user->ID, 'access_s2member_level1') || c_ws_plugin__s2member_user_access::user_access_role($user) === $demotion_role) && !c_ws_plugin__s2member_user_access::user_access_ccaps($user)) {
         return array('type' => 'fixed', 'time' => $last_auto_eot_time, 'tense' => $last_auto_eot_time <= $now ? 'past' : 'future', 'debug' => 'This is an archived/fixed EOT time recorded by s2Member; i.e., the date this customer\'s access expired.');
     }
     if (!$subscr_gateway || !$subscr_id || !is_array($ipn_signup_vars) || !$ipn_signup_vars) {
         return array_merge($empty_response, array('debug' => 'This user has no subscription; i.e., missing `subscr_id`, `subscr_gateway` or `ipn_signup_vars`.'));
     }
     if (empty($ipn_signup_vars['txn_type']) || $ipn_signup_vars['txn_type'] !== 'subscr_signup') {
         return array_merge($empty_response, array('debug' => 'This user has no subscription; i.e., `txn_type` != `subscr_signup`.'));
     }
     $auto_eot_time = c_ws_plugin__s2member_utils_time::auto_eot_time($user->ID, $ipn_signup_vars['period1'], $ipn_signup_vars['period3']);
     if ($check_gateway) {
         switch ($subscr_gateway) {
             case 'paypal':
                 // PayPal (PayPal Pro only).
                 if (!c_ws_plugin__s2member_utils_conds::pro_is_installed() || !class_exists('c_ws_plugin__s2member_pro_paypal_utilities') || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_username'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_password'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_signature']) {
                     return array_merge($empty_response, array('debug' => 'PayPal Pro API credentials missing in your s2Member configuration.'));
                 }
                 if ($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_payflow_api_username']) {
                     if (!($api_response = c_ws_plugin__s2member_pro_paypal_utilities::payflow_get_profile($subscr_id)) || !empty($api_response['__error'])) {
                         return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says there is no subscription for this user.'));
                     }
                     if (preg_match('/^(?:Pending|PendingProfile)$/i', $api_response['STATUS'])) {
                         return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says the subscription for this user is currently pending changes. Unable to determine at this moment. Please try again in 15 minutes.'));
                     }
                     if (!preg_match('/^(?:Active|ActiveProfile)$/i', $api_response['STATUS'])) {
                         return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription is no longer active, and thus, access should be terminated at this time.');
                     }
                     if ($api_response['TERM'] > 0 && $api_response['PAYMENTSLEFT'] <= 0) {
                         return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription has reached its last payment, and thus, access should be terminated at this time.');
                     }
                     if ($api_response['TERM'] <= 0 || $api_response['PAYMENTSLEFT'] > 0) {
                         if ($api_response['NEXTPAYMENT'] && strlen($api_response['NEXTPAYMENT']) === 8) {
                             // MMDDYYYY format is not `strtotime()` compatible.
                             if (($time = strtotime(substr($api_response['NEXTPAYMENT'], -4) . '-' . substr($api_response['NEXTPAYMENT'], 0, 2) . '-' . substr($api_response['NEXTPAYMENT'], 2, 2))) > $now) {
                                 return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The PayPal Pro API says this is the next payment time.');
                             }
                         }
                     }
                 } else {
                     $api_args = array('METHOD' => 'GetRecurringPaymentsProfileDetails', 'PROFILEID' => $subscr_id);
                     if (!($api_response = c_ws_plugin__s2member_paypal_utilities::paypal_api_response($api_args)) || !empty($api_response['__error'])) {
                         return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says there is no subscription for this user.'));
                     }
                     if (preg_match('/^(?:Pending|PendingProfile)$/i', $api_response['STATUS'])) {
                         return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says the subscription for this user is currently pending changes. Unable to determine at this moment. Please try again in 15 minutes.'));
                     }
                     if (!preg_match('/^(?:Active|ActiveProfile)$/i', $api_response['STATUS'])) {
                         return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription is no longer active, and thus, access should be terminated at this time.');
                     }
                     if ($api_response['TOTALBILLINGCYCLES'] > 0 && $api_response['NUMCYCLESREMAINING'] <= 0) {
                         return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription has reached its last payment, and thus, access should be terminated at this time.');
                     }
                     if ($api_response['TOTALBILLINGCYCLES'] <= 0 || $api_response['NUMCYCLESREMAINING'] > 0) {
                         if ($api_response['NEXTBILLINGDATE'] && ($time = strtotime($api_response['NEXTBILLINGDATE'])) > $now) {
                             return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The PayPal Pro API says this is the next payment time.');
                         }
                     }
                 }
                 return array_merge($empty_response, array('debug' => 'No fixed EOT, and there are no more payments needed from this user.'));
                 break;
                 // Break switch.
             // Break switch.
             case 'authnet':
                 // Authorize.Net (EOT only; w/ limited functionality).
                 if (!c_ws_plugin__s2member_utils_conds::pro_is_installed() || !class_exists('c_ws_plugin__s2member_pro_authnet_utilities') || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_authnet_api_login_id'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_authnet_api_trans_key']) {
                     return array_merge($empty_response, array('debug' => 'Authorize.Net API credentials missing in your s2Member configuration.'));
                 }
                 $api_args = array('x_method' => 'status', 'x_subscription_id' => $subscr_id);
                 if (!($api_response = c_ws_plugin__s2member_pro_authnet_utilities::authnet_arb_response($api_args)) || !empty($api_response['__error'])) {
                     return array_merge($empty_response, array('debug' => 'No fixed EOT, and the Authorize.Net API says there is no subscription for this user.'));
                 }
                 if (!preg_match('/^(?:active)$/i', $api_response['subscription_status'])) {
                     return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', 'debug' => 'This is the estimated EOT time. The Authorize.Net API says this subscription is no longer active, and thus, access should be terminated at this time.');
                 }
                 // Next payment time not possible with Authorize.Net at this time.
                 // Fixed recurring intervals not possible to query with Authorize.Net at this time.
                 return array_merge($empty_response, array('debug' => 'Partially-supported payment gateway; unable to determine.'));
                 break;
                 // Break switch.
             // Break switch.
             case 'stripe':
                 // Stripe payment gateway (best).
                 if (!c_ws_plugin__s2member_utils_conds::pro_is_installed() || !class_exists('c_ws_plugin__s2member_pro_stripe_utilities') || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_stripe_api_publishable_key'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_stripe_api_secret_key']) {
                     return array_merge($empty_response, array('debug' => 'Stripe API credentials missing in your s2Member configuration.'));
                 }
                 if (!$subscr_cid) {
                     return array_merge($empty_response, array('debug' => 'No fixed EOT, and no `subscr_cid` on file. Unable to determine.'));
                 }
                 if (!is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($subscr_cid, $subscr_id)) || empty($stripe_subscription->id)) {
                     return array_merge($empty_response, array('debug' => 'No fixed EOT, and the Stripe API says there is no subscription for this user.'));
                 }
                 if ((int) $stripe_subscription->ended_at > 0) {
                     $time = $stripe_subscription->ended_at + $grace_time;
                     return array('type' => 'fixed', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The Stripe API says this subscription reached an expiration on this date + grace time.');
                 }
                 if (in_array($stripe_subscription->status, array('canceled', 'unpaid'), TRUE) || $stripe_subscription->cancel_at_period_end) {
                     $time = $stripe_subscription->current_period_end + $grace_time;
                     return array('type' => 'fixed', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The Stripe API says this subscription was cancelled, and thus, should EOT on this date + grace time.');
                 }
                 if (isset($stripe_subscription->plan->metadata->recurring, $stripe_subscription->plan->metadata->recurring_times) && !$stripe_subscription->plan->metadata->recurring) {
                     $time = (int) $stripe_subscription->start;
                     $time += $stripe_subscription->plan->trial_period_days * DAY_IN_SECONDS;
                     switch ($stripe_subscription->plan->interval) {
                         case 'day':
                             // Every X days in this case.
                             $time += DAY_IN_SECONDS * $stripe_subscription->plan->interval_count * 1;
                             break;
                             // Break switch now.
                         // Break switch now.
                         case 'week':
                             // Every X weeks in this case.
                             $time += WEEK_IN_SECONDS * $stripe_subscription->plan->interval_count * 1;
                             break;
                             // Break switch now.
                         // Break switch now.
                         case 'month':
                             // Every X months in this case.
                             $time += WEEK_IN_SECONDS * 4 * $stripe_subscription->plan->interval_count * 1;
                             break;
                             // Break switch now.
                         // Break switch now.
                         case 'year':
                             // Every X years in this case.
                             $time += YEAR_IN_SECONDS * $stripe_subscription->plan->interval_count * 1;
                             break;
                             // Break switch now.
                     }
                     if ($favor === 'next' && $stripe_subscription->current_period_end + 1 < $time) {
                         if ($stripe_subscription->current_period_end + 1 > $now) {
                             $time = $stripe_subscription->current_period_end + 1;
                             return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The Stripe API says this is the next payment time.');
                         }
                         return array_merge($empty_response, array('debug' => 'Stripe says no more payments needed from this user.'));
                     }
                     $time += $grace_time;
                     // Now add grace to the final EOT time.
                     return array('type' => 'fixed', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The Stripe API says this subscription will be completely over on this date + grace time.');
                 }
                 if (isset($stripe_subscription->plan->metadata->recurring, $stripe_subscription->plan->metadata->recurring_times) && $stripe_subscription->plan->metadata->recurring && $stripe_subscription->plan->metadata->recurring_times <= 0) {
                     if ($stripe_subscription->current_period_end + 1 > $now) {
                         $time = $stripe_subscription->current_period_end + 1;
                         return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The Stripe API says this is the next payment time.');
                     }
                     return array_merge($empty_response, array('debug' => 'Stripe says no more payments needed from this user.'));
                 }
                 if (isset($stripe_subscription->plan->metadata->recurring, $stripe_subscription->plan->metadata->recurring_times) && $stripe_subscription->plan->metadata->recurring && $stripe_subscription->plan->metadata->recurring_times > 0) {
                     $time = (int) $stripe_subscription->start;
                     $time += $stripe_subscription->plan->trial_period_days * DAY_IN_SECONDS;
                     switch ($stripe_subscription->plan->interval) {
                         case 'day':
                             // Every X days in this case.
                             $time += DAY_IN_SECONDS * $stripe_subscription->plan->interval_count * $stripe_subscription->plan->metadata->recurring_times;
                             break;
                             // Break switch now.
                         // Break switch now.
                         case 'week':
                             // Every X weeks in this case.
                             $time += WEEK_IN_SECONDS * $stripe_subscription->plan->interval_count * $stripe_subscription->plan->metadata->recurring_times;
                             break;
                             // Break switch now.
                         // Break switch now.
                         case 'month':
                             // Every X months in this case.
                             $time += WEEK_IN_SECONDS * 4 * $stripe_subscription->plan->interval_count * $stripe_subscription->plan->metadata->recurring_times;
                             break;
                             // Break switch now.
                         // Break switch now.
                         case 'year':
                             // Every X years in this case.
                             $time += YEAR_IN_SECONDS * $stripe_subscription->plan->interval_count * $stripe_subscription->plan->metadata->recurring_times;
                             break;
                             // Break switch now.
                     }
                     if ($favor === 'next' && $stripe_subscription->current_period_end + 1 < $time) {
                         if ($stripe_subscription->current_period_end + 1 > $now) {
                             $time = $stripe_subscription->current_period_end + 1;
                             return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The Stripe API says this is the next payment time.');
                         }
                         return array_merge($empty_response, array('debug' => 'Stripe says no more payments needed from this user.'));
                     }
                     $time += $grace_time;
                     // Now add grace to the final EOT time.
                     return array('type' => 'fixed', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The Stripe API says this subscription will be completely over on this date + grace time.');
                 }
                 if ($stripe_subscription->current_period_end + 1 > $now) {
                     $time = $stripe_subscription->current_period_end + 1;
                     return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The Stripe API says this is the next payment time.');
                 }
                 return array_merge($empty_response, array('debug' => 'No fixed EOT, and Stripe says there are no more payments needed from this user.'));
                 break;
                 // Break switch.
             // Break switch.
             case 'clickbank':
                 // ClickBank (limited functionality).
                 if (!c_ws_plugin__s2member_utils_conds::pro_is_installed() || !class_exists('c_ws_plugin__s2member_pro_clickbank_utilities') || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_clickbank_username'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_clickbank_clerk_key'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_clickbank_developer_key'] || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_clickbank_secret_key']) {
                     return array_merge($empty_response, array('debug' => 'ClickBank API credentials missing in your s2Member configuration.'));
                 }
                 if (empty($ipn_signup_vars['txn_id'])) {
                     // ClickBank receipt number.
                     return array_merge($empty_response, array('debug' => 'No fixed EOT, and no `txn_id` on file. Unable to determine.'));
                 }
                 if (!($api_response = c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_api_order($ipn_signup_vars['txn_id']))) {
                     return array_merge($empty_response, array('debug' => 'No fixed EOT, and the ClickBank API says there is no subscription for this user.'));
                 }
                 if (!preg_match('/^(?:TEST_)?SALE$/i', $api_response['txnType']) || !$api_response['recurring']) {
                     return array_merge($empty_response, array('debug' => 'No fixed EOT, and the ClickBank API says there is no recurring subscription for this user.'));
                 }
                 if (strcasecmp($api_response['status'], 'active') !== 0 || $api_response['futurePayments'] <= 0) {
                     return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', 'debug' => 'This is the estimated EOT time. The ClickBank API says this subscription no longer active, or it has reached its last payment, and thus, access should be terminated at this time.');
                 }
                 if ($api_response['nextPaymentDate'] && ($time = strtotime($api_response['nextPaymentDate'])) > $now) {
                     return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', 'debug' => 'The ClickBank API says this is the next payment time.');
                 }
                 return array_merge($empty_response, array('debug' => 'No fixed EOT, and there are no more payments needed from this user.'));
                 break;
                 // Break switch.
             // Break switch.
             default:
                 // Default case handler.
                 return array_merge($empty_response, array('debug' => 'Partially-supported payment gateway; unable to determine.'));
         }
     }
     return array_merge($empty_response, array('debug' => 'Payment gateway check disabled; unable to determine.'));
 }
 /**
  * Handles ClickBank Return URL processing.
  *
  * @package s2Member\ClickBank
  * @since 1.5
  *
  * @attaches-to ``add_action('init');``
  */
 public static function clickbank_return()
 {
     global $current_site, $current_blog;
     // For Multisite support.
     if (!empty($_GET['s2member_pro_clickbank_return']) && $GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_clickbank_username']) {
         if (is_array($clickbank = c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_postvars_v2_1()) && ($_clickbank = $clickbank)) {
             $clickbank['s2member_log'][] = 'Return-Data received on: ' . date('D M j, Y g:i:s a T');
             $clickbank['s2member_log'][] = 's2Member POST vars verified with ClickBank.';
             $clickbank['s2member_log'][] = 'Sleeping for 5 seconds. Giving ClickBank a chance to finalize processing.';
             sleep(5);
             // Sleep here to give ClickBank a chance to finalize processing. Allows the API call to succeed.
             $clickbank['s2member_log'][] = 'Awake. It\'s ' . date('D M j, Y g:i:s a T') . '. Processing will continue.';
             if (is_array($order = json_decode(c_ws_plugin__s2member_utils_urls::remote('https://api.clickbank.com/rest/1.3/orders/' . $clickbank['cbreceipt'], FALSE, array_merge(c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_api_headers(), array('timeout' => 20))), TRUE)) && ($order = $order['orderData'])) {
                 if (is_array($order) && isset($order[0]) && is_array($order[0])) {
                     $order = $order[0];
                 }
                 // If there is more than one, we only want the first one.
                 foreach ($order as $_k => &$_v) {
                     if (is_array($_v) && isset($_v['@nil'])) {
                         $_v = NULL;
                     }
                 }
                 // Nullify properly.
                 unset($_k, $_v);
                 // Housekeeping.
                 $clickbank['s2member_log'][] = 'Order API variables have been obtained from ClickBank.';
                 $s2vars = c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_parse_s2vars_v2_1(http_build_query($clickbank, NULL, '&'), $order['txnType']);
                 if (!empty($s2vars['s2_p1']) && !empty($s2vars['s2_p3']) && $s2vars['s2_p1'] === '0 D') {
                     // Initial Period. No Trial defaults to Regular Period.
                     $s2vars['s2_p1'] = $s2vars['s2_p3'];
                 }
                 $clickbank['s2vars'] = $s2vars;
                 // So they appear in the log entry for this Notification.
                 if (strcasecmp($order['firstName'] . ' ' . $order['lastName'], $order['customerDisplayName']) !== 0 && preg_match('/([^ ]+)( +)([^ ]+)/', $order['customerDisplayName'])) {
                     list($order['firstName'], $order['lastName']) = preg_split('/ +/', $order['customerDisplayName'], 2);
                 }
                 if (preg_match('/^(TEST_)?SALE$/i', $order['txnType']) && empty($s2vars['s2_p1']) && empty($s2vars['s2_p3'])) {
                     $clickbank['s2member_log'][] = 'ClickBank transaction identified as (`SALE/STANDARD`).';
                     $clickbank['s2member_log'][] = 'Return-Data reformulated. Piping through s2Member\'s core/standard PayPal processor as `txn_type` (`web_accept`).';
                     $clickbank['s2member_log'][] = 'Please check PayPal RTN logs for further processing details.';
                     $rtn = array();
                     // Reset.
                     $rtn['txn_type'] = 'web_accept';
                     $rtn['txn_id'] = $order['receipt'];
                     $rtn['custom'] = $s2vars['s2_custom'];
                     $rtn['mc_gross'] = number_format($order['amount'], 2, '.', '');
                     $rtn['mc_currency'] = strtoupper($order['currency']);
                     $rtn['tax'] = '0.00';
                     // No tax.
                     $rtn['payer_email'] = $order['email'];
                     $rtn['first_name'] = ucwords(strtolower($order['firstName']));
                     $rtn['last_name'] = ucwords(strtolower($order['lastName']));
                     $rtn['option_name1'] = !empty($s2vars['s2_referencing']) ? 'Referencing Customer ID' : 'Originating Domain';
                     $rtn['option_selection1'] = !empty($s2vars['s2_referencing']) ? $s2vars['s2_referencing'] : $_SERVER['HTTP_HOST'];
                     $rtn['option_name2'] = 'Customer IP Address';
                     $rtn['option_selection2'] = $s2vars['s2_customer_ip'];
                     $rtn['item_number'] = $s2vars['s2_invoice'];
                     $rtn['item_name'] = $s2vars['s2_desc'];
                     $rtn_q = '&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-emails';
                     if (!empty($_GET['s2member_pro_clickbank_return_success'])) {
                         // Using a custom Return URL on success?
                         $rtn_q .= '&s2member_paypal_return_success=' . rawurlencode(trim(stripslashes($_GET['s2member_pro_clickbank_return_success'])));
                     }
                     $rtn_r = add_query_arg(urlencode_deep($rtn), home_url('/?s2member_pro_clickbank_return&s2member_paypal_return=1' . $rtn_q));
                     $rtn_r = c_ws_plugin__s2member_utils_urls::add_s2member_sig($rtn_r, 's2member_paypal_proxy_verification');
                     $clickbank['s2member_log'][] = $rtn_r;
                     // Log the full Return redirection URL here.
                     wp_redirect($rtn_r);
                     // Proxy this through s2Member's core PayPal processor.
                 } else {
                     if (preg_match('/^(TEST_)?SALE$/i', $order['txnType']) && !empty($s2vars['s2_p1']) && !empty($s2vars['s2_p3'])) {
                         $clickbank['s2member_log'][] = 'ClickBank transaction identified as (`SALE/RECURRING`).';
                         $clickbank['s2member_log'][] = 'Return-Data reformulated. Piping through s2Member\'s core/standard PayPal processor as `txn_type` (`subscr_signup`).';
                         $clickbank['s2member_log'][] = 'Please check PayPal RTN logs for further processing details.';
                         $rtn = array();
                         // Reset.
                         $rtn['txn_type'] = 'subscr_signup';
                         $rtn['subscr_id'] = $s2vars['s2_subscr_id'];
                         $rtn['recurring'] = $order['futurePayments'] > 1 ? '1' : '0';
                         $rtn['txn_id'] = $order['receipt'];
                         $rtn['custom'] = $s2vars['s2_custom'];
                         $rtn['period1'] = $s2vars['s2_p1'];
                         $rtn['period3'] = $s2vars['s2_p3'];
                         $rtn['mc_amount1'] = number_format($order['amount'], 2, '.', '');
                         $rtn['mc_amount3'] = @number_format($order['rebillAmount'], 2, '.', '');
                         $rtn['mc_currency'] = strtoupper($order['currency']);
                         $rtn['tax'] = '0.00';
                         // No tax.
                         $rtn['payer_email'] = $order['email'];
                         $rtn['first_name'] = ucwords(strtolower($order['firstName']));
                         $rtn['last_name'] = ucwords(strtolower($order['lastName']));
                         $rtn['option_name1'] = !empty($s2vars['s2_referencing']) ? 'Referencing Customer ID' : 'Originating Domain';
                         $rtn['option_selection1'] = !empty($s2vars['s2_referencing']) ? $s2vars['s2_referencing'] : $_SERVER['HTTP_HOST'];
                         $rtn['option_name2'] = 'Customer IP Address';
                         $rtn['option_selection2'] = $s2vars['s2_customer_ip'];
                         $rtn['item_number'] = $s2vars['s2_invoice'];
                         $rtn['item_name'] = $s2vars['s2_desc'];
                         $rtn_q = '&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-emails';
                         if (!empty($_GET['s2member_pro_clickbank_return_success'])) {
                             // Using a custom Return URL on success?
                             $rtn_q .= '&s2member_paypal_return_success=' . rawurlencode(trim(stripslashes($_GET['s2member_pro_clickbank_return_success'])));
                         }
                         $rtn_r = add_query_arg(urlencode_deep($rtn), home_url('/?s2member_pro_clickbank_return&s2member_paypal_return=1' . $rtn_q));
                         $rtn_r = c_ws_plugin__s2member_utils_urls::add_s2member_sig($rtn_r, 's2member_paypal_proxy_verification');
                         $clickbank['s2member_log'][] = $rtn_r;
                         // Log the full Return redirection URL here.
                         wp_redirect($rtn_r);
                         // Proxy this through s2Member's core PayPal processor.
                     } else {
                         $clickbank['s2member_log'][] = 'Unexpected txnType. The ClickBank txnType did not match a required action.';
                         $clickbank['s2member_log'][] = 'Redirecting Customer to the Home Page, due to an error that occurred.';
                         echo '<script type="text/javascript">' . "\n";
                         echo "alert('" . c_ws_plugin__s2member_utils_strings::esc_js_sq(_x('ERROR: Unexpected txnType. Please contact Support for assistance.\\n\\nThe ClickBank txnType did not match a required action.', 's2member-front', 's2member')) . "');" . "\n";
                         echo "window.location = '" . c_ws_plugin__s2member_utils_strings::esc_js_sq(home_url('/')) . "';";
                         echo '</script>' . "\n";
                     }
                 }
             } else {
                 $clickbank['s2member_log'][] = 'Unable to obtain API vars. The ClickBank API may NOT have data for this order yet. Or, your ClickBank API Keys are NOT configured properly under `s2Member ⥱ ClickBank Options`.';
                 $clickbank['s2member_log'][] = var_export($_REQUEST, TRUE);
                 // Recording ``$_POST`` + ``$_GET`` vars for analysis and debugging.
                 $clickbank['s2member_log'][] = 'Return-Data reformulated. Piping through s2Member\'s core/standard PayPal processor with `proxy_use` (`ty-email`).';
                 $clickbank['s2member_log'][] = 'Please check PayPal RTN logs for further processing details.';
                 $rtn_q = '&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-emails,ty-email';
                 if (!empty($_GET['s2member_pro_clickbank_return_success'])) {
                     $rtn_q .= '&s2member_paypal_return_success=' . rawurlencode(trim(stripslashes($_GET['s2member_pro_clickbank_return_success'])));
                 }
                 $rtn_r = home_url('/?s2member_pro_clickbank_return&s2member_paypal_return=1' . $rtn_q);
                 $rtn_r = c_ws_plugin__s2member_utils_urls::add_s2member_sig($rtn_r, 's2member_paypal_proxy_verification');
                 $clickbank['s2member_log'][] = $rtn_r;
                 // Log the full Return redirection URL here.
                 wp_redirect($rtn_r);
                 // Proxy this through s2Member's core PayPal processor.
             }
         } else {
             $clickbank['s2member_log'][] = 'Unable to verify POST vars. This is most likely related to an invalid ClickBank configuration. Please check: s2Member ⥱ ClickBank Options.';
             $clickbank['s2member_log'][] = 'If you\'re absolutely SURE that your ClickBank 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 ClickBank over an HTTPS connection.';
             $clickbank['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.';
             $clickbank['s2member_log'][] = var_export($_REQUEST, TRUE);
             // Recording _POST + _GET vars for analysis and debugging.
             $clickbank['s2member_log'][] = 'Redirecting Customer to the Home Page, due to an error that occurred.';
             echo '<script type="text/javascript">' . "\n";
             echo "alert('" . c_ws_plugin__s2member_utils_strings::esc_js_sq(_x('ERROR: Unable to verify POST vars. Please contact Support for assistance.\\n\\nThis is most likely related to an invalid ClickBank configuration. If you are the site owner, please check: s2Member ⥱ ClickBank Options.', 's2member-front', 's2member')) . "');" . "\n";
             echo "window.location = '" . c_ws_plugin__s2member_utils_strings::esc_js_sq(home_url("/")) . "';";
             echo '</script>' . "\n";
         }
         $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() ? 'clickbank-rtn-4-' . trim(preg_replace('/[^a-z0-9]/i', '-', !empty($_log4) ? $_log4 : ''), '-') . '.log' : 'clickbank-rtn.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($clickbank, TRUE)) . "\n\n", FILE_APPEND);
                 }
             }
         }
         exit;
         // Clean exit; all done here.
     }
 }
 /**
  * Handles ClickBank® IPN URL processing.
  *
  * @package s2Member\ClickBank
  * @since 1.5
  *
  * @attaches-to ``add_action("init");``
  *
  * @return null Or exits script execution after handling the Notification.
  */
 public static function clickbank_notify()
 {
     global $current_site, $current_blog;
     /* For Multisite support. */
     /**/
     if (!empty($_GET["s2member_pro_clickbank_notify"]) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["pro_clickbank_username"]) {
         @ignore_user_abort(true);
         /* Continue processing even if/when connection is broken by the sender. */
         /**/
         if (is_array($clickbank = c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_postvars()) && ($_clickbank = $clickbank)) {
             $clickbank["s2member_log"][] = "IPN received on: " . date("D M j, Y g:i:s a T");
             $clickbank["s2member_log"][] = "s2Member POST vars verified with ClickBank®.";
             /**/
             $s2vars = c_ws_plugin__s2member_pro_clickbank_utilities::clickbank_parse_s2vars($clickbank["cvendthru"], $clickbank["ctransaction"]);
             /**/
             if (isset($s2vars["s2_p1"], $s2vars["s2_p3"]) && $s2vars["s2_p1"] === "0 D") {
                 $s2vars["s2_p1"] = $s2vars["s2_p3"];
             }
             /**/
             $clickbank["s2vars"] = $s2vars;
             /**/
             if (strcasecmp($clickbank["ccustfirstname"] . " " . $clickbank["ccustlastname"], $clickbank["ccustfullname"]) !== 0 && preg_match("/(?:[^ ]+)(?: +)(?:[^ ]+)/", $clickbank["ccustfullname"])) {
                 list($clickbank["ccustfirstname"], $clickbank["ccustlastname"]) = preg_split("/ +/", $clickbank["ccustfullname"], 2);
             }
             /**/
             if (preg_match("/^(?:TEST_)?SALE\$/i", $clickbank["ctransaction"]) && preg_match("/^STANDARD\$/i", $clickbank["cprodtype"])) {
                 $clickbank["s2member_log"][] = "ClickBank® transaction identified as ( `SALE/STANDARD` ).";
                 $clickbank["s2member_log"][] = "IPN reformulated. Piping through s2Member's core/standard PayPal® processor as `txn_type` ( `web_accept` ).";
                 $clickbank["s2member_log"][] = "Please check PayPal® IPN logs for further processing details.";
                 /**/
                 $processing = $processed = true;
                 $ipn = array();
                 /* Reset. */
                 /**/
                 $ipn["txn_type"] = "web_accept";
                 /**/
                 $ipn["txn_id"] = $clickbank["ctransreceipt"];
                 /**/
                 $ipn["custom"] = $s2vars["s2_custom"];
                 /**/
                 $ipn["mc_gross"] = number_format($clickbank["corderamount"] / 100, 2, ".", "");
                 $ipn["mc_currency"] = strtoupper($clickbank["ccurrency"]);
                 $ipn["tax"] = number_format("0.00", 2, ".", "");
                 /**/
                 $ipn["payer_email"] = $clickbank["ccustemail"];
                 $ipn["first_name"] = ucwords(strtolower($clickbank["ccustfirstname"]));
                 $ipn["last_name"] = ucwords(strtolower($clickbank["ccustlastname"]));
                 /**/
                 $ipn["option_name1"] = $s2vars["s2_referencing"] ? "Referencing Customer ID" : "Originating Domain";
                 $ipn["option_selection1"] = $s2vars["s2_referencing"] ? $s2vars["s2_referencing"] : $_SERVER["HTTP_HOST"];
                 /**/
                 $ipn["option_name2"] = "Customer IP Address";
                 $ipn["option_selection2"] = $s2vars["s2_customer_ip"];
                 /**/
                 $ipn["item_number"] = $s2vars["s2_invoice"];
                 $ipn["item_name"] = $s2vars["s2_desc"];
                 /**/
                 $ipn_q = "&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-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 {
                 if (preg_match("/^(?:TEST_)?SALE\$/i", $clickbank["ctransaction"]) && preg_match("/^RECURRING\$/i", $clickbank["cprodtype"])) {
                     $clickbank["s2member_log"][] = "ClickBank® transaction identified as ( `SALE/RECURRING` ).";
                     $clickbank["s2member_log"][] = "IPN reformulated. Piping through s2Member's core/standard PayPal® processor as `txn_type` ( `subscr_signup` ).";
                     $clickbank["s2member_log"][] = "Please check PayPal® IPN logs for further processing details.";
                     /**/
                     $processing = $processed = true;
                     $ipn = array();
                     /* Reset. */
                     /**/
                     $ipn["txn_type"] = "subscr_signup";
                     $ipn["subscr_id"] = $s2vars["s2_subscr_id"];
                     $ipn["recurring"] = $clickbank["cfuturepayments"] > 1 ? "1" : "0";
                     /**/
                     $ipn["txn_id"] = $clickbank["ctransreceipt"];
                     /**/
                     $ipn["custom"] = $s2vars["s2_custom"];
                     /**/
                     $ipn["period1"] = $s2vars["s2_p1"];
                     $ipn["period3"] = $s2vars["s2_p3"];
                     /**/
                     $ipn["mc_amount1"] = number_format($clickbank["corderamount"] / 100, 2, ".", "");
                     $ipn["mc_amount3"] = number_format($clickbank["crebillamnt"] / 100, 2, ".", "");
                     /**/
                     $ipn["mc_gross"] = preg_match("/^[1-9]/", $ipn["period1"]) ? $ipn["mc_amount1"] : $ipn["mc_amount3"];
                     /**/
                     $ipn["mc_currency"] = strtoupper($clickbank["ccurrency"]);
                     $ipn["tax"] = number_format("0.00", 2, ".", "");
                     /**/
                     $ipn["payer_email"] = $clickbank["ccustemail"];
                     $ipn["first_name"] = ucwords(strtolower($clickbank["ccustfirstname"]));
                     $ipn["last_name"] = ucwords(strtolower($clickbank["ccustlastname"]));
                     /**/
                     $ipn["option_name1"] = $s2vars["s2_referencing"] ? "Referencing Customer ID" : "Originating Domain";
                     $ipn["option_selection1"] = $s2vars["s2_referencing"] ? $s2vars["s2_referencing"] : $_SERVER["HTTP_HOST"];
                     /**/
                     $ipn["option_name2"] = "Customer IP Address";
                     $ipn["option_selection2"] = $s2vars["s2_customer_ip"];
                     /**/
                     $ipn["item_number"] = $s2vars["s2_invoice"];
                     $ipn["item_name"] = $s2vars["s2_desc"];
                     /**/
                     $ipn_q = "&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-emails";
                     $ipn_q .= $ipn["mc_gross"] > 0 ? ",subscr-signup-as-subscr-payment" : "";
                     /* Use as first payment? */
                     $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 {
                     if (preg_match("/^(?:TEST_)?BILL\$/i", $clickbank["ctransaction"]) && preg_match("/^RECURRING\$/i", $clickbank["cprodtype"])) {
                         $clickbank["s2member_log"][] = "ClickBank® transaction identified as ( `BILL/RECURRING` ).";
                         $clickbank["s2member_log"][] = "IPN reformulated. Piping through s2Member's core/standard PayPal® processor as `txn_type` ( `subscr_payment` ).";
                         $clickbank["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"] = $s2vars["s2_subscr_id"];
                         /**/
                         $ipn["txn_id"] = $clickbank["ctransreceipt"];
                         /**/
                         $ipn["custom"] = $s2vars["s2_custom"];
                         /**/
                         $ipn["mc_gross"] = number_format($clickbank["corderamount"] / 100, 2, ".", "");
                         $ipn["mc_currency"] = strtoupper($clickbank["ccurrency"]);
                         $ipn["tax"] = number_format("0.00", 2, ".", "");
                         /**/
                         $ipn["payer_email"] = $clickbank["ccustemail"];
                         $ipn["first_name"] = ucwords(strtolower($clickbank["ccustfirstname"]));
                         $ipn["last_name"] = ucwords(strtolower($clickbank["ccustlastname"]));
                         /**/
                         $ipn["option_name1"] = $s2vars["s2_referencing"] ? "Referencing Customer ID" : "Originating Domain";
                         $ipn["option_selection1"] = $s2vars["s2_referencing"] ? $s2vars["s2_referencing"] : $_SERVER["HTTP_HOST"];
                         /**/
                         $ipn["option_name2"] = "Customer IP Address";
                         $ipn["option_selection2"] = $s2vars["s2_customer_ip"];
                         /**/
                         $ipn["item_number"] = $s2vars["s2_invoice"];
                         $ipn["item_name"] = $s2vars["s2_desc"];
                         /**/
                         $ipn_q = "&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-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 {
                         if (preg_match("/^(?:TEST_)?(?:RFND|CGBK|INSF)\$/i", $clickbank["ctransaction"])) {
                             $clickbank["s2member_log"][] = "ClickBank® transaction identified as ( `RFND|CGBK|INSF` ).";
                             $clickbank["s2member_log"][] = "IPN reformulated. Piping through s2Member's core/standard PayPal® processor as `payment_status` ( `refunded|reversed` ).";
                             $clickbank["s2member_log"][] = "Please check PayPal® IPN logs for further processing details.";
                             /**/
                             $processing = $processed = true;
                             $ipn = array();
                             /* Reset. */
                             /**/
                             $ipn["payment_status"] = preg_match("/^(?:TEST_)?RFND\$/", $clickbank["ctransaction"]) ? "refunded" : "reversed";
                             /**/
                             $ipn["parent_txn_id"] = preg_match("/^RECURRING\$/i", $clickbank["cprodtype"]) && $s2vars["s2_subscr_id"] ? $s2vars["s2_subscr_id"] : $clickbank["ctransreceipt"];
                             /**/
                             $ipn["custom"] = $s2vars["s2_custom"];
                             /**/
                             $ipn["mc_fee"] = "-" . number_format("0.00", 2, ".", "");
                             $ipn["mc_gross"] = "-" . number_format(abs($clickbank["corderamount"]) / 100, 2, ".", "");
                             $ipn["mc_currency"] = strtoupper($clickbank["ccurrency"]);
                             $ipn["tax"] = "-" . number_format("0.00", 2, ".", "");
                             /**/
                             $ipn["payer_email"] = $clickbank["ccustemail"];
                             $ipn["first_name"] = ucwords(strtolower($clickbank["ccustfirstname"]));
                             $ipn["last_name"] = ucwords(strtolower($clickbank["ccustlastname"]));
                             /**/
                             $ipn["option_name1"] = $s2vars["s2_referencing"] ? "Referencing Customer ID" : "Originating Domain";
                             $ipn["option_selection1"] = $s2vars["s2_referencing"] ? $s2vars["s2_referencing"] : $_SERVER["HTTP_HOST"];
                             /**/
                             $ipn["option_name2"] = "Customer IP Address";
                             $ipn["option_selection2"] = $s2vars["s2_customer_ip"];
                             /**/
                             $ipn["item_number"] = $s2vars["s2_invoice"];
                             $ipn["item_name"] = $s2vars["s2_desc"];
                             /**/
                             $ipn_q = "&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-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));
                         }
                     }
                 }
             }
             /**/
             if (preg_match("/^(?:TEST_)?(?:SALE|BILL)\$/i", $clickbank["ctransaction"]) && preg_match("/^RECURRING\$/i", $clickbank["cprodtype"]) && (preg_match("/^COMPLETED\$/i", $clickbank["crebillstatus"]) || $clickbank["cfuturepayments"] <= 0) || preg_match("/^(?:TEST_)?CANCEL-REBILL\$/i", $clickbank["ctransaction"]) && preg_match("/^RECURRING\$/i", $clickbank["cprodtype"])) {
                 $clickbank["s2member_log"][] = "ClickBank® transaction identified as ( `RECURRING/COMPLETED` or `CANCEL-REBILL` ).";
                 $clickbank["s2member_log"][] = "IPN reformulated. Piping through s2Member's core/standard PayPal® processor as `txn_type` ( `subscr_cancel` ).";
                 $clickbank["s2member_log"][] = "Please check PayPal® IPN logs for further processing details.";
                 /**/
                 $processing = $processed = true;
                 $ipn = array();
                 /* Reset. */
                 /**/
                 $ipn["txn_type"] = "subscr_cancel";
                 $ipn["subscr_id"] = $s2vars["s2_subscr_id"];
                 /**/
                 $ipn["custom"] = $s2vars["s2_custom"];
                 /**/
                 $ipn["period1"] = $s2vars["s2_p1"];
                 $ipn["period3"] = $s2vars["s2_p3"];
                 /**/
                 $ipn["payer_email"] = $clickbank["ccustemail"];
                 $ipn["first_name"] = ucwords(strtolower($clickbank["ccustfirstname"]));
                 $ipn["last_name"] = ucwords(strtolower($clickbank["ccustlastname"]));
                 /**/
                 $ipn["option_name1"] = $s2vars["s2_referencing"] ? "Referencing Customer ID" : "Originating Domain";
                 $ipn["option_selection1"] = $s2vars["s2_referencing"] ? $s2vars["s2_referencing"] : $_SERVER["HTTP_HOST"];
                 /**/
                 $ipn["option_name2"] = "Customer IP Address";
                 $ipn["option_selection2"] = $s2vars["s2_customer_ip"];
                 /**/
                 $ipn["item_number"] = $s2vars["s2_invoice"];
                 $ipn["item_name"] = $s2vars["s2_desc"];
                 /**/
                 $ipn_q = "&s2member_paypal_proxy=clickbank&s2member_paypal_proxy_use=standard-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));
             }
             /**/
             if (!$processed) {
                 /* If nothing was processed, here we add a message to the logs indicating the IPN was ignored. */
                 $clickbank["s2member_log"][] = "Ignoring this IPN request. The transaction does NOT require any action on the part of s2Member.";
             }
         } else {
             $clickbank["s2member_log"][] = "Unable to verify POST vars. This is most likely related to an invalid ClickBank® configuration. Please check: s2Member -> ClickBank® Options.";
             $clickbank["s2member_log"][] = "If you're absolutely SURE that your ClickBank® 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 ClickBank® over an HTTPS connection.";
             $clickbank["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.";
             $clickbank["s2member_log"][] = var_export($_REQUEST, true);
             /* Recording _POST + _GET vars for analysis and debugging. */
         }
         /*
         If debugging/logging is enabled; we need to append $clickbank 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() ? "clickbank-ipn-4-" . trim(preg_replace("/[^a-z0-9]/i", "-", $_log4), "-") . ".log" : "clickbank-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($clickbank, 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. */
     }
 }