キャッシュを作ってみよう。

PHP高速化のために、ページ内容をデータベースやファイルにキャッシュする方法って色々紹介されてますね。

ってことで、今さらなんかなーって思いつつも。

実は私は、他ブログやニュースなどで、色々なキャッシュ方法を見聞きしてますが、実際に使ったことはありません。

「こういうのがあるよー」ってことを知っている程度です。

なぜか?って。

だって、自分でキャッシュの仕組みを作っちゃってたから。

 

では、コードの前に特徴から。

キャッシュの保存先はデータベースです。

最初は、ファイルベースでを作ってたんだけど、数万ページを超えるようなサイトだと、キャッシュファイルだけでもかなりの数になり、しかもFTPしか使えない状況だと大変なことになってきてたので、データベースに切り替えました。

キャッシュは、ページの任意の範囲で行えます。

ログイン機能など、ユーザーごとに微妙に表示内容の異なるサイトで威力を発揮します。

ヘッダーだけキャッシュ、内容だけキャッシュなど、キャッシュできる範囲は自由です。

もちろん、ページまるごとキャッシュも可能です。

1箇所のキャッシュで、任意の数の値をキャッシュできます。

キャッシュ用の変数は配列です。

ページ内容だけでなく、時間、商品名、説明文などなど、配列なので、好きなだけセットしてください。

例えば、body部はまるごと、meta keywordや、meta descriptionは、個別にキャッシュしたいなどに対応できます。

 

●データベースにテーブルを作成する。

CREATE TABLE IF NOT EXISTS `AultaCacheData` (
  `CacheId` varchar(30) NOT NULL COMMENT 'キャッシュID',
  `CacheData` mediumtext NOT NULL,
  `CacheDatetime` datetime NOT NULL,
  PRIMARY KEY (`CacheId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Aultaキャッシュ';

●定数宣言

// キャッシュ機能の有効・無効
define('CA_FILE_CACHE_ON', true);

●キャッシュからロードする

/*
 * DBからキャッシュデータをロードする
 * $cacheId : キャッシュID
 * $expire : 有効期限(ミリ秒)
 */
function loadCacheDb($cacheId, $expire = 31536000){
  // 戻り値の初期化
  $returnData = array(
      'isLoaded' => false    // キャッシュから正常に読込みした
    , 'timeStamp' => 0      // キャッシュファイルのタイムスタンプ(秒)
    , 'header' => array()  // ヘッダ
    , 'data' => array()    // データ
    );
  // 開発時などは CA_FILE_CACHE_ON = false でキャッシュを無効化
  if ( ! CA_FILE_CACHE_ON) return $returnData;
  
  //  キャッシュのチェック
  $result = dbGetFields(
    "select CacheData, CacheDatetime from AultaCacheData"
    . " where CacheId = '" . dbRealEscape($cacheId) . "'"
  );
  if ($result !== false){  //  キャッシュファイルが存在する
    $t = strtotime($result['CacheDatetime']);
    if ($t > (time() - $expire)){  //  タイムスタンプが有効期限以内なら
      $returnData = (array)json_decode($result['CacheData'], true);
      $returnData['timeStamp'] = $t;  //  ファイルのタイムスタンプをセット
      $returnData['isLoaded'] = true;
    }
  }
  return $returnData;
}

●キャッシュに書き込む

/*
 * キャッシュをDBに登録する
 * $cacheId : キャッシュID
 * $content  : キャッシュする内容(配列)
 */
function saveCacheDb($cacheId, &$cacheData){
  unset($cacheData['isLoaded']);
  unset($cacheData['timeStamp']);
  dbRunSql(
    "replace into AultaCacheData (CacheId, CacheData, CacheDatetime)"
    . " values ("
    . "  '" . dbRealEscape($cacheId) . "'"
    . ", '" . dbRealEscape(json_encode($cacheData)) . "'"
    . ", now()"
    . ")"
  );
}

 

●●使用例

  $isCreate = true;
  $cacheId = 'URLや任意の文字など、識別するためのキー';
  
  $data = loadCacheDb($cacheId, (12 * 3600));
  if ($data['isLoaded']){  //	キャッシュが見つかり、有効期限内
    $isCreate = false;
  } else {  //  キャッシュが無いので作成する。
    $data = array(
      'header' => array()
      'data' => array()
    );
  	~~~~~
  	$dataにキャッシュ内容をセットする。
  	$data['header']、$data['data']に、キャッシュしたい内容を放り込んでいく。
  	データベースには、$data配列のまま保存し、配列のまま取り出すので、好きなように値をセットできます。
  	~~~~~
	  saveCacheDb($cacheId, $dataContentInfo);
  }

サンプル作る途中で、ちょこっと端折ったけど、ページが随時更新されるコミュニティ系のサイトなんかだと、最終の投稿日を「header」に入れておいて、ロード時に、データベース側の最終更新日時と突き合わせたほうが良いと思います。

 

あーー!!

書き終えて気づいた。。。

dbRunSql() と dbGetFields() と dbRealEscape() は、独自関数でした。

とりあえず、

[Utility.php] データベースを楽にする function()

を読んでください。

その後、変更したり、追加したメソッドもあるから、はてなダのほうには、また後日載せます。