Skip to content

Commit b97e4a2

Browse files
committed
Fix issue with Stream
fopen would fail to create a file if it didn't exist in write mode. However touch was working for same file Locator returned null because it couldn't find the file to be created All can't be set on read because you do want to read across all sprinkle In write mode, you'll write to the first location anyways
1 parent 6078a01 commit b97e4a2

File tree

2 files changed

+68
-5
lines changed

2 files changed

+68
-5
lines changed

src/UniformResourceLocator/StreamWrapper/Stream.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,23 @@ public static function setLocator(ResourceLocatorInterface $locator): void
4141
*/
4242
public function stream_open(string $uri, string $mode, int $options, ?string &$opened_path): bool
4343
{
44-
$path = $this->findPath($uri);
44+
// In write mode, we want to write to the first existing path (should
45+
// be a shared location) because fopen will attempts to create the file.
46+
// Otherwise, we need to find the first found path, across location.
47+
if (in_array($mode, ['w', 'w+', 'a', 'a+', 'x', 'x+'], true)) {
48+
$path = $this->findPath($uri, true);
49+
} else {
50+
$path = $this->findPath($uri);
51+
}
4552

4653
if ($path === null) {
4754
return false;
4855
}
4956

5057
$handle = @fopen($path, $mode);
5158

52-
// fopen will return false if mode is 'x' and file already exist.
53-
// See : https://www.php.net/manual/en/function.fopen
59+
// fopen will return false if file is not found or if mode is 'x' and
60+
// file already exist. See : https://www.php.net/manual/en/function.fopen
5461
if ($handle === false) {
5562
return false;
5663
}

tests/UniformResourceLocator/StreamWrapper/StreamTest.php

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,73 @@ public function testChmod(): void
162162
}
163163

164164
/**
165+
* Test on a file that already exist.
165166
* @depends testSimpleFile
166167
*/
167168
public function testFOpen(): void
169+
{
170+
touch($this->file);
171+
$this->assertTrue(file_exists($this->file)); // Make sure file exist, it's the point of the test
172+
$this->assertIsResource(fopen($this->file, 'w'));
173+
unlink($this->file);
174+
}
175+
176+
/**
177+
* Make sure fopen create the file if it doesn't exist.
178+
* @depends testSimpleFile
179+
*/
180+
public function testFOpenFileNotExistButWillCreate(): void
181+
{
182+
$this->assertFalse(file_exists($this->file));
183+
$this->assertIsResource(fopen($this->file, 'w'));
184+
$this->assertTrue(file_exists($this->file));
185+
unlink($this->file);
186+
}
187+
188+
/**
189+
* Make sure fopen will return false if the file doesn't exist in readonly
190+
* mode. Even if locator return a resource path (with all flag).
191+
*
192+
* @depends testSimpleFile
193+
*/
194+
public function testFOpenFileNotExist(): void
168195
{
169196
// stream_open will trigger an error even if the stream return false.
197+
// fopen(bar://test.txt): Failed to open stream: "UserFrosting\UniformResourceLocator\StreamWrapper\Stream::stream_open" call failed
198+
// This suppress this error, and allow us to test the return value.
170199
set_error_handler(function ($no, $str, $file, $line) { // @phpstan-ignore-line
171200
});
172201

173-
touch($this->file); // Touch basic file
202+
$this->assertFalse(file_exists($this->file));
203+
$this->assertFalse(fopen($this->file, 'r'));
204+
$this->assertFalse(file_exists($this->file));
205+
}
206+
207+
/**
208+
* @depends testSimpleFile
209+
*/
210+
public function testFOpenInvalidPath(): void
211+
{
212+
// Catch exception
213+
set_error_handler(function ($no, $str, $file, $line) { // @phpstan-ignore-line
214+
});
215+
216+
$this->assertFalse(fopen('bar://test.txt', 'w'));
217+
}
218+
219+
/**
220+
* fopen will return false if mode is 'x' and file already exist.
221+
* @depends testSimpleFile
222+
*/
223+
public function testFOpenFalseReturn(): void
224+
{
225+
// Catch exception
226+
set_error_handler(function ($no, $str, $file, $line) { // @phpstan-ignore-line
227+
});
228+
229+
touch($this->file);
174230
$this->assertFalse(fopen($this->file, 'x'));
175-
unlink($this->file); // Reset state
231+
unlink($this->file);
176232
}
177233

178234
/**

0 commit comments

Comments
 (0)