PluginProbe ʕ •ᴥ•ʔ
LiteSpeed Cache / 6.5.4
LiteSpeed Cache v6.5.4
trunk 1.0.15 1.9.1.1 2.9.9.2 3.6.4 4.6 5.7.0.1 6.5.4 7.0.0.1 7.0.1 7.1 7.2 7.3 7.3.0.1 7.4 7.5 7.5.0.1 7.6 7.6.1 7.6.2 7.7 7.8 7.8.0.1 7.8.1
litespeed-cache / src / debug2.cls.php
litespeed-cache / src Last commit date
cdn 1 year ago data_structure 1 year ago activation.cls.php 1 year ago admin-display.cls.php 1 year ago admin-settings.cls.php 1 year ago admin.cls.php 1 year ago api.cls.php 1 year ago avatar.cls.php 1 year ago base.cls.php 1 year ago cdn-setup.cls.php 1 year ago cdn.cls.php 1 year ago cloud.cls.php 1 year ago conf.cls.php 1 year ago control.cls.php 1 year ago core.cls.php 1 year ago crawler-map.cls.php 1 year ago crawler.cls.php 1 year ago css.cls.php 1 year ago data.cls.php 1 year ago data.upgrade.func.php 1 year ago db-optm.cls.php 1 year ago debug2.cls.php 1 year ago doc.cls.php 1 year ago error.cls.php 1 year ago esi.cls.php 1 year ago file.cls.php 1 year ago gui.cls.php 1 year ago health.cls.php 1 year ago htaccess.cls.php 1 year ago img-optm.cls.php 1 year ago import.cls.php 1 year ago instance.cls.php 1 year ago lang.cls.php 1 year ago localization.cls.php 1 year ago media.cls.php 1 year ago metabox.cls.php 1 year ago object-cache.cls.php 1 year ago object.lib.php 1 year ago optimize.cls.php 1 year ago optimizer.cls.php 1 year ago placeholder.cls.php 1 year ago preset.cls.php 1 year ago purge.cls.php 1 year ago report.cls.php 1 year ago rest.cls.php 1 year ago root.cls.php 1 year ago router.cls.php 1 year ago str.cls.php 1 year ago tag.cls.php 1 year ago task.cls.php 1 year ago tool.cls.php 1 year ago ucss.cls.php 1 year ago utility.cls.php 1 year ago vary.cls.php 1 year ago vpi.cls.php 1 year ago
debug2.cls.php
563 lines
1 <?php
2
3 /**
4 * The plugin logging class.
5 */
6
7 namespace LiteSpeed;
8
9 defined('WPINC') || exit();
10
11 class Debug2 extends Root
12 {
13 private static $log_path;
14 private static $log_path_prefix;
15 private static $_prefix;
16
17 const TYPE_CLEAR_LOG = 'clear_log';
18 const TYPE_BETA_TEST = 'beta_test';
19
20 const BETA_TEST_URL = 'beta_test_url';
21
22 const BETA_TEST_URL_WP = 'https://downloads.wordpress.org/plugin/litespeed-cache.zip';
23
24 /**
25 * Log class Confructor
26 *
27 * NOTE: in this process, until last step ( define const LSCWP_LOG = true ), any usage to WP filter will not be logged to prevent infinite loop with log_filters()
28 *
29 * @since 1.1.2
30 * @access public
31 */
32 public function __construct()
33 {
34 self::$log_path_prefix = LITESPEED_STATIC_DIR . '/debug/';
35 // Maybe move legacy log files
36 $this->_maybe_init_folder();
37
38 self::$log_path = $this->path('debug');
39 if (!empty($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'lscache_') === 0) {
40 self::$log_path = $this->path('crawler');
41 }
42
43 !defined('LSCWP_LOG_TAG') && define('LSCWP_LOG_TAG', get_current_blog_id());
44
45 if ($this->conf(Base::O_DEBUG_LEVEL)) {
46 !defined('LSCWP_LOG_MORE') && define('LSCWP_LOG_MORE', true);
47 }
48
49 defined('LSCWP_DEBUG_EXC_STRINGS') || define('LSCWP_DEBUG_EXC_STRINGS', $this->conf(Base::O_DEBUG_EXC_STRINGS));
50 }
51
52 /**
53 * Try moving legacy logs into /litespeed/debug/ folder
54 *
55 * @since 6.5
56 */
57 private function _maybe_init_folder()
58 {
59 if (file_exists(self::$log_path_prefix . 'index.php')) {
60 return;
61 }
62 file::save(self::$log_path_prefix . 'index.php', '<?php // Silence is golden.', true);
63
64 $logs = array('debug', 'debug.purge', 'crawler');
65 foreach ($logs as $log) {
66 if (file_exists(LSCWP_CONTENT_DIR . '/' . $log . '.log') && !file_exists($this->path($log))) {
67 rename(LSCWP_CONTENT_DIR . '/' . $log . '.log', $this->path($log));
68 }
69 }
70 }
71
72 /**
73 * Generate log file path
74 *
75 * @since 6.5
76 */
77 public function path($type)
78 {
79 return self::$log_path_prefix . self::FilePath($type);
80 }
81
82 /**
83 * Generate the fixed log filename
84 *
85 * @since 6.5
86 */
87 public static function FilePath($type)
88 {
89 if ($type == 'debug.purge') {
90 $type = 'purge';
91 }
92 $key = defined('AUTH_KEY') ? AUTH_KEY : md5(__FILE__);
93 $rand = substr(md5(substr($key, -16)), -16);
94 return $type . $rand . '.log';
95 }
96
97 /**
98 * End call of one request process
99 * @since 4.7
100 * @access public
101 */
102 public static function ended()
103 {
104 $headers = headers_list();
105 foreach ($headers as $key => $header) {
106 if (stripos($header, 'Set-Cookie') === 0) {
107 unset($headers[$key]);
108 }
109 }
110 self::debug('Response headers', $headers);
111
112 $elapsed_time = number_format((microtime(true) - LSCWP_TS_0) * 1000, 2);
113 self::debug("End response\n--------------------------------------------------Duration: " . $elapsed_time . " ms------------------------------\n");
114 }
115
116 /**
117 * Beta test upgrade
118 *
119 * @since 2.9.5
120 * @access public
121 */
122 public function beta_test($zip = false)
123 {
124 if (!$zip) {
125 if (empty($_REQUEST[self::BETA_TEST_URL])) {
126 return;
127 }
128
129 $zip = $_REQUEST[self::BETA_TEST_URL];
130 if ($zip !== Debug2::BETA_TEST_URL_WP) {
131 if ($zip === 'latest') {
132 $zip = Debug2::BETA_TEST_URL_WP;
133 } else {
134 // Generate zip url
135 $zip = $this->_package_zip($zip);
136 }
137 }
138 }
139
140 if (!$zip) {
141 Debug2::debug('[Debug2] ❌ No ZIP file');
142 return;
143 }
144
145 Debug2::debug('[Debug2] ZIP file ' . $zip);
146
147 $update_plugins = get_site_transient('update_plugins');
148 if (!is_object($update_plugins)) {
149 $update_plugins = new \stdClass();
150 }
151
152 $plugin_info = new \stdClass();
153 $plugin_info->new_version = Core::VER;
154 $plugin_info->slug = Core::PLUGIN_NAME;
155 $plugin_info->plugin = Core::PLUGIN_FILE;
156 $plugin_info->package = $zip;
157 $plugin_info->url = 'https://wordpress.org/plugins/litespeed-cache/';
158
159 $update_plugins->response[Core::PLUGIN_FILE] = $plugin_info;
160
161 set_site_transient('update_plugins', $update_plugins);
162
163 // Run upgrade
164 Activation::cls()->upgrade();
165 }
166
167 /**
168 * Git package refresh
169 *
170 * @since 2.9.5
171 * @access private
172 */
173 private function _package_zip($commit)
174 {
175 $data = array(
176 'commit' => $commit,
177 );
178 $res = Cloud::get(Cloud::API_BETA_TEST, $data);
179
180 if (empty($res['zip'])) {
181 return false;
182 }
183
184 return $res['zip'];
185 }
186
187 /**
188 * Log Purge headers separately
189 *
190 * @since 2.7
191 * @access public
192 */
193 public static function log_purge($purge_header)
194 {
195 // Check if debug is ON
196 if (!defined('LSCWP_LOG') && !defined('LSCWP_LOG_BYPASS_NOTADMIN')) {
197 return;
198 }
199
200 $purge_file = self::cls()->path('purge');
201
202 self::cls()->_init_request($purge_file);
203
204 $msg = $purge_header . self::_backtrace_info(6);
205
206 File::append($purge_file, self::format_message($msg));
207 }
208
209 /**
210 * Enable debug log
211 *
212 * @since 1.1.0
213 * @access public
214 */
215 public function init()
216 {
217 $debug = $this->conf(Base::O_DEBUG);
218 if ($debug == Base::VAL_ON2) {
219 if (!$this->cls('Router')->is_admin_ip()) {
220 defined('LSCWP_LOG_BYPASS_NOTADMIN') || define('LSCWP_LOG_BYPASS_NOTADMIN', true);
221 return;
222 }
223 }
224
225 /**
226 * Check if hit URI includes/excludes
227 * This is after LSCWP_LOG_BYPASS_NOTADMIN to make `log_purge()` still work
228 * @since 3.0
229 */
230 $list = $this->conf(Base::O_DEBUG_INC);
231 if ($list) {
232 $result = Utility::str_hit_array($_SERVER['REQUEST_URI'], $list);
233 if (!$result) {
234 return;
235 }
236 }
237
238 $list = $this->conf(Base::O_DEBUG_EXC);
239 if ($list) {
240 $result = Utility::str_hit_array($_SERVER['REQUEST_URI'], $list);
241 if ($result) {
242 return;
243 }
244 }
245
246 if (!defined('LSCWP_LOG')) {
247 // If not initialized, do it now
248 $this->_init_request();
249 define('LSCWP_LOG', true);
250 }
251 }
252
253 /**
254 * Create the initial log messages with the request parameters.
255 *
256 * @since 1.0.12
257 * @access private
258 */
259 private function _init_request($log_file = null)
260 {
261 if (!$log_file) {
262 $log_file = self::$log_path;
263 }
264
265 // Check log file size
266 $log_file_size = $this->conf(Base::O_DEBUG_FILESIZE);
267 if (file_exists($log_file) && filesize($log_file) > $log_file_size * 1000000) {
268 File::save($log_file, '');
269 }
270
271 // For more than 2s's requests, add more break
272 if (file_exists($log_file) && time() - filemtime($log_file) > 2) {
273 File::append($log_file, "\n\n\n\n");
274 }
275
276 if (PHP_SAPI == 'cli') {
277 return;
278 }
279
280 $servervars = array(
281 'Query String' => '',
282 'HTTP_ACCEPT' => '',
283 'HTTP_USER_AGENT' => '',
284 'HTTP_ACCEPT_ENCODING' => '',
285 'HTTP_COOKIE' => '',
286 'REQUEST_METHOD' => '',
287 'SERVER_PROTOCOL' => '',
288 'X-LSCACHE' => '',
289 'LSCACHE_VARY_COOKIE' => '',
290 'LSCACHE_VARY_VALUE' => '',
291 'ESI_CONTENT_TYPE' => '',
292 );
293 $server = array_merge($servervars, $_SERVER);
294 $params = array();
295
296 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
297 $server['SERVER_PROTOCOL'] .= ' (HTTPS) ';
298 }
299
300 $param = sprintf('💓 ------%s %s %s', $server['REQUEST_METHOD'], $server['SERVER_PROTOCOL'], strtok($server['REQUEST_URI'], '?'));
301
302 $qs = !empty($server['QUERY_STRING']) ? $server['QUERY_STRING'] : '';
303 if ($this->conf(Base::O_DEBUG_COLLAPSE_QS)) {
304 $qs = $this->_omit_long_message($qs);
305 if ($qs) {
306 $param .= ' ? ' . $qs;
307 }
308 $params[] = $param;
309 } else {
310 $params[] = $param;
311 $params[] = 'Query String: ' . $qs;
312 }
313
314 if (!empty($_SERVER['HTTP_REFERER'])) {
315 $params[] = 'HTTP_REFERER: ' . $this->_omit_long_message($server['HTTP_REFERER']);
316 }
317
318 if (defined('LSCWP_LOG_MORE')) {
319 $params[] = 'User Agent: ' . $this->_omit_long_message($server['HTTP_USER_AGENT']);
320 $params[] = 'Accept: ' . $server['HTTP_ACCEPT'];
321 $params[] = 'Accept Encoding: ' . $server['HTTP_ACCEPT_ENCODING'];
322 }
323 // $params[] = 'Cookie: ' . $server['HTTP_COOKIE'];
324 if (isset($_COOKIE['_lscache_vary'])) {
325 $params[] = 'Cookie _lscache_vary: ' . $_COOKIE['_lscache_vary'];
326 }
327 if (defined('LSCWP_LOG_MORE')) {
328 $params[] = 'X-LSCACHE: ' . (!empty($server['X-LSCACHE']) ? 'true' : 'false');
329 }
330 if ($server['LSCACHE_VARY_COOKIE']) {
331 $params[] = 'LSCACHE_VARY_COOKIE: ' . $server['LSCACHE_VARY_COOKIE'];
332 }
333 if ($server['LSCACHE_VARY_VALUE']) {
334 $params[] = 'LSCACHE_VARY_VALUE: ' . $server['LSCACHE_VARY_VALUE'];
335 }
336 if ($server['ESI_CONTENT_TYPE']) {
337 $params[] = 'ESI_CONTENT_TYPE: ' . $server['ESI_CONTENT_TYPE'];
338 }
339
340 $request = array_map(__CLASS__ . '::format_message', $params);
341
342 File::append($log_file, $request);
343 }
344
345 /**
346 * Trim long msg to keep log neat
347 * @since 6.3
348 */
349 private function _omit_long_message($msg)
350 {
351 if (strlen($msg) > 53) {
352 $msg = substr($msg, 0, 53) . '...';
353 }
354 return $msg;
355 }
356
357 /**
358 * Formats the log message with a consistent prefix.
359 *
360 * @since 1.0.12
361 * @access private
362 * @param string $msg The log message to write.
363 * @return string The formatted log message.
364 */
365 private static function format_message($msg)
366 {
367 // If call here without calling get_enabled() first, improve compatibility
368 if (!defined('LSCWP_LOG_TAG')) {
369 return $msg . "\n";
370 }
371
372 if (!isset(self::$_prefix)) {
373 // address
374 if (PHP_SAPI == 'cli') {
375 $addr = '=CLI=';
376 if (isset($_SERVER['USER'])) {
377 $addr .= $_SERVER['USER'];
378 } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
379 $addr .= $_SERVER['HTTP_X_FORWARDED_FOR'];
380 }
381 } else {
382 $addr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
383 $port = isset($_SERVER['REMOTE_PORT']) ? $_SERVER['REMOTE_PORT'] : '';
384 $addr = "$addr:$port";
385 }
386
387 // Generate a unique string per request
388 self::$_prefix = sprintf(' [%s %s %s] ', $addr, LSCWP_LOG_TAG, Str::rrand(3));
389 }
390 list($usec, $sec) = explode(' ', microtime());
391 return date('m/d/y H:i:s', $sec + LITESPEED_TIME_OFFSET) . substr($usec, 1, 4) . self::$_prefix . $msg . "\n";
392 }
393
394 /**
395 * Direct call to log a debug message.
396 *
397 * @since 1.1.3
398 * @access public
399 */
400 public static function debug($msg, $backtrace_limit = false)
401 {
402 if (!defined('LSCWP_LOG')) {
403 return;
404 }
405
406 if (defined('LSCWP_DEBUG_EXC_STRINGS') && Utility::str_hit_array($msg, LSCWP_DEBUG_EXC_STRINGS)) {
407 return;
408 }
409
410 if ($backtrace_limit !== false) {
411 if (!is_numeric($backtrace_limit)) {
412 $backtrace_limit = self::trim_longtext($backtrace_limit);
413 if (is_array($backtrace_limit) && count($backtrace_limit) == 1 && !empty($backtrace_limit[0])) {
414 $msg .= ' --- ' . $backtrace_limit[0];
415 } else {
416 $msg .= ' --- ' . var_export($backtrace_limit, true);
417 }
418 self::push($msg);
419 return;
420 }
421
422 self::push($msg, $backtrace_limit + 1);
423 return;
424 }
425
426 self::push($msg);
427 }
428
429 /**
430 * Trim long string before array dump
431 * @since 3.3
432 */
433 public static function trim_longtext($backtrace_limit)
434 {
435 if (is_array($backtrace_limit)) {
436 $backtrace_limit = array_map(__CLASS__ . '::trim_longtext', $backtrace_limit);
437 }
438 if (is_string($backtrace_limit) && strlen($backtrace_limit) > 500) {
439 $backtrace_limit = substr($backtrace_limit, 0, 1000) . '...';
440 }
441 return $backtrace_limit;
442 }
443
444 /**
445 * Direct call to log an advanced debug message.
446 *
447 * @since 1.2.0
448 * @access public
449 */
450 public static function debug2($msg, $backtrace_limit = false)
451 {
452 if (!defined('LSCWP_LOG_MORE')) {
453 return;
454 }
455 self::debug($msg, $backtrace_limit);
456 }
457
458 /**
459 * Logs a debug message.
460 *
461 * @since 1.1.0
462 * @access private
463 * @param string $msg The debug message.
464 * @param int $backtrace_limit Backtrace depth.
465 */
466 private static function push($msg, $backtrace_limit = false)
467 {
468 // backtrace handler
469 if (defined('LSCWP_LOG_MORE') && $backtrace_limit !== false) {
470 $msg .= self::_backtrace_info($backtrace_limit);
471 }
472
473 File::append(self::$log_path, self::format_message($msg));
474 }
475
476 /**
477 * Backtrace info
478 *
479 * @since 2.7
480 */
481 private static function _backtrace_info($backtrace_limit)
482 {
483 $msg = '';
484
485 $trace = version_compare(PHP_VERSION, '5.4.0', '<') ? debug_backtrace() : debug_backtrace(false, $backtrace_limit + 3);
486 for ($i = 2; $i <= $backtrace_limit + 2; $i++) {
487 // 0st => _backtrace_info(), 1st => push()
488 if (empty($trace[$i]['class'])) {
489 if (empty($trace[$i]['file'])) {
490 break;
491 }
492 $log = "\n" . $trace[$i]['file'];
493 } else {
494 if ($trace[$i]['class'] == __CLASS__) {
495 continue;
496 }
497
498 $args = '';
499 if (!empty($trace[$i]['args'])) {
500 foreach ($trace[$i]['args'] as $v) {
501 if (is_array($v)) {
502 $v = 'ARRAY';
503 }
504 if (is_string($v) || is_numeric($v)) {
505 $args .= $v . ',';
506 }
507 }
508
509 $args = substr($args, 0, strlen($args) > 100 ? 100 : -1);
510 }
511
512 $log = str_replace('Core', 'LSC', $trace[$i]['class']) . $trace[$i]['type'] . $trace[$i]['function'] . '(' . $args . ')';
513 }
514 if (!empty($trace[$i - 1]['line'])) {
515 $log .= '@' . $trace[$i - 1]['line'];
516 }
517 $msg .= " => $log";
518 }
519
520 return $msg;
521 }
522
523 /**
524 * Clear log file
525 *
526 * @since 1.6.6
527 * @access private
528 */
529 private function _clear_log()
530 {
531 $logs = array('debug', 'purge', 'crawler');
532 foreach ($logs as $log) {
533 File::save($this->path($log), '');
534 }
535 }
536
537 /**
538 * Handle all request actions from main cls
539 *
540 * @since 1.6.6
541 * @access public
542 */
543 public function handler()
544 {
545 $type = Router::verify_type();
546
547 switch ($type) {
548 case self::TYPE_CLEAR_LOG:
549 $this->_clear_log();
550 break;
551
552 case self::TYPE_BETA_TEST:
553 $this->beta_test();
554 break;
555
556 default:
557 break;
558 }
559
560 Admin::redirect();
561 }
562 }
563