有些人抱怨 ftp_nlist 总是返回 FALSE。我自己也遇到过这种行为,直到我使用了 ftp_pasv,它在你的客户端位于防火墙后面时很有用(现在大多数客户端都在防火墙后面),然后 ftp_nlist 就可以正常工作了。我并不真正知道使用 ftp_pasv 的所有含义,但如果你读到或遇到 ftp_nlist、ftp_get、ftp_nb_get 无法正常工作的情况,请尝试添加以下内容
ftp_pasv($conn_id,true);
(PHP 4, PHP 5, PHP 7, PHP 8)
ftp_nlist — 返回给定目录中的文件列表
ftp
一个 FTP\Connection 实例。
directory
要列出的目录。此参数也可以包含参数,例如 ftp_nlist($ftp, "-la /your/dir");
。请注意,此参数不会转义,因此文件名中包含空格和其他字符可能会出现一些问题。
如果成功,则返回指定目录中的文件名数组;如果出错,则返回 false
。
版本 | 描述 |
---|---|
8.1.0 | ftp 参数现在需要一个 FTP\Connection 实例;以前需要一个 资源。 |
示例 #1 ftp_nlist() 示例
<?php
// 设置基本连接
$ftp = ftp_connect($ftp_server);
// 使用用户名和密码登录
$login_result = ftp_login($ftp, $ftp_user_name, $ftp_user_pass);
// 获取当前目录的内容
$contents = ftp_nlist($ftp, ".");
// 输出 $contents
var_dump($contents);
?>
上面的示例将输出类似于以下内容
array(3) { [0]=> string(11) "public_html" [1]=> string(10) "public_ftp" [2]=> string(3) "www"
有些人抱怨 ftp_nlist 总是返回 FALSE。我自己也遇到过这种行为,直到我使用了 ftp_pasv,它在你的客户端位于防火墙后面时很有用(现在大多数客户端都在防火墙后面),然后 ftp_nlist 就可以正常工作了。我并不真正知道使用 ftp_pasv 的所有含义,但如果你读到或遇到 ftp_nlist、ftp_get、ftp_nb_get 无法正常工作的情况,请尝试添加以下内容
ftp_pasv($conn_id,true);
ftp_nlist() 或 ftp_rawlist() 耗时很长,然后什么也不返回...
如果你遇到此问题,你可能需要使用 ftp_pasv() 函数启用 PASV 模式 FTP 传输。
示例...
<?php
$ftp_host = "yourFTPHost";
$ftp_user = "yourUsername";
$ftp_password = "yourPassword";
// 连接
echo "<br />连接到 $ftp_host 通过 FTP...";
$conn = ftp_connect($ftp_host);
$login = ftp_login($conn, $ftp_user, $ftp_password);
//
// 启用 PASV(注意:必须在 ftp_login() 后完成)
//
$mode = ftp_pasv($conn, TRUE);
// 登录成功?
if ((!$conn) || (!$login) || (!$mode)) {
die("FTP 连接失败!");
}
echo "<br />登录成功。<br />";
//
// 现在运行 ftp_nlist()
//
$file_list = ftp_nlist($conn, "");
foreach ($file_list as $file)
{
echo "<br>$file";
}
// 关闭
ftp_close($conn);
?>
请注意,从 PHP 7.2 开始,可以使用一个新函数,它将文件列表作为包含所有细节的数组返回,可以直接使用:https://php.net/manual/en/function.ftp-mlsd.php
在运行 WAMP(Vista、Apache 2.21、MySQL 5.1.36、PHP 5.3)并从 LAMP FTP 服务器(Ubuntu 8.04、Apache 2.2.8、MySQL 5.1.51a、PHP 5.2.4、VSFPTD)递归下载文件时,我发现我的脚本在一段时间后停止下载文件。我跟踪到调用 ftp_nlist 导致脚本停止。
为了解决这个问题,我执行了 ftp_pasv($ftp, true)。在客户端或服务器上都没有 VSFTPD、Apache 或 PHP 错误日志中的任何内容。非常奇怪。
您好,
我编写了这个函数来获取文件列表,我只在带有 linux ftp 的 php5 上测试过它。对我来说它工作得很好。
它将返回一个包含名称、类型(文件/文件夹)、所有者、所有者 ID 和权限的数组。
<?php
function ftp_get_filelist($con, $path){
$files = array();
$contents = ftp_rawlist ($con, $path);
$a = 0;
if(count($contents)){
foreach($contents as $line){
preg_match("#([drwx\-]+)([\s]+)([0-9]+)([\s]+)([0-9]+)([\s]+)([a-zA-Z0-9\.]+)([\s]+)([0-9]+)([\s]+)([a-zA-Z]+)([\s ]+)([0-9]+)([\s]+)([0-9]+):([0-9]+)([\s]+)([a-zA-Z0-9\.\-\_ ]+)#si", $line, $out);
if($out[3] != 1 && ($out[18] == "." || $out[18] == "..")){
// do nothing
} else {
$a++;
$files[$a]['rights'] = $out[1];
$files[$a]['type'] = $out[3] == 1 ? "file":"folder";
$files[$a]['owner_id'] = $out[5];
$files[$a]['owner'] = $out[7];
$files[$a]['date_modified'] = $out[11]." ".$out[13] . " ".$out[13].":".$out[16]."";
$files[$a]['name'] = $out[18];
}
}
}
return $files;
}
?>
您好,
雅各布
使用 ftp_nlist() 进行递归目录删除...
<?php
function ftp_rmdirr($path, $handle)
{
if (!(@ftp_rmdir($handle, $path) || @ftp_delete($handle, $path)))
{
$list = ftp_nlist($handle, $path);
if (!empty($list))
foreach($list as $value)
ftp_rmdirr($value, $handle);
}
@ftp_rmdir($handle, $path);
}
?>
如果它能内置到 php 中,那将非常有用。毕竟,大多数情况下我们也希望删除非空的目录。我相信每个使用文件系统的人都遇到过这个问题。
在 Windows 中,如果目录名称中包含空格,则 ftp_nlist 将会崩溃。为了解决这个问题,请使用 ftp_chdir
// 更改目录
ftp_chdir($conn, "包含空格的目录");
// 然后盲目列出
$contents = ftp_nlist($conn, "");
所以我写了一个简单的函数,使用 ftp_nlist() 递归地仅列出指定目录中的文件。
/**
* 返回给定目录中的文件列表,不包括目录。
*
* @param resource $ftp_stream
* FTP 连接的链接标识符。
* @param string $directory
* 要列出的目录。
* 请注意,此参数不会转义,因此文件名中包含空格和其他字符可能会出现一些问题。
* @param bool $recursive
* (可选)如果设置为 TRUE,则发出的命令将以递归方式执行。
*
* @return array
* 返回指定目录中的文件名数组。
*/
function ftp_files_list($ftp_stream, $directory, $recursive = false) {
$files = array();
$list = ftp_nlist($ftp_stream, $directory);
if (is_array($list)) {
// 删除点目录。
$list = array_slice($list, 2);
foreach ($list as $filename) {
$path = $directory . '/' . $filename;
// 如果大小等于 -1,则它是一个目录。
if (ftp_size($ftp_stream, $path) === -1) {
if ($recursive) {
$files = array_merge($files, ftp_files_list($ftp_stream, $path, $recursive));
}
} else {
// 删除根目录路径以确保所有文件路径都是相对的。
$files[] = substr($path, strpos($path, '/') + 1);
}
}
}
return $files;
}
我使用 ftp_rawlist() 创建了一个递归函数来列出所有文件夹和子文件夹中的所有文件。我使用了 ari 的以下函数 parse_rawlist()
function list_all_files($conn_id, $path){
$buff = ftp_rawlist($conn_id, $path);
$res = parse_rawlist( $buff) ;
static $flist = array();
if(count($res)>0){
foreach($res as $result){
// 验证是否是目录,如果不是则添加到文件列表中
if($result['size']== 0){
// 如果此文件是文件夹,则递归调用该函数
list_all_files($conn_id, $path.'/'.$result['name']);
}
else{
// 这是一个文件,添加到最终列表中
$flist[] = $result;
}
}
}
return $flist;
}
turigeza on yahoo com ftp_rmdirr() 函数的更好版本。
如果路径将被删除,则此函数返回 true 或 false
function ftp_rmdirr($handle, $path)
{
if(!@ftp_delete($handle, $path))
{
$list = @ftp_nlist($handle, $path);
if(!empty($list))
foreach($list as $value)
ftp_rmdirr($handle, $value);
}
if(@ftp_rmdir($handle, $path))
return true;
else
return false;
}
我们需要获取所有子目录中的所有文件的列表,但没有看到可以执行此操作的方法,因此我们自己编写了。
<?php
/**
* ftpRecursiveFileListing
*
* 获取给定 ftp 句柄和路径的所有子文件夹中的所有文件的递归列表
*
* @param resource $ftpConnection ftp 连接句柄
* @param string $path 文件夹/目录路径
* @return array $allFiles 文件列表,格式为:directory => $filename
* @author Niklas Berglund
* @author Vijay Mahrra
*/
function ftpRecursiveFileListing($ftpConnection, $path) {
static $allFiles = array();
$contents = ftp_nlist($ftpConnection, $path);
foreach($contents as $currentFile) {
// 假设如果名称中没有点,则它是一个文件夹
if (strpos($currentFile, '.') === false) {
ftpRecursiveFileListing($ftpConnection, $currentFile);
}
$allFiles[$path][] = substr($currentFile, strlen($path) + 1);
}
return $allFiles;
}
?>
我注意到,如果工作路径不同,此函数将无法正常工作,因为 $dir 会保留整个路径字符串的值。这就是为什么添加 basename() 函数会剥离路径,此函数也将适用于子文件夹,而不仅仅是根文件夹。
function ftp_is_dir($dir) {
global $ftp_connect;
if (ftp_chdir($ftp_connect, basename($dir))) {
ftp_chdir($ftp_connect, '..');
return true;
} else {
return false;
}
}
此函数返回一个数组,其中包含目录路径以及此目录中的所有文件和子目录
function ftp_searchdir($conn_id, $dir)
{
if( !@ftp_is_dir( $conn_id, $dir ) ) {
die( 'FTP 服务器上不存在此目录' );
}
if( strrchr( $dir, '/' ) != '/' ) {
$dir = $dir.'/';
}
$dirlist[0] = $dir;
$list = ftp_nlist( $conn_id, $dir );
foreach( $list as $path ) {
$path = './'.$path;
if( $path != $dir.'.' && $path != $dir.'..') {
if( ftp_is_dir( $conn_id, $path ) ) {
$temp = ftp_searchdir( $conn_id, ($path), 1 );
$dirlist = array_merge( $dirlist, $temp );
} else {
$dirlist[] = $path;
}
}
}
ftp_chdir( $conn_id, '/../' );
return $dirlist;
}
----------------------------------------------------------------------
// 检查目录 ($dir) 是否存在
// 返回 true 或 false
function ftp_is_dir( $conn_id, $dir )
{
if( @ftp_chdir( $conn_id, $dir ) ) {
ftp_chdir( $conn_id, '/../' );
return true;
} else {
return false;
}
}
以下函数使用 ftp_nlist 检查给定路径是否是目录;
<?php
function is_ftp_dir($itempath, $ftp_server, $ftp_user_name='anonymous', $ftp_user_pass='') {
if (empty($ftp_user_name)) {
$ftp_user_name = "anonymous";
}
if ($itempath[0]!=="/") {
$itempath = "/".$itempath;
}
$conn_id = ftp_connect($ftp_server);
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
$contents = ftp_nlist($conn_id, "$itempath");
if (!empty($contents[0])) {
$check = str_replace($itempath, "", $contents[0]);
if (!empty($check)) {
return true;
}
}
ftp_close($conn_id);
}
// example :
if (is_ftp_dir("/pub/ftp/unknownitem", "ftp.nowhere", 'username', 'verysecret'')) {
// do something related to directory handling action
} else {
// The target item is a file ...
}
?>
注意
该数组将包含完整路径,而不仅仅是文件名。 至少在我尝试使用 PHP 4.3.11 时
ftp_nlist("www.example.com/docs/some/thing")
它转储了类似这样的内容
[0]=>
string(41) "www.example.com/docs/some/thing/file1.htm"
[1]=>
string(41) "www.example.com/docs/some/thing/file2.htm"
[2]=>
string(41) "www.example.com/docs/some/thing/file3.htm"
[3]=>
string(41) "www.example.com/docs/some/thing/file4.htm"
[4]=>
string(41) "www.example.com/docs/some/thing/file5.htm"
一些 FTP 服务器将重音字符转换为字符“?”。 您可以尝试
<?php
$ftp = ftp_connect($ftp_server);
$login_result = ftp_login($ftp, $ftp_user_name, $ftp_user_pass);
ftp_raw($ftp, 'OPTS UTF8 ON'); // 将服务器设置为以 UTF 返回结果
$contents = ftp_nlist($ftp, ".");
var_dump($contents);
?>
有时,由于您服务器上的 NAT 或防火墙问题,您将无法获取文件夹内容。 因此,您需要将 ftp 连接置于被动模式
<?php
// 设置基本连接
$conn_id = ftp_connect($ftp_server);
// 使用用户名和密码登录
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
// 启用被动模式
ftp_pasv( $conn_id, true );
// 获取当前目录的内容
$contents = ftp_nlist($conn_id, ".");
// 输出 $contents
var_dump($contents);
?>
MAC OS 1.4 (Tiger) 上的 php 5.2.2 似乎默认为主动 ftp。 为了使 ftp_nlist 正常工作,我需要强制 ftp 为被动。
Windows XP 上的 PHP 5.2.3 的默认行为似乎是被动 ftp。
致敬,
wim
如果您由于某些 open_basedir 限制而收到错误,请使用以下方法
<?php
putenv('TMPDIR=/tmp/');
$filelist = ftp_nlist($ftp, "./accounts");
?>
(如果 /tmp/ 是 open_basedir 中允许的目录)
我花了一段时间才发现这一点。
如果我们将第二个参数作为完整目录路径提供,那么它将返回带有完整路径的文件列表,如果我们想只列出文件,您可以按照以下代码进行操作
// 设置基本连接
$conn_id = ftp_connect($ftp_server);
// 使用用户名和密码登录
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
// 如果您想显示来自 /home/test/ 的文件
// 使用以下命令更改目录指向 /home/test
ftp_chdir($conn_id, "test");
// 然后将第二个参数传递为空,这将提供文件列表。
// 获取当前目录的内容
$contents = ftp_nlist($conn_id, "");
注意:这在我的 PHP5 中有效
注意 tom at crysis-online dot com - 您建议的方法似乎取决于服务器。 我目前正在尝试与 proftpd 服务器通话,它似乎对所有文件的返回大小都是 -1。
此函数比以下函数快得多,用于检查对象是文件还是文件夹。
<?php
function is_ftp_dir($file, $ftp_connection){
if(ftp_size($ftp_connection, $file) == '-1'){
return true; // 是目录
}else{
return false; // 是文件
}
}
?>
继 kip 的帖子之后,这有效
if (!ftp_chdir($conn, $folder))
{
ftp_mkdir($conn, $folder);
ftp_chdir($conn, $folder);
}
ftp_nlist 函数的衍生用法:确定给定路径是否存在,以及它是目录还是普通文件(使用基本 ftp 函数并不容易)。 此代码不会发出任何警告或错误。 它使用 ls 选项 -d 提高效率,并使用 -F 在检索到的路径是目录时附加斜杠。
<?php
// 返回有关给定 ftp 路径的信息
// 如果路径不存在,则为 0
// 如果路径是文件,则为 1
// 如果路径是目录,则为 2
function ftp_pathtype( $conn, $path )
{
$res = ftp_nlist( $conn, "-dF " . $path );
if ( isset( $res[0] ) and
strlen( $res[0] ) )
{
if ( $res[0][ strlen( $res[0] )-1 ] === "/" )
// 是目录
return 2;
else
return 1;
} else
return 0;
}
?>
nekrostar at gmx dot net 的函数对我不起作用,所以我尝试用自己的方法来做。 为了检查找到的文件是目录还是文件,我使用 ftp_size 函数。
<?php
function ftplistdir($conn_id, $dir){
$fold_no = array(".", "..", "cgi-data", "comp", "zuern", "counter");
$list = ftp_nlist( $conn_id, $dir );
foreach($list as $file){
if (ftp_size($conn_id, $dir ."/".$file)== -1){
if (in_array($file, $fold_no)) {
print $file ." Ueberspringe ausgeschlossenes Verzeichnis.<br>";
} else {
$geslist[]= $dir ."/". $file;
$temp=ftplistdir($conn_id, $dir ."/". $file);
$geslist=array_merge($geslist, $temp);
}
}else{
$geslist[]= $dir ."/". $file;
}
}
return $geslist;
}
?>
我希望它对任何人都有用
Robert
注意在 Windows 服务器上使用 PHP 的开发人员:从 PHP 4.1.2 开始,ftp_nlist() 在 Windows 版本的 PHP 中已损坏。它将根本不返回任何内容,即使相同的代码在 UNIX 上可以正常工作。因此,如果您疯狂地试图找出为什么该函数没有返回任何内容,请停止浪费时间,您没有做错任何事。希望这将在未来的版本中得到修复,尽管它显然至少从 4.0.6 开始就存在问题。
有关此错误的更多信息,请访问 http://bugs.php.net/bug.php?id=16057
要使用自定义 LIST 标志,例如
LIST -aF ../*/
(列出受保护的公共目录)
您可以使用
<?php
$list = ftp_nlist($ftp, "-aF ../*/");
?>
花了我一段时间才想明白这一点 :-)
对 king_killa at juggalos4life dot com 的注释进行一个小小的更正,它不是 ftp_res,而是 ftp_size。
顺便说一下,这是一个完整的函数,它将获取服务器上的所有文件,然后将它们写入数组。
<?php
$ftp1 = ftp_connect('ftp.nowhere1230404.foo') or die("Couldn't connect to server");
ftp_login($ftp1,'foo','bar');
ftp_pasv($ftp1, TRUE); //Passive Mode is better for this
//Get them file!
echo "Collecting Files on Neodecoder<br>";
//Set defaults just in case. PHP complains anyway if we don't.
$dir = "";
function filecollect($dir,$filelist) {
global $ftp1; //Get our ftp
$files = ftp_nlist($ftp1,$dir); //get files in directory
foreach ($files as $file) {
$isfile = ftp_size($ftp1, $file);
if($isfile == "-1") { //Is a file or directory?
$filelist = filecollect($dir.'/'.$file,$filelist,$num); //If a folder, do a filecollect on it
}
else {
$filelist[(count($filelist)+1)] = $file; //If not, add it as a file to the file list
}
}
return $filelist;
}
$filelist = filecollect($dir,$filelist);
echo "<pre>";
print_r($filelist);
echo "</pre>";
?>
如果您尝试将所有文件从 ftp 服务器传输到另一个服务器,这真的很有用。这就是我一开始编写脚本的原因。呵呵..
这是一个读取整个 FTP 服务器(从您的根目录开始)的示例
function files($dir)
{
/*
if(!isset($dir) || empty($dir))
{
$dir=ftp_pwd($this->conn_id);
}
*/
unset($list);
unset($files);
unset($folders);
unset($folder);
unset($file);
@ftp_chdir($this->conn_id, $dir);
$dir = ftp_pwd($this->conn_id);
$list=Array();
$list=ftp_nlist($this->conn_id, "$dir");
$files = Array();
$folders = Array();
for($i = 0; $i != sizeof($list); $i++)
{
$entry = str_replace("//", "", $list[$i]);
if(@ftp_chdir($this->conn_id, $entry))
{
$folders[] = $entry;
ftp_chdir($this->conn_id, $dir);
}
else
{
$files[] = $entry;
}
}
print "\t<b> Dateien in ".$dir." :</b><br><br>";
foreach($files as $file)
{
print $file."<br>";
}
print "\t<b>Ordner in ".$dir." :</b> <br><br>";
foreach ($folders as $folder)
{
print "\t".$folder."<br>";
ftp_chdir($this->conn_id, $dir);
$this->files($folder);
}
}
如果您对特定文件执行通配符或其他搜索,而该文件不存在,Solaris FTP 服务器将返回“search*.xml: No such file or directory”作为响应数组中的单个元素。这使得很难检查文件是否存在。
一种可能的解决方法是解析您自己的原始目录列表。或者您可以检查错误的逐字表达。但是不同的服务器可能会返回不同的值。一种更简单的补偿方法是使用 ftp_size 命令来验证返回的文件
if ( ($filelist = ftp_nlist( $this->conn_id, $filesearch )) === FALSE )
{
Error( "Could not get file list" );
return FALSE;
}
// 文件实际存在?捕获无效的 FTP 服务器列表响应
if ( !count($filelist) || ftp_size( $this->conn_id, $filelist[0] ) == -1 )
{
Error( "No valid files" );
return FALSE;
}
// 文件确实存在,获取它或执行您想做的任何其他操作
实际上,这工作得更好(抑制 ftp_chdir() 失败时的错误)!
if (!@ftp_chdir($ftp_conn, $userfolder))
{
ftp_mkdir($ftp_conn, $userfolder);
ftp_chdir($ftp_conn, $userfolder);
}
有一些 FTP 服务器根本不接受 ftp_nlist 命令,它们返回一个布尔变量。但我认为它们都接受 LIST 命令,即 ftp_rawlist 命令。因此,您必须将 rawlist 解析为 nlist。我在“fredrik”发布的代码中发现了一个错误,如果 ftp 服务器上的文件名称中有空格,就会出现该错误......所以这里有一个更好的函数
function rawlist_2_nlist($list)
{
$newlist = array();
reset($list);
while (list(,$row) = each($list))
{
$buf="";
if ($row[0]=='d'||$row[0]=='-'){
$buf = substr($row,55);
$newlist[]=$buf;
}
}
return $newlist;
}
另一个 filecollect 脚本,使用静态。
<?php
function filecollect($conn_id,$dir='.') {
static $flist=array();
if ($files = ftp_nlist($cid,$dir)){
foreach ($files as $file) {
if (ftp_size($cid, $file) == "-1"){
filecollect($cid,$file);
} else $flist[] = $file;
}
}
return $flist;
}
$conn_id = ftp_connect('ftp.nowhere.com') or die("Couldn't connect to server");
if (@ftp_login($conn_id, 'anonymous', '[email protected]')){
$filelist = filecollect($conn_id);
echo "<pre>";
print_r($filelist);
echo "</pre>";
}
?>
为了在不支持 ftp_size() 的远程服务器上使文件/文件夹分离工作,最好使用下面提到的 ftp_is_dir() 函数
<?php
// 识别目录
function ftp_is_dir($dir) {
global $ftp_connect;
if (ftp_chdir($ftp_connect, $dir)) {
ftp_chdir($ftp_connect, '..');
return true;
} else {
return false;
}
}
$ftp_nlist = ftp_nlist($ftp_connect, ".");
// 按字母顺序排序
sort($ftp_nlist);
foreach ($ftp_nlist as $v) {
// 1. ftp_is_dir() 为真 => 目录
if (ftp_is_dir($v)) {
// 输出为 [ 目录 ]
echo "[ " . $v . " ]<br />\n";
}
}
foreach ($ftp_nlist as $v) {
// 2. ftp_is_dir() 为假 => 文件
if (!ftp_is_dir($v)) {
// 输出为文件
echo "" . $v . "<br />\n";
}
}
?>
如何按字母顺序获取文件列表,并将所有目录放在顶部
<?php
$ftp_nlist = ftp_nlist($ftp_connect, ".");
// 按字母顺序排序
sort($ftp_nlist);
foreach ($ftp_nlist as $v) {
// 1. 大小为 '-1' => 目录
if (ftp_size($ftp_connect, $v) == -1) {
// 输出为 [ 目录 ]
echo "[ " . $v . " ]<br />\n";
}
}
foreach ($ftp_nlist as $v) {
// 2. 大小不为 '-1' => 文件
if (!(ftp_size($ftp_connect, $v) == -1)) {
// 输出为文件
echo "" . $v . "<br />\n";
}
}
?>
结果如下所示
[ a_mydirectory ]
[ b_mydirectory ]
[ c_mydirectory ]
...
a_myfile.htm
b_myfile.css
c_myfile.php
...
您可以使用 ftp_nlist 进行通配符文件列表,例如
$list=ftp_nlist($conn_id, "$dir/*.txt");