You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FTP文件输出至PHP标准输出异常,求排查方案

问题排查与解决方案

核心问题分析

你遇到的所有问题本质都是因为PHP脚本未遵循HTTP视频流的标准协议:

  • 请求pending、加载慢:未返回Content-Length等关键响应头,浏览器无法预知文件大小,只能持续等待传输完全结束;同时缺少分块传输支持,导致浏览器无法渐进式加载。
  • 无法拖动进度条:未处理HTTP的Range范围请求,浏览器无法请求视频指定片段,只能等全文件加载完成后才能操作。

分步解决方案

1. 获取FTP文件元信息

先通过FTP获取视频的大小和MIME类型,这是设置响应头的基础:

$ftp = ftp_connect($FTPaccount['server']);
ftp_login($ftp, $FTPaccount['user'], $FTPaccount['pass']);
ftp_set_option($ftp, FTP_USEPASVADDRESS, false);
ftp_pasv($ftp, true);

// 获取文件大小
$fileSize = ftp_size($ftp, $filepath);
if ($fileSize === -1) {
    http_response_code(404);
    exit('File not found');
}

// 设置MP4对应的MIME类型
$mimeType = 'video/mp4';

2. 处理Range范围请求

浏览器拖动进度条时会发送Range头,需解析并返回对应片段:

$start = 0;
$end = $fileSize - 1;

// 解析Range请求头
if (isset($_SERVER['HTTP_RANGE'])) {
    preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
    $start = intval($matches[1]);
    $end = !empty($matches[2]) ? intval($matches[2]) : $fileSize - 1;
    // 返回206部分内容状态码
    http_response_code(206);
    header("Content-Range: bytes $start-$end/$fileSize");
} else {
    http_response_code(200);
}

3. 设置标准响应头

这些头是让浏览器正确识别视频流的关键:

header("Content-Type: $mimeType");
header("Accept-Ranges: bytes");
header("Content-Length: " . ($end - $start + 1));
header("Cache-Control: public, max-age=86400"); // 可选,添加缓存优化

4. 分块读取输出FTP文件

关闭PHP输出缓冲,分块读取输出避免一次性加载整个文件:

// 强制关闭输出缓冲
ob_end_clean();
flush();

// 打开输出流并从指定位置读取文件
$fout = fopen('php://output', 'w');
ftp_fget($ftp, $fout, $filepath, FTP_BINARY, $start);

fclose($fout);
ftp_close($ftp);

替代方案:WebDAV代理(效率更高)

既然WebDAV访问速度更快,可尝试用PHP代理WebDAV请求:

$webdavUrl = 'https://your-webdav-server/' . rawurlencode($filepath);
$contextOpts = [
    'http' => [
        'method' => $_SERVER['REQUEST_METHOD'],
        'header' => isset($_SERVER['HTTP_RANGE']) ? "Range: {$_SERVER['HTTP_RANGE']}\r\n" : "",
        'follow_location' => true
    ]
];
$context = stream_context_create($contextOpts);

// 获取文件大小(可选,也可通过HEAD请求获取)
$headers = get_headers($webdavUrl, 1);
$fileSize = isset($headers['Content-Length']) ? intval($headers['Content-Length']) : 0;

// 复用上述Range请求处理逻辑设置响应头

// 输出内容
readfile($webdavUrl, false, $context);

额外排查点

  • 检查PHP配置:确保output_buffering = Off,或用ob_end_clean()强制关闭缓冲。
  • 调整执行超时:如果文件较大,将max_execution_time设置为300秒以上。
  • 测试FTP稳定性:在服务器上用ftp命令手动下载文件,排查FTP服务器本身的速度问题。

内容的提问来源于stack exchange,提问作者RanneR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:00:46