PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
metasync / includes / class-metasync-errorlogs.php

class-metasync-errorlogs.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.7.1, at includes/class-metasync-errorlogs.php

154 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 class ErrorLog {
3 private $logFilePath;
4
5 /**
6 * ErrorLog constructor.
7 *
8 * @param string $logFilePath
9 */
10 public function __construct() {
11 $this->logFilePath = ini_get('error_log');
12 }
13
14 public function getParsedLogFile() {
15 $parsedLogs = [];
16 $logFilePath = $this->logFilePath;
17
18 // error_log can be disabled (empty ini value), set to "syslog", or
19 // point at a file that no longer exists — there is nothing to parse,
20 // and file_get_contents would warn on those values.
21 if (empty($logFilePath) || !is_string($logFilePath) || 'syslog' === $logFilePath || !is_file($logFilePath)) {
22 return $parsedLogs;
23 }
24
25 // A long-lived error log can grow to gigabytes; parsing it whole
26 // exhausts memory on the request that reads it. Read only the
27 // trailing window — recent entries are what the admin UI shows.
28 $tail_bytes = 1024 * 1024;
29 $size = filesize($logFilePath);
30 $content = false;
31 if (false !== $size && $size > $tail_bytes) {
32 $handle = @fopen($logFilePath, 'rb'); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- streaming file I/O; WP_Filesystem cannot return a raw stream handle
33 if (false !== $handle) {
34 fseek($handle, $size - $tail_bytes);
35 $content = stream_get_contents($handle);
36 fclose($handle); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- operates on a native stream handle
37 // Drop the leading partial line the window cut into.
38 if (false !== $content && false !== strpos($content, "\n")) {
39 $content = substr($content, strpos($content, "\n") + 1);
40 }
41 }
42 } else {
43 $content = @file_get_contents($logFilePath);
44 }
45 if (false === $content || '' === $content) {
46 return $parsedLogs;
47 }
48
49 $logFileHandle = explode("\n", $content);
50
51 foreach ($logFileHandle as $id => $currentLine) {
52 // Normal error log line starts with the date & time in []
53 if ('[' === @$currentLine[0]) {
54 // if (10000 === \count($parsedLogs)) {
55 // return $parsedLogs;
56 // }
57
58 // Get the datetime when the error occurred and convert it to
59 // the site's timezone.
60 try {
61 $dateArr = [];
62 preg_match('~^\[(.*?)\]~', $currentLine, $dateArr);
63 $errorDateTime = '';
64 if (!empty($dateArr[1])) {
65 $currentLine = str_replace($dateArr[0], '', $currentLine);
66 $currentLine = trim($currentLine);
67 $errorDateTime = new DateTime($dateArr[1]);
68 $timezone = function_exists('wp_timezone') ? wp_timezone() : new DateTimeZone('UTC');
69 $errorDateTime->setTimezone($timezone);
70 $errorDateTime = $errorDateTime->format('Y-m-d H:i:s');
71 }
72 } catch (\Exception $e) {
73 $errorDateTime = '';
74 }
75
76 // Get the type of the error
77 if (false !== strpos($currentLine, 'PHP Warning')) {
78 $currentLine = str_replace('PHP Warning:', '', $currentLine);
79 $currentLine = trim($currentLine);
80 $errorType = 'WARNING';
81 } else if (false !== strpos($currentLine, 'PHP Notice')) {
82 $currentLine = str_replace('PHP Notice:', '', $currentLine);
83 $currentLine = trim($currentLine);
84 $errorType = 'NOTICE';
85 } else if (false !== strpos($currentLine, 'PHP Fatal error')) {
86 $currentLine = str_replace('PHP Fatal error:', '', $currentLine);
87 $currentLine = trim($currentLine);
88 $errorType = 'FATAL';
89 } else if (false !== strpos($currentLine, 'PHP Parse error')) {
90 $currentLine = str_replace('PHP Parse error:', '', $currentLine);
91 $currentLine = trim($currentLine);
92 $errorType = 'SYNTAX';
93 } else if (false !== strpos($currentLine, 'PHP Exception')) {
94 $currentLine = str_replace('PHP Exception:', '', $currentLine);
95 $currentLine = trim($currentLine);
96 $errorType = 'EXCEPTION';
97 } else {
98 $errorType = 'UNKNOWN';
99 }
100
101 if (false !== strpos($currentLine, ' on line ')) {
102 $errorLine = explode(' on line ', $currentLine);
103 $errorLine = trim($errorLine[1]);
104 $currentLine = str_replace(' on line ' . $errorLine, '', $currentLine);
105 } else {
106 $errorLine = substr($currentLine, strrpos($currentLine, ':') + 1);
107 $currentLine = str_replace(':' . $errorLine, '', $currentLine);
108 }
109
110 $errorFile = explode(' in /', $currentLine, 2);
111 if (isset($errorFile[1])) {
112 $errorFile = '/' . trim($errorFile[1]);
113 $currentLine = str_replace(' in ' . $errorFile, '', $currentLine);
114 } else {
115 $errorFile = '';
116 }
117
118 // The message of the error
119 $errorMessage = trim($currentLine);
120
121 $parsedLogs[] = [
122 'id' => $id+1,
123 'dateTime' => $errorDateTime,
124 'type' => $errorType,
125 'file' => $errorFile,
126 'line' => (int)$errorLine,
127 'message' => $errorMessage,
128 'stackTrace' => []
129 ];
130 } // Stack trace beginning line
131 else if ('Stack trace:' === $currentLine) {
132 $stackTraceLineNumber = 0;
133
134 foreach ($logFileHandle as $line) {
135 $currentLine = str_replace(PHP_EOL, '', $line);
136
137 // If the current line is a stack trace line
138 if ('#' === $currentLine[0]) {
139 $parsedLogsLastKey = key($parsedLogs);
140 $currentLine = str_replace('#' . $stackTraceLineNumber, '', $currentLine);
141 $parsedLogs[$parsedLogsLastKey]['stackTrace'][] = trim($currentLine);
142
143 $stackTraceLineNumber++;
144 } // If the current line is the last stack trace ('thrown in...')
145 else {
146 break;
147 }
148 }
149 }
150 }
151
152 return $parsedLogs;
153 }
154 }