$p, 'status' => 'missing', 'note' => '']; if (@file_exists($p)) { if (!@is_readable($p)) { $entry['status'] = 'unreadable'; $entry['note'] = 'File exists but PHP cannot read it (check permissions).'; } else { $entry['status'] = 'found'; $entry['size'] = (int) @filesize($p); $entry['mtime'] = (int) @filemtime($p); if ($found === null) $found = $p; } } else { $entry['note'] = 'Not found.'; } $checks[] = $entry; } // Build a one-line summary if ($found) { $summary = 'Log file found.'; $verdict = 'found'; } elseif (!$debug_log_const) { $summary = 'WP_DEBUG_LOG is off, so WordPress is not writing a log. If your host writes PHP errors somewhere else, point WP_DEBUG_LOG at that path (or check your host control panel).'; $verdict = 'disabled'; } else { $summary = "WP_DEBUG_LOG is on but no log file has been created — your site hasn't logged any PHP errors recently. That's usually a good thing. If you expected errors and don't see them, your host may be writing logs to a path we don't check (check your hosting control panel for an error_log location)."; $verdict = 'empty'; } return [ 'constants' => [ 'WP_DEBUG' => $debug_const, 'WP_DEBUG_LOG' => $debug_log_const, 'WP_DEBUG_DISPLAY' => $debug_display_const, ], 'wp_debug_log_value' => defined('WP_DEBUG_LOG') ? WP_DEBUG_LOG : null, 'ini_error_log' => ini_get('error_log') ?: null, 'checks' => $checks, 'found' => $found, 'summary' => $summary, 'verdict' => $verdict, ]; } // Returns last $lines lines, newest first public static function tail(string $path, int $lines = 150): array { if (!self::_pro()) return []; if (!@file_exists($path) || !@is_readable($path)) return []; $file = new SplFileObject($path, 'r'); $file->seek(PHP_INT_MAX); $total = $file->key(); $start = max(0, $total - $lines); $result = []; $file->seek($start); while (!$file->eof()) { $line = rtrim((string) $file->current(), "\r\n"); if ($line !== '') $result[] = $line; $file->next(); } return array_reverse($result); } public static function size(string $path): int { return @file_exists($path) ? (int) @filesize($path) : 0; } public static function clear(string $path): bool { if (!self::_pro()) return false; if (!@file_exists($path) || !@is_writable($path)) return false; return (bool) @file_put_contents($path, ''); } public static function format_bytes(int $bytes): string { if ($bytes >= 1048576) return round($bytes / 1048576, 2) . ' MB'; if ($bytes >= 1024) return round($bytes / 1024, 1) . ' KB'; return $bytes . ' B'; } // Counts PHP error log lines stamped with today's date. // Free-safe: returns 0 if no log discovered. Reads only the tail (~512 KB) to stay cheap on huge logs. public static function today_count(?string $path = null): int { $path = $path ?? self::find_path(); if (!$path || !@is_readable($path)) return 0; $size = (int) @filesize($path); if ($size <= 0) return 0; $chunk = 512 * 1024; $offset = max(0, $size - $chunk); $fh = @fopen($path, 'rb'); if (!$fh) return 0; @fseek($fh, $offset); $data = @fread($fh, $chunk); @fclose($fh); if ($data === false || $data === '') return 0; // PHP error log lines start with: "[DD-Mon-YYYY HH:MM:SS TZ] ..." // Use local date — error_log writes timestamps in PHP's configured timezone. $today = date('d-M-Y'); $count = preg_match_all('/^\[' . preg_quote($today, '/') . ' /m', $data); return (int) $count; } // Classifies a log line for color-coding public static function classify(string $line): string { $l = strtolower($line); if (strpos($l, 'fatal error') !== false || strpos($l, 'uncaught') !== false) return 'log-fatal'; if (strpos($l, 'parse error') !== false) return 'log-fatal'; if (strpos($l, 'warning') !== false) return 'log-warning'; if (strpos($l, 'notice') !== false || strpos($l, 'deprecated') !== false) return 'log-notice'; if (strpos($l, 'wp_debug') !== false || strpos($l, '[debug]') !== false) return 'log-debug'; return 'log-default'; } }