Modules

Kohana_Cache_File
extends Cache
extends Kohana_Cache

Implements: Cache_GarbageCollect | Kohana_Cache_GarbageCollect

This class is a transparent base class for Cache_File and should not be accessed directly.

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 [
    // File driver group
    'file' => [
        // Using File driver
        'driver' => 'file',
        // Cache location
        'cache_dir' => APPPATH . 'cache/.kohana_cache',
    ],
];

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
© 2009-2012 Kohana Team
license
https://kohana.top/license

Class declared in MODPATH/cache/classes/Kohana/Cache/File.php on line 45.

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 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)
{
    $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()
{
    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->_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)
{
    $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;
    } catch (RuntimeException $e) {
        // Catch RuntimeException when cache file deleted between isFile and openFile
        return $default;
    }
}

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)
{
    $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(['driver' => 'memcache', '...']);

// Set a new configuration setting
$cache->config('servers', ['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
    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 __construct( array $config ) (defined in Kohana_Cache_File)

Constructs the file cache driver. This method cannot be invoked externally. The file cache driver must be instantiated using the Cache::instance() method.

Parameters

  • array $config required - Config

Tags

Source Code

protected function __construct(array $config)
{
    // Setup parent
    parent::__construct($config);

    try {
        $directory = Arr::get($this->_config, 'cache_dir', Kohana::$cache_dir);
        $this->_cache_dir = new SplFileInfo($directory);
    }
    // PHP < 5.3 exception handle
    catch (ErrorException $e) {
        $this->_cache_dir = $this->_make_directory($directory, 0777, true);
    }
    // PHP >= 5.3 exception handle
    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()]);
    }
}

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 _sanitize_id( string $id ) (defined in Kohana_Cache)

Replaces troublesome characters with underscores.

// 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)
{
    // Change slashes and spaces to underscores
    return str_replace(['/', '\\', ' '], '_', $id);
}