
Надо отметить, что со спасаемым сайтом мне повезло. Он простой и логичный. Копировать статьи, картинки — долгий и скучный процесс. Я решил скопировать сразу все. Что мы имеем:
- Исходный сайт полностью статичный
- ModRewrite все перекидывает в один php-скрипт
- Скрипт ищет файл в кеше, если в кеше нет, запрашивает с сайта-источника
- Решил хранить все в sqlite
В качестве хранилища данных я выбирал между:
Хранить файлы как есть: т.е. если исходный адрес станицы /topic/123.html, то создавать директорию topic и помещать в нее файлы. Например, так делает wget. Но такой подход мне не понравился.
Делать md5-хеш от URI и сохранять в файл data/ТУТХЕШ.db, очень много файлов. Найти потом в этой папке что-либо невозможно. Не понравилось.
Делать md5-хеш и хранить в sqlite базе. По своей сути это, тоже самое, что и предыдущий вариант, но только одним файлом. Рассматривался еще вариант хранения в mysql — но это уж больно не мобильно и громоздко. А sqlite: переписал несколько файлов на новое место — сайт развернут и готов к работе.
ModRewrite — ничего нового я не изобрел:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php
# и на всякий случай редирект:
RewriteCond %{HTTP_HOST} !^apache2dev\.ru$
RewriteRule ^ apache2dev.ru%{REQUEST_URI} [R=301,L]
Как все работает — index.php
С исходным кодом можно ознакомиться тут: apache2dev.ru/index.phps
1. Берем $_SERVER['REQUEST_URI'], на всякий случай добавляем адрес целевого сайта,
2. Получаем md5-хеш
3. Смотрим есть-ли запрашиваемая страница в локальном кеше
4. Если нет, запрашиваем на сайте источнике, разбираем заголовки ответа. Нас интересуют только два: 'Content-Type' и 'Last-Modified'
5. Сохраняем в кеше заголовки и ответ. Выдаем клиенту результат, предварительно немного обработав HTML файлы. Критерий Content-Type = text/html
6. Добавляем Expires на сутки.
Я решил для себя, что в кеше буду хранить данные в первоначальном виде.
Создаем базу данных:
CREATE TABLE storage (loc TEXT PRIMARY KEY, heads TEXT, fdata TEXT, location TEXT);
Теперь когда я открыл свой сайт и увидел на нем страницу с картинками, первая порция данных была сохранена в локальный кеш.
Запускаю
'wget -r мойсайт.ru'
и даю немного поработать. wget с ключом -r пытается рекурсивно скачать весь сайт. У него это получается не очень хорошо. Например, он вообще не знает что такое javascript. Теперь открываю сайт и пробегаюсь по страничкам, чтобы зацепить то, что упустил wget.В заключение я на коленке набросал еще один скриптик, который показывает, что сейчас есть в локальной базе данных. Бегло просматривая список, удаляю пару строчек.

Исходник: apache2dev.ru/list.phps
Перевел сайт в режим работы, т.е. логика теперь такая: если нет данных в локальном кеше, то мы уже ничего запрашивать с сайта-источника не будем, а просто выведем ошибку 404.
Замер скорости
Я производил замер с помощью ab: картинка объемом 70кб и произвольная html-страница. Разница лишь в дополнительных preg_replace (я позволил себе вырезать немного рекламы, заменил абсолютные ссылки на относительные и вставил предупреждение, что эта страница — копия)
# ab -c 10 -n 1000 apache2dev.ru/images/ff_adds/validator.gif
Requests per second: 417.32[#/sec] (mean)
# ab -c 10 -n 1000 apache2dev.ru/2006/01/28/ustanovka-apache-20-2
Requests per second: 29.66 [#/sec] (mean)
Результат меня вполне устраивает.
Плюсы и минусы такого подхода:
- «Спасти» сайт нужно лишь единожды, и потом можно про него забыть. Wordpress я как-то побаиваюсь: за ним нужно следить, обновлять и т.п.
- Сайт уместился в 7 файлов, удобно копировать; sqlite база — 20мб
- Требования к системе минимальные
- Самым главным минусом (по моему мнению) является тот факт, что далеко не каждый сайт можно подобным образом сохранить. Есть сайты гуляя по ссылкам которых, можно не остановиться никогда.
Возможные улучшения:
- В базе данные можно было хранить уже в обработанном виде (preg_replace и проч.)
- А еще данные можно было хранить в сжатом виде. Проверять Accept-Encoding: если там стоит gzip — выдавать как есть, иначе распаковывать
- Если понадобиться высокая производительность, можно попросить nginx кешировать данные, выдаваемые php скриптом
- Предварительно подготавливать URI страницы. Например, удалять всякие ?from=top10, ?from=ap2.2, сейчас одинаковые страницы (но с разными адресами) сохранены по нескольку раз.
- Передавать через context в функцию file_get_contents параметр max_redirects=0, обрабатывать ошибку и сохранять заголовок Location. Сейчас пользователь запросив /get.php?=/download/123.pdf получит сразу данные, как будто бы именно по этому адресу и находится pdf файл, т.к. функция file_get_content (в нашем файле index.php) увидев редирект, автоматический его выполнит, никому не сказав ни слова. А по идеи-то пользователь должен получить ответ от сервера HTTP/1.1 302 Found, и сделать уже сам еще один запрос непосредственно к файлу.
Кстати, сайт про apache, о котором идет речь: apache2dev.ru
Полный комплект: apache2dev.ru/catcher.tgz