PHP Zip
Les archives ZIP permettent de compresser et regrouper des fichiers en PHP grâce à la classe ZipArchive pour créer, lire et extraire des archives.
Une archive ZIP est un fichier qui regroupe un ou plusieurs fichiers et les compresse à l'aide de l'algorithme zip. Les archives sont largement utilisées pour réduire la taille des téléchargements, regrouper des fichiers liés en une seule unité distribuable et sauvegarder des données. Une archive zip porte normalement l'extension de fichier .zip.
Ce chapitre montre comment créer, lire et extraire des archives ZIP en PHP moderne à l'aide de la classe intégrée ZipArchive, avec des exemples exécutables et les pièges à connaître.
La classe ZipArchive
Les anciennes fonctions procédurales zip_* ont été dépréciées dans PHP 7.4 et supprimées dans PHP 8.0. Le code moderne doit utiliser la classe orientée objet ZipArchive, qui fait partie de l'extension zip intégrée (activez ext-zip si elle n'est pas déjà active — vérifiez avec extension_loaded('zip')).
Les méthodes que vous utiliserez le plus souvent sont :
| Méthode | Rôle |
|---|---|
open($filename, $flags) | Ouvre une archive en lecture ou en écriture. Retourne true ou un code d'erreur. |
addFile($path, $entryName) | Ajoute un fichier du disque à l'archive. |
addFromString($entryName, $contents) | Ajoute une entrée à partir d'une chaîne en mémoire. |
addEmptyDir($dirName) | Ajoute une entrée de répertoire vide. |
extractTo($directory, $entries) | Extrait toutes les entrées (ou un sous-ensemble choisi) vers un répertoire. |
getFromName($entryName) | Lit une entrée dans une chaîne sans toucher le disque. |
statIndex($i) / numFiles | Inspecte les entrées et les compte. |
getStatusString() | Retourne un message d'état lisible pour la gestion des erreurs. |
close() | Écrit les modifications en attente et ferme le handle. |
Important : Les modifications effectuées avec
addFile()ouaddFromString()ne sont écrites sur le disque que lorsque vous appelezclose(). Oublierclose()produit une archive vide ou corrompue.
Créer une archive ZIP
Passez le flag ZipArchive::CREATE pour créer une nouvelle archive, et ajoutez ZipArchive::OVERWRITE pour repartir de zéro si un fichier portant ce nom existe déjà :
$zip = new ZipArchive();
$zipName = 'documents.zip';
if ($zip->open($zipName, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) {
// Add an entry from a string (no temp file needed).
$zip->addFromString('readme.txt', "Hello from PHP!\n");
// Add a file from disk, optionally under a folder inside the archive.
$zip->addFile('report.csv', 'data/report.csv');
// Add an empty directory entry.
$zip->addEmptyDir('logs');
echo "Adding {$zip->numFiles} entries to {$zipName}.\n";
$zip->close(); // Must be called for the archive to be written.
echo "Archive saved.\n";
} else {
echo "Could not create the archive.\n";
}En supposant que report.csv existe, cela affiche :
Adding 3 entries to documents.zip.
Archive saved.Lisez numFiles avant close() — une fois le handle fermé, l'objet ne reflète plus le nombre d'entrées.
Lire des entrées sans extraire
Vous pouvez inspecter le contenu d'une archive, ou extraire une seule entrée en mémoire, sans tout décompresser sur le disque :
$zip = new ZipArchive();
if ($zip->open('documents.zip') === true) {
for ($i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->statIndex($i);
echo $entry['name'] . ' (' . $entry['size'] . " bytes)\n";
}
// Read one entry straight into a string.
echo "---\n" . $zip->getFromName('readme.txt');
$zip->close();
}Résultat :
readme.txt (16 bytes)
data/report.csv (20 bytes)
logs/ (0 bytes)
---
Hello from PHP!Extraire une archive sur le disque
extractTo() décompresse l'archive. Vérifiez toujours la valeur de retour et signalez les échecs avec getStatusString() :
$zip = new ZipArchive();
$filename = 'documents.zip';
$extractTo = './extracted_files';
if ($zip->open($filename) === true) {
if (!is_dir($extractTo)) {
mkdir($extractTo, 0755, true);
}
if ($zip->extractTo($extractTo) === true) {
echo "Archive extracted successfully.";
} else {
echo "Extraction failed: " . $zip->getStatusString();
}
$zip->close();
} else {
echo "Failed to open archive.";
}Pour extraire uniquement des fichiers spécifiques, passez leurs noms en second argument :
$zip->extractTo($extractTo, ['readme.txt', 'data/report.csv']);Pièges courants
- Appelez toujours
close(). Tant que vous ne le faites pas, les ajouts n'existent qu'en mémoire et le fichier sur le disque peut être vide. open()ne retourne pasfalsepour toutes les erreurs. En cas d'échec, elle retourne un code d'erreur entier (par exempleZipArchive::ER_NOENTlorsque le fichier est manquant). Comparer strictement avec=== trueest la manière sûre de détecter le succès.- Zip Slip. Lors de l'extraction d'archives non fiables, une entrée malveillante nommée comme
../../etc/passwdpeut s'échapper du répertoire cible. Validez ou désinfectez les noms d'entrées avant d'extraire des fichiers que vous n'avez pas créés. - Mémoire.
getFromName()charge toute l'entrée en mémoire ; pour les grandes entrées, préférezextractTo()ou utilisez un flux avecgetStream().
Sujets connexes
- PHP file_put_contents() — écrire les données lues depuis une archive sur le disque.
- PHP file_get_contents() — lire des fichiers entiers, par exemple avant de les ajouter à un zip.
- PHP file_exists() — confirmer qu'un fichier est présent avant d'appeler
addFile(). - PHP fread() — lire le contenu d'un fichier par morceaux.
Conclusion
La classe ZipArchive est la manière moderne et fiable de travailler avec des archives ZIP en PHP. Vous pouvez créer des archives avec addFile() et addFromString(), les inspecter avec numFiles et statIndex(), extraire des entrées individuelles en mémoire avec getFromName(), et les décompresser avec extractTo() — en n'oubliant jamais d'appeler close() et de vous prémunir contre les noms d'entrées non fiables lors de l'extraction.