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
相关产品推荐
相关产品推荐

