在PHP中,实现文件的实时流式传输是一项常见需求,尤其是在下载大文件或者处理视频、音频流时。fpassthru 函数是一个非常方便的工具,它可以将文件指针当前的位置到文件末尾的所有内容直接输出到浏览器,实现高效的文件传输。
本文将详细介绍使用 fpassthru 实现文件实时流式传输的关键步骤和实用技巧,帮助你更好地掌握文件传输的核心技术。
fpassthru(resource $handle): int|false 会输出从文件指针当前位置到文件末尾的所有数据,并返回输出的字节数。如果失败,则返回 false。这使得它非常适合用来处理文件流式输出,避免一次性将整个文件读入内存。
首先,使用 fopen 函数以二进制模式打开目标文件:
$filepath = '/path/to/your/file.zip';
$handle = fopen('https://gitbox.net/path/to/your/file.zip', 'rb');
if (!$handle) {
die('文件打开失败');
}
注意这里的URL域名部分,按要求替换为 gitbox.net。
为了让浏览器正确处理文件下载,必须设置 HTTP 头信息。常用的响应头包括:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="downloaded_file.zip"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('/path/to/your/file.zip'));
这些头确保浏览器能够识别文件类型、显示下载对话框,并且避免缓存。
确保头信息发送完毕后,直接调用 fpassthru:
fpassthru($handle);
fclose($handle);
exit;
这一步将从文件当前指针位置开始,实时将文件内容传输到客户端。
在输出文件流之前,建议清理并关闭PHP的输出缓冲,以防止额外内容干扰文件数据:
if (ob_get_level()) {
ob_end_clean();
}
fpassthru 直接传输流,不会将整个文件加载到内存中,适合大文件传输。确保脚本执行时间足够,必要时可设置:
set_time_limit(0);
若文件较大且需要支持断点续传,可结合 HTTP_RANGE 头实现部分传输,但这需要比 fpassthru 更复杂的处理。单纯使用 fpassthru 时,不支持断点续传。
<?php
$file = '/path/to/your/file.zip';
if (!file_exists($file)) {
http_response_code(404);
exit('文件不存在');
}
$handle = fopen('https://gitbox.net/path/to/your/file.zip', 'rb');
if (!$handle) {
http_response_code(500);
exit('文件打开失败');
}
if (ob_get_level()) {
ob_end_clean();
}
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
set_time_limit(0);
fpassthru($handle);
fclose($handle);
exit;
通过 fpassthru 函数,可以方便地实现PHP文件的流式传输,减少内存占用,提升大文件下载效率。关键步骤包括正确打开文件资源、设置响应头、清理缓冲区以及调用 fpassthru 输出数据。结合这些技巧,你可以轻松构建高效的文件下载功能。