filemtime() 返回文件系统最后修改时间而非视频拍摄时间,真实时间藏于元数据中,需用ffprobe或exiftool提取并修复,仅改文件时间戳不影响播放器显示。

为什么 filemtime() 返回的时间和视频实际创建时间对不上
PHP 的 filemtime() 读的是文件系统最后修改时间,不是视频元数据里的拍摄时间。很多视频(尤其是手机拍的 MP4、MOV)在传输、重命名、FTP 上传后,filemtime() 就被覆盖成操作时间,原始时间戳就丢了。
真正的时间信息藏在视频容器的元数据里,比如 creation_time 或 date 字段,得用外部工具解析。PHP 自身不解析视频元数据,硬靠 filemtime() 或 filectime() 做判断会误判。
- 用
ffprobe提取原始时间戳:ffprobe -v quiet -show_entries format_tags=creation_time -of default=nw=1 input.mp4 - 返回类似
format_tags=creation_time=2023-05-12T08:23:41.000000Z,需手动提取并转为 Unix 时间戳 - 注意时区:
creation_time通常是 UTC,而touch命令默认按本地时区设置时间,直接传会偏移 - 某些老旧 MP4 或剪辑过的视频可能根本没有
creation_time字段,ffprobe输出为空,这时只能退回到文件系统时间或人工核对
用 touch 批量修复文件时间戳但视频播放器仍显示错误时间
修复文件系统时间戳只是第一步。播放器(如 VLC、QuickTime、Windows 照片应用)优先读取视频内部的 com.apple.creationdate(MOV)、date(MP4)、DateTimeOriginal(AVI)等标签,而不是文件属性。只改 touch 不碰元数据,播放器看到的还是旧时间。
必须用支持写入元数据的工具,且要区分格式:
立即学习“PHP免费学习笔记(深入)”;
- MP4/MOV 推荐用
ffmpeg覆盖date标签:ffmpeg -i input.mp4 -c copy -metadata date="2023-05-12 08:23:41" output.mp4 - AVI 用
exiftool更稳妥:exiftool -DateTimeOriginal="2023:05:12 08:23:41" -overwrite_original input.avi -
ffmpeg的-c copy模式不重编码,快但不保证所有播放器识别新date;若失效,可加-movflags +use_metadata_tags强制写入 - 注意 Windows 下
exiftool需管理员权限才能修改某些 AVI 文件,否则静默失败
视频文件损坏但能播放前几秒——还能抢救元数据吗
能播 ≠ 元数据完整。常见情况是 MOOV atom(包含时长、分辨率、时间戳等关键信息)被截断或写在文件末尾(moov at end),而文件开头损坏导致 ffprobe 直接报错 Invalid data found when processing input。
抢救思路是绕过损坏头,定位并提取残留的 MOOV:
- 用
dd跳过开头损坏部分再试:dd if=input.mp4 bs=1024 skip=100 | ffprobe -v error -show_entries format_tags=date -of default=nw=1 2>/dev/null - 用
mp4dump(来自mp4box)查看 box 结构:mp4dump --deep input.mp4 | grep -A5 -B5 moov,确认 MOOV 是否存在及位置 - 如果 MOOV 完整但不在开头,可用
mp4box -fix input.mp4尝试重建索引(不重编码) - 若
ffprobe报moov atom not found,说明 MOOV 丢失,此时只能靠文件名、目录名、EXIF(如果是拍照生成的 MP4)或备份日志反推时间,无法从文件本身恢复
PHP 脚本调用 ffprobe/exiftool 时卡住或返回空结果
不是命令写错了,大概率是超时、权限或路径问题。PHP 的 exec() 默认没有超时控制,遇到大视频或磁盘慢会假死;同时,Web 服务器用户(如 www-data)常无权访问 /usr/bin/exiftool 或读取某些挂载路径。
- 加超时和错误捕获:
exec('timeout 30s ffprobe -v quiet -show_entries format_tags=creation_time ... 2>&1', $output, $return_code);检查$return_code !== 0再处理输出 - 绝对路径必须写全:
/usr/bin/ffprobe而非ffprobe,Web 进程的$PATH通常很窄 - 确保目标文件可被 Web 用户读取:
chmod 644不够,还需确认父目录有+x权限(否则无法进入目录) - Windows 下
exiftool.exe路径含空格时,必须用双引号包裹:"C:\Program Files\ExifTool\exiftool.exe",且 PHP 的escapeshellarg()对 Windows 路径支持有限,建议手动处理
时间戳修复本质是元数据搬运工,不是魔法。MOOV 丢了、标签被清空、文件权限锁死——这些时候,再好的 PHP 脚本也救不回不存在的东西。



















