PHP强制下载结合mod_rewrite失效及文件扩展名错误问题求助
问题解决思路与方案
一、文件扩展名被篡改的问题
在线/移动端浏览器把.gpx下载成.gpx.xml、.sql变成.sql.txt,核心原因是服务器未正确设置这类文件的MIME类型,导致浏览器自动推断错误文件类型并追加后缀。
解决方法:
方法1:通过
.htaccess配置正确MIME类型
在网站根目录的.htaccess中添加:AddType application/gpx+xml .gpx AddType application/sql .sql让服务器明确告知浏览器文件的正确类型,避免自动追加错误后缀。
方法2:在PHP下载函数中强制指定响应头
完善你的forceDownload()函数,针对不同扩展名设置对应Content-Type,同时严格指定下载规则:function forceDownload($filePath) { $fileName = basename($filePath); $ext = pathinfo($fileName, PATHINFO_EXTENSION); // 手动指定关键文件的MIME类型 $mimeType = match($ext) { 'gpx' => 'application/gpx+xml', 'sql' => 'application/sql', default => mime_content_type($filePath) }; // 禁止浏览器缓存响应 header("Cache-Control: no-cache, no-store, must-revalidate"); header("Pragma: no-cache"); header("Expires: 0"); // 强制下载的核心响应头 header("Content-Type: $mimeType"); header("Content-Disposition: attachment; filename=\"$fileName\""); header("Content-Length: " . filesize($filePath)); readfile($filePath); exit; }
二、重写链接需刷新才下载的问题
直接访问html/download.php正常,但重写后的/download要刷新才触发,大概率是浏览器缓存了重写路径的旧响应,或者Rewrite规则未处理缓存控制。
解决步骤:
修正
.htaccess的Rewrite规则,添加缓存控制与终止标志:RewriteEngine On # 对/download路径强制禁止缓存 <FilesMatch "^download$"> Header set Cache-Control "no-cache, no-store, must-revalidate" Header set Pragma "no-cache" Header set Expires "0" </FilesMatch> RewriteRule ^download$ html/download.php [L]确保浏览器每次访问
/download都会发起新请求,不会复用缓存内容。检查
download.php文件,确保在输出响应头前没有任何多余空格或输出(比如<?php标签前后的空白)——如果有提前输出,会导致下载头失效,浏览器可能先加载页面再触发下载,表现为需要刷新。调整下载链接为
<a href="/download">Download</a>,配合上述规则与PHP头设置,即可直接触发下载,无需刷新。
本地环境正常是因为本地服务器(如XAMPP/WAMP)默认配置了这类文件的MIME类型,而线上服务器未配置,才出现环境差异。
内容的提问来源于stack exchange,提问作者Alexander Galler
相关产品推荐
相关产品推荐

