PHP Classes
elePHPant
Icontem

File: MultiCacheFile.class.php

Recommend this page to a friend!
  Classes of V  >  MultiCache library  >  MultiCacheFile.class.php  >  Download  
File: MultiCacheFile.class.php
Role: Class source
Content type: text/plain
Description: MultiCacheFile class
Class: MultiCache library
Cache data in files or memcached
Author: By
Last change: changed
Date: 5 months ago
Size: 6,411 bytes
 

Contents

Class file image Download
<?php
/**
 * MultiCache class class provides a convenient way to work with caches.
 * MultiCacheFile is a class for work with file system storage.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 */
class MultiCacheFile extends MultiCache {
   
/**
     * File cache directory.
     *
     * @var string
     */
   
public $cachedir = 'cache';

   
/**
     * Number of cache subderictories.
     *
     * @var string
     */
   
public $subdircount = 1;

   
/**
     * Length of cache subderictories.
     *
     * @var string
     */
   
public $subdirlength = 2;

   
/**
     * Cache statistics. The structure is: array(count, size).
     *
     * @var array Cache statistics
     */
   
private $stats = null;

   
/**
     * Gets data.
     *
     * @param mixed $key The key that will be associated with the item.
     * @param mixed $default Default value.
     *
     * @return mixed Stored data.
     */
   
public function get($key, $default = null) {
       
// Get file name
       
$fname = $this->getPathByKey($key);

       
// Read file
       
if (($data = @file_get_contents($fname)) && ($data = @unserialize($data))) {
            list(
$value, $expire) = $data;

            if (
$expire > 0 && $expire < time()) {
               
$this->remove($key);
            } else {
                return
$value;
            }
        }

        return
$default;
    }

   
/**
     * Stores data.
     * If expiration time set in seconds it must be not greater then 2592000 (30 days).
     *
     * @param string $key The key that will be associated with the item.
     * @param mixed $value The variable to store.
     * @param integer $expire Expiration time of the item. Unix timestamp
     * or number of seconds.
     */
   
public function set($key, $value, $expire = null) {
       
parent::set($key, $value, $expire);

       
// Get file name
       
$fname = $this->getPathByKey($key, true);
        if (
$expire > 0 && $expire <= 2592000) {
           
$expire = time() + $expire;
        }

       
// Create file and save new data
       
if (!($fh = fopen($fname, 'wb'))) {
            throw new
Exception("File $fname not created!");
        }

       
flock($fh, LOCK_EX);
       
fwrite($fh, serialize(array($value, $expire)));
       
flock($fh, LOCK_UN);
       
fclose($fh);
    }

   
/**
     * Removes data from the cache.
     *
     * @param string $key The key that will be associated with the item.
     */
   
public function remove($key) {
       
// Get file name
       
$fname = $this->getPathByKey($key);

       
// Delete file
       
if (is_file($fname)) {
            if (!
unlink($fname)) {
                throw new
Exception("File $fname not deleted!");
            }

            if (
$this->stats && $this->stats[0] > 0) {
               
$this->stats[0]--;
            }
        }
    }

   
/**
     * Removes all cached data.
     */
   
public function removeAll() {
       
self::rmdir($this->cachedir);
       
$this->stats = null;
    }

   
/**
     * Cleans expired cached data.
     */
   
public function clean() {
        foreach (new
RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cachedir)) as $file) {
           
$this->get(@base64_decode(basename($file)));
        }

       
$this->stats = null;
    }

   
/**
     * Gets items count.
     *
     * @return integer Items count.
     */
   
public function getItemsCount() {
        if (
$this->stats != null) {
           
$this->stats = $this->getStats();
        }
        return
$this->stats[0];
    }

   
/**
     * Gets cached data size.
     *
     * @return integer Cache size, bytes.
     */
   
public function getSize() {
        if (
$this->stats != null) {
           
$this->stats = $this->getStats();
        }
        return
$this->stats[1];
    }

   
/**
     * Gets cache statistics.
     *
     * @return array Cache statistics.
     */
   
private function getStats() {
       
$cnt = 0;
       
$size = 0;

        foreach (new
RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cachedir)) as $file) {
           
$cnt++;
           
$size += filesize($file);
        }

        return array(
$cnt, $size);
    }

   
/**
     * Removes all files and subdirectories.
     *
     * @param string $dir Directory name.
     */
   
private static function rmdir($dir) {
       
$dir = new RecursiveDirectoryIterator($dir);
        foreach (new
RecursiveIteratorIterator($dir) as $file) {
            @
unlink($file);
        }
        foreach(
$dir as $subDir) {
            if(!@
rmdir($subDir)) {
               
self::rmdir($subDir);
                @
rmdir($subDir);
            }
        }
    }

   
/**
     * Gets file path by key.
     *
     * @param string $key The key that will be associated with the item.
     * @param boolean $ismkdir If true this function creates new subdirectories.
     *
     * @return string File path.
     */
   
private function getPathByKey($key, $ismkdir = false) {
       
$fname = $fcode = base64_encode($key);

        if (
strlen($fname) > 250) {
            throw new
Exception("Hash for key [$key] is bigger then 250 characters!");
        }

       
$dir = $this->cachedir;
       
$len = $this->subdirlength;

        for (
$i = $this->subdircount; $i > 0; $i--) {
           
$dcode = substr($fcode, 0, $len);

            if (
strlen($dcode) < $len) {
                break;
            }

           
$dir .= "/$dcode";

            if (
$ismkdir && !is_dir($dir) && !mkdir($dir, 0777)) {
                throw new
Exception("Directory $dir not created!");
            }

           
$fcode = substr($fcode, $len);
        }

        return
"$dir/$fname";
    }
}