【问题标题】:PHP scandir recursivelyPHP scandir递归
【发布时间】:2016-03-15 09:56:14
【问题描述】:

我希望我的脚本递归地扫描目录,

$files = scandir('/dir');
foreach($files as $file){
if(is_dir($file)){
    echo '<li><label class="tree-toggler nav-header"><i class="fa fa-folder-o"></i>'.$file.'</label>';
    $subfiles = scandir($rooturl.'/'.$file);
        foreach($subfiles as $subfile){
            // and so on and on and on
        }
        echo '<li>';
    } else {
        echo $file.'<br />';
    }
}

我想以这样一种方式循环这个,对于 scandir 找到的每个目录,它会在该目录中找到的文件夹上运行另一个 scandir,

所以 dir 'A' 包含 dir 1/2/3,它现在应该是 scandir(1)、scandir(2)、scandir(3) 对于找到的每个目录,依此类推。

我怎样才能轻松地实现这一点,而无需在每个 foreach 中一遍又一遍地复制粘贴代码?

编辑:由于答案与我已经尝试过的几乎完全相同,因此我将稍微更新一下问题。

使用这个脚本,我需要创建一个树视图列表。使用当前发布的脚本,会发生以下 get 回显:

/images/dir1/file1.png
/images/dir1/file2.png
/images/dir1/file3.png
/images/anotherfile.php
/data/uploads/avatar.jpg
/data/config.php
index.php

我真正需要的是:

<li><label>images</label>
    <ul>
        <li><label>dir1</label>
            <ul>
                <li>file1.png</li>
                <li>file2.png</li>
                <li>file3.png</li>
            </ul>
        </li>
        <li>anotherfile.php</li>
    </ul>
</li>
<li><label>data</label>
    <ul>
        <li><label>uploads</label>
            <ul>
                <li>avatar.jpg</li>
            </ul>
        </li>
        <li>config.php</li>
    </ul>
</li>
<li>index.php</li>

等等,感谢您已经发布的答案!

【问题讨论】:

标签: php file scandir


【解决方案1】:

我知道这是一个老问题,但我写了一个更实用的版本。它不使用全局状态,而是使用纯函数来解决问题:

function scanAllDir($dir) {
  $result = [];
  foreach(scandir($dir) as $filename) {
    if ($filename[0] === '.') continue;
    $filePath = $dir . '/' . $filename;
    if (is_dir($filePath)) {
      foreach (scanAllDir($filePath) as $childFilename) {
        $result[] = $filename . '/' . $childFilename;
      }
    } else {
      $result[] = $filename;
    }
  }
  return $result;
}

【讨论】:

  • 您可能希望使用常量 DIRECTORY_SEPARATOR 而不是硬编码“/”,以便在 Linux 和 Windows 系统上安全使用代码。
  • 由于某种原因它只选择一个子目录并递归扫描它
【解决方案2】:

您可以通过这种方式递归扫描目录,目标是您最顶层的目录:

function scanDir($target) {

        if(is_dir($target)){

            $files = glob( $target . '*', GLOB_MARK ); //GLOB_MARK adds a slash to directories returned

            foreach( $files as $file )
            {
                scanDir( $file );
            }


        } 
    }

您可以根据需要轻松调整此功能。 例如,如果要使用它来删除目录及其内容,您可以这样做:

function delete_files($target) {

        if(is_dir($target)){

            $files = glob( $target . '*', GLOB_MARK ); //GLOB_MARK adds a slash to directories returned

            foreach( $files as $file )
            {
                delete_files( $file );
            }

            rmdir( $target );

        } elseif(is_file($target)) {

            unlink( $target );
    }

你不能以你正在做的方式做到这一点。 以下函数以递归方式获取所有目录、子目录以及您想要的深度以及它们的内容:

function assetsMap($source_dir, $directory_depth = 0, $hidden = FALSE)
    {
        if ($fp = @opendir($source_dir))
        {
            $filedata   = array();
            $new_depth  = $directory_depth - 1;
            $source_dir = rtrim($source_dir, '/').'/';

            while (FALSE !== ($file = readdir($fp)))
            {
                // Remove '.', '..', and hidden files [optional]
                if ( ! trim($file, '.') OR ($hidden == FALSE && $file[0] == '.'))
                {
                    continue;
                }

                if (($directory_depth < 1 OR $new_depth > 0) && @is_dir($source_dir.$file))
                {
                    $filedata[$file] = assetsMap($source_dir.$file.'/', $new_depth, $hidden);
                }
                else
                {
                    $filedata[] = $file;
                }
            }

            closedir($fp);
            return $filedata;
        }
        echo 'can not open dir';
        return FALSE;
    }

将你的路径传递给函数:

$path = 'elements/images/';
$filedata = assetsMap($path, $directory_depth = 5, $hidden = FALSE);

$filedata 是一个包含所有已创建目录和子目录及其内容的数组。这个功能可以让你扫描目录结构($directory_depth),你想要的深度以及摆脱所有无聊的隐藏文件(例如'.','..')

您现在所要做的就是使用返回的数组,即完整的树结构,在您的视图中随意排列数据。

实际上,您尝试做的是一种文件管理器,正如您所知,其中有很多是开源的、免费的。

希望对你有帮助,祝你圣诞快乐。

【讨论】:

  • 感谢您的回复,但是我无法按照我需要的方式进行操作,我已经更新了最初的问题以获得更好的解释:)
  • 我一定会试试这个,我还没有检查开源脚本,因为大多数情况下你必须剥离 70% 的构建以适应你自己的脚本/模板/页面。谢谢你的回复,也祝你自己圣诞快乐! :)
  • 你的扫描目录函数没有返回任何值,你不能用这个名字调用这个函数它是一个保留的名字
【解决方案3】:

虽然这个问题很老了。但我的回答可以帮助访问此问题的人。

这递归地扫描目录和子目录并将输出存储在一个全局变量中。

global $file_info; // All the file paths will be pushed here
$file_info = array();

/**
 * 
 * @function recursive_scan
 * @description Recursively scans a folder and its child folders
 * @param $path :: Path of the folder/file
 * 
 * */
function recursive_scan($path){
    global $file_info;
    $path = rtrim($path, '/');
    if(!is_dir($path)) $file_info[] = $path;
        else {
            $files = scandir($path);
            foreach($files as $file) if($file != '.' && $file != '..') recursive_scan($path . '/' . $file);
        }
}

recursive_scan('/var/www/html/wp-4.7.2/wp-content/plugins/site-backup');
print_r($file_info);

【讨论】:

    【解决方案4】:
    function getFiles(string $directory, array $allFiles = []): array
    {
        $files = array_diff(scandir($directory), ['.', '..']);
    
        foreach ($files as $file) {
            $fullPath = $directory. DIRECTORY_SEPARATOR .$file;
    
            if( is_dir($fullPath) )
                $allFiles += getFiles($fullPath, $allFiles);
            else
                $allFiles[] = $file;
        }
    
        return $allFiles;
    }
    

    我知道这很旧,但我想展示其他答案的稍微不同的版本。使用 array_diff 丢弃“。”和“..”文件夹。还有用于组合 2 个数组的 + 运算符(我很少看到它被使用,所以它可能对某人有用)

    【讨论】:

    • 使用array_diff 真的很好,因为它比array_filter 更简洁
    【解决方案5】:

    创建一个扫描函数并将其命名为recursively...

    例如:

       <?php
    
        function scandir_rec($root)
        {
            echo $root . PHP_EOL;
            // When it's a file or not a valid dir name
            // Print it out and stop recusion 
            if (is_file($root) || !is_dir($root)) {
                return;
            }
    
            // starts the scan
            $dirs = scandir($root);
            foreach ($dirs as $dir) {
                if ($dir == '.' || $dir == '..') {
                    continue; // skip . and ..
                }
    
                $path = $root . '/' . $dir;
                scandir_rec($path); // <--- CALL THE FUNCTION ITSELF TO DO THE SAME THING WITH SUB DIRS OR FILES.
            }
        }
    
        // run it when needed
        scandir_rec('./rootDir');
    

    你可以对这个函数做很多变化。例如,打印一个“li”标签而不是 PHP_EOL,以创建一个树形视图。

    [编辑]

     <?php
    
    function scandir_rec($root)
    {
        // if root is a file
        if (is_file($root)) {
            echo '<li>' . basename($root) . '</li>';
            return;
        }
    
        if (!is_dir($root)) {
            return;
        }
    
        $dirs = scandir($root);
        foreach ($dirs as $dir) {
            if ($dir == '.' || $dir == '..') {
                continue;
            }
    
            $path = $root . '/' . $dir;
            if (is_file($path)) {
                // if file, create list item tag, and done.
                echo '<li>' . $dir . '</li>';
            } else if (is_dir($path)) {
                // if dir, create list item with sub ul tag
                echo '<li>';
                echo '<label>' . $dir . '</label>';
                echo '<ul>';
                scandir_rec($path); // <--- then recursion
                echo '</ul>';
                echo '</li>';
            }
        }
    }
    
    // init call
    $rootDir = 'rootDir';
    echo '<ul>';
    scandir_rec($rootDir);
    echo '</ul>';
    

    【讨论】:

    • 感谢您的回复,但是我无法按照我需要的方式进行操作,我已经更新了最初的问题以获得更好的解释:)
    猜你喜欢
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-15
    • 1970-01-01
    • 2012-08-10
    相关资源
    最近更新 更多