php使用inotify擴展監控文件或目錄,若是發生改變,就執行指定命令

經過inotify擴展監控文件或目錄的變化,若是發生變化,就執行命令。php

能夠應用於 swoole 中,若是文件發生變化,就執行 kill -USR1 進程PID 來實現熱更新。shell

<?php
class Monitor
{
    public $dir = '';
    public $cmd = '';
    public $timeout = 1;

    public function __construct()
    {
        if (!extension_loaded('inotify')) {
            echo '請安裝inotify擴展', PHP_EOL;
            exit;
        }
        //解析命令行參數,有一個:號表示必填項
        $opts = getopt('', ['dir:', 'cmd:']);
        if (!$opts) {
            echo '參數輸入錯誤', PHP_EOL;
            exit;
        }
        if (empty($opts['dir'])) {
            echo '--dir 是必填項', PHP_EOL;
            exit;
        }
        if (empty($opts['cmd'])) {
            echo '--cmd 是必填項', PHP_EOL;
            exit;
        }
        $this->dir = $opts['dir'];
        $this->cmd = trim($opts['cmd']);
        $this->run();
    }

    //對目錄進行監控
    public function run()
    {
        $dirs = $this->getDirs($this->dir);
        if (empty($dirs)) {
            return false;
        }
        $fd = inotify_init();
        //設置爲非阻塞模式
        stream_set_blocking($fd, 0);
        foreach ($dirs as $dir) {
            $watch = inotify_add_watch($fd, $dir, IN_MODIFY | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_CLOSE_WRITE);
            if (!$watch) {
                echo "{$dir} 添加監控錯誤", PHP_EOL;
                exit;
            }
        }
        while (true) {
            $reads = [$fd];
            $write = [];
            $except = [];
            if (stream_select($reads, $write, $except, $this->timeout) > 0) {
                if (!empty($reads)) {
                    foreach ($reads as $read) {
                        //文件改變
                        $fileChg = false;
                        //目錄改變
                        $dirChg = false;
                        //從可讀流中讀取數據
                        $events = inotify_read($read);
                        $fileName = '';
                        foreach ($events as $event) {
                            $fileName = $event['name'];
                            switch ($event['mask']) {
                                case IN_CREATE:
                                case IN_DELETE:
                                    $fileChg = true;
                                    break;
                                case 1073742080:
                                case 1073742336:
                                    $dirChg = true;
                                    break;
                            }
                        }
                        if ($fileChg) {
                            echo "文件 {$fileName} 發生改變, 執行命令 {$this->cmd}", PHP_EOL;
                            echo shell_exec($this->cmd), PHP_EOL;
                        }
                        if ($dirChg) {
                            echo "目錄 {$fileName} 發生改變, 執行命令 {$this->cmd}", PHP_EOL;
                            echo shell_exec($this->cmd), PHP_EOL;
                            return $this->run();
                        }
                    }
                }
            }
        }
        return true;
    }

    //遞歸的獲取當前目錄下全部子目錄路徑
    public function getDirs($dir)
    {
        $dir = realpath($dir);
        $dh = opendir($dir);
        if (!$dh) {
            return [];
        }
        $dirs = [];
        $dirs[] = $dir;
        while (($file = readdir($dh)) !== false) {
            if ($file == '.' || $file == '..') {
                continue;
            }
            $full = $dir . DIRECTORY_SEPARATOR . $file;
            if (is_dir($full)) {
                $dirs = array_merge($dirs, $this->getDirs($full));
            }
        }
        closedir($dh);
        return $dirs;
    }
}

(new Monitor());

演示以下所示:swoole

相關文章
相關標籤/搜索