Zipped file with PHP results in cpgz file after extraction - php

I'm zipping folders and files with php, but when I try to open up the zip file I get an cpgz file instead. After extracting that file I get another zip file. What it does is bassicaly scan the current folder for files and folders to zip.
This is the code I use:
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();
}
if($_GET["archive"]== 'true'){
$date = date("Ymd_Hi");
$dir = dirname(__FILE__);
$filename = $date.".zip";
Zip(getcwd(), $filename);
header("Content-disposition: attachment; filename=$filename");
header('Content-type: application/zip');
readfile($filename);
unlink($filename);
}

I was just having exactly the same issue, and learned that these two function calls can help:
header("Content-disposition: attachment; filename=$filename");
header('Content-type: application/zip');
// Add these
ob_clean();
flush();
readfile($filename);
unlink($filename);
Usually setting Content-Disposition and Content-Length should be enough, however flushing PHPs output buffer and the underlying output buffer (Apache or such) helps when output is accidentally sent before headers are set in PHP.
In my case, commenting out the header() and readfile() calls for debugging helped to see, that warnings were output before the file was sent.
Hope that helps somebody in the future.

Related

Codeigniter Zip directory and download

I am having a very strange problem when zipping a directory and try to download using codeigniter.
Here is the code
$this->load->library('zip'); //Loading the zip library
$directory = $_SESSION['directory-download-path']; //Getting the directory from session
$name = basename($directory); //get the name of the folder
$name = str_replace(" ", "_", $name).".zip"; //create the zip name
unset($_SESSION['directory-download-path']); //removing it from session
$this->zip->read_dir($directory); //read the directory
$this->zip->download($name); //download the zip
It is very simple. The problem occurs with the download. I get the zip file but when i extract it i get a file with .zip.cpgz and continues to extract similar files. Thus i think it is corrupted. Can you please help me why is this occurring. I have permissions and everything on the directory because i am doing other operations.
EDIT:
I found after some more research to add the second parameter as follows:
$this->zip->read_dir($directory, false); //read the directory
But still not working.
Another solution was to add
ob_end_clean();
just before the line: $this->zip->download($name); //download the zip
but still no success!
Since I had no response i made a function outside of codeigniter that zips files and folder recursively which is below:
public 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('\\', '/', $file);
if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..', "Thumbs.db")) )
continue;
$file = 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();
}
After this in the codeigniter controller i made this:
$this->projects->Zip($source, $destination);
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$name");
header("Content-length: " . filesize($destination));
header("Pragma: no-cache");
header("Expires: 0");
readfile($destination);
unlink($destination);
Of course the $destination should be to a temp folder where you have permissions 777 or equivalent so that when the file is sent to the client it will be deleted.
Hope this helps!

How to download a folder from web server to local machine using php

I am able to Zip and download the folder from my local machine using the following code. But I want to download a folder from my web server. How can i do it. please help. I searched a lot on google but i couldn't find a solution.
$the_folder = 'C:/Program Files/Red5/webapps/SOSample/streams/';
$zip_file_name = 'getaaa.zip';
$download_file= true;
//$delete_file_after_download= true; doesnt work!!
class FlxZipArchive extends ZipArchive {
// $location="http://localhost/SOSample";
public function addDir($location, $name) {
$this->addEmptyDir($name);
$this->addDirDo($location, $name);
} // EO addDir;
private function addDirDo($location, $name) {
$name .= '/';
$location .= '/';
// Read all Files in Dir
$dir = opendir ($location);
while ($file = readdir($dir))
{
if ($file == '.' || $file == '..') continue;
// Rekursiv, If dir: FlxZipArchive::addDir(), else ::File();
$do = (filetype( $location . $file) == 'dir') ? 'addDir' : 'addFile';
$this->$do($location . $file, $name . $file);
}
} // EO addDirDo();
}
$za = new FlxZipArchive;
$res = $za->open($zip_file_name, ZipArchive::CREATE);
if($res === TRUE)
{
$za->addDir($the_folder, basename($the_folder));
$za->close();
}
else { echo 'Could not create a zip archive';}
if ($download_file)
{
ob_get_clean();
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=" . basename($zip_file_name) . ";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($zip_file_name));
readfile($zip_file_name);
//deletes file when its done...
//if ($delete_file_after_download)
//{ unlink($zip_file_name); }
}
?>
You can't "download a folder." You have to zip it up.
Instead of giving $location="http://localhost/SOSample"; give full absolute path of your web server palce it in your web server and it will make zip file from your web server. Is your eb server windows or linux based on it give the path to $location variable.
As said you cant download a folder. However, if you have a file path, you can download files separated from each other. Using file_get_contents makes it easy. http://nl1.php.net/file_get_contents
=============== Edit: ===============
You need to recursively add files in the directory. Something like this (untested):
function createZipFromDir($dir, $zip_file) {
$zip = new ZipArchive;
if (true !== $zip->open($zip_file, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)) {
return false;
}
zipDir($dir, $zip);
return $zip;
}
function zipDir($dir, $zip, $relative_path = DIRECTORY_SEPARATOR) {
$dir = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
if ($handle = opendir($dir)) {
while (false !== ($file = readdir($handle))) {
if (file === '.' || $file === '..') {
continue;
}
if (is_file($dir . $file)) {
$zip->addFile($dir . $file, $file);
} elseif (is_dir($dir . $file)) {
zipDir($dir . $file, $zip, $relative_path . $file);
}
}
}
closedir($handle);
}
Then call $zip = createZipFromDir('/tmp/dir', 'files.zip');
Some examples of zip, see: http://www.php.net/manual/en/zip.examples.php
(code from: How to zip a folder and download it using php?)
=============== Edit 2: ===============
Based on your comment:
opendir() is used to open a local directory and since PHP 5.0.0 on an ftp directory.
If your PHP code runs on www.domain.com then /pages/to/path is actually a local directory and you can do this:
$dir ='<wwwroot>/pages/to/path';
if ($handle = opendir($dir)) {
where wwwroot is the root of the filesystem as seen by your php code.
If you're trying to download content from another website, try e.g. file_get_contents(). Note that if the remote server lists the content of a directory the listing is in fact an HTML page generated on the fly by the server. You may find yourself needing to parse that page. A better approach is to check whether the server offers some sort of API where it sends back the content in a standardized form, e.g. in JSON format.

how to create and download zip file without path directory [duplicate]

This question already has answers here:
php creating zips without path to files inside the zip
(4 answers)
Closed 9 years ago.
My code creates a ZIP file and downloads it in this ZIP folder some images exist.
It’s done well but problem is that after I download and extract this folder then all path folder also become my code is:
$id = $row['id'];
$doc_name = $row['doc_name'];
$file_names = explode(',',$doc_name);
$file_path = $_ROOT_REQUIRE."uploads/document/";
$archive_file_name = "demo.zip";
$zip = new ZipArchive($archive_file_name);
if ($zip->open($archive_file_name, ZIPARCHIVE::CREATE ) !== TRUE) {
echo "cannot open <$archive_file_name>\n";
exit("cannot open <$archive_file_name>\n");
}
foreach ($file_names as $files) {
if ($files !== '') {
$zip->addFile("$files", basename($files));
}
}
$zip->close();
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.basename($archive_file_name).'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($archive_file_name));
header('Cache-Control: private');
ob_clean();
flush();
readfile(basename($archive_file_name));
exit;
Your Code look's is Fine.
Just Replace Your Foreach Loop .
foreach ($files as $file)
{
$file = str_replace('\\', '/', $file);
if(filetype($file) == 'file') {
$zip->addFile( $file, pathinfo( $file, PATHINFO_BASENAME ) );
}
}
it should be work
Thanks
A bit unclear on why this would be happening, looking at this line:
$zip->addFile("$files", basename($files));
Why are there " quotes around $files? I would recommend changing that to:
$zip->addFile($files, basename($files));
These are the changes I made and it work well now. Thanks to all.
$overwrite = true;
if($zip->open($archive_file_name,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true)
This larger piece:
foreach ($file_names as $file) {
$files = $file_path.$file;
$files = str_replace('\\', '/', $files);
if(filetype($files) == 'file') {
$zip->addFile( $files, pathinfo( $files, PATHINFO_BASENAME ) );
}
}

PHP zip archive adds extra folder

I have a piece of code which generates a .zip archive containing all files and folders from a given folder. It looks like this:
function zipDirectory($source, $destination, $flag = '')
{
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($flag)
{
$flag = basename($source) . '/';
//$zip->addEmptyDir(basename($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 . '/', '', $flag.$file . '/'));
}
else if (is_file($file) === true)
{
$zip->addFromString(str_replace($source . '/', '', $flag.$file), file_get_contents($file));
}
}
}
else if (is_file($source) === true)
{
$zip->addFromString($flag.basename($source), file_get_contents($source));
}
return $zip->close();
}
zipDirectory($downloadID.'/','temp_'.$downloadID.'.zip', false);
$zip_file = 'temp_'.$downloadID.'.zip';
$file_name = basename($zip_file);
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=" . $file_name);
header("Content-Length: " . filesize($zip_file)+15);
However, the resulting .zip archive ends up containing the specified folder, as well as an extra folder called "C:" with folders inside it, making up the absolute path to the root of my site. There are no files in this chain of folders.
I don't really know what could be causing this... Any ideas? Would be much appreciated.

Every time I create zip file from PHP, there is one empty folder "\data"

Every time I create zip file from PHP, there is one empty folder "\data".
But there is no such folder in server.
When i unzip the zip file and browse that empty folder, it shows path something like:
\data/www/subdomains/site/httpdocs/
it looks like the absolute path of the folder i am trying to zip.
Here are my codes:
<?php
$file = tempnam("tmp","zip");
zip_directory($_GET['catname'].'/'.$_GET['directtozip'].'/',$file);
header('Content-Type: application/zip');
header('Content-Length: ' . filesize($file));
header('Content-Disposition: attachment; filename="'.$_GET['directtozip'].'.zip"');
readfile($file);
unlink($file);
function zip_directory($source,$tempfile){
if(!extension_loaded('zip') || !file_exists($source)) return false;
$zip = new ZipArchive();
if(!$zip->open($tempfile,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){
// Excluded folders or file from zip.
$chk_1 = strstr($file,$source .'/'.'.svn');
if($chk_1){continue;}
$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));
}
}
}
elseif(is_file($source) === true) $zip->addFromString(basename($source), file_get_contents($source));
return $zip->close();
}
zip_directory($source,$tempfile);
?>
Thanks in advance.
What's with the last line zip_directory($source,$tempfile); because $tempfile is not defined.
Your code works OK for me
<?php
$file = tempnam("tmp","zip");
zip_directory('__z/', $file);
header('Content-Type: application/zip');
header('Content-Length: ' . filesize($file));
header('Content-Disposition: attachment; filename="_zzz.zip"');
readfile($file);
unlink($file);
function zip_directory($source, $tempfile){
if(!extension_loaded('zip') || !file_exists($source)) {
return false;
}
$zip = new ZipArchive();
if(!$zip->open($tempfile, 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){
$chk_1 = strstr($file,$source .'/'.'.svn');
if($chk_1){continue;}
$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));
}
}
} elseif( is_file($source) === true ) {
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}
?>

Categories