diff options
| author | Christoph Brill <opensource@christophbrill.de> | 2026-08-03 00:39:30 +0200 |
|---|---|---|
| committer | Christoph Brill <opensource@christophbrill.de> | 2026-08-03 00:39:30 +0200 |
| commit | 54453658f6fe48cd2288dc06345e76331ca361e3 (patch) | |
| tree | bde9cefcee1a168e47bdc029f455743b29efdb72 | |
| parent | da855f9dc4e8c9e230af2c578fd458e734341b9f (diff) | |
Read the logs line by line instead of loading them into an array
| -rw-r--r-- | common.inc.php | 27 | ||||
| -rw-r--r-- | details.php | 8 | ||||
| -rwxr-xr-x | json.php | 10 | ||||
| -rw-r--r-- | stats.php | 8 |
4 files changed, 31 insertions, 22 deletions
diff --git a/common.inc.php b/common.inc.php index a54fa0f..9b1b465 100644 --- a/common.inc.php +++ b/common.inc.php @@ -86,6 +86,33 @@ function validDate($date) } /** + * Read a log file line by line + * + * Reading the whole log using file() keeps every single line in memory at once, + * which for a busy day is several megabytes. All callers only walk the lines + * once and in order, so hand them out one at a time instead. A missing file + * yields nothing, the callers render their usual empty result in that case. + * + * @param string $filename the log file to read + * + * @return Generator the lines of the log, including their line endings + */ +function readLog($filename) +{ + $handle = @fopen($filename, 'r'); + if ($handle === false) { + return; + } + try { + while (($line = fgets($handle)) !== false) { + yield $line; + } + } finally { + fclose($handle); + } +} + +/** * Get the date from a filename * * @param string $filename the filename to extract the month from (e.g. diff --git a/details.php b/details.php index c7fc387..1d93516 100644 --- a/details.php +++ b/details.php @@ -34,14 +34,8 @@ $filename = 'dri-devel-'.$date.'.log'; $pattern = '#(^|[^\"=]{1})(http://|ftp://|https://|mailto:|news:)([^\s<>]+)([\s\n<>]|$)#sm'; $timehashes = array(); -// Guard the read, a missing log would otherwise leak the full path on disk -if (file_exists(LOG_DIR.$filename)) { - $lines = file(LOG_DIR.$filename); -} else { - $lines = array(); -} $anything_displayed = false; -foreach ($lines as $line_num => $line) { +foreach (readLog(LOG_DIR.$filename) as $line) { if (isFromChannel($line, $channel)) { if (!filterJoin($line)) { $user = getUser($line); @@ -39,13 +39,7 @@ if (!isset($_GET['mode'])) { require_once 'common.inc.php'; -// Read all lines of the log into an array $filename = 'dri-devel-'.$date.'.log'; -if (file_exists(LOG_DIR.$filename)) { - $lines = file(LOG_DIR.$filename); -} else { - $lines = array(); -} header("Content-type: application/json;"); @@ -80,7 +74,7 @@ case 'watch': } // Assign all lines to a user - foreach ($lines as $line_num => $line) { + foreach (readLog(LOG_DIR.$filename) as $line) { if (isFromChannel($line, $channel)) { if (!filterJoin($line)) { $user = substr(getUser($line), 2, -1); @@ -124,7 +118,7 @@ case 'watch': case 'show': $retval['users'] = array(); $retval['data'] = array(); - foreach ($lines as $line_num => $line) { + foreach (readLog(LOG_DIR.$filename) as $line) { if (isFromChannel($line, $channel)) { if (!filterJoin($line)) { $user = substr(getUser($line), 2, -1); @@ -35,18 +35,12 @@ if (!isset($_GET['date'])) { require_once 'common.inc.php'; -// Read all lines of the log into an array $filename = 'dri-devel-'.$date.'.log'; -if (file_exists(LOG_DIR.$filename)) { - $lines = file(LOG_DIR.$filename); -} else { - $lines = array(); -} $retval = array(); echo '<pre>'; -foreach ($lines as $line) { +foreach (readLog(LOG_DIR.$filename) as $line) { $user = substr(getUser($line), 2, -1); if ($user) { if (in_array($user, $ignore)) { |
