¿Cómo comprobar si el contenido del directorio ha cambiado con PHP?


Estoy escribiendo un script de galería de fotos en PHP y tengo un solo directorio donde el usuario almacenará sus imágenes. Estoy intentando configurar el almacenamiento en caché de páginas y tener la actualización de caché solo si el contenido del directorio ha cambiado. Pensé que podría hacer esto almacenando en caché la última hora modificada del directorio usando la función filemtime () y compararla con la hora modificada actual del directorio. Sin embargo, como me he dado cuenta, el directorio modificado tiempo no cambia como archivos se agregan o se eliminan de ese directorio (al menos en Windows, aún no estoy seguro de las máquinas Linux).

Así que mi pregunta es, ¿cuál es la forma más sencilla de comprobar si el contenido de un directorio ha sido modificado?

Author: PHLAK, 2009-02-12

10 answers

Uh. Simplemente almacenaría el md5 de una lista de directorios. Si el contenido cambia, el md5(directorio-listing) cambiará. Usted podría obtener el choque md5 muy ocasional, pero creo que la posibilidad es lo suficientemente pequeña..
Alternativamente, puede almacenar un pequeño archivo en ese directorio que contenga la fecha de "última modificación". Pero yo iría con md5.


PS. pensándolo bien, al ver cómo está viendo el rendimiento (almacenamiento en caché), solicitar y hashear la lista de directorios podría no sé totalmente óptimo..

 6
Author: MSpreij,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-25 21:26:25

Como ya han mencionado otros, una mejor manera de resolver esto sería activar una función cuando ocurren eventos particulares, que cambia la carpeta. Sin embargo, si su servidor es unix, puede usar inotifywait para ver el directorio, y luego invocar un script PHP.

Aquí hay un ejemplo simple:

#!/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

Véase también: http://linux.die.net/man/1/inotifywait

 21
Author: troelskn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-12 12:27:41

¿Qué pasa con tocando el directorio después de que un usuario haya enviado su imagen? Changelog dice: Requiere php 5.3 para que Windows funcione, pero creo que debería funcionar en todos los demás entornos

 8
Author: scunliffe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-25 21:10:29

Con inotifywait dentro de 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";
}
 6
Author: chic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-21 04:50:33

Esto es lo que puedes probar. Almacene todas las imágenes en un solo directorio (o en subdirectorios /username dentro de él para acelerar las cosas y disminuir el estrés en el FS) y configure Apache (o whaterver que esté utilizando) para servirlas como contenido estático con "caduca" establecido en 100 años en el futuro. Los nombres de archivo deben contener algún prefijo o sufijo único (marca de tiempo, hash SHA1 del contenido del archivo, etc.), por lo que cada vez que use cambios, el archivo cambia su nombre y Apache servirá una nueva versión, que obtener caché en el camino.

 3
Author: Anton Gogolev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-12 07:28:03

Estás pensando mal.

Debe ejecutar su script indexador de directorio tan pronto como alguien haya subido un nuevo archivo y se haya movido a la ubicación de destino.

 3
Author: SchizoDuckie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-12 08:10:35

IMO la respuesta de edubem es el camino a seguir, sin embargo puedes hacer algo como esto:

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

O una versión más débil / más rápida:

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

Aquí están las funciones utilizadas:

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;
}
 2
Author: Alix Axel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:01:49

Intente eliminar la versión en caché cuando un usuario cargue un archivo en su directorio.

Cuando alguien intente ver la galería, busque primero si hay una versión en caché. Si hay una versión en caché, cargarla, de lo contrario, generar la página, caché, hecho.

 1
Author: Mario,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-12 12:23:33

Estaba buscando algo similar y acabo de encontrar esto:

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

Para mí parece una gran solución ya que voy a tener mucho control (voy a hacer una llamada AJAX para ver si algo cambió).

Espero que esto ayude.

 1
Author: Moises Kirsch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-13 09:01:46

Aquí hay un ejemplo de código, que devolvería 0 si se cambiaba el directorio. Lo uso en copias de seguridad.

El estado cambiado está determinado por la presencia de archivos y sus tamaños de archivo. Puede cambiar esto fácilmente, para comparar el contenido del archivo reemplazando

$longString .= filesize($file);

Con

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

Pero afectará la velocidad de ejecución.

#!/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');
 1
Author: Aldekein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-09 08:20:32