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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:50:31