I am trying to fix an issue in an auto-zip script for some images, which I wrote a while ago and it worked until now. Everything seems fine until $zip->close();
which gives the following:
<b>Warning</b>: ZipArchive::close(): Read error: No such file or directory in <b></b> on line <b>287</b><br />
I read the docs and some forums and found out that this could happen in one of the following scenarios:
file_exists()
on the file$zip->numFiles
and it gives a number of at least 1 (when the zip has no files except the dummy)Here is the relevant code. Some variables are defined beforehand. Note that I write every problem to my log, and this script doesn't generate any entries!
$zip_file = 'Project'.$project_id.'.zip';
$zip = new ZipArchive;
if ($zip_result = $zip->open($zip_path.'/'.$zip_file, ZIPARCHIVE::CREATE) !== true) {
echo 'Error creating zip for project: '.$project_id.'. Error code: '.$zip_result;
help::debugLog('Error creating zip for project: '.$project_id.'. Error code: '.$zip_result);
return false;
}
$file_list = array();
foreach ($item_thumbs as $item)
{
$full_thumb_path = $thumb_dir.'/'.$item['thumb'];
if (file_exists($full_thumb_path) and $item['thumb'])
{
$file_added = $zip->addFile($full_thumb_path, basename($item['thumb']));
if (!$file_added)
help::debugLog('Failed to add item thumb to project zip. Project: '.$project_id.', file name: '.$item['thumb']);
else
$file_list[] = $item['thumb'];
}
elseif ($item['thumb']) /* If thumb indicated in DB doesn't exist in file system */
help::debugLog('Item thumb file '.$item['thumb'].' from item: '.$item['id'].' is missing from its indended location: '.$full_thumb_path);
}
/* Added 2016-05-18 -- creates dummy file for the zip listing its contents, important in case zip is empty */
$file_list_path = $zip_path.'/file_list.txt';
if (!($file_list_file = fopen($file_list_path, 'w+')))
help::debugLog('Failed to create list file (intended for zip) for project: '.$project_id);
fwrite($file_list_file, "File list:\n");
fwrite($file_list_file, implode("\n", $file_list));
if (file_exists($file_list_path))
{
fclose($file_list_file);
if (!$zip->addFile($file_list_path))
help::debugLog('Failed to add list file to project zip for project: '.$project_id);
unlink($file_list_path);
}
else
help::debugLog('Failed to create list file (intended for zip) for project: '.$project_id);
$zip->close(); // line 287
Turns out the solution was very simple, and it's actually referred to in the docs (php.net), in one of the comments:
It may seem a little obvious to some but it was an oversight on my behalf.
If you are adding files to the zip file that you want to be deleted make sure you delete AFTER you call the close() function.
If the files added to the object aren't available at save time the zip file will not be created.
(Source: https://www.php.net/manual/en/ziparchive.close.php#93322)
So from my code above, the "dummy" text file is deleted before the zip is closed, necessarily making it that the file doesn't exist at the time the zip is created.
I had good reason to believe that the zip was created in a temporary location and only moved to the final location on close()
. Turns out this is not the case.