Под катом быстрый и простой кеш, 50 строк кода php и конкретная решенная задача на Joomla (подойдет любая cms на php).
Как-то наш seo-спец мне сказал: лучший сайт — это статический html.
И вот, через несколько месяцев, озаботившись проблемой скорости сайта, я вспомнил его слова.
Объект
Сайт коммерческой организации, около 1000 уников в день;
Стандартный хостинг от известной в Петербурге компании;
Joomla 1.5.x (выше не обновляемся т.к. реализовано большое количество кастомных хаков, плагинов и пр.).
Проблема
Страницы генерируются долго (до 3-5 секунд в часы пик). Встроенный кеш ситуацию улучшил не намного — до (1,5-2 секунды согласно данным из Google Webmaster).
Основная проблема встроенного кеша — в виду универсальности и сложности системы (тут вспоминается желтая программа) ему приходится кешировать каждый модуль в отдельности.
Решение
Для начала избрал самое простое и быстрое решение — закешировать главную страницу. Для этого нужно выполнить несложные действия:
Запускать раз в X дней\часов\минут скрипт сохраняющий главную страницу в корень сайта как index.html;
Устанавливаем в настройках сервера чтобы приоритет при выдаче имела страница index.html. Таким образом, если есть закешированная страница, то движок CMS даже не запустится.
Код скрипта кеширующего главную страницу:
<?php
$page = file_get_contents('http://www.no_habroeffect_plz.ru/'); // здесь загружаем страницу
if (strlen($page)>300) // простейшая проверка что что-то загрузилось
file_put_contents('index.html', $page);
?>
Развитие
Свободный вечер и приступ перфекционизма дали о себе знать: одной главной страницы стало недостаточно.
Решил перевести весь сайт в статику. Первым делом на ум пришла мысль сохранять все в корень с сохранением структуры папок и имен файлов благу адреса на сайте ЧПУ («ох уж это „благо“ — вспоминаются слова сеошника) и дубликатов названий папок CMS не предвиделось.
Но мешать все в кучу как-то не по-человечески, хоть и позволило бы избежать обращения к скриптам. Поэтому решил всю структуру складывать в отдельный каталог.
Получился такой алгоритм действий:
Проверяем есть ли файл в кеше
Если есть — выводим его, если нет — п.3
Генерируем страницу средствами CMS
Сохраняем страницу в кеш
Нюансы. Куда ж без них?
Для страниц с POST и GET данными кеширование отменил. Все что нужно кешировать на сайте имеет статический адрес, а что не нужно (гостевая вида „Вопрос-Ответ“) имеет GET-параметры.
Также для удобства добавил функции принудительного обновления страницы и очистки всего кеша.
Сам скрипт
Состоит из двух файлов:
основной скрипт (инструкция по установке в начале скрипта) _my/mycache.php:
<?php
/*
Скрипт выдает страницы из кеша
Кеш создается автоматически.
Обновление кеша может делаться тремя способами:
1. Автоматически, если он устарел
2. через clearcache.php (очищает весь кеш)
3. В конец адреса страницы добавить "?delcache". Пример http://www.site.com/123.html?delcache
ИНСТРУКЦИЯ:
1. Залить папку "_my" в корень сайта
2. в начале index.php подключить файл: include '_my/mycache.php';
3. в конце index.php вместо вывода добавить это (пример для Joomla 1.5)
//echo JResponse::toString($mainframe->getCfg('gzip'));
///////// КЕШ
$response = JResponse::toString($mainframe->getCfg('gzip'));
echo $response;
cachepage( &$response );
*/
//Время жизни кеша в часах
$cache_hours = 72;
$filename = $_SERVER['SCRIPT_URL'];
// подготавливаем имя файла
if ($filename[strlen($filename)-1]=='/') $filename .= 'index.html'; //добавляем index.html к папкам
$filename = '_my/cache/'.$filename;
$filename = mb_convert_encoding($filename, "Windows-1251", "UTF-8"); //разбираемся с кодировкой
//Проверка надо ли обновить кеш
if ( isset($_GET['delcache']) ) unlink($filename);
if ( !sizeof($_POST) and !sizeof($_SERVER['argv']) ) { //не обрабатываем страницы с POST и GET данными
//подключаем кеш
if (is_file($filename)) {
//проверка кеша на "устарелость"
if ( ((time() - filemtime($filename))/3600) > $cache_hours) {
unlink($filename);
}
//вывод закешированной страницы
else die(file_get_contents($filename));
}
}
//эту функцию вызывать в конце index.php движка
function cachepage($page) {
if ( sizeof($_POST) or sizeof($_SERVER['argv']) ) exit; //не обрабатываем страницы с POST и GET данными
if (strlen($page) < 200) exit; //мелкие страницы тоже не обрабатываем
$filename = $_SERVER['SCRIPT_URL'];
// подготавливаем имя файла
if ($filename[strlen($filename)-1]=='/') $filename .= 'index.html'; //добавляем index.html к папкам
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if (!in_array($ext, array('html','htm','php'))) exit; //ограничение расширений
$filename = '_my/cache/'.$filename;
$filename = mb_convert_encoding($filename, "Windows-1251", "UTF-8"); //разбираемся с кодировкой
//создаем структуру папок
$path = substr($filename, 0, strrpos($filename, '/'));
mkdir($path, 0700, true);
//сохраняем файл
file_put_contents($filename, $page);
}
?>
Время генерации страницы стремится к моментальному. Наконец-то избавился от основного недостатка Джумлы — низкой скорости. Пусть для динамических сайтов решение и не подходит, но свою узкую задачу выполняет уже около месяца.
PS. Если что-то можно было сделать лучше — с удовольствием прочитаю. Веб-разработка — не мой профиль, просто грамотное ТЗ заняло бы объем сравнимый с размером этой статьи и вдвое больше самого скрипта. Плюс (для меня это было самым важным) было интересно.
PPS. Сайт пока даю. Вдруг меня опубликуют — боюсь блогоэффекта, т.к. есть часть динамических страниц.
Комментарии: