如何用PHP检查目录内容是否已更改?

时间:2009-02-12 07:04:27

标签: php directory last-modified filemtime

我正在用PHP编写照片库脚本,并有一个用户存储照片的目录。我正在尝试设置页面缓存并仅在目录内容发生更改时才刷新缓存。我想我可以通过使用filemtime()函数缓存目录的最后修改时间来完成此操作,并将其与目录的当前修改时间进行比较。但是,正如我已经意识到的那样,目录修改时间不会随着从该目录添加或删除文件而改变(至少在Windows上,还不确定Linux机器)。

所以我的问题是,检查目录内容是否被修改的最简单方法是什么?

10 个答案:

答案 0 :(得分:22)

正如其他人已经提到的,解决这个问题的更好方法是在特定事件发生时触发一个功能,即更改文件夹。 但是,如果您的服务器是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

答案 1 :(得分:8)

用户提交图像后的touching目录怎么样? Changelog说:要求php 5.3 for windows工作,但我认为它应该适用于所有其他环境

答案 2 :(得分:6)

嗯。我只是存储目录列表的md5。如果内容更改,md5(目录列表)将更改。你可能会偶然发生md5冲突,但我觉得这个机会很小...... 或者,您可以在该目录中存储包含“上次修改”日期的小文件。但我会选择md5。


PS。第二个想法,看看你如何看待性能(缓存)请求和散列目录列表可能不是完全最优..

答案 3 :(得分:6)

在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";
}

答案 4 :(得分:3)

这是你可以尝试的。将所有图片存储在一个目录中(或者在其中的/username子目录中以加快速度并减轻FS上的压力)并设置Apache(或者您正在使用的whaterver)将它们作为静态内容提供“expires-on”将在未来100年内完成。文件名应包含一些唯一的前缀或后缀(时间戳,文件内容的SHA1哈希等),因此每当使用更改文件时,其名称都会更改,而Apache将提供新版本,这将在此过程中缓存。

答案 5 :(得分:3)

你的想法是错误的。

当有人上传新文件并将其移动到目标位置时,您应该立即执行目录索引器脚本。

答案 6 :(得分:2)

IMO edubem's answer是要走的路,但是你可以这样做:

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;
}

答案 7 :(得分:1)

尝试在用户将文件上传到其目录时删除缓存版本。

当有人试图查看图库时,先查看是否有缓存版本。如果有缓存版本,请加载它,否则,生成页面,缓存它,完成。

答案 8 :(得分:1)

我正在寻找类似的东西,我发现了这个:

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

对我而言,看起来是一个很好的解决方案,因为我将有很多控制权(我将进行一次AJAX调用以查看是否有任何更改)。

希望这会有所帮助。

答案 9 :(得分:1)

这是一个代码示例,如果目录已更改,则返回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');