2009-02-12 10 views
23

Ich schreibe ein Foto-Galerie-Skript in PHP und habe ein einziges Verzeichnis, in dem der Benutzer seine Bilder speichert. Ich versuche, die Zwischenspeicherung von Seiten einzurichten, und lasse den Cache nur aktualisieren, wenn sich der Inhalt des Verzeichnisses geändert hat. Ich dachte, ich könnte dies tun, indem ich die letzte modifizierte Zeit des Verzeichnisses mit der Funktion filemtime() zwischenspeichern und mit der aktuell modifizierten Zeit des Verzeichnisses vergleichen würde. Wie ich jedoch festgestellt habe, ändert sich die geänderte Zeit des Verzeichnisses nicht, da Dateien aus diesem Verzeichnis hinzugefügt oder entfernt werden (zumindest unter Windows, die sich noch nicht über Linux-Maschinen sicher sind).Wie überprüft man, ob Verzeichnisinhalte sich mit PHP verändert haben?

So sind meine Fragen, was ist der einfachste Weg, wenn der Inhalt eines Verzeichnisses geändert wurde, zu überprüfen?

+0

Vielen Dank für die Antworten, aber die meisten Ihrer Antworten sind nicht gültig für ein Skript, das viele Endbenutzer auf vielen verschiedenen Systemen verwenden. Für ein besseres Verständnis dessen, wofür ich das implementiere, schaue auf die Galerieseite http://code.web-geek.net/ck-gallery. – PHLAK

Antwort

6

Uh. Ich würde einfach die MD5 einer Verzeichnisliste speichern. Wenn sich der Inhalt ändert, wird sich die md5 (Verzeichnisliste) ändern. Sie könnte den sehr gelegentlichen md5 Zusammenstoß, aber ich denke, dass der Zufall winzig genug ist ..
Alternativ können Sie eine kleine Datei in diesem Verzeichnis speichern könnten, die das „zuletzt geändert“ Datum enthält. Aber ich würde mit md5 gehen.


PS. auf den zweiten Gedanken, wie Sie Leistung (Caching) suchen und Hashing der Verzeichnisliste möglicherweise nicht ganz optimal sein ..

3

Hier ist, was Sie versuchen können. Speichern Sie alle Bilder in einem einzigen Verzeichnis (oder in /username Unterverzeichnissen darin, um Dinge zu beschleunigen und die FS-Belastung zu verringern) und richten Sie Apache (oder was auch immer Sie verwenden) als statischen Inhalt mit "ablaufbereit" ein "Zu 100 Jahren in der Zukunft. Dateinamen sollten ein eindeutiges Präfix oder Suffix enthalten (Timestamp, SHA1-Hash des Dateiinhalts usw.). Wenn die Datei geändert wird, ändert sich ihr Name und Apache wird eine neue Version bereitstellen, die auf dem Weg zwischengespeichert wird.

+0

Dies umgeht auch Browser, die Dinge aufgrund von Abfragekettenparametern und dergleichen nicht zwischenspeichern (Safari, IIRC). –

+0

Wo kommt das Seiten-Caching dazu? – Mario

+0

Durch das Ändern der Bildnamen werden Lesezeichen gelöscht. – Mario

3

Sie denken in die falsche Richtung.

Sie sollten Ihre Verzeichnis-Indexer Skript, sobald jemand hat eine neue Datei und es bewegt zum Zielort durchführen.

+0

Scheint zunächst eine gute Lösung, aber es gibt ein GOTCHA. Wenn er die Vorlage seiner Seite ändern möchte, schlägt die Lösung fehl, da die zwischengespeicherten Elemente nicht gelöscht werden können. Es würde ein anderes Skript erfordern, um das Ganze wieder aufzubauen. – Mario

+0

Warum sollten Sie die zwischengespeicherten Elemente nicht löschen können? Hast du noch nicht von chmod gehört? – SchizoDuckie

+0

Alles, was ich vorschlagen kann, ist, seine Frage, Ihre Antwort, meine Antwort unten und meinen Kommentar hier sorgfältig zu lesen. Caching im Voraus ist in dieser Situation fehlerhaft. – Mario

8

Was touching das Verzeichnis nach einem Benutzer sein Bild eingereicht hat? Changelog sagt: Benötigt php 5.3 für Windows zu arbeiten, aber ich denke, es sollte in allen anderen Umgebungen funktionieren

+0

+1, Einfach, nett und schnell! –

1

Versuchen Sie, die zwischengespeicherte Version zu löschen, wenn ein Benutzer eine Datei in sein Verzeichnis hochlädt.

Wenn jemand versucht, um die Galerie zu sehen, schauen, wenn es zuerst eine Cache-Version ist. Wenn es eine zwischengespeicherte Version gibt, laden Sie sie, ansonsten erzeugen Sie die Seite, cachen sie, fertig.

+0

Das ist sinnvoll, aber wie kann ich eine hochgeladene Datei überwachen? Mein Skript wird nur ausgeführt, wenn jemand die Seite besucht. Ich kann ein Verzeichnis nicht aktiv überwachen. Deshalb habe ich versucht, das Änderungsdatum des Verzeichnisses zu überprüfen. – PHLAK

21

Wie bereits von anderen erwähnt, lösen ein besseren Weg, dies eine Funktion auslösen würde, wenn bestimmte Ereignisse eintreten, so dass der Ordner ändert. Wenn Ihr Server jedoch ein Unix ist, können Sie inotifywait verwenden, um das Verzeichnis zu überwachen, und dann ein PHP-Skript aufrufen.

Hier ist ein einfaches Beispiel:

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

Siehe auch: http://linux.die.net/man/1/inotifywait

+3

Ich denke, die Lösung sollte auf der PHP-Ebene gehalten werden. Diese Lösung verwickelt die PHP-App mit dem zugrunde liegenden Betriebssystem und verliert die Portabilität. – Mario

+6

Einige Aufgaben werden auf Betriebssystemebene viel besser erledigt. Zum Beispiel ist das Einrichten eines Cronjobs inhärent Betriebssystem-spezifisch. Es gibt keine Möglichkeit, das in PHP zu tun. – troelskn

+2

Hier geht es darum, eine HTML-Seite mit PHP zwischenzuspeichern, es hat mit PHP zu tun. Die Einbeziehung des Betriebssystems wird die Sache umsonst erschweren. Ganz zu schweigen von der versteckten Magie, die diese Lösung versteckt, könnte Programmierer verwirren. – Mario

1

Ich war auf der Suche nach etwas ähnliches, und ich habe gerade dies:

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

Für mich sieht aus wie eine große Lösung, da ich viel Kontrolle haben werde (Ich werde einen AJAX-Aufruf tun um zu sehen, ob sich etwas geändert hat).

Hoffe, dass dies hilft.

+1

Ich habe vergessen zu erwähnen ... mein Plan ist es zu ändern, um ein lokales Verzeichnis zu lesen, anstatt FTP zu verwenden. Aber die Grundlagen sind immer noch da. –

2

IMO edubem's answer ist der Weg zu gehen, aber Sie etwas tun können:

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

Oder eine schwache/schnellere Version:

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

Hier werden die Funktionen verwendet:

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

mit inotifywait innerhalb php

1

Hier ist ein Codebeispiel, das 0 zurückgeben würde, wenn das Verzeichnis geändert wurde. Ich verwende es in Sicherungen.

Der geänderte Status wird durch das Vorhandensein von Dateien und deren Dateigrößen bestimmt. Sie könnten dies leicht, ändern, indem Sie Dateiinhalte vergleichen

ersetzt
$longString .= filesize($file); 

mit

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

aber es wird die Ausführungsgeschwindigkeit beeinflussen.

#!/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'); 
Verwandte Themen