GD 函式庫(imagejpeg、imagepng 等)預設直接輸出至瀏覽器,若要將圖片二進位資料存入 Memcached,需利用 PHP 輸出緩衝區(Output Buffering)攔截輸出。
<?php
// 1. 啟動輸出緩衝
ob_start();
// 2. 產生圖片(此處以 imagejpeg 為例)
// $newimage 為 imagecreatetruecolor() 等建立的 GD 資源
// $quality 為品質參數(0-100),第二參數設為 null/false 表示不輸出檔案
imagejpeg($newimage, null, $quality);
// 3. 獲取緩衝區內容(二進位字串)
$imageData = ob_get_contents();
// 4. 清空並關閉緩衝區
ob_end_clean();
// 5. 寫入 Memcached(假設 getMemcache() 回傳 Memcached 實例)
$mem = getMemcache();
$memKey = 'img_' . md5($uniqueIdentifier); // 自訂唯一鍵名
$mem->set($memKey, $imageData, 7200); // 快取 2 小時
// 6. 輸出給瀏覽器(或直接 echo $imageData)
header('Content-Type: image/jpeg');
echo $imageData;
?>
<?php
$mem = getMemcache();
$imageData = $mem->get($memKey);
if ($imageData !== false) {
header('Content-Type: image/jpeg');
header('Content-Length: ' . strlen($imageData));
echo $imageData;
exit;
}
// 快取未命中:重新產生圖片並存入快取(可重構為共用函式)
// ... 產生圖片邏輯 ...
?>
-I 參數或改用 Redis(支援 512MB)。header('Content-Type: image/...'),否則瀏覽器無法正確渲染。Cache-Control、ETag),減少重複請求流量。ob_get_contents() 失敗或 Memcached 連線失敗時,需有降級策略(直接輸出圖片、記錄日誌)。img_{id}_{w}x{h}_v{version})。class GdCache {
private $mem;
private $ttl = 3600;
public function __construct(Memcached $mem, $ttl = 3600) {
$this->mem = $mem;
$this->ttl = $ttl;
}
public function output($key, callable $generator, $mime = 'image/jpeg') {
$data = $this->mem->get($key);
if ($data !== false) {
$this->sendHeaders($mime, strlen($data));
echo $data;
return;
}
ob_start();
$generator(); // 內部呼叫 imagejpeg/png 等
$data = ob_get_clean();
$this->mem->set($key, $data, $this->ttl);
$this->sendHeaders($mime, strlen($data));
echo $data;
}
private function sendHeaders($mime, $length) {
header("Content-Type: $mime");
header("Content-Length: $length");
header('Cache-Control: public, max-age=' . $this->ttl);
}
}
// 使用方式
$cache = new GdCache(getMemcache(), 7200);
$cache->output('chart_user_123', function() {
// 繪圖邏輯
$im = imagecreatetruecolor(400, 300);
// ...
imagejpeg($im, null, 90);
imagedestroy($im);
});