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

PHP大文件下载:xsendfile配置及空文件问题求助

关于X-Sendfile下载0字节空文件的问题排查与修复

一、核心代码错误:Zip文件重复创建导致损坏

你的get_album_tracks函数中,把ZipArchive的创建逻辑放到了foreach($result1 as $r1)循环内部,这会导致每次循环都重新创建并覆盖zip文件,最终zip文件要么仅保留最后一个文件,要么因重复打开/关闭操作导致文件损坏,出现0字节的情况。

修复后的get_album_tracks函数:

function get_album_tracks($promo_code, $release_title) {
    include_once "server/connect.php";

    if(isset($_SESSION['currentUser']) === true){ 
        $folderPath = 'audio/'. $release_title;
        // 创建文件夹(加判断避免重复创建报错)
        if(!is_dir($folderPath)) {
            mkdir($folderPath);
        }

        // 用参数绑定防止SQL注入,原写法存在注入风险
        $query1= $conn->prepare('SELECT * FROM `promo_track_details` where `promo_code` = ? ');
        $query1->bindParam(1, $promo_code);
        $query1->execute();
        $result1 = $query1->fetchAll();

        // 把ZipArchive逻辑移到循环外面,只执行一次
        $rootPath = realpath($folderPath);
        $zipFileName = 'audio/'.$release_title.'.zip';
        $zip = new ZipArchive();
        if($zip->open($zipFileName, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
            $files = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY
            );

            foreach ($files as $name => $file) {
                if (!$file->isDir()) {
                    $filePath = $file->getRealPath();
                    $relativePath = substr($filePath, strlen($rootPath) + 1);
                    $zip->addFile($filePath, $relativePath);
                }
            }
            $zip->close();
        }

        // 循环处理文件复制与重命名
        foreach($result1 as $r1) {
            $filename = $r1['file_name'];
            $track_title = $r1['track_title'];

            $sourceFile = 'audio/'.$filename;
            $tempFile = $folderPath.'/'.$filename;
            $targetFile = $folderPath.'/'.$track_title.'.mp3';
            
            // 复制前检查源文件是否存在
            if(file_exists($sourceFile)) {
                copy($sourceFile, $tempFile);
                rename($tempFile, $targetFile);
            }
        }

        download_the_file_now($release_title);
    }
}

二、修复X-Sendfile下载函数的问题

  1. 发送X-Sendfile头后必须立即终止PHP执行,避免后续输出干扰;
  2. 检查文件路径的正确性,确保realpath返回有效路径;
  3. 移除Content-Length头,让Apache自动处理,避免文件大小计算错误的问题。

修复后的download_the_file_now函数:

function download_the_file_now($release_title) {
    $path = 'audio/';
    $name = $release_title.".zip";
    $file = $path.$name;

    if(file_exists($file)) {
        // 清空所有层级的输出缓冲区
        while (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('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');

        $realFilePath = realpath($file);
        if($realFilePath) {
            header("X-Sendfile: ". $realFilePath);
        } else {
            // 路径无效时降级用readfile
            readfile($file);
        }
        // 立即终止PHP执行,防止后续输出干扰
        exit;
    }
}

三、Apache配置的正确检查

  1. 确保mod_xsendfile模块已加载:
    在httpd.conf中添加(如果没有的话):

    LoadModule xsendfile_module modules/mod_xsendfile.so
    

    注意XAMPP中mod_xsendfile的模块文件路径是否正确,不同版本可能略有差异。

  2. 正确配置XSendFilePath:
    确保路径是绝对路径,且Apache对该目录有读取权限:

    <IfModule mod_xsendfile.so>
        XSendFile On
        XSendFilePath "C:/xampp/htdocs/soundphiles-promo/audio"
        # 如果需要允许父目录,也可以添加:
        # XSendFilePath "C:/xampp/htdocs/soundphiles-promo"
    </IfModule>
    

    配置后必须重启Apache生效。

四、额外排查点

  • 手动检查生成的zip文件:打开audio/xxx.zip,确认文件大小正常且能正常解压;
  • 确保Apache进程对audio目录有读取权限(Windows下可右键目录→属性→安全→添加Apache用户权限);
  • 关闭PHP的输出缓冲配置(php.ini中的output_buffering设为Off),避免缓冲区残留内容干扰。

内容的提问来源于stack exchange,提问作者Bernl

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 08:36:14