PHP处理含&文件名调用file_exists返回false的问题排查
根因定位
你观察到的$var=trim($_GET[$name]);阶段就发生截断,和PHP对&的处理逻辑无关,本质是HTTP GET请求的固有规则导致:&符号是GET参数的默认分隔符,如果你的下载链接构造时是/download.php?file=A & T.pdf,服务器会自动把&后的内容识别为新的独立参数,最终$_GET['file']拿到的本来就只有A,因此你之前在后端尝试的所有转义方案都不会生效。
修复方案
1. 前端侧必须编码文件名后再构造下载链接
生成下载链接时,要对文件名做URL编码,把&转义为%26,最终生成的合法下载链接应为/download.php?file=A%20%26%20T.pdf,这样后端$_GET['file']才能拿到完整的A & T.pdf字符串。
- 如果是PHP渲染前端页面,生成链接时用
urlencode()处理文件名:
$download_url = '/download.php?file=' . urlencode($filename_from_db);
- 如果是JS前端生成链接,用
encodeURIComponent()处理文件名:
const downloadUrl = `/download.php?file=${encodeURIComponent(filename)}`;
2. 后端侧调整冗余转义逻辑
你当前使用的get_get函数存在逻辑缺陷:对所有字符串类型参数直接调用了pg_escape_string(),这个函数是专门为SQL查询做转义的,你拿到文件名是要读取本地/存储文件,不是拼接SQL语句,这个转义会把文件名里的特殊字符替换为PostgreSQL兼容的转义格式,反而会导致file_exists()无法匹配到真实文件。
建议调整函数增加转义开关,仅在参数用于SQL查询时做转义:
// 调整后的get_get函数,新增is_sql参数控制是否做SQL转义 function get_get($name,$default='',$type='string',$maxlenght=0, $is_sql = false){ if(!isset($_GET[$name])) { $var = $default; } else { $var = trim($_GET[$name]); if($maxlenght > 0 && strlen($var) > $maxlenght) $var = substr($var, 0, $maxlenght); settype($var, $type); // 仅需要拼SQL时才做pg转义 if($is_sql && $type == "string" && !get_magic_quotes_gpc()) { $var = pg_escape_string(my_connect(), $var); } } return $var; } // 获取文件名时调用,不开启SQL转义 $filename = get_get('file', '0', 'string', 255, false);
补充说明
Linux文件系统和Azure文件存储都原生支持带&的文件名,只要你后端拿到的文件名是完整的、路径拼接正确,不需要对&做额外转义就能直接传给file_exists()使用。
内容的提问来源于stack exchange,提问作者strumpy_strudel
相关产品推荐
相关产品推荐

