Class Cache_File

Cache_File

extends Kohana_Cache_File
extends Cache
extends Kohana_Cache

Implements: Kohana_Cache_GarbageCollect | Cache_GarbageCollect

Kohana Cache File driver. Provides a file based driver for the Kohana Cache library. This is one of the slowest caching methods.

Configuration example

Below is an example of a file server configuration.

return array(
     'file'   => array(                          // File driver group
             'driver'         => 'file',         // using File driver
             'cache_dir'     => APPPATH.'cache/.kohana_cache', // Cache location
      ),
)

In cases where only one cache group is required, if the group is named default there is no need to pass the group name when instantiating a cache instance.

General cache group configuration settings

Below are the settings available to all types of cache driver.

Name Required Description
driver YES (string) The driver type to use
cache_dir NO (string) The cache directory to use for this cache instance

System requirements

  • Kohana 3.0.x
  • PHP 5.2.4 or greater

package
Kohana/Cache
category
Base
author
Kohana Team
copyright
(c) Kohana Team
license
https://koseven.ga/LICENSE.md


Information

This class is a transparent base class for Kohana_Cache_File

Constants

DEFAULT_EXPIRE

integer 3600

Properties

public static string $default

default driver to use

string(4) "file"

public static Kohana_Cache $instances

instances

array(0) 

protected string $_cache_dir

the caching directory

Default value:
NULL

protected boolean $_cache_dir_usable

does the cache directory exists and writeable

Default value:
bool FALSE

protected Config $_config

Default value:
array(0) 

Methods

public delete(string $id ) (defined in Kohana_Cache_File)

Delete a cache entry based on id

// Delete 'foo' entry from the file group
Cache::instance('file')->delete('foo');

Parameters

  • string $id required - Id to remove from cache

Return Values

  • boolean

Source Code

public function delete($id)
{
	$this->_cache_dir_usable or $this->_check_cache_dir();

	$filename = Cache_File::filename($this->_sanitize_id($id));
	$directory = $this->_resolve_directory($filename);

	return $this->_delete_file(new SplFileInfo($directory.$filename), FALSE, TRUE);
}

public delete_all() (defined in Kohana_Cache_File)

Delete all cache entries.

Beware of using this method when using shared memory cache systems, as it will wipe every entry within the system for all clients.

// Delete all cache entries in the file group
Cache::instance('file')->delete_all();

Return Values

  • boolean

Source Code

public function delete_all()
{
	$this->_cache_dir_usable or $this->_check_cache_dir();

	return $this->_delete_file($this->_cache_dir, TRUE);
}

public garbage_collect() (defined in Kohana_Cache_File)

Garbage collection method that cleans any expired cache entries from the cache.

Return Values

  • void

Source Code

public function garbage_collect()
{
	$this->_cache_dir_usable or $this->_check_cache_dir();

	$this->_delete_file($this->_cache_dir, TRUE, FALSE, TRUE);
	return;
}

public get(string $id [, string $default = NULL ] ) (defined in Kohana_Cache_File)

Retrieve a cached value entry by id.

// Retrieve cache entry from file group
$data = Cache::instance('file')->get('foo');

// Retrieve cache entry from file group and return 'bar' if miss
$data = Cache::instance('file')->get('foo', 'bar');

Parameters

  • string $id required - Id of cache to entry
  • string $default = NULL - Default value to return if cache miss

Tags

Return Values

  • mixed

Source Code

public function get($id, $default = NULL)
{
	$this->_cache_dir_usable or $this->_check_cache_dir();

	$filename = Cache_File::filename($this->_sanitize_id($id));
	$directory = $this->_resolve_directory($filename);

	// Wrap operations in try/catch to handle notices
	try
	{
		// Open file
		$file = new SplFileInfo($directory.$filename);

		// If file does not exist
		if ( ! $file->isFile())
		{
			// Return default value
			return $default;
		}
		else
		{
			// Test the expiry
			if ($this->_is_expired($file))
			{
				// Delete the file
				$this->_delete_file($file, FALSE, TRUE);
				return $default;
			}

			// open the file to read data
			$data = $file->openFile();

			// Run first fgets(). Cache data starts from the second line
			// as the first contains the lifetime timestamp
			$data->fgets();

			$cache = '';

			while ($data->eof() === FALSE)
			{
				$cache .= $data->fgets();
			}

			return unserialize($cache);
		}

	}
	catch (ErrorException $e)
	{
		// Handle ErrorException caused by failed unserialization
		if ($e->getCode() === E_NOTICE)
		{
			throw new Cache_Exception(__METHOD__.' failed to unserialize cached object with message : '.$e->getMessage());
		}

		// Otherwise throw the exception
		throw $e;
	}
}

public set(string $id , string $data [, integer $lifetime = NULL ] ) (defined in Kohana_Cache_File)

Set a value to cache with id and lifetime

$data = 'bar';

// Set 'bar' to 'foo' in file group, using default expiry
Cache::instance('file')->set('foo', $data);

// Set 'bar' to 'foo' in file group for 30 seconds
Cache::instance('file')->set('foo', $data, 30);

Parameters

  • string $id required - Id of cache entry
  • string $data required - Data to set to cache
  • integer $lifetime = NULL - Lifetime in seconds

Return Values

  • boolean

Source Code

public function set($id, $data, $lifetime = NULL)
{
	$this->_cache_dir_usable or $this->_check_cache_dir();

	$filename = Cache_File::filename($this->_sanitize_id($id));
	$directory = $this->_resolve_directory($filename);

	// If lifetime is NULL
	if ($lifetime === NULL)
	{
		// Set to the default expiry
		$lifetime = Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE);
	}

	// Open directory
	$dir = new SplFileInfo($directory);

	// If the directory path is not a directory
	if ( ! $dir->isDir())
	{
		$this->_make_directory($directory, 0777, TRUE);
	}

	// Open file to inspect
	$resouce = new SplFileInfo($directory.$filename);
	$file = $resouce->openFile('w');

	try
	{
		$data = $lifetime."\n".serialize($data);
		$file->fwrite($data, strlen($data));
		return (bool) $file->fflush();
	}
	catch (ErrorException $e)
	{
		// If serialize through an error exception
		if ($e->getCode() === E_NOTICE)
		{
			// Throw a caching error
			throw new Cache_Exception(__METHOD__.' failed to serialize data for caching with message : '.$e->getMessage());
		}

		// Else rethrow the error exception
		throw $e;
	}
}

final public __clone() (defined in Kohana_Cache)

Overload the __clone() method to prevent cloning

Tags

Return Values

  • void

Source Code

final public function __clone()
{
	throw new Cache_Exception('Cloning of Kohana_Cache objects is forbidden');
}

public config([ mixed $key = NULL , mixed $value = NULL ] ) (defined in Kohana_Cache)

Getter and setter for the configuration. If no argument provided, the current configuration is returned. Otherwise the configuration is set to this class.

// Overwrite all configuration
$cache->config(array('driver' => 'memcache', '...'));

// Set a new configuration setting
$cache->config('servers', array(
     'foo' => 'bar',
     '...'
     ));

// Get a configuration setting
$servers = $cache->config('servers);

Parameters

  • mixed $key = NULL - Key to set to array, either array or config path
  • mixed $value = NULL - Value to associate with key

Return Values

  • mixed

Source Code

public function config($key = NULL, $value = NULL)
{
	if ($key === NULL)
		return $this->_config;

	if (is_array($key))
	{
		$this->_config = $key;
	}
	else
	{
		if ($value === NULL)
			return Arr::get($this->_config, $key);

		$this->_config[$key] = $value;
	}

	return $this;
}

public static instance([ string $group = NULL ] ) (defined in Kohana_Cache)

Creates a singleton of a Kohana Cache group. If no group is supplied the default cache group is used.

// Create an instance of the default group
$default_group = Cache::instance();

// Create an instance of a group
$foo_group = Cache::instance('foo');

// Access an instantiated group directly
$foo_group = Cache::$instances['default'];

Parameters

  • string $group = NULL - The name of the cache group to use [Optional]

Tags

Return Values

  • Cache

Source Code

public static function instance($group = NULL)
{
       // If there is no group supplied, try to get it from the config
       if ($group === NULL)
       {
           $group = Kohana::$config->load('cache.default');
       }

	// If there is no group supplied
	if ($group === NULL)
	{
		// Use the default setting
		$group = Cache::$default;
	}

	if (isset(Cache::$instances[$group]))
	{
		// Return the current group if initiated already
		return Cache::$instances[$group];
	}

	$config = Kohana::$config->load('cache');

	if ( ! $config->offsetExists($group))
	{
		throw new Cache_Exception(
			'Failed to load Kohana Cache group: :group',
			[':group' => $group]
		);
	}

	$config = $config->get($group);

	// Create a new cache type instance
	$cache_class = 'Cache_'.ucfirst($config['driver']);
	Cache::$instances[$group] = new $cache_class($config);

	// Return the instance
	return Cache::$instances[$group];
}

protected _check_cache_dir() (defined in Kohana_Cache_File)

Check that the cache directory exists and writeable. Attempts to create it if not exists.

Tags

Source Code

protected function _check_cache_dir()
{
	try
	{
		$directory = Arr::get($this->_config, 'cache_dir', Kohana::$cache_dir);
		$this->_cache_dir = new SplFileInfo($directory);
	}
	catch (UnexpectedValueException $e)
	{
		$this->_cache_dir = $this->_make_directory($directory, 0777, TRUE);
	}

	// If the defined directory is a file, get outta here
	if ($this->_cache_dir->isFile())
	{
		throw new Cache_Exception('Unable to create cache directory as a file already exists : :resource', [':resource' => $this->_cache_dir->getRealPath()]);
	}

	// Check the read status of the directory
	if ( ! $this->_cache_dir->isReadable())
	{
		throw new Cache_Exception('Unable to read from the cache directory :resource', [':resource' => $this->_cache_dir->getRealPath()]);
	}

	// Check the write status of the directory
	if ( ! $this->_cache_dir->isWritable())
	{
		throw new Cache_Exception('Unable to write to the cache directory :resource', [':resource' => $this->_cache_dir->getRealPath()]);
	}

	$this->_cache_dir_usable = TRUE;
}

protected _delete_file(SplFileInfo $file [, boolean $retain_parent_directory = bool FALSE , boolean $ignore_errors = bool FALSE , boolean $only_expired = bool FALSE ] ) (defined in Kohana_Cache_File)

Deletes files recursively and returns FALSE on any errors

// Delete a file or folder whilst retaining parent directory and ignore all errors
$this->_delete_file($folder, TRUE, TRUE);

Parameters

  • SplFileInfo $file required - File
  • boolean $retain_parent_directory = bool FALSE - Retain the parent directory
  • boolean $ignore_errors = bool FALSE - Ignore_errors to prevent all exceptions interrupting exec
  • boolean $only_expired = bool FALSE - Only expired files

Tags

Return Values

  • boolean

Source Code

protected function _delete_file(SplFileInfo $file, $retain_parent_directory = FALSE, $ignore_errors = FALSE, $only_expired = FALSE)
{
	// Allow graceful error handling
	try
	{
		// If is file
		if ($file->isFile())
		{
			try
			{
				// Handle ignore files
				if (in_array($file->getFilename(), $this->config('ignore_on_delete')))
				{
					$delete = FALSE;
				}
				// If only expired is not set
				elseif ($only_expired === FALSE)
				{
					// We want to delete the file
					$delete = TRUE;
				}
				// Otherwise...
				else
				{
					// Assess the file expiry to flag it for deletion
					$delete = $this->_is_expired($file);
				}

				// If the delete flag is set delete file
				if ($delete === TRUE)
					return unlink($file->getRealPath());
				else
					return FALSE;
			}
			catch (ErrorException $e)
			{
				// Catch any delete file warnings
				if ($e->getCode() === E_WARNING)
				{
					throw new Cache_Exception(__METHOD__.' failed to delete file : :file', [':file' => $file->getRealPath()]);
				}
			}
		}
		// Else, is directory
		elseif ($file->isDir())
		{
			// Create new DirectoryIterator
			$files = new DirectoryIterator($file->getPathname());

			// Iterate over each entry
			while ($files->valid())
			{
				// Extract the entry name
				$name = $files->getFilename();

				// If the name is not a dot
				if ($name != '.' AND $name != '..')
				{
					// Create new file resource
					$fp = new SplFileInfo($files->getRealPath());
					// Delete the file
					$this->_delete_file($fp, $retain_parent_directory, $ignore_errors, $only_expired);
				}

				// Move the file pointer on
				$files->next();
			}

			// If set to retain parent directory, return now
			if ($retain_parent_directory)
			{
				return TRUE;
			}

			try
			{
				// Remove the files iterator
				// (fixes Windows PHP which has permission issues with open iterators)
				unset($files);

				// Try to remove the parent directory
				return rmdir($file->getRealPath());
			}
			catch (ErrorException $e)
			{
				// Catch any delete directory warnings
				if ($e->getCode() === E_WARNING)
				{
					throw new Cache_Exception(__METHOD__.' failed to delete directory : :directory', [':directory' => $file->getRealPath()]);
				}
				throw $e;
			}
		}
		else
		{
			// We get here if a file has already been deleted
			return FALSE;
		}
	}
	// Catch all exceptions
	catch (Exception $e)
	{
		// If ignore_errors is on
		if ($ignore_errors === TRUE)
		{
			// Return
			return FALSE;
		}
		// Throw exception
		throw $e;
	}
}

protected _is_expired(SplFileInfo $file ) (defined in Kohana_Cache_File)

Test if cache file is expired

Parameters

  • SplFileInfo $file required - The cache file

Return Values

  • boolean - TRUE if expired false otherwise

Source Code

protected function _is_expired(SplFileInfo $file)
{
	// Open the file and parse data
	$created = $file->getMTime();
	$data = $file->openFile("r");
	$lifetime = (int) $data->fgets();

	// If we're at the EOF at this point, corrupted!
	if ($data->eof())
	{
		throw new Cache_Exception(__METHOD__ . ' corrupted cache file!');
	}

	//close file
	$data = null;

	// test for expiry and return
	return (($lifetime !== 0) AND ( ($created + $lifetime) < time()));
}

protected _make_directory(string $directory [, integer $mode = integer 511 , boolean $recursive = bool FALSE , resource $context = NULL ] ) (defined in Kohana_Cache_File)

Makes the cache directory if it doesn't exist. Simply a wrapper for mkdir to ensure DRY principles

Parameters

  • string $directory required - Directory path
  • integer $mode = integer 511 - Chmod mode
  • boolean $recursive = bool FALSE - Allows nested directories creation
  • resource $context = NULL - A stream context

Tags

Return Values

  • SplFileInfo

Source Code

protected function _make_directory($directory, $mode = 0777, $recursive = FALSE, $context = NULL)
{
	// call mkdir according to the availability of a passed $context param
	$mkdir_result = $context ?
		mkdir($directory, $mode, $recursive, $context) :
		mkdir($directory, $mode, $recursive);

	// throw an exception if unsuccessful
	if ( ! $mkdir_result)
	{
		throw new Cache_Exception('Failed to create the defined cache directory : :directory', [':directory' => $directory]);
	}

	// chmod to solve potential umask issues
	chmod($directory, $mode);

	return new SplFileInfo($directory);
}

protected _resolve_directory(string $filename ) (defined in Kohana_Cache_File)

Resolves the cache directory real path from the filename

 // Get the realpath of the cache folder
 $realpath = $this->_resolve_directory($filename);

Parameters

  • string $filename required - Filename to resolve

Return Values

  • string

Source Code

protected function _resolve_directory($filename)
{
	return $this->_cache_dir->getRealPath().DIRECTORY_SEPARATOR.$filename[0].$filename[1].DIRECTORY_SEPARATOR;
}

protected static filename(string $string ) (defined in Kohana_Cache_File)

Creates a hashed filename based on the string. This is used to create shorter unique IDs for each cache filename.

// Create the cache filename
$filename = Cache_File::filename($this->_sanitize_id($id));

Parameters

  • string $string required - String to hash into filename

Return Values

  • string

Source Code

protected static function filename($string)
{
	return sha1($string).'.cache';
}

protected __construct(array $config ) (defined in Kohana_Cache)

Ensures singleton pattern is observed, loads the default expiry

Parameters

  • array $config required - Configuration

Source Code

protected function __construct(array $config)
{
	$this->config($config);
}

protected _sanitize_id(string $id ) (defined in Kohana_Cache)

Replaces troublesome characters with underscores and adds prefix to avoid duplicates

// Sanitize a cache id
$id = $this->_sanitize_id($id);

Parameters

  • string $id required - Id of cache to sanitize

Return Values

  • string

Source Code

protected function _sanitize_id($id)
{

    // adding cache prefix to avoid duplicates
    $prefix = '';
    // configuration for the specific cache group
    if (isset($this->_config['prefix']) AND $this->_config['prefix'] !== NULL)
    {
        $prefix = $this->_config['prefix'];
    }
    // prefix general configuration cache
    else
    {
        $prefix = Kohana::$config->load('cache.prefix');
    }

    // sha1 the id makes sure name is not too long and has not any not allowed characters
    return $prefix.sha1($id);
}

Do you want to contribute to Koseven?

We need YOUR help!

This project is open source. What does this mean? YOU can help:
  • Found a bug? Report it on Github
  • Need a feature? Add it Here
  • Want to help? Join the Forum
Go to Github