| @@ -12,10 +12,43 @@ | ||
| 12 | 12 | } |
| 13 | 13 | |
| 14 | 14 | public function getParsedLogFile() { |
| 15 | 15 | $parsedLogs = []; |
| 16 | - $logFileHandle = explode("\n", file_get_contents($this->logFilePath)); | |
| 16 | + $logFilePath = $this->logFilePath; | |
| 17 | 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 | + | |
| 18 | 51 | foreach ($logFileHandle as $id => $currentLine) { |
| 19 | 52 | // Normal error log line starts with the date & time in [] |
| 20 | 53 | if ('[' === @$currentLine[0]) { |
| 21 | 54 | // if (10000 === \count($parsedLogs)) { |
| @@ -21,17 +54,22 @@ | ||
| 21 | 54 | // if (10000 === \count($parsedLogs)) { |
| 22 | 55 | // return $parsedLogs; |
| 23 | 56 | // } |
| 24 | 57 | |
| 25 | - // Get the datetime when the error occurred and convert it to berlin timezone | |
| 58 | + // Get the datetime when the error occurred and convert it to | |
| 59 | + // the site's timezone. | |
| 26 | 60 | try { |
| 27 | 61 | $dateArr = []; |
| 28 | 62 | preg_match('~^\[(.*?)\]~', $currentLine, $dateArr); |
| 29 | - $currentLine = str_replace($dateArr[0], '', $currentLine); | |
| 30 | - $currentLine = trim($currentLine); | |
| 31 | - $errorDateTime = new DateTime($dateArr[1]); | |
| 32 | - $errorDateTime->setTimezone(new DateTimeZone('Europe/Berlin')); | |
| 33 | - $errorDateTime = $errorDateTime->format('Y-m-d H:i:s'); | |
| 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 | + } | |
| 34 | 72 | } catch (\Exception $e) { |
| 35 | 73 | $errorDateTime = ''; |
| 36 | 74 | } |
| 37 | 75 | |
| @@ -68,11 +106,15 @@ | ||
| 68 | 106 | $errorLine = substr($currentLine, strrpos($currentLine, ':') + 1); |
| 69 | 107 | $currentLine = str_replace(':' . $errorLine, '', $currentLine); |
| 70 | 108 | } |
| 71 | 109 | |
| 72 | - $errorFile = explode(' in /', $currentLine); | |
| 73 | - $errorFile = '/' . trim($errorFile[1]); | |
| 74 | - $currentLine = str_replace(' in ' . $errorFile, '', $currentLine); | |
| 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 | + } | |
| 75 | 117 | |
| 76 | 118 | // The message of the error |
| 77 | 119 | $errorMessage = trim($currentLine); |
| 78 | 120 | |