Ziparchive exclude folder & how to make it generic - php

This is a code i found over internet, intended to create a .zip of the entire folder and download it.
I want to do a few changes, but everything I tried doesn't work. What I want:
Make it generic (i.e. I want to have that makezip.php in root folder. I've a file manager, and everytime I call this script from some location (ex. www.domain.com/files/media/images/ it gets that folder).
Delete the zip after the download (I think I did it well, using the comand unlinkbut I'm not sure that's the right way.
Remove that . and .. folder that the zip gets too.
Export the zip with the name date.hour.directory.zip (ex 18Sep2013_13-26-02_images.zip). I tried to do this
$fd = getcwd();
$filename = date("dMY_H:i:s").'_'.$fd.'.zip';
but it didn't worked, it only gets the $fd variable.
I know it isn't supposed to give you all the code and expect that you will look on it nor debug it, but I've tried everything and nothing of it works. I'm learning by myself and I'm a bit newbie on php.
Best regards
<?php
function download($file) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
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($file));
ob_clean();
flush();
readfile($file);
unlink($file);
exit;
}
$directory = '.';
$files = scandir($directory);
if(empty($files))
{
echo("You haven't selected any file to download.");
}
else
{
$zip = new ZipArchive();
$filename = date("dMY_H:i:s").'_arquivo.zip'; //adds timestamp to zip archive so every file has unique filename
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) { // creates new zip archive
exit("Cannot open <$filename>\n");
}
$N = count($files);
for($i=0; $i < $N; $i++)
{
$zip->addFile($files[$i], $files[$i]); //add files to archive
}
$numFiles = $zip->numFiles;
$zip->close();
$time = 8; //how long in seconds do we wait for files to be archived.
$found = false;
for($i=0; $i<$time; $i++){
if($numFiles == $N){ // check if number of files in zip archive equals number of checked files
download($filename);
$found = true;
break;
}
sleep(1); // if not found wait one second before continue looping
}
if($found) { }
else echo "Sorry, this is taking too long";
}
?>

Ok, I've figured out my problems by myself, and I'm sharing the solution for those who want.
Make it generic (i.e. I want to have that makezip.php in root folder. I've a file manager, and everytime I call this script from some location (ex. www.domain.com/files/media/images/ it gets that folder).
I modified the code on index.php, and made a few changes on zip.php (the file which is handling the zipping process. Simples solution.. Dumb!
1 - index.php - just put a simple link
Download folder as a .zip
2 - zip.php
$directory = $_REQUEST['dirz'];
Delete the zip after the download (I think I did it well, using the comand unlinkbut I'm not sure that's the right way.
Yes, it's correct. (on zip.php)
unlink($ZIPNAME);
Remove that . and .. folder that the zip gets too.
$direct = array_diff(scandir($directory), array(".","..","error_log"));
foreach($direct as $file){
if(is_file($directory.'/'.$file)){
$zip->addFile($directory.'/'.$file, $file);
}
}
Export the zip with the name date.hour.directory.zip (ex 18Sep2013_13-26-02_images.zip). I tried to do this $fd = getcwd(); $filename = date("dMY_H:i:s").'_'.$fd.'.zip'; but it didn't worked, it only gets the $fd variable.
Simple as:
$zipname = date("dMY_H-i-s").'_'.basename($directory).'.zip';
Best regards

Related

Code to create ZipArchive file on PHP is not working, once downloaded file is damaged

I am trying this piece of code found on the internet, which helps to create a ZipArchive with files on PHP.
I am trying this on my server, which is an AWS EC2 with Linux Ubuntu where a web server is running. I run the following code :
<?php
function createZipAndDownload($files, $filesPath, $zipFileName)
{
// Create instance of ZipArchive. and open the zip folder.
$zip = new ZipArchive();
$r = $zip->open($zipFileName, ZipArchive::CREATE);
var_dump($r); echo "<br>";
// Adding every attachments files into the ZIP.
foreach ($files as $file) {
$r = $zip->addFile($filesPath . $file, $file);
var_dump($r); echo "<br>";
}
$r = $zip->close();
var_dump($r); echo "<br>";
// Download the created zip file
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename = $zipFileName");
header("Content-length: " . filesize($zipFileName));
header("Pragma: no-cache");
header("Expires: 0");
readfile("$zipFileName");
exit;
}
// Files which need to be added into zip
$files = array('twiglet-1120x720.jpg','22vwqq.jpg','fb4eb7f8aa5431b0b4e26365ebd59933-239x300.jpg');
// Directory of files
$filesPath = 'https://peakon.com/wp-content/uploads/2018/08/';
// Name of creating zip file
$zipName = 'document.zip';
echo createZipAndDownload($files, $filesPath, $zipName);
?>
Then, I have this output :
bool(true)
bool(false)
bool(false)
bool(false)
bool(true)
I understand that the ZipArchive is created, but files are not sent inside the ZipArchive. Nevertheless, the file is downloaded once finished and when I want to open it, it's written that "the file is damaged" and I can't open it.
Can you help me ? Do you know why it is not working ? I could like to insert theses images inside and download it ? (images are just examples)
Thank you in advance for your help.
addFile takes a file system path, not an HTTP URL. There's several ways to fix it but for your case, it might just be easiest to use file_get_contents along with addFromString. file_get_contents does accept URLs, weirdly enough. Note that the parameters for addFromString aren't in the same order as addFile.
$r = $zip->addFromString($file, file_get_contents($filesPath . $file));
In the long run, however, I'd recommend downloading the files, checking the results and throwing error messages as needed, but this should get you started at least.
edit
The parameter ZipArchive::CREATE will only create an archive if it doesn't exist already, so it might actually try opening an existing file and, with your previous attempts, this might result in you opening a corrupt file. Instead, I would recommend using either ZipArchive::OVERWRITE to start over, or ZipArchive::EXCL to guarantee that an existing file is not touched.
Putting this all together, this code, exactly as-is, works when I test it:
function createZipAndDownload($files, $filesPath, $zipFileName)
{
// Create instance of ZipArchive. and open the zip folder.
$zip = new ZipArchive();
$r = $zip->open($zipFileName, ZipArchive::OVERWRITE);
var_dump($r);
echo "<br>";
// Adding every attachments files into the ZIP.
foreach ($files as $file) {
$r = $zip->addFromString($file, file_get_contents($filesPath . $file));
var_dump($r);
echo "<br>";
}
$r = $zip->close();
var_dump($r);
echo "<br>";
// Download the created zip file
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename = $zipFileName");
header("Content-length: " . filesize($zipFileName));
header("Pragma: no-cache");
header("Expires: 0");
readfile($zipFileName);
exit;
}
// Files which need to be added into zip
$files = array('twiglet-1120x720.jpg', '22vwqq.jpg', 'fb4eb7f8aa5431b0b4e26365ebd59933-239x300.jpg');
// Directory of files
$filesPath = 'https://peakon.com/wp-content/uploads/2018/08/';
// Name of creating zip file
$zipName = 'document.zip';
createZipAndDownload($files, $filesPath, $zipName);

Download multiple images into zip

I am trying to add functionality to my website where users can download multiple image files via a single .zip folder. Currently I have this code executing but when i open the downloaded zip file it extracts another zip file my-archive (3) 2.zip.cpgz and every time I try to open it, it extracts yet another zip file.
Here is my basic code using php native zip feature.
$image1 = "http://cdn.screenrant.com/wp-content/uploads/Darth-Vader-voiced-by-Arnold-Schwarzenegger.jpg";
$image2 = "http://cdn.screenrant.com/wp-content/uploads/Star-Wars-Logo-Art.jpg";
$files = array($image1, $image2);
$zipname = 'file.zip';
$zip = new ZipArchive;
$zip->open($zipname, ZipArchive::CREATE);
foreach ($files as $file) {
$zip->addFile($file);
}
$zip->close();
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.$zipname);
header('Content-Length: ' . filesize($zipname));
readfile($zipname);
EDIT
I am trying hard to get the provided answer to work. I just tried the most recent edit and got this error
]
You should download external files and then archive them.
$image1 = "http://cdn.screenrant.com/wp-content/uploads/Darth-Vader-voiced-by-Arnold-Schwarzenegger.jpg";
$image2 = "http://cdn.screenrant.com/wp-content/uploads/Star-Wars-Logo-Art.jpg";
$files = array($image1, $image2);
$tmpFile = tempnam('/tmp', '');
$zip = new ZipArchive;
$zip->open($tmpFile, ZipArchive::CREATE);
foreach ($files as $file) {
// download file
$fileContent = file_get_contents($file);
$zip->addFromString(basename($file), $fileContent);
}
$zip->close();
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename=file.zip');
header('Content-Length: ' . filesize($tmpFile));
readfile($tmpFile);
unlink($tmpFile);
In example above I used file_get_contents function, so please enable allow_url_fopen or use curl to download the files.
Hi guys above code worked perfectly. Images download worked only on live server (only if we use https or http). But it is not worked in local (if we use https or http)..
If you use local follow this -> Only change below lines.
For local use below img's
$image1 = "C:/Users/User/Pictures/Saved Pictures/chandamama.jpg";
$image2 = "C:/Users/User/Pictures/Saved Pictures/beautifull.jpg";
Do not use below img's for local.
$image1 = "http://cdn.screenrant.com/wp-content/uploads/Darth-Vader-voiced-by-Arnold-Schwarzenegger.jpg";
$image2 = "http://cdn.screenrant.com/wp-content/uploads/Star-Wars-Logo-Art.jpg";

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

show all files in a directory on a page [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
PHP list all files in directory
ive got a cron job running creating .xls files every 24hrs, they are creating them in a directory on my site called www.mysite.com/sheets
what i want to do is make a webpage where i can go to and see all the .xls files in that directory and download the ones i was instead of having to download them using an ftp client.
Is there a name for this sort of thing ? what would i write it in ? i was thinking i could do it in php by echoing the folders contents, would that work ?
cheers
You could activate directory listing within your webserver, or you can use a function like glob("*.xls") to list the files and echo their path on the webserver or you can send a file to the browser like this:
<?php
$filename = "path/to/your/file.xls";
$real_filename = "file.xls";
header('Content-Transfer-Encoding: none');
header('Content-Type: application/octet-stream; name="' . $real_filename . '"');
header('Content-Disposition: attachment; filename=' . $real_filename);
$size = #filesize($filename);
if ($size > 0) {
header('Content-length: '.$size);
} else {
header('Content-length: '.#strlen(#file_get_contents($filename)));
}
readfile($filename);
exit;
?>
If you want to list a directory use this:
$handle = opendir("./");
while (false !== ($file = readdir($handle))) {
$fileinfo = pathinfo($file);
if (strtolower($fileinfo[extension]) == "xls") {
echo $file;
}
}
closedir($handle);
Or this:
foreach (glob("*.[xX][lL][sS]") as $filename) {
echo $filename;
}
Use glob() plus some filtering for xls files.
glob("*.xls")
Potentially useful resources (in order of preference):
Manual
http://php.net/filesystemiterator
http://php.net/glob
http://php.net/scandir
http://php.net/opendir
http://php.net/function.dir

How to create a ZIP file using PHP and delete it after user downloads it?

I need to download images from other websites to my server. Create a ZIP file with those images. automatically start download of created ZIP file. once download is complete the ZIP file and images should be deleted from my server.
Instead of automatic download, a download link is also fine. but other logic remains same.
Well, you'll have to first create the zipfile, using the ZipArchive class.
Then, send :
The right headers, indicating to the browser it should download something as a zip -- see header() -- there is an example on that manual's page that should help
The content of the zip file, using readfile()
And, finally, delete the zip file from your server, using unlink().
Note : as a security precaution, it might be wise to have a PHP script running automatically (by crontab, typically), that would delete the old zip files in your temporary directory.
This just in case your normal PHP script is, sometimes, interrupted, and doesn't delete the temporary file.
<?php
Zip('some_directory/','test.zip');
if(file_exists('test.zip')){
//Set Headers:
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime('test.zip')) . ' GMT');
header('Content-Type: application/force-download');
header('Content-Disposition: inline; filename="test.zip"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize('test.zip'));
header('Connection: close');
readfile('test.zip');
exit();
}
if(file_exists('test.zip')){
unlink('test.zip');
}
function Zip($source, $destination)
{
if (!extension_loaded('zip') || !file_exists($source)) {
return false;
}
$zip = new ZipArchive();
if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
return false;
}
$source = str_replace('\\', '/', realpath($source));
if (is_dir($source) === true)
{
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file)
{
$file = str_replace('\\', '/', realpath($file));
if (is_dir($file) === true)
{
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
}
else if (is_file($file) === true)
{
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
}
}
else if (is_file($source) === true)
{
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}
?>
Any idea how many zip file downloads get interrupted and need to be continued?
If continued downloads are a small percentage of your downloads, you can delete the zip file immediately; as long as your server is still sending the file to the client, it'll remain on disk.
Once the server closes the file descriptor, the file's reference count will drop to zero, and finally its blocks on disk will be released.
But, you might spent a fair amount of time re-creating zip files if many downloads get interrupted though. Nice cheap optimization if you can get away with it.
Here's how I've been able to do it in the past. This code assumes you've written the files to a path specified by the $path variable. You might have to deal with some permissions issues on your server configuration with using php's exec
// write the files you want to zip up
file_put_contents($path . "/file", $output);
// zip up the contents
chdir($path);
exec("zip -r {$name} ./");
$filename = "{$name}.zip";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.urlencode($filename));
header('Content-Transfer-Encoding: binary');
readfile($filename);
Other solution: Delete past files before creation new zip file:
// Delete past zip files script
$files = glob('*.zip'); //get all file names in array
$currentTime = time(); // get current time
foreach($files as $file){ // get file from array
$lastModifiedTime = filemtime($file); // get file creation time
// get how old is file in hours:
$timeDiff = abs($currentTime - $lastModifiedTime)/(60*60);
//check if file was modified before 1 hour:
if(is_file($file) && $timeDiff > 1)
unlink($file); //delete file
}
Enable your php_curl extension; (php.ini),Then use the below code to create the zip.
create a folder class and use the code given below:
<?php
include("class/create_zip.php");
$create_zip = new create_zip();
//$url_path,$url_path2 you can use your directory path
$urls = array(
'$url_path/file1.pdf',
'$url_path2/files/files2.pdf'
); // file paths
$file_name = "vin.zip"; // zip file default name
$file_folder = rand(1,1000000000); // folder with random name
$create_zip->create_zip($urls,$file_folder,$file_name);
$create_zip->delete_directory($file_folder); //delete random folder
if(file_exists($file_name)){
$temp = file_get_contents($file_name);
unlink($file_name);
}
echo $temp;
?>
create a folder class and use the code given below:
<?php
class create_zip{
function create_zip($urls,$file_folder,$file_name){
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$file_name);
header('Content-Transfer-Encoding: binary');
$mkdir = mkdir($file_folder);
$zip = new ZipArchive;
$zip->open($file_name, ZipArchive::CREATE);
foreach ($urls as $url)
{
$path=pathinfo($url);
$path = $file_folder.'/'.$path['basename'];
$zip->addFile($path);
$fileopen = fopen($path, 'w');
$init = curl_init($url);
curl_setopt($init, CURLOPT_FILE, $fileopen);
$data = curl_exec($init);
curl_close($init);
fclose($fileopen);
}
$zip->close();
}
function delete_directory($dirname)
{
if (is_dir($dirname))
$dir_handle = opendir($dirname);
if (!$dir_handle)
return false;
while($file = readdir($dir_handle))
{
if ($file != "." && $file != "..")
{
if (!is_dir($dirname."/".$file))
unlink($dirname."/".$file);
else
delete_directory($dirname.'/'.$file);
}
}
closedir($dir_handle);
rmdir($dirname);
return true;
}
}
?>
I went there looking for a similar solution, and after reading the comments found this turnover : before creating your zip file in a dedicated folder (here called 'zip_files', delete all zip you estimate being older than a reasonable time (I took 24h) :
$dossier_zip='zip_files';
if(is_dir($dossier_zip))
{
$t_zip=$dossier_zip.'/*.zip'; #this allow you to let index.php, .htaccess and other stuffs...
foreach(glob($t_zip) as $old_zip)
{
if(is_file($old_zip) and filemtime($old_zip)<time()-86400)
{
unlink($old_zip);
}
}
$zipname=$dossier_zip.'/whatever_you_want_but_dedicated_to_your_user.zip';
if(is_file($zipname))
{
unlink($zipname); #to avoid mixing 2 archives
}
$zip=new ZipArchive;
#then do your zip job
By doing so, after 24h you only have the last zips created, user by user. Nothing prevents you for doing a clean by cron task sometimes, but the problem with the cron task is if someone is using the zip archive when the cron is executed it will lead to an error. Here the only possible error is if someone waits 24h to DL the archive.
Firstly, you download images from webiste
then, with the files you have downloaded you creatae zipfile (great tute)
finally you sent this zip file to browser using readfile and headers (see Example 1)

Categories