什么是 inotify?
inotify 是 Linux 内核的一个子系统,专门用来监控文件系统事件(比如文件的创建、删除、读取、写入和关闭)。
在 PHP 中,inotify 扩展是对这个内核功能的封装。
1. 为什么它比“定时扫描”好?
| 维度 | 定时任务 (Cron) | Inotify 扩展 |
| 实时性 | 取决于间隔(如 1 秒或 5 秒) | 零延迟,文件一关闭立即触发 |
| 性能消耗 | 即使没图片,PHP 也会频繁启动并扫描磁盘 | 静默监听,无事件时不消耗 CPU |
| 可靠性 | 容易漏掉处理中的文件,或重复处理 | 精确捕捉“文件写入完成”那一刻 |
2. 如何安装?
由于它依赖 Linux 内核,Windows 环境下无法使用。在 Linux 上通常通过 pecl 安装:
sudo pecl install inotify
# 安装完成后,在 php.ini 中添加:
# extension=inotify.so
3. PHP 代码怎么写?
效果:死循环运行,监听文件夹,一旦 FTP 完整上传了一张图,它就捕获到路径并输出
<?php
// 1. 初始化 inotify 实例
$fd = inotify_init();
// 2. 添加监听目录(你的 FTP 根目录)
// IN_CLOSE_WRITE 非常重要:表示文件写入完成并关闭,此时读取才完整
$watch_descriptor = inotify_add_watch($fd, ‘/path/to/ftp/images’, IN_CLOSE_WRITE);
echo “正在监听 FTP 目录…\n”;
// 3. 进入无限循环监听
while (true) {
// 读取事件(这一步是阻塞的,没有事件时程序会“休息”,不占 CPU)
$events = inotify_read($fd);
if ($events) {
foreach ($events as $event) {
// $event[‘name’] 就是新上传的文件名
$fileName = $event[‘name’];
$fullPath = “/path/to/ftp/images/” . $fileName;
if (preg_match(‘/\.(jpg|jpeg|png)$/i’, $fileName)) {
echo “检测到新图片: $fullPath \n”;
// — 这里就是以后对接 RabbitMQ 的地方 —
// pushToRabbitMQ($fullPath);
}
}
}
}
// 4. 停止监听(实际运行中基本不会走到这)
inotify_rm_watch($fd, $watch_descriptor);
fclose($fd);
4. 关键点:为什么选 IN_CLOSE_WRITE?
这是很多新手容易踩的坑。
如果监听 IN_CREATE(创建):文件刚创建,内容还是 0KB,PHP 读图会报错。
如果监听 IN_MODIFY(修改):文件传输过程中会触发几十次这个事件,导致重复处理。
IN_CLOSE_WRITE:只有当 FTP 进程把图片写完并关闭了文件句柄时才会触发。这保证了你拿到的图片是 100% 完整的。
避坑指南
子目录问题:标准的 inotify 不支持递归监控子目录。如果你的 FTP 是按照 /camera1/、/camera2/ 这种结构存的,你需要为每个子目录分别调用 inotify_add_watch。
进程守护:这个脚本需要常驻后台运行。建议使用 nohup php script.php & 或者最专业的 Supervisor。