Extraire un ZIP en PHP

Octobre 2012

Extraire un ZIP directement en PHP peut-être très utile, par exemple pour permettre d'uploader plusieurs fichiers avec un seul champ de type file (bouton Parcourir) dans un formulaire HTML.

Pour créer et extraire (lire/écrire) des archives ZIP en PHP, il y a 2 solutions :

  • Utiliser l'extension php Zip qui propose plusieurs fonctions permettant de manipuler les ZIP
  • Utiliser un programme externe en ligne de commande, comme la commande unzip

Avec l'extension ZIP

Pour pouvoir utiliser cette extension, il faut l'avoir activé. Pour activer l'extension ZIP, ouvrez le fichier de configuration PHP : php.ini, et assurez vous que la ligne suivante est décommentée :

extension=php_zip.dll

Pour l'exemple, nous allons créer une fonction qui extrait les fichiers à la racine d'un ZIP dans un répertoire. Cette fonction prendra 2 arguments :

  • $archivePath : le chemin absolu vers le fichier zip, exemple: /tmp/mon_archive.zip
  • $extractDirectory : chemin du dossier où va être extrait le zip
<?php
/**
 * Extrait un zip dans le dossier $extractDirectory
 * Créé le dossier $extractDirectory si il n'existe pas.
 * Seuls les fichiers à la racine du zip ou du premier élément du zip si celui-ci est un dossier sont extraits.
**/
function massUploadUnzipTo($archivePath, $extractDirectory){
	$verbose = array(); // Enregistre les différents événements (utile pour debug)
	$zip = zip_open($archivePath);

	if( !is_resource($zip) ){
		trigger_error("Unable to open zip file", E_USER_NOTICE);
		return false;
	}

	// Création du dossier d'extraction si il n'existe pas
	if( !is_dir($extractDirectory) ){
		if( !mkdir($extractDirectory, 0777, true) ){
			trigger_error("Unable to create extract directory", E_USER_WARNING);
		}
		chmod($extractDirectory, 0777);
	}

	// Test du premier élément : si c'est un dossier on extrait uniquement le contenu de ce dossier, si c'est un fichier on on extrait tous les fichiers à la racine du zip
	// Si le premier élément est vide, le zip est vide, et on sort de la fonction
	if( ($zip_entry = zip_read($zip)) === false ){
		trigger_error("Zip file is empty", E_USER_NOTICE);
		return false;
	}
	// Dossier conteneur (c'est un dossier si son nom se termine pas \ ou /
	if( preg_match('#[\\/]$#', zip_entry_name($zip_entry)) ){
		$zipRoot = zip_entry_name($zip_entry);
	}
	// Fichiers directement à la racine du zip
	else {
		$zipRoot = '';
		file_put_contents($extractDirectory.'/'.zip_entry_name($zip_entry), zip_entry_read($zip_entry, zip_entry_filesize($zip_entry))); // Extraction du premier fichier
	}

	$verbose[] = 'zipRoot: '.$zipRoot;
	$verbose[] = 'first zip entry: '.zip_entry_name($zip_entry);

	// Parcours du zip (éléments suivants)
	while( ($zip_entry = zip_read($zip)) !== false ){
		$currentEntryName = zip_entry_name($zip_entry);

		// Si l'entrée est un dossier, on l'ignore
		if( preg_match('#[\\/]$#', $currentEntryName) ){
			$verbose[] = "$currentEntryName ignored (is folder)";
			continue;
		}

		// Si l'entrée n'est pas dans le dossier qui nous intéresse ($zipRoot), on l'ignore
		if( !preg_match('#^'.$zipRoot.'[^\\/]+$#', $currentEntryName) ){
			$verbose[] = "$currentEntryName ignored (not in zipRoot)";
			continue;
		}

		$verbose[] = "Extracting ".$currentEntryName;
		$extractFilenameFullpath = $extractDirectory.'/'.basename($currentEntryName);
		file_put_contents($extractFilenameFullpath, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry))); // Extraction du premier fichier
		chmod($extractFilenameFullpath, 0777);
	}

	// debug
	//echo '<pre>'.implode("\n", $verbose).'</pre>';
}
?>

Le code est bien commenté donc il ne nécessite pas d'explication particulière. Si vous ne comprenez pas quelque chose, vous pouvez poster un commentaire ou vous inscrire sur le forum.

Commande unzip

L'autre solution c'est d'utiliser un programme en ligne de commande.

Sur UNIX (Linux, BSD, MacOS...) il existe le programme unzip fourni par défaut.

Si vous voulez en savoir plus c'est par ici : excel affiche des dièse à la place du texte.

Son utilisation est extrémement simple, il suffit de lui passer le chemin de l'archive pour extraire dans le dossier courant :

unzip /tmp/mon_archive.zip

Pour exécuter cette commande en PHP, il suffit d'utiliser la fonction exec :

<?php
exec("unzip /tmp/mon_archive.zip");
?>

Si vous êtes sous Windows, vous pouvez utiliser WinRAR qui fonctionne aussi en ligne de commande. Voici d'ailleurs une page qui liste toutes les options (switches) de winrar.exe : http://www.computerhope.com/forum/index.php?topic=74907.0.

Fini de lire cette page ? allez faire un tour ici : dessiner angry birds, ça peut vous intéresser.

0 commentaire
facultatif
Facebook Twitter RSS Email
Forum Excel
Venez découvrir le nouveau forum excel question/réponse à la stackoverflow.com !
Forum Excel
hit parade n'en a rien a foutre du W3C Positionnement et Statistiques Gratuites Vincent Paré