Система кеширования

leosun

Новичок
Система кеширования

Простейшая система кеширования, может кому пригодится

PHP:
<?php
class ClassCache {

  // Настройки класса кеша
  public $config;
  // Флаг кешируется ли скрипт или нет
  public $cache;

  // Инициализация класса кеша
  function __construct($cache_dir=null,$cache_time=null){
	// Флаг создания кеша, по умолчанию он выключен,
	// т.е. кеш не будет создан
	$this->cache = 0;
	// Если директория с кешем не задата при инициализации
	// использовать имя директории поумолчанию
	if ($cache_dir === null)
	  $this->config->cache_dir = './cache';
	// иначе определить пользовательскую директорию для
	// храниния файлов кеша
	else $this->config->cache_dir = $cache_dir;
	// Если время кеширования не задато при инициализации
	// использовать время кеширования поумолчанию - 72 часа
	if ($cache_dir === null)
	  $this->config->cache_time = 259200;
	// иначе определить пользовательское время
	// храниния файлов кеша (причем время задается в часах)
	else $this->config->cache_time = $cache_time*60*60;
	// Проверим обращения к командам кеша
	$this->req_cache();
	// Начать сбор буфера вывода (перехват функций печати)
	ob_start();
  }

  // Обработка скрипта завершина можно выводить результат
  function __destruct() {
 	// Получить буфер вывода в переменную
	$buffer = ob_get_contents();
	// Очистить буфер вывода
	ob_end_clean();
	// Распечатать результат работы скрипта
	echo $buffer;
 	// Если нужно кешировать
	if ($this->cache === 1){
      // Путь к файлу кеша
      $query_str = preg_replace('#&?cl_cache=[0-9]#','',$_SERVER['QUERY_STRING']); // Удаляем служебные запросы к системе кеширования
	  $query_str = urlencode($query_str); // Если сайта динамический кешировать нужно по странице на запрос
      $script_name = $_SERVER['DOCUMENT_ROOT'].$this->config->cache_dir.$_SERVER['SCRIPT_NAME'].'_'.$query_str.'.html';
	  // Если файл с кешем найден - удалить его, он неактуальный
	  if (file_exists($script_name)) unlink($script_name);
	  // Время жизни кешпа
	  $dietime = time() + $this->config->cache_time;
	  // Информация о кеше
      $info_cache = serialize(array('dietime' => $dietime));
	  // Файл с кешем
	  $cache_file = null;
	  // Записать в файл длинну информационного массива
	  $cache_file .= (strlen($info_cache)+1)."\r\n";
	  // Записать в файл информационный массив
	  $cache_file .= $info_cache."\r\n";
	  // Записать в файл весь текст буфера вывода
      $cache_file .= $buffer;
      // Записать все содержимое в файл
      file_put_contents($script_name,$cache_file);
	}
  }

  // Обработка специальных команд в URL для кеширующей системы
  public function req_cache(){
    // Проверить все переменные переданные скрипту
    // одна из этих переменных может быть командой
    // для системы кеширования
	foreach ($_REQUEST as $key => $value){
	  // Найдена команда - очистить кеш
      if ($key === 'cl_cache') $this->cl_cache();
	}
  }

  // Принудительно очистить кеш
  public function cl_cache(){
    // Путь к файлу кеша
    $query_str = preg_replace('#&?cl_cache=[0-9]#','',$_SERVER['QUERY_STRING']); // Удаляем служебные запросы к системе кеширования
	$query_str = urlencode($query_str); // Если сайта динамический кешировать нужно по странице на запрос
    $script_name = $_SERVER['DOCUMENT_ROOT'].$this->config->cache_dir.$_SERVER['SCRIPT_NAME'].'_'.$query_str.'.html';
	// Если файл с кешем найден - удалить его
	if (file_exists($script_name)) unlink($script_name);
  }

  // Проверить скрипт на существование кеша
  public function in_cache($cache_name_block=null){
    // Путь к файлу кеша
    $query_str = preg_replace('#&?cl_cache=[0-9]#','',$_SERVER['QUERY_STRING']); // Удаляем служебные запросы к системе кеширования
	$query_str = urlencode($query_str); // Если сайта динамический кешировать нужно по странице на запрос
    $script_name = $_SERVER['DOCUMENT_ROOT'].$this->config->cache_dir.$_SERVER['SCRIPT_NAME'].'_'.$query_str.'.html';
	// Если файл с кешем найден продолжать проверку на его актуальность
	if (file_exists($script_name)){
	  // Открыть указатель на файл с кешем на чтение
	  $f = fopen($script_name,'r');
	  // Считать размер серилизованных данных о файле кеше
	  $f_byte_to_read = (int)trim(fgets($f));
	  // Прочитать серилизованные данные о файле кеша
	  $f_serialize_config = trim(fgets($f,$f_byte_to_read));
	  // Получить из серилизованной строки массив с настройками
	  $cache_info = unserialize($f_serialize_config);
	  // Проверить время актуальности кеша и сравнить его с текущим временем
      // и если актуальность утрачена, необходимо кеширование файла
      if ($cache_info['dietime'] < time()){
        // Установить флаг - кешировать файлы
        $this->cache = 1;
      } else { // Иначе считать из файла кеш
		// Переменная куда будет считывать кешированный файл
		$cache_file = null;
		// Пока файл не считан до конца - считывать построчно в буфер вывода
		while (!feof($f)){
	      // Считать в буфер вывода
	      echo fgets($f);
		}
      }
   	  // Закрыть указатель на файл с кешем
	  fclose($f);
	  // Кеш найден, выполнять скрипт нет необходимости
	  return true;
	} else {
	  // Файл кеша не найден, необходимо кеширование файла
      $this->cache = 1;
	  // Кеша нет, придется выполнять весь скрипт
	  return false;
	}
  }

}
?>
Пример использования:

PHP:
<?php
  include './modules/cache.class.php';
  $cache = new ClassCache();

  if (!$cache->in_cache()){
	echo 'текст для кеширования';
  };
?>
Может у кого-нибудь есть идеи как сделать блочное кеширование, ну т.е. файл кешировать по частят, я думал сделать просто имена блоков, но потом нереально чистить кеш, ибо нужно бегать по файловой системе, а этого очень не хочется делать...
 

Groove

Новичок
ну почему тут нет как на хабре возможности минусовать...
 

AmdY

Пью пиво
Команда форума
кстати, кто чем пользуется. мне нравится решение с тегами от Zend Framework
 

nirex

Новичок
а лучше всего кэшировать прокси сервером, он во много раз это лучше и быстрее сделает.
 

korchasa

LIMB infected
Автор оригинала: nirex
а лучше всего кэшировать прокси сервером, он во много раз это лучше и быстрее сделает.
Полностраничное кэширование далеко не везде(редко где?) возможно
 

GodFrey

Новичок
AmdY угу, зендовское решение очень удобное.
Только низкая работа при большом кол-ве кэша с тегами.. шо ппц медленная :(
 

fixxxer

К.О.
Партнер клуба
влом вчитываться в код, но большинство таких решений имеет проблему с засиранием кэша запросами к несуществующему контенту. примитивный DOS - вида while(1) file_get_contents("http://site.ru/article/".mt_rand(0,9999999999)).
 
Сверху