Переводим сайт в статический html. Мой опыт

28 Июн
2012

Под катом быстрый и простой кеш, 50 строк кода php и конкретная решенная задача на Joomla (подойдет любая cms на php).

Как-то наш seo-спец мне сказал: лучший сайт — это статический html.
И вот, через несколько месяцев, озаботившись проблемой скорости сайта, я вспомнил его слова.

Объект


  • Сайт коммерческой организации, около 1000 уников в день;
  • Стандартный хостинг от известной в Петербурге компании;
  • Joomla 1.5.x (выше не обновляемся т.к. реализовано большое количество кастомных хаков, плагинов и пр.).

Проблема

Страницы генерируются долго (до 3-5 секунд в часы пик). Встроенный кеш ситуацию улучшил не намного — до (1,5-2 секунды согласно данным из Google Webmaster).
Основная проблема встроенного кеша — в виду универсальности и сложности системы (тут вспоминается желтая программа) ему приходится кешировать каждый модуль в отдельности.

Решение


Для начала избрал самое простое и быстрое решение — закешировать главную страницу. Для этого нужно выполнить несложные действия:
  1. Запускать раз в X дней\часов\минут скрипт сохраняющий главную страницу в корень сайта как index.html;
  2. Устанавливаем в настройках сервера чтобы приоритет при выдаче имела страница 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 не предвиделось.
Но мешать все в кучу как-то не по-человечески, хоть и позволило бы избежать обращения к скриптам. Поэтому решил всю структуру складывать в отдельный каталог.
Получился такой алгоритм действий:
  1. Проверяем есть ли файл в кеше
  2. Если есть — выводим его, если нет — п.3
  3. Генерируем страницу средствами CMS
  4. Сохраняем страницу в кеш

Нюансы. Куда ж без них?

Для страниц с 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);
}

?>

и мини-скрипт полной очистки кеша:
<?php

//рекурсиное удаление папки
function rrmdir($dir) {
    foreach(glob($dir . '/*') as $file) {
        if(is_dir($file))
            rrmdir($file);
        else
            unlink($file);
    }
    rmdir($dir);
}

rrmdir('cache');

?>

Выводы


Время генерации страницы стремится к моментальному. Наконец-то избавился от основного недостатка Джумлы — низкой скорости. Пусть для динамических сайтов решение и не подходит, но свою узкую задачу выполняет уже около месяца.
PS. Если что-то можно было сделать лучше — с удовольствием прочитаю. Веб-разработка — не мой профиль, просто грамотное ТЗ заняло бы объем сравнимый с размером этой статьи и вдвое больше самого скрипта. Плюс (для меня это было самым важным) было интересно.
PPS. Сайт пока даю. Вдруг меня опубликуют — боюсь блогоэффекта, т.к. есть часть динамических страниц.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх