如何检查目录内容是否已使用 PHP 更改?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/540339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to check if directory contents has changed with PHP?
提问by PHLAK
I'm writing a photo gallery script in PHP and have a single directory where the user will store their pictures. I'm attempting to set up page caching and have the cache refresh only if the contents of the directory has changed. I thought I could do this by caching the last modified time of the directory using the filemtime() function and compare it to the current modified time of the directory. However, as I've come to realize, the directory modified time does not change as files are added or removed from that directory (at least on Windows, not sure about Linux machines yet).
我正在用 PHP 编写一个照片库脚本,并且有一个目录,用户将在其中存储他们的图片。我正在尝试设置页面缓存并仅在目录内容发生更改时才刷新缓存。我想我可以通过使用 filemtime() 函数缓存目录的最后修改时间并将其与目录的当前修改时间进行比较来做到这一点。但是,正如我逐渐意识到的那样,目录修改时间不会随着文件的添加或从该目录中删除而改变(至少在 Windows 上,还不确定 Linux 机器)。
So my questions is, what is the simplest way to check if the contents of a directory have been modified?
所以我的问题是,检查目录内容是否已被修改的最简单方法是什么?
采纳答案by MSpreij
Uh. I'd simply store the md5 of a directory listing. If the contents change, the md5(directory-listing) will change. You mightget the very occasional md5 clash, but I think that chance is tiny enough..
Alternatively, you could store a little file in that directory that contains the "last modified" date. But I'd go with md5.
呃。我只是存储目录列表的 md5。如果内容改变,md5(directory-listing) 也会改变。您可能偶尔会遇到 md5 冲突,但我认为这种可能性很小。
或者,您可以在该目录中存储一个包含“上次修改”日期的小文件。但我会选择 md5。
PS. on second thought, seeing as how you're looking at performance (caching) requesting and hashing the directory listing might not be entirely optimal..
附注。再想一想,看看您如何看待请求和散列目录列表的性能(缓存)可能不是完全最佳的..
回答by troelskn
As already mentioned by others, a better way to solve this would be to trigger a function when particular events happen, that changes the folder.
However, if your server is a unix, you can use inotifywaitto watch the directory, and then invoke a PHP script.
正如其他人已经提到的,解决这个问题的更好方法是在发生特定事件时触发一个函数,该函数会更改文件夹。但是,如果您的服务器是 unix,则可以使用inotifywait监视目录,然后调用 PHP 脚本。
Here's a simple example:
这是一个简单的例子:
#!/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
See also: http://linux.die.net/man/1/inotifywait
回答by troelskn
回答by chic
with inotifywait inside php
在 php 中使用 inotifywait
$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";
}
回答by Anton Gogolev
Here's what you may try. Store all pictures in a single directory (or in /usernamesubdirectories inside it to speed things up and to lessen the stress on the FS) and set up Apache (or whaterver you're using) to serve them as static content with "expires-on" set to 100 years in the future. File names should contain some unique prefix or suffix (timestamp, SHA1 hash of file content, etc), so whenever uses changes the file its name gets changed and Apache will serve a new version, which will get cached along the way.
这是您可以尝试的方法。将所有图片存储在一个目录中(或在其中的/username子目录中以加快速度并减轻 FS 的压力)并设置 Apache(或您使用的任何东西)以将它们作为带有“过期时间”的静态内容提供设定为未来 100 年。文件名应包含一些唯一的前缀或后缀(时间戳、文件内容的 SHA1 哈希等),因此每当使用更改时,文件名都会更改,Apache 将提供一个新版本,该版本将在此过程中被缓存。
回答by SchizoDuckie
You're thinking the wrong way.
你想错了。
You should execute your directory indexer script as soon as someone's uploaded a new file and it's moved to the target location.
您应该在有人上传新文件并将其移动到目标位置后立即执行目录索引器脚本。
回答by Alix Axel
IMO edubem's answeris the way to go, however you can do something like this:
IMO edubem 的答案是要走的路,但是您可以执行以下操作:
if (sha1(serialize(Map('/path/to/directory/', true))) != /* previous stored hash */)
{
// directory contents has changed
}
Or a more weak / faster version:
或者更弱/更快的版本:
if (Size('/path/to/directory/', true) != /* previous stored size */)
{
// directory contents has changed
}
Here are the functions used:
下面是用到的函数:
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;
}
回答by Mario
Try deleting the cached version when a user uploads a file to his directory.
当用户将文件上传到他的目录时,尝试删除缓存版本。
When someone tries to view the gallery, look if there's a cached version first. If there's a cached version, load it, otherwise, generate the page, cache it, done.
当有人尝试查看图库时,请先查看是否有缓存版本。如果有缓存版本,则加载它,否则,生成页面,缓存它,完成。
回答by Aldekein
Here is a code sample, that would return 0 if the directory was changed. I use it in backups.
这是一个代码示例,如果目录被更改,它将返回 0。我在备份中使用它。
The changed status is determined by presence of files and their filesizes. You could easily change this, to compare file contents by replacing
更改的状态由文件的存在及其文件大小决定。您可以轻松更改此设置,以通过替换来比较文件内容
$longString .= filesize($file);
with
和
$longString .= crc32(file_get_contents($file));
but it will affect execution speed.
但会影响执行速度。
#!/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');
回答by Moises Kirsch
I was looking for something similar and I just found this:
我正在寻找类似的东西,我刚刚找到了这个:
http://www.franzone.com/2008/06/05/php-script-to-monitor-ftp-directory-changes/
http://www.franzone.com/2008/06/05/php-script-to-monitor-ftp-directory-changes/
For me looks like a great solution since I'll have a lot of control (I'll be doing an AJAX call to see if anything changed).
对我来说看起来是一个很好的解决方案,因为我将拥有很多控制权(我将进行 AJAX 调用以查看是否有任何更改)。
Hope that this helps.
希望这会有所帮助。

