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

Linux下PHP file_exists无法识别含&符号的文件名问题排查

问题分析与解决方案

核心原因

你遇到的问题大概率是原始A&B.txt文件名中的"&"并非标准ASCII半角符号(字节值0x26),而是以下情况之一:

  • 外观相似的Unicode全角符号"&"(Unicode编码U+FF06)
  • 文件名包含不可见控制字符,导致视觉上和A&B.txt一致,但实际字节序列不匹配
  • 跨系统复制文件时的编码转换异常(比如从Windows GBK环境复制到Debian UTF-8环境时的隐性编码错误)

而你通过touch diffA&B.txt创建的文件,使用的是标准半角"&",所以file_exists()能正常识别;scandir('.')能列出文件,是因为它直接读取系统返回的原始文件名字节流,不会做视觉上的字符匹配校验。

验证方法

  1. 用终端命令查看真实文件名
    在Debian终端执行以下命令,查看文件名的原始转义字符:

    ls -b | grep "A.*B.txt"
    
    • 如果是标准半角"&",输出会显示A&B.txt
    • 如果是全角"&",会显示类似A\342\200\254B.txt的转义序列
    • 如果有不可见字符,会显示对应的转义码
  2. 在PHP中对比字节序列
    执行以下代码,对比手动输入的文件名和scandir返回的文件名的二进制内容:

    $files = scandir('.');
    foreach ($files as $file) {
        if (str_contains($file, 'A') && str_contains($file, 'B.txt')) {
            echo "扫描到的文件名:$file\n";
            echo "扫描文件名的十六进制:" . bin2hex($file) . "\n";
            echo "手动输入的十六进制:" . bin2hex('A&B.txt') . "\n";
            echo "file_exists检测结果:" . var_export(file_exists($file), true) . "\n\n";
        }
    }
    

    如果两行十六进制结果不一致,说明文件名的实际字节和你手动输入的不匹配。

解决办法

  1. 重命名文件为标准格式
    根据ls -b的输出结果,用终端命令重命名文件:

    • 如果是全角"&":
      mv "A&B.txt" "A&B.txt"
      
    • 如果是带不可见字符的情况,复制ls -b输出的转义字符串来重命名:
      mv "A\001&B.txt" "A&B.txt"
      
      (替换\001为实际看到的转义码)
  2. 在PHP中使用扫描到的文件名
    如果不需要修改文件名,可以直接使用scandir返回的文件名字符串调用file_exists(),避免手动输入带来的字符匹配问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:30:55