<?php
/**
 * Класс кеша.
 * Отвечает за кеширование результатов выполнения действий.
 *
 * @copyright NetMonsters <team@netmonsters.ru>
 * @link
 * @package Majestic
 * @subpackage Cache
 * @since
 * @version SVN: $Id$
 * @filesource $URL$
 */
final class Cache
{
    private $cache_file;
    private $cache_folder;
    private $cache_time;

    private $mode = 0777;
    private $infofile = '_infofile';

    const HASH_ENABLE = true;

    function __construct($cache_name, $cache_time)
    {
        if (!preg_match('/[a-zA-Z0-9_]/', $cache_name)) {
            throw new MJException('Wrong cache identifier "'.$cache_name.'". Must use only [a-zA-Z0-9_]');
        }

        if ($cache_name == $this->infofile) {
            throw new MJException('Name "'.$this->infofile.'" is reserved. Try another one.');
        }

        if ($cache_time == 0) {
            throw new MJException('cache_time must be non-zero');
        }

        if ($cache_time > 86400) {
            throw new MJException('cache_time cannot be greater than 86400 sec (24 hours)');
        }

        if (substr($cache_name, 0, 1) == '_') {
            $this->cache_folder = CACHE_PATH;
        } else {
            $parts = explode('_', $cache_name, 2);
            $this->cache_folder = CACHE_PATH.'/'.(isset($parts[1]) ? $parts[0] : '_all');
            if (self::HASH_ENABLE) {
                $hash = md5($cache_name);
                $this->cache_folder .= '/'.substr($hash, 0, 1).'/'.substr($hash, 0, 2);
            }
        }

        $this->cache_file = $this->cache_folder.'/'.$cache_name;
        if (!is_writable($this->cache_folder)) {
            mkdir($this->cache_folder, $this->mode, true);
        }

        $this->cache_time = (int) $cache_time;
    }

    /**
     * Сохраняет кэш в файл
     *
     * @param string/array $data - строка (либо одномерный массив) сохраняемых данных
     * @return boolean - сохранил или нет
     */
    function save($data)
    {
        if ($this->cache_time != 0 && is_writable($this->cache_folder)) {
            $this->clearOld(); //очистка старых файлов.
            // а был-ли кеш?
            $exists = file_exists($this->cache_file);
            $result = file_put_contents($this->cache_file, $data);
            // если не существовал кеш - выставляем корректные права на него.
            if ($result && !$exists) {
                chmod($this->cache_file, 0664);
            }
            return (bool)$result;
        }
        return false;
    }

    /**
     * Достает кэш из файла
     *
     * @return string - содержимое кеша
     */
    function load()
    {
        if ($this->cache_time != 0) {
            return file_get_contents($this->cache_file);
        }
        return false;
    }

    /**
    * Принудительно очистить кеш
    *
    */
    function reset()
    {
        @unlink($this->cache_file);
    }

    /**
    * Проверяет, закешированы ли данные с таким именем
    *
    * @return boolean - закеширован или нет
    */
    function isCached()
    {
        if (is_readable($this->cache_file)) {
            if ($this->cache_time < 0 || $this->cache_time + filemtime($this->cache_file) > time()) {
                return true;
            }
            $this->reset(); //удалим просроченый файл
        }
        return false;
    }

    /**
    * Удаление файлов старше суток
    *
    */
    function clearOld()
    {
        $file = CACHE_PATH . '/' . $this->infofile;
        if (!file_exists($file) || date('Ymd', filemtime($file)) != date('Ymd')) {
            exec('find ' . CACHE_PATH . '/ -type f \! -path "*.svn*" -mtime +1 -delete'); //не удаляет папки сохраняя структуру
            touch($file);
        }
    }
}

?>