How to get ZipArchive to not overwrite certain files and folders - php

I would like to extract a zip folder to a location and to replace all files and folders except a few, how can I do this?
I currently do the following.
$backup = realpath('./backup/backup.zip');
$zip = new ZipArchive();
if ($zip->open("$backup", ZIPARCHIVE::OVERWRITE) !== TRUE) {
die ('Could not open archive');
}
$zip->extractTo('minus/');
$zip->close();
How can I put conditions in for what files and folders should NOT be replaced? It would be great if some sort of loop could be used.
Thanks all for any help

You could do something like this, I tested it and it works for me:
// make a list of all the files in the archive
$entries = array();
for ($idx = 0; $idx < $zip->numFiles; $idx++) {
$entries[] = $zip->getNameIndex($idx);
}
// remove $entries for the files you don't want to overwrite
// only extract the remaining $entries
$zip->extractTo('minus/', $entries);
This solution is based on the numFiles property and the getNameIndex method, and it works even when the archive is structured into subfolders (the entries will look like /folder/subfolder/file.ext).
Also, the extractTo method takes a second optional paramer that holds the list of files to be extracted.

If you just want to extract specific files from the archive (and you know what they are) then use the second parameter (entries).
$zip->extractTo('minus/', array('file1.ext', 'newfile2.xml'));
If you want to extract all the files that do not exist, then you can try one of the following:
$files = array();
for($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
// if $filename not in destination / or whatever the logic is then
$files[] = $filename;
}
$zip->extractTo($path, $files);
$zip->close();
You can also use $zip->getStream( $filename ) to read a stream that you then write to the destination file.

Related

How to count all folder ,file and files in sub folder in server using php?

How to count all folder ,file and files in sub folder in server using php ?
i want to count all files ,folder and files in sub folder in path /home1/example/public_html/
First i use this code
<?php
$directory = "/home1/example/public_html/";
$filecount = 0;
$files = glob($directory . "*");
if ($files){
$filecount = count($files);
}
echo "There were $filecount files";
?>
it's show There were 561 files
And then i use this code
<?php
$fi = new FilesystemIterator(__DIR__, FilesystemIterator::SKIP_DOTS);
printf("There were %d Files", iterator_count($fi));
?>
it's show There were 566 Files
And last i use this code
<?php
// integer starts at 0 before counting
$i = 0;
$dir = '/home1/example/public_html/';
if ($handle = opendir($dir)) {
while (($file = readdir($handle)) !== false){
if (!in_array($file, array('.', '..')) && !is_dir($dir.$file))
$i++;
}
}
// prints out how many were in the directory
echo "There were $i files";
?>`
it's show There were 500 Files
But result were difference.
I was test by create file in /home1/example/public_html/images/ But all result still show same like before i create file.
How can i do ?
Your second example will return a more precise answer than the first because glob ignores hidden files and FilesystemIterator does not.
The big difference in the third example is that in #1 and #2 you are iterating and then counting both files and directories, where as in #3 you are filtering directories in the count (by calling is_dir).
So #3 is probably correct (except for what I mention in the NOTE below), and I would suggest using a variant of #2 which will be much easier to read:
function recursive_file_count($dir)
{
$fi = new FilesystemIterator($dir, FilesystemIterator::SKIP_DOTS);
$c = 0;
foreach ($fi as $fileInfo)
{
if (!$fileInfo->isDir()) { ++$c; }
// can also test for $fileInfo->isLink() if needed
}
return $c;
}
NOTE: The count is also affected by filesystem permissions. So for example if this script is running in Apache under the httpd user, and the httpd doesn't have execute permission on a certain directory, it won't be able to enter that directory and count its files. There is no way to solve that without some sort of evil privilege escalation hacks.

On creating zip file by php I get two files instead of one

I'm struggling around with a simple PHP functionality: Creating a ZIP Archive with some files in.
The problem is, it does not create only one file called filename.zip but two files called filename.zip.a07600 and filename.zip.b07600. Pls. see the following screenshot:
The two files are perfect in size and I even can rename each of them to filename.zip and extract it without any problems.
Can anybody tell me what is going wrong???
function zipFilesAndDownload_Defect($archive_file_name, $archiveDir, $file_path = array(), $files_array = array()) {
// Archive File Name
$archive_file = $archiveDir."/".$archive_file_name;
// Time-to-live
$archiveTTL = 86400; // 1 day
// Delete old zip file
#unlink($archive_file);
// Create the object
$zip = new ZipArchive();
// Create the file and throw the error if unsuccessful
if ($zip->open($archive_file, ZIPARCHIVE::CREATE) !== TRUE) {
$response->res = "Cannot open '$archive_file'";
return $response;
}
// Add each file of $file_name array to archive
$i = 0;
foreach($files_array as $value){
$expl = explode("/", $value);
$file = $expl[(count($expl)-1)];
$path_file = $file_path[$i] . "/" . $file;
$size = round((filesize ($path_file) / 1024), 0);
if(file_exists($path_file)){
$zip->addFile($path_file, $file);
}
$i++;
}
$zip->close();
// Then send the headers to redirect to the ZIP file
header("HTTP/1.1 303 See Other"); // 303 is technically correct for this type of redirect
header("Location: $archive_file");
exit;
}
The code which calls the function is a file with a switch-case... it is called itself by an ajax-call:
case "zdl":
$files_array = array();
$file_path = array();
foreach ($dbh->query("select GUID, DIRECTORY, BASENAME, ELEMENTID from SMDMS where ELEMENTID = ".$osguid." and PROJECTID = ".$osproject.";") as $subrow) {
$archive_file_name = $subrow['ELEMENTID'].".zip";
$archiveDir = "../".$subrow['DIRECTORY'];
$files_array[] = $archiveDir.DIR_SEPARATOR.$subrow['BASENAME'];
$file_path[] = $archiveDir;
}
zipFilesAndDownload_Defect($archive_file_name, $archiveDir, $file_path, $files_array);
break;
One more code... I tried to rename the latest 123456.zip.a01234 file to 123456.zip and then unlink the old 123456.zip.a01234 (and all prior added .a01234 files) with this function:
function zip_file_exists($pathfile){
$arr = array();
$dir = dirname($pathfile);
$renamed = 0;
foreach(glob($pathfile.'.*') as $file) {
$path_parts = pathinfo($file);
$dirname = $path_parts['dirname'];
$basename = $path_parts['basename'];
$extension = $path_parts['extension'];
$filename = $path_parts['filename'];
if($renamed == 0){
$old_name = $file;
$new_name = str_replace(".".$extension, "", $file);
#copy($old_name, $new_name);
#unlink($old_name);
$renamed = 1;
//file_put_contents($dir."/test.txt", "old_name: ".$old_name." - new_name: ".$new_name." - dirname: ".$dirname." - basename: ".$basename." - extension: ".$extension." - filename: ".$filename." - test: ".$test);
}else{
#unlink($file);
}
}
}
In short: copy works, rename didn't work and "unlink"-doesn't work at all... I'm out of ideas now... :(
ONE MORE TRY: I placed the output of $zip->getStatusString() in a variable and wrote it to a log file... the log entry it produced is: Renaming temporary file failed: No such file or directory.
But as you can see in the graphic above the file 43051221.zip.a07200 is located in the directory where the zip-lib opens it temporarily.
Thank you in advance for your help!
So, after struggling around for days... It was so simple:
Actually I work ONLY on *nix Servers so in my scripts I created the folders dynamically with 0777 Perms. I didn't know that IIS doesn't accept this permissions format at all!
So I remoted to the server, right clicked on the folder Documents (the hierarchically most upper folder of all dynamically added files and folders) and gave full control to all users I found.
Now it works perfect!!! The only thing that would be interesting now is: is this dangerous of any reason???
Thanks for your good will answers...
My suspicion is that your script is hitting the PHP script timeout. PHP zip creates a temporary file to zip in to where the filename is yourfilename.zip.some_random_number. This file is renamed to yourfilename.zip when the zip file is closed. If the script times out it will probably just get left there.
Try reducing the number of files to zip, or increasing the script timeout with set_time_limit()
http://php.net/manual/en/function.set-time-limit.php

Check if file exists in .tar using PHP

In my program I need to read .png files from a .tar file.
I am using pear Archive_Tar class (http://pear.php.net/package/Archive_Tar/redirected)
Everything is fine if the file im looking for exists, but if it is not in the .tar file then the function timouts after 30 seconds. In the class documentation it states that it should return null if it does not find the file...
$tar = new Archive_Tar('path/to/mytar.tar');
$filePath = 'path/to/my/image/image.png';
$file = $tar->extractInString($filePath); // This works fine if the $filePath is correct
// if the path to the file does not exists
// the script will timeout after 30 seconds
var_dump($file);
return;
Any suggestions on solving this or any other library that I could use to solve my problem?
The listContent method will return an array of all files (and other information about them) present in the specified archive. So if you check if the file you wish to extract is present in that array first, you can avoid the delay that you are experiencing.
The below code isn't optimised - for multiple calls to extract different files for example the $files array should only be populated once - but is a good way forward.
include "Archive/Tar.php";
$tar = new Archive_Tar('mytar.tar');
$filePath = 'path/to/my/image/image.png';
$contents = $tar->listContent();
$files = array();
foreach ($contents as $entry) {
$files[] = $entry['filename'];
}
$exists = in_array($filePath, $files);
if ($exists) {
$fileContent = $tar->extractInString($filePath);
var_dump($fileContent);
} else {
echo "File $filePath does not exist in archive.\n";
}

php include file with newest date

I'm trying to make a sort of blog with php and I want to include the 5 newest files in an other directory by modification time.
I can inculde them all one by one each time I have made a new file, but it would be nice if I can just include the newest 5.
Because i don't want to put the modification date in the file name I really don't know how to do it.
Is there a way to do that?
$path = "/path/to/directory"; //the directory path
$latest5files = array(); //array for latest 5 files to be stored
$d = dir($path);
while ((false !== ($entry = $d->read())) || count($latest5files) < 5)
{
$filepath = "{$path}/{$entry}";
if ((is_file($filepath)))
{
$latest_filename[] = $entry;
}
}
Then include the whole files in the array
for ($i = 0; $i < count($latest5files); $i++)
{
include $latest5files[ $i ];
}
You can get list files with array for eg.
$a[1234567890] = 'file1.php';
arsort($a);
foreach(array_slice($input, 0, 5) as $fTime => $file):
http://php.net/manual/en/function.filemtime.php
http://php.net/manual/en/function.stat.php
You can check the file modification time with this functions.
Read the file sort it with that time.
More info on
Sorting files by creation/modification date in PHP
This would be a way to get last access info of all files in a directory
$p = "path";
$a = scandir($p);
foreach($a as $f){
$last_access = fileatime($p."/".$f);
}

How to use PHP readdir to read files in directories outside of the root level and link?

I am using a php include (side nav menu- where php script would be) that resides on the root level of my webserver.
I would like to use a php readdir or scandir to list the contents of a different folder on my server (/report_1) with links to those files excluding html, htm and xslt extensions. (or to just only include php extensions)
Currently I am using a readdir that only reads the contents of the current directory it resides in and returns links excluding certain file types.(see code below)
I would eventually like to have a php file in the include that lists and links to files outside the "include" root level. Any help would be very appreciated.
<?php
// These files will be ignored
$excludedFiles = array (
'excludeMe.file',
'excludeMeAs.well'
);
// These file extensions will be ignored
$excludedExtensions = array (
'html',
'htm',
'php'
);
// Make sure we ignore . and ..
$excludedFiles = array_merge($excludedFiles,array('.','..'));
// Convert to lower case so we are not case-sensitive
for ($i = 0; isset($excludedFiles[$i]); $i++) $excludedFiles[$i] =
strtolower(ltrim($excludedFiles[$i],'.'));
for ($i = 0; isset($excludedExtensions[$i]); $i++) $excludedExtensions[$i] =
strtolower($excludedExtensions[$i]);
// Loop through directory
$count = 0;
if ($handle = opendir('.')) {
while (false !== ($file = readdir($handle))) {
$extn = explode('.',$file);
$extn = array_pop($extn);
// Only echo links for files that don't match our rules
if (!in_array(strtolower($file),$excludedFiles) &&
!in_array(strtolower($extn),$excludedExtensions)) {
$count++;
print("".$file."<br />\n");
}
}
echo '<br /><br />Return';
closedir($handle);
}
?>
Make the directory loop a function.
Check if the current file is a directory using is_dir
If it is, re-run that directory through the same function.
Otherwise print the file name as you are doing.
You might want to consider using absolute paths in your links.
Hope this helps.

Categories