Read php file located in zip archive - php

I have been trying to read a PHP file inside a ZIP archive. I have coded the following code, which can read text documents and echo without errors, but when I tested it with a PHP file, nothing appear. So what can I do to read the PHP file without extracting?
<?php
$zip = zip_open("test.zip");
$filename= "test.php";
if (is_resource($zip))
{
while ($zip_entry = zip_read($zip))
{
if (zip_entry_open($zip, $zip_entry) && zip_entry_name($zip_entry) == $filename)
{
echo "Name: " . zip_entry_name($zip_entry) . "<br />";
echo "<p>";
echo "File Contents:<br/>";
$contents = zip_entry_read($zip_entry);
echo "$contents<br />";
zip_entry_close($zip_entry);
}
}
zip_close($zip);
}
Thanks in advance!

There aren't a lot of resources out there for using the default zip_read() php function, but this https://github.com/Ne-Lexa/php-zip library makes using zip files in php a breeze, you should check it out.

You can use stream wrappers to read a file directly from within a zip, in one line, without extracting anything to disk. For example:
$str = file_get_contents('zip://test.zip#test.php');

Related

Using phpseclib to check if file already exists

I'm trying to create a script that will send across files from one server to another. My script successfully does that as well as checks if the file has something in it or not. My next step is to check whether the file already exists on the server; if the file already exists it does not send and if it does not exist, it does send.
I've tried a few different things and can't seem to get my head around it. How can I get it to check whether the file already exists or not? Any help would be appreciated!
(I had a look at some similar questions but couldn't find anything specific to my issue.)
require('constants.php');
$files = $sftp->nlist('out/');
foreach($files as $file) {
if(basename((string) $file)) {
if(strpos($file,".") > 1) { //Checks if file
$filesize = $sftp->size('out/'.$file); //gets filesize
if($filesize > 1){
if (file_exists('import/'.$file)){
echo $file.' already exists';
}
else {
$sftp->get('out/'.$file, 'import/'.$file); //Sends file over
//$sftp->delete('out/'.$file); //Deletes file from out folder
}
else {
echo $file. ' is empty.</br>';
}
}
}
}
}
EDIT: To try and get this to work, I wrote the following if statement to see if it was finding the file test.php;
if (file_exists('test.txt')){
echo 'True';
} else {
echo 'False';
}
This returned true (a good start) but as soon as I put this into my code, I just get a 500 Internal Server Error (extremely unhelpful). I cannot turn on errors as it is on a server that multiple people use.
I also tried changing the file_exists line to;
if (file_exists('test.txt'))
in the hopes that would work but still didn't work.
Just to clarify, I'm sending the files from the remote server to my local server.
There is a closing curly brace missing right before the second else keyword.
Please try to use a code editor with proper syntax highlighting and code formatting to spot such mistakes on the fly while you are still editing the PHP file.
The corrected and formatted code:
require('constants.php');
$files = $sftp->nlist('out/');
foreach ($files as $file) {
if (basename((string)$file)) {
if (strpos($file, ".") > 1) { //Checks if file
$filesize = $sftp->size('out/' . $file); //gets filesize
if ($filesize > 1) {
if (file_exists('import/' . $file)) {
echo $file . ' already exists';
} else {
$sftp->get('out/' . $file, 'import/' . $file); //Sends file over
}
} else {
echo $file . ' is empty.</br>';
}
}
}
}
Your code checks the file exist in your local server not in remote server.
if (file_exists('import/'.$file)){
echo $file.' already exists';
}
You need to check in remote server using sftp object like
if($sftp->file_exists('import/'.$file)){
echo $file.' already exists';
}
Edit:
Add clearstatcache() before checking file_exists() function as the results of the function get cached.
Refer: file_exists

Use copy() in a foreach loop to copy multiple files php

I'm trying to copy multiple files from one domain on a web server to another using copy() and looping through a list of files, but it's only copying the last file on the list.
Here is the contents of files-list.txt:
/templates/template.php
/admin/admin.css
/admin/codeSnippets.php
/admin/editPage.php
/admin/index.php
/admin/functions.php
/admin/style.php
/admin/editPost.php
/admin/createPage.php
/admin/createPost.php
/admin/configuration.php
This script runs on the website that I'm trying to copy the files to. Here's the script:
$filesList = file_get_contents("http://copyfromhere.com/copythesefiles/files-list.txt");
$filesArray = explode("\n", $filesList);
foreach($filesArray as $file) {
$filename = trim('http://copyfromhere.com/copythesefiles' . $file);
$dest = "destFolder" . $file;
if(!#copy($filename, $dest))
{
$errors= error_get_last();
echo "COPY ERROR: ".$errors['type'];
echo "<br />\n".$errors['message'];
} else {
echo "$filename copied to $dest from remote!<br/>";
}
}
I get the affirmative message for each and every file individually just as I should, but when I check the directory, only the last file from files-list.txt is there. I've tried changing the order, so I know the problem lies with the script, not any individual file.
The output from the echo statements looks something like this:
http://copyfromhere.com/copythesefiles/admin/admin.css copied to updates/admin/editPage.php from remote!
http://copyfromhere.com/copythesefiles/admin/admin.css copied to updates/admin/editPost.php from remote!
http://copyfromhere.com/copythesefiles/admin/admin.css copied to updates/admin/index.php from remote!
Etc
I've modified your code slightly, and tested it on my local dev server. The following seems to work:
$fileURL = 'http://copyfromhere.com/copythesefiles';
$filesArray = file("$fileURL/files-list.txt", FILE_IGNORE_NEW_LINES);
foreach ($filesArray as $file) {
$fileName = "$fileURL/$file";
$dest = str_replace($fileURL, 'destFolder', $fileName);
if (!copy($fileName, $dest)) {
$errors= error_get_last();
echo "COPY ERROR: ".$errors['type'];
echo "<br />\n".$errors['message'];
}
else {
echo "$fileName copied to $dest from remote!<br/>";
}
}
This uses the same fix that Mark B pointed out, but also consolidated the code a little.
Unless the data you're fetching from that remote site has leading/ in the path/filename, you're not generating proper paths:
$file = 'foo.txt'; // example only
$dest = "destFolder" . $file;
produces destFolderfoo.txt, and you end up littering your script's working directory with a bunch of wonky filenames. Perhaps you wanted
$dest = 'destFolder/' . $file;
^----note this
instead.

Unzipping to a variable

I need to process the contents of a zipped file, but I can't change the permissions on the server where my program will be hosted.
This means that I can't download the zip file to the server, so I need to read the contents of the file into a variable without writing it to the file system.
Can I grab the string contents of such variable and get the unzipped contents into a new variable?
So far, I've looked into using the zip php extension, and the pclzip library, but both need to use actual files.
This is what I want to do in pseudo code:
$contentsOfMyZipFile = ZipFileToString();
$myUnzippedContents = libUnzip($contentsOfMyZipFile);
Any ideas?
Look at this example.
<?php
$open = zip_open($file);
if (is_numeric($open)) {
echo "Zip Open Error #: $open";
} else {
while($zip = zip_read($open)) {
zip_entry_open($zip);
$text = zip_entry_read($zip , zip_entry_filesize($zip));
zip_entry_close($zip);
}
print_r($text);
?>
I use this in my project:
function unzip_file( $data ) {
//save in tmp zip data
$zipname = "/tmp/file_xxx.zip";
$handle = fopen($zipname, "w");
fwrite($handle, $data);
fclose($handle);
//then open and read it.
$open = zip_open($zipname);
if (is_numeric($open)) {
echo "Zip Open Error #: $open";
} else {
while ($zip = zip_read($open)) {
zip_entry_open($zip);
$text = zip_entry_read($zip, zip_entry_filesize($zip));
zip_entry_close($zip);
}
}
/*delete tmp file and return variable with data(in this case plaintext)*/
unlink($zipname);
return $text;
}
I hope it helps you.

$zip Rename Functions Not Working in PHP

I am extracting a zip file in PHP and trying to rename it to content.txt. Here is my code:
if($this->copyFile($this->src,$this->dest)) {
$this->log .= "Successfully copied the file. Starting unzip.<br />";
$res = $this->zip->open($this->dest);
if ($res === TRUE) {
$this->zip->extractTo("/htdocs/content-refresh/");
$this->extracted = $this->zip->getNameIndex(0);
$this->log .= "Extracted ".$this->extracted." onto our server.<br />";
if($this->zip->renameIndex(0,'content.txt')) {
$this->log .= "Renamed update file to content.txt.<br />";
} else {
$this->log .= "Could not rename update file to content.txt.<br />";
}
$this->zip->close();
$this->log .= "The update file is ready to go. Now you can use the update functions.<br />";
} else {
$this->log .= "Could not unzip the file.<br />";
}
}
Here is the file output:
Successfully copied the file. Starting unzip.
Extracted Hotel_All_Active 01-19-11.txt onto our server.
Renamed update file to content.txt.
The update file is ready to go. Now you can use the update functions.
The problem is that it does not rename the file. I have also tried:
$this->zip->renameName(strval($this->extracted),'content.txt')
But that also prints out that it renamed the file, but does not. Am I doing something wrong here, or is this function buggy?
The renameIndex() function is for renaming a file inside an archive.
Looking at the code in the PHP Manual for that function, it's you can see it's modifying the archive:
$zip = new ZipArchive;
$res = $zip->open('test.zip');
if ($res === TRUE) {
$zip->renameIndex(2,'newname.txt');
$zip->close();
} else {
echo 'failed, code:' . $res;
}
You need to use the rename() function instead.

Best way to read zip file in PHP

file_get_contents("zip:///a/b/c.zip") is returning NULL. How can I read unzipped contents of a zip file in PHP 5+?
use ZipArchive class
$zip = new ZipArchive;
$zip->open('test.zip');
echo $zip->getFromName('filename.txt');
$zip->close();
Use zip_open and zip_read functions to do it.
Documentation to it you can find at http://php.net/manual/en/function.zip-read.php
<?php
/**
* This method unzips a directory within a zip-archive
*
* #author Florian 'x!sign.dll' Wolf
* #license LGPL v2 or later
* #link http://www.xsigndll.de
* #link http://www.clansuite.com
*/
function extractZip( $zipFile = '', $dirFromZip = '' )
{
define(DIRECTORY_SEPARATOR, '/');
$zipDir = getcwd() . DIRECTORY_SEPARATOR;
$zip = zip_open($zipDir.$zipFile);
if ($zip)
{
while ($zip_entry = zip_read($zip))
{
$completePath = $zipDir . dirname(zip_entry_name($zip_entry));
$completeName = $zipDir . zip_entry_name($zip_entry);
// Walk through path to create non existing directories
// This won't apply to empty directories ! They are created further below
if(!file_exists($completePath) && preg_match( '#^' . $dirFromZip .'.*#', dirname(zip_entry_name($zip_entry)) ) )
{
$tmp = '';
foreach(explode('/',$completePath) AS $k)
{
$tmp .= $k.'/';
if(!file_exists($tmp) )
{
#mkdir($tmp, 0777);
}
}
}
if (zip_entry_open($zip, $zip_entry, "r"))
{
if( preg_match( '#^' . $dirFromZip .'.*#', dirname(zip_entry_name($zip_entry)) ) )
{
if ($fd = #fopen($completeName, 'w+'))
{
fwrite($fd, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)));
fclose($fd);
}
else
{
// We think this was an empty directory
mkdir($completeName, 0777);
}
zip_entry_close($zip_entry);
}
}
}
zip_close($zip);
}
return true;
}
// The call to exctract a path within the zip file
extractZip( 'clansuite.zip', 'core/filters' );
?>
look at the build in zip functions:
http://php.net/manual/en/book.zip.php
The zip:// protocol is provided by the ZIP extension of PHP. Check in your phpinfo() output whether the extension has been installed or not.
I am responding to the first part of the question i.e. using the file_get_contents method
'file_get_contents("zip:///a/b/c.zip")' Usually that method is used to read one particular file nested inside the zip file. In order to extract all the contents; others have given nice answers.
I am using PHP 7.2.34 on windows and later on in Linux. I kept a zip file at d:\data and this syntax works in windows. It does echo the contents of example1.py which is inside a "folder" in the ZIP file.
Possibly it is also to do with where/how the zip file was created. When I had created the zip file from within PHP, the internal delimiters were backslashes but when Windows created the zip file (by using the "Send to compressed folder" feature in Windows explorer) then Windows was using the Linux convention inside the zip file!
More testing is needed here to know which delimiter for the internal paths, is being used in the zip file
<?php
$str = file_get_contents('zip://d:/data/demo.zip#examples\\example1.py');
echo $str;
?>

Categories