У меня есть несколько сайтов на общем хосте, на котором запущен Apache 2. Я хотел бы сжать HTML, CSS и Javascript, которые доставляются в браузер. Хост отключил mod_deflate и mod_gzip, поэтому эти параметры недоступны. Однако у меня есть PHP 5, поэтому я мог бы использовать компонент gzip.
В настоящее время я помещаю следующее в файл .htaccess:
php_value output_handler ob_gzhandler
Однако это только сжимает HTML и оставляет CSS и JS.
Есть ли надежный способ прозрачного сжатия вывода CSS и JS без необходимости менять каждую страницу? Я искал Google и предлагал ряд решений, но мне еще нужно заставить их работать. Если кто-то может предложить решение, которое они знают для работы, это было бы очень благодарно получено.
Обратите внимание, что метод 2 в разделе «Окончательная публикация» в Gzipping вашего CSS выглядит как хорошее решение, но я не мог заставить его работать. Кто-нибудь еще преуспел в использовании этого метода?
Извините за задержку – для меня это занятая неделя.
Предположения:
.htaccess
находится в том же файле, что и compress.php
static
подкаталоге Я начал свое решение, установив следующие директивы в .htaccess:
RewriteEngine on RewriteRule ^static/.+\.(js|ico|gif|jpg|jpeg|png|css|swf)$ compress.php [NC]
Требуется, чтобы ваш провайдер позволял переопределять параметры mod_rewrite
в файлах .htaccess
. Тогда сам файл compress.php может выглядеть так:
<?php $basedir = realpath( dirname($_SERVER['SCRIPT_FILENAME']) ); $file = realpath( $basedir . $_SERVER["REQUEST_URI"] ); if( !file_exists($file) && strpos($file, $basedir) === 0 ) { header("HTTP/1.0 404 Not Found"); print "File does not exist."; exit(); } $components = split('\.', basename($file)); $extension = strtolower( array_pop($components) ); switch($extension) { case 'css': $mime = "text/css"; break; default: $mime = "text/plain"; } header( "Content-Type: " . $mime ); readfile($file);
Разумеется, вы должны добавить в оператор switch больше типов mime. Я не хотел, чтобы решение зависело от расширения файловой системы pecl или любых других библиотек обнаружения магического типа mime – это самый простой подход.
Что касается обеспечения подлинности скрипта – я делаю перевод на реальный путь в файловой системе, поэтому никакие взломы «../../../etc/passwd» или другие пути файлов shellscript не проходят.
Это
$basedir = realpath( dirname($_SERVER['SCRIPT_FILENAME']) ); $file = realpath( $basedir . $_SERVER["REQUEST_URI"] );
сниппет. Хотя я уверен, что большинство путей, которые находятся в другой иерархии, чем $ basedir, будут обрабатываться Apache, прежде чем они даже достигнут скрипта.
Также я проверяю, находится ли результирующий путь внутри дерева каталогов скрипта. Добавьте заголовки для управления кешем, как предложил pilif, и у вас должно быть рабочее решение для вашей проблемы.
Что я делаю:
js
и stylesheets в css
, соответственно. В конфигурации Apache я добавляю такие директивы:
<Directory /data/www/path/to/some/site/js/> AddHandler application/x-httpd-php .js php_value auto_prepend_file gzip-js.php php_flag zlib.output_compression On </Directory> <Directory /data/www/path/to/some/site/css/> AddHandler application/x-httpd-php .css php_value auto_prepend_file gzip-css.php php_flag zlib.output_compression On </Directory>
gzip-js.php в каталоге js
выглядит следующим образом:
<?php header("Content-type: text/javascript; charset: UTF-8"); ?>
… и gzip-cs.php в каталоге css
выглядит так:
<?php header("Content-type: text/css; charset: UTF-8"); ?>
Это может быть не самое изящное решение, но оно, безусловно, является простым, которое требует нескольких изменений и хорошо работает.
что бы вы ни делали, будьте осторожны с кешированием на стороне клиента:
Браузеры делают всевозможные трюки, чтобы попытаться свести к минимуму полосу пропускания, и есть много способов в протоколе HTTP, чтобы сделать это, все из которых обрабатываются apache – если вы просто обслуживаете локальный файл.
Если вы этого не сделаете, это ваша ответственность .
Посмотрите, по крайней мере, на ETag и механику If-Modified-Since, поддерживаемую всеми текущими браузерами, и, по-видимому, являются наиболее надежным способом запроса сервера на обновленный контент.
Возможный способ использования CSS-файла для браузеров с использованием If-Modified-Since-Header – это что-то вроде этого (пустые заголовки для отключения любых кеширующих заголовков PHP отправляются по умолчанию):
$p = 'path/to/css/file' $i = stat($p); if ($_SERVER['HTTP_IF_MODIFIED_SINCE']){ $imd = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); if ( ($imd > 0) && ($imd >= $i['mtime'])){ header('HTTP/1.0 304 Not Modified'); header('Expires:'); header('Cache-Control:'); header('Last-Modified: '.date('r', $i['mtime'])); exit; } } header('Last-Modified: '.date('r', $i['mtime'])); header('Content-Type: text/css'); header('Content-Length: '.filesize($p)); header('Cache-Control:'); header('Pragma:'); header('Expires:'); readfile($p);
Код будет использовать заголовок if-modified-since, который браузер отправляет, чтобы проверить, изменился ли фактический файл на сервере с даты, указанной браузером. Если это так, файл отправляется, в противном случае возвращается 304 Not Modified, и браузеру не нужно повторно загружать весь контент (и, если он достаточно интеллектуальный, он также поддерживает анализируемый CSS в памяти).
Существует еще один механик, в котором сервер отправляет уникальный заголовок ETag для каждой части контента. Клиент отправит это обратно, используя заголовок If-None-Match, позволяющий серверу решать не только дату последней модификации, но и самого содержимого.
Это только делает код более сложным, хотя я так и оставил его. FF, IE и Opera (возможно, Safari тоже) отправляют заголовок If-Modified-Since, когда они получают контент с прикрепленным заголовком Last-Modified, поэтому это работает нормально.
Также имейте в виду, что определенные версии IE (или используемое JScript-Runtime) все еще имеют проблемы с переданным GZIP контентом.
Ой. И я знаю, что это не вопрос, но Acrobat также в некоторых версиях. У меня были случаи и случаи белых экранов при работе с PDF-файлами с кодировкой передачи gzip.
Вместо gzipping «на лету», когда пользователи запрашивают файлы CSS и JavaScript, вы можете их заранее скопировать. Пока Apache обслуживает их с правильными заголовками, вы золотые.
Например, в Mac OS X gzipping файла в командной строке так же просто, как:
gzip -c styles.css > styles-gzip.css
Возможно, это не рабочий процесс, который работает для вас.
Вы можете испытать удачу с mod_rewrite .
Создайте сценарий, который принимает локальное статическое имя файла как входное, например, $_SERVER['QUERY_STRING']
и выводит его в сжатой форме. Многие провайдеры не позволяют настраивать mod_rewrite
с файлами .htaccess
или полностью отключить его.
Если вы раньше не использовали переписывание , я рекомендую руководство для начинающих, как, вероятно, это . Таким образом, вы можете заставить apache перенаправить все запросы на статический файл на php-скрипт. style.css будет перенаправлен на compress.php? style.css, например.
Как всегда будьте предельно осторожны на входе, которое вы принимаете, или у вас есть эксплойт XSS
на ваших руках!