diff --git a/src/StreamWrapper.php b/src/StreamWrapper.php index 21159ea..9d54992 100644 --- a/src/StreamWrapper.php +++ b/src/StreamWrapper.php @@ -258,14 +258,37 @@ public function stream_open( $this->log('info', __METHOD__, func_get_args()); $this->path = $path; $this->mode = $mode; + + // Attempt to open for reading if mode is read or read/write + if (strpbrk($mode, 'r+') !== false) { + try { + $this->openRead(); + } catch (\Throwable $e) { + $this->log('error', __METHOD__, ['exception' => $e]); + return false; + } + } + return true; } - public function stream_read(int $count): string + /** + * @param int $count + * + * @return false|string + */ + public function stream_read(int $count) { $this->log('info', __METHOD__, func_get_args()); - $this->openRead(); - return stream_get_contents($this->read, $count); + try { + $this->openRead(); + return stream_get_contents($this->read, $count); + } catch (Throwable $e) { + $this->log('error', __METHOD__, func_get_args() + [ + 'exception' => $e, + ]); + return false; + } } public function stream_seek(int $offset, int $whence = SEEK_SET): bool @@ -297,8 +320,15 @@ public function stream_set_option(int $option, int $arg1, ?int $arg2 = null): bo public function stream_stat() { $this->log('info', __METHOD__); - $this->openRead(); - return fstat($this->read); + try { + $this->openRead(); + return fstat($this->read); + } catch (Throwable $e) { + $this->log('error', __METHOD__, func_get_args() + [ + 'exception' => $e, + ]); + return false; + } } public function stream_tell(): int diff --git a/tests/StreamWrapperTest.php b/tests/StreamWrapperTest.php index 8daf8d1..203565f 100644 --- a/tests/StreamWrapperTest.php +++ b/tests/StreamWrapperTest.php @@ -119,6 +119,8 @@ function dumpLogs() }); it('can acquire multiple shared locks', function () { + touch('fly://foo'); + $stream1 = fopen('fly://foo', 'r'); $result = flock($stream1, LOCK_SH); expect($result)->toBeTrue(); @@ -148,6 +150,8 @@ function dumpLogs() }); it('cannot acquire an exclusive lock with existing locks', function () { + touch('fly://foo'); + $stream1 = fopen('fly://foo', 'r'); $result = flock($stream1, LOCK_SH); expect($result)->toBeTrue(); @@ -277,3 +281,9 @@ function dumpLogs() expect($actual)->toBe($expected); }); + +it('fails attempting to read a missing file', function () { + $actual = @file_get_contents("fly://doesnotexist.txt"); + + expect($actual)->toBe(false); +});