2008-09-26 27 views
14

使用PHP處理圖像緩存的最佳實踐方式是什麼?使用PHP和MySQL緩存調整大小的圖像的最佳方法

當前文件名存儲在MySQL數據庫中,該數據庫與原始文件名和alt標記一起被重命名爲上傳的GUID。

當圖像被放入HTML頁面時,使用諸如'/images/get/200x200/{guid}.jpg'這樣的URL來重寫爲一個php腳本。這允許我的設計人員指定(大致 - 源圖像可能更小)的文件大小。

然後,php腳本創建一個大小(URL中的200x200)和GUID文件名的散列,如果之前已經生成了該文件(散列名稱存在於TMP目錄中的文件),則從該文件發送文件應用程序TMP目錄。如果哈希文件名不存在,那麼它被創建,寫入磁盤並以相同的方式提供,

這是否有效,因爲它可能是? (它也支持加水印圖像和水印設置存儲在哈希中,但這不在此範圍內)。

回答

10

有于丹Udey的重寫例如兩個錯別字(我不能對此發表評論),它應該是:

RewriteCond %{REQUEST_URI} ^/images/cached/ 
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f 
RewriteRule (.*) /images/generate.php?$1 [L] 

問候。

0

您的方法看起來相當合理 - 我會補充說一些機制應該到位檢查緩存版本的生成日期是否是原始(源)圖像文件的最後修改時間戳之後,如果不重新生成緩存/調整大小的版本。這將確保如果設計者更改了圖像,緩存將被適當更新。

+0

不錯的建議,但... 如果通過上傳的新映像(通過管理界面)更改源,則會生成新的GUID,並且緩存的文件名將不再匹配。 圖像不應該與(s)FTP上傳,但我們都知道假設。 ;) 無論如何將看看實現。 – 2008-09-26 17:31:46

+0

我還檢查圖像是否被緩存_after_對緩存腳本進行了任何修改,即if(filemtime($ cached_image)> filemtime($ _ SERVER ['SCRIPT_FILENAME'])){...}` – 2011-05-01 12:33:52

0

這聽起來像一個堅實的方式來做到這一點。下一步可能是超越PHP/MySQL。

也許,調整你的頭

如果您使用PHP發送MIME類型,你也可以使用「保活」和「緩存控制」頭擴展您的圖像的生活在服務器上,並採取一些PHP/MySQL的負載。

另外,考慮apache插件(s)爲緩存以及。像mod_expires

哦,還有一件事,你有多少控制你的服務器?我們是否應該限制這個對話只是 PHP/MySQL?

+0

該應用程序託管在VPS上,所以我有root權限。 mod_expires已安裝,因此看起來像一個簡單的.htaccess調整可以減少服務器的負載。 好的提示,謝謝。 – 2008-09-26 17:35:16

0

phpThumb是一個框架,可以即時生成調整大小的圖像/縮略圖。它也實現了緩存,實現起來非常簡單。

來調整圖像的代碼是:

<img src="/phpThumb.php?src=/path/to/image.jpg&w=200&amp;h=200" alt="thumbnail"/> 

會給你的200×200的縮略圖;

它還支持加水印。

瞧瞧吧: http://phpthumb.sourceforge.net/

5

一注值得加入是爲了確保你的代碼不會產生這些圖像的「未經授權」的大小。

因此,下面的URL將創建圖像1234的200x200版本(如果尚不存在的話)。我會高度建議您確保請求的網址包含您支持的圖片尺寸。

/images/get/200x200/1234.jpg 

有惡意的人可以先要求隨機網址,總是改變圖像的高度&寬度。這將導致您的服務器出現一些嚴重問題,它將坐在那裏,基本上處於受到攻擊的狀態,從而生成您不支持的尺寸圖像。

/images/get/0x1/1234.jpg 
/images/get/0x2/1234.jpg 
... 
/images/get/0x9999999/1234.jpg 
/images/get/1x1/1234.jpg 
... 
etc 

這裏的代碼說明這是一個隨機剪斷:

<?php 

    $pathOnDisk = getImageDiskPath($_SERVER['REQUEST_URI']); 

    if(file_exists($pathOnDisk)) { 
     // send header with image mime type 
     echo file_get_contents($pathOnDisk); 
     exit; 
    } else { 
     $matches = array(); 
     $ok = preg_match(
      '/\/images\/get\/(\d+)x(\d+)\/(\w+)\.jpg/', 
      $_SERVER['REQUEST_URI'], $matches); 

     if(! $ok) { 
      // invalid url 
      handleInvalidRequest(); 
     } else { 
      list(, $width, $height, $guid) = $matches; 

      // you should do this! 
      if(isSupportedSize($width, $height)) { 
       // size is supported. all good 
       // generate the resized image, save it & output it 
      } else { 
       // invalid size requested!!! 
       handleInvalidRequest(); 
      } 
     } 
    } 

    // snip 
    function handleInvalidRequest() { 
     // do something w/ invalid request   
     // show a default graphic, log it etc 
    } 
?> 
+0

使用die()是可怕的代碼。您基本上都會紓困,將一行文本轉儲到客戶端,而不進行任何糾錯。如果在生產中使用此示例,請使用替換圖像或有用的錯誤替換die()調用。 – 2008-09-26 19:19:32

+0

我同意你的意見。它只是示例代碼,以獲得只是 – phatduckk 2008-09-27 05:16:18

30

我會做不同的方式。

問題: 1. PHP提供文件的效率低於它的效率。 2.每次請求鏡像時,PHP都要檢查文件是否存在 3. Apache比PHP要好得多。

這裏有幾個解決方案。

您可以在Apache上使用mod_rewrite。可以使用mod_rewrite來測試一個文件是否存在,如果存在,請改爲提供該文件。這完全繞過了PHP,並使事情變得更快。但是,真正的做法是生成一個應該始終存在的特定URL模式,如果不是,則重定向到PHP。

例如:

RewriteCond %{REQUEST_URI} ^/images/cached/ 
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f 
RewriteRule (.*) /images/generate.php?$1 [L] 

所以,如果一個客戶端請求/images/cached/<something>和該文件不存在,Apache將請求重定向到/images/generate.php?/images/cached/<something>。然後,該腳本可以生成映像,將其寫入緩存,然後將其發送給客戶端。將來,除了新圖像之外,PHP腳本不會被調用。

使用緩存。正如另一張海報所說,使用諸如mod_expires,Last-Modified頭等等來響應條件GET請求。如果客戶端不需要重新請求圖像,頁面加載速度將顯着加快,並且服務器上的加載將減少。

對於您必須從PHP發送圖像的情況,您可以使用mod_xsendfile以較少的開銷執行此操作。有關此問題,請參閱the excellent blog post from Arnold Daniels,但請注意,他的示例適用於下載。要以內聯方式提供圖像,請取出Content-Disposition標頭(第三個標頭()調用)。

希望這可以幫助 - 更多的是在我的偏頭痛結束後。

1

似乎偉大的文章,但我的問題仍然沒有解決。我沒有訪問我的主機提供商的htaccess,所以沒有問題的Apache調整。真的有辦法爲圖像設置cace-control標題嗎?

0

我已經成功地做到這一點僅僅用在PHP重定向頭:

if (!file_exists($filename)) { 

    // *** Insert code that generates image *** 

    // Content type 
    header('Content-type: image/jpeg'); 

    // Output 
    readfile($filename);  

} else { 
    // Redirect 
    $host = $_SERVER['HTTP_HOST']; 
    $uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\'); 
    $extra = $filename; 
    header("Location: http://$host$uri/$extra"); 
} 
0

而是保持文件的地址在數據庫中,我更喜歡加入一個隨機數的文件名每當事情是這樣的,用戶登錄用戶1234:?圖像/ picture_1234.png RND = 6534122341

如果用戶在會議期間提交了一張新照片,我只刷新了隨機數。

GUID解決緩存問題100%。然而,這使得難以跟蹤圖片文件。通過這種方法,用戶有可能在將來登錄時再次看到相同的圖片。但是,如果您從十億個數字中生成您的隨機數,則可能性很低。

相關問題