PHP: Listing files in a ZIP archive
Have you ever wanted to be able to look inside a zip archive using PHP to see what is in there without having to first unzip the file? Here we present a standalone static PHP class that does just that.
ZipArchiveBrowser source code
Here is the complete source code for \Chirp\ZipArchiveBrowser:
<?PHP
namespace Chirp;
class ZipArchiveBrowser
{
// Original PHP code by Chirp Internet: www.chirpinternet.eu
// Please acknowledge use of this code by including this header.
private static $files = []; // file tree
private static function add_directory(&$base, $parts)
{
// add an empty directory to the tree
$dir = array_shift($parts);
if(!isset($base[$dir])) {
$base[$dir] = [];
}
if(isset($parts[0]) && $parts[0]) {
self::add_directory($base[$dir], $parts);
}
}
private static function add_file(&$base, $parts)
{
// add a file to the tree
if(isset($parts[1]) && $parts[1]) {
self::add_file($base[array_shift($parts)], $parts);
} else {
$base[] = end($parts);
}
}
public static function get_contents($inputfile, $include_empty_dirs = TRUE)
{
if(!file_exists($inputfile)) {
throw new \Exception("File Not Found.");
return FALSE;
}
// open zip file using ZipArchive
$zip = new \ZipArchive;
if(TRUE === ($ret = $zip->open($inputfile, \ZipArchive::RDONLY))) {
$numfiles = $zip->count();
for($idx=0; $idx < $numfiles; $idx++) {
$parts = explode(DIRECTORY_SEPARATOR, $zip->getNameIndex($idx));
if(end($parts)) {
// found a file
self::add_file(self::$files, $parts);
} elseif($include_empty_dirs) {
// found an empty directory
self::add_directory(self::$files, $parts);
}
} // for each entry in zip file
$zip->close();
} else {
throw new \Exception("File could not be opened by ZipArchive.", $ret);
return FALSE;
}
return self::$files;
}
}
There is a single public method get_contents() which will return a file tree describing the zip archive contents as an array. It has a flag to let you exclude empty directories. By default empty directories will be included in the output.
The add_* methods operate recursively by passing down the current branch (position in the tree) that is being constructed.
Using ZipArchiveBrowser
Using the ZipArchiveBrowser class is straight-forward:
<?PHP
$inputfile = "path-to-your-zip-file.zip"
try {
$output = \Chirp\ZipArchiveBrowser::get_contents($inputfile);
echo "<pre>",print_r($output),"</pre>\n";
} catch(\Exception $e) {
echo "Caught exception: (",$e->getCode(),") ",$e->getMessage(),"\n";
}
?>
Note that because this is a static class you don't have to instantiate an object using new, but can instead invoke the public method directly using ::.
THe class will throw an Exception in the case of a missing file or one that can't be opened by ZipArchive. In the latter case there will be an error code that can be looked up here. For example, ZipArchive::ER_NOZIP (19) means 'Not a zip archive'.
Sample output
For a simple zip archive with no directories:
Array
(
[0] => Style Guide.pdf
[1] => Logo.png
[2] => Logo.eps
[3] => logo.jpg
)
For a more complicated folder structure:
Array
(
[Random Images] => Array
(
[0] => background4.jpg
[1] => background5.jpg
[2] => background7.jpg
[3] => maze-builder-4.png
[4] => background6.jpg
[5] => balloon-orange.png
[6] => background2.jpg
[7] => .DS_Store
[8] => maze-builder-1.png
[9] => background3.jpg
[10] => background1.jpg
[11] => maze-builder-3.png
[12] => maze-builder-2.png
[13] => balloon-blue.png
[14] => background10.jpg
[15] => background11.jpg
[empty folder] => Array
(
)
[16] => balloon.png
[another folder] => Array
(
[yet another folder] => Array
(
[0] => background12.jpg
)
[0] => .DS_Store
)
)
)
The input needs to be a local file that is readable by the web server. In practice this may be a user-uploaded file or one that has been fetched from a third-party API. The ZIP file is not actually unpacked by this script - it just has its index read.
To have the files listed alphabetically you can just use asort($output) in the above code. For more advanced sorting options see our article on Directory Listing using SPL where we demonstrate how to use the SplHeap PHP class.
An HTML form for uploading
To get you started, here is an HTML form you can use to allow a ZIP file to be uploaded for processing:
<form method="POST" action="#" enctype="multipart/form-data">
<p>Zip File: <input type="file" required name="zipfile" accept="application/zip"></p>
<p><input type="submit" name="upload" value="Upload"></p>
</form>
Note that the 'enctype' form attribute is required if you want the file to be uploaded, while the 'accept' attribute on the file input is advisory only and will not actually prevent uploading of other file types by the browser.
You can then get the location of the uploaded (temporary) file using:
<?PHP
$inputfile = $_FILES['zipfile']['tmp_name'];
?>
Please be careful allowing users to upload files to your server!
Future developments
The above script, while useful, is just a first step towards a system that we are developing that will allow in-place editing of the ZIP archive contents to delete and rename files and then re-save the file. Stay tuned for details.
References
- PHP.net: The ZipArchive class
Related Articles - Parsing files
- PHP Parsing HTML to find Links
- PHP Parsing robots.txt
- PHP Parsing HTML files with DOMDocument and DOMXpath
- PHP Listing files in a ZIP archive