Все началось с ...
Несколько лет назад я только начал знакомиться с web-программированием, и одним из моих первых «проектов» был каталожек сайтов. Разработка велась для себя, в целях повышения опыта. Но т.к. аналогичных сайтов тьма-тьмущая, хотелось сделать что-то особенное. Я решил, что каждый сайт в каталоге будет представлен со скриншотом. Как все это автоматизировать я не знал, потому первое время я делал все скриншоты руками и заливал их уже как готовые файлы.
Шло время, проект «покрылся пылью», времени заниматься ним не было, но примерно год назад накатила новая «волна креатива» и захотелось мне решить «задачку автоскриншотера».
Первое, что пришло на ум — это готовые сервисы по созданию скриншотов, предоставяющие API. Но, перебрав некоторые (сейчас уже названия не помню), понял, что это не для меня: возможности были довольно урезаны, иногда приходилось довольно долго ждать «очереди», иногда сайты на скринах выглядели довольно убого. А главной проблемой было то, что все это должно было работать асинхронно и из скрипта я бы не смог понять — то ли сервис отдал мне временную картинку-заглушку, то ли уже готовый скриншот сайта.
Итого, я решил сделать собственный «велосипед».
Выбор инструмента
Для начала, нужно было найти утилитку, умеющую делать скриншоты, работающую в linux из командной строки (сайт крутится у меня на ubuntu server, потому иксов нет). Мне помог коллега по работе, дав ссылку на CutyCapt.
CutyCapt — небольшая кросс-платформенная утилита (работающая из командной строки) для создания скриншота веб-страницы и сохранения в различные векторные и растровые форматы, включая SVG, PDF, PS, PNG, JPEG, TIFF, GIF, BM P(перевод оригинального описания с оф. сайта).
Чтобы не заниматься копипастом с официального сайта просто скажу, что там уже все описано: установка, зависимости, параметры запуска, пример, а также способ использования при отсутствии X-сервера (через xvfb-run).
Кодинг
Итак, с инструментом определились. Вернемся к сайту. Я видел это так: у администратора на страничке описания есть кнопка «сделать скриншот», которая через AJAX запрос вызывает скрипт, создающий картинку, выполняющий с ней нужные обработки (ресайз/кроп/эскиз) и др.
Сказано — сделано. Приведу часть кода моего PHP-скрипта (оставив самое основное):
<?PHP
// тут какие-то действия по получению URL сайта, скрин которого нужно создать
// будь то выборка из БД (по переданному id), или еще что-то
$url = 'http://habrahabr.ru'; // "хардкод" для примера
// имя временного файла для сохранения скриншота
$tmpfname = tempnam('/tmp', 'catalog') . '.jpg';
// эскейпим перед вставкой в строку команды
$url = escapeshellarg($url);
// собираем командную строку
// из параметров для CutyCapt я передавал только мин. ширину экрана, url и имя файла, куда сохранять скриншот - мне этого хватило
// о "xvfb-run" я писал выше
$cmd = sprintf('xvfb-run --server-args="-screen 0, 1024x768x24" /ПАПКА/C/БИНАРНИКОМ/CutyCapt --min-width=1280 --url=%s --out=\'%s\'', $url, $tmpfname);
// Выполняем
exec($cmd);
// Проверяем, что скрин создался
if (file_exists($tmpfname)) {
// проверяем, что он не 0 байт (у меня иногда так случалось)
if (filesize($tmpfname) > 1) {
// а тут уже делаем с файлом по имени $tmpfname все, что душе угодно
// делаем его копию в нужную папку, изменяем размер, обрезаем в нужных пропорциях, создаем дополнительный эскиз.....
// я, например, использовал phpthumb (phpthumb.gxdlabs.com) для обработки
$f = date("ymd_his", time()).".jpg"; // имя для скрина
if (copy($tmpfname, IMAGES_DIR.$f)) {
if (file_exists(IMAGES_DIR.$f)) {
try{
$thumb = PhpThumbFactory::create(IMAGES_DIR.$f);
// качество jpg
$thumb->setOptions( array('jpegQuality' => 90) );
// изменение размер
$thumb->resize(800);
// обрезка до квадрата 800x800px
$thumb->crop(0, 0, 800, 800);
$thumb->save(IMAGES_DIR.$f);
// эскизик
$thumb->resize(200)->crop(0,0,200,150);
$thumb->save(IMAGES_DIR.'t_'.$f);
}
catch(exception $e) {
// обрабатываем исключение...
}
// здесь я сохранял имя скрина в БД, и др.
}
}
}
// удаляем временный файл
unlink($tmpfname);
}
// тут я отправлял результат работы в json - инфу об удачном/неудачном создании скрина
?>
Ах да, хотел бы поделиться информацией о «подводных камнях»:
- Иногда CutyCapt очень долго скринил, но так и не доделывал свою работу;
- Иногда делал 0-байтные скрины
- Иногда вылетал с ошибкой на некоторых flash-сайтах. Пришлось пожертвовать ими и просто удалить flash-plugin из системы. Теперь просто на скринах на месте флеша — пусто, зато вылетов больше нет из-за флеша.
Литература:
Официальный сайт CutyCapt
PHP.net
P.S. Если кому кажется, что я мало написал про CutyCapt, говорите — я дополню статью (просто мне показалось, что на оф. сайте все четко описано)