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();
}
?>
Related
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.
I have written the PHP script to generate the zip file. it's working fine when I use rar software to extract it but not getting extract with rar software. I can't ask to users to install rar software to extract downloaded zip file.
I don't know where i am commiting mistakes.
Here i attached error screen shot which i get when try to open zip file.
// Here is code snippet
$obj->create_zip($files_to_zip, $dir . '/download.zip');
// Code for create_zip function
//create the archive
$zip = new ZipArchive();
if ($zip->open($destination, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
return false;
}
//add the files
foreach ($valid_files as $file) {
$filearr = explode('/', $file);
$zip->addFile($file, end($filearr));
}
$zip->close();
If $valid_files is a glob'd array, use basename() instead of end(), your zip might not actually have added any files causing for it to be an invalid zip (however that would be visible in the size of the zip file).
Also try winrar/winzip/7zip and see what they return, microsoft's internal zip engine might not be up to date enough to open the zips.
I have also encountered this problem, using 7z solved the problem but we need to send the zip to somebody else so 7z is a nono.
I found that, in my case it is that the file path is too long:
When I use this:
$zip->addFile($files_path.'/people.txt');
And it generated a zip folder nested very deep e.g. ["/tmp/something/something1/something2/people.txt"]
So I need to use this instead
$zip->addFile($files_path.'/people.txt', 'people.txt');
Which generate a a zip folder with only 1 layer ["people.txt"], and Windows Zip read perfectly~
Hope this helps somebody that also have this problem!
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?
I'm reading files that are located inside a .zip archive (in this case an XBRL taxonomy) using PHP 7 and its ZipArchive functions, but a whole lot of files that I am sure are inside are simply skipped, ignored as they do not exist.
This is the result of running zipinfo www.eba.europa.eu.zip on the file
https://www.dropbox.com/s/336njdmfg8uaho8/output-zipinfo.txt?dl=0
This is the result of reading the content of the zip using the following code:
$zip = new \ZipArchive();
$zip->open("www.eba.europa.eu.zip");
for ($i = 0; $i < $zip->numFiles; $i++) {
echo 'Filename: ' . $zip->getNameIndex($i) . PHP_EOL;
}
https://www.dropbox.com/s/7njkp5i92d68fxs/output-ziparchive.txt?dl=0
As you can see all the files with finrep in their name just are not present in the second test.
What could it be? Missing permissions on something? File size/number limit? Sorry for the Dropbox links, but the logs are both quite big considering the number of files.
Thanks in advance for the help!
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.