Files
dualfroz 53a7d85862 fix: only treat the last path segment as a filename in path()
isFilePath() checked the entire path for a dot to decide whether path() was given
a file or a directory. Because the path includes the location and name, a dot in
a parent segment (for example a location like /tmp/my.app) caused a directory
argument to be misclassified as a file, so the requested subdirectory was not
created. Inspect only the last path segment instead.
2026-09-04 09:42:16 +02:00

2.3 KiB

fix: only treat the last path segment as a filename in path()

Problem

TemporaryDirectory::path() fails to create a requested subdirectory when the temporary directory's location contains a dot:

$tmp = (new Spatie\TemporaryDirectory\TemporaryDirectory('/tmp/my.app'))
    ->name('run1')
    ->create();

$path = $tmp->path('abc');   // "abc" is a directory
is_dir($path);               // false  <-- the directory was not created

path('abc') is documented and tested to create the abc subdirectory (see it_can_create_a_subdirectory_in_the_temporary_directory), but here it returns a path whose directory does not exist.

Root cause

src/TemporaryDirectory.php. path() decides whether the argument points to a file (create only the parent directory) or a directory (create the whole path) via isFilePath():

protected function isFilePath(string $path): bool
{
    return str_contains($path, '.');
}

$path is the full path (location + name + argument), so the check reacts to a dot anywhere in it - including a dot in the location such as /tmp/my.app. When that happens, a directory argument like abc is misclassified as a file, and removeFilenameFromPath() strips the abc segment, so only the already existing parent is created and abc is skipped.

The fix

Only the last path segment can be a filename, so inspect just that segment:

protected function isFilePath(string $path): bool
{
    $lastSeparator = strrpos($path, DIRECTORY_SEPARATOR);
    $lastSegment = $lastSeparator === false ? $path : substr($path, $lastSeparator + 1);

    return str_contains($lastSegment, '.');
}

A dot in a parent segment (the location or name) no longer affects the file/directory decision, while a real filename such as test.txt in the last segment is still detected.

Test

Added it_can_create_a_subdirectory_when_the_location_contains_a_dot, which creates a temporary directory under a location containing dots and asserts that path('abc') actually creates the abc directory.

Gate

composer install && vendor/bin/phpunit

Result: exit code 0 - OK (23 tests, 37 assertions).

Counterfactual: reverting isFilePath() to str_contains($path, '.') makes the new test fail - Failed asserting that directory "/tmp/my.dotted.location/temporary_directory/abc" exists.