/** * Add a path to the watcher * * @param string $path * @param int $mode * @param bool $recursive */ public function addPath($path, $mode = IN_MODIFY, $recursive = true) { TypeCheck::doCheck(DataType::STRING, DataType::INT, DataType::BOOLEAN); if ($this->isExcluded($path)) { return; } if (is_dir($path) && $recursive) { $children = scandir($path); foreach ($children as $child) { if ($child != '.' && $child != '..' && $child != '.git' && is_dir($path . DIRECTORY_SEPARATOR . $child)) { $this->addPath($path . DIRECTORY_SEPARATOR . $child, $mode, $recursive); } } } $watchDescriptor = inotify_add_watch($this->inotifyStreamDescriptor, $path, $mode); $this->watchDescriptors[$watchDescriptor] = $path; }
public function start() { $this->stop = false; $fd = inotify_init(); $wd = inotify_add_watch($fd, $this->path, IN_ALL_EVENTS); $read = [$fd]; $write = null; $except = null; stream_select($read, $write, $except, 0); stream_set_blocking($fd, 0); while (true) { if ($this->stop) { inotify_rm_watch($fd, $wd); return fclose($fd); } if ($events = inotify_read($fd)) { foreach ($events as $details) { if ($details['name']) { $target = rtrim($this->path, '/') . '/' . $details['name']; } else { $target = $this->path; } $file = new \SplFileInfo($target); switch (true) { case $details['mask'] & IN_MODIFY: $this->modify($file); break; } $this->all($file); } } } }
function watchADir($path) { $this->dirs[$path] = $path; $this->ifds[$path] = inotify_init(); $this->wds[$path] = inotify_add_watch($this->ifds[$path], $path, self::DIR_MASK); $this->log("add dir {$path} " . print_r($this->dirs, 1) . print_r($this->wds, 1)); }
function tail($file, &$pos) { // get the size of the file if (!$pos) { $pos = filesize($file); } // Open an inotify instance $fd = inotify_init(); // Watch $file for changes. $watch_descriptor = inotify_add_watch($fd, $file, IN_ALL_EVENTS); // Loop forever (breaks are below) while (true) { // Read events (inotify_read is blocking!) $events = inotify_read($fd); // Loop though the events which occured foreach ($events as $event => $evdetails) { // React on the event type switch (true) { // File was modified case $evdetails['mask'] & IN_MODIFY: // Stop watching $file for changes inotify_rm_watch($fd, $watch_descriptor); // Close the inotify instance fclose($fd); // open the file $fp = fopen($file, 'r'); if (!$fp) { return false; } // seek to the last EOF position fseek($fp, $pos); // read until EOF while (!feof($fp)) { $buf .= fread($fp, 8192); } // save the new EOF to $pos $pos = ftell($fp); // (remember: $pos is called by reference) // close the file pointer fclose($fp); // return the new data and leave the function return $buf; break; // File was moved or deleted // File was moved or deleted case $evdetails['mask'] & IN_MOVE: case $evdetails['mask'] & IN_MOVE_SELF: case $evdetails['mask'] & IN_DELETE: case $evdetails['mask'] & IN_DELETE_SELF: // Stop watching $file for changes inotify_rm_watch($fd, $watch_descriptor); // Close the inotify instance fclose($fd); // Return a failure return false; break; } } } }
/** * @param array $directories * @param \Closure|null $callback * @return Watcher * @throws \RuntimeException */ public function watch(array $directories, \Closure $callback = null) { foreach ($directories as $directory) { if (!is_dir($directory)) { $this->clearWatch(); throw new \RuntimeException("[{$directory}] is not a directory."); } $wd = inotify_add_watch($this->inotify, $directory, $this->events); $this->watchDir[$directory] = $wd; } $this->callback = $callback; // Listen modify. \swoole_event_add($this->inotify, function () use($callback) { $events = inotify_read($this->inotify); if (!$events) { return; } foreach ($events as $event) { if (!empty($event['name'])) { echo sprintf("[%s]\t" . sprintf('["%s"] modify', $event['name']) . PHP_EOL, date('Y-m-d H:i:s')); } } if (is_callable($callback)) { $callback($this); } }); return $this; }
/** * Simple tail program using the inotify extension * Usage: ./tail.php file */ function main_loop($file, $file_fd) { $inotify = inotify_init(); if ($inotify === false) { fprintf(STDERR, "Failed to obtain an inotify instance\n"); return 1; } $watch = inotify_add_watch($inotify, $file, IN_MODIFY); if ($watch === false) { fprintf(STDERR, "Failed to watch file '%s'", $file); return 1; } while (($events = inotify_read($inotify)) !== false) { echo "Event received !\n"; foreach ($events as $event) { if (!($event['mask'] & IN_MODIFY)) { continue; } echo stream_get_contents($file_fd); break; } } // May not happen inotify_rm_watch($inotify, $watch); fclose($inotify); fclose($file_fd); return 0; }
/** * Adds your subscription on object in FS * @param string $path Path * @param mixed $cb Callback * @param integer $flags Look inotify_add_watch() * @return true */ public function addWatch($path, $cb, $flags = null) { $path = realpath($path); if (!isset($this->files[$path])) { $this->files[$path] = []; if ($this->inotify) { $this->descriptors[inotify_add_watch($this->inotify, $path, $flags ?: IN_MODIFY)] = $path; } } $this->files[$path][] = $cb; Timer::setTimeout('fileWatcher'); return true; }
/** * Adds a path to the list of watched paths * * @param string $path Path to the watched file or directory * @param integer $mask Bitmask of inotify constants * @return integer unique watch identifier, can be used to remove() watch later */ public function add($path, $mask) { if ($this->inotifyHandler === false) { // inotifyHandler not started yet => start a new one $this->inotifyHandler = \inotify_init(); stream_set_blocking($this->inotifyHandler, 0); // wait for any file events by reading from inotify handler asynchronously $this->loop->addReadStream($this->inotifyHandler, $this); } $descriptor = \inotify_add_watch($this->inotifyHandler, $path, $mask); $this->watchDescriptors[$descriptor] = array('path' => $path); return $descriptor; }
public function addWatch($path, $subscriber, $flags = NULL) { $path = realpath($path); if (!isset($this->files[$path])) { $this->files[$path] = array(); if ($this->inotify) { $this->descriptors[inotify_add_watch($this->inotify, $path, $flags ?: IN_MODIFY)] = $path; } } $this->files[$path][] = $subscriber; Daemon_TimedEvent::setTimeout('fileWatcherTimedEvent'); return true; }
public function watch(TrackedObject $tracked) { $path = realpath($tracked->getResource()); if ($tracked->getResource() instanceof FileResource) { return; } if (!$path) { return; } $id = inotify_add_watch($this->inotify, $path, $this->inotifyEventMask); $this->inotifyMap[$id] = $tracked; return parent::watch($tracked); }
protected function addWatches($in, Path $path, &$watches) { if (!$path->isDir()) { // not in a directory, bail return; } $wd = inotify_add_watch($in, $path->getPathname(), $this->computedMask); $watches[$wd] = $path; printf("\rAdding watches... %d", count($watches)); // recurse into this directory's children $children = $path->getChildren(); foreach ($children as $child) { if ($child->isDir()) { $this->addWatches($in, $child, $watches); } } }
/** * Adds the path to the list of files and folders to monitor for changes. * If the path is a file, its modification time is stored for comparison. * If a directory, the modification times for each sub-directory and file * are recursively stored. * * @param string $path A valid path to a file or directory */ public function watchPath($path) { if (!$this->inotify) { $this->paths[] = $path; $this->addModifiedTimes($path); return; } $mask = IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | IN_MOVE | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF; $directoryIterator = new \RecursiveDirectoryIterator(realpath($path)); $subPaths = new \RecursiveIteratorIterator($directoryIterator); // Iterate over instances of \SplFileObject foreach ($subpaths as $subPath) { if ($subPath->isDir()) { $watchDescriptor = inotify_add_watch($this->inotify, $subPath->getRealPath(), $mask); $this->paths[$watchDescriptor] = $subPath->getRealPath(); } } }
function check_files_change($inotify_fd) { global $monitor_files; // 读取有哪些文件事件 $events = inotify_read($inotify_fd); if ($events) { // 检查哪些文件被更新了 foreach ($events as $ev) { // 更新的文件 $file = $monitor_files[$ev['wd']]; echo $file . " update and reload\n"; unset($monitor_files[$ev['wd']]); // 需要把文件重新加入监控 $wd = inotify_add_watch($inotify_fd, $file, IN_MODIFY); $monitor_files[$wd] = $file; } // 给父进程也就是主进程发送reload信号 posix_kill(posix_getppid(), SIGUSR1); } }
/** * Watch resource * * @return int */ protected function addWatch() { return inotify_add_watch($this->getBag()->getInotify(), $this->getResource()->getResource(), $this->getInotifyEventMask()); }
<?php // Open an inotify instance $fd = inotify_init(); // Watch __FILE__ for metadata changes (e.g. mtime) $watch_descriptor = inotify_add_watch($fd, __FILE__, IN_ATTRIB); // generate an event touch(__FILE__); // Read events $events = inotify_read($fd); print_r($events); // The following methods allows to use inotify functions without blocking on inotify_read(): // - Using stream_select() on $fd: $read = array($fd); $write = null; $except = null; stream_select($read, $write, $except, 0); // - Using stream_set_blocking() on $fd stream_set_blocking($fd, 0); inotify_read($fd); // Does no block, and return false if no events are pending // - Using inotify_queue_len() to check if event queue is not empty $queue_len = inotify_queue_len($fd); // If > 0, inotify_read() will not block // Stop watching __FILE__ for metadata changes inotify_rm_watch($fd, $watch_descriptor); // Close the inotify instance // This may have closed all watches if this was not already done fclose($fd);
public function add($path, $mode) { return inotify_add_watch($this->inotify, $path, $mode); }
/** * 增加需要监控的文件 * @param string $file */ public static function addFile($file) { $wd = inotify_add_watch(self::$inotifyFd, $file, IN_MODIFY); self::$inotifyWatchFds[$wd] = $file; }
public function createInotifyWatches($inotify) { $paths = array(); $watches = array(); foreach ($this->tasks as $taskPaths) { foreach ($taskPaths as $path) { $path = realpath($path); if (!in_array($path, $paths)) { $paths[] = $path; } } } foreach ($paths as $path) { /** @noinspection PhpUndefinedFunctionInspection */ /** @noinspection PhpUndefinedConstantInspection */ $watch = inotify_add_watch($inotify, $path, IN_CREATE | IN_MODIFY | IN_CLOSE_WRITE | IN_ATTRIB); if (!isset($this->pathsByWatch[$watch])) { $this->pathsByWatch[$watch] = array(); } $this->pathsByWatch[$watch][] = $path; $watches[] = $watch; } return $watches; }
#!/usr/bin/env php <?php // http://php.net/manual/zh/function.inotify-init.php // 使用php 的inotify 扩展实时监控系统文件或目录的变动 $fd = inotify_init(); $wd = inotify_add_watch($fd, __FILE__, IN_ALL_EVENTS); // 读取事件 $events = inotify_read($fd); var_dump($events);
echo "data: {$data}\n"; echo "\n"; ob_flush(); flush(); } else { if (filesize($file) < $pos) { echo "event: clear\n"; echo "data: \n"; echo "\n"; ob_flush(); flush(); $pos = 0; break; } } $watch = inotify_add_watch($fd, $file, IN_ALL_EVENTS); flock($fp, LOCK_UN); fclose($fp); while (true) { $events = inotify_read($fd); foreach ($events as $event => $details) { if ($details["mask"] & IN_CLOSE_WRITE) { $fp = fopen($file, "r"); flock($fp, LOCK_SH); fseek($fp, $pos); $data = ""; while (!feof($fp)) { $data .= fread($fp, 8192); } $pos = ftell($fp); flock($fp, LOCK_UN);
}); }); $server->on('Message', function (swoole_websocket_server $server, $frame) { echo "message: " . $frame->data; $result = json_decode($frame->data, true); $filename = $result['filename']; //以文件名作为数组的值,Key是fd $filename = __DIR__ . '/' . $filename; if (!is_file($filename)) { $server->push($frame->fd, "file[{$filename}] is not exist.\n"); return; } //还没有创建inotify句柄 if (empty(G::$files[$filename]['inotify_fd'])) { //添加监听 $wd = inotify_add_watch(G::$inotify, $filename, IN_MODIFY); $fp = fopen($filename, 'r'); clearstatcache(); $filesizelatest = filesize($filename); fseek($fp, $filesizelatest); G::$watchList[$wd] = $filename; G::$files[$filename]['inotify_fd'] = $wd; G::$files[$filename]['fp'] = $fp; } //清理掉其他文件的监听 if (!empty(G::$users[$frame->fd]['watch_file'])) { $oldfile = G::$users[$frame->fd]['watch_file']; $k = array_search($frame->fd, G::$files[$oldfile]['users']); unset(G::$files[$oldfile]['users'][$k]); } //用户监听的文件
<?php /** * Created by PhpStorm. * User: USER * Date: 28/5/2015 * Time: 9:20 */ echo 'inotify is not for window'; echo 'http://grokbase.com/t/php/pecl-dev/12884jyyf2/php-extension-inotify'; $wd_constants = array(1 => array('IN_ACCESS', 'File was accessed (read)'), 2 => array('IN_MODIFY', 'File was modified'), 4 => array('IN_ATTRIB', 'Metadata changed (e.g. permissions, mtime, etc.)'), 8 => array('IN_CLOSE_WRITE', 'File opened for writing was closed'), 16 => array('IN_CLOSE_NOWRITE', 'File not opened for writing was closed'), 32 => array('IN_OPEN', 'File was opened'), 128 => array('IN_MOVED_TO', 'File moved into watched directory'), 64 => array('IN_MOVED_FROM', 'File moved out of watched directory'), 256 => array('IN_CREATE', 'File or directory created in watched directory'), 512 => array('IN_DELETE', 'File or directory deleted in watched directory'), 1024 => array('IN_DELETE_SELF', 'Watched file or directory was deleted'), 2048 => array('IN_MOVE_SELF', 'Watch file or directory was moved'), 24 => array('IN_CLOSE', 'Equals to IN_CLOSE_WRITE | IN_CLOSE_NOWRITE'), 192 => array('IN_MOVE', 'Equals to IN_MOVED_FROM | IN_MOVED_TO'), 4095 => array('IN_ALL_EVENTS', 'Bitmask of all the above constants'), 8192 => array('IN_UNMOUNT', 'File system containing watched object was unmounted'), 16384 => array('IN_Q_OVERFLOW', 'Event queue overflowed (wd is -1 for this event)'), 32768 => array('IN_IGNORED', 'Watch was removed (explicitly by inotify_rm_watch() or because file was removed or filesystem unmounted'), 1073741824 => array('IN_ISDIR', 'Subject of this event is a directory'), 1073741840 => array('IN_CLOSE_NOWRITE', 'High-bit: File not opened for writing was closed'), 1073741856 => array('IN_OPEN', 'High-bit: File was opened'), 1073742080 => array('IN_CREATE', 'High-bit: File or directory created in watched directory'), 1073742336 => array('IN_DELETE', 'High-bit: File or directory deleted in watched directory'), 16777216 => array('IN_ONLYDIR', 'Only watch pathname if it is a directory (Since Linux 2.6.15)'), 33554432 => array('IN_DONT_FOLLOW', 'Do not dereference pathname if it is a symlink (Since Linux 2.6.15)'), 536870912 => array('IN_MASK_ADD', 'Add events to watch mask for this pathname if it already exists (instead of replacing mask).'), 2147483648.0 => array('IN_ONESHOT', 'Monitor pathname for one event, then remove from watch list.')); $path = $argv[1]; $fd = inotify_init(); stream_set_blocking($fd, 0); $watch_descriptor = inotify_add_watch($fd, $path, IN_ALL_EVENTS); $poll = 0; while (true) { $ecount = 0; $fcount = 0; // Poll for queued events, generated meanwhile // Because while (true) { } has some seriously bad mojo sleep(5); $poll++; $events = inotify_read($fd); if ($events) { $ecount = count($events); } echo "=== " . date("Y-m-d H:i:s") . " inotify poll #{$poll} contains " . $ecount . " events"; if ($events) { echo ":"; }
/** * @param $dir * @param bool $root * @return bool * @throws NotFound */ function watch($dir, $root = true) { //目录不存在 if (!is_dir($dir)) { throw new NotFound("[{$dir}] is not a directory."); } //避免重复监听 if (isset($this->watchFiles[$dir])) { return false; } //根目录 if ($root) { $this->rootDirs[] = $dir; } $wd = inotify_add_watch($this->inotify, $dir, $this->events); $this->watchFiles[$dir] = $wd; $files = scandir($dir); foreach ($files as $f) { if ($f == '.' or $f == '..') { continue; } $path = $dir . '/' . $f; //递归目录 if (is_dir($path)) { $this->watch($path, false); } //检测文件类型 $fileType = strstr($f, '.'); if (isset($this->reloadFileTypes[$fileType])) { $wd = inotify_add_watch($this->inotify, $path, $this->events); $this->watchFiles[$path] = $wd; } } return true; }
<?php //创建一个inotify句柄 $fd = inotify_init(); //监听文件,仅监听修改操作,如果想要监听所有事件可以使用IN_ALL_EVENTS $watch_descriptor = inotify_add_watch($fd, __DIR__ . '/inotify.data', IN_MODIFY); swoole_event_add($fd, function ($fd) { $events = inotify_read($fd); if ($events) { foreach ($events as $event) { echo "inotify Event :" . var_export($event, 1) . "\n"; } } });
<?php $fd = inotify_init(); // modify表示写入内容,access表示读取内容,attribute表示meta信息修改(例如 user:group, 创建日期) $watch_descriptor = inotify_add_watch($fd, __DIR__, IN_MODIFY | IN_ACCESS | IN_ATTRIB); swoole_event_add($fd, function ($fd) { $events = inotify_read($fd); if ($events) { foreach ($events as $event) { echo "inotify Event :" . var_dump($event) . "\n"; } } });
private function _addWatch($path) { $wd = inotify_add_watch($this->_fd, $path, IN_MODIFY | IN_ATTRIB | IN_MOVE | IN_CREATE | IN_DELETE | IN_DONT_FOLLOW); $this->_watches[$wd] = $path; }
protected function addWatches(Package $rootPackage, Package $package, &$mapping, &$watches, $inotify, OutputInterface $output) { if ($package->getExtends()) { $this->addWatches($rootPackage, $this->packages[$package->getExtends()], $mapping, $watches, $inotify, $output); } foreach (array_merge($package->getFiles(), $package->getWatches()) as $file) { if ($file instanceof PackageFile) { $this->addWatches($rootPackage, $this->packages[$file->getPackageName()], $mapping, $watches, $inotify, $output); } else { if ($file instanceof LocalFile) { $pathname = $file->getPathname(); if (isset($mapping[$pathname])) { if ($output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL) { $output->writeln(sprintf(' + watch <comment>%s</comment>', $pathname)); } $mapping[$pathname][] = $rootPackage; } else { if ($output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL) { $output->writeln(sprintf(' + watch <comment>%s</comment>', $pathname)); } $watchDescriptor = inotify_add_watch($inotify, $pathname, IN_CLOSE_WRITE); $mapping[$pathname] = [$rootPackage]; $watches[$watchDescriptor] = $pathname; } } } } }
/** * 监控日志文件 * * @param array $logPaths * @return void * @throws ZtChart_Model_Monitor_Exception */ public function tail($logPaths) { if (($inotify = inotify_init()) === false) { throw new ZtChart_Model_Monitor_Daemon_Exception('Failed to obtain an inotify instance.'); } $watchFiles = $watchDirs = array(); foreach ($logPaths as $file) { if (($watch = inotify_add_watch($inotify, $file, IN_CREATE | IN_MODIFY)) === false) { throw new ZtChart_Model_Monitor_Daemon_Exception("Failed to watch file '{$file}'."); } if (is_file($file)) { if (false === ($fd = fopen($file, "r"))) { throw new ZtChart_Model_Monitor_Daemon_Exception("File '{$file}' is not readable."); } $this->_ffseek($fd); $watchFiles[$watch] = $fd; } else { if (is_dir($file)) { $watchFiles[$watch] = array(); $watchDirs[$watch] = $file; } } } while (($events = inotify_read($inotify)) !== false) { foreach ($events as $event) { if ($event['mask'] & IN_Q_OVERFLOW) { throw new ZtChart_Model_Monitor_Daemon_Exception("The number of inotify queued events reaches upper limit."); } if (!$this->accept($event['name'])) { continue; } if ($event['mask'] & (IN_CREATE | IN_MODIFY)) { if (!($event['mask'] & IN_ISDIR)) { if (!array_key_exists($event['name'], $watchFiles[$event['wd']])) { $fn = $fd = null; foreach ($watchFiles[$event['wd']] as $wfn => $wfd) { if (strncasecmp($wfn, $event['name'], strpos($wfn, '.')) == 0) { $fn = $wfn; $fd = $wfd; break; } } // 判断当前创建或修改的日志文件是否最新 if (strcasecmp($fn, $event['name']) < 0) { if (is_resource($fd) && fclose($fd)) { unset($watchFiles[$event['wd']][$fn]); } $filename = $watchDirs[$event['wd']] . DIRECTORY_SEPARATOR . $event['name']; if (false === ($fd = fopen($filename, "r"))) { $this->_logger->err("File '{$filename}' is not readable\n"); continue; } if ($event['mask'] & IN_MODIFY) { $this->_ffseek($fd); } $watchFiles[$event['wd']][$event['name']] = $fd; } else { // 如果不是最新的日志文件(重写的上一个小时的日志文件),则不处理。 continue; } } else { $fd = $watchFiles[$event['wd']][$event['name']]; } } else { continue; // $fd = $watchFiles[$event['wd']]; } // 读取日志并分析 $raw = ''; $lines = 0; while (true) { $raw .= $block = fread($fd, 4096); if (false !== ($pos = strpos($raw, "\n"))) { $rawline = substr($raw, 0, $pos + 1); try { $mlog = new ZtChart_Model_Monitor_Log($rawline); $line = $mlog->transform(); if (!empty($line)) { $this->_shmWrite($mlog->getShmIdentifier(), $line); $lines++; } } catch (ZtChart_Model_Monitor_Log_Exception $e) { $this->_logger->warn("日志处理错误:" . iconv('GBK', 'UTF-8', $rawline)); } $raw = substr($raw, $pos + 1); } else { if (($offset = strlen($block)) > 0) { fseek($fd, -$offset, SEEK_CUR); } break; } } if (0 != $lines) { $this->_logger->info(sprintf("%4s行有效数据已处理:%s", $lines, $watchDirs[$event['wd']] . '/' . $event['name'])); } } } } foreach ($watchFiles as $watch => $fd) { if (is_resource($fd)) { $fd = (array) $fd; } array_walk($fd, 'fclose'); inotify_rm_watch($inotify, $watch); } fclose($inotify); }
<?php // Open an inotify instance $fd = inotify_init(); // Watch __FILE__ for metadata changes (e.g. mtime) $watch_descriptor = inotify_add_watch($fd, __DIR__ . '/php', IN_MODIFY | IN_MOVED_FROM | IN_CREATE | IN_DELETE | IN_ISDIR); while (true) { // Read events $events = inotify_read($fd); print_r($events); }
public function init() { $this->ifd = inotify_init(); $this->wd = inotify_add_watch($this->ifd, $this->path, self::MASK); }