Как проверить, изменилось ли содержимое каталога с помощью PHP?

Я пишу сценарий фотогалереи в PHP и имею единственный каталог, где пользователь будет хранить свои фотографии. Я пытаюсь настроить кеширование страниц и обновлять кеш, только если содержимое каталога изменилось. Я думал, что могу сделать это, кэшируя последнее измененное время в каталоге с помощью функции filemtime () и сравнивая его с текущим измененным временем каталога. Однако, как я понял, измененное время каталога не меняется, поскольку файлы добавляются или удаляются из этого каталога (по крайней мере, в Windows, но не уверен в машинах Linux).

Итак, мои вопросы: какой самый простой способ проверить, было ли изменено содержимое каталога?

Solutions Collecting From Web of "Как проверить, изменилось ли содержимое каталога с помощью PHP?"

Э-э. Я бы просто сохранил md5 в списке каталогов. Если содержимое изменится, изменится md5 (каталог-листинг). Вы можете получить очень случайное столкновение md5, но я думаю, что этот шанс достаточно крошечный.
Кроме того, вы можете сохранить небольшой файл в этом каталоге, который содержит дату последнего изменения. Но я бы пошел с md5.


PS. на второй взгляд, видя, как вы смотрите на производительность (кэширование), запрашивая и хешируя список каталогов, может оказаться не совсем оптимальным.

Как уже упоминалось другими, лучший способ решить эту задачу – вызвать функцию, когда происходят определенные события, которые меняют папку. Однако, если ваш сервер является unix, вы можете использовать inotifywait для просмотра каталога, а затем вызвать скрипт PHP.

Вот простой пример:

 #!/bin/sh inotifywait --recursive --monitor --quiet --event modify,create,delete,move --format '%f' /path/to/directory/to/watch | while read FILE ; do php /path/to/trigger.php $FILE done 

См. Также: http://linux.die.net/man/1/inotifywait

Как насчет касания каталога после того, как пользователь отправил его изображение? Changelog говорит: Требуется php 5.3 для работы окон, но я думаю, что он должен работать во всех других средах

с inotifywait внутри php

 $watchedDir = 'watch'; $in = popen("inotifywait --monitor --quiet --format '%e %f' --event create,moved_to '$watchedDir'", 'r'); if ($in === false) throw new Exception ('fail start notify'); while (($line = fgets($in)) !== false) { list($event, $file) = explode(' ', rtrim($line, PHP_EOL), 2); echo "$event $file\n"; } 

Вот что вы можете попробовать. Храните все изображения в одном каталоге (или в подкаталогах /username внутри него, чтобы ускорить работу и уменьшить нагрузку на FS), и настройте Apache (или whaterver, который вы используете), чтобы служить им как статический контент с «expires- на "100 лет в будущем. Имена файлов должны содержать некоторый уникальный префикс или суффикс (отметка времени, SHA1 хэш содержимого файла и т. Д.), Поэтому всякий раз, когда использует изменения, имя файла изменяется, а Apache будет обслуживать новую версию, которая будет кэшироваться по пути.

Вы ошибаетесь.

Вы должны выполнить свой скрипт индексатора каталога, как только кто-то загрузит новый файл и переместится в целевое местоположение.

Ответ IMO edubem – это путь, но вы можете сделать что-то вроде этого:

 if (sha1(serialize(Map('/path/to/directory/', true))) != /* previous stored hash */) { // directory contents has changed } 

Или более слабая / быстрая версия:

 if (Size('/path/to/directory/', true) != /* previous stored size */) { // directory contents has changed } 

Вот используемые функции:

 function Map($path, $recursive = false) { $result = array(); if (is_dir($path) === true) { $path = Path($path); $files = array_diff(scandir($path), array('.', '..')); foreach ($files as $file) { if (is_dir($path . $file) === true) { $result[$file] = ($recursive === true) ? Map($path . $file, $recursive) : $this->Size($path . $file, true); } else if (is_file($path . $file) === true) { $result[$file] = Size($path . $file); } } } else if (is_file($path) === true) { $result[basename($path)] = Size($path); } return $result; } function Size($path, $recursive = true) { $result = 0; if (is_dir($path) === true) { $path = Path($path); $files = array_diff(scandir($path), array('.', '..')); foreach ($files as $file) { if (is_dir($path . $file) === true) { $result += ($recursive === true) ? Size($path . $file, $recursive) : 0; } else if (is_file() === true) { $result += sprintf('%u', filesize($path . $file)); } } } else if (is_file($path) === true) { $result += sprintf('%u', filesize($path)); } return $result; } function Path($path) { if (file_exists($path) === true) { $path = rtrim(str_replace('\\', '/', realpath($path)), '/'); if (is_dir($path) === true) { $path .= '/'; } return $path; } return false; } 

Попробуйте удалить кешированную версию, когда пользователь загрузит файл в свой каталог.

Когда кто-то пытается просмотреть галерею, посмотрите, есть ли сначала кешированная версия. Если есть кешированная версия, загрузите ее, в противном случае создайте страницу, выполните кеширование, сделайте.

Я искал что-то подобное, и я просто нашел это:

http://www.franzone.com/2008/06/05/php-script-to-monitor-ftp-directory-changes/

Для меня выглядит отличное решение, так как у меня будет большой контроль (я буду делать вызов AJAX, чтобы увидеть, что-то изменилось).

Надеюсь, что это поможет.

Вот пример кода, который вернет 0, если каталог был изменен. Я использую его в резервных копиях.

Измененный статус определяется наличием файлов и их файлов. Вы можете легко изменить это, чтобы сравнить содержимое файла, заменив

 $longString .= filesize($file); 

с

 $longString .= crc32(file_get_contents($file)); 

но это повлияет на скорость выполнения.

 #!/usr/bin/php <?php $dirName = $argv[1]; $basePath = '/var/www/vhosts/majestichorseporn.com/web/'; $dataFile = './backup_dir_if_changed.dat'; # startup checks if (!is_writable($dataFile)) die($dataFile . ' is not writable!'); if (!is_dir($basePath . $dirName)) die($basePath . $dirName . ' is not a directory'); $dataFileContent = file_get_contents($dataFile); $data = @unserialize($dataFileContent); if ($data === false) $data = array(); # find all files ang concatenate their sizes to calculate crc32 $files = glob($basePath . $dirName . '/*', GLOB_BRACE); $longString = ''; foreach ($files as $file) { $longString .= filesize($file); } $longStringHash = crc32($longString); # do changed check if (isset ($data[$dirName]) && $data[$dirName] == $longStringHash) die('Directory did not change.'); # save hash do DB $data[$dirName] = $longStringHash; file_put_contents($dataFile, serialize($data)); die('0');