I. Introduction

Cet article présente la compression de fichiers avec la bibliothèque Zlib de Jean-loup Gailly et Mark Adler. Les fichiers compressés avec cet algorithme portent l'extension gz. La bibliothèque est téléchargeable ici : http://www.gzip.org/zlib/

II. Accès aux fichiers

Pour enregistrer ou lire un fichier compressé, il faut utiliser les fonctions gzopen() et gzclose() sur le même modèle que les fonctions standards fopen() et fclose(). Ces deux fonctions retournent un pointeur de fichier qui devra être passé en argument aux autres fonctions de traitement.

II-A. Ouverture

Les modes d'ouverture des fichiers sont les mêmes qu'avec la fonction standard fopen().

Mode

Description

r

ouverture en lecture seule, pointeur placé en début de fichier

r+

ouverture en lecture et écriture, pointeur placé en début de fichier

w

ouverture en écriture seule, pointeur placé en début de fichier, écrase le contenu du fichier, si le fichier n'existe pas, on tente de le créer

w+

ouverture en lecture et écriture, pointeur placé en début de fichier, écrase le contenu du fichier, si le fichier n'existe pas, on tente de le créer

a

ouverture en lecture seule, pointeur placé en fin de fichier, si le fichier n'existe pas, on tente de le créer

a+

ouverture en lecture et écriture, pointeur placé en fin de fichier, si le fichier n'existe pas, on tente de le créer

Ce mode peut être complété par le niveau de compression (en écriture seulement) entier compris entre 0 et 9, exemple : w5. Un autre suffixe peut être ajouté pour indiquer une heuristique pour filtrer les données : f, exemple : w5f. Le suffixe h permet de n'activer que la compression de Huffman, exemple : w5h.

Syntaxe d'ouverture de fichier :

 
Sélectionnez
1.
resource gzopen(string $filename, string $mode, int $use_include_path)

Exemple d'ouverture de fichier en lecture :

 
Sélectionnez
1.
$gz = gzopen("archive.gz", "r");

Si le paramètre optionnel $use_include_path est passé à 1, alors la fonction gzopen() recherchera le fichier dans le répertoire défini par la directive de configuration include_path du php.ini. La fonction gzopen() retourne un entier valant false en cas d'erreur.

II-B. Fermeture

Syntaxe de fermeture de fichier :

 
Sélectionnez
1.
int gzclose(resource $gz)

Exemple de fermeture de fichier :

 
Sélectionnez
1.
gzclose($gz);

La fonction gzclose() retourne un entier valant true si succès, ou false en cas d'erreur.

III. Accès aux données

Les accès au contenu des fichiers ouverts dépendent de leur mode d'ouverture. On peut lire avec gzread() un fichier ouvert en lecture, et écrire avec gzwrite() dans un fichier ouvert en écriture.

III-A. Lecture

III-A-1. Par bloc

Syntaxe :

 
Sélectionnez
1.
string gzread(resource $gz, int $length)

Exemple :

 
Sélectionnez
1.
$str = gzread($gz, 1024);

La fonction gzread() retourne une chaîne de caractères en décompressant à la volée le fichier spécifié. La lecture commence à la position courante et se termine après $length caractères décompressés lus, ou en fin de fichier si celle-ci a été atteinte.

III-A-2. Par ligne

Syntaxe :

 
Sélectionnez
1.
string gzgets(resource $gz, int $length)

Retourne une chaîne décompressée de taille maximale $length - 1. La lecture s'arrête si un saut de ligne ou une fin de fichier est rencontré(e). Permet une lecture ligne par ligne du fichier.

III-A-3. Par ligne, sans balise

Syntaxe :

 
Sélectionnez
1.
string gzgetss(resource $gz, int $length [, string $allowable_tags ])

Identique à gzgets(), sauf que toutes les balises HTML et PHP sont automatiquement supprimées. Le paramètre optionnel $allowable_tags permet de lister les balises à conserver.

III-A-4. Par caractère

Syntaxe :

 
Sélectionnez
1.
string gzgetc(resource $gz)

Retourne une chaîne décompressée contenant un seul caractère. Permet une lecture caractère par caractère du fichier. Retourne false si la fin du fichier est atteinte.

III-A-5. Tout le fichier dans un tableau

Syntaxe :

 
Sélectionnez
1.
array gzfile(string $filename [, int $use_include_path ])

Exemple :

 
Sélectionnez
1.
2.
3.
4.
$file = gzfile('archive.gz');
foreach($file as $elem) {
  $text .= trim($elem);
}

Identique à la fonction file(), mais décompresse à la volée le contenu du fichier, si celui-ci est compressé (cette fonction peut donc servir à lire des fichiers non compressés). Retourne un tableau dont chaque élément est une ligne du fichier $filename. Le paramètre optionnel $use_include_path passé à 1 permet de rechercher le fichier dans le répertoire défini par la directive de configuration include_path du php.ini.

contrairement aux autres fonctions, cette fonction prend pour paramètre le nom du fichier et pas un pointeur créé par gzopen(). Il n'est donc pas utile d'ouvrir le fichier au préalable.

III-A-6. Tout le fichier à l'écran

Syntaxe :

 
Sélectionnez
1.
int readgzfile(string $filename [, int $use_include_path ])

Exemple :

 
Sélectionnez
1.
readgzfile('archive.gz');

Identique à la fonction readfile(), mais décompresse à la volée le contenu du fichier, si celui-ci est compressé (cette fonction peut donc servir à lire des fichiers non compressés). Lit le fichier et l'affiche directement dans la sortie standard. Retourne le nombre d'octets décompressés. Le paramètre optionnel $use_include_path passé à 1 permet de rechercher le fichier dans le répertoire défini par la directive de configuration include_path du php.ini.

contrairement aux autres fonctions, cette fonction prend pour paramètre le nom du fichier et pas un pointeur créé par gzopen(). Il n'est donc pas utile d'ouvrir le fichier au préalable.

III-B. Écriture

Syntaxe d'écriture :

 
Sélectionnez
1.
int gzwrite(resource $gz, string $str [, int $length ])

Exemples d'écriture :

 
Sélectionnez
1.
2.
gzwrite($gz, $str);
gzwrite($gz, $str, 1024);

La fonction gzwrite() compresse la chaîne $str à la volée et écrit le résultat dans le fichier spécifié. L'écriture débute à la position courante du fichier et s'arrête après $length caractères non compressés écrits ou dès que la fin de la chaîne $str a été atteinte.

gzputs() est un alias de gzwrite().

III-C. Position du pointeur interne

III-C-1. Position du pointeur

Syntaxe :

 
Sélectionnez
1.
int gztell(resource $gz)

Identique à ftell() : retourne la position courante du pointeur de lecture dans le fichier.

III-C-2. Déplacement du pointeur

Syntaxe :

 
Sélectionnez
1.
int gzseek(resource $gz, int $offset)

Semblable à fseek(). Déplace de $offset octets dans le fichier. S'il est ouvert en écriture, seuls les déplacements vers l'avant sont possibles : il compresse une série de zéros jusqu'à la position indiquée. Retourne 0 si succès, -1 sinon.

III-C-3. Retour au début

Syntaxe :

 
Sélectionnez
1.
int gzrewind(resource $gz)

Identique à rewind(). Replace le pointeur interne au début du fichier. Utile pour relire un fichier. Retourne 0 en cas d'échec.

III-C-4. Fin de fichier

Syntaxe :

 
Sélectionnez
1.
int gzeof(resource $gz)

Identique à feof(). Retourne true si la fin du fichier a été atteinte, false sinon.

IV. Compression à la volée

IV-A. Compression

Syntaxe de compression :

 
Sélectionnez
1.
string gzcompress(string $str [, int $level ])

Exemples de compression :

 
Sélectionnez
1.
2.
$str = gzcompress($str, 9);
$str = gzcompress($str);

La fonction gzcompress() compresse la chaîne $str et retourne le résultat. L'argument optionnel $level définit la qualité de la compression, ce doit être un nombre entier positif compris entre 0 (pas de compression) et 9 (compression maximale).

cette fonction ne doit pas être utilisée pour créer un fichier archive, car ce dernier doit comporter des entêtes que seules les fonctions gzencode() et gzopen() créent.

IV-B. Décompression

Syntaxe de décompression :

 
Sélectionnez
1.
string gzuncompress(string $str [, int $length])

Exemples de décompression :

 
Sélectionnez
1.
2.
$str = gzuncompress($str, 100);
$str = gzuncompress($str);

La fonction gzuncompress() décompresse la chaîne $str compressée par gzcompress() et retourne le résultat. Cette fonction retourne false si la chaîne décompressée est plus de 256 fois supérieure à la chaîne compressée $str, ou de taille supérieure à $length caractères.

IV-C. Compression indépendante

Syntaxe :

 
Sélectionnez
1.
string gzencode(string $data [, int $level [, int $encoding_mode ] ])

Exemple :

 
Sélectionnez
1.
2.
3.
4.
5.
$data = implode('', file('test.txt'));
$gzdata = gzencode($data, 9);
$fp = fopen('test.txt.gz', 'w');
fwrite($fp, $gzdata);
fclose($fp);

Retourne une chaîne résultant de la compression de $data ou false si échec. Le paramètre optionnel $level spécifie le niveau de compression (entre 0 et 9). Le paramètre optionnel $encoding_mode permet de spécifier la constante FORCE_GZIP (par défaut) ou bien FORCE_DEFLATE, cette dernière produit une chaîne compressée réduite sans la somme de contrôle finale CRC32.

Contrairement à gzcompress(), cette fonction produit tous les entêtes nécessaires à la création d'un fichier avec les fonctions standards.

V. Exemples

V-A. Compression d'un fichier du serveur

Le script ci-dessous procède comme suit :

  • lecture du fichier source avec les fonctions standards fopen() et fread() ;
  • compression du contenu de ce fichier avec gzencode() ;
  • création d'un nouveau fichier avec les fonctions standards, dont le contenu est le résultat de la compression du premier fichier ;
  • affichage à l'écran du grain de la compression en valeur absolue et en valeur relative.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
<?php
/******************************************
* COMPRESSION D'UN FICHIER DU SERVEUR

*  - lecture des données originales
*  - compression avec gzencode()
*  - écriture des données compressées
*  - affichage du gain de la compression

*        29 mai 2003, Hugo ETIEVANT
*  http://cyberzoide.developpez.com/php4/
*******************************************/

// nom et chemin du fichier à compresser
$filename = './gz.pdf';

// ouverture du fichier à compresser
if($fp = fopen($filename, "rb")) {

  // lecture du contenu
  $size1 = filesize($filename);
  $data = fread($fp, $size1);
  // fermeture
  fclose($fp);
  
  // compression des données
  $gzdata = gzencode($data, 9);
  
  // ouverture et création du fichier compressé
  if($fp = fopen($filename.'.gz', 'wb')) {

    // écriture des données compressées
    fwrite($fp, $gzdata);
    // fermeture
    fclose($fp);
    
    // calcul gain de la compression
    $size2 = filesize($filename.'.gz');
    $diff = $size1-$size2;
    $pc = round($diff/$size1*100, 2);
    echo "Gain de la compression : $diff octets soit $pc %.";

  } else {
    echo "Impossible d'ouvrir $filename.gz en écriture.";
  } 

} else {
  echo "Impossible d'ouvrir $filename en lecture.";
}

?>

Affiche ceci :

 
Sélectionnez
1.
Gain de la compression : 17909 octets soit 32.63 %.

V-B. Affichage du contenu d'un fichier compressé

Le script ci-dessous procède comme suit :

  • ouverture d'un fichier compressé avec gzopen() en mode lecture binaire (« rb ») ;
  • lecture et décompression à la volée du contenu par bloc de 1024 avec gzread() tant que la fin de fichier n'est pas vérifiée (gzeof()) ;
  • affichage du texte à l'écran.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
<?php
/******************************************
* LECTURE D'UN FICHIER COMPRESSE

*        29 mai 2003, Hugo ETIEVANT
*  http://cyberzoide.developpez.com/php4/
*******************************************/

// nom et chemin du fichier compressé
$filename = './gz.txt.gz';

// ouverture du fichier compresser à lire
if($gz = gzopen($filename, "rb")) {

  // tant qu'on n'a pas atteint la fin du fichier
  while(!gzeof($gz)) {
    // lecture et décompression à la volée
    $text.= gzread($gz, 1024);
  }
  
  // affichage du texte
  echo $text;
  
} else {
  echo "Impossible d'ouvrir $filename en lecture.";
}

?>

Je remercie Le vieux pour la relecture et ses suggestions de corrections orthographiques.