PHP ftp_pwd() 函数

PHP ftp_pwd() 函数用于获取FTP服务器上的当前工作目录。

作用:此函数返回当前连接的FTP服务器上的当前目录路径,类似于Unix/Linux中的pwd命令。

语法

ftp_pwd(resource $ftp): string|false

参数说明

参数 描述
ftp 必需。FTP连接的标识符,由ftp_connect()ftp_ssl_connect()返回

返回值

  • 成功时返回当前目录的路径(字符串)
  • 失败时返回 false

与其他目录操作函数的关系

函数 功能 关系
ftp_pwd() 获取当前工作目录 基本目录查询
ftp_chdir() 改变当前工作目录 ftp_pwd()配合使用
ftp_cdup() 切换到上级目录 目录导航
ftp_mkdir() 创建新目录 创建后可能需要ftp_pwd()确认位置
ftp_rmdir() 删除目录 删除前可能需要ftp_pwd()确认当前目录
ftp_nlist() 列出目录内容 列出ftp_pwd()返回的目录内容

示例

示例1:基本用法 - 获取当前目录

<?php
// 连接FTP服务器
$ftp_server = "ftp.example.com";
$ftp_user = "username";
$ftp_pass = "password";

$ftp_conn = ftp_connect($ftp_server);
if (!$ftp_conn) {
    die("无法连接到 $ftp_server");
}

// 登录
if (!ftp_login($ftp_conn, $ftp_user, $ftp_pass)) {
    die("登录失败");
}

// 启用被动模式
ftp_pasv($ftp_conn, true);

// 获取当前目录
$current_dir = ftp_pwd($ftp_conn);

if ($current_dir !== false) {
    echo "当前目录: $current_dir\n";

    // 列出当前目录内容
    $file_list = ftp_nlist($ftp_conn, $current_dir);
    if ($file_list !== false) {
        echo "目录内容:\n";
        foreach ($file_list as $file) {
            echo "  - $file\n";
        }
    }
} else {
    echo "无法获取当前目录\n";
}

// 关闭FTP连接
ftp_close($ftp_conn);
?>

示例2:目录导航和追踪

<?php
class FTPNavigator {
    private $ftp_conn;
    private $history = [];
    private $max_history = 10;

    public function __construct($server, $username, $password) {
        $this->ftp_conn = ftp_connect($server);
        if (!$this->ftp_conn) {
            throw new Exception("无法连接到FTP服务器");
        }

        if (!ftp_login($this->ftp_conn, $username, $password)) {
            throw new Exception("FTP登录失败");
        }

        ftp_pasv($this->ftp_conn, true);

        // 记录初始目录
        $this->recordCurrentDir();
    }

    public function getCurrentDir() {
        $dir = ftp_pwd($this->ftp_conn);
        if ($dir === false) {
            throw new Exception("无法获取当前目录");
        }
        return $dir;
    }

    public function changeDir($directory) {
        $old_dir = $this->getCurrentDir();

        if (ftp_chdir($this->ftp_conn, $directory)) {
            $new_dir = $this->getCurrentDir();
            echo "目录切换成功: $old_dir -> $new_dir\n";
            $this->recordCurrentDir();
            return $new_dir;
        } else {
            echo "目录切换失败: 无法切换到 $directory\n";
            return false;
        }
    }

    public function goToParentDir() {
        if (ftp_cdup($this->ftp_conn)) {
            $new_dir = $this->getCurrentDir();
            echo "切换到上级目录: $new_dir\n";
            $this->recordCurrentDir();
            return $new_dir;
        } else {
            echo "无法切换到上级目录\n";
            return false;
        }
    }

    public function listCurrentDir($detailed = false) {
        $current_dir = $this->getCurrentDir();
        echo "当前目录: $current_dir\n";

        if ($detailed) {
            // 使用 rawlist 获取详细信息
            $list = ftp_rawlist($this->ftp_conn, $current_dir);
        } else {
            // 使用 nlist 获取简单列表
            $list = ftp_nlist($this->ftp_conn, $current_dir);
        }

        if ($list === false) {
            echo "无法列出目录内容\n";
            return [];
        }

        echo "目录内容 (" . count($list) . " 个项目):\n";

        if ($detailed) {
            foreach ($list as $item) {
                echo "  $item\n";
            }
        } else {
            foreach ($list as $item) {
                $basename = basename($item);
                // 判断是否是目录
                if ($this->isDirectory($item)) {
                    echo "  📁 $basename/\n";
                } else {
                    $size = ftp_size($this->ftp_conn, $item);
                    $size_str = ($size != -1) ? " (" . $this->formatBytes($size) . ")" : "";
                    echo "  📄 $basename$size_str\n";
                }
            }
        }

        return $list;
    }

    public function createDir($dir_name) {
        $current_dir = $this->getCurrentDir();
        $new_dir = rtrim($current_dir, '/') . '/' . $dir_name;

        if (ftp_mkdir($this->ftp_conn, $new_dir)) {
            echo "目录创建成功: $new_dir\n";
            return $new_dir;
        } else {
            echo "目录创建失败: $new_dir\n";
            return false;
        }
    }

    public function getHistory() {
        return $this->history;
    }

    public function goBack($steps = 1) {
        if (count($this->history) <= $steps) {
            echo "历史记录不足,无法后退 $steps 步\n";
            return false;
        }

        // 移除当前记录
        array_pop($this->history);

        // 后退指定步数
        for ($i = 1; $i < $steps; $i++) {
            array_pop($this->history);
        }

        // 获取目标目录
        $target = end($this->history);
        if ($target) {
            return $this->changeDir($target);
        }

        return false;
    }

    public function printPathInfo() {
        $current_dir = $this->getCurrentDir();
        $parts = explode('/', trim($current_dir, '/'));

        echo "路径分析:\n";
        echo "完整路径: $current_dir\n";
        echo "目录深度: " . count($parts) . "\n";

        if (!empty($parts)) {
            echo "路径组成:\n";
            $path_so_far = '';
            foreach ($parts as $index => $part) {
                $path_so_far .= '/' . $part;
                echo "  " . str_repeat('  ', $index) . "├── $part ($path_so_far)\n";
            }
        }

        // 检查权限
        echo "目录测试:\n";
        echo "  可读取: " . ($this->canReadDir() ? '✓' : '✗') . "\n";
        echo "  可写入: " . ($this->canWriteDir() ? '✓' : '✗') . "\n";
    }

    private function isDirectory($path) {
        $current = $this->getCurrentDir();

        // 尝试切换目录来判断
        if (@ftp_chdir($this->ftp_conn, $path)) {
            // 切换回原目录
            ftp_chdir($this->ftp_conn, $current);
            return true;
        }

        return false;
    }

    private function canReadDir() {
        $list = @ftp_nlist($this->ftp_conn, '.');
        return $list !== false;
    }

    private function canWriteDir() {
        // 尝试创建一个临时文件来测试写入权限
        $test_file = '.test_write_' . time();
        $result = @ftp_put($this->ftp_conn, $test_file, 'php://memory', FTP_ASCII);

        if ($result) {
            // 删除测试文件
            ftp_delete($this->ftp_conn, $test_file);
            return true;
        }

        return false;
    }

    private function recordCurrentDir() {
        $dir = $this->getCurrentDir();
        $this->history[] = $dir;

        // 限制历史记录长度
        if (count($this->history) > $this->max_history) {
            array_shift($this->history);
        }
    }

    private function formatBytes($bytes, $precision = 2) {
        if ($bytes <= 0) return '0 Bytes';

        $units = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        $base = log($bytes, 1024);
        $pow = floor($base);
        $pow = min($pow, count($units) - 1);

        return round(pow(1024, $base - $pow), $precision) . ' ' . $units[$pow];
    }

    public function __destruct() {
        if ($this->ftp_conn) {
            ftp_close($this->ftp_conn);
        }
    }
}

// 使用示例
try {
    $nav = new FTPNavigator('localhost', 'user', 'pass');

    echo "=== FTP目录导航演示 ===\n\n";

    // 显示当前目录
    $current_dir = $nav->getCurrentDir();
    echo "初始目录: $current_dir\n\n";

    // 列出目录内容
    $nav->listCurrentDir();

    echo "\n";

    // 创建新目录
    $nav->createDir('test_folder');

    // 切换到新目录
    $nav->changeDir('test_folder');

    // 再次列出目录内容
    $nav->listCurrentDir();

    // 返回上级目录
    $nav->goToParentDir();

    // 显示路径信息
    $nav->printPathInfo();

    // 显示历史记录
    echo "\n目录历史:\n";
    $history = $nav->getHistory();
    foreach ($history as $index => $dir) {
        echo "  [$index] $dir\n";
    }

} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}
?>

示例3:实用的目录操作工具

<?php
class FTPDirectoryManager {
    private $ftp_conn;

    public function __construct($ftp_conn) {
        $this->ftp_conn = $ftp_conn;
    }

    /**
     * 获取当前目录的详细信息
     */
    public function getDirectoryInfo($directory = null) {
        if ($directory === null) {
            $directory = ftp_pwd($this->ftp_conn);
            if ($directory === false) {
                return false;
            }
        }

        $info = [
            'path' => $directory,
            'exists' => false,
            'is_readable' => false,
            'is_writable' => false,
            'contents' => [],
            'file_count' => 0,
            'dir_count' => 0,
            'total_size' => 0
        ];

        // 检查目录是否存在
        $current_dir = ftp_pwd($this->ftp_conn);
        if (@ftp_chdir($this->ftp_conn, $directory)) {
            $info['exists'] = true;
            // 切换回原目录
            ftp_chdir($this->ftp_conn, $current_dir);
        } else {
            return $info; // 目录不存在,返回基本信息
        }

        // 获取目录内容
        $items = @ftp_nlist($this->ftp_conn, $directory);
        if ($items === false) {
            $info['is_readable'] = false;
            return $info;
        }

        $info['is_readable'] = true;

        foreach ($items as $item) {
            if ($item == '.' || $item == '..') {
                continue;
            }

            $item_info = $this->getItemInfo($item, $directory);

            if ($item_info['type'] == 'dir') {
                $info['dir_count']++;
            } else {
                $info['file_count']++;
                $info['total_size'] += $item_info['size'];
            }

            $info['contents'][] = $item_info;
        }

        // 检查写入权限
        $info['is_writable'] = $this->testWritePermission($directory);

        return $info;
    }

    /**
     * 获取文件/目录的详细信息
     */
    private function getItemInfo($item, $base_dir) {
        $full_path = rtrim($base_dir, '/') . '/' . basename($item);

        $info = [
            'name' => basename($item),
            'full_path' => $full_path,
            'type' => 'unknown',
            'size' => 0,
            'modified' => 0,
            'permissions' => ''
        ];

        // 尝试判断是否是目录
        $current_dir = ftp_pwd($this->ftp_conn);
        if (@ftp_chdir($this->ftp_conn, $full_path)) {
            $info['type'] = 'dir';
            // 切换回原目录
            ftp_chdir($this->ftp_conn, $current_dir);
        } else {
            $info['type'] = 'file';
            $info['size'] = ftp_size($this->ftp_conn, $full_path);
            if ($info['size'] == -1) {
                $info['size'] = 0;
            }
        }

        // 获取修改时间
        $mtime = ftp_mdtm($this->ftp_conn, $full_path);
        if ($mtime > 0) {
            $info['modified'] = $mtime;
            $info['modified_formatted'] = date('Y-m-d H:i:s', $mtime);
        }

        return $info;
    }

    /**
     * 测试目录的写入权限
     */
    private function testWritePermission($directory) {
        $test_file = rtrim($directory, '/') . '/.write_test_' . time();
        $test_content = 'test';

        // 尝试创建测试文件
        $temp_file = tempnam(sys_get_temp_dir(), 'ftp_test');
        file_put_contents($temp_file, $test_content);

        $result = @ftp_put($this->ftp_conn, $test_file, $temp_file, FTP_ASCII);

        unlink($temp_file);

        if ($result) {
            // 删除测试文件
            @ftp_delete($this->ftp_conn, $test_file);
            return true;
        }

        return false;
    }

    /**
     * 获取目录树
     */
    public function getDirectoryTree($directory = null, $max_depth = 3, $current_depth = 0) {
        if ($directory === null) {
            $directory = ftp_pwd($this->ftp_conn);
            if ($directory === false) {
                return false;
            }
        }

        if ($current_depth >= $max_depth) {
            return [
                'path' => $directory,
                'name' => basename($directory),
                'type' => 'dir',
                'truncated' => true
            ];
        }

        $tree = [
            'path' => $directory,
            'name' => basename($directory) ?: '/',
            'type' => 'dir',
            'contents' => []
        ];

        $items = @ftp_nlist($this->ftp_conn, $directory);
        if ($items === false) {
            $tree['error'] = '无法读取目录';
            return $tree;
        }

        foreach ($items as $item) {
            $basename = basename($item);
            if ($basename == '.' || $basename == '..') {
                continue;
            }

            $full_path = rtrim($directory, '/') . '/' . $basename;

            // 判断是否是目录
            $current_dir = ftp_pwd($this->ftp_conn);
            if (@ftp_chdir($this->ftp_conn, $full_path)) {
                // 是目录,递归处理
                ftp_chdir($this->ftp_conn, $current_dir);
                $subtree = $this->getDirectoryTree($full_path, $max_depth, $current_depth + 1);
                $tree['contents'][] = $subtree;
            } else {
                // 是文件
                $size = ftp_size($this->ftp_conn, $full_path);
                $tree['contents'][] = [
                    'path' => $full_path,
                    'name' => $basename,
                    'type' => 'file',
                    'size' => $size != -1 ? $size : 0
                ];
            }
        }

        return $tree;
    }

    /**
     * 格式化目录树为文本
     */
    public function formatTree($tree, $indent = '', $last = true) {
        $output = '';

        $prefix = $indent . ($last ? '└── ' : '├── ');
        $icon = $tree['type'] == 'dir' ? '📁 ' : '📄 ';

        $output .= $prefix . $icon . $tree['name'];

        if ($tree['type'] == 'file' && isset($tree['size'])) {
            $output .= ' (' . $this->formatBytes($tree['size']) . ')';
        }

        if (isset($tree['truncated'])) {
            $output .= ' [...]';
        }

        $output .= "\n";

        if (isset($tree['contents']) && is_array($tree['contents'])) {
            $child_indent = $indent . ($last ? '    ' : '│   ');
            $count = count($tree['contents']);

            foreach ($tree['contents'] as $i => $child) {
                $is_last = ($i == $count - 1);
                $output .= $this->formatTree($child, $child_indent, $is_last);
            }
        }

        return $output;
    }

    /**
     * 查找文件或目录
     */
    public function find($pattern, $directory = null, $search_type = 'both') {
        if ($directory === null) {
            $directory = ftp_pwd($this->ftp_conn);
            if ($directory === false) {
                return [];
            }
        }

        $results = [];

        $items = @ftp_nlist($this->ftp_conn, $directory);
        if ($items === false) {
            return $results;
        }

        foreach ($items as $item) {
            $basename = basename($item);
            if ($basename == '.' || $basename == '..') {
                continue;
            }

            $full_path = rtrim($directory, '/') . '/' . $basename;

            // 判断类型
            $current_dir = ftp_pwd($this->ftp_conn);
            $is_dir = @ftp_chdir($this->ftp_conn, $full_path);
            if ($is_dir) {
                ftp_chdir($this->ftp_conn, $current_dir);
                $type = 'dir';
            } else {
                $type = 'file';
            }

            // 检查是否匹配搜索条件
            $matches = false;
            if ($search_type == 'both' || $search_type == $type) {
                if (fnmatch($pattern, $basename)) {
                    $matches = true;
                }
            }

            if ($matches) {
                $results[] = [
                    'path' => $full_path,
                    'name' => $basename,
                    'type' => $type,
                    'size' => $type == 'file' ? ftp_size($this->ftp_conn, $full_path) : 0
                ];
            }

            // 如果是目录,递归搜索
            if ($is_dir) {
                $sub_results = $this->find($pattern, $full_path, $search_type);
                $results = array_merge($results, $sub_results);
            }
        }

        return $results;
    }

    private function formatBytes($bytes, $precision = 2) {
        if ($bytes <= 0) return '0 Bytes';

        $units = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        $base = log($bytes, 1024);
        $pow = floor($base);
        $pow = min($pow, count($units) - 1);

        return round(pow(1024, $base - $pow), $precision) . ' ' . $units[$pow];
    }
}

// 使用示例
$ftp_conn = ftp_connect('localhost');
if ($ftp_conn && ftp_login($ftp_conn, 'user', 'pass')) {
    ftp_pasv($ftp_conn, true);

    $manager = new FTPDirectoryManager($ftp_conn);

    echo "=== FTP目录管理工具 ===\n\n";

    // 获取当前目录信息
    $current_dir = ftp_pwd($ftp_conn);
    echo "当前目录: $current_dir\n\n";

    $dir_info = $manager->getDirectoryInfo();

    if ($dir_info) {
        echo "目录信息:\n";
        echo "路径: {$dir_info['path']}\n";
        echo "存在: " . ($dir_info['exists'] ? '是' : '否') . "\n";
        echo "可读: " . ($dir_info['is_readable'] ? '是' : '否') . "\n";
        echo "可写: " . ($dir_info['is_writable'] ? '是' : '否') . "\n";
        echo "文件数: {$dir_info['file_count']}\n";
        echo "目录数: {$dir_info['dir_count']}\n";
        echo "总大小: " . $manager->formatBytes($dir_info['total_size']) . "\n";

        if (!empty($dir_info['contents'])) {
            echo "\n目录内容:\n";
            foreach ($dir_info['contents'] as $item) {
                $icon = $item['type'] == 'dir' ? '📁' : '📄';
                $size = $item['type'] == 'file' ? ' (' . $manager->formatBytes($item['size']) . ')' : '';
                echo "  $icon {$item['name']}$size\n";
            }
        }
    }

    echo "\n=== 目录树结构 ===\n";
    $tree = $manager->getDirectoryTree('/', 2);
    echo $manager->formatTree($tree);

    echo "\n=== 文件搜索 ===\n";
    $results = $manager->find('*.txt', '/', 'file');
    echo "找到 " . count($results) . " 个文本文件:\n";
    foreach ($results as $result) {
        echo "  📄 {$result['path']}\n";
    }

    ftp_close($ftp_conn);
} else {
    echo "无法连接FTP服务器\n";
}
?>

注意事项

  • ftp_pwd() 返回的是服务器端的当前目录,可能与客户端本地目录不同
  • 某些FTP服务器可能不支持PWD命令,导致函数失败
  • 返回的路径格式可能因服务器操作系统而异(Unix使用/,Windows可能使用\
  • 在错误处理时,应检查返回值是否为false
  • 函数可能因网络问题或权限不足而失败
  • 返回的路径可能是绝对路径或相对路径,取决于服务器实现
  • 建议在关键操作前调用ftp_pwd()确认当前目录

最佳实践建议

推荐做法
  • 在执行目录相关操作前,先获取当前目录作为参考点
  • 保存初始目录,以便在操作完成后能够返回
  • 使用ftp_pwd()验证目录切换是否成功
  • 实现目录历史记录功能,方便导航
  • 在处理相对路径时,先获取当前目录作为基准
  • 在错误处理中提供有意义的错误信息,包含当前目录
避免做法
  • 不要假设ftp_pwd()总是成功,应检查返回值
  • 避免在不必要时频繁调用ftp_pwd(),可能影响性能
  • 不要假设返回的路径格式总是相同的
  • 避免硬编码目录路径,应使用ftp_pwd()获取当前目录
  • 不要忽略目录权限问题,结合ftp_pwd()检查可访问性
  • 避免在不安全的网络环境中暴露目录信息

常见问题解答

ftp_pwd() 返回 false 的可能原因:

  1. 连接问题:FTP连接已断开或无效
  2. 服务器不支持:某些FTP服务器可能不支持 PWD 命令
  3. 权限问题:当前用户没有权限获取目录信息
  4. 网络问题:网络中断或超时
  5. 服务器配置:服务器配置限制了 PWD 命令的使用
  6. 参数错误:传入的FTP连接资源无效

解决方法:检查连接状态、用户权限和服务器日志。

确保目录操作正确的策略:

  1. 保存初始目录:在开始操作前保存当前目录
  2. 使用绝对路径:尽量使用绝对路径而不是相对路径
  3. 验证目录切换:调用ftp_chdir()后,使用ftp_pwd()验证是否成功
  4. 实现错误恢复:操作失败时能够返回到已知的安全目录
  5. 记录目录历史:记录目录变更历史,便于调试和恢复
  6. 使用目录管理器:封装目录操作为类,提供更安全的方法
// 示例:安全的目录操作
$start_dir = ftp_pwd($ftp);
// 执行操作...
// 如果失败,返回起始目录
ftp_chdir($ftp, $start_dir);

函数 作用 返回值 用途
ftp_pwd() 获取当前工作目录的路径 字符串(路径)或 false 获取当前位置,用于导航和验证
ftp_nlist('.') 列出当前目录的内容 数组(文件名列表)或 false 查看当前目录包含哪些文件和目录

简单来说:

  • ftp_pwd() 告诉你"你在哪里"
  • ftp_nlist('.') 告诉你"这里有什么"

相关函数

  • ftp_chdir() - 改变当前工作目录
  • ftp_cdup() - 切换到上级目录
  • ftp_mkdir() - 在FTP服务器上创建目录
  • ftp_rmdir() - 删除FTP服务器上的目录
  • ftp_nlist() - 列出FTP目录中的文件
  • ftp_rawlist() - 返回目录的详细列表
  • ftp_size() - 返回指定文件的大小
  • ftp_mdtm() - 返回指定文件的最后修改时间