PHP的pecl_http模块中http_send_file已移除?求现代替代方案
替代pecl_http 1.x中http_send_file()的现代方案
pecl_http 2.x确实移除了http_send_file()、http_send_data等一批实用函数,且文档说明缺失。这些函数的核心价值是自动处理HTTP Range请求(支持分段下载)、响应头设置,下面是几个无需依赖旧版pecl_http的替代方案:
一、PHP原生手动实现(无额外扩展)
这是最通用的方案,纯原生代码就能复刻原函数的核心功能,自动识别Range请求并处理分段下载:
function send_file($file_path) { if (!file_exists($file_path) || !is_readable($file_path)) { http_response_code(404); exit('File not found'); } $file_size = filesize($file_path); $file = fopen($file_path, 'rb'); // 基础响应头设置 header('Content-Type: ' . mime_content_type($file_path)); header('Content-Disposition: attachment; filename="' . basename($file_path) . '"'); header('Accept-Ranges: bytes'); // 解析Range请求头 $range = $_SERVER['HTTP_RANGE'] ?? ''; if (preg_match('/bytes=(\d+)-(\d+)?/', $range, $matches)) { $start = intval($matches[1]); $end = isset($matches[2]) ? intval($matches[2]) : $file_size - 1; // 处理超出文件范围的请求 if ($start >= $file_size) { http_response_code(416); // 请求范围无效 header("Content-Range: bytes */$file_size"); exit; } $end = min($end, $file_size - 1); $length = $end - $start + 1; // 返回部分内容响应头 http_response_code(206); header("Content-Range: bytes $start-$end/$file_size"); header("Content-Length: $length"); // 输出指定区间的文件内容 fseek($file, $start); while ($length > 0) { $chunk_size = min(8192, $length); echo fread($file, $chunk_size); $length -= $chunk_size; flush(); } } else { // 返回完整文件 header("Content-Length: $file_size"); fpassthru($file); } fclose($file); exit; }
这个函数会自动处理:
- 文件存在性检查
- 正确的Content-Type和下载文件名设置
- Range请求解析与分段输出
- 416(请求范围无效)等错误响应
二、框架场景:用Symfony HttpFoundation组件
如果你的项目基于Laravel、Symfony这类框架,直接用BinaryFileResponse即可,它已经封装了所有Range请求处理逻辑,开箱即用:
use Symfony\Component\HttpFoundation\BinaryFileResponse; $response = new BinaryFileResponse($file_path); $response->setContentDisposition( BinaryFileResponse::DISPOSITION_ATTACHMENT, basename($file_path) ); $response->send();
Laravel中还可以用response()->download(),底层也是基于这个组件,同样支持Range请求。
三、高性能场景:用Swoole扩展
如果是基于Swoole的HTTP服务,直接用Swoole内置的sendfile方法,性能比PHP-FPM模式更高,且原生支持Range请求:
$response->header('Content-Type', mime_content_type($file_path)); $response->header('Content-Disposition', 'attachment; filename="' . basename($file_path) . '"'); $response->sendfile($file_path);
内容的提问来源于stack exchange,提问作者havij
相关产品推荐
相关产品推荐

