diff --git a/wire/core/FileLog.php b/wire/core/FileLog.php index ed99d2df..ea59a076 100644 --- a/wire/core/FileLog.php +++ b/wire/core/FileLog.php @@ -5,7 +5,7 @@ * * Creates and maintains a text-based log file. * - * ProcessWire 3.x, Copyright 2016 by Ryan Cramer + * ProcessWire 3.x, Copyright 2023 by Ryan Cramer * https://processwire.com * */ @@ -89,6 +89,7 @@ class FileLog extends Wire { * */ public function __construct($path, $identifier = '') { + parent::__construct(); if($identifier) { $path = rtrim($path, '/') . '/'; @@ -98,19 +99,32 @@ class FileLog extends Wire { $path = dirname($path) . '/'; } $this->path = $path; - if(!is_dir($path)) $this->wire('files')->mkdir($path); } - - public function __get($key) { - if($key == 'delimiter') return $this->delimeter; // @todo learn how to spell - return parent::__get($key); + + /** + * Wired to API + * + */ + public function wired() { + parent::wired(); + $this->path(); + } + + /** + * @param string $name + * @return mixed + * + */ + public function __get($name) { + if($name == 'delimiter') return $this->delimeter; // @todo learn how to spell + return parent::__get($name); } /** * Clean a string for use in a log file entry * * @param $str - * @return mixed|string + * @return string * */ protected function cleanStr($str) { @@ -219,7 +233,7 @@ class FileLog extends Wire { // if we were creating the file, make sure it has the right permission if($mode === 'w') { - $files = $this->wire('files'); /** @var WireFileTools $files */ + $files = $this->wire()->files; $files->chmod($this->logFilename); } @@ -271,18 +285,42 @@ class FileLog extends Wire { } } + /** + * Get filesize + * + * @return int|false + * + */ public function size() { return filesize($this->logFilename); } + /** + * Get file basename + * + * @return string + * + */ public function filename() { return basename($this->logFilename); } + /** + * Get file pathname + * + * @return string|bool + * + */ public function pathname() { return $this->logFilename; } + /** + * Get file modification time + * + * @return int|false + * + */ public function mtime() { return filemtime($this->logFilename); } @@ -483,7 +521,7 @@ class FileLog extends Wire { } if($options['toFile']) { - $toFile = $this->path . basename($options['toFile']); + $toFile = $this->path() . basename($options['toFile']); $fp = fopen($toFile, 'w'); if(!$fp) throw new \Exception("Unable to open file for writing: $toFile"); } else { @@ -536,7 +574,7 @@ class FileLog extends Wire { if($fp) { fclose($fp); - $this->wire('files')->chmod($toFile); + $this->wire()->files->chmod($toFile); return $cnt; } @@ -553,8 +591,7 @@ class FileLog extends Wire { * @param $line * @param array $options * @param bool $stopNow Populates this with true when it can determine no more lines are necessary. - * @return bool|int Returns boolean true if valid, false if not. - * If valid as a result of a date comparison, the unix timestmap for the line is returned. + * @return bool Returns boolean true if valid, false if not. * */ protected function isValidLine($line, array $options, &$stopNow) { @@ -623,13 +660,15 @@ class FileLog extends Wire { fclose($fpw); fclose($fpr); + + $files = $this->wire()->files; if($cnt) { - $this->wire('files')->unlink($filename, true); - $this->wire('files')->rename("$filename.new", $filename, true); - $this->wire('files')->chmod($filename); + $files->unlink($filename, true); + $files->rename("$filename.new", $filename, true); + $files->chmod($filename); } else { - $this->wire('files')->unlink("$filename.new", true); + $files->unlink("$filename.new", true); } return $cnt; @@ -651,8 +690,9 @@ class FileLog extends Wire { 'dateTo' => time(), )); if(file_exists($toFile)) { - $this->wire('files')->unlink($this->logFilename, true); - $this->wire('files')->rename($toFile, $this->logFilename, true); + $files = $this->wire()->files; + $files->unlink($this->logFilename, true); + $files->rename($toFile, $this->logFilename, true); return $qty; } return 0; @@ -665,7 +705,7 @@ class FileLog extends Wire { * */ public function delete() { - return $this->wire('files')->unlink($this->logFilename, true); + return $this->wire()->files->unlink($this->logFilename, true); } public function __toString() { @@ -704,6 +744,16 @@ class FileLog extends Wire { if($chunkSize > 0) $this->chunkSize = (int) $chunkSize; return $this->chunkSize; } + + /** + * Get path where the log is stored (with trailing slash) + * @return string + * + */ + public function path() { + if(!is_dir($this->path)) $this->wire()->files->mkdir($this->path); + return $this->path; + } } diff --git a/wire/core/WireLog.php b/wire/core/WireLog.php index d0cf140a..6443ad63 100644 --- a/wire/core/WireLog.php +++ b/wire/core/WireLog.php @@ -8,7 +8,7 @@ * * #pw-summary Enables creation of logs, logging of events, and management of logs. * - * ProcessWire 3.x, Copyright 2019 by Ryan Cramer + * ProcessWire 3.x, Copyright 2023 by Ryan Cramer * https://processwire.com * * @method bool save($name, $text, $options = array()) @@ -139,14 +139,15 @@ class WireLog extends Wire { if($options['url']) { $url = $options['url']; } else { - $input = $this->wire('input'); + $input = $this->wire()->input; + $sanitizer = $this->wire()->sanitizer; $url = $input ? $input->httpUrl() : ''; if(strlen($url) && $input) { if(count($input->get)) { $url .= "?"; foreach($input->get as $k => $v) { - $k = $this->wire('sanitizer')->name($k); - $v = $this->wire('sanitizer')->name($v); + $k = $sanitizer->name($k); + $v = $sanitizer->name($v); $url .= "$k=$v&"; } $url = rtrim($url, "&"); @@ -201,7 +202,8 @@ class WireLog extends Wire { /** * Return array of all logs, sorted by name * - * Each log entry is an array that includes the following: + * Each item in returned array is an associative array that includes the following: + * * - `name` (string): Name of log file, excluding extension. * - `file` (string): Full path and filename of log file. * - `size` (int): Size in bytes @@ -216,13 +218,8 @@ class WireLog extends Wire { public function getLogs($sortNewest = false) { $logs = array(); - $dir = new \DirectoryIterator($this->wire('config')->paths->logs); - foreach($dir as $file) { - if($file->isDot() || $file->isDir()) continue; - if($file->getExtension() != $this->logExtension) continue; - $name = basename($file, '.' . $this->logExtension); - if($name != $this->wire('sanitizer')->pageName($name)) continue; + foreach($this->getFiles() as $name => $file) { if($sortNewest) { $sortKey = $file->getMTime(); @@ -245,7 +242,7 @@ class WireLog extends Wire { ksort($logs); } - return $logs; + return array_values($logs); } /** @@ -260,10 +257,37 @@ class WireLog extends Wire { */ public function getFilename($name) { $name = strtolower($name); - if($name !== $this->wire('sanitizer')->pageName($name)) { + if($name !== $this->wire()->sanitizer->pageName($name)) { throw new WireException("Log name must contain only [-_.a-z0-9] with no extension"); } - return $this->wire('config')->paths->logs . $name . '.' . $this->logExtension; + return $this->path() . $name . '.' . $this->logExtension; + } + + /** + * Get SplFileInfo objects for each log file indexed by log name + * + * #pw-internal + * + * @return \SplFileInfo[] + * @throws WireException + * @since 3.0.214 + * + */ + public function getFiles() { + + $dir = new \DirectoryIterator($this->path()); + $sanitizer = $this->wire()->sanitizer; + $files = array(); + + foreach($dir as $file) { + if($file->isDot() || $file->isDir()) continue; + if($file->getExtension() != $this->logExtension) continue; + $name = $file->getBasename(".$this->logExtension"); + if($name != $sanitizer->pageName($name)) continue; + $files[$name] = $file; + } + + return $files; } /** @@ -299,7 +323,7 @@ class WireLog extends Wire { * */ public function getLines($name, array $options = array()) { - $pageNum = !empty($options['pageNum']) ? $options['pageNum'] : $this->wire('input')->pageNum; + $pageNum = !empty($options['pageNum']) ? $options['pageNum'] : $this->wire()->input->pageNum; unset($options['pageNum']); $log = $this->getFileLog($name); $limit = isset($options['limit']) ? (int) $options['limit'] : 100; @@ -334,7 +358,7 @@ class WireLog extends Wire { $log = $this->getFileLog($name); $limit = isset($options['limit']) ? $options['limit'] : 100; - $pageNum = !empty($options['pageNum']) ? $options['pageNum'] : $this->wire('input')->pageNum; + $pageNum = !empty($options['pageNum']) ? $options['pageNum'] : $this->wire()->input->pageNum; unset($options['pageNum']); $lines = $log->find($limit, $pageNum, $options); @@ -446,7 +470,7 @@ class WireLog extends Wire { */ public function getDate($name, $dateFrom, $dateTo = 0, $limit = 100) { $log = $this->getFileLog($name); - $pageNum = $this->wire('input')->pageNum(); + $pageNum = $this->wire()->input->pageNum(); return $log->getDate($dateFrom, $dateTo, $pageNum, $limit); } @@ -466,6 +490,35 @@ class WireLog extends Wire { return false; } + /** + * Delete all log files + * + * @param bool $throw Throw WireException if any delete fails? (default=false) + * @return array Basenames of deleted log files + * @since 3.0.214 + * + */ + public function deleteAll($throw = false) { + + $deleted = array(); + $failed = array(); + + foreach($this->getFiles() as $name => $file) { + $log = $this->getFileLog($name); + if($log && $log->delete()) { + $deleted[] = $name; + } else { + $failed[] = $name; + } + } + + if($throw && count($failed)) { + throw new WireException("Failed to delete logs: " . implode(', ', $failed)); + } + + return $deleted; + } + /** * Prune log file to contain only entries from last [n] days * @@ -473,7 +526,7 @@ class WireLog extends Wire { * * @param string $name Name of log file, excluding path and extension. * @param int $days Number of days - * @return int Number of items in new log file or boolean false on failure + * @return int Number of items in newly pruned log file or boolean false on failure * @throws WireException * */ @@ -485,6 +538,22 @@ class WireLog extends Wire { return $log->pruneDate($oldestDate); } + /** + * Prune all log files to given number of days + * + * @param int $days + * @return array + * @since 3.0.214 + * + */ + public function pruneAll($days) { + $result = array(); + foreach($this->getFiles() as $name => $filename) { + $result[$name] = $this->prune($name, $days); + } + return $result; + } + /** * Returns instance of FileLog for given log name * @@ -500,6 +569,7 @@ class WireLog extends Wire { $filename = $this->getFilename($name); $key = "$filename$delimiter"; if(isset($this->fileLogs[$key])) return $this->fileLogs[$key]; + /** @var FileLog $log */ $log = $this->wire(new FileLog($filename)); $log->setDelimiter($delimiter); $this->fileLogs[$key] = $log; @@ -534,4 +604,14 @@ class WireLog extends Wire { return $this; } + /** + * Return disk path to log files + * + * @return string + * @since 3.0.214 + * + */ + public function path() { + return $this->wire()->config->paths->logs; + } }