idimsh / php-inotify-monitor
PHP Inotify 扩展和 React PHP 的包装库,用于监视文件/目录的三个主要事件:创建、修改、删除
Requires
- php: >=7.1
- mkraemer/react-inotify: 1.1.0
Requires (Dev)
- phpunit/phpunit: >= 7.0, < 8.0
- squizlabs/php_codesniffer: ~3.2
- vladahejda/phpunit-assert-exception: dev-master
This package is auto-updated.
Last update: 2024-09-29 05:08:37 UTC
README
React PHP Inotify Monitor / Watcher
PHP Inotify 扩展和 React PHP 的包装库
一个利用 React PHP Event Loop 和 React Inotify 监视文件系统变化的库
它被创建来监视三个基本事件:创建、修改和删除。并且将使用 React Inotify 需要的许多事件减少到简单的三个。
要求
- PHP >= 7.1
- inotify php 扩展
- 支持 inotify 扩展的类似 Linux 的系统
功能
- 监视文件和目录
- 使用 shell 模式配置要监视的模式
- 配置监视的嵌套级别,支持全局级别和模式级别
- 在运行循环之前,基本目录不需要存在,它将自动(可选)等待创建。
- 优化速度
安装
$ composer require idimsh/php-inotify-monitor
或 composer.json
{ "require": { "idimsh/php-inotify-monitor": "dev-master" } }
基本用法
require_once 'vendor/autoload.php'; use Dimsh\React\Filesystem\Monitor\Monitor; use Dimsh\React\Filesystem\Monitor\MonitorConfigurator; $monitor = new Monitor(MonitorConfigurator::factory() ->setBaseDirectory('/tmp') ->setLevel(2) ->setFilesToMonitor([ '*.yaml', ])); $monitor ->on(Monitor::EV_CREATE, function ($path, $monitor) { echo "created: $path\n"; }) ->on(Monitor::EV_MODIFY, function ($path, $monitor) { echo "modified: $path\n"; }) ->on(Monitor::EV_DELETE, function ($path, $monitor) { echo "deleted: $path\n"; }) ->run();
以下代码将监视 /tmp/
内部最多两个级别的 *.yaml
文件,因此以下模式匹配: /tmp/*.yaml
和 /tmp/*/*.yaml
,但不匹配 /tmp/*/*/*.yaml
类
定义了两个类
MonitorConfigurator
:用于配置监视器Monitor
:定义事件处理器,并在捕获事件时执行操作。
构造函数接受一个MonitorConfigurator
对象作为依赖项。
继承自\Evenement\EventEmitter
。
MonitorConfigurator
的 API 方法
-
setBaseDirectory()
:定义监视器将监视其更改的目录,它必须是绝对路径,如果不是:使用当前工作目录构造绝对路径,因此空基本目录是有效的。
一般规则是:不要将其设置为根目录'/'
,并且不要在大量文件正在修改的目录上进行操作,如:/var/log/
。
如果指定的目录表示文件,则抛出\Exception
。 -
setLevel()
:指定要在基本目录内部递归到的级别,默认为 1,即在基本目录内直接。
如果基本目录是/var/www/
,那么
/var/www/file1.html
在级别 1
/var/www/html/file2.html
在级别 2
将级别设置为 0(零)将递归到所有子目录。 -
setFilesToMonitor([])
:接受一个数组,该数组包含表示监视器将监视更改的文件和/或目录的 shell 模式。
当一个文件(或目录)匹配在此处定义的模式时,已创建、修改或删除,则调用该事件定义的处理函数,并传递文件或目录的绝对路径以及监视器对象实例。
可以通过指定以斜杠'/'
结尾的 shell 模式来针对目录,文件模式不以斜杠结尾。
中间不包含斜杠'/'
的模式递归到由setLevel()
定义的级别,因此类似'*.yaml'
的条目将匹配任何扩展名为yaml
的文件,直到定义的级别。
但是 包含中间或开头斜杠的模式被视为绝对形式,并且不是递归的,所以像'*/*.yaml'
这样的条目(与条目'/*/*.yaml'
完全等价)将匹配基目录第2级下的任何扩展名为yaml
的文件,并且它不会在任何其他级别匹配它们(除非列表中的其他条目指示这样做)。
模式不得包含基目录 在从它们的绝对路径中删除基目录后,将检查基目录内部的文件/目录。 -
setFireModifiedOnDirectories()
:默认为 false。设置为 true 以在目录上触发修改事件,这发生在目录属性(mtime、权限)更改时。只有当目录与setFilesToMonitor([])
中指定的模式之一匹配时,才会触发修改事件 (再次,匹配目录的模式是那些以斜杠'/'
结尾的)。
为了在设置此标志时监视基目录本身,模式条目将是空字符串''
,它具有特殊含义:如果fire_modified_on_directories
设置为 on,则匹配基目录。 -
setMonitorCreatedOnly()
:默认为 false。设置为 true 以仅监视 "CREATED" 事件,由 Monitor 本身用于快速等待不存在的基目录。 -
setAutoCreateNotFoundMonitor()
:默认为 false。设置为 true,Monitor 实例将自动为不存在的基目录创建另一个内部 Monitor。通常当 Monitor 运行且基目录在文件系统中不存在时,运行调用将立即返回,并且不会进行任何监视。将此标志设置为true
将创建一个内部 Monitor 对象实例,该实例针对监视父 Monitor 实例的基目录的创建进行了优化。
示例
MonitorConfigurator::factory() ->setBaseDirectory('/tmp') ->setLevel(2) ->setFilesToMonitor([ '*.yaml', # Will monitor and matches files: '/tmp/*.yaml', '/tmp/*/*.yaml' only '/*.xml', # Will monitor and matches files: '/tmp/*.xml' only, '/tmp/*/*.xml' are not # monitored because this pattern starts with a slash and is not recursive. 'config*/', # Will monitor and matches directories: '/tmp/config-yaml/', '/tmp/config*/', '/tmp/*/config*/' # (This only makes scense if setFireModifiedOnDirectories() is set to true) ]));
MonitorConfigurator::factory() ->setBaseDirectory('/etc') ->setLevel(5) ->setFilesToMonitor([ 'nginx/*.conf', # Will monitor and matches files: '/etc/nginx/*.conf', this pattern constains # a slash so not recursive and is at level 2 # In fact with this config level is set internally to 2, since there is no # pattern which will match at levels 3 to 5. ]));
Monitor
的 API 方法
Monitor
的构造函数接受一个 MonitorConfigurator
实例,可选地接受一个外部 React PHP LoopInterface(或 React PHP EventLoop)的实例。如果没有传递外部 EventLoop,将创建一个内部的一个。
必须 运行 循环,并且 Monitor 的 run()
方法将在 EventLoop(外部或内部)上执行 run()
调用。
如果例如两个 Monitor 需要监视两个不同的基目录(每个有不同的模式),则创建一个外部 Loop,将其传递给两个 Monitor
实例,并在初始化后外部触发 run()
。
Monitor 扩展了 EventEmitter
类,并且可以使用 on()
方法设置其实例以侦听事件,可识别的事件是
Monitor::EV_CREATE
Monitor::EV_MODIFY
Monitor::EV_DELETE
每个事件的回调函数将传递事件发生的文件/目录路径以及触发事件的 Monitor
实例。
将带有尾随斜杠的目录传递到回调中。
在 EventLoop 上调用 run()
将会阻塞,因此使用此类的工作进程必须处理它。
-
run()
:将运行事件循环(无论是传递给构造函数的外部一个还是内部创建的一个)。此调用将阻塞。
如果调用run()
并将外部事件循环传递给构造函数,将生成一个类型为user
的警告,以通知调用者外部事件循环是打算由调用者而不是 Monitor 本身调用的。 -
stop()
:通过删除所有已注册的监视来停止 Monitor。 -
stopAll()
:通过删除所有已注册的监视并在事件循环上调用stop()
来停止 Monitor,导致它停止。 -
stopQuick()
:通过快速调用inotify close停止监控。除非在特殊情况下(如POSIX信号处理器内部),否则不建议使用。 -
stopQuickAll()
:与stopQuick()
类似,还会在事件循环中调用stop。
示例
/** * This example will monitor the file upload directory of a web application * for PHP files and automatically delete any PHP file created or uploaded. */ require_once 'vendor/autoload.php'; use Dimsh\React\Filesystem\Monitor\Monitor; use Dimsh\React\Filesystem\Monitor\MonitorConfigurator; $base_dir = '/tmp/uploads'; $monitor_config = MonitorConfigurator::factory() ->setLevel(2) ->setAutoCreateNotFoundMonitor(true)// wait for $base_dir to be created if not exists. ->setFireModifiedOnDirectories(true) ->setFilesToMonitor([ '*.php', // monitor any php file in the uploads directory. '', // since ->setFireModifiedOnDirectories(true) is set, // this entry means that we want to be notified if // the $base_dir has been modified also (permissions). '*/*.swf', // monitor swf files at level 2 only '/stop-if-created/', // monitor this exact directory at level 1, and in our // event handler we will stop the monitor if this // directory is created. ]); try { $monitor_config->setBaseDirectory($base_dir); } catch (\Exception $e) { die("exception thrown: [{$e->getMessage()}]\n"); } $monitor = new Monitor($monitor_config); $monitor ->on(Monitor::EV_CREATE, function ($path, $monitor) use ($base_dir) { /** @var Monitor $monitor */ if ($path === "$base_dir/stop-if-created/") { echo "stopping ... \n"; $monitor->stop(); } if ($monitor->hasTrailingSlash($path)) { // this will just print once for: // "directory created: $base_dir/stop-if-created/" // since we are not monitoring any directory with our set patterns // except one, the stop will occur after all event handlers are fired. echo "directory created: $path\n"; } else { echo "file created: $path\n"; if (strtolower(substr($path, -4)) === '.php') { echo "php files are not allowed to be created in upload directory\n"; @unlink($path); } } }) ->on(Monitor::EV_MODIFY, function ($path, $monitor) use ($base_dir) { if ($base_dir === $path) { echo "base directory modified: $path\n"; } else { echo "modified: $path\n"; } }) ->on(Monitor::EV_DELETE, function ($path, $monitor) { // this will be printed for PHP files which we are deleting on our created handler also. echo "deleted: $path\n"; }); $monitor->run();
注意事项
如果遇到如下PHP警告
PHP警告:在1vendor/mkraemer/react-inotify/src/MKraemer/ReactInotify/Inotify.php中调用inotify_add_watch()时,达到了inotify监视器的用户限制,或者内核未能分配所需资源。
以下命令可以解决问题
$ echo 999999 | sudo tee -a /proc/sys/fs/inotify/max_user_watches && \ echo 999999 | sudo tee -a /proc/sys/fs/inotify/max_queued_events && \ echo 999999 | sudo tee -a /proc/sys/fs/inotify/max_user_instances && \ sudo sysctl -p
但这个警告可能表明您正在使用过多资源设置监视器,这可能意味着配置错误。
许可证
MIT