Okay let me explain. I have two folders on my server, let's say they're called f1/ and f2/.
Both folders have several files. I'd like to ZipArchive both folders. However, the best I can do is getting the .zip to contain both folders. What I want is to take all the files and folders WITHIN both f1/ and f2/ and archive them, thus having the content of f1/ and f2/ in the root of the .zip, not the two folders.
This is the code I'm currently using, which, like I said, doesn't do what I want:
$zipname = 'ZipArc.zip';
$zip = new ZipArchive;
$zip->open($zipname, ZipArchive::CREATE);
foreach ($array as $file => $value)
{
$zip->addFile("f1/" . $file . ".ini");
}
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("f2/Data/"));
foreach ($iterator as $key=>$value) {
$zip->addFile(realpath($key), $key);
}
}
$zip->close();
I've searched and searched, but I can't seem to hit the right keywords to find a solution.
Read the docs closer: http://php.net/manual/en/ziparchive.addfile.php
bool ZipArchive::addFile($filename, $localname, ....)
^^^^^^^^^^
so
$zip->addFile('/real/path/on/your/server/file.txt', '/path/within/zip/foo.bar');
Related
I have a rar file with the many files and folders. I want to extract files in the sub-folders of the rar file to the main folder.
I have tried this:
$archive = RarArchive::open('example.rar');
$entries = $archive->getEntries();
foreach ($entries as $entry)
$entry->extract($dir);
$archive->close();
However this extracts the files to the same folder, rather than the main folder.
Any suggestions?
i tried an own solution, and it's works:
$archive = RarArchive::open('example.rar');
$entries = $archive->getEntries();
foreach ($entries as $entry)
{
$fileinfo = pathinfo($entry->getName());
copy("rar://".$file."#".$entry->getName(), $dir.'/'.$fileinfo['basename']);
}
$archive->close();
for don't extract folders (empty folders), we can put
if(!empty($fileinfo['extension']))
before copy function.
thanks to me :-)
I'm writing a PHP script that archives a selected directory and all its sub-folders. The code works fine, however, I'm running into a small problem with the structure of my archived file.
Imagine the script is located in var/app/current/example/two/ and that it wants to backup everything plus its sub directories starting at var/app/current
When I run the script it creates an archive with the following structure:
/var/app/current/index.html
/var/app/current/assets/test.css
/var/app/current/example/file.php
/var/app/current/example/two/script.php
Now I was wondering how:
a) How can I remove the /var/app/current/ folders so that the root directory of the archive starts beyond the folder current, creating the following structure:
index.html
assets/test.css
example/file.php
example/two/script.php
b) Why & how can I get rid of the "/" before the folder var?
//Create ZIP file
$zip = new ZipArchive();
$tmpzip = realpath(dirname(__FILE__))."/".substr(md5(TIME_NOW), 0, 10).random_str(54).".zip";
//If ZIP failed
if($zip->open($tmpzip,ZIPARCHIVE::CREATE)!== TRUE)
{
$status = "0";
}
else
{
//Fetch all files from directory
$basepath = getcwd(); // var/app/current/example/two
$basepath = str_replace("/example/two", "", $basepath); // var/app/current
$dir = new RecursiveDirectoryIterator($basepath);
//Loop through each file
foreach(new RecursiveIteratorIterator($dir) as $files => $file)
{
if(($file->getBasename() !== ".") && ($file->getBasename() !== ".."))
{
$zip->addFile(realpath($file), $file);
}
}
$zip->close();
You should try with:
$zip->addFile(realpath($file), str_replace("/var/app/current/","",$file));
I've never used the ZipArchive class before but with most archiver application it works if you change the directory and use relative path.
So you can try to use chdir to the folder you want to zip up.
Problem
I am building an online file manager, for downloading a whole directory structure I am generating a zip file of all subdirectories and files (recursively), therefore I use the RecursiveDirectoryIterator.
It all works well, but empty directories are not in the generated zip file, although the dir is handled correctly. This is what i am currently using:
<?php
$dirlist = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
$filelist = new RecursiveIteratorIterator($dirlist, RecursiveIteratorIterator::SELF_FIRST);
$zip = new ZipArchive();
if ($zip->open($tmpName, ZipArchive::CREATE) !== TRUE) {
die();
}
foreach ($filelist as $key=>$value) {
$result = false;
if (is_dir($key)) {
$result = $zip->addEmptyDir($key);
//this message is correctly generated!
DeWorx_Logger::debug('added dir '.$key .'('.$this->clearRelativePath($key).')');
}
else {
$result = $zip->addFile($key, $key);
}
}
$zip->close();
If I ommit the FilesystemIterator::SKIP_DOTS I end up having a . file in all directories.
Conclusion
The iterator works, the addEmptyDir call gets executed (the result is checked too!) correctly, creating a zip file with various zip tools works with empty directories as intendet.
Is this a bug in phps ZipArchive (php.net lib or am I missing something? I don't want to end up creating dummy files just to keep the directory structure intact.
Any ideas on why this is perfectly working in my localhost but not in the server where I uploaded it to? In the server, it creates the zip but does not create the folders, it puts all the files inside the .zip, with no folders distinction.
function rzip($source, $destination) {
// create object
$zip = new ZipArchive();
// open archive
if ($zip->open($destination, ZIPARCHIVE::CREATE) !== TRUE) {
die ("Could not open archive");
}
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source));
foreach ($iterator as $key=>$value) {
$new_filename = substr($key,strrpos($key,"/") + 1);
$zip->addFile(realpath($key), $new_filename) or die ("ERROR: Could not add file: $key");
}
$zip->close();
}
You are mis-using (or not using) the RecursiveDirectoryIterator in places.
The first point is that you will iterate over the dot folders (. and ..) which is probably undesired; to stop this, use the SKIP_DOTS flag.
Next, there are tools to get the file's path relative to the main directory being iterated over and to get the real path too; using the getSubPathname() and getRealpath() methods, respectively.
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(
$source, RecursiveDirectoryIterator::SKIP_DOTS));
foreach ($iterator as $key => $value) {
$localname = $iterator->getSubPathname();
$filename = $value->getRealpath();
$zip->addFile($filename, $localname) or die ("ERROR: Could not add file: $key");
}
The above is only an answer because it's too long for a comment. Nothing above answers why, "this is perfectly working in my localhost but not in the server".
I have the following code snippet. I'm trying to list all the files in a directory and make them available for users to download. This script works fine with directories that don't have sub-directories, but if I wanted to get the files in a sub-directory, it doesn't work. It only lists the directory name. I'm not sure why the is_dir is failing on me... I'm a bit baffled on that. I'm sure that there is a better way to list all the files recursively, so I'm open to any suggestions!
function getLinks ($folderName, $folderID) {
$fileArray = array();
foreach (new DirectoryIterator(<some base directory> . $folderName) as $file) {
//if its not "." or ".." continue
if (!$file->isDot()) {
if (is_dir($file)) {
$tempArray = getLinks($file . "/", $folderID);
array_merge($fileArray, $tempArray);
} else {
$fileName = $file->getFilename();
$url = getDownloadLink($folderID, $fileName);
$fileArray[] = $url;
}
}
}
Instead of using DirectoryIterator, you can use RecursiveDirectoryIterator, which provides functionality for iterating over a file structure recursively. Example from documentation:
$path = realpath('/etc');
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name => $object){
echo "$name\n";
}
This prints a list of all files and
directories under $path (including
$path ifself). If you want to omit
directories, remove the
RecursiveIteratorIterator::SELF_FIRST
part.
You should use RecursiveDirectoryIterator, but you might also want to consider using the Finder component from Symfony2. It allows for easy on the fly filtering (by size, date, ..), including dirs or files, excluding dirs or dot-files, etc. Look at the docblocks inside the Finder.php file for instructions.