应优先用 hash_file('sha256', $path) 比对文件内容,哈希一致则内容必相同,不一致则内容必不同;避免用 filemtime()/filesize() 替代内容比对,慎用截断哈希或非恒定时间比较。

直接用 hash_file() 比对文件内容最稳
两个文件内容是否一致,99% 的场景下不需要逐行 diff —— 只要内容完全相同,哈希值就一定相同;只要哈希值不同,内容必然不同。这是数学保证,比读文件、转字符串、再 strcmp 快得多,也更可靠。
关键点:别用 md5_file() 或 sha1_file() 硬写,统一走 hash_file(),它支持更多算法且接口一致:
-
hash_file('sha256', '/path/a.txt')返回标准 64 字符 hex 字符串 - 小文件('xxh128'(PHP 8.1+)最快,但兼容性差;生产环境优先选
'sha256' - 注意文件权限和路径是否真实可读,
hash_file()失败会返回false,不是空字符串 - Windows 下路径分隔符不影响,但要注意符号链接——
hash_file()对软链是读目标文件,不是链本身
逐行 diff 只在需要定位差异时才值得做
如果你看到 “两文件看起来一样但哈希不同”,大概率是换行符(\r\n vs \n)、BOM、末尾空格或编码隐式转换导致的。这时候才该上 diff 逻辑,而不是一开始就想“看看哪几行不一样”。
PHP 原生没内置 diff 函数,但有轻量方案:
- 用
file()读成数组后传给array_diff_assoc()只能发现新增/缺失行,不反映顺序变化 - 真要类 shell
diff -u效果,推荐调用系统命令:exec("diff -u " . escapeshellarg($a) . " " . escapeshellarg($b), $output, $return),注意$return === 0表示无差异,1表示有差异,2才是执行失败 - 别用
file_get_contents()+explode("\n"),Windows 换行会被切错;file()自动处理 EOL - 大文件(>10MB)慎用逐行比较,内存和时间都会飙升;先哈希筛一遍,再对哈希不等的少数文件做 diff
filemtime() 和 filesize() 不能代替内容比对
这两个函数常被误当作“快速判断文件是否变化”的替代方案,但它们只反映元数据,不是内容。同内容文件可能因复制、touch、FTP 上传等操作导致修改时间或大小微变(比如 FAT32 时间精度只有 2 秒),也可能内容变了但时间/大小碰巧一样(极小概率,但存在)。
-
filemtime()在 NFS 或容器挂载卷下可能不准,尤其跨时区或客户端缓存开启时 -
filesize()对稀疏文件、符号链接、procfs 文件(如/proc/meminfo)返回值无意义 - 如果只是做缓存校验,建议组合使用:
if (hash_equals(hash_file('sha256', $f), $cached_hash) && filemtime($f) === $cached_mtime),双保险但依然以哈希为准
哈希比较要注意二进制安全和时序攻击
用 == 或 === 直接比较哈希字符串,在极端情况下可能被时序攻击利用(虽然文件哈希场景实际风险极低)。更麻烦的是,如果其中一个哈希是空或 null,=== 会直接 false,但你可能想捕获这个错误态。
- 始终用
hash_equals($h1, $h2)做恒定时间比较,它内部已处理类型转换和空值 -
hash_equals()要求两个参数都是字符串,false会触发 warning,所以先判空:if ($h1 === false || $h2 === false) { /* handle error */ } - 别把哈希存成 int 或截断(比如只取前 8 位),碰撞概率指数级上升;
sha256就老实用全 64 位
哈希计算本身不难,难的是意识到什么时候不该用哈希——比如你要审计日志变更轨迹,或者合并配置片段,这时候 diff 就不是“备选”,而是必需。但凡不确定,先跑一遍 hash_file('sha256', $x),结果不对再拆开看。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











