CodeIgniter でデータベースを使ったシンプルなキャッシュを実装するサンプルコード

CakePHP では細かいキャッシュを取ることができますが、CodeIgniter には細かいキャッシュ機能を見つけることができませんでした。そのため PEAR::Cache_Lite を使うか、独自で実装します。

使い方

私が作ってみたキャッシュの使い方です。

1
2
3
4
5
if( ! $data = $this->Cache->get('cache_name', 3600)) {
    $data = 'キャッシュさせるデータ';
    $this->Cache->save('cache_name', $data);
}
echo $data;

$this->Cache->get() の第一引数はキーです。第二引数に有効期限を秒で入れます。60と入れると現在から60秒よりデータが古い場合にキャッシュが取得できなくなり、false が返ってきますので、$this->Cache->save() でデータを保存するシンプルな仕組みです。

キャッシュ用のテーブルを作成する

1
2
3
4
5
6
7
8
CREATE TABLE IF NOT EXISTS `caches` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `cache_name` varchar(32) CHARACTER SET utf8 NOT NULL,
  `cache_value` longtext CHARACTER SET utf8 NOT NULL,
  `updated` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Cache モデル

データベースへの接続はここでは行っていませんので、接続をしていない場合は書き換えてください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
class Cache extends CI_Model
{
    function save($cacheName, $cacheValue)
    {
        $sql = "SELECT id FROM caches WHERE cache_name = ? LIMIT 1";
        $query = $this->db->query($sql, Array($cacheName));
        if($query->num_rows() > 0) {
            $sql = "UPDATE caches SET cache_value = ?, updated = ? WHERE cache_name = ?";
            if( ! $this->db->query($sql, Array(serialize($cacheValue), date('Y-m-d H:i:s'), $cacheName))) {
                return false;
            }
        } else {
            $sql = "INSERT INTO caches (cache_name, cache_value, updated) VALUES (?, ?, ?)";
            if( ! $this->db->query($sql, Array($cacheName, serialize($cacheValue), date('Y-m-d H:i:s')))) {
                return false;
            }
        }
    }
 
    function get($cacheName, $cacheTime = 10000000)
    {
        $sql = "SELECT cache_value, updated FROM caches WHERE cache_name = ? LIMIT 1";
        $query = $this->db->query($sql, Array($cacheName));
        if($query->num_rows() > 0) {
            $cache = $query->result();
            if($cache[0]->updated < date('Y-m-d H:i:s', time() - $cacheTime)) {
                return false;
            }
            return unserialize($cache[0]->cache_value);
        }
        return false;
    }
}

以上になります。ざっと書いたサンプルコードですので、お使いの環境に合わせて作り込んだり、書き換えたりしてみてください。

追記: コードの $cacheName のエスケープ処理を行っていないとのことで @kenji_s 様から指摘頂きました。その際にクエリのバインディングを使うと良いとアドバイス頂きました。

1
2
$sql = "SELECT id FROM caches WHERE cache_name = ? LIMIT 1";
$query = $this->db->query($sql, Array($cacheName));

このクエリのバインディングについては以下のページの末尾に詳しく書いてあります。上記のコードもこれを使ったものに差し替えました。

これを使えばエスケープを自動的に行ってくれます。個別にエスケープ処理をすると、抜けなどが合った場合に問題に繋がりますので、これで値を渡すようにすると安全かもしれません。

コメント

コメントは受け付けていません。