new ZipArchive()

20 mai 2013 nakama

Développement

(Cet article a été écrit il y a très longtemps, dans une galaxie très très lointaine)

Nous allons voir comment créer un ZIP à partir d’un dossier que l’on aura spécifié.

On va utiliser la classe ZipArchive de php et créer une classe perso qui va contenir tout le script (par exemple zip.php).

Le début

// on crée notre classe perso
class ZipCreate {

    // on pérpare des variables
	private $name;
	private $root;
	private $folder;
	private $zip;

    // fichier à exclure
    private $excludeFiles = array();

    // fichier particulier à exclure de chaque dossier
    private $excludeAllFiles = array();

    // dossier à exclure
    private $excludeFolders = array();

    // extention à exclure
    private $excludeExt = array();

Je pense qu’une explication est inutile, les variables commencent par $exclude vont nous permettre d’exclure certain fichier/dossier.

Le constructeur

function __construct($root, $nomZip = NULL, $folder = NULL){

	// On instancie la classe
    $this->zip = new ZipArchive();

    // nom du zip : par défaut archive
    $this->name = ($nomZip != "") ? $nomZip : 'archive';
    $this->name = $this->name.'-'.date("Ymd-Hi").'.zip';

    // chemin du fichier
    $this->root = $root;

    // On valide le chemin spécifié : si c'est bien un dossier
    if (! is_dir($this->root)) return exit;

    // nom du dossier qui va contenir les zip : par défaut zip
    $this->folder = ($folder != "") ? $folder : 'zip';

    // si le dossier n'existe pas, on le crée
    if(!file_exists($this->folder)) mkdir($this->folder);

    // On crée une nouvelle archive
    if(! $this->zip->open($this->folder.'/'.$this->name, ZipArchive::CREATE) == TRUE) return;
}

Grâce au constructeur, dès que l’on va instancier la classe, tous ces éléments seront exécutés.

Explications :

– on instancie la classe ZipArchive de php
– on configure le nom du zip et le chemin du fichier (root)
– on vérifie que le fichier est bien un dossier
– on crée le dossier qui va sauvegarder le zip s’il n’existe pas
– on crée l’archive

Les méthodes

// Ajouter un nom de fichier à exclure
// bien spécifier le chemin du fichier
public function excludeFiles($filenames) {
    foreach ($filenames as $value) {
        $this->excludeFiles[] = $this->root.$value;
    }
}

// Ajouter un nom de fichier à exclure
// de tous les dossiers
public function excludeAllFiles($Allfilenames) {
    $this->excludeAllFiles = $Allfilenames;
}

// Ajouter un répertoire à exclure
public function excludeFolders($dir) {
    foreach ($dir as $value) {
        $this->excludeFolders[] = $this->root.$value;
    }
}

// Ajouter une extension à exclure
public function excludeExt($ext) {
    $this->excludeExt = $ext;
}

Les méthodes sont en public, car on va devoir les appeler en dehors de la classe pour spécifier les fichiers à exclure et elles prennent toutes en paramètre un tableau.

Pour la méthode excludeFiles et excludeFolders, le foreach sert à rajouter le nom du dossier que l’on va zip. Comme cela, quand on va spécifier les fichiers/dossiers à exclure, il ne sera pas utile d’ajouter à chaque fois le dossier que l’on souhaite zip (se sera plus clair dans la partie instanciation de la classe perso un peu plus bas).

// création du zip + téléchargement si $dl = true
public function creationZip($dl = false, $delete = false) {

    $this->addDir($this->root);

    // on ferme le zip
    $this->zip->close();

    // si $dl = true on propose le zip à télécharger
    if($dl === true){
        header('Content-Transfer-Encoding: binary');
	    header('Content-Disposition: attachment; filename="'.$this->name);
	    header('Content-Length: '.filesize($this->folder.'/'.$this->name));
	    readfile($this->folder.'/'.$this->name);

        // $delete = true on supprime le fichier après l'avoir téléchargé
        if($delete === true) unlink($this->folder.'/'.$this->name);
    }
}

Cette méthode nous sert à créé le zip, à le proposer en téléchargement et à le supprimer ou non du dossier (utile si l’on souhaite uniquement le proposer au téléchargement et ne rien conserver sur le serveur).

On fait appel à notre méthode addDir pour ajouter tous les fichiers/dossiers au zip.

Les 2 paramètres ne sont pas obligatoire :

– si le 1er vaut TRUE alors on propose le téléchargement
– si le 2e vaut TRUE alors on supprime le fichier, après l’avoir proposé en téléchargement

Le 2e paramètre est lié au 1er, on peut choisir de conserver ou non le fichier uniquement après avoir téléchargé le fichier !

La dernière méthode : récursive ?

    private function addDir($path) {

        // Lecture des fichiers
        $fichiers = scandir($path);
        // Suppression des . et ..
        unset($fichiers[0], $fichiers[1]);

        foreach($fichiers as $fichier){
            // on test si le fichier est un dossier
            if(is_dir($path.$fichier)) {
                // si le dossier ne se trouve pas dans les dossiers exclus
                // on appel de nouveau la méthode addDir avec en paramètre le nouveau dossier
                if ( !in_array($path.$fichier.'/', $this->excludeFolders) )
                    $this->addDir($path.$fichier.'/');
            }else{
                // si le fichier ne se trouve pas dans les fichiers exclus
                // si l'extension ne se trouve pas les extensions exclus
                // si le fichier ne se trouve pas les fichiers exclus de tous les dossiers
                // on l'ajoute à l'archive
                if ( (!in_array($path.$fichier, $this->excludeFiles)) && (!in_array(pathinfo($fichier, PATHINFO_EXTENSION), $this->excludeExt)) && (!in_array($fichier, $this->excludeAllFiles)) )
                    $this->zip->addFile($path.$fichier);
            }
        }
    }
} // fin classe

Déjà, avant tout, que signifie récursive ? Regardez la ligne 14, on fait de nouveau appel à la méthode addDir. Récursive signifie que la méthode s’appelle elle-même.

Explications :

– on scan le fichier
– on supprime le . (dossier actuel) et les .. (dossier parent)
– on teste si le fichier est un dossier ou non
– s’il s’agit d’un fichier, on vérifie qu’il ne se trouve pas dans les tableaux des fichiers à exclure et s’il ne s’y trouve pas, on l’ajoute à l’archive.
– s’il s’agit d’un dossier, on vérifie qu’il ne se trouve pas le tableau des dossiers à exclure et s’il ne s’y trouve pas, on appelle de nouveau la méthode addDir pour récupérer le contenu du dossier.

Ce fonctionnement est le même pour chaque dossier et sous-dossier, jusqu’à ce qu’il n’y ait plus de dossier à parcourir.

Pas de panique

La méthode récursive reprend là où elle s’arrête : (exemple)

– dans un dossier (img) qui contient des images et un sous-dossier avec d’autres images
– la méthode ajoute les fichiers au zip et arrive au sous-dossier
– elle fait appel de nouveau à la méthode et parcours le sous-dossier en ajoutant les fichiers
– une fois fini, elle continue d’ajouter le reste des fichiers du dossiers précédent

Le mécanisme de récursivité est assez complexe à comprendre au début, mais en vous entrainant à l’utiliser vous vous sentirez beaucoup plus à l’aise avec ce fonctionnement.

Le fichier qui fait appel au script de zip

Par exemple : download.php

include_once 'zip.php';

// 1er argument : le dossier que l'on va zip
// 2e  argument : le nom du zip (optionnel) par défaut : archive
// 3e  argument : le dossier qui va save le zip (optionnel) par défaut : zip
$zip = new ZipCreate('www/', 'siteWeb');

// on exclut certain fichier
$zip->excludeFiles(array('inc/info.ini'));

// on exclut tous les fichiers informations.txt
$zip->excludeAllFiles(array('informations.txt'));

// on exclut l'extension mac
$zip->excludeExt(array('.DS_Store'));

// on exclut le dossier .git, .sass-cache et thumb
$zip->excludeFolders(array('.git/', 'sass/.sass-cache/', 'img/thumb/'));

$zip->creationZip(true);

Explications :

– on ajoute notre classe perso et on l’instancie
– on précise les fichiers/dossiers à exclure
– on appelle la méthode qui va créer le zip et le proposer en téléchargement

La structure que j’ai utilisé pour le test :

Les éléments surlignés ne seront PAS pris en compte dans le zip (avec le fichier download.php vu juste avant). Nom de l’archive qui sera créée : siteWeb-20130519-2259.zip

-dl_zip/
-dl_zip/zip/
-dl_zip/download.php
-dl_zip/zip.php

-dl_zip/www/
-dl_zip/www/.git/
-dl_zip/www/.git/config

-dl_zip/www/css/
-dl_zip/www/css/informations.txt
-dl_zip/www/css/reset.css
-dl_zip/www/css/style.css

-dl_zip/www/js/
-dl_zip/www/js/scripts.js

-dl_zip/www/sass/
-dl_zip/www/sass/informations.txt
-dl_zip/www/sass/_main.scss
-dl_zip/www/sass/_font_scss
-dl_zip/www/sass/.sass-cache/
-dl_zip/www/sass/.sass-cache/main.scss

-dl_zip/www/inc/
-dl_zip/www/inc/info.ini
-dl_zip/www/inc/informations.txt
-dl_zip/www/inc/config.php

-dl_zip/www/img/
-dl_zip/www/img/image01.png
-dl_zip/www/img/image02.png
-dl_zip/www/img/thumb/
-dl_zip/www/img/thumb/thumb_image01.png
-dl_zip/www/img/thumb/thumb_image02.png

Attention : un dossier vide ne sera pas ajouté au zip.

Mots-clés associés à cet article :

Retrouvez d'autres articles par catégories