PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 260805
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v260805
260917 260913 260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 120213 All 189 releases
s2member / src / includes / classes / paypal-notify-in.inc.php

paypal-notify-in.inc.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions 260805, at src/includes/classes/paypal-notify-in.inc.php

253 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * s2Member's PayPal IPN handler (inner processing routines).
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\PayPal
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_paypal_notify_in'))
22 {
23 /**
24 * s2Member's PayPal IPN handler (inner processing routines).
25 *
26 * @package s2Member\PayPal
27 * @since 3.5
28 */
29 class c_ws_plugin__s2member_paypal_notify_in
30 {
31 /**
32 * Handles PayPal IPN processing.
33 *
34 * These same routines also handle s2Member Pro/PayPal Pro operations;
35 * giving you the ability *(as needed)* to Hook into these routines using
36 * WordPress Hooks/Filters; as seen in the source code below.
37 *
38 * Please do NOT modify the source code directly.
39 * Instead, use WordPress Hooks/Filters.
40 *
41 * For example, if you'd like to add your own custom conditionals, use:
42 * ``add_filter ('ws_plugin__s2member_during_paypal_notify_conditionals', 'your_function');``
43 *
44 * @package s2Member\PayPal
45 * @since 3.5
46 *
47 * @attaches-to ``add_action('init');``
48 */
49 public static function paypal_notify()
50 {
51 global $current_site, $current_blog;
52
53 do_action('ws_plugin__s2member_before_paypal_notify', get_defined_vars());
54
55 if(!empty($_GET['s2member_paypal_notify']) && ($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_business'] || !empty($_REQUEST['s2member_paypal_proxy'])))
56 {
57 @ignore_user_abort(TRUE); // Important. Continue processing even if/when the connection is broken by the sending party.
58
59 include_once ABSPATH.'wp-admin/includes/admin.php'; // Get administrative functions. Needed for `wp_delete_user()`.
60
61 $email_configs_were_on = c_ws_plugin__s2member_email_configs::email_config_status(); // Filters on?
62 c_ws_plugin__s2member_email_configs::email_config_release(); // Release s2Member Filters.
63
64 $paypal = array(); // Initialize PayPal array; we also reference this with a variable for a possible proxy handler.
65 if(!empty($_REQUEST['s2member_paypal_proxy']) && in_array($_REQUEST['s2member_paypal_proxy'], array('alipay', 'stripe', 'authnet', 'clickbank', 'ccbill', 'google'), TRUE))
66 ${esc_html(trim(stripslashes($_REQUEST['s2member_paypal_proxy'])))} = & $paypal; // Internal alias by reference.
67
68 if(is_array($paypal = c_ws_plugin__s2member_paypal_utilities::paypal_postvars()) && ($_paypal = $paypal) && ($_paypal_s = serialize($_paypal)))
69 {
70 $paypal['s2member_log'][] = 'IPN received on: '.date('D M j, Y g:i:s a T');
71 $paypal['s2member_log'][] = 's2Member POST vars verified '.((!empty($paypal['proxy_verified'])) ? 'with a Proxy Key' : 'through a POST back to PayPal.');
72
73 $payment_status_issues = '/^(failed|denied|expired|refunded|partially_refunded|reversed|reversal|canceled_reversal|voided)$/i';
74
75 $paypal['subscr_gateway'] = (!empty($_REQUEST['s2member_paypal_proxy'])) ? esc_html(trim(stripslashes($_REQUEST['s2member_paypal_proxy']))) : 'paypal';
76
77 $coupon = (!empty($_REQUEST['s2member_paypal_proxy_coupon']) && is_array($_REQUEST['s2member_paypal_proxy_coupon'])) ? stripslashes_deep($_REQUEST['s2member_paypal_proxy_coupon']) : array();
78 $coupon = (isset($coupon['full_coupon_code'], $coupon['coupon_code'], $coupon['affiliate_id']) && is_string($coupon['full_coupon_code']) && is_string($coupon['coupon_code']) && is_string($coupon['affiliate_id'])) ? $coupon : array('full_coupon_code' => '', 'coupon_code' => '', 'affiliate_id' => '');
79
80 if(!empty($paypal['txn_type']) && $paypal['txn_type'] === 'merch_pmt')
81 // This is mostly irrelevant, but it helps to keep the logs cleaner.
82 sleep(15); // Wait for Pro-Form procesing to complete.
83
84 if(empty($paypal['custom']) && !empty($paypal['recurring_payment_id'])) // Recurring Profile ID.
85 $paypal['custom'] = c_ws_plugin__s2member_utils_users::get_user_custom_with($paypal['recurring_payment_id']);
86
87 else if(empty($paypal['custom']) && !empty($paypal['mp_id'])) // Billing Agreement ID.
88 $paypal['custom'] = c_ws_plugin__s2member_utils_users::get_user_custom_with($paypal['mp_id']);
89
90 //250522 At least set it to an empty string.
91 else if(empty($paypal['custom']))
92 $paypal['custom'] = '';
93
94 //250606 Added option to skip domain validation.
95 if ($GLOBALS['WS_PLUGIN__']['s2member']['o']['skip_ipn_domain_validation']
96 || (!empty($paypal['custom']) && preg_match('/^'.preg_quote(preg_replace('/\:([0-9]+)$/', '', $_SERVER['HTTP_HOST']), '/').'/i', $paypal['custom'])))
97 {
98 if ($GLOBALS['WS_PLUGIN__']['s2member']['o']['skip_ipn_domain_validation'])
99 $paypal['s2member_log'][] = 's2Member originating domain validation was skipped.';
100 else
101 $paypal['s2member_log'][] = 's2Member originating domain (`$_SERVER["HTTP_HOST"]`) validated.';
102
103 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
104 if(!apply_filters('ws_plugin__s2member_during_paypal_notify_conditionals', FALSE, get_defined_vars()))
105 {
106 unset($__refs, $__v); // From the filter above.
107
108 if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_virtual_terminal::cp(get_defined_vars())))
109 $paypal = $_paypal_cp;
110
111 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_express_checkout::cp(get_defined_vars())))
112 $paypal = $_paypal_cp;
113
114 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_cart::cp(get_defined_vars())))
115 $paypal = $_paypal_cp;
116
117 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_send_money::cp(get_defined_vars())))
118 $paypal = $_paypal_cp;
119
120 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_web_accept_sp::cp(get_defined_vars())))
121 $paypal = $_paypal_cp;
122
123 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_wa_ccaps_wo_level::cp(get_defined_vars())))
124 $paypal = $_paypal_cp;
125
126 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_subscr_or_wa_w_level::cp(get_defined_vars())))
127 $paypal = $_paypal_cp;
128
129 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_rec_profile_creation_w_level::cp(get_defined_vars())))
130 $paypal = $_paypal_cp;
131
132 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_subscr_modify_w_level::cp(get_defined_vars())))
133 $paypal = $_paypal_cp;
134
135 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_w_level::cp(get_defined_vars())))
136 $paypal = $_paypal_cp;
137
138 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_failed_w_level::cp(get_defined_vars())))
139 $paypal = $_paypal_cp;
140
141 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_cancellation_w_level::cp(get_defined_vars())))
142 $paypal = $_paypal_cp;
143
144 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_eots_w_level::cp(get_defined_vars())))
145 $paypal = $_paypal_cp;
146
147 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_sp_refund_reversal::cp(get_defined_vars())))
148 $paypal = $_paypal_cp;
149
150 else if(($_paypal_cp = c_ws_plugin__s2member_paypal_notify_in_billing_agreement_signup::cp(get_defined_vars())))
151 $paypal = $_paypal_cp;
152
153 else // Ignoring this IPN request. The txn_type/status does NOT require any action.
154 $paypal['s2member_log'][] = 'Ignoring this IPN request. The `txn_type/status` does NOT require any action on the part of s2Member.';
155 }
156 else unset($__refs, $__v); // Else a custom conditional has been applied by Filters.
157 }
158 else if(!empty($paypal['txn_type']) && preg_match('/^recurring_payment_profile_cancel$/i', $paypal['txn_type']))
159 {
160 $paypal['s2member_log'][] = 'Transaction type (`recurring_payment_profile_cancel`), but there is no match to an existing account; so verification of `$_SERVER["HTTP_HOST"]` was not possible.';
161 $paypal['s2member_log'][] = 'It\'s likely this account was just upgraded/downgraded by s2Member Pro; so the Subscr. ID has probably been updated on-site; nothing to worry about here.';
162 }
163 else if(!empty($paypal['txn_type']) && preg_match('/^recurring_/i', $paypal['txn_type'])) // Otherwise, is this a ^recurring_ txn_type?
164 $paypal['s2member_log'][] = 'Transaction type (`^recurring_?`), but there is no match to an existing account; so verification of `$_SERVER["HTTP_HOST"]` was not possible.';
165
166 else // Else, use the default ``$_SERVER['HTTP_HOST']`` error.
167 $paypal['s2member_log'][] = 'Unable to verify `$_SERVER["HTTP_HOST"]`. Please check the `custom` value in your Button Code. It MUST start with your domain name.';
168 }
169 else // Extensive log reporting here. This is an area where many site owners find trouble. Depending on server configuration; remote HTTPS connections may fail.
170 {
171 if (!empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_SERVER['HTTP_USER_AGENT'])) {
172 if (preg_match('/(msie|trident|gecko|webkit|presto|konqueror|playstation)[\/ ]([0-9\.]+)/i', $_SERVER['HTTP_USER_AGENT'])) {
173 $paypal['s2member_indicator'] = 'This PayPal IPN Handler by s2Member® is active & listening.';
174 }
175 }
176 $paypal['s2member_log'][] = 'Unable to verify $_POST vars. This is most likely related to an invalid configuration of s2Member, or a problem with server compatibility.';
177 $paypal['s2member_log'][] = 'Please see this KB article: `http://www.s2member.com/kb/server-scanner/`. We suggest that you run the s2Member Server Scanner.';
178 $paypal['s2member_log'][] = var_export($_REQUEST, TRUE); // Recording _POST + _GET vars for analysis and debugging.
179 }
180 if($email_configs_were_on) // Back on?
181 c_ws_plugin__s2member_email_configs::email_config();
182 /*
183 Add IPN proxy (when available) to the ``$paypal`` array.
184 */
185 if(!empty($_REQUEST['s2member_paypal_proxy']))
186 $paypal['s2member_paypal_proxy'] = esc_html(trim(stripslashes((string)$_REQUEST['s2member_paypal_proxy'])));
187 /*
188 Add IPN proxy use vars (when available) to the ``$paypal`` array.
189 */
190 if(!empty($_REQUEST['s2member_paypal_proxy_use']))
191 $paypal['s2member_paypal_proxy_use'] = esc_html(trim(stripslashes((string)$_REQUEST['s2member_paypal_proxy_use'])));
192 /*
193 Add IPN proxy coupon vars (when available) to the ``$paypal`` array.
194 */
195 if(!empty($_REQUEST['s2member_paypal_proxy_coupon']))
196 $paypal['s2member_paypal_proxy_coupon'] = stripslashes_deep((array)$_REQUEST['s2member_paypal_proxy_coupon']);
197 /*
198 Also add IPN proxy self-verification (when available) to the ``$paypal`` array.
199 */
200 if(!empty($_REQUEST['s2member_paypal_proxy_verification']))
201 $paypal['s2member_paypal_proxy_verification'] = esc_html(trim(stripslashes((string)$_REQUEST['s2member_paypal_proxy_verification'])));
202 /*
203 Log this IPN post-processing event now.
204 */
205 c_ws_plugin__s2member_utils_logs::log_entry('gateway-core-ipn', $paypal);
206 /*
207 Hook during core IPN post-processing might be useful for developers.
208 */
209 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
210 do_action('ws_plugin__s2member_during_paypal_notify', get_defined_vars());
211 unset($__refs, $__v);
212 /*
213 260322 Log effective response state before/after forcing a 200.
214 Output response headers & content body.
215 */
216 $paypal['s2member_log'][] = 'Pre-response `headers_sent`: '.((headers_sent($headers_sent_file, $headers_sent_line)) ? 'yes @ '.$headers_sent_file.':'.$headers_sent_line : 'no');
217 $paypal['s2member_log'][] = 'Pre-response `http_response_code()`: '.((function_exists('http_response_code')) ? (string)http_response_code() : 'n/a');
218 $paypal['s2member_log'][] = 'Pre-response headers: '.var_export(headers_list(), TRUE);
219
220 while(@ob_end_clean()); // Clean output buffers.
221
222 if(function_exists('http_response_code'))
223 http_response_code(200);
224
225 if(!empty($_SERVER['SERVER_PROTOCOL']))
226 header($_SERVER['SERVER_PROTOCOL'].' 200 OK', TRUE, 200);
227 else
228 header('HTTP/1.1 200 OK', TRUE, 200);
229
230 status_header(200); // OK status code.
231 header('Content-Type: text/plain; charset=UTF-8');
232
233 $paypal['s2member_log'][] = 'Post-response `http_response_code()`: '.((function_exists('http_response_code')) ? (string)http_response_code() : 'n/a');
234 $paypal['s2member_log'][] = 'Post-response headers: '.var_export(headers_list(), TRUE);
235
236 if (!empty($paypal['s2member_paypal_proxy_return_url'])) {
237 if(preg_match('/^https?%3A/ui', $paypal['s2member_paypal_proxy_return_url'])) {
238 $paypal['s2member_paypal_proxy_return_url'] = urldecode($paypal['s2member_paypal_proxy_return_url']);
239 } // See: <https://github.com/websharks/s2member/issues/1024>
240 exit($paypal['s2member_paypal_proxy_return_url']);
241 } elseif (!empty($paypal['s2member_indicator'])) {
242 exit($paypal['s2member_indicator']);
243 } else {
244 exit(); // Default behavior.
245 }
246 }
247 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
248 do_action('ws_plugin__s2member_after_paypal_notify', get_defined_vars());
249 unset($__refs, $__v);
250 }
251 }
252 }
253