ZipArchive issue "Error 21 - Is a Directory" in PHP
Asked Answered
P

2

10

I'm generating a set of HTML, CSS, and image files and I'm using ZipArchive to compress them into a zip file. I've confirmed that the generated assets are valid, but when I attempt to zip the set of files, the resulting archive file is not able to be opened.

I'm not getting any errors in the PHP and when I echo $zip->close() it returns true which I assume to mean that it was able to write to and save the file without issue. Opening the zip with the mac Archive Utility throws this error:

"Unable to expand "filename.zip" into "Downloads". (Error 21 - Is a directory.)

What might be wrong here?

Here is the entire PHP script:

<?php
$ref = $_SERVER["HTTP_REFERER"];
$html = $_REQUEST['html'];
$images = $_REQUEST['images'];

$folder = uniqid();
$prepped = str_replace($ref.'server/php/files/', 'images/', $html);

mkdir("./runways/$folder", 0777);
mkdir("./runways/$folder/images", 0777);
mkdir("./runways/$folder/css", 0777);


file_put_contents('./runways/'.$folder.'/index.html',$prepped);
copy('../../css/runway.css', './runways/'.$folder.'/css/runway.css');

foreach($images as $image) {
    $i = urldecode(str_replace($ref.'server/php/files/', '', $image));
    $idata = file_get_contents('./files/'.$i);
    file_put_contents('./runways/'.$folder.'/images/'.$i, $idata);

}

//echo $ref.'server/php/runways/'.$folder.'/';

$sourcefolder = './runways/'.$folder.'/';
$zipfilename = $folder.'.zip';

$dirlist = new RecursiveDirectoryIterator($sourcefolder);
$filelist = new RecursiveIteratorIterator($dirlist);

ini_set('max_execution_time', 5000);
$zip = new ZipArchive();

if ($zip->open('./zips/'.$zipfilename, ZIPARCHIVE::CREATE) !== TRUE) {
    die ("Could not open archive");
}

foreach ($filelist as $key=>$value) {
    $zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
}
$zip->close();

echo $ref.'server/php/zips/'.$zipfilename;

?>
Provocative answered 20/5, 2014 at 22:45 Comment(0)
K
1

The archive you're creating includes current working directories and parent directories (filenames "." and ".."), which you should leave out. For example if you view the contents of an archive the original code creates, you'll see something like this:

$ unzip -l 54b69fbd2de29.zip 
Archive:  54b69fbd2de29.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  01-14-15 09:56   ./runways/54b69fbd2de29/.
        0  01-14-15 09:56   ./runways/54b69fbd2de29/..
        0  01-14-15 09:56   ./runways/54b69fbd2de29/css/.
        0  01-14-15 09:56   ./runways/54b69fbd2de29/css/..
       12  01-14-15 09:56   ./runways/54b69fbd2de29/css/runway.css
        0  01-14-15 09:56   ./runways/54b69fbd2de29/images/.
        0  01-14-15 09:56   ./runways/54b69fbd2de29/images/..
       26  01-14-15 09:56   ./runways/54b69fbd2de29/images/image1.jpg
       31  01-14-15 09:56   ./runways/54b69fbd2de29/images/image2.jpg
        6  01-14-15 09:56   ./runways/54b69fbd2de29/index.html
 --------                   -------
       75                   10 files

You don't want "./runways/54b69fbd2de29/." or "./runways/54b69fbd2de29/..", etc. Here's one way to fix this, change the final foreach to the following (note also that you don't need $key=>$value, just $key):

foreach ($filelist as $key) {
    if (!preg_match('/\/\.{1,2}$/',$key)){
        $zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
    }
}

The resulting archive is valid, and looks like this:

unzip -l 54b6a39d55a63.zip 
Archive:  54b6a39d55a63.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
       12  01-14-15 10:13   ./runways/54b6a39d55a63/css/runway.css
       26  01-14-15 10:13   ./runways/54b6a39d55a63/images/image1.jpg
       31  01-14-15 10:13   ./runways/54b6a39d55a63/images/image2.jpg
        6  01-14-15 10:13   ./runways/54b6a39d55a63/index.html
 --------                   -------
       75                   4 files
Klina answered 14/1, 2015 at 17:20 Comment(0)
T
1

A little background: I have chosen for my website to be wiped, and I have downloaded public_html as a zip file. I was a bit scared I wouldn't be able restore my website once it has been reset.

A quick solution (and the one that worked for me) is to use an app from the App Store called The Unarchiver. I had this same issue when using a file compressed from the cPanel file manager, and The Unarchiver seemed to fix it.

Theodoratheodore answered 8/8, 2016 at 7:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.