今天看下CI的文件缓存机制,使用起来的确很简单啊。把原理记下来:
1. 先说下使用方式吧:【这个是直接从手册,复制过来的】
启用缓存功能,只需要将下面的代码放入你的任何一个控制器(controller)的方法(function)内:
$this->output->cache(n);
其中n是你希望缓存更新的 分钟 数。可以使用 m/60 来精确到秒,例如 1/60 ,则是精确到 1秒
上面的代码可以放到任何一个 function 里面。他的出现顺序对缓存并没有影响,所以将它放在你认为最合乎逻辑的地方。一旦上面的代码放到了控制器的方法中,页面就会被缓存。
警告: 由于CI存储缓存文件的方式,只有通过 view 文件的输出才能被缓存。
注意: 在缓存文件产生之前,请确保application/cache文件夹可写。
2. 缓存运行原理
在CI的核心文件 CodeIgniter.php文件182行
/*
* ------------------------------------------------------
* Is there a valid cache file? If so, we're done...
* ------------------------------------------------------
*/
if ($EXT->call_hook('cache_override') === FALSE
&& $OUT->_display_cache($CFG, $URI) === TRUE)
{
exit;
}
$EXT->call_hook('cache_override') 调用钩子,不存在返回false
$OUT->_display_cache($CFG, $URI) 判断缓存文件当前url下缓存文件是否存在
下面看看output类中 _display_cache方法
/**
* Update/serve cached output
*
* @uses CI_Config
* @uses CI_URI
*
* @param object &$CFG CI_Config class instance
* @param object &$URI CI_URI class instance
* @return bool TRUE on success or FALSE on failure
*/
public function _display_cache(&$CFG, &$URI)
{
$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
// Build the file path. The file name is an MD5 hash of the full URI
$uri = $CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;
$filepath = $cache_path.md5($uri);//带路径的缓存文件名
if ( ! @file_exists($filepath) OR ! $fp = @fopen($filepath, FOPEN_READ))
{
return FALSE;
}
flock($fp, LOCK_SH);
$cache = (filesize($filepath) > 0) ? fread($fp, filesize($filepath)) : '';
flock($fp, LOCK_UN);
fclose($fp);
// 检查序列化文件信息
if ( ! preg_match('/^(.*)ENDCI--->/', $cache, $match))
{
return FALSE;
}
$cache_info = unserialize($match[1]);
$expire = $cache_info['expire'];//缓存的到期时间
$last_modified = filemtime($cache_path);//取得文件的修改时间
// 判断文件是否过期
if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
{
// 如果已到期就删除
@unlink($filepath);
log_message('debug', 'Cache file has expired. File deleted.');
return FALSE;
}
else
{
// Or else send the HTTP cache control headers.
$this->set_cache_header($last_modified, $expire);
}
// Add headers from cache file.
foreach ($cache_info['headers'] as $header)
{
$this->set_header($header[0], $header[1]);
}
//输出缓存
$this->_display(substr($cache, strlen($match[0])));
log_message('debug', 'Cache file is current. Sending it to browser.');
return TRUE;
}
再看看生成文件缓存的方法
/**
* Write Cache
*
* @param string $output Output data to cache
* @return void
*/
public function _write_cache($output)
{
$CI =& get_instance();
$path = $CI->config->item('cache_path');
$cache_path = ($path === '') ? APPPATH.'cache/' : $path;
if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
return;
}
$uri = $CI->config->item('base_url').
$CI->config->item('index_page').
$CI->uri->uri_string();
$cache_path .= md5($uri);//缓存的文件名就是MD5的当前url值
if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
return;
}
$expire = time() + ($this->cache_expiration * 60);//缓存时间
// Put together our serialized info.
$cache_info = serialize(array(
'expire' => $expire,
'headers' => $this->headers
));
if (flock($fp, LOCK_EX))
{
fwrite($fp, $cache_info.'ENDCI--->'.$output);//写入文件
flock($fp, LOCK_UN);
}
else
{
log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);
return;
}
fclose($fp);
@chmod($cache_path, FILE_WRITE_MODE);
log_message('debug', 'Cache file written: '.$cache_path);
// Send HTTP cache-control headers to browser to match file cache settings.
$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
}
还有缓存删除_delete_cache这里就不在粘贴了,详细看output类吧。
ci文件缓存是很明了,就是在载入视图后,生成一个md5的文件,然后 文件内容中有缓存到期时间,下此重新载入的时候,就可直接调用了
有一个缺点就是所有的缓存文件都放在同一个目录下,如果站点较大的话,自己可以修改,分级目录保存。
下面是CI论坛里一位牛人 优化缓存机制 扩展了 output类
http://codeigniter.org.cn/forums/forum.php?mod=viewthread&tid=11515
//=================================================================
今天用来CI文件缓存发现分页的时候不起作用,于是就看缓存的生成方式
$uri = $CI->config->item('base_url').
$CI->config->item('index_page').
$CI->uri->uri_string();
$CI-uri-uri_string()这个方法不返回带有查询查询字符串的, 所以致使分页的缓存都是同一个文件名。的分页url后面是 ?page=&name=&是这种形式的 我把上述中的url改了一下
$uri = $CI->config->item('base_url').
$CI->config->item('index_page').
$CI->input->server('REQUEST_URI');
搞定。