corrupted zip with readfile - php

I'm using this code to have users download all files in a given directory:
<?php
set_time_limit();
$zipname = getcwd();
$zipname = substr($zipname,strrpos($zipname,'/')+1);
$zipname = $zipname.'.zip';
$zip = new ZipArchive;
$zip->open('./'.basename($zipname).'', ZipArchive::CREATE);
if ($dir_handle = opendir('./')) {
while (false !== ($entry = readdir($dir_handle))) {
if ($entry != "." && $entry != ".." && !strstr($entry,'.php')) {
$zip->addFile($entry);
}
}
closedir($dir_handle);
}
else {
die('file not found');
}
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="'.basename($zipname).'"');
header('Content-Length: ' . filesize($zipname));
header('Location: ./'.$zipname);
?>
The code works perfectly, but I wanted to delete from the server after the user downloads it, so I tried by just adding
unlink($zipname);
in the last line. Obviously I got a File not found error.
Then I tried replacing the last header with
readfile($zipname);
and the download starts, but the zip file downloaded is somehow corrupted and will not unzip.
What am I doing wrong?
Thanks for your help

That's because $zipname is just .zip after your substr call.
example:
https://3v4l.org/7L515
Do this instead:
$zipname = dirname(__FILE__).".zip";
also, this sounds like a bad idea to begin with.

Related

Files are not being added to the ZIP archive php

I tried two ways for adding files to ZIP. But none of them are working. Downloaded ZIP size is 0 Bytes. I have the following code to add files from uploads/Applications folder to the ZIP archive.
$zip = new ZipArchive();
$zip_name = "REU_Files.zip";
if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE)
die("Sorry ZIP creation failed at this time");
// first try
$handle = opendir("uploads/Applications/");
while(false !== ($file = readdir($handle)))
if ($file != "." && $file != "..")
{
$zip->addFile("uploads/Applications/" . $file);
}
// Second try
$zip->addEmptyDir("Applications/");
foreach (glob("uploads/Applications/*") as $file) {
$zip->addFile($file, "Applications/" . basename($file));
}
$zip->close();
// Making zip downloadable
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
readfile($zip_name);
unlink($zip_name);
Please help me finding where my code went wrong. Thanks in advance.

Zip files in a folder and give the archive folder's name

I'm very new to php and I just made my first script, which is working fine, but is missing a final touch.
The script zips all files in the folder containing the php and creates a downloadable archive.
Here's the code
<?php
$zipname = 'test.zip';
$zip = new ZipArchive;
$zip->open('D://mypath//zip//$zipname', ZipArchive::CREATE);
if ($dir_handle = opendir('./')) {
while (false !== ($entry = readdir($dir_handle))) {
if ($entry != "." && $entry != ".." && !strstr($entry,'.php') && !strstr($entry,'.zip')) {
$zip->addFile($entry);
}
}
closedir($dir_handle);
}
else {
die('file not found');
}
$zip->close();
header('Content-Type: application/zip');
header("Content-Disposition: attachment; filename=$zipname");
header('Content-Length: ' . filesize($zipname));
header("Location: $zipname");
?>
What I'd like to achieve is having $zipname = "the name of the folder.zip"
So, if the php is inside "/mypath/blablabla/" i want my zip $zipname to be "blablabla.zip"
Any help will be appreciated!
EDIT:
here's the working code:
<?php
$zipname = getcwd();
$zipname = substr($zipname,strrpos($zipname,'\\')+1);
$zipname = $zipname.'.zip';
$zip = new ZipArchive;
$zip->open('D:/inetpub/webs/mydomaincom/zip/'.basename($zipname).'', ZipArchive::CREATE);
if ($dir_handle = opendir('./')) {
while (false !== ($entry = readdir($dir_handle))) {
if ($entry != "." && $entry != ".." && !strstr($entry,'.php')) {
$zip->addFile($entry);
}
}
closedir($dir_handle);
}
else {
die('file not found');
}
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="'.basename($zipname).'"');
header('Content-Length: ' . filesize($zipname));
header('Location: /zip/'.$zipname);
?>
You could use getcwd() :
http://php.net/manual/fr/function.getcwd.php
$zipname = getcwd();
It'll return the path of the current folder, then you could just hash the result to get only the name of the folder :
// We remove all the uneeded part of the path
$zipname = substr($zipname,strrpos($zipname,'\\')+1);
//Then we add .zip to the result :
$zipname = $zipname.'.zip';
This should do the trick.
And if you want to also use the name of the parent folder :
$zipname = getcwd();
// We remove the uneeded part of the path
$parentFolderPath = substr($zipname, 0,strrpos($zipname,'\\'));
$parentFolder = substr($parentFolderPath, strrpos($parentFolderPath,'\\')+1);
//Keep current folder name
$currentFolder = substr($zipname,strrpos($zipname,'\\')+1);
//Join both
$zipname = $parentFolder.'_'.$currentFolder;
//Then we add .zip to the result :
$zipname = $zipname.'.zip';
Instead of redirecting with header(), you could use readfile():
header('Content-Disposition: attachment; filename="'.basename($zipname).'"');
readfile($zipname);
With basename() only the last part is shown to the user and with readfile() you are giving out the actual file, no matter where it is.

Debugging zip archive and download

I'd like a bit of help debugging this code. I'm trying to zip some files, which I provide as paths to Ziparchive. I think the zip file is empty, possibly. When I test this on a staging site I get a 'decompression failed' error. When I test this locally I get the following error in php logs
PHP Warning: readfile(images.zip): failed to open stream: No such file or directory in /Applications/MAMP/htdocs/8018_Whites/wordpress/downloadzip.php on line 29.
Here is the code:
<?php
//get image urls string
//$cat_string = "url1,url2,url3..."
if (isset($_GET['category-images'])) {
$cat_string=$_GET['category-images'];
}
//change string to array
$cat_array=explode(",", $cat_string);
$files=$cat_array;
$zipname = 'images.zip';
$zip = new ZipArchive;
$zip->open($zipname, ZipArchive::CREATE);
foreach ($files as $file) {
if(!strstr($file,'.php')) $zip->addFile($file);
}
$zip->close();
if ($zipname) {
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.$zipname);
header('Content-Length: ' . filesize($zipname));
readfile($zipname);
exit();
}
?>
Do I need to add ob_start/ob_flush to this code, and should I put the ob_flush after readfile?
All files and Zip folder to give absolute path. so zip is properly created.
<?php
$zip_root ='/var/www/gplhome/'
$file_root ='/var/www/gplhome/project/'
//get image urls string
//$cat_string = "url1,url2,url3..."
if (isset($_GET['category-images'])) {
$cat_string=$_GET['category-images'];
}
//change string to array
$cat_array=explode(",", $cat_string);
$files=$cat_array;
$zipname = $zip_root.'images.zip';
$zip = new ZipArchive;
if ($zip->open($zipname, ZIPARCHIVE::CREATE) != TRUE) {
die("Could not open archive");
}
foreach ($files as $file) {
if(!strstr($file_root.$file,'.php')) $zip->addFile($file_root.$file);
}
$zip->close();
if ($zipname) {
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.$zipname);
header('Content-Length: ' . filesize($zipname));
readfile($zipname);
exit();
}
?>
check the return value of $zip->close(), it returns false on error.
check the return value of $zip->addFile(), it returns false on error.
ensure that you use only file name for headers and full name for readfile.
check if the file is created. Replace
if ($zipname) {
with
if (is_readable($zipname)) {
don't put ?> and the end of the php file

Creating ZIP File in PHP coming up with Browser errors, not Script errors

I created a code to backup an entire website & automatically download it on a single click. Here is what my code looks like:
if (file_exists("file.zip")) {
unlink("file.zip");
}
$folder_array = array();
$file_array = array();
function listFolderFiles($dir){
global $folder_array;
global $file_array;
$ffs = scandir($dir);
foreach($ffs as $ff){
if ($ff != '.' && $ff != '..') {
if (is_dir($dir.'/'.$ff)) {
$new_item = "$dir/$ff";
$new_item = str_replace('..//','',$new_item);
if ($new_item !== "stats") {
array_push($folder_array, $new_item);
listFolderFiles($dir.'/'.$ff);
}
}
else {
$new_item = "$dir/$ff";
$new_item = str_replace('..//','',$new_item);
if (($new_item !== "stats/logs") && ($new_item !== "stats/")) {
array_push($file_array, $new_item);
}
}
}
}
}
listFolderFiles('../');
$zip = new ZipArchive;
if ($zip->open('file.zip', true ? ZIPARCHIVE::OVERWRITE:ZIPARCHIVE::CREATE) === TRUE) {
foreach($folder_array as $folder) {
$zip->addEmptyDir($folder);
}
foreach($file_array as $key => $file) {
$file_path = "../$file";
$zip->addFile($file_path, $file);
}
}
$zip->close();
$file = "file.zip";
chmod("$file", 0700);
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=". $file);
readfile($file);
Now this code was working good for awhile, but it seems today it doesn't want to work. The thing is, it's not a PHP script error. I've checked my error logs and nothing is showing up. It appears to be a browser error, but each browser displays a different message:
Chrome says "This webpage is not available"
Firefox says "The connection was reset"
Internet Explorer says "This page can't be displayed"
Even though these errors come up, the ZIP file is still being created and I can download it from the server.
Here is a list of things I've tried after extensive research:
1) I removed the code to have the ZIP file download automatically (all code written after I close the ZIP file). Still get the browser errors.
2) I read that it's possible too many files are getting opened and its going over my limit. I added to the code to close and reopen the ZIP file after every 200 files. Still didn't work.
3) I limited the amount of files to ZIP. Everything was working fine below 500. Between 500 to 1,000 files, the code would work a partial amount of the time. Sometimes it would go through fine, the others it would give me the browser error. After 1,000 or so it just wouldn't work properly at all.
The hosting is through GoDaddy.
PHP Version is 5.2.17
max_execution_time is set at 240 (the code never goes this long, usually only takes about 30 sec to run)
memory_limit is set at 500M (more than twice the size of all the files combined)
I'm at a loss, I really don't know what is going on because this code was working just fine for 1,500 files a few weeks ago. And again, the ZIP file is still being created, there are no PHP errors and it's only the Browsers that are coming back with these errors.
I don't know what's wrong with your code, but I'm using the code below and it has been working forever with me.
function create_zip($path, $save_as)
{
if (!extension_loaded('zip'))
throw new ErrorException('Extension ZIP has not been compiled or loaded in php.');
else if(!file_exists($path))
throw new ErrorException('The file/path you want to zip doesn\'t exist!');
$zip = new ZipArchive();
if (!$zip->open($save_as, ZIPARCHIVE::CREATE))
throw new ErrorException('Could not create zip file!');
$ignore = array('.','..');
if($path == dirname($save_as))
$ignore[] = basename($save_as);
$path = str_replace('\\', '/', realpath($path));
if (is_dir($path)) {
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
$file = str_replace('\\', '/', $file);
if( in_array(substr($file, strrpos($file, '/')+1),$ignore )) continue;
$file = realpath($file);
if (is_dir($file)) {
$zip->addEmptyDir(str_replace($path . '/', '', $file . '/'));
}
else if (is_file($file)) {
$zip->addFromString(str_replace($path . '/', '', $file), file_get_contents($file));
}
}
}
else if (is_file($path)) {
$zip->addFromString(basename($path), file_get_contents($path));
}
return $zip->close();
}
$zip = create_zip('/path/to/your/zip/directory', '/path/to/your/save.zip');
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename('/path/to/your/save.zip').'"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize('/path/to/your/save.zip'));
echo readfile('/path/to/your/save.zip');
instantate an iterator (before creating the zip archive, just in case the zip file is created inside the source folder) and traverse the directory to get the file list.
See More Code At:click me

PHP ZipArchive download working but not adding files to zip

I know there is many questions regarding the ZipArchive and how it works but after following all these I still can't get my program to work.
I don't know where i'm going wrong because I have die methods in and none of them are getting activated.
$path = "/export/scripts/CLOUD/logs/web/Private_Testbox/Jan_28_2013_16_20_44_atvts78_rollout_config/";
$fileName = explode('/', $path);
$zipname = $fileName[count($fileName) - 2];
$zip = new ZipArchive;
$handle = opendir($path);
//Check whether Zip can be opened
if ($zip->open($zipname, ZIPARCHIVE::CREATE) !== TRUE) {
die("Could not open archive");
}
//Add all files to an array
while ($file = readdir($handle))
{
$zip->addFile($path, $file);
}
closedir($handle);
$zip->close();
//Send zip folder
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename=' . $zipname . '.zip');
readfile($zip);
This file downloads the zip folder but there is never anything in it.
Thanks for help in advance.
You forgot a die() on the ->addFile() call, which means you're assuming that the files actually got added.
readfile() does not return the full path to a file in a directory, only the actual "local" filename, which means you're adding files which don't exist in the script's current working directory. Try:
$zip->addFile($file, $path . $file);
^^^^^^^^^^^^^^^^^^^^^
instead. As it stands now, your code is using $path as the filename to embed in the zip, and directories cannot be used as filenames. And without the $path . $file, addFile is looking in the wrong spot, e.g. it's the equivalent of getcwd() . $file instead.

Categories