我正在尝试制作一个递归函数,以获取数组中ftp服务器中的所有目录和子目录。
我尝试了很多我在网上找到的功能。最适合我的是这个:
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 ;
}
这个函数的问题是,它不允许目录的名称中有".",并且位于根目录中的每个文件也将被视为一个目录。所以我调整了功能,得到了这个:
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 ;
}
这工作得很好,但给出了我想要的结果。但它太慢了,无法使用。
我也尝试过使用ftp_rawlist
,但它也有同样的缺点,速度非常慢。
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;
}
最近几天我一直被这个问题困扰着,我越来越绝望了。如果有人有任何建议,请告诉我
如果您的服务器支持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;
}
如果您没有PHP7.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获取目录结构。
我已经构建了一个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
此代码是Martin Prikryl代码的变体。它速度较慢,但没有任何空白区故障。只有当您对上面的代码有任何问题时,才使用此代码。
function ftp_list_files_recursive($ftp_stream, $path){
$lines = ftp_nlist($ftp_stream, $path);
$result = array();
foreach ($lines as $line) {
if (ftp_size($ftp_stream, $line) == -1) {
$result = array_merge($result, ftp_list_files_recursive($ftp_stream, $line));
}
else{
$result[] = $line;
}
}
return $result;
}