首页  >  问答  >  正文

PHP FTP 递归目录列表

<p>我正在尝试创建一个递归函数来从数组中的 ftp 服务器获取所有目录和子目录。</p> <p>我尝试了很多在网上找到的功能。最适合我的是这个:</p> <pre class="brush:php;toolbar:false;">public function getAllSubDirFiles() { $dir = array("."); $a = count($dir); $i = 0; $depth = 20; $b = 0; while (($a != $b) && ($i < $depth)) { $i++; $a = count($dir); foreach ($dir as $d) { $ftp_dir = $d . "/"; $newdir = ftp_nlist($this->connectionId, $ftp_dir); foreach ($newdir as $key => $x) { if ((strpos($x, ".")) || (strpos($x, ".") === 0)) { unset($newdir[$key]); } elseif (!in_array($x, $dir)) { $dir[] = $x; } } } $b = count($dir); } return $dir ; }</pre> <p>这个函数的问题是它不允许目录有“.”。在它的名称中,位于根目录中的每个文件也将被视为一个目录。所以我调整了函数并得到了这个:</p> <pre class="brush:php;toolbar:false;">public function getAllSubDirFiles($ip, $id, $pw) { $dir = array("."); $a = count($dir); $i = 0; $depth = 20; $b =0; while (($a != $b) && ($i < $depth)) { $i++; $a = count($dir); foreach ($dir as $d) { $ftp_dir = $d . "/"; $newdir = ftp_nlist($this->connectionId, $ftp_dir); foreach ($newdir as $key => $x) { if (!is_dir('ftp://'.$id.':'.$pw.'@'.$ip.'/'.$x)) { unset($newdir[$key]); } elseif (!in_array($x, $dir)) { $dir[] = $x; } } } $b = count($dir); } return $dir ; }</pre> <p>这工作得很好,但给出了我想要的结果。但它太慢了,无法使用。 </p> <p>我也尝试过使用<code>ftp_rawlist</code>,但它也有同样的缺点,那就是速度非常慢。</p> <pre class="brush:php;toolbar:false;">public function getAllSubDirFiles() { $dir = array("."); $a = count($dir); $i = 0; $depth = 20; $b = 0; while (($a != $b) && ($i < $depth)) { $i++; $a = count($dir); foreach ($dir as $d) { $ftp_dir = $d . "/"; $newdir = $this->getFtp_rawlist('/' . $ftp_dir); foreach ($newdir as $key => $x) { $firstChar = substr($newdir[$key][0], 0, 1); $a = 8; while ($a < count($newdir[$key])) { if ($a == 8) { $fileName = $ftp_dir . '/' . $newdir[$key][$a]; } else { $fileName = $fileName . ' ' . $newdir[$key][$a]; } $a++; } if ($firstChar != 'd') { unset($newdir[$key]); } elseif (!in_array($fileName, $dir)) { $dir[] = $fileName; } } } $b = count($dir); } return $dir; } public function getFtp_rawlist($dir) { $newArr = array(); $arr = ftp_rawlist($this->connectionId, $dir); foreach ($arr as $value) { $stringArr = explode(" ", $value); $newArr[] = array_values(array_filter($stringArr)); } return $newArr; }</pre> <p>过去几天我一直被这个问题困扰,我越来越绝望了。如果有人有任何建议请告诉我</p>
P粉621033928P粉621033928394 天前599

全部回复(2)我来回复

  • P粉903052556

    P粉9030525562023-08-25 17:19:00

    我构建了一个 OOP FTP 客户端库,可以帮助您解决此问题很多,仅使用此代码,您可以检索仅包含附加有用信息的目录列表,例如(chmod、上次修改时间、大小...)。

    代码:

    // Connection
    $connection = new FtpConnection("localhost", "foo", "12345");
    $connection->open();
            
    // FtpConfig
    $config = new FtpConfig($connection);
    $config->setPassive(true);
    
    $client = new FtpClient($connection);
    
    $allFolders =
        // directory, recursive, filter
        $client->listDirectoryDetails('/', true, FtpClient::DIR_TYPE); 
    
    // Do whatever you want with the folders
    

    回复
    0
  • P粉763662390

    P粉7636623902023-08-25 11:29:06

    如果您的服务器支持 MLSD 命令并且您有 PHP 7.2 或更高版本,则可以使用 ftp_mlsd 函数

    function ftp_mlsd_recursive($ftp_stream, $directory)
    {
        $result = [];
    
        $files = ftp_mlsd($ftp_stream, $directory);
        if ($files === false)
        {
            die("Cannot list $directory");
        }
    
        foreach ($files as $file)
        { 
            $name = $file["name"];
            $filepath = $directory . "/" . $name;
            if (($file["type"] == "cdir") || ($file["type"] == "pdir"))
            {
                // noop
            }
            else if ($file["type"] == "dir")
            {
                $result = array_merge($result, ftp_mlsd_recursive($ftp_stream, $filepath));
            }
            else
            {
                $result[] = $filepath;
            }
        } 
        return $result;
    }

    如果您没有 PHP 7.2,您可以尝试自行实现 MLSD 命令。首先,请参阅 ftp_rawlist 命令的用户注释:
    https://www.php.net/manual/en/ function.ftp-rawlist.php#101071


    如果您无法使用MLSD,那么您在判断条目是文件还是文件夹时尤其会遇到问题。虽然您可以使用 ftp_size 技巧,但调用 每个条目的 ftp_size 可能需要很长时间。

    但是,如果您只需要针对一个特定的 FTP 服务器进行工作,则可以使用 ftp_rawlist 以特定于平台的格式检索文件列表并对其进行解析。

    以下代码假定采用常见的 *nix 格式。

    function ftp_nlst_recursive($ftp_stream, $directory)
    {
        $result = [];
    
        $lines = ftp_rawlist($ftp_stream, $directory);
        if ($lines === false)
        {
            die("Cannot list $directory");
        }
    
        foreach ($lines as $line)
        {
            $tokens = preg_split("/\s+/", $line, 9);
            $name = $tokens[8];
            $type = $tokens[0][0];
            $filepath = $directory . "/" . $name;
    
            if ($type == 'd')
            {
                $result = array_merge($result, ftp_nlst_recursive($ftp_stream, $filepath));
            }
            else
            {
                $result[] = $filepath;
            }
        }
        return $result;
    }

    对于 DOS 格式,请参阅:使用 PHP 从 FTP 获取目录结构

    回复
    0
  • 取消回复