PHP无法纯实现视频水印,必须依赖ffmpeg;文字水印用drawtext滤镜最可靠,支持字体、位置、颜色等控制,需指定正确字体路径并做参数过滤、超时防护和错误捕获。

PHP用ffmpeg命令行添加文字水印最可靠
PHP本身不支持直接操作视频帧,所谓“原生代码”实现水印其实是调用系统级工具,核心依赖 ffmpeg。想绕过 ffmpeg 用纯 PHP 处理视频,目前没有稳定可行方案。
文字水印推荐用 drawtext 滤镜,它支持字体、大小、位置、颜色、透明度和时间范围控制,比叠加PNG图更轻量、更可控。
ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:fontsize=24:fontcolor=white:x=(w-tw)/2:y=h-50:text='© MySite'" -c:a copy output.mp4- Windows 下
fontfile路径要写成C\:/Windows/Fonts/msyh.ttc这种正斜杠格式,反斜杠会报错 - 中文必须指定支持 Unicode 的字体文件(如
msyh.ttc或NotoSansCJK.ttc),否则显示方块 - 如果提示
Cannot find a valid font for the drawtext filter,说明fontfile路径不对或字体不支持该字符集
用overlay滤镜叠加图片水印要注意坐标与缩放
图片水印本质是把一张 PNG(建议带 alpha 通道)按帧叠加到视频上,靠 overlay 滤镜实现。它比文字水印多一步预处理:确保水印图尺寸合理、位置适配不同分辨率视频。
- 简单叠加:
-vf "overlay=10:10"表示左上角偏移 10px,但若水印图太大,会溢出画面 - 自适应缩放水印:
-vf "movie=logo.png[wm];[in][wm]overlay=x=W-w-10:y=10",其中W是视频宽,w是水印图宽,右上角对齐 - 水印图必须是本地路径(不能是 HTTP URL),且 PHP 进程要有读取权限;常见错误
No such file or directory往往是路径没转义或权限问题 - 叠加后视频编码未重置会导致花屏,务必加
-c:a copy(音频直拷)和显式指定视频编码,如-c:v libx264 -crf 23
PHP执行ffmpeg必须做安全与超时防护
直接用 exec() 或 shell_exec() 调用 ffmpeg 看似简单,但生产环境极易出问题:超长视频卡死进程、恶意文件名注入、输出日志爆炸、权限失控。
立即学习“PHP免费学习笔记(深入)”;
- 永远不要拼接用户输入进命令行,用
escapeshellarg()包裹所有路径和参数,例如:escapeshellarg($input_path) - 设执行超时:
exec('timeout 300 ' . $cmd . ' 2>&1', $output, $return_code),避免单个任务拖垮整个服务 - 捕获错误日志很重要,
2>&1必须带上,否则ffmpeg报错你完全看不到;$return_code !== 0就代表失败 - 别在 Web 请求中长时间执行,大视频建议扔进队列(如 Redis + Worker),前端轮询状态
常见合成失败的三个隐藏原因
即使命令在终端能跑通,PHP 中仍可能静默失败,多数卡在环境差异上。
-
ffmpeg不在$PATH中:Web 服务(如 nginx+php-fpm)的 PATH 和终端不同,要用绝对路径,比如/usr/local/bin/ffmpeg - SELinux 或 AppArmor 限制了 php-fpm 对
ffmpeg的调用,CentOS/RHEL 上查ausearch -m avc -ts recent - 临时目录无写权限:
ffmpeg内部可能需要 /tmp,而 php-fpm 配置了open_basedir或禁用了sys_temp_dir
水印逻辑本身不复杂,难的是让 ffmpeg 在各种服务器环境下稳定、安全、可追踪地跑起来——参数只是表象,环境才是真正的门槛。



















