PHP Copy not working after update to php 5.5 - php

I am using php copy function to extract a zip file and put files to a new directory using copy function (actually i am not using $zip->extractTo because it maintains dir stucture of zip as well, and I want to unzip all the files in a single directory that I am creating ).
my code is
$zip = new ZipArchive;
if ($zip->open($src)===true)
{
//$zip->extractTo($dest);
//$zip->close();
// Above method maintain dir stucture of zip as well,
// but we need files directly in dest folder
for($i = 0; $i < $zip->numFiles; $i++)
{
$filename = $zip->getNameIndex($i);
if(substr($filename, -1) == '/')
continue; // Its a directory name so skip and dont add in dest folder
$fileinfo = pathinfo($filename);
copy("zip://".$src."#".$filename, $dest.$fileinfo['basename']);
}
$zip->close();
return true;
}
This is working fine on my development and QA servers where I have PHP 5.2 and 5.3
But it is not working on a PHP 5.5.14.
copy("zip://".$src."#".$filename, $dest.$fileinfo['basename']);
returns false.
So problem is with copy.
Can anyone please suggest what can be solution.

Related

PHP: Unable to extact particular files from a ZIP archive

I am trying to extract files from a zip file, but its failing with following error
Warning: copy(zip://upload/myzip-file.zip#myzip-file/file_001.csv): Failed to open stream: operation failed in {code line}
My file myzip-file.zip is placed inside upload folder, my code is able to read the contents of this file, but its unable to extract file one by one (I want to extract particular files only. I also want to avoid creation of sub folder)
$zip = new ZipArchive;
if ($zip->open($zipPath) === true) {
for($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
$fileinfo = pathinfo($filename);
copy("zip://".$zipPath."#".$filename, "my-path/".$fileinfo['basename']);
}
$zip->close();
}
I suspect that copy functoin is not able to understand zip://
I found this sample on net where people have achived same using copy command but its not working for me any more.
Please note
My php script is at same location as are upload and my-path (All three in same directory)
My Zip does contain an extra folder myzip-file and its confirmed by extracting the full zip contentents and this sinppet $zip->getNameIndex($i); also revealed that.
Please note you don't have to fix it, but if have any sample which is extracting one single file from zip. It will work for me.
I have tested your PHP script, it will work if
using relative path (so use $zipPath="./upload/myzip-file.zip"; and "./my-path/")
my-path is writable
over the iteration, better do not process the "file" if the $filename is actually a directory
so the directory structure is like the attached picture (myzip-file.zip is placed inside the upload folder, the process.php is the PHP to do the job)
So use the following code (I tested in a linux server and it works)
<?php
$zipPath="./upload/myzip-file.zip";
$zip = new ZipArchive;
if ($zip->open($zipPath) === true) {
for($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
$fileinfo = pathinfo($filename);
if (substr($filename, -1) !="/"){
copy("zip://".$zipPath."#".$filename, "./my-path/".$fileinfo['basename']);
}
}
$zip->close();
}
?>

How to copy the source code of my website recursively into a zip file and download using PHP

Since my file manager doesn't allow me to download multiple files, instead only allowing me to download them one by one (which is tedious, and, eventually will become inefficient), I want to know how to download all my website file contents into a single zip folder. I found a code that works from geeksForGeeks, however it only zips on that current directory level (not recursively). I want every file on my website put into a zip folder while preserving their place in their corresponding folders.
The code I found:
// Enter the name of directory
$pathdir = "./";
// Enter the name to creating zipped directory
$zipcreated = "BackupFiles.zip";
// Create new zip class
$zip = new ZipArchive;
if($zip -> open($zipcreated, ZipArchive::CREATE ) === TRUE) {
// Store the path into the variable
$dir = opendir($pathdir);
while($file = readdir($dir)) {
if(is_file($pathdir.$file)) {
$zip -> addFile($pathdir.$file, $file);
}
}
$zip ->close();
}
How do I add the folders as well? It only zips the files of the current directory and not all the subfolders.

PHP — Information on the zip:// protocol

I am using ZipArchive class to unzip a file and put its contents somewhere useful. Using information derived from the comments on php.net, I ended up writing this function:
function unzip(string $zipFile, string $destination) {
$zip = new ZipArchive();
$zip->open($zipFile);
for($i=0; $i<$zip->numFiles; $i++) {
$file=$zip->getNameIndex($i);
if(substr($file,-1) == '/') continue; // skip containing folder
$name=basename($file);
copy("zip://$zipFile#$file","$destination/$name");
}
$zip->close();
}
This is to copy the individual files without the folder structure.
I can understand most of the code, but I cannot get any information on the following expression:
"zip://$zipFile#$file"
I know what it doing (obviously it is extracting one of the files from the Zip archive), but can anyone tell me more about the zip:// protocol, and why it uses the # to reference a particular file?
Check out source of Zip extension
https://github.com/php/php-src/blob/master/ext/zip/zip_stream.c
line 135. fragment = strchr(path, '#');
get pointer of entry in path/to/zip#entry
line 141.
if (strncasecmp("zip://", path, 6) == 0)
{
path += 6;
}
if zip:// is equal first 6 characters of path
I won't go into the logic of this code. It just exists here (zip_stream.c) and maybe somewhere else.
It seems like this extension "creates" zip:// protocol over php executable that is laying over apache server.

PHP ZipArchive file iteration ignores directories

I'm using the ZipArchive class in PHP for the first time, and I'm having a bit of trouble. All I'm trying to do is iterate through the files in the ZIP archive, and it all works, except it doesn't seem there's any way to get subdirectory names inside the ZIP file, and I need that information. If there are files inside the subdirectoy, I suppose I could parse the directory names out of the file names, but if there are empty directories, they're completely lost.
For instance, if I have this directory tree in a ZIP:
root_folder
root_folder -> test_file.ext
root_folder -> empty_dir
Now I try to read that ZIP file's entries into memory like this in PHP:
<?php
$zip = new ZipArchive;
if ($zip->open('test.zip') == TRUE) {
for ($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
echo $filename."<br />";
}
$zip->close();
}
?>
If I do this, then root_folder\test_file.ext is found correctly, but root_folder\empty_dir is just lost entirely.
So how do I use the ZipArchive class to find all the files and directories, including empty ones inside the archive?

Zipping up a folder without extra folders in the zipped file

So, I understand it's pretty easy to zip a folder and its contents given that php.net and stackoverflow are full of sample codes. I am trying to zip up a folder as well. This is my code:
$zip = new ZipArchive;
$zip->open('myzip.zip', ZipArchive::CREATE);
foreach (glob("/Volumes/Data/Users/username/Desktop/Archive/some/thisFolder/*") as $file) {
$zip->addFile($file);
}
$zip->close();
My script is running in a folder, say on Desktop, and I want to zip thisFolder and its contents. The above code WORKS. But, the problem is that when I unzip the myzip.zip created, I get a structure like
Volumes>Data>Users>username>Desktop>Archive>some>thisFolder
and then I find the contents inside the 8th folder (thisFolder) in this case. How can I change this code so that when I unzip myzip.zip,I would straightaway see the folder thisFolder with the contents inside it instead of having to navigate through folders 7 times before getting my content?
I tried to change the path and silly things like that. But, it doesn't work.
Thanks
If you want everything in the file to be a name relative to your starting folder, use chdir() to start from there:
chdir("/Volumes/Data/Users/username/Desktop/Archive/some/thisFolder");
foreach (glob("*") as $file) {
$zip->addFile($file);
}
Actually, I don't think this will work when $file is a subdirectory -- addFile doesn't recurse automatically. There's a comment in the documentation that shows how to write a recursive zip function:
http://www.php.net/manual/en/ziparchive.addemptydir.php
bool ZipArchive::addFile ( string $filename [, string $localname ] )
filename
The path to the file to add.
localname
local name inside ZIP archive.
You can use the pathinfo function to each $file in your loop, in order to retrieve the filename without the path, and then, use it as second parameter to the addFile method.
pathinfo doc here
Here is an example that could solve your problem:
// Create your zip archive
$zip = new ZipArchive;
// open it in creation mode
$zip->open('myzip.zip', ZipArchive::CREATE);
// Loop on all your file
$mask = "/Volumes/Data/Users/username/Desktop/Archive/some/thisFolder";
$allAvailableFiles = glob($mask . "/*")
foreach ($allAvailableFiles as $file)
{
// Retrieve pathinfo
$info = pathinfo($file);
// Generate the internal directory
$internalDir = str_replace($mask, "", $info['dirname']);
// Add the file with internal directory
$zip->addFile($file, $internalDir . "/" . $info['basename']);
}
$zip->close();

Categories