Skip to content

Commit d83a5be

Browse files
authored
Merge pull request #263 from opcodesio/bug/handle-inaccessible-files
handle inaccessible files
2 parents 85f7389 + b260fc1 commit d83a5be

File tree

8 files changed

+82
-4
lines changed

8 files changed

+82
-4
lines changed

src/Concerns/LogReader/KeepsFileHandle.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ protected function openFile(): static
4141
return $this;
4242
}
4343

44-
$this->fileHandle = fopen($this->file->path, 'r');
44+
try {
45+
$this->fileHandle = fopen($this->file->path, 'r');
46+
} catch (\ErrorException $exception) {
47+
throw new CannotOpenFileException('Could not open "'.$this->file->path.'" for reading.', 0, $exception);
48+
}
4549

4650
if ($this->fileHandle === false) {
4751
throw new CannotOpenFileException('Could not open "'.$this->file->path.'" for reading.');

src/LogFile.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Support\Arr;
66
use Opcodes\LogViewer\Events\LogFileDeleted;
7+
use Opcodes\LogViewer\Exceptions\CannotOpenFileException;
78
use Opcodes\LogViewer\Exceptions\InvalidRegularExpression;
89
use Opcodes\LogViewer\Facades\LogViewer;
910
use Opcodes\LogViewer\Logs\LogType;
@@ -118,7 +119,12 @@ public function getFirstLine(): string
118119

119120
public function getNthLine(int $lineNumber): string
120121
{
121-
$handle = fopen($this->path, 'r');
122+
try {
123+
$handle = fopen($this->path, 'r');
124+
} catch (\ErrorException $e) {
125+
throw new CannotOpenFileException('Could not open "'.$this->path.'" for reading.', 0, $e);
126+
}
127+
122128
$line = '';
123129
for ($i = 0; $i < $lineNumber; $i++) {
124130
$line = fgets($handle);

src/LogTypeRegistrar.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Opcodes\LogViewer;
44

5+
use Opcodes\LogViewer\Exceptions\CannotOpenFileException;
56
use Opcodes\LogViewer\Exceptions\SkipLineException;
67
use Opcodes\LogViewer\Logs\HorizonLog;
78
use Opcodes\LogViewer\Logs\HorizonOldLog;
@@ -58,7 +59,11 @@ public function guessTypeFromFirstLine(LogFile|string $textOrFile): ?string
5859
{
5960
if ($textOrFile instanceof LogFile) {
6061
$file = $textOrFile;
61-
$textOrFile = $textOrFile->getFirstLine();
62+
try {
63+
$textOrFile = $textOrFile->getFirstLine();
64+
} catch (CannotOpenFileException $exception) {
65+
return null;
66+
}
6267
}
6368

6469
foreach ($this->logTypes as [$type, $class]) {
@@ -74,6 +79,8 @@ public function guessTypeFromFirstLine(LogFile|string $textOrFile): ?string
7479
if ($class::matches($file->getNthLine($lineNumber))) {
7580
return $type;
7681
}
82+
} catch (CannotOpenFileException $exception) {
83+
return null;
7784
} catch (SkipLineException $exception) {
7885
continue;
7986
}

src/Readers/MultipleLogReader.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Illuminate\Pagination\LengthAwarePaginator;
66
use Illuminate\Pagination\Paginator;
77
use Opcodes\LogViewer\Direction;
8+
use Opcodes\LogViewer\Exceptions\CannotOpenFileException;
89
use Opcodes\LogViewer\Facades\LogViewer;
910
use Opcodes\LogViewer\LevelCount;
1011
use Opcodes\LogViewer\LogFile;
@@ -218,7 +219,11 @@ public function scan(int $maxBytesToScan = null, bool $force = false): void
218219

219220
$fileSizeScanned += $logQuery->numberOfNewBytes();
220221

221-
$logQuery->scan($maxBytesToScan, $force);
222+
try {
223+
$logQuery->scan($maxBytesToScan, $force);
224+
} catch (CannotOpenFileException $exception) {
225+
continue;
226+
}
222227

223228
if (isset($maxBytesToScan) && $fileSizeScanned >= $maxBytesToScan) {
224229
break;

tests/Pest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
uses(TestCase::class)->in(__DIR__);
1212
uses()->afterEach(fn () => clearGeneratedLogFiles())->in('Feature', 'Unit');
1313
uses()->beforeEach(fn () => Artisan::call('log-viewer:publish'))->in('Feature');
14+
uses()->beforeEach(function () {
15+
// let's not include any of the default mac logs or similar
16+
config(['log-viewer.include_files' => ['*.log', '**/*.log']]);
17+
})->in('Unit', 'Feature');
1418

1519
/*
1620
|--------------------------------------------------------------------------

tests/Unit/CustomLogs/ExtendableLogReaderTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@
5454
],
5555
]);
5656

57+
it('handles unaccessible files', function () {
58+
if (PHP_OS_FAMILY === 'Windows') {
59+
$this->markTestSkipped('File permissions work differently on Windows. The feature tested might still work.');
60+
}
61+
62+
$file = generateLogFile(randomContent: true);
63+
chmod($file->path, 0333); // prevent reading
64+
65+
expect($this->logRegistrar->guessTypeFromFirstLine($file))
66+
->toBeNull();
67+
});
68+
5769
it('prefers user-defined log types over default ones', function () {
5870
// first, the default http access log
5971
$defaultAccessLogLine = '8.68.121.11 - UID 123 - [01/Feb/2023:01:53:51 +0000] "POST /main/tag/category HTTP/2.0" 404 4819 "-" "-"';

tests/Unit/LogReaderTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22

33
use Illuminate\Support\Facades\File;
4+
use Opcodes\LogViewer\Exceptions\CannotOpenFileException;
45
use Opcodes\LogViewer\Readers\IndexedLogReader;
56

67
beforeEach(function () {
@@ -40,3 +41,14 @@
4041
->and($index->count())->toBe(2)
4142
->and($index->getFlatIndex())->toHaveCount(2);
4243
});
44+
45+
it('throws an exception when file cannot be opened for reading', function () {
46+
if (PHP_OS_FAMILY === 'Windows') {
47+
$this->markTestSkipped('File permissions work differently on Windows. The feature tested might still work.');
48+
}
49+
50+
chmod($this->file->path, 0333); // prevent reading
51+
$logReader = $this->file->logs();
52+
53+
$logReader->scan();
54+
})->expectException(CannotOpenFileException::class);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
use Opcodes\LogViewer\Facades\LogViewer;
4+
5+
it('continues reading when one file cannot be read', function () {
6+
if (PHP_OS_FAMILY === 'Windows') {
7+
$this->markTestSkipped('File permissions work differently on Windows. The feature tested might still work.');
8+
}
9+
10+
$files = [
11+
generateLogFile(randomContent: true),
12+
generateLogFile(randomContent: true),
13+
generateLogFile(randomContent: true),
14+
];
15+
16+
$filesFound = LogViewer::getFiles();
17+
expect($filesFound->count())->toBe(3);
18+
19+
chmod($files[1]->path, 0333); // prevent reading
20+
21+
try {
22+
$filesFound->logs()->scan();
23+
24+
$this->assertTrue(true);
25+
} catch (\Exception $exception) {
26+
$this->fail('Exception thrown: '.$exception->getMessage());
27+
}
28+
});

0 commit comments

Comments
 (0)