PHP ftp_chdir() 函数

注意:ftp_chdir() 函数需要启用FTP扩展。在使用前请确保已安装并启用FTP扩展。

定义和用法

ftp_chdir() 函数用于改变FTP服务器上的当前工作目录。它是FTP协议中 CWD 命令的PHP实现。

使用此函数可以在FTP服务器上导航到不同的目录,便于后续的文件操作(如上传、下载、删除等)。

  • 功能:改变当前工作目录
  • 作用域:在FTP服务器上操作,不影响本地文件系统
  • 权限要求:需要对该目录有读取权限
  • 兼容性:几乎所有FTP服务器都支持此命令

语法

ftp_chdir(resource $ftp_stream, string $directory): bool

参数值

参数 描述
$ftp_stream FTP连接资源。由 ftp_connect()ftp_ssl_connect() 函数返回的连接标识符。
$directory 目标目录。要切换到的目录路径。
  • 可以是绝对路径(以 / 开头)
  • 可以是相对路径(相对于当前目录)
  • 支持 .(当前目录)和 ..(父目录)
  • 路径分隔符通常是 /(Unix风格)

返回值

  • 成功时返回 true
  • 失败时返回 false
常见失败原因:
  1. 目录不存在
  2. 没有访问权限
  3. FTP连接已断开
  4. 路径格式错误

路径类型示例

路径类型 示例 描述
绝对路径 /home/user/public_html 从根目录开始的完整路径
相对路径 public_html/images 相对于当前目录的路径
上级目录 .. 切换到父目录
当前目录 . 保持在当前目录(通常无意义)
多级向上 ../../uploads 向上两级,然后进入uploads目录

示例

示例 1:基本用法 - 切换FTP目录

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

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

// 登录到FTP服务器
if (@ftp_login($conn_id, $ftp_user, $ftp_pass)) {
    echo "已连接到 $ftp_server,用户为 $ftp_user<br>";
} else {
    echo "无法以 $ftp_user 身份登录<br>";
    ftp_close($conn_id);
    exit;
}

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

// 获取当前目录
$current_dir = ftp_pwd($conn_id);
echo "当前目录: " . htmlspecialchars($current_dir) . "<br>";

// 切换到 public_html 目录(相对路径)
if (ftp_chdir($conn_id, "public_html")) {
    echo "成功切换到 public_html 目录<br>";
    $current_dir = ftp_pwd($conn_id);
    echo "当前目录: " . htmlspecialchars($current_dir) . "<br>";
} else {
    echo "无法切换到 public_html 目录<br>";
}

// 切换到 images 子目录
if (ftp_chdir($conn_id, "images")) {
    echo "成功切换到 images 子目录<br>";
    $current_dir = ftp_pwd($conn_id);
    echo "当前目录: " . htmlspecialchars($current_dir) . "<br>";
}

// 使用绝对路径切换到根目录
if (ftp_chdir($conn_id, "/")) {
    echo "成功切换到根目录<br>";
    $current_dir = ftp_pwd($conn_id);
    echo "当前目录: " . htmlspecialchars($current_dir) . "<br>";
}

// 切换到父目录
if (ftp_chdir($conn_id, "..")) {
    echo "成功切换到父目录(由于在根目录,可能失败)<br>";
} else {
    echo "无法切换到父目录(可能在根目录)<br>";
}

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

示例 2:封装安全的目录操作类

<?php
/**
 * 安全的FTP目录操作类
 */
class SecureFTPDirectory {
    private $conn_id;
    private $current_path;
    private $history = [];
    private $max_history = 50;

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

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

        ftp_pasv($this->conn_id, true);
        $this->current_path = $this->getCurrentDirectory();
        $this->addToHistory($this->current_path);
    }

    /**
     * 获取当前目录
     */
    private function getCurrentDirectory() {
        $dir = @ftp_pwd($this->conn_id);
        if ($dir === false) {
            throw new Exception("无法获取当前目录");
        }
        return $dir;
    }

    /**
     * 添加到历史记录
     */
    private function addToHistory($path) {
        $this->history[] = $path;

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

    /**
     * 安全的改变目录
     */
    public function changeDirectory($directory) {
        // 验证目录参数
        if (!is_string($directory) || trim($directory) === '') {
            throw new InvalidArgumentException("目录参数不能为空");
        }

        $original_path = $this->current_path;

        try {
            // 尝试切换目录
            if (!@ftp_chdir($this->conn_id, $directory)) {
                throw new Exception("无法切换到目录: $directory");
            }

            // 验证切换是否成功
            $new_path = $this->getCurrentDirectory();

            // 检查是否真的改变了目录
            if ($new_path === $original_path && $directory !== '.' && $directory !== './') {
                // 这可能意味着目录不存在或权限不足
                throw new Exception("目录切换失败或目录不存在: $directory");
            }

            $this->current_path = $new_path;
            $this->addToHistory($new_path);

            return [
                'success' => true,
                'from' => $original_path,
                'to' => $new_path,
                'message' => "成功切换到目录: $new_path"
            ];

        } catch (Exception $e) {
            // 恢复原始目录
            @ftp_chdir($this->conn_id, $original_path);
            $this->current_path = $original_path;

            return [
                'success' => false,
                'error' => $e->getMessage(),
                'attempted' => $directory,
                'current' => $original_path
            ];
        }
    }

    /**
     * 切换到绝对路径
     */
    public function changeToAbsolutePath($absolute_path) {
        // 确保路径以/开头
        if (strpos($absolute_path, '/') !== 0) {
            $absolute_path = '/' . $absolute_path;
        }

        return $this->changeDirectory($absolute_path);
    }

    /**
     * 切换到父目录
     */
    public function goToParent() {
        return $this->changeDirectory('..');
    }

    /**
     * 导航到指定路径(支持相对和绝对路径)
     */
    public function navigateTo($path) {
        // 处理相对路径
        if (strpos($path, '/') !== 0) {
            // 相对路径:基于当前目录
            $path = $this->normalizePath($this->current_path . '/' . $path);
        }

        return $this->changeToAbsolutePath($path);
    }

    /**
     * 规范化路径
     */
    private function normalizePath($path) {
        $path = str_replace('\\', '/', $path);
        $parts = explode('/', $path);
        $result = [];

        foreach ($parts as $part) {
            if ($part === '' || $part === '.') {
                continue;
            }

            if ($part === '..') {
                if (!empty($result)) {
                    array_pop($result);
                }
            } else {
                $result[] = $part;
            }
        }

        return '/' . implode('/', $result);
    }

    /**
     * 获取当前路径
     */
    public function getCurrentPath() {
        return $this->current_path;
    }

    /**
     * 检查目录是否存在
     */
    public function directoryExists($directory) {
        $current = $this->current_path;

        try {
            $result = $this->changeDirectory($directory);
            // 切换回原始目录
            $this->changeDirectory($current);
            return $result['success'];
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * 获取目录历史
     */
    public function getHistory() {
        return $this->history;
    }

    /**
     * 列出目录内容
     */
    public function listDirectory($path = '.') {
        $result = $this->changeDirectory($path);
        if (!$result['success']) {
            return $result;
        }

        $list = @ftp_nlist($this->conn_id, '.');
        if ($list === false) {
            return [
                'success' => false,
                'error' => '无法列出目录内容',
                'path' => $this->current_path
            ];
        }

        // 切换回原始目录
        $original_path = $result['from'];
        $this->changeDirectory($original_path);

        return [
            'success' => true,
            'path' => $result['to'],
            'items' => $list,
            'count' => count($list)
        ];
    }

    /**
     * 创建目录
     */
    public function createDirectory($directory_name, $recursive = false) {
        if ($recursive) {
            return $this->createDirectoryRecursive($directory_name);
        }

        if (!@ftp_mkdir($this->conn_id, $directory_name)) {
            return [
                'success' => false,
                'error' => "无法创建目录: $directory_name"
            ];
        }

        return [
            'success' => true,
            'message' => "成功创建目录: $directory_name"
        ];
    }

    /**
     * 递归创建目录
     */
    private function createDirectoryRecursive($directory_name) {
        $parts = explode('/', trim($directory_name, '/'));
        $current_path = $this->current_path;

        foreach ($parts as $part) {
            if (!@ftp_chdir($this->conn_id, $part)) {
                if (!@ftp_mkdir($this->conn_id, $part)) {
                    // 恢复原始路径
                    @ftp_chdir($this->conn_id, $current_path);
                    return [
                        'success' => false,
                        'error' => "无法创建目录: $part"
                    ];
                }
                @ftp_chdir($this->conn_id, $part);
            }
        }

        // 恢复原始路径
        @ftp_chdir($this->conn_id, $current_path);

        return [
            'success' => true,
            'message' => "成功创建目录: $directory_name"
        ];
    }

    /**
     * 关闭连接
     */
    public function close() {
        if ($this->conn_id) {
            ftp_close($this->conn_id);
            $this->conn_id = null;
        }
    }

    public function __destruct() {
        $this->close();
    }
}

// 使用示例
echo "<h4>安全的FTP目录操作示例:</h4>";

try {
    // 创建安全FTP目录操作实例
    $ftp = new SecureFTPDirectory(
        "ftp.example.com",
        "username",
        "password"
    );

    echo "初始目录: " . htmlspecialchars($ftp->getCurrentPath()) . "<br><br>";

    // 示例1:切换到相对路径
    echo "<strong>示例1:切换到相对路径</strong><br>";
    $result = $ftp->changeDirectory("public_html");
    if ($result['success']) {
        echo "✓ " . $result['message'] . "<br>";
        echo "  从: " . htmlspecialchars($result['from']) . "<br>";
        echo "  到: " . htmlspecialchars($result['to']) . "<br><br>";
    } else {
        echo "✗ " . $result['error'] . "<br><br>";
    }

    // 示例2:切换到绝对路径
    echo "<strong>示例2:切换到绝对路径</strong><br>";
    $result = $ftp->changeToAbsolutePath("/var/www/html");
    if ($result['success']) {
        echo "✓ " . $result['message'] . "<br><br>";
    } else {
        echo "✗ " . $result['error'] . "<br><br>";
    }

    // 示例3:切换到父目录
    echo "<strong>示例3:切换到父目录</strong><br>";
    $result = $ftp->goToParent();
    if ($result['success']) {
        echo "✓ " . $result['message'] . "<br><br>";
    } else {
        echo "✗ " . $result['error'] . "<br><br>";
    }

    // 示例4:导航到路径(自动处理相对/绝对)
    echo "<strong>示例4:导航到复杂路径</strong><br>";
    $result = $ftp->navigateTo("uploads/2023/images");
    if ($result['success']) {
        echo "✓ " . $result['message'] . "<br><br>";
    } else {
        echo "✗ " . $result['error'] . "<br><br>";
    }

    // 示例5:检查目录是否存在
    echo "<strong>示例5:检查目录是否存在</strong><br>";
    $exists = $ftp->directoryExists("uploads");
    echo "目录 'uploads' " . ($exists ? "存在" : "不存在") . "<br><br>";

    // 示例6:列出目录内容
    echo "<strong>示例6:列出目录内容</strong><br>";
    $result = $ftp->listDirectory();
    if ($result['success']) {
        echo "目录: " . htmlspecialchars($result['path']) . "<br>";
        echo "包含 " . $result['count'] . " 个项目:<br>";
        foreach ($result['items'] as $item) {
            echo "  - " . htmlspecialchars(basename($item)) . "<br>";
        }
    } else {
        echo "✗ " . $result['error'] . "<br>";
    }

    // 显示历史记录
    echo "<br><strong>目录历史记录:</strong><br>";
    $history = $ftp->getHistory();
    foreach ($history as $index => $path) {
        echo ($index + 1) . ". " . htmlspecialchars($path) . "<br>";
    }

    // 自动关闭连接

} catch (Exception $e) {
    echo "<div class='alert alert-danger'>错误: " . htmlspecialchars($e->getMessage()) . "</div>";
}
?>

示例 3:FTP文件管理器实现

<?php
/**
 * FTP文件管理器类
 */
class FTPFileManager {
    private $conn_id;
    private $current_path;
    private $session_id;

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

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

        ftp_pasv($this->conn_id, true);
        $this->current_path = ftp_pwd($this->conn_id);
        $this->session_id = $session_id ?: uniqid('ftp_', true);

        // 初始化会话数据
        $this->initSession();
    }

    /**
     * 初始化会话数据
     */
    private function initSession() {
        if (!isset($_SESSION['ftp_manager'][$this->session_id])) {
            $_SESSION['ftp_manager'][$this->session_id] = [
                'history' => [],
                'bookmarks' => [],
                'last_operation' => null
            ];
        }

        $this->addToHistory($this->current_path);
    }

    /**
     * 添加到历史记录
     */
    private function addToHistory($path) {
        $_SESSION['ftp_manager'][$this->session_id]['history'][] = [
            'path' => $path,
            'time' => time()
        ];

        // 限制历史记录数量
        if (count($_SESSION['ftp_manager'][$this->session_id]['history']) > 100) {
            array_shift($_SESSION['ftp_manager'][$this->session_id]['history']);
        }
    }

    /**
     * 改变目录
     */
    public function changeDirectory($directory) {
        $original_path = $this->current_path;

        if (!@ftp_chdir($this->conn_id, $directory)) {
            throw new Exception("无法切换到目录: $directory");
        }

        $this->current_path = ftp_pwd($this->conn_id);
        $this->addToHistory($this->current_path);

        // 记录操作
        $_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
            'type' => 'change_directory',
            'from' => $original_path,
            'to' => $this->current_path,
            'time' => time()
        ];

        return $this->current_path;
    }

    /**
     * 获取当前目录信息
     */
    public function getCurrentDirectoryInfo() {
        $info = [
            'path' => $this->current_path,
            'items' => [],
            'stats' => [
                'directories' => 0,
                'files' => 0,
                'total_size' => 0
            ]
        ];

        $items = @ftp_rawlist($this->conn_id, '.');
        if ($items === false) {
            return $info;
        }

        foreach ($items as $item) {
            $parsed = $this->parseRawListItem($item);
            if ($parsed) {
                $info['items'][] = $parsed;

                if ($parsed['type'] === 'dir') {
                    $info['stats']['directories']++;
                } else {
                    $info['stats']['files']++;
                    $info['stats']['total_size'] += $parsed['size'];
                }
            }
        }

        return $info;
    }

    /**
     * 解析原始列表项
     */
    private function parseRawListItem($line) {
        // Unix格式解析
        if (preg_match('/^([-d])([-rwxs]{9})\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\w{3}\s+\d+\s+[\d:]+)\s+(.+)$/', $line, $matches)) {
            return [
                'type' => $matches[1] === 'd' ? 'dir' : 'file',
                'permissions' => $matches[2],
                'links' => (int)$matches[3],
                'owner' => $matches[4],
                'group' => $matches[5],
                'size' => (int)$matches[6],
                'date' => $matches[7],
                'name' => $matches[8],
                'icon' => $matches[1] === 'd' ? 'folder' : 'file'
            ];
        }

        return null;
    }

    /**
     * 上传文件
     */
    public function uploadFile($local_path, $remote_name = null) {
        if (!file_exists($local_path)) {
            throw new Exception("本地文件不存在: $local_path");
        }

        if (!$remote_name) {
            $remote_name = basename($local_path);
        }

        if (!@ftp_put($this->conn_id, $remote_name, $local_path, FTP_BINARY)) {
            throw new Exception("文件上传失败: $local_path");
        }

        // 记录操作
        $_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
            'type' => 'upload_file',
            'file' => $remote_name,
            'size' => filesize($local_path),
            'time' => time()
        ];

        return true;
    }

    /**
     * 下载文件
     */
    public function downloadFile($remote_name, $local_path = null) {
        if (!$local_path) {
            $local_path = './downloads/' . $remote_name;
        }

        // 确保下载目录存在
        $dir = dirname($local_path);
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        if (!@ftp_get($this->conn_id, $local_path, $remote_name, FTP_BINARY)) {
            throw new Exception("文件下载失败: $remote_name");
        }

        // 记录操作
        $_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
            'type' => 'download_file',
            'file' => $remote_name,
            'local_path' => $local_path,
            'time' => time()
        ];

        return $local_path;
    }

    /**
     * 创建目录
     */
    public function createDirectory($name) {
        if (!@ftp_mkdir($this->conn_id, $name)) {
            throw new Exception("无法创建目录: $name");
        }

        // 记录操作
        $_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
            'type' => 'create_directory',
            'name' => $name,
            'path' => $this->current_path . '/' . $name,
            'time' => time()
        ];

        return true;
    }

    /**
     * 删除文件或目录
     */
    public function delete($name) {
        // 检查是文件还是目录
        if (@ftp_chdir($this->conn_id, $name)) {
            // 是目录,切换回
            ftp_chdir($this->conn_id, '..');

            // 递归删除目录
            if (!$this->deleteDirectoryRecursive($name)) {
                throw new Exception("无法删除目录: $name");
            }
        } else {
            // 是文件
            if (!@ftp_delete($this->conn_id, $name)) {
                throw new Exception("无法删除文件: $name");
            }
        }

        // 记录操作
        $_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
            'type' => 'delete',
            'name' => $name,
            'time' => time()
        ];

        return true;
    }

    /**
     * 递归删除目录
     */
    private function deleteDirectoryRecursive($directory) {
        $items = @ftp_nlist($this->conn_id, $directory);

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

                $full_path = $directory . '/' . basename($item);

                if (@ftp_chdir($this->conn_id, $full_path)) {
                    ftp_chdir($this->conn_id, '..');
                    $this->deleteDirectoryRecursive($full_path);
                } else {
                    @ftp_delete($this->conn_id, $full_path);
                }
            }
        }

        return @ftp_rmdir($this->conn_id, $directory);
    }

    /**
     * 重命名文件或目录
     */
    public function rename($old_name, $new_name) {
        if (!@ftp_rename($this->conn_id, $old_name, $new_name)) {
            throw new Exception("重命名失败: $old_name -> $new_name");
        }

        // 记录操作
        $_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
            'type' => 'rename',
            'old_name' => $old_name,
            'new_name' => $new_name,
            'time' => time()
        ];

        return true;
    }

    /**
     * 添加书签
     */
    public function addBookmark($name, $path = null) {
        if (!$path) {
            $path = $this->current_path;
        }

        $_SESSION['ftp_manager'][$this->session_id]['bookmarks'][$name] = [
            'path' => $path,
            'time' => time()
        ];

        return true;
    }

    /**
     * 跳转到书签
     */
    public function goToBookmark($name) {
        if (!isset($_SESSION['ftp_manager'][$this->session_id]['bookmarks'][$name])) {
            throw new Exception("书签不存在: $name");
        }

        $path = $_SESSION['ftp_manager'][$this->session_id]['bookmarks'][$name]['path'];
        return $this->changeDirectory($path);
    }

    /**
     * 获取书签列表
     */
    public function getBookmarks() {
        return $_SESSION['ftp_manager'][$this->session_id]['bookmarks'];
    }

    /**
     * 获取操作历史
     */
    public function getHistory() {
        return $_SESSION['ftp_manager'][$this->session_id]['history'];
    }

    /**
     * 获取最后操作
     */
    public function getLastOperation() {
        return $_SESSION['ftp_manager'][$this->session_id]['last_operation'];
    }

    /**
     * 渲染文件管理器界面
     */
    public function renderInterface() {
        $info = $this->getCurrentDirectoryInfo();

        echo "<div class='ftp-file-manager'>";
        echo "<div class='card'>";

        // 头部:路径导航
        echo "<div class='card-header bg-light'>";
        echo "<div class='row align-items-center'>";
        echo "<div class='col-md-8'>";
        echo "<h5 class='mb-0'><i class='fas fa-folder'></i> " . htmlspecialchars($this->current_path) . "</h5>";
        echo "</div>";
        echo "<div class='col-md-4 text-end'>";

        // 父目录按钮
        if ($this->current_path !== '/') {
            echo "<button class='btn btn-sm btn-outline-primary' onclick='ftpGoToParent()'>";
            echo "<i class='fas fa-level-up-alt'></i> 上级目录";
            echo "</button> ";
        }

        // 根目录按钮
        echo "<button class='btn btn-sm btn-outline-secondary' onclick='ftpGoToRoot()'>";
        echo "<i class='fas fa-home'></i> 根目录";
        echo "</button>";

        echo "</div>";
        echo "</div>";
        echo "</div>";

        // 统计信息
        echo "<div class='card-body py-2 bg-light'>";
        echo "<small class='text-muted'>";
        echo "目录: {$info['stats']['directories']} | ";
        echo "文件: {$info['stats']['files']} | ";
        echo "大小: " . $this->formatSize($info['stats']['total_size']);
        echo "</small>";
        echo "</div>";

        // 文件列表
        echo "<div class='card-body p-0'>";
        echo "<div class='table-responsive'>";
        echo "<table class='table table-hover mb-0'>";
        echo "<thead class='table-light'>";
        echo "<tr><th>名称</th><th>大小</th><th>修改时间</th><th>权限</th><th>操作</th></tr>";
        echo "</thead>";
        echo "<tbody>";

        // 父目录链接
        if ($this->current_path !== '/') {
            echo "<tr onclick='ftpChangeDirectory(\"..\")' style='cursor: pointer;'>";
            echo "<td><i class='fas fa-level-up-alt text-primary'></i> ..</td>";
            echo "<td>-</td><td>-</td><td>-</td><td></td>";
            echo "</tr>";
        }

        // 目录和文件列表
        foreach ($info['items'] as $item) {
            $icon = $item['type'] === 'dir' ? '<i class="fas fa-folder text-warning"></i>' :
                                            '<i class="fas fa-file text-secondary"></i>';
            $size = $item['type'] === 'dir' ? '-' : $this->formatSize($item['size']);

            echo "<tr>";
            echo "<td>$icon " . htmlspecialchars($item['name']) . "</td>";
            echo "<td>$size</td>";
            echo "<td>" . htmlspecialchars($item['date']) . "</td>";
            echo "<td>" . htmlspecialchars($item['permissions']) . "</td>";

            echo "<td>";
            if ($item['type'] === 'dir') {
                echo "<button class='btn btn-sm btn-outline-primary' onclick='ftpChangeDirectory(\"" . htmlspecialchars($item['name']) . "\")'>进入</button> ";
            } else {
                echo "<button class='btn btn-sm btn-outline-success' onclick='ftpDownloadFile(\"" . htmlspecialchars($item['name']) . "\")'>下载</button> ";
            }
            echo "<button class='btn btn-sm btn-outline-danger' onclick='ftpDeleteItem(\"" . htmlspecialchars($item['name']) . "\")'>删除</button>";
            echo "</td>";

            echo "</tr>";
        }

        echo "</tbody>";
        echo "</table>";
        echo "</div>";
        echo "</div>";

        // 操作面板
        echo "<div class='card-footer bg-light'>";
        echo "<div class='row'>";
        echo "<div class='col-md-6'>";
        echo "<div class='input-group input-group-sm'>";
        echo "<input type='text' id='ftpNewDir' class='form-control' placeholder='新目录名'>";
        echo "<button class='btn btn-outline-success' onclick='ftpCreateDirectory()'>创建目录</button>";
        echo "</div>";
        echo "</div>";
        echo "<div class='col-md-6'>";
        echo "<div class='input-group input-group-sm'>";
        echo "<input type='file' id='ftpUploadFile' class='form-control'>";
        echo "<button class='btn btn-outline-primary' onclick='ftpUploadFile()'>上传文件</button>";
        echo "</div>";
        echo "</div>";
        echo "</div>";
        echo "</div>";

        echo "</div>";
        echo "</div>";
    }

    /**
     * 格式化文件大小
     */
    private function formatSize($bytes) {
        if ($bytes == 0) return '0 B';
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $i = floor(log($bytes, 1024));
        return round($bytes / pow(1024, $i), 2) . ' ' . $units[$i];
    }

    /**
     * 关闭连接
     */
    public function close() {
        if ($this->conn_id) {
            ftp_close($this->conn_id);
            $this->conn_id = null;
        }
    }

    public function __destruct() {
        $this->close();
    }
}

// 使用示例(需要会话支持)
echo "<h4>FTP文件管理器示例:</h4>";

// 启动会话(如果尚未启动)
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

try {
    // 创建FTP文件管理器实例
    // 注意:在实际应用中,这些参数应该来自表单输入或配置文件
    $ftp_manager = new FTPFileManager(
        "ftp.example.com",
        "username",
        "password",
        "example_session"
    );

    // 处理操作(在实际应用中应该通过AJAX或表单提交处理)
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // 这里应该处理各种操作
        // 为了示例清晰,省略具体处理代码
    }

    // 渲染文件管理器界面
    $ftp_manager->renderInterface();

    // 显示附加信息
    echo "<div class='row mt-3'>";

    // 历史记录
    echo "<div class='col-md-6'>";
    echo "<div class='card'>";
    echo "<div class='card-header'>最近访问</div>";
    echo "<div class='card-body' style='max-height: 200px; overflow-y: auto;'>";
    $history = $ftp_manager->getHistory();
    foreach (array_slice($history, -5) as $item) {
        echo "<div>" . date('H:i:s', $item['time']) . " - " . htmlspecialchars($item['path']) . "</div>";
    }
    echo "</div></div></div>";

    // 最后操作
    echo "<div class='col-md-6'>";
    echo "<div class='card'>";
    echo "<div class='card-header'>最后操作</div>";
    echo "<div class='card-body'>";
    $last_op = $ftp_manager->getLastOperation();
    if ($last_op) {
        echo "类型: " . htmlspecialchars($last_op['type']) . "<br>";
        echo "时间: " . date('Y-m-d H:i:s', $last_op['time']) . "<br>";
        if (isset($last_op['file'])) {
            echo "文件: " . htmlspecialchars($last_op['file']) . "<br>";
        }
    } else {
        echo "暂无操作记录";
    }
    echo "</div></div></div>";

    echo "</div>";

    // 添加JavaScript函数(简化版)
    echo "<script>
    function ftpChangeDirectory(dir) {
        alert('在实际应用中,这里会通过AJAX调用changeDirectory方法,切换到: ' + dir);
    }
    function ftpGoToParent() {
        ftpChangeDirectory('..');
    }
    function ftpGoToRoot() {
        ftpChangeDirectory('/');
    }
    function ftpDownloadFile(file) {
        alert('下载文件: ' + file);
    }
    function ftpDeleteItem(item) {
        if (confirm('确定要删除 ' + item + ' 吗?')) {
            alert('删除: ' + item);
        }
    }
    function ftpCreateDirectory() {
        var dir = document.getElementById('ftpNewDir').value;
        if (dir) {
            alert('创建目录: ' + dir);
        }
    }
    function ftpUploadFile() {
        var file = document.getElementById('ftpUploadFile').files[0];
        if (file) {
            alert('上传文件: ' + file.name);
        }
    }
    </script>";

} catch (Exception $e) {
    echo "<div class='alert alert-danger'>错误: " . htmlspecialchars($e->getMessage()) . "</div>";
}
?>

示例 4:批量目录操作

<?php
/**
 * FTP批量目录操作类
 */
class FTPBatchOperations {
    private $conn_id;

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

    /**
     * 批量创建目录
     */
    public function createDirectories($directories) {
        $results = [];
        $success_count = 0;
        $fail_count = 0;

        foreach ($directories as $directory) {
            $result = $this->createDirectory($directory);
            $results[] = $result;

            if ($result['success']) {
                $success_count++;
            } else {
                $fail_count++;
            }
        }

        return [
            'total' => count($directories),
            'success' => $success_count,
            'failed' => $fail_count,
            'results' => $results
        ];
    }

    /**
     * 创建单个目录
     */
    private function createDirectory($directory) {
        $original_dir = ftp_pwd($this->conn_id);

        try {
            if (@ftp_mkdir($this->conn_id, $directory)) {
                return [
                    'success' => true,
                    'directory' => $directory,
                    'message' => '目录创建成功'
                ];
            } else {
                return [
                    'success' => false,
                    'directory' => $directory,
                    'error' => '目录创建失败'
                ];
            }
        } catch (Exception $e) {
            return [
                'success' => false,
                'directory' => $directory,
                'error' => $e->getMessage()
            ];
        } finally {
            @ftp_chdir($this->conn_id, $original_dir);
        }
    }

    /**
     * 批量切换目录并执行操作
     */
    public function executeInDirectories($operations) {
        $results = [];
        $original_dir = ftp_pwd($this->conn_id);

        foreach ($operations as $operation) {
            $directory = $operation['directory'];
            $callback = $operation['callback'];

            // 切换到目录
            if (!@ftp_chdir($this->conn_id, $directory)) {
                $results[] = [
                    'directory' => $directory,
                    'success' => false,
                    'error' => '无法切换到目录'
                ];
                continue;
            }

            // 执行回调函数
            try {
                if (is_callable($callback)) {
                    $result = call_user_func($callback, $this->conn_id);
                    $results[] = [
                        'directory' => $directory,
                        'success' => true,
                        'result' => $result
                    ];
                } else {
                    throw new Exception('无效的回调函数');
                }
            } catch (Exception $e) {
                $results[] = [
                    'directory' => $directory,
                    'success' => false,
                    'error' => $e->getMessage()
                ];
            }
        }

        // 返回原始目录
        @ftp_chdir($this->conn_id, $original_dir);

        return $results;
    }

    /**
     * 查找文件
     */
    public function findFiles($pattern, $start_directory = '.') {
        $results = [];
        $original_dir = ftp_pwd($this->conn_id);

        // 递归查找函数
        $findRecursive = function($directory, $pattern, &$results) use (&$findRecursive) {
            // 切换到目标目录
            if (!@ftp_chdir($this->conn_id, $directory)) {
                return;
            }

            // 获取目录列表
            $items = @ftp_nlist($this->conn_id, '.');
            if ($items === false) {
                return;
            }

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

                // 检查是否是目录
                if (@ftp_chdir($this->conn_id, $item)) {
                    // 是目录,递归查找
                    ftp_chdir($this->conn_id, '..');
                    $findRecursive($directory . '/' . $item, $pattern, $results);
                } else {
                    // 是文件,检查是否匹配模式
                    if (fnmatch($pattern, basename($item))) {
                        $results[] = $directory . '/' . $item;
                    }
                }
            }
        };

        // 开始查找
        $findRecursive($start_directory, $pattern, $results);

        // 返回原始目录
        @ftp_chdir($this->conn_id, $original_dir);

        return $results;
    }

    /**
     * 同步目录结构
     */
    public function syncDirectoryStructure($local_dir, $remote_dir) {
        if (!is_dir($local_dir)) {
            return [
                'success' => false,
                'error' => '本地目录不存在'
            ];
        }

        $results = [];
        $original_remote_dir = ftp_pwd($this->conn_id);

        // 递归同步函数
        $syncRecursive = function($local_path, $remote_path) use (&$syncRecursive, &$results) {
            // 在远程创建目录
            if (!@ftp_chdir($this->conn_id, $remote_path)) {
                if (!@ftp_mkdir($this->conn_id, $remote_path)) {
                    $results[] = [
                        'type' => 'mkdir',
                        'path' => $remote_path,
                        'success' => false,
                        'error' => '无法创建目录'
                    ];
                    return false;
                }
                $results[] = [
                    'type' => 'mkdir',
                    'path' => $remote_path,
                    'success' => true
                ];
            }

            // 获取本地目录内容
            $local_items = scandir($local_path);

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

                $local_item_path = $local_path . '/' . $item;
                $remote_item_path = $remote_path . '/' . $item;

                if (is_dir($local_item_path)) {
                    // 递归处理子目录
                    $syncRecursive($local_item_path, $remote_item_path);
                } else {
                    // 上传文件
                    if (!@ftp_put($this->conn_id, $remote_item_path, $local_item_path, FTP_BINARY)) {
                        $results[] = [
                            'type' => 'upload',
                            'file' => $item,
                            'success' => false,
                            'error' => '上传失败'
                        ];
                    } else {
                        $results[] = [
                            'type' => 'upload',
                            'file' => $item,
                            'success' => true
                        ];
                    }
                }
            }

            return true;
        };

        // 开始同步
        $sync_success = $syncRecursive($local_dir, $remote_dir);

        // 返回原始目录
        @ftp_chdir($this->conn_id, $original_remote_dir);

        return [
            'success' => $sync_success,
            'results' => $results
        ];
    }
}

// 使用示例
echo "<h4>FTP批量操作示例:</h4>";

// 假设已经建立了FTP连接
$ftp_server = "ftp.example.com";
$ftp_user = "username";
$ftp_pass = "password";

$conn_id = ftp_connect($ftp_server);
if (!$conn_id) {
    die("无法连接到FTP服务器");
}

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

ftp_pasv($conn_id, true);

// 创建批量操作实例
$batch_ops = new FTPBatchOperations($conn_id);

echo "<h5>1. 批量创建目录:</h5>";
$directories = [
    'uploads/2023',
    'uploads/2023/images',
    'uploads/2023/documents',
    'backups/daily',
    'backups/weekly',
    'temp'
];

$create_results = $batch_ops->createDirectories($directories);

echo "批量创建目录结果:<br>";
echo "总数: {$create_results['total']},成功: {$create_results['success']},失败: {$create_results['failed']}<br>";

echo "<table class='table table-sm'>";
echo "<thead><tr><th>目录</th><th>结果</th><th>信息</th></tr></thead>";
echo "<tbody>";
foreach ($create_results['results'] as $result) {
    $class = $result['success'] ? 'table-success' : 'table-danger';
    echo "<tr class='$class'>";
    echo "<td>" . htmlspecialchars($result['directory']) . "</td>";
    echo "<td>" . ($result['success'] ? '成功' : '失败') . "</td>";
    echo "<td>" . htmlspecialchars($result['message'] ?? $result['error'] ?? '') . "</td>";
    echo "</tr>";
}
echo "</tbody></table>";

echo "<h5>2. 查找文件:</h5>";
echo "查找所有 .jpg 文件:<br>";
$jpg_files = $batch_ops->findFiles('*.jpg', '.');
if (empty($jpg_files)) {
    echo "未找到 .jpg 文件<br>";
} else {
    echo "找到 " . count($jpg_files) . " 个文件:<br>";
    foreach ($jpg_files as $file) {
        echo htmlspecialchars($file) . "<br>";
    }
}

echo "<h5>3. 在不同目录执行操作:</h5>";
$operations = [
    [
        'directory' => 'uploads/2023',
        'callback' => function($conn) {
            // 计算文件数量和大小的回调函数
            $files = ftp_nlist($conn, '.');
            $file_count = 0;
            $total_size = 0;

            foreach ($files as $file) {
                if ($file === '.' || $file === '..') continue;
                if (!@ftp_chdir($conn, $file)) {
                    $size = ftp_size($conn, $file);
                    if ($size !== -1) {
                        $file_count++;
                        $total_size += $size;
                    }
                }
            }

            return [
                'files' => $file_count,
                'total_size' => $total_size
            ];
        }
    ]
];

$execute_results = $batch_ops->executeInDirectories($operations);
echo "<pre>" . print_r($execute_results, true) . "</pre>";

echo "<h5>4. 同步目录结构:</h5>";
echo "(此示例需要真实的本地目录)<br>";
// $sync_results = $batch_ops->syncDirectoryStructure('/local/path', '/remote/path');
// echo "<pre>" . print_r($sync_results, true) . "</pre>";

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

示例 5:高级错误处理和日志记录

<?php
/**
 * 带错误处理和日志记录的FTP操作类
 */
class FTPWithLogging {
    private $conn_id;
    private $logger;
    private $error_count = 0;
    private $operation_count = 0;

    public function __construct($server, $username, $password, $logger = null) {
        $this->logger = $logger;

        $this->log("正在连接到FTP服务器: $server", 'info');
        $this->conn_id = @ftp_connect($server);

        if (!$this->conn_id) {
            $this->log("无法连接到FTP服务器: $server", 'error');
            throw new Exception("无法连接到FTP服务器: $server");
        }

        $this->log("正在登录FTP服务器,用户: $username", 'info');
        if (!@ftp_login($this->conn_id, $username, $password)) {
            $this->log("FTP登录失败,用户: $username", 'error');
            ftp_close($this->conn_id);
            throw new Exception("FTP登录失败");
        }

        ftp_pasv($this->conn_id, true);
        $this->log("FTP连接成功建立", 'success');
    }

    /**
     * 日志记录
     */
    private function log($message, $level = 'info') {
        $timestamp = date('Y-m-d H:i:s');
        $log_entry = "[$timestamp] [$level] $message";

        // 如果提供了日志记录器,使用它
        if ($this->logger && is_callable($this->logger)) {
            call_user_func($this->logger, $log_entry, $level);
        }

        // 同时输出到页面(仅用于演示)
        $css_class = '';
        switch ($level) {
            case 'error': $css_class = 'text-danger'; break;
            case 'warning': $css_class = 'text-warning'; break;
            case 'success': $css_class = 'text-success'; break;
            case 'info': $css_class = 'text-info'; break;
            default: $css_class = 'text-muted';
        }

        echo "<div class='ftp-log $css_class' style='font-family: monospace; font-size: 12px;'>$log_entry</div>";
    }

    /**
     * 安全的改变目录
     */
    public function changeDirectory($directory, $retry_count = 2) {
        $this->operation_count++;
        $original_dir = ftp_pwd($this->conn_id);

        $this->log("尝试切换到目录: $directory (当前: $original_dir)", 'info');

        for ($attempt = 1; $attempt <= $retry_count; $attempt++) {
            try {
                if (!@ftp_chdir($this->conn_id, $directory)) {
                    $error_msg = "第{$attempt}次尝试切换目录失败: $directory";

                    // 分析可能的错误原因
                    $error_analysis = $this->analyzeDirectoryError($directory);
                    $this->log("$error_msg - $error_analysis", 'warning');

                    if ($attempt < $retry_count) {
                        sleep(1); // 等待后重试
                        continue;
                    }

                    $this->error_count++;
                    $this->log("切换目录最终失败: $directory", 'error');
                    throw new Exception("无法切换到目录: $directory - $error_analysis");
                }

                $new_dir = ftp_pwd($this->conn_id);
                $this->log("成功切换到目录: $new_dir", 'success');
                return $new_dir;

            } catch (Exception $e) {
                if ($attempt == $retry_count) {
                    // 最后一次尝试也失败,恢复原始目录
                    @ftp_chdir($this->conn_id, $original_dir);
                    throw $e;
                }
            }
        }

        return false;
    }

    /**
     * 分析目录错误原因
     */
    private function analyzeDirectoryError($directory) {
        $original_dir = ftp_pwd($this->conn_id);
        $analysis = [];

        // 检查是否是绝对路径
        if (strpos($directory, '/') !== 0) {
            $analysis[] = '相对路径';
        } else {
            $analysis[] = '绝对路径';
        }

        // 检查目录是否存在
        if ($this->directoryExists($directory)) {
            $analysis[] = '目录存在';
        } else {
            $analysis[] = '目录可能不存在';
        }

        // 检查路径是否包含特殊字符
        if (preg_match('/[<>:"|?*]/', $directory)) {
            $analysis[] = '路径包含非法字符';
        }

        // 检查路径长度(某些FTP服务器有路径长度限制)
        if (strlen($directory) > 255) {
            $analysis[] = '路径可能过长';
        }

        return implode('; ', $analysis);
    }

    /**
     * 检查目录是否存在
     */
    private function directoryExists($directory) {
        $current_dir = ftp_pwd($this->conn_id);

        if (@ftp_chdir($this->conn_id, $directory)) {
            ftp_chdir($this->conn_id, $current_dir);
            return true;
        }

        return false;
    }

    /**
     * 递归列出目录结构
     */
    public function listDirectoryRecursive($directory = '.', $max_depth = 5) {
        $this->operation_count++;
        $this->log("递归列出目录: $directory (最大深度: $max_depth)", 'info');

        $result = $this->listRecursive($directory, 0, $max_depth);
        $this->log("目录列表完成,找到 " . count($result) . " 个项目", 'success');

        return $result;
    }

    private function listRecursive($directory, $depth, $max_depth) {
        if ($depth > $max_depth) {
            return [];
        }

        $result = [];
        $original_dir = ftp_pwd($this->conn_id);

        try {
            // 切换到目标目录
            $this->changeDirectory($directory);

            // 获取目录列表
            $items = @ftp_nlist($this->conn_id, '.');
            if ($items === false) {
                throw new Exception("无法列出目录内容");
            }

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

                $full_path = ($directory === '.') ? $item : $directory . '/' . $item;

                // 检查是否是目录
                if (@ftp_chdir($this->conn_id, $item)) {
                    // 是目录,递归处理
                    ftp_chdir($this->conn_id, '..');
                    $result[] = [
                        'type' => 'dir',
                        'path' => $full_path,
                        'depth' => $depth
                    ];

                    // 递归处理子目录
                    $sub_items = $this->listRecursive($full_path, $depth + 1, $max_depth);
                    $result = array_merge($result, $sub_items);
                } else {
                    // 是文件
                    $size = @ftp_size($this->conn_id, $item);
                    $result[] = [
                        'type' => 'file',
                        'path' => $full_path,
                        'size' => ($size !== -1) ? $size : null,
                        'depth' => $depth
                    ];
                }
            }

        } catch (Exception $e) {
            $this->log("列出目录时出错: " . $e->getMessage(), 'error');
        } finally {
            // 确保返回原始目录
            @ftp_chdir($this->conn_id, $original_dir);
        }

        return $result;
    }

    /**
     * 创建目录树
     */
    public function createDirectoryTree($tree) {
        $this->operation_count++;
        $this->log("开始创建目录树", 'info');

        $results = $this->createTreeRecursive($tree, '.');

        $success_count = 0;
        $fail_count = 0;

        foreach ($results as $result) {
            if ($result['success']) {
                $success_count++;
            } else {
                $fail_count++;
            }
        }

        $this->log("目录树创建完成: $success_count 成功, $fail_count 失败",
                   $fail_count > 0 ? 'warning' : 'success');

        return $results;
    }

    private function createTreeRecursive($tree, $base_path) {
        $results = [];
        $original_dir = ftp_pwd($this->conn_id);

        try {
            // 确保在基础路径
            $this->changeDirectory($base_path);

            foreach ($tree as $name => $subtree) {
                $full_path = ($base_path === '.') ? $name : $base_path . '/' . $name;

                // 创建当前目录
                if (!@ftp_chdir($this->conn_id, $name)) {
                    if (@ftp_mkdir($this->conn_id, $name)) {
                        $results[] = [
                            'path' => $full_path,
                            'success' => true,
                            'message' => '目录创建成功'
                        ];
                        $this->log("创建目录: $full_path", 'success');
                    } else {
                        $results[] = [
                            'path' => $full_path,
                            'success' => false,
                            'error' => '目录创建失败'
                        ];
                        $this->log("创建目录失败: $full_path", 'error');
                        continue;
                    }
                }

                // 递归处理子目录
                if (is_array($subtree)) {
                    $sub_results = $this->createTreeRecursive($subtree, $full_path);
                    $results = array_merge($results, $sub_results);
                }
            }

        } catch (Exception $e) {
            $results[] = [
                'path' => $base_path,
                'success' => false,
                'error' => $e->getMessage()
            ];
        } finally {
            @ftp_chdir($this->conn_id, $original_dir);
        }

        return $results;
    }

    /**
     * 获取统计信息
     */
    public function getStats() {
        return [
            'operations' => $this->operation_count,
            'errors' => $this->error_count,
            'success_rate' => $this->operation_count > 0 ?
                (($this->operation_count - $this->error_count) / $this->operation_count * 100) : 100,
            'current_dir' => ftp_pwd($this->conn_id),
            'server_type' => @ftp_systype($this->conn_id)
        ];
    }

    /**
     * 关闭连接
     */
    public function close() {
        if ($this->conn_id) {
            $stats = $this->getStats();
            $this->log("关闭FTP连接,操作统计: " .
                      "{$stats['operations']} 次操作, " .
                      "{$stats['errors']} 次错误, " .
                      "成功率: " . round($stats['success_rate'], 2) . "%", 'info');

            ftp_close($this->conn_id);
            $this->conn_id = null;
        }
    }

    public function __destruct() {
        $this->close();
    }
}

// 使用示例
echo "<h4>带日志记录的FTP操作示例:</h4>";

// 自定义日志记录器
$custom_logger = function($message, $level) {
    // 在实际应用中,这里可以写入文件、数据库等
    // 这里只是简单输出
    $colors = [
        'error' => '#dc3545',
        'warning' => '#ffc107',
        'success' => '#198754',
        'info' => '#0dcaf0'
    ];

    $color = $colors[$level] ?? '#6c757d';
    // 可以在这里添加更多的日志处理逻辑
};

try {
    // 创建带日志记录的FTP操作实例
    $ftp = new FTPWithLogging(
        "ftp.example.com",
        "username",
        "password",
        $custom_logger
    );

    echo "<div style='border: 1px solid #ddd; padding: 10px; margin: 10px 0; max-height: 300px; overflow-y: auto; background: #f8f9fa;'>";
    echo "<strong>操作日志:</strong><br>";

    // 示例1:切换到目录
    $ftp->changeDirectory("public_html");

    // 示例2:递归列出目录
    $list = $ftp->listDirectoryRecursive(".", 2);

    echo "</div>";

    // 显示目录列表
    echo "<h5>目录结构(前20项):</h5>";
    echo "<div style='max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 10px;'>";
    $count = 0;
    foreach (array_slice($list, 0, 20) as $item) {
        $indent = str_repeat('    ', $item['depth']);
        $icon = $item['type'] === 'dir' ? '📁' : '📄';
        $size = isset($item['size']) ? " (" . formatSize($item['size']) . ")" : "";
        echo $indent . $icon . " " . htmlspecialchars(basename($item['path'])) . $size . "<br>";
        $count++;
    }
    if (count($list) > 20) {
        echo "... 还有 " . (count($list) - 20) . " 项<br>";
    }
    echo "</div>";

    // 示例3:创建目录树
    echo "<h5>创建测试目录树:</h5>";
    $directory_tree = [
        'test_dir' => [
            'subdir1' => [],
            'subdir2' => [
                'deep_dir' => []
            ],
            'subdir3' => []
        ]
    ];

    $create_results = $ftp->createDirectoryTree($directory_tree);

    // 显示统计信息
    $stats = $ftp->getStats();
    echo "<div class='alert alert-info'>";
    echo "<strong>统计信息:</strong><br>";
    echo "操作次数: {$stats['operations']}<br>";
    echo "错误次数: {$stats['errors']}<br>";
    echo "成功率: " . round($stats['success_rate'], 2) . "%<br>";
    echo "当前目录: " . htmlspecialchars($stats['current_dir']) . "<br>";
    echo "服务器类型: " . htmlspecialchars($stats['server_type'] ?? '未知');
    echo "</div>";

    // 自动关闭连接

} catch (Exception $e) {
    echo "<div class='alert alert-danger'>错误: " . htmlspecialchars($e->getMessage()) . "</div>";
}

/**
 * 格式化文件大小
 */
function formatSize($bytes) {
    if ($bytes == 0) return '0 B';
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $i = floor(log($bytes, 1024));
    return round($bytes / pow(1024, $i), 2) . ' ' . $units[$i];
}
?>

注意事项

  • 权限检查:需要对该目录有读取权限才能成功切换
  • 路径格式:不同操作系统的FTP服务器可能有不同的路径分隔符
  • 连接状态:必须在有效的FTP连接上调用此函数
  • 错误处理:应检查函数返回值,处理可能的失败情况
  • 路径解析:相对路径是基于当前工作目录解析的
  • 编码问题:包含非ASCII字符的目录名可能导致问题
  • 性能考虑:频繁的目录切换可能影响性能
  • 安全性:避免使用用户提供的未经清理的路径

常见错误代码和解决方法

错误现象 可能原因 解决方法
返回 false 目录不存在 检查目录路径是否正确;使用 ftp_nlist() 验证目录存在
权限被拒绝 没有读取权限 检查FTP用户权限;联系服务器管理员
连接失败 FTP连接已断开 重新建立连接;增加超时时间
路径格式错误 路径包含非法字符 清理路径字符串;避免特殊字符
目录切换但未改变 符号链接或权限问题 使用 ftp_pwd() 验证当前目录

相关FTP函数

函数 描述 ftp_chdir() 的关系
ftp_cdup() 切换到父目录 ftp_cdup() 相当于 ftp_chdir("..")
ftp_pwd() 返回当前目录名 获取当前目录,通常与 ftp_chdir() 配合使用
ftp_mkdir() 建立新目录 创建目录后,可以使用 ftp_chdir() 切换到新目录
ftp_nlist() 返回目录的文件列表 切换目录后,可以使用此函数列出目录内容
ftp_rawlist() 返回目录的详细列表 提供更详细的目录信息

最佳实践

  1. 总是检查返回值:检查 ftp_chdir() 是否成功
  2. 使用绝对路径:在复杂应用中,优先使用绝对路径避免混淆
  3. 记录目录操作:重要的目录切换操作应该记录日志
  4. 错误恢复:失败时恢复到之前的目录状态
  5. 路径验证:切换目录前验证路径的有效性
  6. 批量操作优化:批量目录操作时,尽量减少不必要的目录切换
  7. 用户友好的错误信息:为用户提供清晰的错误提示
  8. 资源管理:确保FTP连接在使用后正确关闭

浏览器支持

该函数是 PHP 后端函数,与浏览器无关。需要 PHP 4.0 或更高版本,且启用 FTP 扩展。