Modules

HTTP_Cache
extends Kohana_HTTP_Cache

HTTT Caching adaptor class that provides caching services to the Request_Client class, using HTTP cache control logic as defined in RFC 2616.

package
Kohana
category
Base
author
Kohana Team
copyright
© 2008-2012 Kohana Team
license
http://kohanaframework.org/license
since
3.2.0

Class declared in SYSPATH/classes/http/cache.php on line 3.

Constants

CACHE_STATUS_KEY

string(14) "x-cache-status"

CACHE_STATUS_SAVED

string(5) "SAVED"

CACHE_STATUS_HIT

string(3) "HIT"

CACHE_STATUS_MISS

string(4) "MISS"

CACHE_HIT_KEY

string(12) "x-cache-hits"

Properties

protected boolean $_allow_private_cache

Defines whether this client should cache private cache directives

protected Cache $_cache

cache driver to use for HTTP caching

protected callback $_cache_key_callback

Cache key generator callback

protected int $_request_time

The timestamp of the request

protected int $_response_time

The timestamp of the response

Methods

public __construct( [ array $options = array(0) ] ) (defined in Kohana_HTTP_Cache)

Constructor method for this class. Allows dependency injection of the required components such as Cache and the cache key generator.

Parameters

  • array $options = array(0) -

Source Code

public function __construct(array $options = array())
{
	foreach ($options as $key => $value)
	{
		if (method_exists($this, $key))
		{
			$this->$key($value);
		}
	}

	if ($this->_cache_key_callback === NULL)
	{
		$this->cache_key_callback('HTTP_Cache::basic_cache_key_generator');
	}
}

public allow_private_cache( [ boolean $setting = NULL ] ) (defined in Kohana_HTTP_Cache)

Gets or sets the Request_Client::allow_private_cache setting. If set to TRUE, the client will also cache cache-control directives that have the private setting.

Parameters

  • boolean $setting = NULL - Allow caching of privately marked responses

Tags

Return Values

  • boolean
  • [Request_Client]

Source Code

public function allow_private_cache($setting = NULL)
{
	if ($setting === NULL)
		return $this->_allow_private_cache;

	$this->_allow_private_cache = (bool) $setting;
	return $this;
}

public static basic_cache_key_generator( Request $request ) (defined in Kohana_HTTP_Cache)

Basic cache key generator that hashes the entire request and returns it. This is fine for static content, or dynamic content where user specific information is encoded into the request.

 // Generate cache key
 $cache_key = HTTP_Cache::basic_cache_key_generator($request);

Parameters

  • Request $request required - $request

Return Values

  • string

Source Code

public static function basic_cache_key_generator(Request $request)
{
	$uri     = $request->uri();
	$query   = $request->query();
	$headers = $request->headers()->getArrayCopy();
	$body    = $request->body();

	return sha1($uri.'?'.http_build_query($query, NULL, '&').'~'.implode('~', $headers).'~'.$body);
}

public cache( [ Kohana_Cache $cache = NULL ] ) (defined in Kohana_HTTP_Cache)

Getter and setter for the internal caching engine, used to cache responses if available and valid.

Parameters

  • Kohana_Cache $cache = NULL - Engine to use for caching

Return Values

  • Kohana_Cache
  • Kohana_Request_Client

Source Code

public function cache(Cache $cache = NULL)
{
	if ($cache === NULL)
		return $this->_cache;

	$this->_cache = $cache;
	return $this;
}

public cache_key_callback( [ callback $callback = NULL ] ) (defined in Kohana_HTTP_Cache)

Sets or gets the cache key generator callback for this caching class. The cache key generator provides a unique hash based on the Request object passed to it.

The default generator is HTTP_Cache::basic_cache_key_generator(), which serializes the entire HTTP_Request into a unique sha1 hash. This will provide basic caching for static and simple dynamic pages. More complex algorithms can be defined and then passed into HTTP_Cache using this method.

 // Get the cache key callback
 $callback = $http_cache->cache_key_callback();

 // Set the cache key callback
 $http_cache->cache_key_callback('Foo::cache_key');

 // Alternatively, in PHP 5.3 use a closure
 $http_cache->cache_key_callback(function (Request $request) {
       return sha1($request->render());
 });

Parameters

  • callback $callback = NULL - $callback

Tags

Return Values

  • mixed

Source Code

public function cache_key_callback($callback = NULL)
{
	if ($callback === NULL)
		return $this->_cache_key_callback;

	if ( ! is_callable($callback))
		throw new HTTP_Exception('cache_key_callback must be callable!');

	$this->_cache_key_callback = $callback;
	return $this;
}

public cache_lifetime( Response $response ) (defined in Kohana_HTTP_Cache)

Calculates the total Time To Live based on the specification RFC 2616 cache lifetime rules.

Parameters

  • Response $response required - Response to evaluate

Return Values

  • mixed - TTL value or false if the response should not be cached

Source Code

public function cache_lifetime(Response $response)
{
	// Get out of here if this cannot be cached
	if ( ! $this->set_cache($response))
		return FALSE;

	// Calculate apparent age
	if ($date = $response->headers('date'))
	{
		$apparent_age = max(0, $this->_response_time - strtotime($date));
	}
	else
	{
		$apparent_age = max(0, $this->_response_time);
	}

	// Calculate corrected received age
	if ($age = $response->headers('age'))
	{
		$corrected_received_age = max($apparent_age, intval($age));
	}
	else
	{
		$corrected_received_age = $apparent_age;
	}

	// Corrected initial age
	$corrected_initial_age = $corrected_received_age + $this->request_execution_time();

	// Resident time
	$resident_time = time() - $this->_response_time;

	// Current age
	$current_age = $corrected_initial_age + $resident_time;

	// Prepare the cache freshness lifetime
	$ttl = NULL;

	// Cache control overrides
	if ($cache_control = $response->headers('cache-control'))
	{
		// Parse the cache control header
		$cache_control = HTTP_Header::parse_cache_control($cache_control);

		if (isset($cache_control['max-age']))
		{
			$ttl = $cache_control['max-age'];
		}

		if (isset($cache_control['s-maxage']) AND isset($cache_control['private']) AND $this->_allow_private_cache)
		{
			$ttl = $cache_control['s-maxage'];
		}

		if (isset($cache_control['max-stale']) AND ! isset($cache_control['must-revalidate']))
		{
			$ttl = $current_age + $cache_control['max-stale'];
		}
	}

	// If we have a TTL at this point, return
	if ($ttl !== NULL)
		return $ttl;

	if ($expires = $response->headers('expires'))
		return strtotime($expires) - $current_age;

	return FALSE;
}

public cache_response( string $key , Request $request [, Response $response = NULL ] ) (defined in Kohana_HTTP_Cache)

Caches a Response using the supplied Cache and the key generated by Request_Client::_create_cache_key.

If not response is supplied, the cache will be checked for an existing one that is available.

Parameters

  • string $key required - The cache key to use
  • Request $request required - The HTTP Request
  • Response $response = NULL - The HTTP Response

Return Values

  • mixed

Source Code

public function cache_response($key, Request $request, Response $response = NULL)
{
	if ( ! $this->_cache instanceof Cache)
		return FALSE;

	// Check for Pragma: no-cache
	if ($pragma = $request->headers('pragma'))
	{
		if ($pragma  == 'no-cache')
			return FALSE;
		elseif (is_array($pragma) AND in_array('no-cache', $pragma))
			return FALSE;
	}

	// If there is no response, lookup an existing cached response
	if ($response === NULL)
	{
		$response = $this->_cache->get($key);

		if ( ! $response instanceof Response)
			return FALSE;

		// Do cache hit arithmetic, using fast arithmetic if available
		if ($this->_cache instanceof Cache_Arithmetic)
		{
			$hit_count = $this->_cache->increment(HTTP_Cache::CACHE_HIT_KEY.$key);
		}
		else
		{
			$hit_count = $this->_cache->get(HTTP_Cache::CACHE_HIT_KEY.$key);
			$this->_cache->set(HTTP_Cache::CACHE_HIT_KEY.$key, ++$hit_count);
		}

		// Update the header to have correct HIT status and count
		$response->headers(HTTP_Cache::CACHE_STATUS_KEY,
			HTTP_Cache::CACHE_STATUS_HIT)
			->headers(HTTP_Cache::CACHE_HIT_KEY, $hit_count);

		return $response;
	}
	else
	{
		if (($ttl = $this->cache_lifetime($response)) === FALSE)
			return FALSE;

		$response->headers(HTTP_Cache::CACHE_STATUS_KEY,
			HTTP_Cache::CACHE_STATUS_SAVED);

		// Set the hit count to zero
		$this->_cache->set(HTTP_Cache::CACHE_HIT_KEY.$key, 0);

		return $this->_cache->set($key, $response, $ttl);
	}
}

public create_cache_key( Request $request [, callback $callback = bool FALSE ] ) (defined in Kohana_HTTP_Cache)

Creates a cache key for the request to use for caching Kohana_Response returned by Request::execute.

This is the default cache key generating logic, but can be overridden by setting HTTP_Cache::cache_key_callback().

Parameters

  • Request $request required - Request to create key for
  • callback $callback = bool FALSE - Optional callback to use instead of built-in method

Return Values

  • string

Source Code

public function create_cache_key(Request $request, $callback = FALSE)
{
	if (is_callable($callback))
		return call_user_func($callback, $request);
	else
		return HTTP_Cache::basic_cache_key_generator($request);
}

public execute( Request_Client $client , Request $request ) (defined in Kohana_HTTP_Cache)

Executes the supplied Request with the supplied Request_Client. Before execution, the HTTP_Cache adapter checks the request type, destructive requests such as POST, PUT and DELETE will bypass cache completely and ensure the response is not cached. All other Request methods will allow caching, if the rules are met.

Parameters

  • Request_Client $client required - Client to execute with Cache-Control
  • Request $request required - Request to execute with client

Return Values

  • [Response]

Source Code

public function execute(Request_Client $client, Request $request)
{
	if ( ! $this->_cache instanceof Cache)
		return $client->execute_request($request);

	// If this is a destructive request, by-pass cache completely
	if (in_array($request->method(), array(
		HTTP_Request::POST, 
		HTTP_Request::PUT, 
		HTTP_Request::DELETE)))
	{
		// Kill existing caches for this request
		$this->invalidate_cache($request);

		$response = $client->execute_request($request);

		$cache_control = HTTP_Header::create_cache_control(array(
			'no-cache',
			'must-revalidate'
		));

		// Ensure client respects destructive action
		return $response->headers('cache-control', $cache_control);
	}

	// Create the cache key
	$cache_key = $this->create_cache_key($request, $this->_cache_key_callback);

	// Try and return cached version
	if (($response = $this->cache_response($cache_key, $request)) instanceof Response)
		return $response;

	// Start request time
	$this->_request_time = time();

	// Execute the request with the Request client
	$response = $client->execute_request($request);

	// Stop response time
	$this->_response_time = (time() - $this->_request_time);

	// Cache the response
	$this->cache_response($cache_key, $request, $response);

	$response->headers(HTTP_Cache::CACHE_STATUS_KEY, 
		HTTP_Cache::CACHE_STATUS_MISS);

	return $response;
}

public static factory( mixed $cache [, array $options = array(0) ] ) (defined in Kohana_HTTP_Cache)

Factory method for HTTP_Cache that provides a convenient dependency injector for the Cache library.

 // Create HTTP_Cache with named cache engine
 $http_cache = HTTP_Cache::factory('memcache', array(
     'allow_private_cache' => FALSE
     )
 );

 // Create HTTP_Cache with supplied cache engine
 $http_cache = HTTP_Cache::factory(Cache::instance('memcache'),
     array(
         'allow_private_cache' => FALSE
     )
 );

Parameters

  • mixed $cache required - Cache engine to use
  • array $options = array(0) - Options to set to this class

Tags

  • Uses - [Cache]

Return Values

  • HTTP_Cache

Source Code

public static function factory($cache, array $options = array())
{
	if ( ! $cache instanceof Cache)
	{
		$cache = Cache::instance($cache);
	}

	$options['cache'] = $cache;

	return new HTTP_Cache($options);
}

public invalidate_cache( Request $request ) (defined in Kohana_HTTP_Cache)

Invalidate a cached response for the Request supplied. This has the effect of deleting the response from the Cache entry.

Parameters

  • Request $request required - Response to remove from cache

Return Values

  • void

Source Code

public function invalidate_cache(Request $request)
{
	if (($cache = $this->cache()) instanceof Cache)
	{
		$cache->delete($this->create_cache_key($request, $this->_cache_key_callback));
	}

	return;
}

public request_execution_time( ) (defined in Kohana_HTTP_Cache)

Returns the duration of the last request execution. Either returns the time of completed requests or FALSE if the request hasn't finished executing, or is yet to be run.

Return Values

  • mixed

Source Code

public function request_execution_time()
{
	if ($this->_request_time === NULL OR $this->_response_time === NULL)
		return FALSE;

	return $this->_response_time - $this->_request_time;
}

public set_cache( Response $response ) (defined in Kohana_HTTP_Cache)

Controls whether the response can be cached. Uses HTTP protocol to determine whether the response can be cached.

Parameters

  • Response $response required - The Response

Tags

Return Values

  • boolean

Source Code

public function set_cache(Response $response)
{
	$headers = $response->headers()->getArrayCopy();

	if ($cache_control = Arr::get($headers, 'cache-control'))
	{
		// Parse the cache control
		$cache_control = HTTP_Header::parse_cache_control($cache_control);

		// If the no-cache or no-store directive is set, return
		if (array_intersect($cache_control, array('no-cache', 'no-store')))
			return FALSE;

		// Check for private cache and get out of here if invalid
		if ( ! $this->_allow_private_cache AND in_array('private', $cache_control))
		{
			if ( ! isset($cache_control['s-maxage']))
				return FALSE;

			// If there is a s-maxage directive we can use that
			$cache_control['max-age'] = $cache_control['s-maxage'];
		}

		// Check that max-age has been set and if it is valid for caching
		if (isset($cache_control['max-age']) AND $cache_control['max-age'] < 1)
			return FALSE;
	}

	if ($expires = Arr::get($headers, 'expires') AND ! isset($cache_control['max-age']))
	{
		// Can't cache things that have expired already
		if (strtotime($expires) <= time())
			return FALSE;
	}

	return TRUE;
}