-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Cache headers
Category:Contributions::Modifications
This extension to the Output Class caches headers which were set via $this->output->set_header().
When you set a header via $this->output->set_header(), but also use caching via $this->output->cache(), those headers you sent will not be cached along with your content.
This can be very problematic: if you're caching CSS, for example, you want the cache to return that CSS along with the Content-Type header "text/css" - otherwise most browsers will interpret your CSS as just plain text, and hence not use it for rendering. With this simple extension to the Output class, headers will also be cached and returned.
The following code is compatible and tested with CodeIgniter 1.6.3 and 1.7.0, if you want instructions for an older version of CodeIgniter, please view an older revision of this page. Thanks to Aquillyne for the idea and the previous version.
This extension is more memory efficient as the current (1.7.0) caching system, so even if you don't need the header caching, this extension is worth installing. For benchmarks, please visit the Header caching thread
Create a file in application/libraries named MY_Output.php ( as described in the user guide ) and copy/paste the following code:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* MY_Output
*
* Modified _write_cache and _display_cache to allow for header caching
* works with CodeIgniter 1.7.0
*
* @package CodeIgniter
* @subpackage Libraries
* @category Output
* @author Arjen van Bochoven
* @link http://codeigniter.com/wiki/Cache_headers
*/
class MY_Output extends CI_Output {
// --------------------------------------------------------------------
/**
* Write a Cache File
*
* @access public
* @return void
*/
function _write_cache($output)
{
$CI =& get_instance();
$path = $CI->config->item('cache_path');
$cache_path = ($path == '') ? BASEPATH.'cache/' : $path;
if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
{
return;
}
$uri = $CI->config->item('base_url').
$CI->config->item('index_page').
$CI->uri->uri_string();
$cache_path .= md5($uri);
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);
if (flock($fp, LOCK_EX))
{
fwrite($fp, serialize(array('exp' => $expire, 'headers' => $this->headers, 'output' => $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, DIR_WRITE_MODE);
log_message('debug', "Cache file written: ".$cache_path);
}
// --------------------------------------------------------------------
/**
* Update/serve a cached file
*
* @access public
* @return void
*/
function _display_cache(&$CFG, &$URI)
{
$cache_path = ($CFG->item('cache_path') == '') ? BASEPATH.'cache/' : $CFG->item('cache_path');
if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
{
return FALSE;
}
// 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))
{
return FALSE;
}
if ( ! $fp = @fopen($filepath, FOPEN_READ))
{
return FALSE;
}
flock($fp, LOCK_SH);
$cache = '';
if (filesize($filepath) > 0)
{
$cache = fread($fp, filesize($filepath));
}
flock($fp, LOCK_UN);
fclose($fp);
// Restore the cache array
$cache = unserialize($cache);
// Validate cache file
if ( ! isset($cache['exp'] ) OR ! isset($cache['headers']) OR ! isset($cache['output']))
{
return FALSE;
}
// Has the file expired? If so we'll delete it.
if (time() >= trim($cache['exp']))
{
@unlink($filepath);
log_message('debug', "Cache file has expired. File deleted");
return FALSE;
}
// Restore headers
$this->headers = $cache['headers'];
// Display the cache
$this->_display($cache['output']);
log_message('debug', "Cache file is current. Sending it to browser.");
return TRUE;
}
}