| 1 |
<?php |
| 2 |
// @codingStandardsIgnoreFile |
| 3 |
/** |
| 4 |
* General utilities. |
| 5 |
* |
| 6 |
* Copyright: © 2009-2011 |
| 7 |
* {@link http://websharks-inc.com/ WebSharks, Inc.} |
| 8 |
* (coded in the USA) |
| 9 |
* |
| 10 |
* Released under the terms of the GNU General Public License. |
| 11 |
* You should have received a copy of the GNU General Public License, |
| 12 |
* along with this software. In the main directory, see: /licensing/ |
| 13 |
* If not, see: {@link http://www.gnu.org/licenses/}. |
| 14 |
* |
| 15 |
* @package s2Member\Utilities |
| 16 |
* @since 3.5 |
| 17 |
*/ |
| 18 |
if(!defined('WPINC')) // MUST have WordPress. |
| 19 |
exit ('Do not access this file directly.'); |
| 20 |
|
| 21 |
if(!class_exists('c_ws_plugin__s2member_utilities')) |
| 22 |
{ |
| 23 |
/** |
| 24 |
* General utilities. |
| 25 |
* |
| 26 |
* @package s2Member\Utilities |
| 27 |
* @since 3.5 |
| 28 |
*/ |
| 29 |
class c_ws_plugin__s2member_utilities |
| 30 |
{ |
| 31 |
/** |
| 32 |
* Evaluates PHP code, and 'returns' output. |
| 33 |
* |
| 34 |
* @package s2Member\Utilities |
| 35 |
* @since 3.5 |
| 36 |
* |
| 37 |
* @param string $code A string of data, possibly with embedded PHP code. |
| 38 |
* @param array $vars Variables to put into the scope of `eval()`. |
| 39 |
* |
| 40 |
* @return string Output after PHP evaluation. |
| 41 |
*/ |
| 42 |
public static function evl($code = '', $vars = array()) |
| 43 |
{ |
| 44 |
if(is_array($vars) && !empty($vars)) |
| 45 |
extract($vars, EXTR_PREFIX_SAME, '_extract_'); |
| 46 |
|
| 47 |
ob_start(); // Output buffer. |
| 48 |
|
| 49 |
eval ('?>'.trim($code)); |
| 50 |
|
| 51 |
return ob_get_clean(); |
| 52 |
} |
| 53 |
|
| 54 |
/** |
| 55 |
* Buffers (gets) function output. |
| 56 |
* |
| 57 |
* A variable length of additional arguments are possible. |
| 58 |
* Additional parameters get passed into the ``$function``. |
| 59 |
* |
| 60 |
* @package s2Member\Utilities |
| 61 |
* @since 3.5 |
| 62 |
* |
| 63 |
* @param string $function Name of a function to call upon. |
| 64 |
* |
| 65 |
* @return string Output after call to function. |
| 66 |
* Any output is buffered and returned. |
| 67 |
*/ |
| 68 |
public static function get($function = '') |
| 69 |
{ |
| 70 |
$args = func_get_args(); |
| 71 |
$function = array_shift($args); |
| 72 |
|
| 73 |
if(is_string($function) && $function) |
| 74 |
{ |
| 75 |
ob_start(); // Open output buffer. |
| 76 |
|
| 77 |
if(is_array($args) && !empty($args)) |
| 78 |
$return = call_user_func_array($function, $args); |
| 79 |
|
| 80 |
else // There are no additional arguments to pass. |
| 81 |
$return = call_user_func($function); |
| 82 |
|
| 83 |
$echo = ob_get_clean(); // Close buffer. |
| 84 |
|
| 85 |
return !strlen($echo) && strlen($return) ? $return : $echo; |
| 86 |
} |
| 87 |
return NULL; |
| 88 |
} |
| 89 |
|
| 90 |
/** |
| 91 |
* Builds a version checksum for this installation. |
| 92 |
* |
| 93 |
* @package s2Member\Utilities |
| 94 |
* @since 3.5 |
| 95 |
* |
| 96 |
* @return string String with `[version]-[pro version]-[consolidated checksum]`. |
| 97 |
*/ |
| 98 |
public static function ver_checksum() |
| 99 |
{ |
| 100 |
$checksum = WS_PLUGIN__S2MEMBER_VERSION; // Software version string. |
| 101 |
$checksum .= (c_ws_plugin__s2member_utils_conds::pro_is_installed()) ? '-'.WS_PLUGIN__S2MEMBER_PRO_VERSION : ''; // Pro version string? |
| 102 |
$checksum .= '-'.abs(crc32($GLOBALS['WS_PLUGIN__']['s2member']['c']['checksum'].$GLOBALS['WS_PLUGIN__']['s2member']['o']['options_checksum'].$GLOBALS['WS_PLUGIN__']['s2member']['o']['options_version'])); |
| 103 |
|
| 104 |
return $checksum; // (i.e., version-pro version-checksum) |
| 105 |
} |
| 106 |
|
| 107 |
/** |
| 108 |
* String with current time details. |
| 109 |
* |
| 110 |
* @package s2Member\Utilities |
| 111 |
* @since 130210 |
| 112 |
* |
| 113 |
* @return string String with time representation (in UTC time). |
| 114 |
*/ |
| 115 |
public static function time_details() |
| 116 |
{ |
| 117 |
$time = time(); // The time at this very moment. |
| 118 |
$details = date('D M jS, Y', $time).' @ precisely '.date('g:i a e', $time); |
| 119 |
|
| 120 |
return $details; // Return all details. |
| 121 |
} |
| 122 |
|
| 123 |
/** |
| 124 |
* String with all version details *(for PHP, WordPress, s2Member, and Pro)*. |
| 125 |
* |
| 126 |
* @package s2Member\Utilities |
| 127 |
* @since 3.5 |
| 128 |
* |
| 129 |
* @return string String with `PHP vX.XX :: WordPress vX.XX :: s2Member vX.XX :: s2Member Pro vX.XX`. |
| 130 |
*/ |
| 131 |
public static function ver_details() |
| 132 |
{ |
| 133 |
$details = 'PHP v'.PHP_VERSION.' :: WordPress v'.get_bloginfo('version').' :: s2Member v'.WS_PLUGIN__S2MEMBER_VERSION; |
| 134 |
$details .= (c_ws_plugin__s2member_utils_conds::pro_is_installed()) ? ' :: s2Member Pro v'.WS_PLUGIN__S2MEMBER_PRO_VERSION : ''; |
| 135 |
|
| 136 |
return $details; // Return all details. |
| 137 |
} |
| 138 |
|
| 139 |
/** |
| 140 |
* Generates s2Member Security Badge. |
| 141 |
* |
| 142 |
* @package s2Member\Utilities |
| 143 |
* @since 3.5 |
| 144 |
* |
| 145 |
* @param string $v A variation number to display. Defaults to `1`. |
| 146 |
* @param bool $no_cache Defaults to false. If true, the HTML markup will contain query string params that prevent caching. |
| 147 |
* @param bool $display_on_failure . Defaults to false. True if we need to display the 'NOT yet verified' version inside admin panels. |
| 148 |
* |
| 149 |
* @return string HTML markup for display of s2Member Security Badge. |
| 150 |
*/ |
| 151 |
public static function s_badge_gen($v = '1', $no_cache = FALSE, $display_on_failure = FALSE) |
| 152 |
{ |
| 153 |
if($v && file_exists(($template = dirname(dirname(__FILE__)).'/templates/badges/s-badge.php'))) |
| 154 |
{ |
| 155 |
switch((int)$v) // Width/height based on variation. |
| 156 |
{ |
| 157 |
case 1: // Variation number 1. |
| 158 |
|
| 159 |
$width_height_attrs = 'width="200" height="55"'; |
| 160 |
$width_height_styles = 'width:200px; height:55px;'; |
| 161 |
|
| 162 |
break; // Break switch loop. |
| 163 |
|
| 164 |
case 2: // Variation number 2. |
| 165 |
|
| 166 |
$width_height_attrs = 'width="180" height="58"'; |
| 167 |
$width_height_styles = 'width:180px; height:58px;'; |
| 168 |
|
| 169 |
break; // Break switch loop. |
| 170 |
|
| 171 |
case 3: // Variation number 3. |
| 172 |
|
| 173 |
$width_height_attrs = 'width="80" height="15"'; |
| 174 |
$width_height_styles = 'width:80px; height:15px;'; |
| 175 |
|
| 176 |
break; // Break switch loop. |
| 177 |
|
| 178 |
default: // Default case handler. |
| 179 |
|
| 180 |
$width_height_attrs = $width_height_styles = ''; |
| 181 |
|
| 182 |
break; // Break switch loop. |
| 183 |
} |
| 184 |
$badge = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($template))); |
| 185 |
|
| 186 |
$badge = preg_replace('/%%v%%/i', (string)(int)$v, $badge); |
| 187 |
$badge = preg_replace('/%%site_url%%/i', urlencode(home_url()), $badge); |
| 188 |
$badge = preg_replace('/%%no_cache%%/i', $no_cache ? '&no_cache='.urlencode(mt_rand()) : '', $badge); |
| 189 |
$badge = preg_replace('/%%display_on_failure%%/i', $display_on_failure ? '&display_on_failure=1' : '', $badge); |
| 190 |
$badge = preg_replace(array('/%%width_height_attrs%%/i', '/%%width_height_styles%%/i'), array($width_height_attrs, $width_height_styles), $badge); |
| 191 |
} |
| 192 |
return !empty($badge) ? $badge : ''; // Return Security Badge. |
| 193 |
} |
| 194 |
|
| 195 |
/** |
| 196 |
* Acquires information about memory usage. |
| 197 |
* |
| 198 |
* @package s2Member\Utilities |
| 199 |
* @since 110815 |
| 200 |
* |
| 201 |
* @return string String with `Memory x MB :: Real Memory x MB :: Peak Memory x MB :: Real Peak Memory x MB`. |
| 202 |
*/ |
| 203 |
public static function mem_details() |
| 204 |
{ |
| 205 |
$memory = number_format(memory_get_usage() / 1048576, 2, '.', ''); |
| 206 |
$real_memory = number_format(memory_get_usage(TRUE) / 1048576, 2, '.', ''); |
| 207 |
$peak_memory = number_format(memory_get_peak_usage() / 1048576, 2, '.', ''); |
| 208 |
$real_peak_memory = number_format(memory_get_peak_usage(TRUE) / 1048576, 2, '.', ''); |
| 209 |
|
| 210 |
$details = 'Memory '.$memory.' MB :: Real Memory '.$real_memory.' MB :: Peak Memory '.$peak_memory.' MB :: Real Peak Memory '.$real_peak_memory.' MB'; |
| 211 |
|
| 212 |
return $details; // Return all details. |
| 213 |
} |
| 214 |
|
| 215 |
/** |
| 216 |
* Acquires s2Member options for the Main Site of a Multisite Network. |
| 217 |
* |
| 218 |
* @package s2Member\Utilities |
| 219 |
* @since 110912 |
| 220 |
* |
| 221 |
* @return array Array of s2Member options for the Main Site. |
| 222 |
*/ |
| 223 |
public static function mms_options() |
| 224 |
{ |
| 225 |
return (is_multisite()) ? (array)get_site_option('ws_plugin__s2member_options') : array(); |
| 226 |
} |
| 227 |
|
| 228 |
/** |
| 229 |
* Builds an array of backtrace callers. |
| 230 |
* |
| 231 |
* @package s2Member\Utilities |
| 232 |
* @since 110912 |
| 233 |
* |
| 234 |
* @param array $debug_backtrace Optional. Defaults to ``debug_backtrace()``. |
| 235 |
* |
| 236 |
* @return array Array of backtrace callers (lowercase). |
| 237 |
*/ |
| 238 |
public static function callers($debug_backtrace = NULL) |
| 239 |
{ |
| 240 |
$callers = array(); // Initialize array. |
| 241 |
foreach(($debug_backtrace = is_array($debug_backtrace) ? $debug_backtrace : debug_backtrace()) as $caller) |
| 242 |
if(isset($caller['class'], $caller['function']) || (!isset($caller['class']) && isset($caller['function']))) |
| 243 |
$callers[] = isset($caller['class']) ? $caller['class'].'::'.$caller['function'] : $caller['function']; |
| 244 |
|
| 245 |
return array_map('strtolower', array_unique($callers)); |
| 246 |
} |
| 247 |
|
| 248 |
/** |
| 249 |
* Sends an email using WordPress' `wp_mail()`, supporting HTML formatting and auto From header. |
| 250 |
* |
| 251 |
* Automatically sets Content-Type to `text/html` if HTML markers are found. |
| 252 |
* If no `From:` header is provided, adds one using s2Member options via `email_config()` filters. |
| 253 |
* |
| 254 |
* @since 250605 |
| 255 |
* |
| 256 |
* @param string|string[] $to Recipient email address(es). |
| 257 |
* @param string $subject Email subject line. |
| 258 |
* @param string $message Email body. May contain HTML. |
| 259 |
* @param string|string[] $headers Optional. Additional headers. |
| 260 |
* @param string|string[] $attachments Optional. File paths to attach. |
| 261 |
* |
| 262 |
* @return bool True if the email was sent successfully, false otherwise. |
| 263 |
*/ |
| 264 |
public static function mail($to, $subject, $message, $headers = '', $attachments = []) |
| 265 |
{ |
| 266 |
// If From: not already in headers, add it using configured options. |
| 267 |
if (stripos($headers, 'From:') === false) { |
| 268 |
c_ws_plugin__s2member_email_configs::email_config(); // Setup From filters |
| 269 |
$from_email = isset($GLOBALS['WS_PLUGIN__']['s2member']['o']['reg_email_from_email']) ? $GLOBALS['WS_PLUGIN__']['s2member']['o']['reg_email_from_email'] : ''; |
| 270 |
$from_name = isset($GLOBALS['WS_PLUGIN__']['s2member']['o']['reg_email_from_name']) ? str_replace('"', "'", $GLOBALS['WS_PLUGIN__']['s2member']['o']['reg_email_from_name']) : ''; |
| 271 |
$headers .= (empty($headers) ? '' : "\r\n") . 'From: "' . $from_name . '" <' . $from_email . '>'; |
| 272 |
c_ws_plugin__s2member_email_configs::email_config_release(); // Remove filters. |
| 273 |
} |
| 274 |
|
| 275 |
// Check HTML tags. |
| 276 |
$is_html = false; |
| 277 |
foreach (['</', '/>', '<i', '<b', '<h'] as $tag) { |
| 278 |
if (strpos($message, $tag) !== false) { |
| 279 |
$is_html = true; |
| 280 |
break; |
| 281 |
} |
| 282 |
} |
| 283 |
if ($is_html && strpos($message, '<p') === false && strpos($message, '<br') === false) { |
| 284 |
$message = wpautop($message); |
| 285 |
} |
| 286 |
|
| 287 |
// Add correct content type. |
| 288 |
$headers .= (empty($headers) ? '' : "\r\n"); |
| 289 |
$headers .= 'Content-Type: ' . ($is_html ? 'text/html' : 'text/plain') . '; charset=UTF-8'; |
| 290 |
|
| 291 |
return wp_mail($to, $subject, $message, $headers, $attachments); |
| 292 |
} |
| 293 |
|
| 294 |
/** |
| 295 |
* Renders an s2Member email template editor (TinyMCE if HTML emails are enabled). |
| 296 |
* Falls back to a plain <textarea> if HTML emails are disabled. |
| 297 |
* Displays a soft warning if the database charset may strip emojis. |
| 298 |
* |
| 299 |
* @since 250610 |
| 300 |
* |
| 301 |
* @param string $option_key The s2Member option key (w/o prefix). |
| 302 |
* @param string $editor_id Optional. The DOM ID for the editor. Defaults to derived from option_key. |
| 303 |
* @param array $editor_args Optional. Extra arguments for `wp_editor()`. |
| 304 |
*/ |
| 305 |
public static function editor($option_key, $editor_id = '', array $editor_args = []) |
| 306 |
{ |
| 307 |
$value = isset($GLOBALS['WS_PLUGIN__']['s2member']['o'][$option_key]) ? $GLOBALS['WS_PLUGIN__']['s2member']['o'][$option_key] : ''; |
| 308 |
$editor_id = $editor_id ? $editor_id : strtr('ws_plugin__s2member_' . $option_key, ['_' => '-']); |
| 309 |
|
| 310 |
// If HTML emails are enabled, use wp_editor() |
| 311 |
$html_enabled = !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['html_emails_enabled']); |
| 312 |
if ($html_enabled) { |
| 313 |
$args = wp_parse_args($editor_args, [ |
| 314 |
'textarea_name' => 'ws_plugin__s2member_' . $option_key, |
| 315 |
'textarea_rows' => 20, |
| 316 |
'editor_height' => null, |
| 317 |
'media_buttons' => false, |
| 318 |
'teeny' => false, |
| 319 |
'quicktags' => true, |
| 320 |
'tinymce' => [ |
| 321 |
'height' => 400, |
| 322 |
'resize' => true, |
| 323 |
'wp_autoresize_on' => false, |
| 324 |
'toolbar1' => 'formatselect | bold italic underline strikethrough | bullist numlist blockquote | alignleft aligncenter alignright | link unlink | undo redo | removeformat', |
| 325 |
'toolbar2' => '', |
| 326 |
], |
| 327 |
]); |
| 328 |
wp_editor($value, $editor_id, $args); |
| 329 |
} else { |
| 330 |
echo '<textarea name="ws_plugin__s2member_' . esc_attr($option_key) . '" id="' . esc_attr($editor_id) . '" rows="20">' |
| 331 |
. format_to_edit($value) . '</textarea><br />' . "\n"; |
| 332 |
} |
| 333 |
|
| 334 |
// Check charset and warn about emojis. |
| 335 |
global $wpdb; |
| 336 |
$collation = $wpdb->get_var( |
| 337 |
$wpdb->prepare( |
| 338 |
"SELECT COLLATION_NAME |
| 339 |
FROM information_schema.COLUMNS |
| 340 |
WHERE TABLE_SCHEMA = %s |
| 341 |
AND TABLE_NAME = %s |
| 342 |
AND COLUMN_NAME = 'option_value'", |
| 343 |
$wpdb->dbname, |
| 344 |
$wpdb->options |
| 345 |
) |
| 346 |
); |
| 347 |
$charset = $collation ? strtolower(preg_replace('/_.+$/', '', $collation)) : ''; |
| 348 |
if ($charset && $charset !== 'utf8mb4') { |
| 349 |
echo '<div class="ws-menu-page-hilite" style="margin-bottom:.2em;">'; |
| 350 |
echo '⚠️ <strong>Note:</strong> Your database uses the <code>' . esc_html($charset) . '</code> charset for WordPress option values. Changes to your email will be lost if you use emojis, as they require the <code>utf8mb4</code> charset.'; |
| 351 |
echo '</div>'; |
| 352 |
} |
| 353 |
} |
| 354 |
|
| 355 |
/** |
| 356 |
* Cancels a subscription using a gateway-aware dispatch routine. |
| 357 |
* |
| 358 |
* This is designed for replacement/modification flows where the old subscription must be |
| 359 |
* canceled after a new checkout begins. Callers should pass the previously captured |
| 360 |
* subscription details from before proxy/IPN processing updates the user's current profile. |
| 361 |
* |
| 362 |
* For PayPal-family subscriptions, this uses captured signup/proxy vars first when available |
| 363 |
* as a product hint, and then falls back to trying other configured cancellation routines |
| 364 |
* that are still plausible for the captured subscription context. //260407 |
| 365 |
* |
| 366 |
* Gateway/product handlers may no longer be configured or loaded by the current installation. |
| 367 |
* In those cases this routine fails safely and returns `FALSE` instead of calling unavailable code. |
| 368 |
* |
| 369 |
* @package s2Member\Utilities |
| 370 |
* @since 260407 |
| 371 |
* |
| 372 |
* @param string|bool $subscr_gateway Previously captured `s2member_subscr_gateway`. |
| 373 |
* @param string|bool $subscr_id Previously captured `s2member_subscr_id`. |
| 374 |
* @param string|bool $subscr_baid Previously captured `s2member_subscr_baid`. |
| 375 |
* @param string|bool $subscr_cid Previously captured `s2member_subscr_cid`. |
| 376 |
* @param array $ipn_signup_vars Previously captured signup/proxy vars for product-specific routing. |
| 377 |
* @param bool $immediate Optional. If false, cancel at period end where supported. |
| 378 |
* @param string $reason Optional human-readable cancellation reason for APIs that accept one. |
| 379 |
* |
| 380 |
* @return bool True if a cancellation request was accepted; else false. |
| 381 |
*/ |
| 382 |
public static function cancel_gateway_subscription($subscr_gateway = FALSE, $subscr_id = FALSE, $subscr_baid = FALSE, $subscr_cid = FALSE, $ipn_signup_vars = array(), $immediate = TRUE, $reason = '') |
| 383 |
{ |
| 384 |
$subscr_gateway = strtolower((string)$subscr_gateway); |
| 385 |
$subscr_id = (string)$subscr_id; |
| 386 |
$subscr_baid = (string)$subscr_baid; |
| 387 |
$subscr_cid = (string)$subscr_cid; |
| 388 |
$ipn_signup_vars = (is_array($ipn_signup_vars)) ? $ipn_signup_vars : array(); |
| 389 |
|
| 390 |
if(!$subscr_gateway || !$subscr_id) |
| 391 |
return FALSE; |
| 392 |
|
| 393 |
switch($subscr_gateway) |
| 394 |
{ |
| 395 |
case 'stripe': |
| 396 |
if(!$subscr_cid || !class_exists('c_ws_plugin__s2member_pro_stripe_utilities')) |
| 397 |
return FALSE; |
| 398 |
|
| 399 |
//260407 Stripe replacement flows need the guard around old-subscription cancellation. |
| 400 |
c_ws_plugin__s2member_pro_stripe_utilities::set_replacement_cancellation_guard($subscr_id); |
| 401 |
|
| 402 |
if(!is_object(c_ws_plugin__s2member_pro_stripe_utilities::cancel_customer_subscription($subscr_cid, $subscr_id, !$immediate))) |
| 403 |
{ |
| 404 |
c_ws_plugin__s2member_pro_stripe_utilities::clear_replacement_cancellation_guard($subscr_id); |
| 405 |
return FALSE; |
| 406 |
} |
| 407 |
return TRUE; |
| 408 |
|
| 409 |
case 'authnet': |
| 410 |
if(!class_exists('c_ws_plugin__s2member_pro_authnet_utilities')) |
| 411 |
return FALSE; |
| 412 |
|
| 413 |
return (($authnet = c_ws_plugin__s2member_pro_authnet_utilities::authnet_arb_response(array('x_method' => 'cancel', 'x_subscription_id' => $subscr_id))) && empty($authnet['__error'])) ? TRUE : FALSE; |
| 414 |
|
| 415 |
case 'paypal': |
| 416 |
$paypal_proxy_use = (!empty($ipn_signup_vars['s2member_paypal_proxy_use'])) ? (string)$ipn_signup_vars['s2member_paypal_proxy_use'] : ''; |
| 417 |
$paypal_invoice = (!empty($ipn_signup_vars['invoice'])) ? (string)$ipn_signup_vars['invoice'] : ''; |
| 418 |
$ppco_hint = ($paypal_proxy_use === 'paypal_checkout' || strpos($paypal_invoice, 's2mpf-') === 0); |
| 419 |
$can_try_ppco = FALSE; |
| 420 |
$can_try_standard = FALSE; |
| 421 |
$can_try_payflow = FALSE; |
| 422 |
|
| 423 |
$paypal_checkout_creds = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_creds(); |
| 424 |
$can_try_ppco = (!empty($paypal_checkout_creds['client_id']) && !empty($paypal_checkout_creds['secret'])); |
| 425 |
|
| 426 |
$can_try_standard = (!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_username']) |
| 427 |
&& !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_password']) |
| 428 |
&& !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_signature'])); |
| 429 |
|
| 430 |
$can_try_payflow = (!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_payflow_api_username']) |
| 431 |
&& !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_payflow_api_partner']) |
| 432 |
&& !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_payflow_api_vendor']) |
| 433 |
&& !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_payflow_api_password']) |
| 434 |
&& class_exists('c_ws_plugin__s2member_pro_paypal_utilities')); |
| 435 |
|
| 436 |
//260819.0543 Use positive product provenance where available; I-* is ambiguous, while Payflow profile IDs use RP/RT prefixes. |
| 437 |
$payflow_hint = (bool)preg_match('/^R[PT]/i', $subscr_id); |
| 438 |
if($ppco_hint) |
| 439 |
$paypal_routes = array('ppco', 'standard', 'payflow'); |
| 440 |
else if($payflow_hint) |
| 441 |
$paypal_routes = array('payflow', 'standard', 'ppco'); |
| 442 |
else |
| 443 |
$paypal_routes = array('standard', 'ppco', 'payflow'); |
| 444 |
|
| 445 |
$reason = trim((string)$reason); |
| 446 |
if(!$reason) |
| 447 |
$reason = 'Cancelled by replacement checkout.'; |
| 448 |
|
| 449 |
foreach($paypal_routes as $_paypal_route) |
| 450 |
{ |
| 451 |
switch($_paypal_route) |
| 452 |
{ |
| 453 |
case 'ppco': |
| 454 |
if(!$can_try_ppco) |
| 455 |
break; |
| 456 |
|
| 457 |
if(($paypal_checkout = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_subscription_cancel($subscr_id, $reason)) |
| 458 |
&& !empty($paypal_checkout['code']) && ($paypal_checkout['code'] === 204 || ($paypal_checkout['code'] >= 200 && $paypal_checkout['code'] <= 299))) |
| 459 |
return TRUE; |
| 460 |
break; |
| 461 |
|
| 462 |
case 'standard': |
| 463 |
if(!$can_try_standard) |
| 464 |
break; |
| 465 |
|
| 466 |
if(($paypal_standard = c_ws_plugin__s2member_paypal_utilities::paypal_standard_subscription_cancel($subscr_id)) |
| 467 |
&& empty($paypal_standard['__error'])) |
| 468 |
return TRUE; |
| 469 |
break; |
| 470 |
|
| 471 |
case 'payflow': |
| 472 |
if(!$can_try_payflow) |
| 473 |
break; |
| 474 |
|
| 475 |
if(c_ws_plugin__s2member_pro_paypal_utilities::payflow_cancel_profile($subscr_id, $subscr_baid)) |
| 476 |
return TRUE; |
| 477 |
break; |
| 478 |
} |
| 479 |
} |
| 480 |
} |
| 481 |
return FALSE; |
| 482 |
} |
| 483 |
} |
| 484 |
} |
| 485 |
|