一、安装inotify扩展

1、下载inotify扩展源码

https://pecl.php.net/package/inotify

对于php7以上版本,请下载 inotify-2.0.0.tgz。

2、编译安装

tar xf inotify-2.0.0.tgz
cd inotify-2.0.0
/data/nmp/php/bin/phpize
./configure --with-php-config=/data/nmp/php/bin/php-config
make && make install

3、修改php.ini,添加

extension = inotify.so

  

二、使用inotify进行文件监控

php的inotify扩展提供了监控文件或目录的功能,可以用来实现,服务的热更新,或安全监控。

inotify一共提供了5个函数:

1、inotify_init() 用于初始化一个实例,返回的是一个 stream 资源对象,可以被标准stream函数使用,如stream_set_blocking()。

2、inotify_add_watch() 将一个文件或目录添加到监控列表中,如果存在,则替换。

3、inotify_read() 从 inotify 实例中读取事件,如果没有返回false,如果有,返回一个 inotify 事件数组。

4、inotify_queue_len() 返回队列中事件的个数,可以理解为系统把 inotify_add_watch 关注的事件一个个加入队列,通过 inotify_read() 读取事件。

5、inotify_rm_watch() 取消监控。

一个简单的阻塞监控代码:

<?php

//初始化一个inotify实例
$fd = inotify_init(); //设置为阻塞模式,当inotify_read()无法从$fd中读取到事件时,会一直阻塞在那里。
stream_set_blocking($fd, 1); //事件掩码
$eventMask = [
IN_ACCESS => 'File was accessed (read)',
IN_MODIFY => 'File was modified',
IN_ATTRIB => 'Metadata changed',
IN_CLOSE_WRITE => 'File opened for writing was closed',
IN_CLOSE_NOWRITE => 'File not opened for writing was closed',
IN_OPEN => 'File was opened',
IN_MOVED_TO => 'File moved into watched directory',
IN_MOVED_FROM => 'File moved out of watched directory',
IN_CREATE => 'File or directory created in watched directory',
IN_DELETE => 'File or directory deleted in watched directory',
IN_DELETE_SELF => 'Watched file or directory was deleted',
IN_MOVE_SELF => 'Watch file or directory was moved',
IN_CLOSE => 'Equals to IN_CLOSE_WRITE | IN_CLOSE_NOWRITE',
IN_MOVE => 'Equals to IN_MOVED_FROM | IN_MOVED_TO',
IN_ALL_EVENTS => 'Bitmask of all the above constants',
IN_UNMOUNT => 'File system containing watched object was unmounted',
IN_Q_OVERFLOW => 'Event queue overflowed (wd is -1 for this event)',
IN_IGNORED => 'Watch was removed (explicitly by inotify_rm_watch() or because file was removed or filesystem unmounted',
IN_ISDIR => 'Subject of this event is a directory',
IN_ONLYDIR => 'Only watch pathname if it is a directory',
IN_DONT_FOLLOW => 'Do not dereference pathname if it is a symlink',
IN_MASK_ADD => 'Add events to watch mask for this pathname if it already exists',
IN_ONESHOT => 'Monitor pathname for one event, then remove from watch list.',
1073741840 => 'High-bit: File not opened for writing was closed',
1073741856 => 'High-bit: File was opened',
1073742080 => 'High-bit: File or directory created in watched directory',
1073742336 => 'High-bit: File or directory deleted in watched directory',
]; //添加监控,修改,创建,删除事件
$watch = inotify_add_watch($fd, './tmp', IN_MODIFY | IN_CREATE | IN_DELETE | IN_ISDIR); //循环读取事件
while ($events = inotify_read($fd)) {
// $events会是一个二维数组
// wd 表示inotify_add_watch()返回的监控描述符
// mask 表示事件掩码
// cookie 表示唯一的ID,用于关联相关的事件
// name 表示文件的名称
echo date('Y-m-d H:i:s'), PHP_EOL;
foreach ($events as $event) {
$eventName = isset($eventMask[$event['mask']]) ? $eventMask[$event['mask']] : '';
echo $event['name'], PHP_EOL;
echo $eventName, PHP_EOL;
}
} //取消监控
inotify_rm_watch($fd, $watch); //关闭资源
fclose($fd);

  

三、我们通过非阻塞的方式来监控文件

<?php

//初始化一个inotify实例
$fd = inotify_init(); //设置为非阻塞模式
stream_set_blocking($fd, 0); //事件掩码
$eventMask = [
IN_ACCESS => 'File was accessed (read)',
IN_MODIFY => 'File was modified',
IN_ATTRIB => 'Metadata changed',
IN_CLOSE_WRITE => 'File opened for writing was closed',
IN_CLOSE_NOWRITE => 'File not opened for writing was closed',
IN_OPEN => 'File was opened',
IN_MOVED_TO => 'File moved into watched directory',
IN_MOVED_FROM => 'File moved out of watched directory',
IN_CREATE => 'File or directory created in watched directory',
IN_DELETE => 'File or directory deleted in watched directory',
IN_DELETE_SELF => 'Watched file or directory was deleted',
IN_MOVE_SELF => 'Watch file or directory was moved',
IN_CLOSE => 'Equals to IN_CLOSE_WRITE | IN_CLOSE_NOWRITE',
IN_MOVE => 'Equals to IN_MOVED_FROM | IN_MOVED_TO',
IN_ALL_EVENTS => 'Bitmask of all the above constants',
IN_UNMOUNT => 'File system containing watched object was unmounted',
IN_Q_OVERFLOW => 'Event queue overflowed (wd is -1 for this event)',
IN_IGNORED => 'Watch was removed (explicitly by inotify_rm_watch() or because file was removed or filesystem unmounted',
IN_ISDIR => 'Subject of this event is a directory',
IN_ONLYDIR => 'Only watch pathname if it is a directory',
IN_DONT_FOLLOW => 'Do not dereference pathname if it is a symlink',
IN_MASK_ADD => 'Add events to watch mask for this pathname if it already exists',
IN_ONESHOT => 'Monitor pathname for one event, then remove from watch list.',
1073741840 => 'High-bit: File not opened for writing was closed',
1073741856 => 'High-bit: File was opened',
1073742080 => 'High-bit: File or directory created in watched directory',
1073742336 => 'High-bit: File or directory deleted in watched directory',
]; //添加监控,修改,创建,删除事件
$watch = inotify_add_watch($fd, './tmp', IN_MODIFY | IN_CREATE | IN_DELETE | IN_ISDIR); //循环
while (true) {
//所有可读的流,监听读事件
$reads = [$fd];
//可写的流,设为空,表示我们不需要监听写事件
$write = [];
//异常事件
$except = [];
//参数四,表示超时时间
//如果设置成大于0,表示等待事件发生的超时时间
//如果设置等于0,表示不断调用select,执行后立马返回
//如果设置null,表示阻塞一直到监听发生变化
if (stream_select($reads, $write, $except, 3) > 0) {
//注意$reads是引用传递,select每次会把可读的流放到$reads中,所以$reads变量是会改变的
if (!empty($reads)) {
foreach ($reads as $read) {
//从可读流中读取数据
$events = inotify_read($read);
foreach ($events as $event) {
echo $event['name'], ' --- ', $eventMask[$event['mask']], PHP_EOL;
}
}
}
} else {
echo 'select timeout ...', PHP_EOL;
}
} //取消监控
inotify_rm_watch($fd, $watch); //关闭资源
fclose($fd);

  

四、封装一个类,用来监控文件或目录。

<?php

class InotifyMonitor
{
//需要监控的事件
const MONITOR_EVENT = IN_MODIFY | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_CLOSE_WRITE; //事件掩码
const EVENT_MASK = [
IN_ACCESS => 'File was accessed (read)',
IN_MODIFY => 'File was modified',
IN_ATTRIB => 'Metadata changed',
IN_CLOSE_WRITE => 'File opened for writing was closed',
IN_CLOSE_NOWRITE => 'File not opened for writing was closed',
IN_OPEN => 'File was opened',
IN_MOVED_TO => 'File moved into watched directory',
IN_MOVED_FROM => 'File moved out of watched directory',
IN_CREATE => 'File or directory created in watched directory',
IN_DELETE => 'File or directory deleted in watched directory',
IN_DELETE_SELF => 'Watched file or directory was deleted',
IN_MOVE_SELF => 'Watch file or directory was moved',
IN_CLOSE => 'Equals to IN_CLOSE_WRITE | IN_CLOSE_NOWRITE',
IN_MOVE => 'Equals to IN_MOVED_FROM | IN_MOVED_TO',
IN_ALL_EVENTS => 'Bitmask of all the above constants',
IN_UNMOUNT => 'File system containing watched object was unmounted',
IN_Q_OVERFLOW => 'Event queue overflowed (wd is -1 for this event)',
IN_IGNORED => 'Watch was removed (explicitly by inotify_rm_watch() or because file was removed or filesystem unmounted',
IN_ISDIR => 'Subject of this event is a directory',
IN_ONLYDIR => 'Only watch pathname if it is a directory',
IN_DONT_FOLLOW => 'Do not dereference pathname if it is a symlink',
IN_MASK_ADD => 'Add events to watch mask for this pathname if it already exists',
IN_ONESHOT => 'Monitor pathname for one event, then remove from watch list.',
1073741840 => 'High-bit: File not opened for writing was closed',
1073741856 => 'High-bit: File was opened',
1073742080 => 'High-bit: File or directory created in watched directory',
1073742336 => 'High-bit: File or directory deleted in watched directory',
]; //用于保存inotify_init返回的资源
public $fds = [];
//用于保存监控的文件路径
public $paths = [];
//用于保存inotify_add_watch返回的监控描述符
public $wds = [];
//超时时间
public $timeout = 3; /**
* $paths添加监控的路径数组,可以是目录或文件
*/
public function __construct($paths = [])
{
if (!empty($paths)) {
foreach ($paths as $path) {
if (file_exists($path)) {
if (is_dir($path)) {
$this->addDir($path);
} else {
$this->addFile($path);
}
}
}
}
} public function __destruct()
{
if (!empty($this->fds)) {
foreach ($this->fds as $fd) {
fclose($fd);
}
}
} /**
* 添加文件监控
*/
public function addFile($file)
{
$file = realpath($file);
$fd = inotify_init();
$fid = (int)$fd;
//保存inotify资源
$this->fds[$fid] = $fd;
//设置为非阻塞模式
stream_set_blocking($this->fds[$fid], 0);
//保存文件路径
$this->paths[$fid] = $file;
//保存监控描述符
$this->wds[$fid] = inotify_add_watch($this->fds[$fid], $file, self::MONITOR_EVENT);
} /**
* 添加目录监控
*/
public function addDir($dir)
{
$dir = realpath($dir);
if ($dh = opendir($dir)) {
//将目录加入监控中
$fd = inotify_init();
//一般文件的资源描述符是一个整形,可以用来当索引
$fid = (int)$fd;
$this->fds[$fid] = $fd;
stream_set_blocking($this->fds[$fid], 0);
$this->paths[$fid] = $dir;
$this->wds[$fid] = inotify_add_watch($this->fds[$fid], $dir, self::MONITOR_EVENT);
//遍历目录下文件
while (($file = readdir($dh)) !== false) {
if ($file == '.' || $file == '..') {
continue;
}
$file = $dir . DIRECTORY_SEPARATOR . $file;
if (is_dir($file)) {
$this->addDir($file);
}
}
closedir($dh);
}
} /**
* 移除监控
*/
public function remove($fid)
{
unset($this->paths[$fid]);
fclose($this->fds[$fid]);
unset($this->fds[$fid]);
} /**
* 运行监控
*/
public function run()
{
while (true) {
$reads = $this->fds;
$write = [];
$except = [];
if (stream_select($reads, $write, $except, $this->timeout) > 0) {
if (!empty($reads)) {
foreach ($reads as $read) {
//从可读流中读取数据
$events = inotify_read($read);
//资源描述符,整形
$fid = (int)$read;
//获取inotify实例的路径
$path = $this->paths[$fid];
foreach ($events as $event) {
$file = $path . DIRECTORY_SEPARATOR . $event['name'];
switch ($event['mask']) {
case IN_CREATE:
case 1073742080:
if (is_dir($file)) {
echo 'add ...', PHP_EOL;
echo 'fid : ', $fid, PHP_EOL;
$this->addDir($file);
}
break;
case IN_DELETE_SELF:
if (is_dir($file)) {
echo 'remove ...', PHP_EOL;
echo 'fid : ', $fid, PHP_EOL;
$this->remove($fid); $key = array_search($read, $reads);
unset($reads[$key]);
}
break;
}
echo $event['name'], ' --- ', self::EVENT_MASK[$event['mask']], PHP_EOL;
}
}
}
} else {
echo '------------------', PHP_EOL;
echo '当前监控的路径列表', PHP_EOL;
print_r($this->paths);
echo '------------------', PHP_EOL;
}
}
}
} (new InotifyMonitor(['./tmp', './test.php']))->run();

  

php使用inotify扩展监控文件或目录的变化的更多相关文章

  1. php使用inotify扩展监控文件或目录,如果发生改变,就执行指定命令

    通过inotify扩展监控文件或目录的变化,如果发生变化,就执行命令. 可以应用于 swoole 中,如果文件发生变化,就执行 kill -USR1 进程PID 来实现热更新. <?php cl ...

  2. 根据 inotify 自己开发软件监控文件系统活动

    了解 inotify Inotify 是一个 Linux 内核特性,它监控文件系统,并且及时向专门的应用程序发出相关的事件警告,比如删除.读.写和卸载操作等.您还可以跟踪活动的源头和目标等细节. 使用 ...

  3. 【转载】CentsOS系统inotify实时监控服务器文件(夹)定制事件处理程序

    原始博文和参考博文 1.CentsOS系统inotify实时监控服务器文件 2.Linux中让进程在后台运行的方法 3.linux inotify 监控文件系统事件 非常好 方法一 说明: 服务器系统 ...

  4. 两台linux主机使用unison + inotify实现web文件夹同步

    两台服务器同步数据 unison 是一款跨平台的文件同步对象,不仅支撑本地对本地同步,也支持通过SSH,RSH和Socket 等网络协议进行同步. unison 支持双向同步,你可以同A同步到B ,也 ...

  5. rsync+inotify百万级文件实时同步

    实验环境:Centos7.4 目的:将源服务器的文件实时同步至目标服务器 源服务器:10.11.1.107 目标服务器:10.11.1.106 分别在两个节点安装rsync yum -y instal ...

  6. Java 7 中 NIO.2 的使用——第四节 文件和目录

    Files类提供了很多方法用于检查在于你真正实际去操作一个文件或目录.这些方法强烈推荐,也非常有用,也能避免很多异常的发生.例如,一个很好的习惯就是在你试着移动一个文件从一个地方到另一个地方的时候,先 ...

  7. inotify监控文件变化

    1.安装inotify-tools yum install make  gcc gcc-c++  #安装编译工具 inotify-tools下载地址:http://github.com/downloa ...

  8. [转帖]Linux下inotify监控文件夹状态,发生变化后触发rsync同步

    Linux下inotify监控文件夹状态,发生变化后触发rsync同步 https://www.cnblogs.com/fjping0606/p/6114123.html 1.安装工具--inotif ...

  9. [转]C# FileSystemWatcher监控指定文件或目录的文件的创建、删除、改动、重命名等活动

    觉得这个很常用..比如一些软件.   http://www.rabbit8.cn/DoNet/407.html   FileSystemWatcher控件主要功能: 监控指定文件或目录的文件的创建.删 ...

随机推荐

  1. 【cf932E】E. Team Work(第二类斯特林数)

    传送门 题意: 求\(\displaystyle \sum_{i=0}^n{n\choose i}i^k,n\leq 10^9,k\leq 5000\). 思路: 将\(i^k\)用第二类斯特林数展开 ...

  2. [考试反思]1110csp-s模拟测试109:细节

    细节...决定成败 T2数组开小,T3long long没开够. 而且其实不止这样,考试结束前15分钟发现了好多低错: T3双向边没开2倍.dfs没递归调用.T2为了调试bitset开20没改(后来改 ...

  3. RobotFramework不同版本优劣势

    一.RIDE 1.5.2.1 1. 安装: pip install robotframework-ride==1.5.2.1 2. 优点: 此版本是RIDE发布以来最为稳定的版本,使用性能上也较为流畅 ...

  4. vue 客户端渲染和服务端渲染

    参考链接 https://www.cnblogs.com/tiedaweishao/p/6644267.html

  5. C#以对象为成员的例子

    using System; using System.Collections.Generic; using System.Text; namespace test { class Program { ...

  6. .Netcore Swagger - 解决外部库导致的“Actions require an explicit HttpMethod binding for Swagger 2.0”

    现象: 项目中导入Ocelot后,swagger页面无法正常显示,查看异常发现 Ocelot.Raft.RaftController 中的 Action 配置不完全,swagger扫描时不能正确生成 ...

  7. Java - IO 内存流和打印流

    IO 内存流和打印流操作 字符编码 计算机中所有的信息组成都是二进制数据,所有能够描述的中文文字都是经过处理后的结果:所有的语言文字都会使用编码来进行描述,例如:ASCII码 常见编码 GBK/GB2 ...

  8. Android 亮度调节功能开发思路整理

    做 Android 音视频播放器开发的时候,我们基本都会遇到一类需求:音量 & 亮度 调节.其中做亮度调节功能的时候,发现还是有一定复杂度的. Android亮度调节分为两个类,分别是: An ...

  9. Ubuntu16.0 GTX1660Ti 安装NVIDIA CUDA cuDNN Tensflow

    主要参考这篇文章Ubuntu16.04(GTX1660ti)cuda10.0和cudnn7.6环境配置 (环境乃一生之敌!!!). 容易错的点: 安装NVIDIA驱动的时候选择run版本,不要选择de ...

  10. 网络编程~~~ socket(套字节)

    一 socket (套接字) socket处于应用层与传输层之间,提供了一些简单的接口,避免与操作系统之间的对接,省去了相当繁琐复杂的操作. socket在python中属于一个模块,通过调用模块中已 ...