2008-09-07 20 views
8

Tengo algunos sitios en un host compartido que ejecuta Apache 2. Me gustaría comprimir el HTML, CSS y Javascript que se entregan al navegador. El host ha deshabilitado mod_deflate y mod_gzip, por lo que estas opciones están desactivadas. Sin embargo, tengo PHP 5 a mi disposición, así que podría usar el componente gzip de eso.La mejor manera de comprimir HTML, CSS y JS con mod_deflate y mod_gzip deshabilitado

Actualmente estoy poniendo lo siguiente en mi archivo .htaccess:

php_value output_handler ob_gzhandler

Sin embargo, esto sólo se comprime el código HTML y deja fuera el CSS y JS.

¿Existe una manera confiable de comprimir de forma transparente la salida de CSS y JS sin tener que cambiar cada página? He buscado en Google y se presentan una serie de soluciones, pero todavía tengo que hacer que una funcione. Si alguien pudiera sugerir una solución que supieran que funcionaría, sería muy gratamente recibida.

Nota, Método 2 en The Definitive Post on Gzipping your CSS parece una buena solución, pero no pude conseguir que funcione. ¿Alguien más ha tenido éxito usando este método?

+0

simplemente curioso: ¿por qué la compañía anfitriona deshabilitó mod_deflate y mod_gzip ?! ¡En realidad es su interés despertarlos! – scunliffe

Respuesta

1

Puedes probar tu suerte con mod_rewrite.

Crea una secuencia de comandos que toma un nombre de archivo estático local como entrada, a través, p. Ej. $_SERVER['QUERY_STRING'] y lo emite en forma comprimida. Muchos proveedores no permiten la configuración de mod_rewrite con los archivos .htaccess o la tienen completamente inhabilitada.

Si no ha usado reescriba antes, le recomiendo una buena guía para principiantes, como probablemente this one. De esta manera puede hacer que apache redirija todas las solicitudes de un archivo estático a un script php. style.css se redirigirá a compress.php? style.css por ejemplo.

Como siempre ser extremadamente prudente en la entrada que acepta o si tiene una XSS explotar en sus manos!

+0

@macbirdie, muchas gracias por esta sugerencia. ¿Puede proporcionar o vincular a algún ejemplo de este enfoque? También me interesaría escuchar algunas técnicas generales para asegurar ese guión. –

4

Lo que hago:

  • coloco guiones de un js y hojas de estilo en un dir css, respectivamente.
  • En la configuración de Apache, agrego directivas de este modo:

    <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 en el directorio js se ve así:

    <?php 
        header("Content-type: text/javascript; charset: UTF-8"); 
    ?> 
    
  • ... y gzip-cs.php en el directorio css se ve así:

    <?php 
        header("Content-type: text/css; charset: UTF-8"); 
    ?> 
    

esto puede no ser la solución más elegante, pero sin duda es un sencillo que requiere pocos cambios y funciona bien.

+0

Acabo de probar esto y no pude hacerlo funcionar desafortunadamente. Cuando agrego las directivas como se sugiere, obtengo un error interno del servidor. –

1

lo que hagas, tener cuidado con el almacenamiento en caché del lado del cliente:

Navegadores hacer todo tipo de trucos para tratar de minimizar el ancho de banda y hay muchas maneras en el protocolo HTTP para hacer eso, todo lo cual son tratados por apache, si solo está sirviendo un archivo local.

Si no lo está, entonces es su responsabilidad.

Eche un vistazo al menos a los mecanismos ETag y If-Modified-Since que son compatibles con todos los navegadores actuales y parecen ser la forma más robusta de consultar el contenido actualizado del servidor.

Una posible manera de servir a un archivo CSS para navegadores utilizando el If-Modified-Since encabezado es algo como esto (las cabeceras vacías para desactivar cualquiera de las cabeceras no almacenamiento en caché de PHP envía por defecto):

$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); 

El código usará if-modified-since-header que el navegador envía para verificar si el archivo real en el servidor ha cambiado desde la fecha que el navegador ha proporcionado. Si es así, el archivo se envía, de lo contrario, se devuelve un 304 No modificado y el navegador no tiene que volver a descargar todo el contenido (y si es lo suficientemente inteligente, también mantiene el CSS analizado en la memoria).

Hay otra mecánica que implica que el servidor envíe un cabezal ETag único para cada contenido. El cliente lo enviará de vuelta usando un encabezado If-None-Match que le permita al servidor decidir no solo en la fecha de la última modificación sino también en el contenido mismo.

Esto hace que el código sea más complicado, así que lo he omitido. FF, IE y Opera (probablemente Safari también) envían el encabezado If-Modified-Since cuando reciben contenido con un encabezado Last-Modified adjunto, por lo que funciona bien.

También tenga en cuenta que ciertas versiones de IE (o el JScript-Runtime que utiliza) todavía tienen problemas con el contenido transferido por GZIP.

Oh. Y sé que eso no forma parte de la pregunta, pero también lo hace Acrobat en algunas versiones. He tenido casos y casos de pantallas blancas mientras he servido archivos PDF con codificación de transferencia gzip.

+0

¿tiene un src/url para los problemas de IE/JScript con contenido GZIP? Recuerdo versiones anteriores de IE (por ejemplo, antes de IE6) que no admitían gzip, pero eso solo significa que obtienen el contenido descomprimido más lento que se sirve. Si todavía hay un problema con IE, ciertamente me gustaría saberlo. – scunliffe

+0

Tuve casos en los que IE no fue capaz de analizar archivos JS externos que se transfirieron con gzip. Y algunas versiones (incluso actuales) del complemento de Acrobat tampoco pueden manejar la compresión, aunque afirmen que sí pueden hacerlo. – pilif

7

Disculpa por la demora: es una semana ocupada para mí.

Supuestos:

  • .htaccess está en el mismo archivo que compress.php
  • archivos estáticos para ser comprimido están en static subdirectorio

empecé mi solución de fijar las directrices siguientes en..htaccess:

RewriteEngine on 
RewriteRule ^static/.+\.(js|ico|gif|jpg|jpeg|png|css|swf)$ compress.php [NC] 

Se requiere que su proveedor le permite anular mod_rewrite opciones en .htaccess archivos. A continuación, el archivo de compress.php sí mismo puede tener este aspecto:

<?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); 

Usted debe agregar por supuesto más tipos MIME a la sentencia switch. No quería que la solución dependiera de la extensión pecl fileinfo ni de ninguna otra biblioteca de detección de tipo MIME mágico: este es el enfoque más simple.

En cuanto a la seguridad de la secuencia de comandos, realizo una traducción a una ruta real en el sistema de archivos para que no se procesen las rutas de archivos '../../../etc/passwd' ni otras rutas de archivos de shellscript.

Ese es el fragmento

$basedir = realpath(dirname($_SERVER['SCRIPT_FILENAME'])); 
$file = realpath($basedir . $_SERVER["REQUEST_URI"]); 

. Aunque estoy bastante seguro de que la mayoría de las rutas que están en otra jerarquía que $ basedir serán manejadas por Apache antes de que lleguen al script.

También verifico si la ruta resultante está dentro del árbol de directorios del script. Agregue los encabezados para el control de caché como se sugirió y debe tener una solución de trabajo para su problema.

+0

Gracias, voy a probar esto. Seguro que desearía que SOF tuviera alertas por correo electrónico para avisarte cuando se actualice una pregunta. –

+0

Oye, con esto, ¿cómo lo usaría? Guardo esto como compress.php ¿correcto? ¿Uso un include? – Coughlin

+0

Este script asume que es ejecutado por la regla de reescritura de apache y recibe un nombre de archivo como parámetro de URI. – macbirdie

1

En lugar de gzip sobre la marcha cuando los usuarios solicitan los archivos CSS y JavaScript, puede gzip antes de tiempo. Mientras Apache les sirva con los encabezados correctos, eres dorado.

Por ejemplo, en Mac OS X, gzipping un archivo en la línea de comandos es tan fácil como:

gzip -c styles.css > styles-gzip.css 

podría no ser el tipo de flujo de trabajo que funcione para usted sin embargo.

Cuestiones relacionadas