+
80
-

php如何实时监听目录有新文件变化?

php

请问php如何实时监听目录有新文件变化?

网友回复

+
1
-

第一种不需要安装东西直接通过while循环对比目录下文件夹的md5值是否有变动,代码如下:

<?php

 
class FileWatch
{
 
    protected $all = array();
 
    public function __construct($dir)
    {
      
        $this->watch($dir);
    }
 
    //子类中重写这个方法
    public function run($file)
    {
    }
 
    protected function all_file($dir)
    {
        if (is_file($dir)) {
            $this->all[$dir] = md5_file($dir);
            return $this->all;
        }
        if (is_dir($dir)) {
            $open = opendir($dir);
            while (($file = readdir($open)) !== false) {
                if ($file != "." && $file != "..") {
                    $f = $dir . "/" . $file;
                    if (is_file($f)) {
                        $this->all[$f] = md5_file($f);
                    } elseif (is_dir($f)) {
                        $this->all_file($f);
                    }
 
                }
            }
        }
        return $this->all;
    }
 
    public function watch($dir)
    {
        $this->all = array();
        $old = $this->all_file($dir);
        while (true) {
            sleep(2);
          
            $this->all = array();
            $new = $this->all_file($dir);
            $re = array_diff($new, $old);
            $del = array_diff_key($old, $new);
            $re = array_merge($re, $del);
            if ($re) {
                $this->all = array();
                $old = $this->all_file($dir);
                $file = array_keys($re);
                $this->run($file[0]);
            }
        }
    }
}//endclass
//使用方法
class mywatch extends FileWatch
{
  
    public function run($file)
    {
        
     
        if(!empty($file)) {
            echo "new file or file has been changed with ".$file.PHP_EOL;
           
 
          
        } else {
            echo "no files has created and no files has been changed".PHP_EOL;
        }
    }
}
echo 'Your System is '.PHP_OS.PHP_EOL;
echo "Welcome to use fileWatch System".PHP_EOL;
$watch = new mywatch("/data/wwwroot/default/Data/");

第二种是通过inotify扩展监控文件或目录的变化,参考了https://www.cnblogs.com/jkko123/p/10861236.html

1、下载inotify扩展源码,安装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();

//设置为非阻塞模式
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);

我知道答案,我要回答