pathinfo()在windows上处理中文路径必须设置正确locale,否则dirname丢中文、basename截断或为空;根本原因是其按字节扫描分隔符,多字节字符字节值易与0x5c/0x2f冲突,导致静默错误。

pathinfo() 在 Windows 上处理中文路径时,不设 locale 就直接用,大概率出错 —— dirname 丢中文、basename 截断、甚至返回空字符串,这不是 bug,是它本来就这样设计的。
Windows 下 pathinfo() 解析中文路径失败的典型现象
你在 Windows(比如 Win10 + PHP 7.4)中执行:
$path = 'D: emp项目测试ceshia07.webp'; print_r(pathinfo($path));
得到的 [dirname] 很可能是 D: emp,而不是预期的 D: emp项目测试;[basename] 可能变成乱码或空。根本原因不是 PHP 版本低,而是:pathinfo() 是 locale-aware 函数,它内部按字节扫描 或 /,而中文 GBK/UTF-8 多字节字符的某个字节恰好等于 0x5c(反斜杠)或 0x2f(正斜杠),导致提前截断。
- 现象只在 Windows 常见,因为默认用
分隔符,且系统 locale 常为Chinese (Simplified)_China.936(GBK) - Linux 下多数用 UTF-8 locale,默认行为更稳定,但不代表绝对安全
- 即使你传的是 UTF-8 编码路径,若系统没装
zh_CN.UTF-8locale 或没启用,setlocale(LC_ALL, 'zh_CN.UTF-8')会返回false,等于白设
setlocale() 必须生效,否则一切白搭
别只写 setlocale(LC_ALL, 'zh_CN.UTF-8') 就完事。先确认系统是否真支持这个 locale:
// 检查当前 locale
echo setlocale(LC_ALL, 0); // 输出类似 LC_CTYPE=C
// 尝试设置并验证返回值
if (false === setlocale(LC_ALL, 'zh_CN.UTF-8')) {
echo "locale zh_CN.UTF-8 未安装或名称错误";
}
// 正确的 locale 名称格式(注意:无连字符,.UTF8 不带 '-')
// 常见有效值:'zh_CN.UTF-8'、'Chinese_China.936'、'en_US.UTF-8'
- Windows 下常用
Chinese_China.936(对应 GBK),不是zh_CN.UTF-8—— 后者在 Windows 原生支持极弱 - Linux 下用
locale -a | grep zh_CN查看已安装 locale,没结果就需sudo apt install language-pack-zh-hans(Ubuntu)或等效命令 -
setlocale()是进程级全局设置,在多线程 Web Server(如 Apache on Windows、IIS)中可能被其他请求覆盖,不能依赖“设一次永久生效”
更稳妥的替代方案:绕过 locale 依赖的自定义解析
如果你无法控制服务器 locale,或需要跨平台一致行为,直接用字符串操作代替 pathinfo() 更可靠:
function safe_pathinfo($path) {
$path = str_replace('\', '/', $path); // 统一分隔符
$dir = dirname($path);
$base = basename($path);
$ext = pathinfo($path, PATHINFO_EXTENSION);
$name = $ext ? substr($base, 0, -(strlen($ext) + 1)) : $base;
return compact('dir', 'base', 'ext', 'name');
}
// 使用示例
$result = safe_pathinfo('D:/temp/项目/测试/ceshia07.webp');
// $result['dir'] === 'D:/temp/项目/测试'
- 不依赖 locale,纯 UTF-8 字符串处理,
dirname()和basename()在 PHP 中对 UTF-8 路径本身是安全的(只要分隔符统一) - 避免使用
pathinfo($path, PATHINFO_FILENAME)—— 它和PATHINFO_EXTENSION共享逻辑,仍受 locale 影响 - 注意:此法不处理
..或.归一化,如需防御路径遍历,应额外调用realpath()或白名单校验
文件上传场景下 pathinfo() 的隐藏风险
很多人用 pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION) 做扩展名白名单校验,却忽略:当 locale 错误时,PATHINFO_EXTENSION 可能返回空,或把 shell.php 错判成 .php,而 PATHINFO_BASENAME 可能漏掉前面的 ../ —— 这不是理论风险,是真实可利用的路径遍历漏洞。
- 永远不要只靠
pathinfo()来“净化”用户输入路径 - 扩展名校验必须结合
mb_strtolower()和严格白名单(如in_array($ext, ['jpg','png','pdf'], true)) - 保存文件前务必用
basename()提取最终文件名,并手动过滤.、/、等危险字符
真正麻烦的从来不是怎么让 pathinfo() 支持中文,而是它在 locale 错误时既不报错也不警告,静默返回错误结果 —— 这种“看起来正常”的失效,最容易在上线后突然暴露问题。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











