See this question. I can't use that code:
function addFolderToZip($dir, $zipArchive, $zipdir = ''){
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
//Add the directory
$zipArchive->addEmptyDir($dir);
// Loop through all the files
while (($file = readdir($dh)) !== false) {
//If it's a folder, run the function again!
if(!is_file($dir . $file)){
// Skip parent and root directories
if( ($file !== ".") && ($file !== "..")){
addFolderToZip($dir . $file . "/", $zipArchive, $zipdir . $file . "/");
}
}else{
// Add the files
$zipArchive->addFile($dir . $file, $zipdir . $file);
}
}
}
Please write an example for me. The second problem is too complex.
When I use addfile function it will add and appear in the archive as a file and this great. Now when I use:
$z = new ZipArchive();
$z->open('test.zip')
for ($i=0; $i< $z->numFiles;$i++) {
$aZipDtls = $z->statIndex($i);
echo $aZipDtls['name'];
}
it now shows if I add a file in folder like that:
$zip->addFile('/path/to/index.txt', 'dir/newname.txt');
it show in the Winrar soft a dir then a file but in the code it shows it as one file.
Like that in winrar:
dir/
dir/newname.txt
In my PHP system, just only show one file without its dir, like that:
dir/newname.txt
This mean it's impossible to add a new file in a dir.
Difficult to know what you want, but here goes:
<?php
$zip = new ZipArchive();
$zip->open('test.zip');
$zip->addFile('/path/to/newname.txt','dir/newname1.txt');
$zip->addFile('/path/to/newname.txt','dir/newname2.txt');
$zip->addFile('/path/to/newname.txt','dir/dir/newname3.txt');
$zip->addFile('/path/to/newname.txt','dir/dir/dir/newname4.txt');
for ($i=0; $i< $zip->numFiles;++$i) {
$aZipDtls = $zip->statIndex($i);
echo $aZipDtls['name'],"\n";
}
$zip->close();
?>
Should cover all questions. That will unzip with exactly the structure you'd expect it to. The discrepancy is likely due to the way WinRar displays the archive structure.
Related
For the below code I have multiple directories and files. I can display one filename per directory(Which is good with the "BREAK").
<?php
$dir = "/images/";
$i=0;
// Open a directory, and read its contents
if (is_dir($dir)){
if ($dh = opendir($dir)){
while (($file = readdir($dh)) !== false){
echo "filename:" . $file . "<br>";
break;
//---- if ($i>=5) { break; }
}
closedir($dh);
}
}
?>
With
if ($i>=5) { break; } I can still display 5 filenames but it reads only one directory.
I want to display at least 5 file names from all directories, how can I do it?
Use the scandir function.
array scandir ( string $directory [, int $sorting_order = SCANDIR_SORT_ASCENDING [, resource $context ]] )
or
If you are using unix you could also do a system call and run the following command.
ls /$dir | head -5
$dir is the directory and -5 is the number filenames in the directory.
Since you said that you have multiple directory's, I rewrote your code a bit:
(Here I first loop through all directory's with array_map() then I get all files from each directory with glob(). After this I just limit the files per directory with array_slice() and at the end I simply print all file names)
<?php
$directorys = ["images/", "xy/"];
$limit = 3;
//get all files
$files = array_map(function($v){
return glob("$v*.*");
}, $directorys);
//limit files per directory
$files = array_map(function($v)use($limit){
return array_slice($v, 0, $limit);
}, $files);
foreach($files as $directory) {
echo "<b>Directory</b><br>";
foreach($directory as $file)
echo "$file<br>";
echo "<br><br>";
}
?>
You don't have to break it, you can just skip it. And in doing so, you have to use continue instead.
$dir = "/images/";
$i=0;
// Open a directory, and read its contents
if (is_dir($dir)){
if ($dh = opendir($dir)){
while (($file = readdir($dh)) !== false){
echo "filename:" . $file . "<br>";
if ($i>=5)
continue;
}
closedir($dh);
}
}
Here is also another scenario. Because you mentioned that you have many directories but you only show one main directory, I am guessing that the directories you've mentioned were inside the /images/ directory.
$dir = "images/";
$i=1;
// Open a directory, and read its contents
if (is_dir($dir)){
if ($dh = opendir($dir)){
while (($file = readdir($dh)) !== false){
$j=1;
if (is_dir($file)) {
if ($internalDir = opendir($file)) {
while (($internalFile = readdir($internalDir)) !== false) {
echo $file."->filename: ".$internalFile."<br>";
if ($j>=5)
continue;
$j++;
}
closedir(opendir($file));
}
} else {
echo "filename:" . $file . "<br>";
if ($i>=5)
continue;
$i++;
}
}
closedir($dh);
}
}
Read more about continue here: http://php.net/manual/en/control-structures.continue.php
I have some PHP code that I am using to try and zip a folder. The folder has two subfolders in it and several individual files.
Here is the code: -
<?php
$src = $_POST['srcin'];
$dst = $_POST['dstin'];
$zip = new ZipArchive;
$zip->open($dst, ZipArchive::CREATE);
if (false !== ($dir = opendir($src)))
{
while (false !== ($file = readdir($dir)))
{
if ($file != '.' && $file != '..')
{
$ans = DIRECTORY_SEPARATOR;
$zip->addFile($src.DIRECTORY_SEPARATOR.$file);
}
}
}
else
{
die('Can\'t read dir');
}
$zip->close();
echo json_encode('Folder Compressed');
?>
The input values are: -
srcin = "TestFolder"
dstin = "TestFolder.zip".
What is happening is that I am getting a zip file. However, the subfolders are being created as files.
I got the above code from searching this forum on how to ZIP a folder, yet I cannot see anything mentioned regarding subfolders not being zipped properly.
Any help is much appreciated.
Thanks
Martin
You should create a directory with addEmptyDir before you add a file to it.
Here is an example(see top comment) how to archive a directory recursively
I have a directory structure like this :
members/
login.php
register.php
I zip them by PHP ZipArchive in my windows machine, but when I upload it to linux host and extract there by PHP it gives me these as two files with no directory :
members\login.php
members\register.php
I want to have the complete directory structure on the host after unzipping the file.
Note that this unpacking code runs without any problem in my local machine. Is it something about windows and linux or what? How can I resolve it?
PHP does not actually provide a function that extracts a ZIP including its directory structure. I found the following code in a user comment in the manual:
function unzip($zipfile)
{
$zip = zip_open($zipfile);
while ($zip_entry = zip_read($zip)) {
zip_entry_open($zip, $zip_entry);
if (substr(zip_entry_name($zip_entry), -1) == '/') {
$zdir = substr(zip_entry_name($zip_entry), 0, -1);
if (file_exists($zdir)) {
trigger_error('Directory "<b>' . $zdir . '</b>" exists', E_USER_ERROR);
return false;
}
mkdir($zdir);
}
else {
$name = zip_entry_name($zip_entry);
if (file_exists($name)) {
trigger_error('File "<b>' . $name . '</b>" exists', E_USER_ERROR);
return false;
}
$fopen = fopen($name, "w");
fwrite($fopen, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)), zip_entry_filesize($zip_entry));
}
zip_entry_close($zip_entry);
}
zip_close($zip);
return true;
}
Source here.
try DIRECTORY_SEPARATOR
instead of using:
$path = $someDirectory.'/'.$someFile;
use:
$path = $someDirectory. DIRECTORY_SEPARATOR .$someFile;
Change your code to this:
$zip = new ZipArchive;
if ($zip->open("module. DIRECTORY_SEPARATOR .$file[name]") === TRUE) {
$zip->extractTo('module. DIRECTORY_SEPARATOR');
}
And it will work for both operating systems.
Good luck,
The problem solved! Here's what I did :
I change the code of creating zip file into this function from php.net user comments :
function addFolderToZip($dir, $zipArchive){
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
//Add the directory
$zipArchive->addEmptyDir($dir);
// Loop through all the files
while (($file = readdir($dh)) !== false) {
//If it's a folder, run the function again!
if(!is_file($dir . $file)){
// Skip parent and root directories
if(($file !== ".") && ($file !== "..")){
addFolderToZip($dir . $file . "/", $zipArchive);
}
}else{
// Add the files
$zipArchive->addFile($dir . $file);
}
}
}
}
}
$zip = new ZipArchive;
$zip->open("$modName.zip", ZipArchive::CREATE);
addFolderToZip("$modName/", $zip);
$zip->close();
And in the host I wrote just this code to extract the zipped file :
copy($file["tmp_name"], "module/$file[name]");
$zip = new ZipArchive;
if ($zip->open("module/$file[name]") === TRUE) {
$zip->extractTo('module/');
}
$zip->close();
It created the folder and sub-folders. The only bug left is that it extracts every file in all subfolders in the main folder too, so there is two versions of each file in subfolders.
$path = '/home/username/www/;
if($zip = new ZipArchive){
if($zip->open('backup_'. time() .'.zip', ZipArchive::CREATE)){
if(false !== ($dir = opendir($path))){
while (false !== ($file = readdir($dir))){
if ($file != '.' && $file != '..' && $file != 'aaa'){
$zip->addFile($path . $file);
echo 'Adding '. $file .' to path '. $path . $file .' <br>';
}
}
}
else
{
echo 'Can not read dir';
}
$zip->close();
}
else
{
echo 'Could not create backup file';
}
}
else
{
echo 'Could not launch the ZIP libary. Did you install it?';
}
Hello again Stackoverflow! I want to backup a folder with all its content including (empty) subfolders and every file in them, whilst excluding a single folder (and ofcourse . and ..). The folder that needs to be excluded is aaa.
So when I run this script (every folder does have chmod 0777) it runs without errors, but the ZIP file doesn't show up. Why? And how can I solve this?
Thanks in advance!
have you tried to access the zip folder via PHP rather than looking in FTP as to whether it exists or not - as it might not appear immediately to view in FTP
function addFolderToZip($dir, $zipArchive, $zipdir = ''){
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
//Add the directory
if(!empty($zipdir)) $zipArchive->addEmptyDir($zipdir);
// Loop through all the files
while (($file = readdir($dh)) !== false) {
//If it's a folder, run the function again!
if(!is_file($dir . $file)){
// Skip parent and root directories, and any other directories you want
if( ($file !== ".") && ($file !== "..") && ($file !== "aa")){
addFolderToZip($dir . $file . "/", $zipArchive, $zipdir . $file . "/");
}
}else{
// Add the files
$zipArchive->addFile($dir . $file, $zipdir . $file);
}
}
}
}
}
After a while of fooling around this is what I found working. Use it as seen below.
$zipArchive = new ZipArchive;
$name = 'backups\backup_'. time() .'.zip';
$zipArchive->open($name, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);
addFolderToZip($path, $zipArchive);
Here's my answer, checks if the modification time is greater then something as well.
<?php
$zip = new ZipArchive;
$zip_name = md5("backup".time()).".zip";
$res = $zip->open($zip_name, ZipArchive::CREATE);
$realpath = str_replace('filelist.php','',__FILE__);
$path = realpath('.');
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name => $object){
if (is_file($object)) {
$file_count ++;
$epoch = $object->getMTime();
if($epoch>='1374809360'){ // Whatever date you want to start at
$array[] = str_replace($realpath,'',$object->getPathname());
}
}
}
foreach($array as $files) {
$zip->addFile($files);
}
$zip->close();
echo $zip_name.'-'.$file_count.'-'.$count_files;
?>
new php programmer here. I have been trying to rename all the files in a folder by replacing the extension.
The code I'm using is from the answer to a similar question on SO.
if ($handle = opendir('/public_html/testfolder/')) {
while (false !== ($fileName = readdir($handle))) {
$newName = str_replace(".php",".html",$fileName);
rename($fileName, $newName);
}
closedir($handle);
}
I get no errors when running the code, but no changes are made to the filenames.
Any insight on why this isn't working? My permission settings should allow it.
Thanks in advance.
EDIT: I get a blank page when checking the return value of rename(), now trying something with glob() which might be a better option than opendir...?
EDIT 2: With the 2nd code snippet below, I can print the contents of $newfiles. So the array exists, but the str_replace + rename() snippet fails to change the filename.
$files = glob('testfolder/*');
foreach($files as $newfiles)
{
//This code doesn't work:
$change = str_replace('php','html',$newfiles);
rename($newfiles,$change);
// But printing $newfiles works fine
print_r($newfiles);
}
Here is the simple solution:
PHP Code:
// your folder name, here I am using templates in root
$directory = 'templates/';
foreach (glob($directory."*.html") as $filename) {
$file = realpath($filename);
rename($file, str_replace(".html",".php",$file));
}
Above code will convert all .html file in .php
You're probably working in the wrong directory. Make sure to prefix $fileName and $newName with the directory.
In particular, opendir and readdir don't communicate any information on the present working directory to rename. readdir only returns the file's name, not its path. So you're passing just the file name to rename.
Something like below should work better:
$directory = '/public_html/testfolder/';
if ($handle = opendir($directory)) {
while (false !== ($fileName = readdir($handle))) {
$newName = str_replace(".php",".html",$fileName);
rename($directory . $fileName, $directory . $newName);
}
closedir($handle);
}
Are you sure that
opendir($directory)
works? Have you checked that? Because it seems there might be some Document Root missing here...
I would try
$directory = $_SERVER['DOCUMENT_ROOT'].'public_html/testfolder/';
And then Telgin's solution:
if ($handle = opendir($directory)) {
while (false !== ($fileName = readdir($handle))) {
$newName = str_replace(".php",".html",$fileName);
rename($directory . $fileName, $directory . $newName);
}
closedir($handle);
}
That happens if the file is opened. Then php cannot do any changes to the file.
<?php
$directory = '/var/www/html/myvetrx/media/mydoc/';
if ($handle = opendir($directory)) {
while (false !== ($fileName = readdir($handle))) {
$dd = explode('.', $fileName);
$ss = str_replace('_','-',$dd[0]);
$newfile = strtolower($ss.'.'.$dd[1]);
rename($directory . $fileName, $directory.$newfile);
}
closedir($handle);
}
?>
Thank you so much for the suggestions. it's working for me!