SPL: Fix for bug 66405 RecursiveDirectoryIterator with CURRENT_AS_PATHNAME

Currently when you use RecursiveDirectoryIterator with the
CURRENT_AS_PATHNAME flag PHP will throw an UnexpectedValueException with
message 'Objects returned by RecursiveIterator::getChildren() must implement
RecursiveIterator'.This happend because getChildren() will return the
current directory name instead of an Iterator (or subclass of) as required
by the RecursiveIterator interface.

This commit changes getChildren() to return annother
RecursiveDirectoryIterator but current() still returns the path name when
CURRENT_AS_PATHNAME is used. A PHPT test case (bug66405.phpt) that
reproduces the bug is included.

This fix was originally against the PHP-5.4 branch, but it was not merged
before 5.4 reached EOL. I am hoping to get it applied to 5.5, 5.6, and
master.
This commit is contained in:
Paul Garvin 2014-05-07 00:17:45 -04:00 committed by Julien Pauli
parent 1813fe9f38
commit 605d32bedd
2 changed files with 77 additions and 22 deletions

View File

@ -1523,29 +1523,25 @@ SPL_METHOD(RecursiveDirectoryIterator, getChildren)
spl_filesystem_object_get_file_name(intern TSRMLS_CC);
if (SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
RETURN_STRINGL(intern->file_name, intern->file_name_len, 1);
} else {
MAKE_STD_ZVAL(zflags);
MAKE_STD_ZVAL(zpath);
ZVAL_LONG(zflags, intern->flags);
ZVAL_STRINGL(zpath, intern->file_name, intern->file_name_len, 1);
spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, zpath, zflags TSRMLS_CC);
zval_ptr_dtor(&zpath);
zval_ptr_dtor(&zflags);
subdir = (spl_filesystem_object*)zend_object_store_get_object(return_value TSRMLS_CC);
if (subdir) {
if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) {
subdir->u.dir.sub_path_len = spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
} else {
subdir->u.dir.sub_path_len = strlen(intern->u.dir.entry.d_name);
subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len);
}
subdir->info_class = intern->info_class;
subdir->file_class = intern->file_class;
subdir->oth = intern->oth;
MAKE_STD_ZVAL(zflags);
MAKE_STD_ZVAL(zpath);
ZVAL_LONG(zflags, intern->flags);
ZVAL_STRINGL(zpath, intern->file_name, intern->file_name_len, 1);
spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, zpath, zflags TSRMLS_CC);
zval_ptr_dtor(&zpath);
zval_ptr_dtor(&zflags);
subdir = (spl_filesystem_object*)zend_object_store_get_object(return_value TSRMLS_CC);
if (subdir) {
if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) {
subdir->u.dir.sub_path_len = spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
} else {
subdir->u.dir.sub_path_len = strlen(intern->u.dir.entry.d_name);
subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len);
}
subdir->info_class = intern->info_class;
subdir->file_class = intern->file_class;
subdir->oth = intern->oth;
}
}
/* }}} */

View File

@ -0,0 +1,59 @@
--TEST--
SPL: RecursiveDirectoryIterator with CURRENT_AS_PATHNAME flag
--CREDITS--
Paul Garvin pgarvin76@gmail.com
--FILE--
<?php
$td = __DIR__ . '/bug66405';
mkdir($td);
touch($td . '/file1.txt');
touch($td . '/file2.md');
mkdir($td . '/testsubdir');
touch($td . '/testsubdir/file3.csv');
class Bug66405 extends RecursiveDirectoryIterator
{
public function current()
{
$current = parent::current();
echo gettype($current) . " $current\n";
return $current;
}
public function getChildren()
{
$children = parent::getChildren();
if (is_object($children)) {
echo get_class($children) . " $children\n";
} else {
echo gettype($children) . " $children\n";
}
return $children;
}
}
$rdi = new Bug66405($td, FilesystemIterator::CURRENT_AS_PATHNAME | FilesystemIterator::SKIP_DOTS);
$rii = new RecursiveIteratorIterator($rdi);
ob_start();
foreach ($rii as $file) {
//noop
}
$results = explode("\n", ob_get_clean());
sort($results);
echo implode("\n", $results);
?>
--CLEAN--
<?php
$td = __DIR__ . '/bug66405';
unlink($td . '/testsubdir/file3.csv');
unlink($td . '/file2.md');
unlink($td . '/file1.txt');
rmdir($td . '/testsubdir');
rmdir($td);
?>
--EXPECTF--
Bug66405 file3.csv
string %s/bug66405/file1.txt
string %s/bug66405/file2.md
string %s/bug66405/testsubdir/file3.csv