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.