|
Funciones de compresión |
Manejando ficheros comprimidos
PHP dispone de funciones que permiten manejar ficheros comprimidos utilizando para la compresión la función zlib de Jean-loup Gailly y Mark Adler.Comprimiendo cadenas
Las funciones anteriores permiten la creación, lectura y modificación de ficheros comprimidosDescomprimiendo cadenas
gzuncompress(cadena)Funciones para buferización de salidas
ob_start()Cabeceras para transferir información comprimida
Cuando un servidor recibe una petición de una página web el navegador del cliente siempre envía información sobre su disposición a aceptar diferentes tipos de contenidos.Algunas limitaciones
En todos estos ejemplos hemos dado por supuesto que los navegadores de los clientes aceptan la codificación gzip, pero es evidente que si eso no ocurriera la página se visualizaría erróneamente.Herramientas de compresión
Existen varias herramientas para compresión de ficheros. Las más populares son las funciones de la biblioteca bzip2 de Julian Seward que generan ficheros comprimidos que se reconocen por su extensión (bz2) y la función de zlib de Jean-loup Gailly y Mark Adler para leer y grabar archivos comprimidos con extensión gz![]() |
Versión 4.3.0 de PHP
Los comentarios anteriores son válidos para la versión 4.2.3 -y anteriores- de PHP. A partir de la versión 4.3.0 la librería de compresión viene incluida en el propio programa y por tanto se activa automaticamente al instalar PHP. En esta nueva versión no encontrarás la la extensión extension=php_zlib.dll en php.ini.Ejemplo de compresión y lectura de un fichero
Aquí tienes un ejemplo en el que he intentado utilizar todas la funciones de compresión de ficheros que te comenzo al margen.<? # asignamos un nombre al fichero con extensión "gz" $fichero ='prueba.gz'; # abrimos el fichero en modo escritura (w) # con el nivel máximo de compresión (9) $f=gzopen($fichero,"w9",0); $cadena="Este es el primer bloque de texto que hemos introducido en el fichero comprimido. "; $cadena .="Añadimos este segundo bloque"; echo "<i>Esta es el fichero inicial:</i> ".$cadena."<br>"; # escribimos (comprimida) la cadena en el fichero gzwrite($f,$cadena); # cerramos el fichero gzclose($f); #abrimos el fichero en modo lectura $f=gzopen($fichero,"r"); echo "<i>Estos son los tres primeros caracteres de la cadena:</i> "; # escribimos los tres primeros caracteres, el puntero (por defecto) # apunta al comienzo de la cadena echo gzread($f, 3)."<br>"; # desplazamos el puntero hasta el carácter nº 8 gzseek($f,8); echo "<i>Estos son los seis caracteres siguientes al octavo:</i> "; # escribimos seis caracteres a partir del octavo echo gzread($f, 6)."<br>"; echo "<i>Ahora el puntero está en:</i> "; # buscamos la posición actual de puntero echo gztell($f)."<br>"; # movemos el puntero hasta el comienzo del fichero gzrewind($f); echo "<i>Estos son los diez primeros caracteres de la cadena:</i> "; # escribimos los diez primeros caracteres del fichero echo gzread($f, 10)."<br>"; # volvemos el puntero al comienzo del fichero gzrewind($f); echo "<i>Escribimos el fichero completo:</i> "; # con gzpasthru escribimos el fichero completo # el puntero está al principio porque alli lo ha situado gzrewind # no necesitamos utilizar "echo" ni "print" ya que gzpassthru # escribe directamente el contenido del fichero gzpassthru($f); # tenemos que volver a abrir el fichero ya que gzpassthru # se encargó de cerrarlo después de leerlo $f=gzopen($fichero,"r"); echo "<br><i>Aquí estará todo el fichero:</i> "; gzpassthru ($f); # la función readgzfile abre el fichero, imprime su contenido y lo cierra echo "<br><i>Aqui se imprime la cadena completa usando readgzfile</i>: <br>"; readgzfile($fichero); # con gzfile también se abre el fichero, # pero ahora el contenido no se presenta # directamente. Es recogido en un array. # Para visualizarlo debemos imprimir # el primer elemento del array. $z=gzfile($fichero); echo "<br><i>Este es el primer elemento (0) del array generado por gzfile</i>: ".$z[0]; # gzfile cierra el fichero. # No podemos poner gzclose porque nos daría error ?>
| comprime1.php |
Utilizando un directorio distinto
El ejemplo anterior está desarrollado para el supuesto que el script y el fichero comprimido estén en el mismo directorio.Elección del grado óptimo de compresión
Puede parecer -a primera vista- que la condición óptima de compresión sería elegir el nivel 9 y eso es cierto si tomamos únicamente en consideración el tamaño final del fichero comprimido, pero... siempre hay un pero...;-) esa opción implica una raletización del proceso de compresión ya que obliga a ejecutar el algoritmo de compresión reiteradas veces y es probable que la reducción real del tamaño no justifique ese tiempo de compresión.Compresión de cadenas
Aquí tienes un ejemplo en el que uso las tres funciones de compresión de cadenas así como las opciones de descompresión y lectura de cada una de ellas.<? # creamos una cadena de ejemplo $cadena="Esta es la cadena a comprimir. Intentaremos que sea larga porque parece que si la hacemos muy corta en vez de reducirse su tamaño parece que aumenta. Y como sigue siendo enormemente grande la cadena comprimida intentaremos hacerla aun mayor a ver que pasa "; # comprimimos con la función gzcompress $c=gzcompress($cadena,9); echo "<br>".$c; # descomprimimos con la función gzcompress $dc=gzuncompress($c); echo "<br>".$dc."<br>"; # ahora utilizamos la función gzencode $c1=gzencode($cadena,9,FORCE_GZIP); echo "<br>".$c1."<br>"; # el resultado lo guardamos en un fichero con extensión gz # pero abierto en modo "normal", es decir escribiendo # dentro del fichero la cadena "tal cual" fue devuelta # por gzencode $f=fopen("pepe.gz","w"); fwrite($f,$c1); fclose($f); # abrimos el fichero anterior utilizando las funciones # de lectura de fichero comprimidos $f=gzopen("pepe.gz","r"); readgzfile("pepe.gz"); gzclose($f); # borramos el fichero una vez leido unlink("pepe.gz"); # otra opción de compresión de cadenas utilizando la función # gzdeflate $c2= gzdeflate($cadena,9); echo "<br><BR>".$c2; # con la función gzinflate podemos descomprimir la cadena # comprimida generada por gzdeflate $dc2=gzinflate($c2); echo "<br>".$dc2; ?>
| comprime3.php |
Economizando espacio en el servidor
Aunque no pueden esperarse milagros si parece que es posible alguna economía de espacio almacenando ficheros comprimidos en el servidor y utilizando un script de descompresión a la hora de visualizar la página.<? # Iniciamos una variable "vacia" $cadena=""; # Abrimos el fichero en modo lectura (r) $f1=fopen("tramo4_1.html","r"); # hacemos un bucle para leer el fichero # hasta encontrar el final (feof) y vamos recogiendo # el contenido en la variable while (!feof($f1)) { $cadena .= fgets($f1, 1024); } # comprimimos la cadena con gzencode # con lo cual la propia función añade los "encabezados" # de formato gzip $c1=gzencode($cadena,3,FORCE_GZIP); # abrimos un nuevo fichero modo escritura (w) con "fopen", es decir como un fichero normal $f=fopen("tramo4_1.html.gz","w"); # escribimos la cadena "tal cual" # en este fichero fwrite($f,$c1); # cerramos el fichero comprimido fclose($f); echo "La compresión ha terminado"; ?>
<? # abrimos el fichero comprimido con "gzopen" $f=gzopen("tramo4_1.html.gz","r"); # leemos el contenido completo # en forma transparente ya que readgzfile descomprime # la salida readgzfile("tramo4_1.html.gz"); # cerramos el fichero gzclose($f); ?>
| Ejecutar script |
Economizando tiempo de transferencia
No solo se puede economizar espacio en el servidor. También es posible enviar comprimidas -desde el servidor hasta el cliente- las páginas web<? # activamos la buferización de la salida # para que no se presenten los resultados del script #directamente en la página # ¡¡Cuidado con no dejar lineas en blanco delante del script # ya que vamos a insertar luego Headers!! ob_start(); # abrimos y leemos el fichero html $f1=fopen("tramo4_1.html","r"); fpassthru($f1); # recogemos el contenido del buffer # en la variable cadena $cadena = ob_get_contents(); # comprimimos la cadea con gzencode # para que incluya los encabezados "gzip" $cd=gzencode($cadena,3,FORCE_GZIP); # desactivamos la "buferización" # y borramos el contenido del buffer ob_end_clean(); # insertamos la cabeceras # indicando el tipo de contenido Header('Content-Encoding: gzip'); Header('Content-Length: ' . strlen($cd)); # presentamos el contenido (cadena comprimida) que será # "traducido" automáticamente por el navegador echo $cd; ?>
| Ejecutar script |
Economizando espacio y tiempo
Este que te inserto aquí, es un ejemplo -muy similar al anterior- en el que se recoge la información a partir de un fichero comprimido -economía de espacio- y se envía al cliente también comprimida -economía de tiempo- como ves... a este paso... voy a dar la impresión de ser un aspirante a la cartera ministerial de economía... pero... te juro que... no es esa mi intención... palabra... ;-)<? ob_start(); #En este caso abrimos el fichero con "gzopen" # ya que se trata de un fichero comprimido # todo lo demás es idéntico al ejemplo anterior $f1=gzopen("tramo4_1.html.gz","r"); gzpassthru($f1); $cadena = ob_get_contents(); $cd=gzencode($cadena,3,FORCE_GZIP); ob_end_clean(); Header('Content-Encoding: gzip'); Header('Content-Length: ' . strlen($cd)); echo $cd; ?>
| Ejecutar script |
Evitando problemas con las cachés intermedias
Si optas por discriminar entre navegadores que aceptan/no aceptan codificación podrás evitar los riesgos de utilización de una versión incorrecta de la página almacenada en una caché intemedia entre servidor y cliente incluyendo estas cabeceras: