PHP ftp_size() 函数

ftp_size() 函数用于获取 FTP 服务器上指定文件的大小(以字节为单位)。

该函数通过发送 FTP 的 SIZE 命令来获取文件大小。需要注意的是,不是所有的 FTP 服务器都支持 SIZE 命令。

提示:对于目录,该函数会返回 -1。对于不存在的文件,通常也会返回 -1,但具体行为取决于服务器实现。

语法

ftp_size ( resource $ftp_stream , string $remote_file ) : int

参数

参数 类型 描述
$ftp_stream resource 必需的。FTP 连接的标识符,由 ftp_connect()ftp_ssl_connect() 返回。
$remote_file string 必需的。要获取大小的远程文件的路径(在 FTP 服务器上)。

返回值

返回值 描述
正整数 文件的大小(以字节为单位)。
-1 出现错误或文件大小无法确定。可能的原因包括:
  • 文件不存在
  • 指定的是目录而不是文件
  • FTP 服务器不支持 SIZE 命令
  • 没有访问文件的权限

示例

示例 1:基本使用 - 获取文件大小

以下示例展示了如何获取 FTP 服务器上文件的大小。

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

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

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

// 获取文件大小
$remote_file = "public_html/document.pdf";
$file_size = ftp_size($conn, $remote_file);

if ($file_size != -1) {
    echo "文件大小: " . $file_size . " 字节\n";
    echo "文件大小: " . round($file_size / 1024, 2) . " KB\n";
    echo "文件大小: " . round($file_size / (1024 * 1024), 2) . " MB\n";
} else {
    echo "无法获取文件大小。文件可能不存在或服务器不支持 SIZE 命令。\n";
}

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

示例 2:检查多个文件的大小

批量检查多个文件的大小。

<?php
$conn = ftp_connect("ftp.example.com");
ftp_login($conn, "username", "password");

// 文件列表
$files = [
    "public_html/index.html",
    "public_html/style.css",
    "public_html/app.js",
    "public_html/images/logo.png",
    "public_html/uploads/document.pdf"
];

echo "文件大小检查:\n";
echo "=================================\n";

foreach ($files as $file) {
    $size = ftp_size($conn, $file);

    if ($size != -1) {
        // 格式化文件大小
        $formatted_size = format_file_size($size);
        echo str_pad(basename($file), 20) . " : " . $formatted_size . "\n";
    } else {
        echo str_pad(basename($file), 20) . " : 无法获取大小(文件可能不存在或是目录)\n";
    }
}

/**
 * 格式化文件大小
 * @param int $bytes 字节数
 * @param int $precision 小数位数
 * @return string 格式化后的文件大小
 */
function format_file_size($bytes, $precision = 2) {
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= pow(1024, $pow);

    return round($bytes, $precision) . ' ' . $units[$pow];
}

ftp_close($conn);
?>

示例 3:检查服务器是否支持 SIZE 命令

在实际使用前检查服务器是否支持获取文件大小功能。

<?php
$conn = ftp_connect("ftp.example.com");
ftp_login($conn, "username", "password");

/**
 * 检查 FTP 服务器是否支持 SIZE 命令
 * @param resource $conn FTP 连接
 * @return bool 如果服务器支持 SIZE 命令返回 true,否则返回 false
 */
function check_size_command_support($conn) {
    // 创建一个已知存在的小文件用于测试
    $test_file = "test_size_check.txt";

    // 首先检查文件是否存在
    $file_list = ftp_nlist($conn, ".");

    if (in_array($test_file, $file_list)) {
        // 尝试获取文件大小
        $size = ftp_size($conn, $test_file);

        if ($size != -1 && $size > 0) {
            return true; // 服务器支持 SIZE 命令
        }
    }

    // 如果测试文件不存在,尝试检查其他已知文件
    $other_files = ftp_nlist($conn, ".");
    if (!empty($other_files)) {
        foreach ($other_files as $file) {
            // 跳过目录(尝试获取大小,目录通常返回 -1)
            if (ftp_size($conn, $file) != -1) {
                return true;
            }
        }
    }

    return false; // 服务器可能不支持 SIZE 命令
}

// 检查服务器支持情况
if (check_size_command_support($conn)) {
    echo "服务器支持 SIZE 命令,可以获取文件大小。\n";
} else {
    echo "服务器可能不支持 SIZE 命令,无法获取文件大小。\n";
    echo "替代方案:可以尝试下载文件到本地然后获取大小,但这会消耗带宽。\n";
}

ftp_close($conn);
?>

示例 4:完整示例 - 文件大小监控

监控文件大小变化,适用于日志文件等场景。

<?php
/**
 * FTP 文件大小监控类
 */
class FTPFileMonitor {
    private $conn;
    private $log_file;

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

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

        $this->log_file = $log_file;

        // 记录监控开始
        $this->log("FTP 文件大小监控开始 " . date('Y-m-d H:i:s'));
    }

    /**
     * 监控指定文件的大小变化
     * @param string $remote_file 远程文件路径
     * @param int $interval 检查间隔(秒)
     * @param int $duration 监控持续时间(秒),0表示无限
     */
    public function monitorFile($remote_file, $interval = 60, $duration = 0) {
        $start_time = time();
        $last_size = -1;

        $this->log("开始监控文件: $remote_file");
        $this->log("检查间隔: $interval 秒");

        while (true) {
            // 检查是否超过监控持续时间
            if ($duration > 0 && (time() - $start_time) > $duration) {
                $this->log("监控持续时间结束,停止监控");
                break;
            }

            $current_size = ftp_size($this->conn, $remote_file);

            if ($current_size == -1) {
                $this->log("[" . date('H:i:s') . "] 错误:无法获取文件大小,文件可能不存在");
            } else {
                if ($last_size == -1) {
                    // 第一次获取大小
                    $this->log("[" . date('H:i:s') . "] 初始文件大小: " . $this->format_size($current_size));
                } elseif ($current_size != $last_size) {
                    $change = $current_size - $last_size;
                    $change_str = ($change > 0) ? "+" . $this->format_size($change) : $this->format_size($change);
                    $this->log("[" . date('H:i:s') . "] 文件大小变化: " .
                              $this->format_size($last_size) . " → " .
                              $this->format_size($current_size) . " (" . $change_str . ")");
                }

                $last_size = $current_size;
            }

            // 等待指定的间隔时间
            sleep($interval);
        }
    }

    /**
     * 格式化文件大小
     */
    private function format_size($bytes) {
        $units = ['B', 'KB', 'MB', 'GB'];

        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        $bytes /= pow(1024, $pow);

        return round($bytes, 2) . $units[$pow];
    }

    /**
     * 记录日志
     */
    private function log($message) {
        $log_entry = date('Y-m-d H:i:s') . " - " . $message . "\n";
        file_put_contents($this->log_file, $log_entry, FILE_APPEND);
        echo $log_entry;
    }

    public function __destruct() {
        if ($this->conn) {
            ftp_close($this->conn);
            $this->log("FTP 连接已关闭");
        }
    }
}

// 使用示例
try {
    $monitor = new FTPFileMonitor('ftp.example.com', 'username', 'password');

    // 监控日志文件,每30秒检查一次,持续10分钟
    $monitor->monitorFile('logs/application.log', 30, 600);

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

注意事项

  • 服务器支持:不是所有的 FTP 服务器都支持 SIZE 命令。在使用前应检查服务器支持情况。
  • 目录处理:对于目录,ftp_size() 通常会返回 -1。如果需要获取目录大小,需要递归计算其内容的大小。
  • 性能考虑:对于大文件或网络延迟较高的情况,获取文件大小可能需要一些时间。
  • 缓存:某些 FTP 服务器可能会缓存文件大小信息,返回的结果可能不是实时的。
  • 权限问题:如果没有足够的权限访问文件,函数可能返回 -1
  • 二进制文件:对于二进制文件,返回的大小是准确的。对于文本文件,某些服务器可能返回不同的值,取决于传输模式。
  • 替代方案:如果服务器不支持 SIZE 命令,可以考虑使用 ftp_nlist()ftp_rawlist() 来获取文件信息,然后解析文件大小。

常见错误和解决方案

问题 可能的原因和解决方案
始终返回 -1
  • 服务器不支持 SIZE 命令
  • 文件不存在
  • 指定的是目录而不是文件
  • 权限不足
返回的大小不正确
  • 服务器缓存了旧的文件大小信息
  • 文件正在被修改
  • 服务器端压缩可能影响报告的大小
性能问题
  • 网络延迟高 - 考虑增加超时时间
  • 同时检查多个大文件 - 批量处理时添加延迟
连接断开
  • 服务器超时 - 使用 ftp_set_option() 设置更长的超时时间
  • 网络不稳定 - 添加重试机制

相关函数