Bug #75210 [Com]: GlobIterator on current directory uses invalid path for SplFileInfo
| From: | thiago dot oak at gmail dot com | Date: | Thu, 12 Oct 2017 13:36:16 +0000 |
| Subject: | Bug #75210 [Com]: GlobIterator on current directory uses invalid path for SplFileInfo | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-211643@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=75210&edit=1
ID: 75210
Comment by: thiago dot oak at gmail dot com
Reported by: php at pointpro dot nl
Summary: GlobIterator on current directory uses invalid path
for SplFileInfo
Status: Analyzed
Type: Bug
Package: SPL related
Operating System: Ubuntu 16.04
PHP Version: 7.1.9
Block user comment: N
Private report: N
New Comment:
I was looking into this a bit
If I understand this correctly it seems that on
intern->type = SPL_FS_DIR; // https://github.com/php/php-src/blob/PHP-7.1.9/ext/spl/spl_directory.c#L234
we assume we the "top level" things we iterate are always directories.
this works well on places like FilesystemIterator::__construct since they will give you an error if
the "top level" is not a dir - "failed to open dir: Not a directory in..."
One way I was thinking we could avoid this, is maybe after
spprintf(&path, 0, "glob://%s", path); // https://github.com/php/php-src/blob/PHP-7.1.9/ext/spl/spl_directory.c#L719
checking if the 8th char is a * and replacing it with ./*
but this feels wrong. not sure what a good solution would be here
and
Previous Comments:
------------------------------------------------------------------------
[2017-09-15 12:10:24] requinix@php.net
It's not that the slash is added but that an implicit "." parent path is not added:
the full path constructed is path-from-pattern + "/" + filename, and if the pattern does
not have a path then that part is an empty string.
https://github.com/php/php-src/blob/PHP-7.1.9/ext/spl/spl_directory.c#L187
Places that use a file name, like getFilename(), recognize that the path is empty and simply return
the full path as-is (including the stray leading slash) rather than extract the file name from the
full path.
What should be happening is that the full path is path-from-pattern + "/" + filename when
there is a path, and just filename when there is not. That mirrors how regular SplFileInfo objects
work too.
This bug technically would affect all the SPL filesystem iterators, however I think GlobIterator is
the only one that can be created in a way that uses an empty path name - eg,
DirectoryIterator("") says "Directory name must not be empty".
Coincidentally, the example for GlobIterator::__construct uses an empty path too but it's
written in a way that doesn't reveal the problem :D
------------------------------------------------------------------------
[2017-09-15 11:43:54] sjon at hortensius dot net
Can confirm, see https://3v4l.org/aUqLF
------------------------------------------------------------------------
[2017-09-15 10:48:48] php at pointpro dot nl
Description:
------------
When using the GlobIterator for the current directory, results depend on the notation. When using,
for example, *.php, the resulting SplFileInfo objects will be invalid, while if you use
'./*.php' they will be valid.
Observe the difference in output with the test script. I ran it in a directory containing the script
itself as test.php and two other files called test2.php and test3.php
It seems that that the GlobIterator adds a '/' at the beginning of the path when I specify
no path information, which makes SplFileInfo resolve it as a file in the file system root, which is
not correct.
I'm tried this using 7.1.9-1+ubuntu16.04.1+deb.sury.org+1 from http://ppa.launchpad.net/ondrej/php/ubuntu
and the same also occurs in 7.0.23-1+ubuntu16.04.1+deb.sury.org+1 from that same repository.
Test script:
---------------
$it = new GlobIterator("./*.php");
foreach ($it as $p)
{
echo $p->getFilename() . " " . ($p->isFile() ? "IS" : "IS
NOT") . " a file\n";
}
$it = new GlobIterator("*.php");
foreach ($it as $p)
{
echo $p->getFilename() . " " . ($p->isFile() ? "IS" : "IS
NOT") . " a file\n";
}
Expected result:
----------------
./test.php IS a file
./test2.php IS a file
./test3.php IS a file
test.php IS a file
test2.php IS a file
test3.php IS a file
Actual result:
--------------
test.php IS a file
test2.php IS a file
test3.php IS a file
/test.php IS NOT a file
/test2.php IS NOT a file
/test3.php IS NOT a file
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=75210&edit=1