I am using this code to read a protected directory (username&password) contents called (protect).
<?php
require_once("admin/global.inc.php");
// increase script timeout value
ini_set('max_execution_time', 300);
//Generate a new flag
$random = (rand(000000,999999));
$date = date("y-m-d");
// create object
$zip = new ZipArchive();
// open archive
if ($zip->open("$date-$random.zip", ZIPARCHIVE::CREATE) !== TRUE) {
die ("Could not open archive");
}
// initialize an iterator
// pass it the directory to be processed
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("protect/")); //check question #2
// iterate over the directory
// add each file found to the archive
foreach ($iterator as $key=>$value) {
if ($key != 'protect/.htaccess')
{
$zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
$query="INSERT INTO `archives_logs` (`id`, `file`, `flag`, `date`) VALUES (NULL, '$key', '$random', '$date')";
$query_result = mysql_query ($query);
}
}
// close and save archive
$zip->close();
echo "Archive created successfully.";
?>
If I place my code file in a location differerent than the protected directory location, i have to change the path of the directory to be compressed which is fine, BUT the problem is that all directories in the path are included in the Zip Archive.
So if open the compressed file i get: www/username/public_html/etc...
Here is the directories strcuture:
www/protect/(files to be compressed here)
www/compress_code.php (here is my current code file)
The path that I wish to place my code file in is:
www/protect/admin/files/compress_code.php
Q1) How do I keep my code file in the last mentioned location WITHOUT including the path in my ZipArchive file?
Q2) When my code is in the same location of the directory to be compressed, and when i open the compressed file i see, protect/(the files). Can I add only the content of protect directory in the Zip Archive without inclduing the directory itself?
It's pretty simple:
Store the target path in a variable.
Remove target path from the localname before adding the file.
Like this:
$flags = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::SKIP_DOTS;
$target = 'protect/';
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($target, $flags));
foreach ($iterator as $key=>$value) {
if ($key != "{$target}.htaccess")
{
$localname = substr($key, strlen($target));
$zip->addFile($key, $localname) or die ("ERROR: Could not add file: $key");
}
}
This should actually answers both of your questions.
Related
I am using the function below to compress files, but in each directory it can automatically add two files as shown below (red Delineating).
How do I compress files while excluding these unwanted files?
function ziparchive($name,$folder){
// create object
$ziparchivename= $name.'.zip';
//echo $ziparchivename;
$zip = new ZipArchive();
// open archive
if ($zip->open($ziparchivename, ZIPARCHIVE::CREATE) !== TRUE) {
die ("Could not open archive");
}
// initialize an iterator
// pass it the directory to be processed
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($folder));
// iterate over the directory
// add each file found to the archive
foreach ($iterator as $key=>$value) {
$zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
}
// close and save archive
$zip->close();
echo "Archive created successfully.";
}
Some thing like this should work.
$skipFiles = array('.', '..');
foreach ($iterator as $key=>$value) {
if(!in_array($key, $skipFiles)){
$zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
}
php manual in_array
Another place to search is the array_search.
Another place to search is the array_search.
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 want the code to make all files in the tree to .zip files in the root
<?PHP
// create object
$zip = new ZipArchive();
// open archive
if ($zip->open('my-archive.zip', ZIPARCHIVE::CREATE) !== TRUE) {
die ("Could not open archive");
}
// list of files to add
// list of files to add
$fileList = array(
'im/asd.pdf',
'im/df.pdf',
'im/d/qoyyum.txt'
);
// add files
foreach ($fileList as $f) {
$zip->addFile($f) or die ("ERROR: Could not add file: $f");
}
// close and save archive
$zip->close();
echo "Archive created successfully.";
?>
for example folder /im contains
/im/asd.pdf
/im/df.pdf
/im/d/qoyyum.txt
the 'my-archive.zip' extract should look like this
my-archive/asd.pdf
my-archive/df.pdf
my-archive/qoyyum.txt
I want to prevent the folder hierarchy when extracting the zip. so that every files should be in the root of the extracted zip folder
please suggest a tip to do
There's a second parameter in ZipArchive::addFile() called localname (see here) which lets you set the local name of the file within the zip archive. Use this to override the directory structure which is the default.
foreach ($fileList as $f) {
$filename_parts = explode('/', $f); // Split the filename up by the '/' character
$zip->addFile($f, end($filename_parts)) or die ("ERROR: Could not add file: $f");
}
Is there a way to compress/archive a folder in the server using php script to .zip or .rar or to any other compressed format, so that on request we could archive the folder and then give the download link
Thanks in advance
Here is an example:
<?php
// Adding files to a .zip file, no zip file exists it creates a new ZIP file
// increase script timeout value
ini_set('max_execution_time', 5000);
// create object
$zip = new ZipArchive();
// open archive
if ($zip->open('my-archive.zip', ZIPARCHIVE::CREATE) !== TRUE) {
die ("Could not open archive");
}
// initialize an iterator
// pass it the directory to be processed
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("themes/"));
// iterate over the directory
// add each file found to the archive
foreach ($iterator as $key=>$value) {
$zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
}
// close and save archive
$zip->close();
echo "Archive created successfully.";
?>
Beware of a possible problem in Adnan's example: If the target myarchive.zip is inside the the source folder, then you need to exclude it in the loop, or to run the iterator before creating the archive file (if it doesn't exist already). Here's a revised script that uses the latter option, and adds some config vars up top. This one shouldn't be used to add to an existing archive.
<?php
// Config Vars
$sourcefolder = "./" ; // Default: "./"
$zipfilename = "myarchive.zip"; // Default: "myarchive.zip"
$timeout = 5000 ; // Default: 5000
// 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.
$dirlist = new RecursiveDirectoryIterator($sourcefolder);
$filelist = new RecursiveIteratorIterator($dirlist);
// set script timeout value
ini_set('max_execution_time', $timeout);
// instantate object
$zip = new ZipArchive();
// create and open the archive
if ($zip->open("$zipfilename", ZipArchive::CREATE) !== TRUE) {
die ("Could not open archive");
}
// add each file in the file list to the archive
foreach ($filelist as $key=>$value) {
$zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
}
// close the archive
$zip->close();
echo "Archive ". $zipfilename . " created successfully.";
// And provide download link ?>
<a href="http:<?php echo $zipfilename;?>" target="_blank">
Download <?php echo $zipfilename?></a>
PHP comes with the ZipArchive extension, which is just right for you.