From f1c72d862b9ecdf7c3971171383366ff68c5af21 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Tue, 9 Jun 2026 05:59:16 -0400 Subject: [PATCH 1/8] Preserve modification time of rotated log files in `FileRotator`. --- CHANGELOG.md | 1 + src/FileRotator.php | 8 ++++++++ tests/FileRotatorTest.php | 31 +++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cd17d6..2da0eb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 3.1.1 under development - Enh #83: Explicitly import classes in "use" section (@mspirkov) +- Bug #84: Preserve modification time of rotated log files in `FileRotator` (@terabytesoftw) ## 3.1.0 December 13, 2025 diff --git a/src/FileRotator.php b/src/FileRotator.php index 3a2d393..0829e6b 100644 --- a/src/FileRotator.php +++ b/src/FileRotator.php @@ -13,6 +13,7 @@ use function fclose; use function feof; use function file_exists; +use function filemtime; use function filesize; use function flock; use function fread; @@ -20,6 +21,7 @@ use function is_file; use function sprintf; use function substr; +use function touch; use function unlink; use const LOCK_EX; @@ -129,6 +131,8 @@ public function shouldRotateFile(string $file): bool */ private function rotate(string $rotateFile, string $newFile): void { + $mTime = @filemtime($rotateFile); + copy($rotateFile, $newFile); if ($this->compressRotatedFiles && !$this->isCompressed($newFile)) { @@ -139,6 +143,10 @@ private function rotate(string $rotateFile, string $newFile): void if ($this->fileMode !== null) { chmod($newFile, $this->fileMode); } + + if ($mTime !== false) { + touch($newFile, $mTime); + } } /** diff --git a/tests/FileRotatorTest.php b/tests/FileRotatorTest.php index 91b83d6..1e1bd28 100644 --- a/tests/FileRotatorTest.php +++ b/tests/FileRotatorTest.php @@ -14,10 +14,13 @@ use function clearstatcache; use function dirname; use function file_get_contents; +use function filemtime; use function filesize; use function mkdir; use function range; use function str_repeat; +use function time; +use function touch; final class FileRotatorTest extends TestCase { @@ -71,6 +74,34 @@ public function testRotate(bool $compress): void } } + /** + * @dataProvider rotateDataProvider + */ + public function testRotatePreservesModificationTime(bool $compress): void + { + $rotator = new FileRotator(1, 2, null, $compress); + $logFile = $this->getLogFilePath(); + $fileTarget = new FileTarget($logFile, $rotator); + $logger = new Logger([$fileTarget]); + $compressExtension = $compress ? '.gz' : ''; + + $logger->debug($this->generateKilobytesOfData(1)); + $logger->flush(true); + + $expectedTime = time() - 7200; + touch($logFile, $expectedTime); + clearstatcache(); + + $logger->debug('x'); + $logger->flush(true); + + clearstatcache(); + + $rotatedFile = "{$logFile}.1{$compressExtension}"; + $this->assertFileExists($rotatedFile); + $this->assertSame($expectedTime, filemtime($rotatedFile)); + } + /** * @dataProvider rotateDataProvider */ From 2264a9e259a3cbd8b74392b7153bf45b296f6858 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Tue, 9 Jun 2026 06:21:38 -0400 Subject: [PATCH 2/8] Fix modification time preservation for rotated log files in `FileRotator`. --- src/FileRotator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FileRotator.php b/src/FileRotator.php index 0829e6b..42910fb 100644 --- a/src/FileRotator.php +++ b/src/FileRotator.php @@ -133,7 +133,7 @@ private function rotate(string $rotateFile, string $newFile): void { $mTime = @filemtime($rotateFile); - copy($rotateFile, $newFile); + $copied = copy($rotateFile, $newFile); if ($this->compressRotatedFiles && !$this->isCompressed($newFile)) { $this->compress($newFile); @@ -144,7 +144,7 @@ private function rotate(string $rotateFile, string $newFile): void chmod($newFile, $this->fileMode); } - if ($mTime !== false) { + if ($copied && $mTime !== false) { touch($newFile, $mTime); } } From adbb81c9574f496c67236f8d6e273cbdb76f19a4 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Tue, 9 Jun 2026 06:23:47 -0400 Subject: [PATCH 3/8] Fix error typo. --- src/FileRotator.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FileRotator.php b/src/FileRotator.php index 42910fb..1c353b7 100644 --- a/src/FileRotator.php +++ b/src/FileRotator.php @@ -132,7 +132,6 @@ public function shouldRotateFile(string $file): bool private function rotate(string $rotateFile, string $newFile): void { $mTime = @filemtime($rotateFile); - $copied = copy($rotateFile, $newFile); if ($this->compressRotatedFiles && !$this->isCompressed($newFile)) { From 1d12ad3ce82a6d559f841b57869d6a1de61339f4 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Tue, 9 Jun 2026 06:47:42 -0400 Subject: [PATCH 4/8] Update `rector-cs-yml`. --- .github/workflows/rector-cs.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/rector-cs.yml b/.github/workflows/rector-cs.yml index de7ea7f..6dbf1df 100644 --- a/.github/workflows/rector-cs.yml +++ b/.github/workflows/rector-cs.yml @@ -12,7 +12,7 @@ on: - '.php-cs-fixer.dist.php' permissions: - contents: read + contents: write concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -21,8 +21,5 @@ concurrency: jobs: rector: uses: yiisoft/actions/.github/workflows/rector-cs.yml@master - secrets: - token: ${{ secrets.YIISOFT_GITHUB_TOKEN }} with: - repository: ${{ github.event.pull_request.head.repo.full_name }} php: '8.0' From 0c50fbceb2a64eac93be00b7280d17355075e376 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Tue, 9 Jun 2026 06:56:34 -0400 Subject: [PATCH 5/8] Update `rector-cs-yml`. --- .github/workflows/rector-cs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rector-cs.yml b/.github/workflows/rector-cs.yml index 6dbf1df..192dc43 100644 --- a/.github/workflows/rector-cs.yml +++ b/.github/workflows/rector-cs.yml @@ -1,7 +1,7 @@ name: Rector + PHP CS Fixer on: - pull_request_target: + pull_request: paths: - 'config/**' - 'src/**' From cf22a246d9fbed8fa0bab43eb4aa4c450d165ada Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Tue, 9 Jun 2026 11:06:09 -0400 Subject: [PATCH 6/8] Remove `@` in `filetime()` function. --- src/FileRotator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FileRotator.php b/src/FileRotator.php index 1c353b7..981e778 100644 --- a/src/FileRotator.php +++ b/src/FileRotator.php @@ -131,7 +131,7 @@ public function shouldRotateFile(string $file): bool */ private function rotate(string $rotateFile, string $newFile): void { - $mTime = @filemtime($rotateFile); + $mTime = filemtime($rotateFile); $copied = copy($rotateFile, $newFile); if ($this->compressRotatedFiles && !$this->isCompressed($newFile)) { From 5c6b2b7c90601024e95783de0e10437bcc0dc603 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Wed, 10 Jun 2026 07:48:23 -0400 Subject: [PATCH 7/8] Appy fixed review. --- src/FileRotator.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/FileRotator.php b/src/FileRotator.php index 981e778..ad34c8f 100644 --- a/src/FileRotator.php +++ b/src/FileRotator.php @@ -132,7 +132,10 @@ public function shouldRotateFile(string $file): bool private function rotate(string $rotateFile, string $newFile): void { $mTime = filemtime($rotateFile); - $copied = copy($rotateFile, $newFile); + + if (copy($rotateFile, $newFile) === false) { + return; + } if ($this->compressRotatedFiles && !$this->isCompressed($newFile)) { $this->compress($newFile); @@ -143,7 +146,7 @@ private function rotate(string $rotateFile, string $newFile): void chmod($newFile, $this->fileMode); } - if ($copied && $mTime !== false) { + if ($mTime !== false) { touch($newFile, $mTime); } } From 2296825d753bfa6f0af29699e7fe5d02f6d20028 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Fri, 12 Jun 2026 08:54:06 -0400 Subject: [PATCH 8/8] Apply fixed more review. --- src/FileRotator.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/FileRotator.php b/src/FileRotator.php index ad34c8f..83da6c8 100644 --- a/src/FileRotator.php +++ b/src/FileRotator.php @@ -133,9 +133,7 @@ private function rotate(string $rotateFile, string $newFile): void { $mTime = filemtime($rotateFile); - if (copy($rotateFile, $newFile) === false) { - return; - } + copy($rotateFile, $newFile); if ($this->compressRotatedFiles && !$this->isCompressed($newFile)) { $this->compress($newFile);