php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80056 missing files when using `foreach` to iterate `RecursiveDirectoryIterator`
Submitted: 2020-09-04 08:02 UTC Modified: 2020-09-15 15:26 UTC
From: 397836525 at qq dot com Assigned: cmb (profile)
Status: Not a bug Package: *Directory/Filesystem functions
PHP Version: 7.4.10 OS: Windows
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: 397836525 at qq dot com
New email:
PHP Version: OS:

 

 [2020-09-04 08:02 UTC] 397836525 at qq dot com
Description:
------------
I tried to use the RecursiveDirectoryIterator with the foreach funtion to get all the files below a directory, and I found some files were missing from the result.After some experiments, it seems that it only happens under the circumstance of a directory with large amount of files, like 60 or more.

here's the code:

<?php
    
$directory = new RecursiveDirectoryIterator($this->path);

foreach ($directory as $filename => $fileInfo) {
    echo $filename . PHP_EOL;
}

?>

please use the patch file to reproduce the bug.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-09-04 08:08 UTC] 397836525 at qq dot com
here's the code for reproducing the bug.

<?php
/**
 * Created by RexMin.
 * Description.
 * Email: rexmin@futunn.com
 * Date: 2020/9/4
 * Time: 14:40
 */

class Test
{
    protected $path = 'directory';

    public function createTestFiles ()
    {
        $amount = 63;

        if (!is_dir($this->path)) {
            mkdir($this->path);
        }

        foreach (scandir($this->path) as $filename) {
            @unlink("{$this->path}/$filename");
        }

        for ($num = 1; $num <= $amount; $num++) {
            fopen("{$this->path}/{$num}.txt", "a");
        }
    }

    public function runTest()
    {
        echo 'get by foreach: ' . $this->getByForeach() . PHP_EOL;
        echo 'get by foreach with rewind: ' . $this->getByForeachWithRewind() . PHP_EOL;
        echo 'get by foreach after foreach: ' . $this->getByForeachAfterForeach() . PHP_EOL;
        echo 'get by loop: ' . $this->getByloop() . PHP_EOL;
        echo 'get by iterator_to_array: ' . $this->getByIteratorToArray() . PHP_EOL;
        echo 'get by iterator_to_array with rewind: ' . $this->getByIteratorToArrayWithRewind() . PHP_EOL;
    }

    public function getByForeach()
    {
        $directory = new RecursiveDirectoryIterator($this->path);
        $count = 0;
        foreach ($directory as $filename => $fileInfo) {
            $count++;
        }

        return $count;
    }

    public function getByForeachWithRewind()
    {
        $directory = new RecursiveDirectoryIterator($this->path);
        $count = 0;
        $directory->rewind();
        foreach ($directory as $filename => $fileInfo) {
            $count++;
        }

        return $count;
    }

    public function getByForeachAfterForeach()
    {
        $directory = new RecursiveDirectoryIterator($this->path);
        $count = 0;
        foreach ($directory as $filename => $fileInfo) {
            // do nothing
        }
        foreach ($directory as $filename => $fileInfo) {
            $count++;
        }

        return $count;
    }

    public function getByLoop()
    {
        $directory = new RecursiveDirectoryIterator($this->path);
        $count = 0;
        while ($directory->valid()) {
            $count++;
            $directory->next();
        }

        return $count;
    }

    public function getByIteratorToArray()
    {
        $directory = new RecursiveDirectoryIterator($this->path);
        return count(iterator_to_array($directory));
    }

    public function getByIteratorToArrayWithRewind()
    {
        $directory = new RecursiveDirectoryIterator($this->path);
        $directory->rewind();
        return count(iterator_to_array($directory));
    }
}

$test = new Test();
$test->createTestFiles();
$test->runTest();
 [2020-09-04 08:15 UTC] cmb@php.net
-Status: Open +Status: Feedback -Assigned To: +Assigned To: cmb
 [2020-09-04 08:15 UTC] cmb@php.net
I cannot reproduce the reported behavior.

> please use the patch file to reproduce the bug.

Not sure if you tried to add some file as patch, but that won't
necessarily work.  Please make such scripts publicly available
somewhere else (e.g. gist.github.com, pastebin.com), and share the
link here.
 [2020-09-04 08:23 UTC] 397836525 at qq dot com
Somehow I cannot upload my test code by using patch file.So I paste the test code in the previos comment.please check.
 [2020-09-07 07:15 UTC] cmb@php.net
-Status: Feedback +Status: Open -Assigned To: cmb +Assigned To:
 [2020-09-07 07:15 UTC] cmb@php.net
For some reason I missed that script.  Anyhow, I cannot reproduce
the issue with that script.  All six methods return the expected
65.
 [2020-09-07 07:20 UTC] 397836525 at qq dot com
Hi there, I finally find out that the reason to problem is actually the environment.

I was using the docker with the `WSL 2 based engine` under the Windows system. As soon as I changed the docker engine into `Legacy Hyper-V backend`, the problem disappeared.
 [2020-09-15 15:26 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2020-09-15 15:26 UTC] cmb@php.net
Thanks!  Then this is unlikely to be a PHP issue.
 [2020-09-16 07:36 UTC] joffrey at ne2000 dot nl
For reference, a ticket on the core of this issue is filed at Microsoft's WSL2 Linux Kernel repository: https://github.com/microsoft/WSL2-Linux-Kernel/issues/187
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 18 17:01:28 2024 UTC