/**
  * Handles processing of Pro-Form billing updates.
  *
  * @package s2Member\Stripe
  * @since 140617
  *
  * @attaches-to ``add_action('init');``
  */
 public static function stripe_update()
 {
     if (!empty($_POST['s2member_pro_stripe_update']['nonce']) && ($nonce = $_POST['s2member_pro_stripe_update']['nonce']) && wp_verify_nonce($nonce, 's2member-pro-stripe-update')) {
         $GLOBALS['ws_plugin__s2member_pro_stripe_update_response'] = array();
         // This holds the global response details.
         $global_response =& $GLOBALS['ws_plugin__s2member_pro_stripe_update_response'];
         $post_vars = c_ws_plugin__s2member_utils_strings::trim_deep(stripslashes_deep($_POST['s2member_pro_stripe_update']));
         $post_vars['attr'] = !empty($post_vars['attr']) ? (array) unserialize(c_ws_plugin__s2member_utils_encryption::decrypt($post_vars['attr'])) : array();
         $post_vars['attr'] = apply_filters('ws_plugin__s2member_pro_stripe_update_post_attr', $post_vars['attr'], get_defined_vars());
         $post_vars = c_ws_plugin__s2member_utils_captchas::recaptcha_post_vars($post_vars);
         // Collect reCAPTCHA™ post vars.
         if (!c_ws_plugin__s2member_pro_stripe_responses::stripe_form_attr_validation_errors($post_vars['attr'])) {
             if (!($form_submission_validation_errors = c_ws_plugin__s2member_pro_stripe_responses::stripe_form_submission_validation_errors('update', $post_vars))) {
                 if (is_user_logged_in() && ($user = wp_get_current_user()) && ($user_id = $user->ID)) {
                     if (($cur__subscr_cid = get_user_option('s2member_subscr_cid')) && ($cur__subscr_id = get_user_option('s2member_subscr_id'))) {
                         if (is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($cur__subscr_cid, $cur__subscr_id)) && !preg_match('/^canceled$/i', $stripe_subscription->status) && !$stripe_subscription->cancel_at_period_end) {
                             unset($_POST['s2member_pro_stripe_update']['source_token']);
                             // These are good one-time only.
                             unset($_POST['s2member_pro_stripe_update']['source_token_summary']);
                             if (is_object($set_customer_source = c_ws_plugin__s2member_pro_stripe_utilities::set_customer_source($cur__subscr_cid, $post_vars['source_token'], $post_vars, $post_vars['attr']['reject_prepaid']))) {
                                 $global_response = array('response' => _x('<strong>Confirmed.</strong> Your billing information has been updated.', 's2member-front', 's2member'));
                                 if ($post_vars['attr']['success'] && ($custom_success_url = str_ireplace(array('%%s_response%%', '%%response%%'), array(urlencode(c_ws_plugin__s2member_utils_encryption::encrypt($global_response['response'])), urlencode($global_response['response'])), $post_vars['attr']['success'])) && ($custom_success_url = trim(preg_replace('/%%(.+?)%%/i', '', $custom_success_url)))) {
                                     wp_redirect(c_ws_plugin__s2member_utils_urls::add_s2member_sig($custom_success_url, 's2p-v')) . exit;
                                 }
                             } else {
                                 $global_response = array('response' => $set_customer_source, 'error' => TRUE);
                             }
                         } else {
                             $global_response = array('response' => _x('<strong>Unable to update.</strong> You have NO recurring fees. Or, your billing profile is no longer active. Please contact Support if you need assistance.', 's2member-front', 's2member'), 'error' => TRUE);
                         }
                     } else {
                         $global_response = array('response' => _x('<strong>Oops.</strong> No Customer|Subscr. ID. Please contact Support for assistance.', 's2member-front', 's2member'), 'error' => TRUE);
                     }
                 } else {
                     $global_response = array('response' => _x('You\'re <strong>NOT</strong> logged in.', 's2member-front', 's2member'), 'error' => TRUE);
                 }
             } else {
                 // Input form field validation errors.
                 $global_response = $form_submission_validation_errors;
             }
         }
     }
 }
 /**
  * Validates the configuration of the current form.
  *
  * Free Registration Forms do NOT require API Credentials.
  *
  * @package s2Member\Stripe
  * @since 140617
  *
  * @param array $attr An array of Pro-Form Attributes.
  *
  * @return null|array Null if there are no errors, else a response array.
  */
 public static function stripe_form_attr_validation_errors($attr = array())
 {
     if (!($response = c_ws_plugin__s2member_pro_stripe_responses::stripe_form_api_validation_errors($attr)) || !empty($attr['register'])) {
         if ($attr['cancel']) {
             if (!is_user_logged_in()) {
                 $response = array('response' => sprintf(_x('You must <a href="%s" rel="nofollow">log in</a> to cancel your account.', 's2member-front', 's2member'), esc_attr(wp_login_url($_SERVER['REQUEST_URI']))), 'error' => TRUE);
             } else {
                 if (!is_object($user = wp_get_current_user()) || !($user_id = $user->ID) || !($subscr_cid = get_user_option('s2member_subscr_cid', $user_id)) || !($subscr_id = get_user_option('s2member_subscr_id', $user_id))) {
                     $response = array('response' => _x('Nothing to cancel. You\'re NOT a paid Member.', 's2member-front', 's2member'), 'error' => TRUE);
                 } else {
                     if (!is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($subscr_cid, $subscr_id))) {
                         $response = array('response' => _x('Nothing to cancel. You have NO recurring fees.', 's2member-front', 's2member'), 'error' => TRUE);
                     } else {
                         if (preg_match('/^canceled$/i', $stripe_subscription->status) || $stripe_subscription->cancel_at_period_end) {
                             $response = array('response' => _x('Nothing to cancel. You have NO recurring fees.', 's2member-front', 's2member'), 'error' => TRUE);
                         }
                     }
                 }
             }
         } else {
             if ($attr['update']) {
                 if (!is_user_logged_in()) {
                     $response = array('response' => sprintf(_x('You must <a href="%s" rel="nofollow">log in</a> to update your billing information.', 's2member-front', 's2member'), esc_attr(wp_login_url($_SERVER['REQUEST_URI']))), 'error' => TRUE);
                 } else {
                     if (!is_object($user = wp_get_current_user()) || !($user_id = $user->ID) || !($subscr_cid = get_user_option('s2member_subscr_cid', $user_id)) || !($subscr_id = get_user_option('s2member_subscr_id', $user_id))) {
                         $response = array('response' => _x('Nothing to update. You\'re NOT a paid Member.', 's2member-front', 's2member'), 'error' => TRUE);
                     } else {
                         if (!is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($subscr_cid, $subscr_id))) {
                             $response = array('response' => _x('Nothing to update. You have NO recurring fees. Or, your billing profile is no longer active. Please contact Support if you need assistance.', 's2member-front', 's2member'), 'error' => TRUE);
                         } else {
                             if (preg_match('/^canceled$/i', $stripe_subscription->status) || $stripe_subscription->cancel_at_period_end) {
                                 $response = array('response' => _x('Nothing to update. You have NO recurring fees. Or, your billing profile is no longer active. Please contact Support if you need assistance.', 's2member-front', 's2member'), 'error' => TRUE);
                             }
                         }
                     }
                 }
             } else {
                 if ($attr['register']) {
                     if (!is_string($attr['level']) || !is_numeric($attr['level'])) {
                         $response = array('response' => sprintf(_x('Invalid form configuration. Missing "level" attribute. Membership Level. Must be numeric [0-%s].', 's2member-admin', 's2member'), esc_html($GLOBALS['WS_PLUGIN__']['s2member']['c']['levels'])), 'error' => TRUE);
                     } else {
                         if ($attr['level'] < 0 || $attr['level'] > $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels']) {
                             $response = array('response' => sprintf(_x('Invalid form configuration. Invalid "level" attribute. Membership Level. Must be numeric [0-%s].', 's2member-admin', 's2member'), esc_html($GLOBALS['WS_PLUGIN__']['s2member']['c']['levels'])), 'error' => TRUE);
                         } else {
                             if ($attr['ccaps'] && (!is_string($attr['ccaps']) || preg_replace('/^-all[' . "\r\n\t" . '\\s;,]*/', '', str_replace('+', '', $attr['ccaps'])) && !preg_match('/^([a-z_0-9,]+)$/', preg_replace('/^-all[' . "\r\n\t" . '\\s;,]*/', '', str_replace('+', '', $attr['ccaps']))))) {
                                 $response = array('response' => _x('Invalid form configuration. Invalid "ccaps" attribute. Custom Capabilities. When provided, must be all lowercase [a-z_0-9,]. A preceding `-all,` directive is also acceptable.', 's2member-admin', 's2member'), 'error' => TRUE);
                             } else {
                                 if ($attr['tp'] && (!is_string($attr['tp']) || !is_numeric($attr['tp']))) {
                                     $response = array('response' => _x('Invalid form configuration. Invalid "tp" attribute. The Trial Period. When provided, must be numeric.', 's2member-admin', 's2member'), 'error' => TRUE);
                                 } else {
                                     if ($attr['tp'] && $attr['tp'] < 1) {
                                         $response = array('response' => _x('Invalid form configuration. Invalid "tp" attribute. The Trial Period. When provided, must be >= 1.', 's2member-admin', 's2member'), 'error' => TRUE);
                                     } else {
                                         if ($attr['tp'] && (!$attr['tt'] || !is_string($attr['tt']))) {
                                             $response = array('response' => _x('Invalid form configuration. Missing "tt" attribute. The Trial Term. When "tp" is provided, "tt" (Trial Term) must be one of D,W,M,Y.', 's2member-admin', 's2member'), 'error' => TRUE);
                                         } else {
                                             if ($attr['tp'] && !preg_match('/[DWMY]/', $attr['tt'])) {
                                                 $response = array('response' => _x('Invalid form configuration. Invalid "tt" attribute. The Trial Term. When "tp" is provided, "tt" (Trial Term) must be one of D,W,M,Y.', 's2member-admin', 's2member'), 'error' => TRUE);
                                             } else {
                                                 if ($attr['custom'] && (!is_string($attr['custom']) || !preg_match('/^' . preg_quote(preg_replace('/\\:([0-9]+)$/', '', $_SERVER['HTTP_HOST']), '/') . '/i', $attr['custom']))) {
                                                     $response = array('response' => _x('Invalid form configuration. Invalid "custom" attribute. When provided, must start with your domain name.', 's2member-admin', 's2member-admin'), 'error' => TRUE);
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 } else {
                     if ($attr['sp']) {
                         if (!$attr['ids'] || !is_string($attr['ids'])) {
                             $response = array('response' => _x('Invalid form configuration. Missing "ids" attribute. Must contain comma-delimited Post/Page IDs.', 's2member-admin', 's2member'), 'error' => TRUE);
                         } else {
                             if (!preg_match('/^([0-9,]+)$/', $attr['ids'])) {
                                 $response = array('response' => _x('Invalid form configuration. Invalid "ids" attribute. Must contain comma-delimited Post/Page IDs. Must contain [0-9,] only.', 's2member-admin', 's2member'), 'error' => TRUE);
                             } else {
                                 if (!$attr['exp'] || !is_string($attr['exp'])) {
                                     $response = array('response' => _x('Invalid form configuration. Missing "exp" attribute. Specific Post/Page Expiration (in hours). Must be numeric.', 's2member-admin', 's2member'), 'error' => TRUE);
                                 } else {
                                     if (!is_numeric($attr['exp'])) {
                                         $response = array('response' => _x('Invalid form configuration. Invalid "exp" attribute. Specific Post/Page Expiration (in hours). Must be numeric.', 's2member-admin', 's2member'), 'error' => TRUE);
                                     } else {
                                         if ($attr['exp'] < 1) {
                                             $response = array('response' => _x('Invalid form configuration. Invalid "exp" attribute. Specific Post/Page Expiration (in hours). Must be >= 1.', 's2member-admin', 's2member'), 'error' => TRUE);
                                         } else {
                                             if ($attr['exp'] > 438291) {
                                                 $response = array('response' => _x('Invalid form configuration. Invalid "exp" attribute. Specific Post/Page Expiration (in hours). Must be <= 438291.', 's2member-admin', 's2member'), 'error' => TRUE);
                                             } else {
                                                 if (!$attr['sp_ids_exp'] || !is_string($attr['sp_ids_exp'])) {
                                                     $response = array('response' => _x('Invalid form configuration. Missing "sp_ids_exp" internal attribute. Please check Shortcode Attributes.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                 } else {
                                                     if (!preg_match($GLOBALS['WS_PLUGIN__']['s2member']['c']['sp_access_item_number_regex'], $attr['sp_ids_exp'])) {
                                                         $response = array('response' => _x('Invalid form configuration. Invalid "sp_ids_exp" internal attribute. Please check Shortcode Attributes.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                     } else {
                                                         if (!$attr['desc'] || !is_string($attr['desc'])) {
                                                             $response = array('response' => _x('Invalid form configuration. Missing "desc" attribute. Please provide a Description for this form.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                         } else {
                                                             if (strlen($attr['desc']) > 100) {
                                                                 $response = array('response' => _x('Invalid form configuration. Your "desc" (Description) attribute must be <= 100 characters long.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                             } else {
                                                                 if (!$attr['custom'] || !is_string($attr['custom'])) {
                                                                     $response = array('response' => _x('Invalid form configuration. Missing "custom" attribute. Must start with your domain name.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                 } else {
                                                                     if (!preg_match('/^' . preg_quote(preg_replace('/\\:([0-9]+)$/', '', $_SERVER['HTTP_HOST']), '/') . '/i', $attr['custom'])) {
                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "custom" attribute. Must start with your domain name.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                     } else {
                                                                         if (!$attr['cc'] || !is_string($attr['cc'])) {
                                                                             $response = array('response' => _x('Invalid form configuration. Missing "cc" attribute. Must be a 3 character Currency Code.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                         } else {
                                                                             if (strlen($attr['cc']) !== 3) {
                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "cc" attribute. Must be a 3 character Currency Code.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                             } else {
                                                                                 if (!strlen($attr['ra']) || !is_string($attr['ra'])) {
                                                                                     $response = array('response' => _x('Invalid form configuration. Missing "ra" attribute. The Regular Amount. Must be >= 0.00.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                 } else {
                                                                                     if (!is_numeric($attr['ra'])) {
                                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "ra" attribute. The Regular Amount. Must be numeric.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                     } else {
                                                                                         if ($attr['ra'] < 0.0) {
                                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "ra" attribute. The Regular Amount. Must be >= 0.00.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                         } else {
                                                                                             if ($attr['ra'] > 0.0 && $attr['ra'] < 0.5) {
                                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "ra" attribute. The Regular Amount (when greater than 0.00), must be >= 0.50; i.e., the minimum amount that Stripe will charge is 0.50', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                             } else {
                                                                                                 if ($attr['ra'] > 999999.99) {
                                                                                                     $response = array('response' => _x('Invalid form configuration. Invalid "ra" attribute. The Regular Amount. Must be <= 999999.99.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                 }
                                                                                             }
                                                                                         }
                                                                                     }
                                                                                 }
                                                                             }
                                                                         }
                                                                     }
                                                                 }
                                                             }
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     } else {
                         if ($attr['modify'] && !is_user_logged_in()) {
                             $response = array('response' => sprintf(_x('You must <a href="%s" rel="nofollow">login</a> to update your billing plan.', 's2member-front', 's2member'), esc_attr(wp_login_url($_SERVER['REQUEST_URI']))), 'error' => TRUE);
                         } else {
                             if ($attr['level'] === '*' && !is_user_logged_in()) {
                                 $response = array('response' => sprintf(_x('You must <a href="%s" rel="nofollow">login</a> before making this purchase.', 's2member-front', 's2member'), esc_attr(wp_login_url($_SERVER['REQUEST_URI']))), 'error' => TRUE);
                             } else {
                                 if ((!$attr['level'] || !is_string($attr['level']) || !is_numeric($attr['level'])) && $attr['level'] !== '*') {
                                     $response = array('response' => sprintf(_x('Invalid form configuration. Missing "level" attribute. Membership Level. Must be numeric [1-%s], or an asterisk (*).', 's2member-admin', 's2member'), esc_html($GLOBALS['WS_PLUGIN__']['s2member']['c']['levels'])), 'error' => TRUE);
                                 } else {
                                     if (($attr['level'] < 1 || $attr['level'] > $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels']) && $attr['level'] !== '*') {
                                         $response = array('response' => sprintf(_x('Invalid form configuration. Invalid "level" attribute. Membership Level. Must be numeric [1-%s], or an asterisk (*).', 's2member-admin', 's2member'), esc_html($GLOBALS['WS_PLUGIN__']['s2member']['c']['levels'])), 'error' => TRUE);
                                     } else {
                                         if ($attr['ccaps'] && (!is_string($attr['ccaps']) || preg_replace('/^-all[' . "\r\n\t" . '\\s;,]*/', '', str_replace('+', '', $attr['ccaps'])) && !preg_match('/^([a-z_0-9,]+)$/', preg_replace('/^-all[' . "\r\n\t" . '\\s;,]*/', '', str_replace('+', '', $attr['ccaps']))))) {
                                             $response = array('response' => _x('Invalid form configuration. Invalid "ccaps" attribute. Custom Capabilities. When provided, must be all lowercase [a-z_0-9,]. A preceding `-all,` directive is also acceptable.', 's2member-admin', 's2member'), 'error' => TRUE);
                                         } else {
                                             if ($attr['level'] === '*' && (!is_string($attr['ccaps']) || !preg_replace('/^-all[' . "\r\n\t" . '\\s;,]*/', '', str_replace('+', '', $attr['ccaps'])) || !preg_match('/^([a-z_0-9,]+)$/', preg_replace('/^-all[' . "\r\n\t" . '\\s;,]*/', '', str_replace('+', '', $attr['ccaps']))))) {
                                                 $response = array('response' => _x('Invalid form configuration. Missing or invalid "ccaps" attribute. When "level" is "*" for (Independent Custom Capabilities), "ccaps" is required. All lowercase [a-z_0-9,]. A preceding `-all,` directive is also acceptable.', 's2member-admin', 's2member'), 'error' => TRUE);
                                             } else {
                                                 if (!$attr['desc'] || !is_string($attr['desc'])) {
                                                     $response = array('response' => _x('Invalid form configuration. Missing "desc" attribute. Please provide a Description for this form.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                 } else {
                                                     if (strlen($attr['desc']) > 100) {
                                                         $response = array('response' => _x('Invalid form configuration. Your "desc" (Description) attribute must be <= 100 characters long.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                     } else {
                                                         if (!$attr['custom'] || !is_string($attr['custom'])) {
                                                             $response = array('response' => _x('Invalid form configuration. Missing "custom" attribute. Must start with your domain name.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                         } else {
                                                             if (!preg_match('/^' . preg_quote(preg_replace('/\\:([0-9]+)$/', '', $_SERVER['HTTP_HOST']), '/') . '/i', $attr['custom'])) {
                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "custom" attribute. Must start with matching domain.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                             } else {
                                                                 if (!$attr['cc'] || !is_string($attr['cc'])) {
                                                                     $response = array('response' => _x('Invalid form configuration. Missing "cc" attribute. Must be a 3 character Currency Code.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                 } else {
                                                                     if (strlen($attr['cc']) !== 3) {
                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "cc" attribute. Must be a 3 character Currency Code.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                     } else {
                                                                         if ($attr['tp'] && (!is_string($attr['tp']) || !is_numeric($attr['tp']))) {
                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "tp" attribute. The Trial Period. When provided, must be numeric.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                         } else {
                                                                             if ($attr['tp'] && $attr['tp'] < 1) {
                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "tp" attribute. The Trial Period. When provided, must be >= 1.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                             } else {
                                                                                 if ($attr['tp'] && (!$attr['tt'] || !is_string($attr['tt']))) {
                                                                                     $response = array('response' => _x('Invalid form configuration. Missing "tt" attribute. The Trial Term. When "tp" is provided, "tt" (Trial Term) must be one of D,W,M,Y.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                 } else {
                                                                                     if ($attr['tp'] && !preg_match('/[DWMY]/', $attr['tt'])) {
                                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "tt" attribute. The Trial Term. When "tp" is provided, "tt" (Trial Term) must be one of D,W,M,Y.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                     } else {
                                                                                         if ($attr['tp'] && $attr['tt'] === 'D' && $attr['tp'] > 365 && $attr['ta'] > 0) {
                                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "tt, tp" attributes. There is an Intial/Trial amount, and "tt" (Trial Term) attribute is "D", and "tp" (Trial Period) > 365.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                         } else {
                                                                                             if ($attr['tp'] && $attr['tt'] === 'W' && $attr['tp'] > 52 && $attr['ta'] > 0) {
                                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "tt, tp" attributes. There is an Intial/Trial amount, and "tt" (Trial Term) attribute is "W", and "tp" (Trial Period) > 52.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                             } else {
                                                                                                 if ($attr['tp'] && $attr['tt'] === 'M' && $attr['tp'] > 12 && $attr['ta'] > 0) {
                                                                                                     $response = array('response' => _x('Invalid form configuration. Invalid "tt, tp" attributes. There is an Intial/Trial amount, and "tt" (Trial Term) attribute is "M", and "tp" (Trial Period) > 12.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                 } else {
                                                                                                     if ($attr['tp'] && $attr['tt'] === 'Y' && $attr['tp'] > 2 && $attr['ta'] > 0) {
                                                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "tt, tp" attributes. There is an Intial/Trial amount, and "tt" (Trial Term) attribute is "Y", and "tp" (Trial Period) > 2.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                     } else {
                                                                                                         if ($attr['tp'] && $attr['ta'] && !is_numeric($attr['ta'])) {
                                                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "ta" attribute. The Trial Amount. When provided, must be numeric.', "s2member-admin", 's2member'), 'error' => TRUE);
                                                                                                         } else {
                                                                                                             if ($attr['tp'] && $attr['ta'] && $attr['ta'] < 0.5) {
                                                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "ta" attribute. The Trial Amount. When provided, must be >= 0.50.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                             } else {
                                                                                                                 if ($attr['tp'] && $attr['ta'] && $attr['ta'] > 999999.99) {
                                                                                                                     $response = array('response' => _x('Invalid form configuration. Invalid "ta" attribute. The Trial Amount. When provided, must be <= 999999.99.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                 } else {
                                                                                                                     if (!$attr['rp'] || !is_string($attr['rp'])) {
                                                                                                                         $response = array('response' => _x('Invalid form configuration. Missing "rp" attribute. The Regular Period. Must be >= 1.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                     } else {
                                                                                                                         if (!is_numeric($attr['rp'])) {
                                                                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "rp" attribute. The Regular Period. Must be numeric.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                         } else {
                                                                                                                             if ($attr['rp'] < 1) {
                                                                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "rp" attribute. The Regular Period. Must be >= 1.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                             } else {
                                                                                                                                 if (!$attr['rt'] || !is_string($attr['rt'])) {
                                                                                                                                     $response = array('response' => _x('Invalid form configuration. Missing "rt" attribute. The Regular Term. Must be one of D,W,M,Y,L.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                 } else {
                                                                                                                                     if (!preg_match('/[DWMYL]/', $attr['rt'])) {
                                                                                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "rt" attribute. The Regular Term. Must be one of D,W,M,Y,L.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                     } else {
                                                                                                                                         if ($attr['rt'] === 'D' && $attr['rp'] > 365 && $attr['rr'] !== 'BN') {
                                                                                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "rt, rp, rr" attributes. The "rt" (Regular Term) attribute is "D", "rp" (Regular Period) > 365, and "rr" is not "BN" (Buy Now).', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                         } else {
                                                                                                                                             if ($attr['rt'] === 'W' && $attr['rp'] > 52 && $attr['rr'] !== 'BN') {
                                                                                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "rt, rp, rr" attributes. The "rt" (Regular Term) attribute is "W", "rp" (Regular Period) > 52, and "rr" is not "BN" (Buy Now).', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                             } else {
                                                                                                                                                 if ($attr['rt'] === 'M' && $attr['rp'] > 12 && $attr['rr'] !== 'BN') {
                                                                                                                                                     $response = array('response' => _x('Invalid form configuration. Invalid "rt, rp, rr" attributes. The "rt" (Regular Term) attribute is "M", "rp" (Regular Period) > 12, and "rr" is not "BN" (Buy Now).', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                 } else {
                                                                                                                                                     if ($attr['rt'] === 'Y' && $attr['rp'] > 1 && $attr['rr'] !== 'BN') {
                                                                                                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "rt, rp, rr" attributes. The "rt" (Regular Term) attribute is "Y", "rp" (Regular Period) > 1, and "rr" is not "BN" (Buy Now).', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                     } else {
                                                                                                                                                         if ($attr['rt'] === 'L' && $attr['rp'] > 1) {
                                                                                                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "rp, rt" attributes. The "rt" (Regular Term) attribute is "L" (Lifetime), and "rp" (Regular Period) > 1.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                         } else {
                                                                                                                                                             if ($attr['rt'] === 'L' && $attr['rr'] !== 'BN') {
                                                                                                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "rt, rr" attributes. The "rt" (Regular Term) attribute is "L" (Lifetime), and "rr" is not "BN" (Buy Now).', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                             } else {
                                                                                                                                                                 if (!$attr['level_ccaps_eotper'] || !is_string($attr['level_ccaps_eotper'])) {
                                                                                                                                                                     $response = array('response' => _x('Invalid form configuration. Missing "level_ccaps_eotper" attribute. Please check Shortcode Attributes.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                 } else {
                                                                                                                                                                     if ($attr['level'] !== '*' && !preg_match($GLOBALS['WS_PLUGIN__']['s2member']['c']['membership_item_number_w_level_regex'], $attr['level_ccaps_eotper'])) {
                                                                                                                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "level_ccaps_eotper" attribute. Please check Shortcode Attributes.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                     } else {
                                                                                                                                                                         if ($attr['level'] === '*' && !preg_match($GLOBALS['WS_PLUGIN__']['s2member']['c']['membership_item_number_wo_level_regex'], $attr['level_ccaps_eotper'])) {
                                                                                                                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "level_ccaps_eotper" attribute. Please check Shortcode Attributes.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                         } else {
                                                                                                                                                                             if (!strlen($attr['ra']) || !is_string($attr['ra'])) {
                                                                                                                                                                                 $response = array('response' => _x('Invalid form configuration. Missing "ra" attribute. The Regular Amount. Must be >= 0.00.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                             } else {
                                                                                                                                                                                 if (!is_numeric($attr['ra'])) {
                                                                                                                                                                                     $response = array('response' => _x('Invalid form configuration. Invalid "ra" attribute. The Regular Amount. Must be numeric.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                                 } else {
                                                                                                                                                                                     if ($attr['ra'] < 0.0) {
                                                                                                                                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "ra" attribute. The Regular Amount. Must be >= 0.00.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                                     } else {
                                                                                                                                                                                         if ($attr['ra'] > 0.0 && $attr['ra'] < 0.5) {
                                                                                                                                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "ra" attribute. The Regular Amount (when greater than 0.00), must be >= 0.50; i.e., the minimum amount that Stripe will charge is 0.50', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                                         } else {
                                                                                                                                                                                             if ($attr['ra'] > 999999.99) {
                                                                                                                                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "ra" attribute. The Regular Amount. Must be <= 999999.99.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                                             } else {
                                                                                                                                                                                                 if ($attr['rr'] && (!is_string($attr['rr']) || !preg_match('/^([0-1]|BN)$/', $attr['rr']))) {
                                                                                                                                                                                                     $response = array('response' => _x('Invalid form configuration. Invalid "rr" attribute. Regular Recurring. When provided, must be 0, 1, or BN.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                                                 } else {
                                                                                                                                                                                                     if ($attr['rr'] === 'BN' && $attr['tp']) {
                                                                                                                                                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "rr, tp" attributes. The "rr" (Regular Recurring) attribute is "BN" (Buy Now), and "tp" (Trial Period) is not "0".', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                                                     } else {
                                                                                                                                                                                                         if ($attr['level'] === '*' && $attr['rr'] !== 'BN') {
                                                                                                                                                                                                             $response = array('response' => _x('Invalid form configuration. Invalid "level, rr" attributes. The "level" (Level) attribute is "*" for (Independent Custom Capabilities), and "rr" is not "BN" (Buy Now).', "s2member-admin", 's2member'), 'error' => TRUE);
                                                                                                                                                                                                         } else {
                                                                                                                                                                                                             if ($attr['rrt'] && (!is_string($attr['rrt']) || !is_numeric($attr['rrt']))) {
                                                                                                                                                                                                                 $response = array('response' => _x('Invalid form configuration. Invalid "rrt" attribute. Recurring Times (fixed). When provided, must be numeric.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                                                             } else {
                                                                                                                                                                                                                 if ($attr['rrt'] && $attr['rrt'] < 1) {
                                                                                                                                                                                                                     $response = array('response' => _x('Invalid form configuration. Invalid "rrt" attribute. Recurring Times (fixed). When provided, must be >= 1.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                                                                 } else {
                                                                                                                                                                                                                     if ($attr['rrt'] && $attr['rr'] !== '1') {
                                                                                                                                                                                                                         $response = array('response' => _x('Invalid form configuration. Invalid "rr, rrt" attributes. When "rrt" (Recurring Times) is provided, "rr" (Regular Recurring) must be 1.', 's2member-admin', 's2member'), 'error' => TRUE);
                                                                                                                                                                                                                     }
                                                                                                                                                                                                                 }
                                                                                                                                                                                                             }
                                                                                                                                                                                                         }
                                                                                                                                                                                                     }
                                                                                                                                                                                                 }
                                                                                                                                                                                             }
                                                                                                                                                                                         }
                                                                                                                                                                                     }
                                                                                                                                                                                 }
                                                                                                                                                                             }
                                                                                                                                                                         }
                                                                                                                                                                     }
                                                                                                                                                                 }
                                                                                                                                                             }
                                                                                                                                                         }
                                                                                                                                                     }
                                                                                                                                                 }
                                                                                                                                             }
                                                                                                                                         }
                                                                                                                                     }
                                                                                                                                 }
                                                                                                                             }
                                                                                                                         }
                                                                                                                     }
                                                                                                                 }
                                                                                                             }
                                                                                                         }
                                                                                                     }
                                                                                                 }
                                                                                             }
                                                                                         }
                                                                                     }
                                                                                 }
                                                                             }
                                                                         }
                                                                     }
                                                                 }
                                                             }
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return empty($response) ? NULL : $response;
 }
Esempio n. 3
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 processing of Pro-Form cancellations.
  *
  * @package s2Member\Stripe
  * @since 140617
  *
  * @attaches-to ``add_action('init');``
  */
 public static function stripe_cancellation()
 {
     if (!empty($_POST['s2member_pro_stripe_cancellation']['nonce']) && ($nonce = $_POST['s2member_pro_stripe_cancellation']['nonce']) && wp_verify_nonce($nonce, 's2member-pro-stripe-cancellation')) {
         $GLOBALS['ws_plugin__s2member_pro_stripe_cancellation_response'] = array();
         // This holds the global response details.
         $global_response =& $GLOBALS['ws_plugin__s2member_pro_stripe_cancellation_response'];
         $post_vars = c_ws_plugin__s2member_utils_strings::trim_deep(stripslashes_deep($_POST['s2member_pro_stripe_cancellation']));
         $post_vars['attr'] = !empty($post_vars['attr']) ? (array) unserialize(c_ws_plugin__s2member_utils_encryption::decrypt($post_vars['attr'])) : array();
         $post_vars['attr'] = apply_filters('ws_plugin__s2member_pro_stripe_cancellation_post_attr', $post_vars['attr'], get_defined_vars());
         $post_vars['recaptcha_challenge_field'] = isset($_POST['recaptcha_challenge_field']) ? trim(stripslashes($_POST['recaptcha_challenge_field'])) : '';
         $post_vars['recaptcha_response_field'] = isset($_POST['recaptcha_response_field']) ? trim(stripslashes($_POST['recaptcha_response_field'])) : '';
         if (!c_ws_plugin__s2member_pro_stripe_responses::stripe_form_attr_validation_errors($post_vars['attr'])) {
             if (!($form_submission_validation_errors = c_ws_plugin__s2member_pro_stripe_responses::stripe_form_submission_validation_errors('cancellation', $post_vars))) {
                 if (is_user_logged_in() && is_object($user = wp_get_current_user()) && ($user_id = $user->ID)) {
                     if (($cur__subscr_cid = get_user_option('s2member_subscr_cid')) && ($cur__subscr_id = get_user_option('s2member_subscr_id'))) {
                         if (is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($cur__subscr_cid, $cur__subscr_id))) {
                             if (!preg_match('/^canceled$/i', $stripe_subscription->status) && !$stripe_subscription->cancel_at_period_end) {
                                 if (is_object(c_ws_plugin__s2member_pro_stripe_utilities::cancel_customer_subscription($cur__subscr_cid, $cur__subscr_id))) {
                                     if (is_array($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars())) {
                                         $ipn['txn_type'] = 'subscr_cancel';
                                         $ipn['subscr_cid'] = $ipn_signup_vars['subscr_cid'];
                                         $ipn['subscr_id'] = $ipn_signup_vars['subscr_id'];
                                         $ipn['custom'] = $ipn_signup_vars['custom'];
                                         $ipn['period1'] = $ipn_signup_vars['period1'];
                                         $ipn['period3'] = $ipn_signup_vars['period3'];
                                         $ipn['payer_email'] = $ipn_signup_vars['payer_email'];
                                         $ipn['first_name'] = $ipn_signup_vars['first_name'];
                                         $ipn['last_name'] = $ipn_signup_vars['last_name'];
                                         $ipn['option_name1'] = $ipn_signup_vars['option_name1'];
                                         $ipn['option_selection1'] = $ipn_signup_vars['option_selection1'];
                                         $ipn['option_name2'] = $ipn_signup_vars['option_name2'];
                                         $ipn['option_selection2'] = $ipn_signup_vars['option_selection2'];
                                         $ipn['item_name'] = $ipn_signup_vars['item_name'];
                                         $ipn['item_number'] = $ipn_signup_vars['item_number'];
                                         $ipn['s2member_paypal_proxy'] = 'stripe';
                                         $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));
                                     }
                                     $global_response = array('response' => _x('<strong>Billing termination confirmed.</strong> Your account has been cancelled.', 's2member-front', 's2member'));
                                     if ($post_vars['attr']['success'] && ($custom_success_url = str_ireplace(array('%%s_response%%', '%%response%%'), array(urlencode(c_ws_plugin__s2member_utils_encryption::encrypt($global_response['response'])), urlencode($global_response['response'])), $post_vars['attr']['success'])) && ($custom_success_url = trim(preg_replace('/%%(.+?)%%/i', '', $custom_success_url)))) {
                                         wp_redirect(c_ws_plugin__s2member_utils_urls::add_s2member_sig($custom_success_url, 's2p-v')) . exit;
                                     }
                                 } else {
                                     $global_response = array('response' => _x('API failure. Please contact Support for assistance.', 's2member-front', 's2member'), 'error' => TRUE);
                                 }
                             } else {
                                 $global_response = array('response' => _x('<strong>Billing terminated.</strong> Your account has been cancelled.', 's2member-front', 's2member'));
                                 if ($post_vars['attr']['success'] && ($custom_success_url = str_ireplace(array('%%s_response%%', '%%response%%'), array(urlencode(c_ws_plugin__s2member_utils_encryption::encrypt($global_response['response'])), urlencode($global_response['response'])), $post_vars['attr']['success'])) && ($custom_success_url = trim(preg_replace('/%%(.+?)%%/i', '', $custom_success_url)))) {
                                     wp_redirect(c_ws_plugin__s2member_utils_urls::add_s2member_sig($custom_success_url, 's2p-v')) . exit;
                                 }
                             }
                         } else {
                             $global_response = array('response' => _x('<strong>Billing terminated.</strong> Your account has been cancelled.', 's2member-front', 's2member'));
                             if ($post_vars['attr']['success'] && ($custom_success_url = str_ireplace(array('%%s_response%%', '%%response%%'), array(urlencode(c_ws_plugin__s2member_utils_encryption::encrypt($global_response['response'])), urlencode($global_response['response'])), $post_vars['attr']['success'])) && ($custom_success_url = trim(preg_replace('/%%(.+?)%%/i', '', $custom_success_url)))) {
                                 wp_redirect(c_ws_plugin__s2member_utils_urls::add_s2member_sig($custom_success_url, 's2p-v')) . exit;
                             }
                         }
                     } else {
                         $global_response = array('response' => _x('<strong>Billing terminated.</strong> Your account has been cancelled.', 's2member-front', 's2member'));
                         if ($post_vars['attr']['success'] && ($custom_success_url = str_ireplace(array('%%s_response%%', '%%response%%'), array(urlencode(c_ws_plugin__s2member_utils_encryption::encrypt($global_response['response'])), urlencode($global_response['response'])), $post_vars['attr']['success'])) && ($custom_success_url = trim(preg_replace('/%%(.+?)%%/i', '', $custom_success_url)))) {
                             wp_redirect(c_ws_plugin__s2member_utils_urls::add_s2member_sig($custom_success_url, 's2p-v')) . exit;
                         }
                     }
                     if ($post_vars['attr']['unsub']) {
                         c_ws_plugin__s2member_list_servers::process_list_server_removals_against_current_user(TRUE);
                     }
                 } else {
                     $global_response = array('response' => _x('You\'re <strong>NOT</strong> logged in.', 's2member-front', 's2member'), 'error' => TRUE);
                 }
             } else {
                 // Input form field validation errors.
                 $global_response = $form_submission_validation_errors;
             }
         }
     }
 }
 /**
  * Handles Stripe Webhook/IPN event processing.
  *
  * @package s2Member\Stripe
  * @since 140617
  *
  * @attaches-to ``add_action('init');``
  */
 public static function stripe_notify()
 {
     global $current_site, $current_blog;
     if (!empty($_GET['s2member_pro_stripe_notify']) && $GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_stripe_api_secret_key']) {
         $stripe = array();
         // Initialize array of Webhook/IPN event data and s2Member log details.
         @ignore_user_abort(TRUE);
         // Continue processing even if/when connection is broken.
         require_once dirname(__FILE__) . '/stripe-sdk/lib/Stripe.php';
         Stripe::setApiKey($GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_stripe_api_secret_key']);
         if (is_object($event = c_ws_plugin__s2member_pro_stripe_utilities::get_event()) && ($stripe['event'] = $event)) {
             switch ($event->type) {
                 case 'invoice.payment_succeeded':
                     // Subscription payments.
                     if (!empty($event->data->object) && ($stripe_invoice = $event->data->object) instanceof Stripe_Invoice && !empty($stripe_invoice->customer) && !empty($stripe_invoice->subscription) && ($stripe_invoice_total = number_format(c_ws_plugin__s2member_pro_stripe_utilities::cents_to_dollar_amount($stripe_invoice->total, $stripe_invoice->currency), 2, '.', '')) > 0 && is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($stripe_invoice->customer, $stripe_invoice->subscription)) && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_subscription->id))) {
                         $processing = TRUE;
                         $ipn['txn_type'] = 'subscr_payment';
                         $ipn['txn_id'] = $stripe_invoice->id;
                         $ipn['txn_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['custom'] = $ipn_signup_vars['custom'];
                         $ipn['mc_gross'] = $stripe_invoice_total;
                         $ipn['mc_currency'] = strtoupper($stripe_invoice->currency);
                         $ipn['tax'] = number_format(0, 2, '.', '');
                         $ipn['period1'] = $ipn_signup_vars['period1'];
                         $ipn['period3'] = $ipn_signup_vars['period3'];
                         $ipn['payer_email'] = $ipn_signup_vars['payer_email'];
                         $ipn['first_name'] = $ipn_signup_vars['first_name'];
                         $ipn['last_name'] = $ipn_signup_vars['last_name'];
                         $ipn['option_name1'] = $ipn_signup_vars['option_name1'];
                         $ipn['option_selection1'] = $ipn_signup_vars['option_selection1'];
                         $ipn['option_name2'] = $ipn_signup_vars['option_name2'];
                         $ipn['option_selection2'] = $ipn_signup_vars['option_selection2'];
                         $ipn['item_name'] = $ipn_signup_vars['item_name'];
                         $ipn['item_number'] = $ipn_signup_vars['item_number'];
                         $ipn['s2member_paypal_proxy'] = 'stripe';
                         $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));
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         if ($maybe_end_subscription = self::_maybe_end_subscription_after_payment($stripe_invoice->customer, $stripe_subscription)) {
                             $stripe['s2member_log'][] = $maybe_end_subscription;
                         }
                         $stripe['s2member_log'][] = 'Webhook/IPN event `' . $event->type . '` reformulated. Piping through s2Member\'s core gateway processor as `txn_type` (`' . $ipn['txn_type'] . '`).';
                         $stripe['s2member_log'][] = 'Please check core IPN logs for further processing details.';
                     }
                     break;
                     // Break switch handler.
                 // Break switch handler.
                 case 'invoice.payment_failed':
                     // Subscription payment failures.
                     if (!empty($event->data->object) && ($stripe_invoice = $event->data->object) instanceof Stripe_Invoice && !empty($stripe_invoice->customer) && !empty($stripe_invoice->subscription) && ($stripe_invoice_total = number_format(c_ws_plugin__s2member_pro_stripe_utilities::cents_to_dollar_amount($stripe_invoice->total, $stripe_invoice->currency), 2, '.', '')) > 0 && is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($stripe_invoice->customer, $stripe_invoice->subscription)) && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_subscription->id))) {
                         $processing = TRUE;
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         if ($maybe_end_subscription = self::_maybe_end_subscription_after_payment($stripe_invoice->customer, $stripe_subscription)) {
                             $stripe['s2member_log'][] = $maybe_end_subscription;
                         }
                         $stripe['s2member_log'][] = 'Ignoring `' . $event->type . '`. s2Member does NOT respond to individual payment failures; only to subscription cancellations.';
                         $stripe['s2member_log'][] = 'You may control the behavior(s) associated w/ subscription payment failures from your Stripe Dashboard please.';
                     }
                     break;
                     // Break switch handler.
                 // Break switch handler.
                 case 'customer.deleted':
                     // Customer deletions.
                     if (!empty($event->data->object) && ($stripe_customer = $event->data->object) instanceof Stripe_Customer && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_customer->id))) {
                         $processing = TRUE;
                         $ipn['txn_type'] = 'subscr_eot';
                         $ipn['subscr_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['custom'] = $ipn_signup_vars['custom'];
                         $ipn['period1'] = $ipn_signup_vars['period1'];
                         $ipn['period3'] = $ipn_signup_vars['period3'];
                         $ipn['payer_email'] = $ipn_signup_vars['payer_email'];
                         $ipn['first_name'] = $ipn_signup_vars['first_name'];
                         $ipn['last_name'] = $ipn_signup_vars['last_name'];
                         $ipn['option_name1'] = $ipn_signup_vars['option_name1'];
                         $ipn['option_selection1'] = $ipn_signup_vars['option_selection1'];
                         $ipn['option_name2'] = $ipn_signup_vars['option_name2'];
                         $ipn['option_selection2'] = $ipn_signup_vars['option_selection2'];
                         $ipn['item_name'] = $ipn_signup_vars['item_name'];
                         $ipn['item_number'] = $ipn_signup_vars['item_number'];
                         $ipn['s2member_paypal_proxy'] = 'stripe';
                         $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));
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         $stripe['s2member_log'][] = 'Webhook/IPN event `' . $event->type . '` reformulated. Piping through s2Member\'s core gateway processor as `txn_type` (`' . $ipn['txn_type'] . '`).';
                         $stripe['s2member_log'][] = 'Please check core IPN logs for further processing details.';
                     }
                     break;
                     // Break switch handler.
                 // Break switch handler.
                 case 'customer.subscription.deleted':
                     // Customer subscription deletion.
                     if (!empty($event->data->object) && ($stripe_subscription = $event->data->object) instanceof Stripe_Subscription && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_subscription->id))) {
                         $processing = TRUE;
                         $ipn['txn_type'] = 'subscr_eot';
                         $ipn['subscr_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['custom'] = $ipn_signup_vars['custom'];
                         $ipn['period1'] = $ipn_signup_vars['period1'];
                         $ipn['period3'] = $ipn_signup_vars['period3'];
                         $ipn['payer_email'] = $ipn_signup_vars['payer_email'];
                         $ipn['first_name'] = $ipn_signup_vars['first_name'];
                         $ipn['last_name'] = $ipn_signup_vars['last_name'];
                         $ipn['option_name1'] = $ipn_signup_vars['option_name1'];
                         $ipn['option_selection1'] = $ipn_signup_vars['option_selection1'];
                         $ipn['option_name2'] = $ipn_signup_vars['option_name2'];
                         $ipn['option_selection2'] = $ipn_signup_vars['option_selection2'];
                         $ipn['item_name'] = $ipn_signup_vars['item_name'];
                         $ipn['item_number'] = $ipn_signup_vars['item_number'];
                         $ipn['s2member_paypal_proxy'] = 'stripe';
                         $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));
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         $stripe['s2member_log'][] = 'Webhook/IPN event `' . $event->type . '` reformulated. Piping through s2Member\'s core gateway processor as `txn_type` (`' . $ipn['txn_type'] . '`).';
                         $stripe['s2member_log'][] = 'Please check core IPN logs for further processing details.';
                     }
                     break;
                     // Break switch handler.
             }
             if (empty($processing)) {
                 $stripe['s2member_log'][] = 'Ignoring this Webhook/IPN. The event does NOT require any action on the part of s2Member.';
             }
         } else {
             $stripe['s2member_log'][] = 'Unable to verify Webhook/IPN event ID. This is most likely related to an invalid Stripe configuration. Please check: s2Member → Stripe Options.';
             $stripe['s2member_log'][] = 'If you\'re absolutely SURE that your Stripe configuration is valid, you may want to run some tests on your server, just to be sure \\$_POST variables (and php://input) are populated; and that your server is able to connect to Stripe over an HTTPS connection.';
             $stripe['s2member_log'][] = 's2Member uses the Stripe SDK for remote connections; which relies upon the cURL extension for PHP. Please make sure that your installation of PHP has the cURL extension; and that it\'s configured together with OpenSSL for HTTPS communication.';
             $stripe['s2member_log'][] = var_export($_REQUEST, TRUE) . "\n" . var_export(json_decode(@file_get_contents('php://input')), TRUE);
         }
         $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() ? 'stripe-ipn-4-' . trim(preg_replace('/[^a-z0-9]/i', '-', !empty($_log4) ? $_log4 : ''), '-') . '.log' : 'stripe-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($stripe, 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 Stripe Webhook/IPN event processing.
  *
  * @package s2Member\Stripe
  * @since 140617
  *
  * @attaches-to ``add_action('init');``
  */
 public static function stripe_notify()
 {
     global $current_site, $current_blog;
     if (!empty($_GET['s2member_pro_stripe_notify']) && $GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_stripe_api_secret_key']) {
         $stripe = array();
         // Initialize array of Webhook/IPN event data and s2Member log details.
         @ignore_user_abort(TRUE);
         // Continue processing even if/when connection is broken.
         if (!class_exists('Stripe')) {
             require_once dirname(__FILE__) . '/stripe-sdk/lib/Stripe.php';
         }
         Stripe::setApiKey($GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_stripe_api_secret_key']);
         if (is_object($event = c_ws_plugin__s2member_pro_stripe_utilities::get_event()) && ($stripe['event'] = $event)) {
             switch ($event->type) {
                 case 'invoice.payment_succeeded':
                     // Subscription payments.
                     if (!empty($event->data->object) && ($stripe_invoice = $event->data->object) instanceof Stripe_Invoice && !empty($stripe_invoice->customer) && !empty($stripe_invoice->subscription) && ($stripe_invoice_total = number_format(c_ws_plugin__s2member_pro_stripe_utilities::cents_to_dollar_amount($stripe_invoice->total, $stripe_invoice->currency), 2, '.', '')) > 0 && is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($stripe_invoice->customer, $stripe_invoice->subscription)) && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_subscription->id))) {
                         $processing = TRUE;
                         $ipn['txn_type'] = 'subscr_payment';
                         $ipn['txn_id'] = $stripe_invoice->id;
                         $ipn['txn_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['custom'] = $ipn_signup_vars['custom'];
                         $ipn['mc_gross'] = $stripe_invoice_total;
                         $ipn['mc_currency'] = strtoupper($stripe_invoice->currency);
                         $ipn['tax'] = number_format(0, 2, '.', '');
                         $ipn['period1'] = $ipn_signup_vars['period1'];
                         $ipn['period3'] = $ipn_signup_vars['period3'];
                         $ipn['payer_email'] = $ipn_signup_vars['payer_email'];
                         $ipn['first_name'] = $ipn_signup_vars['first_name'];
                         $ipn['last_name'] = $ipn_signup_vars['last_name'];
                         $ipn['option_name1'] = $ipn_signup_vars['option_name1'];
                         $ipn['option_selection1'] = $ipn_signup_vars['option_selection1'];
                         $ipn['option_name2'] = $ipn_signup_vars['option_name2'];
                         $ipn['option_selection2'] = $ipn_signup_vars['option_selection2'];
                         $ipn['item_name'] = $ipn_signup_vars['item_name'];
                         $ipn['item_number'] = $ipn_signup_vars['item_number'];
                         $ipn['s2member_paypal_proxy'] = 'stripe';
                         $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));
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         if ($maybe_end_subscription = self::_maybe_end_subscription_after_payment($stripe_invoice->customer, $stripe_subscription)) {
                             $stripe['s2member_log'][] = $maybe_end_subscription;
                         }
                         $stripe['s2member_log'][] = 'Webhook/IPN event `' . $event->type . '` reformulated. Piping through s2Member\'s core gateway processor as `txn_type` (`' . $ipn['txn_type'] . '`).';
                         $stripe['s2member_log'][] = 'Please check core IPN logs for further processing details.';
                     }
                     break;
                     // Break switch handler.
                 // Break switch handler.
                 case 'invoice.payment_failed':
                     // Subscription payment failures.
                     if (!empty($event->data->object) && ($stripe_invoice = $event->data->object) instanceof Stripe_Invoice && !empty($stripe_invoice->customer) && !empty($stripe_invoice->subscription) && ($stripe_invoice_total = number_format(c_ws_plugin__s2member_pro_stripe_utilities::cents_to_dollar_amount($stripe_invoice->total, $stripe_invoice->currency), 2, '.', '')) > 0 && is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($stripe_invoice->customer, $stripe_invoice->subscription)) && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_subscription->id))) {
                         $processing = TRUE;
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         if ($maybe_end_subscription = self::_maybe_end_subscription_after_payment($stripe_invoice->customer, $stripe_subscription)) {
                             $stripe['s2member_log'][] = $maybe_end_subscription;
                         }
                         $stripe['s2member_log'][] = 'Ignoring `' . $event->type . '`. s2Member does NOT respond to individual payment failures; only to subscription cancellations.';
                         $stripe['s2member_log'][] = 'You may control the behavior(s) associated w/ subscription payment failures from your Stripe Dashboard please.';
                     }
                     break;
                     // Break switch handler.
                 // Break switch handler.
                 case 'customer.deleted':
                     // Customer deletions.
                     if (!empty($event->data->object) && ($stripe_customer = $event->data->object) instanceof Stripe_Customer && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_customer->id))) {
                         $processing = TRUE;
                         $ipn['txn_type'] = 'subscr_eot';
                         $ipn['subscr_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['custom'] = $ipn_signup_vars['custom'];
                         $ipn['period1'] = $ipn_signup_vars['period1'];
                         $ipn['period3'] = $ipn_signup_vars['period3'];
                         $ipn['payer_email'] = $ipn_signup_vars['payer_email'];
                         $ipn['first_name'] = $ipn_signup_vars['first_name'];
                         $ipn['last_name'] = $ipn_signup_vars['last_name'];
                         $ipn['option_name1'] = $ipn_signup_vars['option_name1'];
                         $ipn['option_selection1'] = $ipn_signup_vars['option_selection1'];
                         $ipn['option_name2'] = $ipn_signup_vars['option_name2'];
                         $ipn['option_selection2'] = $ipn_signup_vars['option_selection2'];
                         $ipn['item_name'] = $ipn_signup_vars['item_name'];
                         $ipn['item_number'] = $ipn_signup_vars['item_number'];
                         $ipn['s2member_paypal_proxy'] = 'stripe';
                         $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));
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         $stripe['s2member_log'][] = 'Webhook/IPN event `' . $event->type . '` reformulated. Piping through s2Member\'s core gateway processor as `txn_type` (`' . $ipn['txn_type'] . '`).';
                         $stripe['s2member_log'][] = 'Please check core IPN logs for further processing details.';
                     }
                     break;
                     // Break switch handler.
                 // Break switch handler.
                 case 'customer.subscription.deleted':
                     // Customer subscription deletion.
                     if (!empty($event->data->object) && ($stripe_subscription = $event->data->object) instanceof Stripe_Subscription && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_subscription->id))) {
                         $processing = TRUE;
                         $ipn['txn_type'] = 'subscr_eot';
                         $ipn['subscr_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['custom'] = $ipn_signup_vars['custom'];
                         $ipn['period1'] = $ipn_signup_vars['period1'];
                         $ipn['period3'] = $ipn_signup_vars['period3'];
                         $ipn['payer_email'] = $ipn_signup_vars['payer_email'];
                         $ipn['first_name'] = $ipn_signup_vars['first_name'];
                         $ipn['last_name'] = $ipn_signup_vars['last_name'];
                         $ipn['option_name1'] = $ipn_signup_vars['option_name1'];
                         $ipn['option_selection1'] = $ipn_signup_vars['option_selection1'];
                         $ipn['option_name2'] = $ipn_signup_vars['option_name2'];
                         $ipn['option_selection2'] = $ipn_signup_vars['option_selection2'];
                         $ipn['item_name'] = $ipn_signup_vars['item_name'];
                         $ipn['item_number'] = $ipn_signup_vars['item_number'];
                         $ipn['s2member_paypal_proxy'] = 'stripe';
                         $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));
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         $stripe['s2member_log'][] = 'Webhook/IPN event `' . $event->type . '` reformulated. Piping through s2Member\'s core gateway processor as `txn_type` (`' . $ipn['txn_type'] . '`).';
                         $stripe['s2member_log'][] = 'Please check core IPN logs for further processing details.';
                     }
                     break;
                     // Break switch handler.
                 // Break switch handler.
                 case 'charge.refunded':
                     // Customer refund (partial or full).
                     if (!empty($event->data->object) && ($stripe_charge = $event->data->object) instanceof Stripe_Charge && !empty($strip_charge->amount_refunded) && !empty($stripe_charge->customer) && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_charge->customer))) {
                         $processing = TRUE;
                         $ipn['payment_status'] = 'refunded';
                         $ipn['subscr_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['parent_txn_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['custom'] = $ipn_signup_vars['custom'];
                         $ipn['mc_fee'] = '-' . number_format('0.00', 2, '.', '');
                         $ipn['mc_gross'] = '-' . number_format(abs($strip_charge->amount), 2, '.', '');
                         $ipn['mc_currency'] = strtoupper($strip_charge->currency);
                         $ipn['tax'] = '-' . number_format('0.00', 2, '.', '');
                         $ipn['period1'] = $ipn_signup_vars['period1'];
                         $ipn['period3'] = $ipn_signup_vars['period3'];
                         $ipn['payer_email'] = $ipn_signup_vars['payer_email'];
                         $ipn['first_name'] = $ipn_signup_vars['first_name'];
                         $ipn['last_name'] = $ipn_signup_vars['last_name'];
                         $ipn['option_name1'] = $ipn_signup_vars['option_name1'];
                         $ipn['option_selection1'] = $ipn_signup_vars['option_selection1'];
                         $ipn['option_name2'] = $ipn_signup_vars['option_name2'];
                         $ipn['option_selection2'] = $ipn_signup_vars['option_selection2'];
                         $ipn['item_name'] = $ipn_signup_vars['item_name'];
                         $ipn['item_number'] = $ipn_signup_vars['item_number'];
                         $ipn['s2member_paypal_proxy'] = 'stripe';
                         $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));
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         $stripe['s2member_log'][] = 'Webhook/IPN event `' . $event->type . '` reformulated. Piping through s2Member\'s core gateway processor.';
                         $stripe['s2member_log'][] = 'Please check core IPN logs for further processing details.';
                     }
                     break;
                     // Break switch handler.
                 // Break switch handler.
                 case 'charge.dispute.created':
                     // Customer dispute (chargeback).
                     if (!empty($event->data->object->charge) && ($stripe_charge = c_ws_plugin__s2member_pro_stripe_utilities::get_charge($event->data->object->charge)) instanceof Stripe_Charge && !empty($stripe_charge->customer) && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_charge->customer))) {
                         $processing = TRUE;
                         $ipn['payment_status'] = 'reversed';
                         $ipn['subscr_cid'] = $ipn_signup_vars['subscr_cid'];
                         $ipn['subscr_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['parent_txn_id'] = $ipn_signup_vars['subscr_id'];
                         $ipn['custom'] = $ipn_signup_vars['custom'];
                         $ipn['mc_fee'] = '-' . number_format('0.00', 2, '.', '');
                         $ipn['mc_gross'] = '-' . number_format(abs($strip_charge->amount), 2, '.', '');
                         $ipn['mc_currency'] = strtoupper($strip_charge->currency);
                         $ipn['tax'] = '-' . number_format('0.00', 2, '.', '');
                         $ipn['period1'] = $ipn_signup_vars['period1'];
                         $ipn['period3'] = $ipn_signup_vars['period3'];
                         $ipn['payer_email'] = $ipn_signup_vars['payer_email'];
                         $ipn['first_name'] = $ipn_signup_vars['first_name'];
                         $ipn['last_name'] = $ipn_signup_vars['last_name'];
                         $ipn['option_name1'] = $ipn_signup_vars['option_name1'];
                         $ipn['option_selection1'] = $ipn_signup_vars['option_selection1'];
                         $ipn['option_name2'] = $ipn_signup_vars['option_name2'];
                         $ipn['option_selection2'] = $ipn_signup_vars['option_selection2'];
                         $ipn['item_name'] = $ipn_signup_vars['item_name'];
                         $ipn['item_number'] = $ipn_signup_vars['item_number'];
                         $ipn['s2member_paypal_proxy'] = 'stripe';
                         $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));
                         $stripe['s2member_log'][] = 'Stripe Webhook/IPN event type identified as: `' . $event->type . '` on: ' . date('D M j, Y g:i:s a T');
                         $stripe['s2member_log'][] = 'Webhook/IPN event `' . $event->type . '` reformulated. Piping through s2Member\'s core gateway processor.';
                         $stripe['s2member_log'][] = 'Please check core IPN logs for further processing details.';
                     }
                     break;
                     // Break switch handler.
             }
             if (empty($processing)) {
                 $stripe['s2member_log'][] = 'Ignoring this Webhook/IPN. The event does NOT require any action on the part of s2Member.';
             }
         } else {
             $stripe['s2member_log'][] = 'Unable to verify Webhook/IPN event ID. This is most likely related to an invalid Stripe configuration. Please check: s2Member → Stripe Options.';
             $stripe['s2member_log'][] = 'If you\'re absolutely SURE that your Stripe configuration is valid, you may want to run some tests on your server, just to be sure \\$_POST variables (and php://input) are populated; and that your server is able to connect to Stripe over an HTTPS connection.';
             $stripe['s2member_log'][] = 's2Member uses the Stripe SDK for remote connections; which relies upon the cURL extension for PHP. Please make sure that your installation of PHP has the cURL extension; and that it\'s configured together with OpenSSL for HTTPS communication.';
             $stripe['s2member_log'][] = var_export($_REQUEST, TRUE) . "\n" . var_export(json_decode(@file_get_contents('php://input')), TRUE);
         }
         c_ws_plugin__s2member_utils_logs::log_entry('stripe-ipn', $stripe);
         status_header(200);
         header('Content-Type: text/plain; charset=UTF-8');
         while (@ob_end_clean()) {
         }
         exit;
     }
 }