php加速下载文件,比普通下载快三倍以上

3天前学习17

直接通过服务器下载文件有点慢,写了个加速下载代码,使用的php5.3,windows服务器,需要修改下文件路径

差不多比直接下载文件快三倍以上。

<?php
/**
 * PHP5.3.28 服务器端ZIP下载接口(部署到服务器,浏览器请求直接下载到本地)
 * 运行环境:PHP5.3.28 + Windows + NTS + CGI/FastCGI(你的服务器环境)
 * 核心特性:高速流式下载 + 断点续传 + 大文件支持 + 内存优化 + 浏览器适配
 */
// ======================== 【必须修改的2处核心配置】 =======================
$LOCAL_ZIP_FILE = 'D:/TTT/www/your_file.zip'; // ★服务器本地的ZIP文件绝对路径(必填)
$DOWNLOAD_FILE_NAME = 'my_download.zip';     // ★下载到本地时显示的文件名(自定义)
// ==========================================================================

// 全局配置(适配你的PHP5.3环境,无需修改)
set_time_limit(0);          // 取消执行超时限制(大文件必备)
ini_set('memory_limit', '64M'); // 进一步降低内存占用,适配128M限制
ini_set('output_buffering', 'off'); // 关闭输出缓冲,流式下载核心
ob_end_clean();             // 清空缓冲区,防止文件损坏

// 初始化下载处理器
$downloader = new ServerZipDownloader();
$downloader->download($LOCAL_ZIP_FILE, $DOWNLOAD_FILE_NAME);

/**
 * 服务器端ZIP下载核心类(PHP5.3完全兼容,极致速度优化)
 */
class ServerZipDownloader
{
    /**
     * 主下载方法:响应HTTP请求,将服务器本地ZIP流式下载到客户端
     * @param string $localFile 服务器本地ZIP绝对路径
     * @param string $showName  客户端显示的下载文件名
     */
    public function download($localFile, $showName)
    {
        // ========== 第一步:前置校验(核心,防止报错) ==========
        if (!$this->checkFileExist($localFile)) {
            $this->outputError('服务器本地ZIP文件不存在!路径:'.$localFile);
            return;
        }
        
        $fileSize = filesize($localFile); // 获取服务器本地文件大小
        $fileExt  = strtolower(pathinfo($localFile, PATHINFO_EXTENSION));
        
        if ($fileExt !== 'zip') {
            $this->outputError('文件格式错误,仅支持ZIP文件下载!');
            return;
        }
        
        if ($fileSize <= 0) {
            $this->outputError('ZIP文件为空或损坏!');
            return;
        }

        // ========== 第二步:设置HTTP响应头(浏览器下载核心+断点续传) ==========
        $this->setDownloadHeaders($showName, $fileSize);

        // ========== 第三步:高速流式下载核心(速度拉满,内存零占用) ==========
        $this->streamFileToClient($localFile, $fileSize);
        exit;
    }

    /**
     * 校验服务器本地文件是否存在且可读
     */
    private function checkFileExist($file)
    {
        if (!file_exists($file)) return false;
        if (!is_file($file)) return false;
        if (!is_readable($file)) return false;
        return true;
    }

    /**
     * 设置HTTP下载响应头(关键:浏览器识别下载、断点续传、中文文件名兼容)
     */
    private function setDownloadHeaders($fileName, $fileSize)
    {
        // 解决Windows+PHP5.3中文文件名乱码问题
        $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
        if (preg_match('/MSIE|Edge/i', $ua)) {
            $fileName = urlencode($fileName);
        } else {
            $fileName = iconv('UTF-8', 'GB2312//IGNORE', $fileName);
        }

        // 核心响应头(下载类型+禁用缓存)
        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename="'.$fileName.'"');
        header('Pragma: no-cache');
        header('Cache-Control: no-cache, must-revalidate');
        header('Expires: 0');
        header('Accept-Ranges: bytes'); // 开启断点续传支持

        // 断点续传核心逻辑(适配浏览器/下载工具的暂停、续传功能)
        $range = '';
        if (isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])) {
            $range = $_SERVER['HTTP_RANGE'];
            $range = preg_replace('/[\s|,].*/', '', $range);
            list($a, $range) = explode('=', $range);
            list($start, $end) = explode('-', $range);
            $start = (int)$start;
            $end   = $end ? (int)$end : $fileSize - 1;
            
            header('HTTP/1.1 206 Partial Content');
            header('Content-Length: ' . ($end - $start + 1));
            header('Content-Range: bytes ' . $start . '-' . $end . '/' . $fileSize);
        } else {
            header('Content-Length: ' . $fileSize); // 返回完整文件大小
        }
    }

    /**
     * 流式输出文件到客户端(PHP5.3速度最优方案,零内存占用,突破30M限制)
     * ✅ 替代原生readfile,解决大文件下载慢/卡死/内存溢出问题
     */
    private function streamFileToClient($file, $fileSize)
    {
        $fp = fopen($file, 'rb'); // 二进制只读模式(Windows最优)
        if (!$fp) {
            $this->outputError('服务器文件读取失败!');
            return;
        }

        // 处理断点续传的起始位置
        $start = 0;
        if (isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])) {
            $range = $_SERVER['HTTP_RANGE'];
            $range = preg_replace('/[\s|,].*/', '', $range);
            list($a, $range) = explode('=', $range);
            list($start) = explode('-', $range);
            $start = (int)$start;
            fseek($fp, $start); // 定位到断点位置
        }

        // ========== 速度优化核心:分块流式输出 ==========
        $bufferSize = 1024 * 1024; // 1MB输出缓冲区(适配128M内存,速度最快)
        while (!feof($fp) && connection_status() === CONNECTION_NORMAL) {
            $buffer = fread($fp, $bufferSize);
            echo $buffer;
            ob_flush(); // 立即输出缓冲区内容
            flush();    // 强制刷新系统输出缓冲区
        }

        fclose($fp); // 关闭文件句柄
    }

    /**
     * 输出错误信息(友好提示)
     */
    private function outputError($msg)
    {
        header('Content-Type: text/html; charset=utf-8');
        echo '<meta charset="UTF-8">';
        echo '<h2 style="color:red;">下载失败</h2>';
        echo '<p>错误信息:'.$msg.'</p>';
        echo '<p>请检查服务器本地ZIP文件路径是否正确!</p>';
        exit;
    }
}
?>

扫描二维码推送至手机访问。

版权声明:本文由星光下的赶路人发布,如需转载请注明出处。

本文链接:https://forstyle.cc/zblog/post/106.html

分享给朋友: