PHP REST API文件上传下载功能.sql文件下载后大小为0或损坏问题
修复方案
核心问题根因
你遇到的下载文件异常是以下几个问题共同导致的:
- 错误使用HTTP协议读取本地文件,且未对文件名做URL编码:你构造的请求URL中包含带空格的文件名
mtc_project (1).sql,空格属于URL非法字符,未编码就发起请求会被服务器判定为非法请求返回400错误,readfile读取失败所以输出内容为空/仅包含PHP警告,最终下载的文件大小异常、无法打开。 - 多余的HTTP请求开销+稳定性问题:需要读取的文件本身就在服务器本地磁盘,完全不需要绕一圈走HTTP请求,直接读文件系统路径既可以避免URL编码类问题,性能也更高。
- exit位置错误:
readfile执行后直接调用exit,后续的下载状态更新SQL永远不会被执行。 - 额外风险:你原有SQL直接拼接参数
$param,存在SQL注入漏洞;直接使用用户上传的原始文件名存储,存在路径遍历、特殊字符兼容问题。
修复后代码
下载函数修复
public function downloadFile($param){ // 和上传逻辑保持一致的本地文件存储路径 $file_path_prefix = '../files/'; // 改为参数绑定,避免SQL注入 $q = "SELECT * FROM data_file WHERE module_id = ?"; $stmt = $this->conn->prepare($q); $stmt->execute([$param]); $row = $stmt->fetch(PDO::FETCH_ASSOC); if(!empty($row)){ $filename = $row['file_name']; $full_file_path = $file_path_prefix . $filename; // 提前判断本地文件是否存在、可读 if(!file_exists($full_file_path) || !is_readable($full_file_path)){ Responses::http_not_found(); exit(); } // 输出下载头 header('Content-Type: application/octet-stream'); header("Content-Transfer-Encoding: Binary"); header("Content-disposition: attachment; filename=\"". $filename . "\""); // 直接读本地文件输出 readfile($full_file_path); // 把状态更新逻辑放到exit之前执行 $date = date('Y-m-d H:i:s'); $update = "UPDATE server_status SET file_start = ?, file_start_time = ? WHERE module_id = ?"; $updateStmnt2 = $this->conn->prepare($update); $updateStmnt2->execute([ 2, $date, $param ]); exit(); }else{ Responses::http_not_found(); } }
上传函数优化(可选,彻底解决文件名兼容问题)
public function uploadFile($param,$file){ $upload_path = '../files/'; $temp_path = $file['tmp_name']; // 替换文件名中的空格、特殊字符,避免后续读取兼容问题 $safe_filename = preg_replace('/[^\w\.\-]/u', '_', $file['name']); // 也可以选择重命名文件彻底避免重名、特殊字符问题: // $ext = pathinfo($file['name'], PATHINFO_EXTENSION); // $safe_filename = time() . '_' . uniqid() . '.' . $ext; if (file_exists($upload_path . $safe_filename)) { unlink($upload_path . $safe_filename); } if(move_uploaded_file($temp_path,$upload_path.$safe_filename)){ // 存储处理后的安全文件名到数据库 $file['name'] = $safe_filename; $this->setFileQuery($param,$file); }else{ Responses::http_error(); } }
内容的提问来源于stack exchange,提问作者Vince
相关产品推荐
相关产品推荐

