2009-02-12 45 views
23

Tôi đang viết một tập lệnh thư viện ảnh trong PHP và có một thư mục duy nhất mà người dùng sẽ lưu trữ hình ảnh của họ. Tôi đang cố gắng thiết lập bộ nhớ đệm trang và chỉ làm mới bộ nhớ cache nếu nội dung của thư mục đã thay đổi. Tôi nghĩ rằng tôi có thể làm điều này bằng cách bộ nhớ đệm thời gian sửa đổi cuối cùng của thư mục bằng cách sử dụng hàm filemtime() và so sánh nó với thời gian sửa đổi hiện tại của thư mục. Tuy nhiên, như tôi đã nhận ra, thư mục sửa đổi thời gian không thay đổi khi các tập tin được thêm vào hoặc loại bỏ khỏi thư mục đó (ít nhất là trên Windows, không chắc chắn về các máy Linux).Cách kiểm tra xem nội dung thư mục có thay đổi với PHP không?

Vì vậy, câu hỏi của tôi là, cách đơn giản nhất để kiểm tra xem nội dung của thư mục đã được sửa đổi chưa?

+0

Cảm ơn câu trả lời nhưng hầu hết câu trả lời của bạn không hợp lệ cho tập lệnh mà nhiều người dùng cuối trên nhiều hệ thống khác nhau sẽ sử dụng. Để hiểu rõ hơn về những gì tôi đang thực hiện điều này, hãy xem trang thư viện tại http://code.web-geek.net/ck-gallery – PHLAK

Trả lời

6

Uh. Tôi chỉ đơn giản là lưu trữ md5 của một danh sách thư mục. Nếu nội dung thay đổi, md5 (danh sách thư mục) sẽ thay đổi. Bạn có thể nhận được xung đột md5 rất thường xuyên, nhưng tôi nghĩ cơ hội đó đủ nhỏ ..
Ngoài ra, bạn có thể lưu trữ một tệp nhỏ trong thư mục chứa ngày "được sửa đổi lần cuối". Nhưng tôi sẽ đi với md5.


PS. trên suy nghĩ thứ hai, nhìn thấy như thế nào bạn đang nhìn vào hiệu suất (caching) yêu cầu và băm danh sách thư mục có thể không hoàn toàn tối ưu ..

3

Đây là những gì bạn có thể thử. Lưu trữ tất cả hình ảnh trong một thư mục (hoặc trong /username thư mục con bên trong nó để tăng tốc độ và giảm bớt căng thẳng trên FS) và thiết lập Apache (hoặc người bạn đang sử dụng) để phục vụ chúng dưới dạng nội dung tĩnh với "hết hạn "đặt tới 100 năm trong tương lai. Tên tệp phải chứa một số tiền tố hoặc hậu tố duy nhất (dấu thời gian, hàm băm SHA1 của nội dung tệp, v.v.), vì vậy bất cứ khi nào sử dụng thay đổi, tên của tệp sẽ bị thay đổi và Apache sẽ phân phối phiên bản mới, sẽ được lưu trong bộ nhớ cache.

+0

Điều này cũng tránh được các trình duyệt không lưu vào bộ nhớ cache do các tham số chuỗi truy vấn và các thông tin tương tự (Safari, iirc). –

+0

Bộ nhớ đệm của trang có ở đâu trong tất cả điều này? – Mario

+0

Thay đổi tên hình ảnh sẽ giết dấu trang. – Mario

3

Bạn đang suy nghĩ sai.

Bạn nên thực thi tập lệnh chỉ mục thư mục của mình ngay sau khi ai đó tải lên tệp mới và tệp được di chuyển đến vị trí mục tiêu.

+0

Có vẻ như một giải pháp tốt lúc đầu, nhưng có một GOTCHA. Nếu anh ta muốn thay đổi mẫu của trang của mình, giải pháp của bạn không thành công vì bạn không thể xóa các mục được lưu trong bộ nhớ cache để chúng làm mới. Nó sẽ đòi hỏi một kịch bản khác để xây dựng lại toàn bộ sự việc. – Mario

+0

Tại sao bạn không thể xóa các mục được lưu trong bộ nhớ cache? Bạn đã không nghe nói về chmod? – SchizoDuckie

+0

Tất cả những gì tôi có thể đề nghị là đọc lại câu hỏi của anh ấy một cách cẩn thận, câu trả lời của bạn, câu trả lời của tôi ở phía dưới và bình luận của tôi ở đây. Caching upfront bị lỗi trong tình huống này. – Mario

8

Còn thư mục touching sau khi người dùng gửi hình ảnh của anh ấy thì sao? Changelog nói: Yêu cầu php 5.3 cho cửa sổ để làm việc, nhưng tôi nghĩ rằng nó sẽ hoạt động trên tất cả các môi trường khác

+0

+1, Đơn giản, đẹp và nhanh chóng! –

1

Thử xóa phiên bản đã lưu trong bộ nhớ cache khi người dùng tải tệp lên thư mục của mình.

Khi ai đó cố xem thư viện, trước tiên hãy xem có phiên bản được lưu trong bộ nhớ cache hay không. Nếu có phiên bản được lưu trong bộ nhớ cache, hãy tải phiên bản đó, nếu không, hãy tạo trang, lưu bộ nhớ cache, xong.

+0

Điều này có ý nghĩa, nhưng làm cách nào để theo dõi tệp tải lên? Kịch bản của tôi chỉ thực hiện khi ai đó truy cập trang, tôi không thể chủ động theo dõi một thư mục, đó là lý do tại sao tôi đã cố gắng kiểm tra ngày sửa đổi của thư mục. – PHLAK

21

Như đã được đề cập bởi những người khác, cách tốt hơn để giải quyết vấn đề này là kích hoạt chức năng khi các sự kiện cụ thể xảy ra, thay đổi thư mục. Tuy nhiên, nếu máy chủ của bạn là unix, bạn có thể sử dụng inotifywait để xem thư mục và sau đó gọi tập lệnh PHP.

Dưới đây là một ví dụ đơn giản:

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

Xem thêm: http://linux.die.net/man/1/inotifywait

+3

Tôi nghĩ rằng giải pháp nên được giữ ở cấp độ PHP. Giải pháp này vướng víu ứng dụng PHP với hệ điều hành cơ bản và mất tính di động. – Mario

+6

Một số tác vụ được xử lý tốt hơn ở cấp hệ điều hành. Ví dụ, thiết lập một cronjob vốn là hệ điều hành cụ thể. Không có cách nào để làm điều đó trong PHP. – troelskn

+2

Đây là về caching một trang HTML với PHP, nó phải làm với PHP. Liên quan đến hệ điều hành này sẽ làm phức tạp vấn đề không có gì. Chưa kể đến ma thuật ẩn mà giải pháp này ẩn giấu có thể gây nhầm lẫn cho các lập trình viên. – Mario

1

tôi đang tìm kiếm một cái gì đó tương tự và tôi chỉ thấy điều này:

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

Đối với tôi trông giống như một giải pháp tuyệt vời kể từ khi tôi sẽ có rất nhiều điều khiển (Tôi sẽ làm một cuộc gọi AJAX để xem có thay đổi gì không).

Hy vọng điều này sẽ hữu ích.

+1

Tôi quên đề cập đến ... kế hoạch của tôi là thay đổi nó để đọc một thư mục cục bộ thay vì sử dụng FTP. Nhưng những điều cơ bản vẫn còn ở đó. –

2

IMO edubem's answer là con đường để đi, tuy nhiên bạn có thể làm một cái gì đó như thế này:

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

Hoặc một yếu hơn/phiên bản nhanh hơn:

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

Sau đây là các chức năng sử dụng:

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

với inotifywait bên trong 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"; 
} 
1

Đây là mẫu mã, sẽ trả về 0 nếu thư mục đã được thay đổi. Tôi sử dụng nó trong bản sao lưu.

Trạng thái đã thay đổi được xác định bởi sự hiện diện của tệp và tệp của chúng được định dạng. Bạn có thể dễ dàng thay đổi này, để so sánh nội dung tập tin bằng cách thay thế

$longString .= filesize($file); 

với

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

nhưng nó sẽ ảnh hưởng đến tốc độ thực hiệ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'); 
Các vấn đề liên quan