Определенно, что вы должны использовать, это Inotify это быстрая и простая в настройке, несколько вариантов непосредственно от bash или php посвящать простой node-inotify экземпляр для этой задачи
Но Inotify
не используется в Windows, но вы можете легко написать приложение командной строки с помощью FileSystemWatcher или FindFirstChangeNotification и позвоните по номеру exec
Если вы ищете только PHP solution
, то это довольно сложно, и вам может не хватить производительности, потому что единственный способ - это непрерывное сканирование этой папки
Здесь Простой эксперимент
- Не использовать в производстве
- Не удается управлять большим набором файлов
- Не поддерживает мониторинг файлов
- Поддерживается только NEW, DELETED и MODIFIED
- Не поддерживает рекурсию
Пример
if (php_sapi_name() !== 'cli')
die("CLI ONLY");
date_default_timezone_set("America/Los_Angeles");
$sm = new Monitor(__DIR__ . "/test");
// Add hook when new files are created
$sm->hook(function ($file) {
// Send a mail or log to a file
printf("#EMAIL NEW FILE %s\n", $file);
}, Monitor::NOTIFY_NEW);
// Add hook when files are Modified
$sm->hook(function ($file) {
// Do monthing meaningful like calling curl
printf("#HTTP POST MODIFIED FILE %s\n", $file);
}, Monitor::NOTIFY_MODIFIED);
// Add hook when files are Deleted
$sm->hook(function ($file) {
// Crazy ... Send SMS fast or IVR the Boss that you messed up
printf("#SMS DELETED FILE %s\n", $file);
}, Monitor::NOTIFY_DELETED);
// Start Monitor
$sm->start();
Используемый кэш
// Simpe Cache
// Can be replaced with Memcache
class Cache {
public $f;
function __construct() {
$this->f = fopen("php://temp", "rw+");
}
function get($k) {
rewind($this->f);
return json_decode(stream_get_contents($this->f), true);
}
function set($k, $data) {
fseek($this->f, 0);
fwrite($this->f, json_encode($data));
return $k;
}
function run() {
}
}
Экспериментальный класс
// The Experiment
class Monitor {
private $dir;
private $info;
private $timeout = 1; // sec
private $timeoutStat = 60; // sec
private $cache;
private $current, $stable, $hook = array();
const NOTIFY_NEW = 1;
const NOTIFY_MODIFIED = 2;
const NOTIFY_DELETED = 4;
const NOTIFY_ALL = 7;
function __construct($dir) {
$this->cache = new Cache();
$this->dir = $dir;
$this->info = new SplFileInfo($this->dir);
$this->scan(true);
}
public function start() {
$i = 0;
$this->stable = (array) $this->cache->get(md5($this->dir));
while(true) {
// Clear System Cache at Intervals
if ($i % $this->timeoutStat == 0) {
clearstatcache();
}
$this->scan(false);
if ($this->stable != $this->current) {
$this->cache->set(md5($this->dir), $this->current);
$this->stable = $this->current;
}
sleep($this->timeout);
$i ++;
// printf("Memory Usage : %0.4f \n", memory_get_peak_usage(false) /
// 1024);
}
}
private function scan($new = false) {
$rdi = new FilesystemIterator($this->dir, FilesystemIterator::SKIP_DOTS);
$this->current = array();
foreach($rdi as $file) {
// Skip files that are not redable
if (! $file->isReadable())
return false;
$path = addslashes($file->getRealPath());
$keyHash = md5($path);
$fileHash = $file->isFile() ? md5_file($path) : "#";
$hash["t"] = $file->getMTime();
$hash["h"] = $fileHash;
$hash["f"] = $path;
$this->current[$keyHash] = json_encode($hash);
}
if ($new === false) {
$this->process();
}
}
public function hook(Callable $call, $type = Monitor::NOTIFY_ALL) {
$this->hook[$type][] = $call;
}
private function process() {
if (isset($this->hook[self::NOTIFY_NEW])) {
$diff = array_flip(array_diff(array_keys($this->current), array_keys($this->stable)));
$this->notify(array_intersect_key($this->current, $diff), self::NOTIFY_NEW);
unset($diff);
}
if (isset($this->hook[self::NOTIFY_DELETED])) {
$deleted = array_flip(array_diff(array_keys($this->stable), array_keys($this->current)));
$this->notify(array_intersect_key($this->stable, $deleted), self::NOTIFY_DELETED);
}
if (isset($this->hook[self::NOTIFY_MODIFIED])) {
$this->notify(array_diff_assoc(array_intersect_key($this->stable, $this->current), array_intersect_key($this->current, $this->stable)), self::NOTIFY_MODIFIED);
}
}
private function notify(array $files, $type) {
if (empty($files))
return;
foreach($this->hook as $t => $hooks) {
if ($t & $type) {
foreach($hooks as $hook) {
foreach($files as $file) {
$info = json_decode($file, true);
$hook($info['f'], $type);
}
}
}
}
}
}