php无法原生实现实时文件夹监控,需依赖inotifywait(linux)或robocopy(windows)等外部工具,或改用python/node.js等语言实现监听服务供php消费事件。

PHP 本身没有内置的、跨平台的实时文件夹监控机制,inotify(Linux)和 ReadDirectoryChangesW(Windows)这类系统级 API 无法直接在纯 PHP 脚本中持续监听——你写的 PHP 脚本执行完就退出,没法“常驻后台”。真要实现实时监测,必须借助外部工具或进程管理手段。
用 inotifywait 命令配合 PHP 启动守护进程
Linux 下最轻量、可靠的方式是调用 inotifywait(来自 inotify-tools 包),让 PHP 启动并读取它的 stdout 流。它能真正事件驱动,不轮询、无延迟、低资源占用。
- 先确认已安装:
inotifywait -h能输出帮助即表示可用;若未安装,Ubuntu/Debian 执行sudo apt install inotify-tools,CentOS/RHEL 用sudo yum install inotify-tools - PHP 中用
proc_open启动长运行的inotifywait进程,避免exec或shell_exec因阻塞导致脚本卡死 - 关键参数必须加:
-m(持续监控)、-e create,delete,modify,move(指定事件类型)、--format '%w%f %e'(结构化输出,便于 PHP 解析) - 注意:PHP 进程需保持运行,建议用
nohup php monitor.php > /dev/null 2>&1 &启动,并配合pcntl_signal处理 SIGTERM 以安全终止子进程
scandir + 时间戳轮询只适合开发或低频场景
如果只是本地调试、CI 脚本触发、或每分钟才检查一次,用 scandir 配合 filemtime 是最简单方案,但绝不能称为“实时”。
- 每次调用都需完整遍历目录,文件越多越慢;频繁轮询(如 1 秒一次)会显著增加 I/O 和 CPU 开销
- 两次扫描之间发生的快速创建+删除可能被漏掉(竞态窗口)
- 注意
scandir返回结果不含路径,拼接时务必用realpath或规范分隔符:$full_path = $dir . DIRECTORY_SEPARATOR . $file - 缓存上次扫描的
filemtime和filesize到数组或 Redis,比每次都stat更高效
Windows 下只能靠 robocopy 或第三方服务兜底
Windows 没有原生类 Unix 的 inotify,PHP 的 stream_select 对目录句柄无效,FileSystemWatcher 是 .NET 专属。PHP 唯一可行的折中方案是:
立即学习“PHP免费学习笔记(深入)”;
- 用
robocopy的/MON:1(监控变更)或/MOT:10(每隔 10 秒检查)参数启动监听,输出到临时日志,PHP 定期tail -n 1类似方式读取最后一行 - 或改用 Python/Node.js 写一个监听服务(如
watchdog库),PHP 通过 HTTP 或 socket 与其通信 - 绝对不要尝试用
glob+sleep循环——Windows 下文件系统缓存行为更不可控,且filemtime在某些共享盘或 OneDrive 同步目录中会严重滞后
真正的“实时”意味着毫秒级响应和事件保序,这在 PHP 单进程模型里天然受限。如果你的业务要求高可靠性(比如自动触发构建、审计日志),优先考虑把监控逻辑移出 PHP,让它只做事件消费端;否则,哪怕加了 pcntl_fork,也得面对信号处理、僵尸进程、内存泄漏这些容易被忽略的底层细节。











