[eluser]Patrick Savalle[/eluser]
I needed the output caching to save the HTTP headers (serving JSON and XML from views). Currently CI does not save these headers in the cache. A modification is very simple. I hacked it into the system files. If you're not as lazy as me you could place these functions in a application/core/CI_Output.php override.
Two functions need to be overriden. These are the new versions.
(I also added LZF compression but did not test that. As I said: I'm lazy. The caching however works and now does save the headers with the cached file.)
In
system/core/output.php
Code:
// --------------------------------------------------------------------
/**
* Write a Cache File
*
* @access public
* @return void
*/
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 );
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 ) )
{
$cache = serialize( array( $expire, $this->headers, $output ) );
if ( function_exists( 'lzf_decompress' ) && function_exists( 'lzf_compress' ) )
{
$cache = lzf_compress( $cache );
}
fwrite( $fp, $cache );
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 );
}
// --------------------------------------------------------------------
/**
* Update/serve a cached file
*
* @access public
* @return void
*/
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 ) )
{
return FALSE;
}
if ( !$fp = @fopen( $filepath, FOPEN_READ ) )
{
return FALSE;
}
flock( $fp, LOCK_SH );
$cache = NULL;
if ( filesize( $filepath ) > 0 )
{
$cache = fread( $fp, filesize( $filepath ) );
}
flock( $fp, LOCK_UN );
fclose( $fp );
if ( function_exists( 'lzf_decompress' ) && function_exists( 'lzf_compress' ) )
{
$cache = lzf_decompress( $cache );
}
list( $expire, $headers, $output ) = unserialize( $cache );
// Has the file expired? If so we'll delete it.
if ( time( ) >= $expire )
{
if ( is_really_writable( $cache_path ) )
{
@unlink( $filepath );
log_message( 'debug', "Cache file has expired. File deleted" );
return FALSE;
}
}
// Output the headers
if ( count( $headers ) > 0 )
{
foreach ( $headers as $header )
{
header( $header[0], $header[1] );
}
}
// Display the cache
$this->_display( $output );
log_message( 'debug', "Cache file is current. Sending it to browser." );
return TRUE;
}