画像をケータイの画面サイズ別にキャッシュするには

By ookura - 08/11/07 - このエントリをはてなブックマークに追加このエントリをYahoo!ブックマークに追加このエントリをdel.icio.usに追加このエントリをFC2ブックマークに追加

以前、画像を機種画面サイズ別に出力する方法について述べましたが、今回は生成画像のキャッシュ方法について。
→参照:「ケータイ端末別に画像画面サイズを変換するには 」
 
 
縮小画像の動的生成は処理が重く、非常にサーバー負荷が高いです。
特にアクセスの多い携帯サイトの場合、サイト運営上のボトルネックになってきます。
そこで今回は生成した画像をキャッシュとして保存し、動的生成のコストを減らす方法について説明します。
 
 


キャッシュ保存パスの指定

キャッシュを保存するディレクトリを用意します。
キャッシュディレクトリのパーミッションはあらかじめファイルの保存が可能な属性にしておきます。
 
キャッシュを保存するファイルパスは以下の形式とします。

[キャッシュディレクトリ]/w_[画面横幅]h_[画面高さ]/ファイル名

 
※参考
ディレクトリに保存する画像が極端に多い場合はファイル名の1文字目・2文字目でディレクトリを分けるようにするとアクセス速度とサーバーの負荷を減らすのに効果的です。

[キャッシュディレクトリ]/w_[画面横幅]h_[画面高さ]/[1文字目]/[2文字目]/ファイル名

 
 


キャッシュ画像の生成処理

普通に画像を縮小して出力した後にキャッシュ画像を保存します。
その際、保存するディレクトリが存在しないとエラーになりますので、存在しなければ作成してから保存します。

// ヘッダ情報として出力したい形式のMIME情報を出力
// 説明省略のためJPEG出力に限定
header("Content-Type: image/jpeg");
imagejpeg($outImg);

// キャッシュ保存
if (!is_dir(dirname($cacheFilepath))) {
    mkdir(dirname($cacheFilepath), 0755, true);
}
imagejpeg($outImg, $cacheFilepath);

 
 


キャッシュ画像がある場合の処理

キャッシュ画像がある場合はキャッシュ画像を読み込んでそのまま出力します。
後でキャッシュを削除する際の判断基準になるようにアクセスしたらタイムスタンプを更新します。

if (file_exists($cacheFilepath)) {
    // JPEGヘッダ出力
    header("Content-Type: image/jpeg");
    
    // キャッシュファイルを読み込んで出力
    $outImg = imagecreatefromjpeg($cacheFilepath);
    imagejpeg($outImg);
    
    // メモリ開放
    imagedestroy($outImg);
    
    // キャッシュ管理のため、タイムスタンプを更新
    exec("touch {$cacheFilepath}");
    
}

 
 


PHPソース例

実際のソースは以下の通りです。
 
sample1.php

<?php
/* 
 * 端末サイズ別に画像キャッシュファイルを保存して出力するサンプル
 */

// 画像ファイルパス情報
$imgFileName = basename($_GET['file']);

$imgFilePath = '../../../img/sample/1135/' . $imgFileName;

// キャッシュ保存ディレクトリ
$cacheDir = '../../../img/sample/1135/cache/';

// ファイルの存在チェック
if ((!file_exists($imgFilePath)) || ($imgFilePath == '')) {
    die('Error : File not exists.');
}

// 端末情報取得
$userAgent = $_SERVER['HTTP_USER_AGENT'];
$deviceList = file('../../../data/sample/1135/' . "DeviceData.csv");
foreach ($deviceList as $key => $value) {
    list($carrier, $name, $agent, $deviceWidth, $deviceHeight) = explode(',', $value);
    if (preg_match('/' . preg_quote($agent, '/') . '/', $userAgent)) {
        $match = true;
        break;
    } else {
        $match = false;
    }
}

// マッチしなかった場合の処理
if (!$match) {
    $carrier = 'PC';
    $name = '';
    $agent = '';
    $deviceWidth  = 240;
    $deviceHeight = 320;
}

// キャッシュファイル保存パスを決定
$cacheFilepath = "{$cacheDir}w{$deviceWidth}_h{$deviceHeight}/{$imgFileName}";

// キャッシュ画像の表示
if (file_exists($cacheFilepath)) {
    // JPEGヘッダ出力
    header("Content-Type: image/jpeg");
    
    // キャッシュファイルを読み込んで出力
    $outImg = imagecreatefromjpeg($cacheFilepath);
    imagejpeg($outImg);
    
    // メモリ開放
    imagedestroy($outImg);
    
    // キャッシュ管理のため、タイムスタンプを更新
    exec("touch {$cacheFilepath}");
    
// 画像の動的生成 & キャッシュ画像ファイル作成
} else {
    
    // 画像ファイルの幅,高さ,mimetypeを確認
    list($imageWidth, $imageHeight, $imageType) = getimagesize($imgFilePath);
    
    
    // 無変換の場合は画像サイズを出力サイズとする
    $outWidth  = $imageWidth;
    $outHeight = $imageHeight;
    
    // 元画像幅が端末幅を超える場合は横幅調整
    if (($deviceWidth !== 0) && ($imageWidth > $deviceWidth)) {
        // 出力幅 = 端末幅
        $outWidth  = $deviceWidth;
        // 出力高さ = 元画像高さ × (端末幅の元画像幅に対する割合)
        $outHeight = $imageHeight * ($deviceWidth / $imageWidth);
    }
    
    // 出力高さが端末高さを超える場合は縦幅調整
    if (($deviceHeight !== 0) && ($outHeight > $deviceHeight)) {
        // 出力幅 = 出力幅 × (端末高さの元画像高さに対する割合)
        $outWidth  = $outWidth * ($deviceHeight / $outHeight);
        // 出力高さ = 端末高さ
        $outHeight = $deviceHeight;
    }
    
    // 切り上げ
    $outWidth  = ceil($outWidth);
    $outHeight  = ceil($outHeight);
    
    
    // 拡張子を判別して画像情報を取得
    $extention = pathinfo($imgFilePath, PATHINFO_EXTENSION);
    $extention = strtolower($extention);
    
    $mimeType = image_type_to_mime_type($imageType);
    
    // 説明省略のためJPEG読み込みに限定
    switch ($extention) {
    case 'jpg' :
        // mimetypeが拡張子と異なる場合はエラー終了
        if ($mimeType != 'image/jpeg') {
            die('Error : This file is not jpeg file.');
        }
        $imageID = imagecreatefromjpeg($imgFilePath);
        break;
    default ;
        die('Error : This file cannot convert.');
        break;
    }
    
    // 必要であればリサイズ
    if (($outWidth != $imageWidth) || ($outHeight != $imageHeight)) {
        // 新規イメージを作成
        $outImg = imagecreatetruecolor($outWidth, $outHeight);
        // リサイズしてコピー
        imagecopyresampled($outImg, $imageID, 0, 0, 0, 0, 
            $outWidth, $outHeight, $imageWidth, $imageHeight);
    } else {
        $outImg = $imageID;
    }
    
    // ヘッダ情報として出力したい形式のMIME情報を出力
    // 説明省略のためJPEG出力に限定
    header("Content-Type: image/jpeg");
    imagejpeg($outImg);
    
    // キャッシュ保存
    if (!is_dir(dirname($cacheFilepath))) {
        mkdir(dirname($cacheFilepath), 0755, true);
    }
    imagejpeg($outImg, $cacheFilepath);
    
    // メモリ解放
    imagedestroy($imageID);
    imagedestroy($outImg);
}
?>

 


実行例

実行例はこちらからご確認下さい。
キャッシュ画像の生成・削除が確認できます。

URLをメールで送る
http://ookura.tanikaze.com/Sample/post1135/