PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / trunk
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions vtrunk
260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 120213 120219 120301 All 187 releases
s2member / src / includes / classes / utils-logs.inc.php

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

282 lines 20.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * Log 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_utils_logs'))
22 {
23 /**
24 * Log utilities.
25 *
26 * @package s2Member\Utilities
27 * @since 3.5
28 */
29 class c_ws_plugin__s2member_utils_logs
30 {
31 /**
32 * Logs an entry.
33 *
34 * @since 130315
35 * @package s2Member\Utilities
36 *
37 * @param string $slug The file name; i.e., a slug.
38 * e.g., `mailchimp-api`, `s2-http-api-debug`.
39 *
40 * @param mixed $data The data to log.
41 */
42 public static function log_entry($slug, $data)
43 {
44 if(!($slug = trim((string)$slug)))
45 return; // Not possible.
46
47 if(!$data) return; // Nothing to log.
48
49 if(!$GLOBALS['WS_PLUGIN__']['s2member']['o']['gateway_debug_logs'])
50 return; // Nothing to do; logging not enabled right now.
51
52 if(!is_dir($logs_dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir']))
53 return; // Log directory does not exist at this time.
54
55 if(!is_writable($logs_dir)) return; // Not writable.
56
57 $logt = c_ws_plugin__s2member_utilities::time_details();
58 $logv = c_ws_plugin__s2member_utilities::ver_details();
59 $logm = c_ws_plugin__s2member_utilities::mem_details();
60
61 $log4 = ''; // Initialize.
62 if(is_multisite() && !is_main_site()) // Child blog in a multisite network?
63 $log4 .= $GLOBALS['current_blog']->domain.$GLOBALS['current_blog']->path."\n";
64 $log4 .= @$_SERVER['HTTP_HOST'].@$_SERVER['REQUEST_URI']."\n";
65 $log4 .= 'User-Agent: '.@$_SERVER['HTTP_USER_AGENT'];
66
67 $log2 = $slug.'.log'; // Initialize.
68 if(is_multisite() && !is_main_site()) // Child blog in a multisite network?
69 $log2 = $slug.'-4-'.trim(preg_replace('/[^a-z0-9]/i', '-', $GLOBALS['current_blog']->domain.$GLOBALS['current_blog']->path), '-').'.log';
70
71 c_ws_plugin__s2member_utils_logs::archive_oversize_log_files();
72
73 file_put_contents(
74 $logs_dir.'/'.$log2,
75 'LOG ENTRY: '.$logt."\n".$logv."\n".$logm."\n".$log4."\n".
76 c_ws_plugin__s2member_utils_logs::conceal_private_info(print_r($data, TRUE))."\n\n",
77 FILE_APPEND // Append to an existing log file; if exists.
78 );
79 }
80
81 /**
82 * Logs HTTP communication (if enabled).
83 *
84 * @since 120212
85 * @package s2Member\Utilities
86 *
87 * @attaches-to `http_api_debug` hook.
88 *
89 * @param mixed $response Passed by action.
90 * @param mixed $state Passed by action.
91 * @param mixed $class Passed by action.
92 * @param mixed $args Passed by action.
93 * @param mixed $url Passed by action.
94 */
95 public static function http_api_debug($response = NULL, $state = NULL, $class = NULL, $args = NULL, $url = NULL)
96 {
97 if(!$GLOBALS['WS_PLUGIN__']['s2member']['o']['gateway_debug_logs'])
98 return; // Logging is NOT enabled in this case.
99
100 $http_api_debug = array(
101 'state' => $state, 'transport_class' => $class,
102 'args' => $args, 'url' => $url, 'response' => $response
103 );
104 if(!empty($args['s2member']) || strpos($url, 's2member') !== FALSE)
105 self::log_entry('s2-http-api-debug', $http_api_debug);
106
107 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['gateway_debug_logs_extensive'])
108 self::log_entry('wp-http-api-debug', $http_api_debug);
109 }
110
111 /**
112 * Attempts to conceal private details in log entries.
113 *
114 * @since 130315
115 * @package s2Member\Utilities
116 *
117 * @param string $log_entry The log entry we need to conceal private details in.
118 *
119 * @return string Filtered string with some data X'd out :-)
120 */
121 public static function conceal_private_info($log_entry)
122 {
123 if(!($log_entry = trim((string)$log_entry)))
124 return $log_entry; // Nothing to do.
125
126 $log_entry = preg_replace('/\b([3456][0-9]{10,11})([0-9]{4})\b/', 'xxxxxxxxxxxx'.'$2', $log_entry);
127
128 $log_entry = preg_replace('/(\'.*pass_?(?:word)?(?:[0-9]+)?\'\s*\=\>\s*\')([^\']+)(\')/', '$1'.'xxxxxxxx/pass'.'$3', $log_entry);
129 $log_entry = preg_replace('/(\[\s*[^\]\r\n]*pass_?(?:word)?(?:[0-9]+)?[^\]\r\n]*\]\s*\=\>\s*)([^\r\n]*)/i', '$1'.'xxxxxxxx/pass', $log_entry);
130 $log_entry = preg_replace('/(\".*pass_?(?:word)?(?:[0-9]+)?\"\s*\:\s*\")([^\"]+)(\")/i', '$1'.'xxxxxxxx/pass'.'$3', $log_entry);
131 //260830.1632 Query-string redaction must stop at CR/LF as well as `&`; debug logs are multiline, and scanning across entries can make PCRE fail and return NULL.
132 $log_entry = preg_replace('/([&?][^&\r\n]*pass_?(?:word)?(?:[0-9]+)?\=)([^&\r\n]+)/', '$1'.'xxxxxxxx/pass', $log_entry);
133
134 $log_entry = preg_replace('/(\'api_?(?:key|secret)\'\s*\=\>\s*\')([^\']+)(\')/', '$1'.'xxxxxxxx/api/key/sec'.'$3', $log_entry);
135 $log_entry = preg_replace('/(\[\s*[^\]\r\n]*api_?(?:key|secret)[^\]\r\n]*\]\s*\=\>\s*)([^\r\n]*)/i', '$1'.'xxxxxxxx/api/key/sec', $log_entry);
136 $log_entry = preg_replace('/(\"[^\"]*api_?(?:key|secret)[^\"]*\"\s*\:\s*\")([^\"]+)(\")/i', '$1'.'xxxxxxxx/api/key/sec'.'$3', $log_entry);
137 $log_entry = preg_replace('/([&?][^&\r\n]*api_?(?:key|secret)\=)([^&\r\n]+)/i', '$1'.'xxxxxxxx/api/key/sec', $log_entry);
138
139 $log_entry = preg_replace('/(\'(?:PWD|SIGNATURE)\'\s*\=\>\s*\')([^\']+)(\')/', '$1'.'xxxxxxxx/PWD/SIG'.'$3', $log_entry);
140 $log_entry = preg_replace('/(\[\s*[^\]\r\n]*(?:PWD|SIGNATURE)[^\]\r\n]*\]\s*\=\>\s*)([^\r\n]*)/', '$1'.'xxxxxxxx/PWD/SIG', $log_entry);
141 $log_entry = preg_replace('/(\"(?:PWD|SIGNATURE)\"\s*\:\s*\")([^\"]+)(\")/', '$1'.'xxxxxxxx/PWD/SIG'.'$3', $log_entry);
142 $log_entry = preg_replace('/([&?][^&\r\n]*(?:PWD|SIGNATURE)\=)([^&\r\n]+)/', '$1'.'xxxxxxxx/PWD/SIG', $log_entry);
143 $log_entry = preg_replace('/((?:^|[&?])[^&\r\n]*(?:PWD|SIGNATURE)(?:\[[^\]&=]*\]|%5B[^&=]*%5D)?\=)([^&\r\n]+)/im', '$1'.'xxxxxxxx/PWD/SIG', $log_entry);
144
145 $log_entry = preg_replace('/(\'(?:x_login|x_tran_key)\'\s*\=\>\s*\')([^\']+)(\')/', '$1'.'xxxxxxxx/key/tran'.'$3', $log_entry);
146 $log_entry = preg_replace('/(\[\s*[^\]\r\n]*(?:x_login|x_tran_key)[^\]\r\n]*\]\s*\=\>\s*)([^\r\n]*)/i', '$1'.'xxxxxxxx/key/tran', $log_entry);
147 $log_entry = preg_replace('/(\"(?:x_login|x_tran_key)\"\s*\:\s*\")([^\"]+)(\")/i', '$1'.'xxxxxxxx/key/tran'.'$3', $log_entry);
148 $log_entry = preg_replace('/([&?][^&\r\n]*(?:x_login|x_tran_key)\=)([^&\r\n]+)/i', '$1'.'xxxxxxxx/key/tran', $log_entry);
149
150 //260617 Conceal card verification values in gateway and HTTP API logs.
151 $log_entry = preg_replace('/(\'(?:CVV2?|CVC2?|CSC|CARD_?CODE|X_CARD_CODE|x_card_code|card_?code|card_?verification)\'\s*\=\>\s*\')([^\']+)(\')/i', '$1'.'xxxxxxxx/cvv'.'$3', $log_entry);
152 $log_entry = preg_replace('/(\[\s*[^\r\n]*(?:CVV2?|CVC2?|CSC|CARD_?CODE|X_CARD_CODE|x_card_code|card_?code|card_?verification)[^\r\n]*\]\s*\=\>\s*)([^\r\n]*)/i', '$1'.'xxxxxxxx/cvv', $log_entry);
153 $log_entry = preg_replace('/(\"[^\"]*(?:CVV2?|CVC2?|CSC|CARD_?CODE|X_CARD_CODE|x_card_code|card_?code|card_?verification)[^\"]*\"\s*\:\s*\")([^\"]+)(\")/i', '$1'.'xxxxxxxx/cvv'.'$3', $log_entry);
154 $log_entry = preg_replace('/((?:^|[&?])[^&\r\n]*(?:CVV2?|CVC2?|CSC|CARD_?CODE|X_CARD_CODE|x_card_code|card_?code|card_?verification)(?:\[[^\]&=]*\]|%5B[^&=]*%5D)?\=)([^&\r\n]+)/im', '$1'.'xxxxxxxx/cvv', $log_entry);
155 $log_entry = preg_replace('/(<((?:CVV2?|CVC2?|CSC|CARD_?CODE|X_CARD_CODE|x_card_code|card_?code|card_?verification))\b[^>]*>)(.*?)(<\/\2>)/is', '$1'.'xxxxxxxx/cvv'.'$4', $log_entry);
156
157 $log_entry = preg_replace('/(Authorization\s*:\s*Basic\s+)[A-Za-z0-9\/\+\=]+/i', '$1'.'xxxxxxxx/basic-auth', $log_entry);
158 $log_entry = preg_replace('/(\[\s*Authorization\s*\]\s*=\>\s*Basic\s+)[A-Za-z0-9\/\+\=]+/i', '$1'.'xxxxxxxx/basic-auth', $log_entry);
159 $log_entry = preg_replace('/(\"Authorization\"\s*:\s*\"Basic\s+)[A-Za-z0-9\/\+\=]+(\")/i', '$1'.'xxxxxxxx/basic-auth'.'$2', $log_entry);
160
161 //260303 Conceal OAuth access tokens in logged response bodies too.
162 $log_entry = preg_replace('/(\"access_token\"\s*:\s*\")([^\"]+)(\")/i', '$1'.'xxxxxxxx/access-token'.'$3', $log_entry);
163 $log_entry = preg_replace('/(\[\s*access_token\s*\]\s*=\>\s*)([^\r\n]*)/i', '$1'.'xxxxxxxx/access-token', $log_entry);
164
165 return $log_entry; // With some private info concealed now.
166 }
167
168 /**
169 * Archives logs to prevent HUGE files from building up over time.
170 *
171 * @since 3.5
172 * @package s2Member\Utilities
173 *
174 * @param bool $stagger Defaults to a `TRUE` value.
175 *
176 * @return bool Always returns a `TRUE` value.
177 */
178 public static function archive_oversize_log_files($stagger = TRUE)
179 {
180 if($stagger && !is_float($stagger = time() / 2))
181 return TRUE; // Bypass this time.
182
183 if(!is_dir($dir = $GLOBALS['WS_PLUGIN__']['s2member']['c']['logs_dir']) || !is_writable($dir))
184 return TRUE; // Not necessary; directory is nonexistent or not writable.
185
186 if(!($log_files = scandir($dir)) || !shuffle($log_files))
187 return TRUE; // No files; not necessary.
188
189 $counter = 1; // Initialize archiving counter.
190 $max = apply_filters('ws_plugin__s2member_oversize_log_file_bytes', 2097152, get_defined_vars());
191
192 foreach($log_files as $file) // Go through each log file. Up to 25 files at a time.
193 {
194 if(preg_match('/\.log$/i', $file) && !preg_match('/\-ARCHIVED\-/i', $file) && is_file($dir_file = $dir.'/'.$file))
195 if(filesize($dir_file) > $max && is_writable($dir_file)) // The file must be writable.
196 if($log = preg_replace('/\.log$/i', '', $dir_file)) // Strip .log before renaming.
197 rename($dir_file, $log.'-ARCHIVED-'.date('m-d-Y').'-'.time().'.log');
198
199 if(($counter = $counter + 1) > 25) // Up to 25 files at a time.
200 break; // Stop for now.
201 }
202 return TRUE; // Always returns a `TRUE` value.
203 }
204
205 /**
206 * Removes expired Transients inserted into the database by s2Member.
207 *
208 * @since 3.5
209 * @package s2Member\Utilities
210 *
211 * @param bool $stagger Defaults to a `TRUE` value.
212 *
213 * @return bool Always returns a `TRUE` value.
214 */
215 public static function cleanup_expired_s2m_transients($stagger = TRUE)
216 {
217 global $wpdb; /** @var wpdb $wpdb */
218
219 if($stagger && !is_float($stagger = time() / 2))
220 return TRUE; // Bypass this time.
221
222 if(($expired_s2m_transients = $wpdb->get_results("SELECT * FROM `".$wpdb->options."` WHERE `option_name` LIKE '".esc_sql(c_ws_plugin__s2member_utils_strings::like_escape('_transient_timeout_s2m_'))."%' AND `option_value` < '".esc_sql(time())."' LIMIT 5")))
223 foreach($expired_s2m_transients as $_expired_s2m_transient) // Delete the _timeout, and also the transient entry name itself.
224 if(($_id = $_expired_s2m_transient->option_id) && ($_name = preg_replace('/_transient_timeout_/i', '_transient_', $_expired_s2m_transient->option_name, 1)))
225 $wpdb->query("DELETE FROM `".$wpdb->options."` WHERE (`option_id` = '".esc_sql($_id)."' OR `option_name` = '".esc_sql($_name)."')");
226
227 return TRUE; // Always returns a `TRUE` value.
228 }
229
230 /**
231 * Array of log file descriptions.
232 *
233 * @since 120214
234 * @package s2Member\Utilities
235 *
236 * @var array Array of log file descriptions.
237 */
238 public static $log_file_descriptions = array
239 ( // Array keys are regex patterns matching their associated log file names.
240 '/gateway\-core\-ipn/' => array('short' => 'Core IPN and post-processing handler.', 'long' => 'This log file records all communication between s2Member and the IPN/Webhook/Callback services associated with various payment gateways. All transactions pass through s2Member\'s core processor, and they will be logged in this file; including transactions processed via s2Member Pro-Forms—for all Payment Gateway integrations.'),
241 '/gateway\-core\-rtn/' => array('short' => 'Core PDT/Auto-Return communication.', 'long' => 'This log file records all communication between s2Member and the PDT/Auto-Return/Thank-You services associated with various payment gateways (i.e., routines that help s2Member process Thank-You pages). This log file is not used in s2Member Pro-Form integrations however.'),
242
243 '/stripe\-api/' => array('short' => 'Stripe API communication.', 'long' => 'This log file records all communication between s2Member and Stripe APIs. See also: gateway-core-ipn.log (s2Member\'s core processor).'),
244 '/stripe\-ipn/' => array('short' => 'Stripe Webhook/IPN communication.', 'long' => 'This log file records the Webhook/IPN data that Stripe sends to s2Member. See also: gateway-core-ipn.log (s2Member\'s core processor).'),
245
246 '/paypal\-api/' => array('short' => 'PayPal API communication.', 'long' => 'This log file records all communication between s2Member and PayPal APIs. Such as PayPal Button Encryption and PayPal Pro API calls that process transactions. This log file may be used (in some scenarios), even if you\'re running a PayPal Payments Pro (Payflow Edition) account. See also: gateway-core-ipn.log (s2Member\'s core processor).'),
247 '/paypal\-payflow\-api/' => array('short' => 'PayPal Pro (PayFlow Edition) API communication.', 'long' => 'This log file records all communication between s2Member and the PayPal Payments Pro (PayFlow Edition) APIs. This log file is only used if you operate a PayPal Payments Pro (PayFlow Edition) account; i.e., only if you integrate s2Member Pro with Payflow for Recurring Billing. See also: gateway-core-ipn.log (s2Member\'s core processor).'),
248 '/paypal\-checkout/' => array('short' => 'PayPal Checkout (REST/JS SDK) communication.', 'long' => 'This log file records communication related to s2Member\'s PayPal Checkout integration (REST API requests, JS SDK/checkout flow diagnostics, and webhook/notify proxy details). See also: gateway-core-ipn.log (s2Member\'s core processor).'),
249
250 '/authnet\-api/' => array('short' => 'Authorize.Net API communication.', 'long' => 'This log file records all communication between s2Member and Authorize.Net APIs (for both AIM and ARB integrations). See also: gateway-core-ipn.log (s2Member\'s core processor).'),
251 '/authnet\-arb/' => array('short' => 'Authorize.Net ARB Subscription status checks.', 'long' => 'This log file records s2Member\'s Authorize.Net ARB Subscription status checks. s2Member polls the ARB service periodically to check the status of existing Members (e.g., to see if billing is still active or not).'),
252 '/authnet\-ipn/' => array('short' => 'Authorize.Net Silent Post/IPN communication.', 'long' => 'This log file records the Silent Post/IPN data Authorize.Net sends to s2Member with details regarding new transactions. See also: gateway-core-ipn.log (s2Member\'s core processor).'),
253
254 '/alipay\-ipn/' => array('short' => 'AliPay IPN communication.', 'long' => 'This log file records the IPN data AliPay sends to s2Member with details regarding new transactions. See also: gateway-core-ipn.log (s2Member\'s core processor).'),
255 '/alipay\-rtn/' => array('short' => 'AliPay Auto-Return communication.', 'long' => 'This log file records the Auto-Return data AliPay sends to s2Member with details regarding new transactions (i.e., logs routines that help s2Member process Thank-You pages). See also: gateway-core-rtn.log (s2Member\'s core processor).'),
256
257 '/clickbank\-ipn/' => array('short' => 'ClickBank IPN communication.', 'long' => 'This log file records the IPN data ClickBank sends to s2Member with details regarding new transactions, cancellations, expirations, etc. See also: gateway-core-ipn.log (s2Member\'s core processor).'),
258 '/clickbank\-rtn/' => array('short' => 'ClickBank Auto-Return communication.', 'long' => 'This log file records the Auto-Return data ClickBank sends to s2Member with details regarding new transactions (i.e., logs routines that help s2Member process Thank-You pages). See also: gateway-core-rtn.log (s2Member\'s core processor).'),
259
260 '/google\-rtn/' => array('short' => 'Google Auto-Return communication.', 'long' => 'This log file records the Auto-Return data Google sends to s2Member with details regarding new transactions (i.e., logs routines that help s2Member process Thank-You pages). See also: gateway-core-rtn.log (s2Member\'s core processor). NOTE (regarding Google Wallet)... this particular log file is currently implemented for a possible future use ONLY. At this time there is no need for an Auto-Return handler with Google Wallet, because Google Wallet return handling is done via email-only at this time.'),
261 '/google\-ipn/' => array('short' => 'Google Postback/IPN communication.', 'long' => 'This log file records the Postback/IPN data Google sends to s2Member with details regarding new transactions, cancellations, expirations, etc. See also: gateway-core-ipn.log (s2Member\'s core processor).'),
262
263 '/ccbill\-ipn/' => array('short' => 'ccBill Bg Post/IPN communication.', 'long' => 'This log file records the Bg Post/IPN data ccBill sends to s2Member with details regarding new transactions. See also: gateway-core-ipn.log (s2Member\'s core processor).'),
264 '/ccbill\-rtn/' => array('short' => 'ccBill Auto-Return communication.', 'long' => 'This log file records the Auto-Return data ccBill sends to s2Member with details regarding new transactions (i.e., logs routines that help s2Member process Thank-You pages). See also: gateway-core-rtn.log (s2Member\'s core processor).'),
265 '/ccbill\-dl\-ipn/' => array('short' => 'ccBill Datalink Subscription status checks.', 'long' => 'This log file records s2Member\'s ccBill Datalink Subscription status checks that may result in actions taken by s2Member. s2Member polls the ccBill Datalink service periodically to check the status of existing Members (e.g., to see if billing is still active or not).'),
266 '/ccbill\-dl/' => array('short' => 'ccBill Datalink collections.', 'long' => 'This log file records s2Member\'s ccBill Datalink connections. s2Member polls the ccBill Datalink service periodically to obtain information about existing Users/Members.'),
267
268 '/mailchimp\-api/' => array('short' => 'MailChimp API communication.', 'long' => 'This log file records all of s2Member\'s communication with MailChimp APIs.'),
269 '/aweber\-api/' => array('short' => 'AWeber API communication.', 'long' => 'This log file records all of s2Member\'s communication with AWeber APIs.'),
270 '/getresponse\-api/' => array('short' => 'GetResponse API communication.', 'long' => 'This log file records all of s2Member\'s communication with GetResponse APIs.'),
271
272 '/reg\-handler/' => array('short' => 'User registrations processed by s2Member.', 'long' => 'This log file records all User/Member registrations processed by s2Member (either directly or indirectly). This includes both free and paid registrations. It also logs registrations that occur as a result of new Users/Members being created from the Dashboard by a site owner. It also includes registrations that occur through the s2Member Pro Remote Operations API.'),
273
274 '/s2\-http\-api\-debug/' => array('short' => 'All outgoing HTTP connections related to s2Member.', 'long' => 'This log file records all outgoing WP_Http connections that are specifically related to s2Member. This log file can be extremely helpful. It includes technical details about remote HTTP connections that are not available in other log files.'),
275 '/wp\-http\-api\-debug/' => array('short' => 'All outgoing WordPress HTTP connections.', 'long' => 'This log file records all outgoing HTTP connections processed by the WP_Http class. This includes everything processed by WordPress; even things unrelated to s2Member. This log file can be extremely helpful. It includes technical details about remote HTTP connections that are not available in other log files.'),
276
277 '/auto\-eot\-system/' => array('short' => 'EOTs processed via CRON job.', 'long' => 'This log file records all EOTs processed by the WP_Cron job that powers the s2Member Auto-EOT System. Once a customer has an EOT Time, the CRON job comes in and actually handles a demotion or deletion (based on your configuration). That is what this log file shows; i.e., the actual demotion or deletion taking place.'),
278 '/eot\-reminders/' => array('short' => 'EOT reminder emails processed via CRON job.', 'long' => 'This log file records all EOT reminder emails processed by the WP_Cron job that powers the s2Member Auto-EOT System. EOT Renewal/Reminder Email notifications are available only in the pro version of s2Member.'),
279 );
280 }
281 }
282