PharData class fails when tar contents has relative paths - php

I'm having trouble with using Phar to access gzipped tar files.
Here's my test code:
<?php
function r($a) {
print " has " . count($a) . " files:\n";
foreach (new RecursiveIteratorIterator($a) as $path => $fileinfo) {
print " " . $path . "\n";
}
}
print "\n1.tgz";
r(new PharData('1.tgz'));
print "\n2.tgz";
r(new PharData('2.tgz'));
print "\norig dir:";
chdir('orig-dir');
r(new RecursiveDirectoryIterator('./'));
Here's the fixture:
mkdir -p orig-dir/subdir; touch orig-dir/{a,b,subdir/c}; cd orig-dir
tar czf ../1.tgz *
tar czf ../2.tgz ./
cd ../
# put the test code file here and run with php test-code.php
Here's the output:
1.tgz has 4 files:
phar:///tmp/t/1.tgz/a
phar:///tmp/t/1.tgz/b
phar:///tmp/t/1.tgz/subdir/c
2.tgz has 5 files:
orig dir: has 1 files:
./b
./.
./subdir/.
./subdir/c
./subdir/..
./..
./a
Q. Why is phar having such difficulties with the 2nd tar file? (I'm on php 5.6)

Related

Running commands from PHP exec shows different result than from shell

The PHP exec command is not executing the same as the shell's interaction.
cd /var/www/myfolder
zip -r /var/www/myfolder/temp/newfile.zip ./*
generates just a zip of files in the temp directory. However (simplified version):
$zip_dir = '/var/www/myfolder';
$temp_dir = $zip_dir . '/temp/';
chdir($zip_dir);
exec('zip -r ' . $temp_dir . 'newfile.zip ./*', $return);
generates the same zip but with the full path's of var and www (which results in two copies of myfolder so my file is twice as large as needed). The $return however has the same output as the command line execution. Both state only 15 files directories/folders were zipped. There is no mention of var or www in the PHP output.
I believe the chdir() command will not have any bearing on how the commands in exec() are run. So this might fix it:
$zip_dir = '/var/www/myfolder';
$temp_dir = $zip_dir . '/temp/';
$cmd = 'cd ' . escapeshellarg($zip_dir) . ' && zip -r ' . escapeshellarg($temp_dir . 'newfile.zip') . ' ./*';
exec($cmd, $return);
Note we always escape variables being passed to the command line.
But why not just zip within PHP?
<?php
$zip_target = "/var/www/myfolder";
$zip_file = "/var/www/myfolder/temp/newfile.zip";
$zip_temp = tempnam(sys_get_temp_dir(), 'a458');
$zip_obj = new \ZipArchive();
if ($zip_obj->open($zip_temp, ZIPARCHIVE::OVERWRITE)) {
$zip_obj->addGlob("$zip_target/**/*.*");
}
$zip_obj->close();
rename($zip_temp, $zip_file);

Download array of files on same server as PHP script

I have an array or over 1,000 files that I need to download to my local PC from my server.
I need to keep it to replicate the same file/folder structure for each file.
Here is an example list of files:
/lib/Zend/EventManager/Filter/FilterIterator.php
/lib/Zend/EventManager/config.php
/lib/Zend/Text/Figlet/themes.php
/lib/Zend/Gdata/Analytics/DataEntry.php
/lib/Zend/Gdata/Analytics/AccountQuery.php
/lib/Zend/Gdata/Calendar/files.php
/lib/Zend/Gdata/Query.php
/lib/Zend/Gdata/Gbase/Feed.php
/lib/Zend/Gdata/Photos.php
/lib/Zend/Gdata/Photos/AlbumFeed.php
/lib/Zend/Gdata/Media/Extension/press.php
/lib/Zend/Gdata/Media/file.php
/lib/Zend/Gdata/Extension/RecurrenceException.php
/lib/Zend/Gdata/Extension/Comments.php
/lib/Zend/Gdata/Extension/Recurrence.php
/lib/Zend/Gdata/Extension/Rating.php
To create the folders, navigate to them with FTP, and then download them would take me all day long! How can I do this with PHP?
These files cannot be accessed in the browser with a URL so I have to use the file path.
UPDATE
Here is what I have tried so far using PHP ZipArchive...
files.txt
Test file to test a sample of the files I will need. Final result will be over 1,000 files
lib/Zend/EventManager/Filter/FilterIterator.php
lib/Zend/EventManager/config.php
lib/Zend/Text/Figlet/themes.php
lib/Zend/Gdata/Analytics/DataEntry.php
lib/Zend/Gdata/Analytics/AccountQuery.php
lib/Zend/Gdata/Calendar/files.php
lib/Zend/Gdata/Query.php
lib/Zend/Gdata/Gbase/Feed.php
lib/Zend/Gdata/Photos.php
lib/Zend/Gdata/Photos/AlbumFeed.php
lib/Zend/Gdata/Media/Extension/press.php
lib/Zend/Gdata/Media/file.php
lib/Zend/Gdata/Extension/RecurrenceException.php
lib/Zend/Gdata/Extension/Comments.php
lib/Zend/Gdata/Extension/Recurrence.php
lib/Zend/Gdata/Extension/Rating.php
lib/Zend/Gdata/Books/VolumeQuery.php
lib/Zend/Gdata/Books/VolumeFeed.php
lib/Zend/Gdata/Exif/themes.php
lib/Zend/Gdata/MimeBodyString.php
lib/Zend/Gdata/HttpAdapterStreamingProxy.php
lib/Zend/Gdata/Spreadsheets/Extension/test.php
lib/Zend/Gdata/Spreadsheets/ListEntry.php
lib/Zend/Gdata/Gapps/Query.php
lib/Zend/Gdata/Gapps/GroupQuery.php
lib/Zend/Gdata/Gapps/EmailListRecipientQuery.php
lib/Zend/Gdata/Gapps/Error.php
lib/Zend/Gdata/Gapps/OwnerFeed.php
lib/Zend/Gdata/Gapps/alias.php
lib/Zend/Gdata/Gapps/MemberQuery.php
lib/Zend/Gdata/Gapps/EmailListQuery.php
lib/Zend/Gdata/Gapps/NicknameFeed.php
lib/Zend/Gdata/Exif.php
lib/Zend/Gdata/App/LoggingHttpClientAdapterSocket.php
lib/Zend/Gdata/App/Extension.php
lib/Zend/Gdata/App/MediaEntry.php
lib/Zend/Gdata/App/FeedEntryParent.php
lib/Zend/Gdata/App/AuthException.php
download.php
$zip = new ZipArchive();
$filename = "./test112.zip";
if ($zip->open($filename, ZipArchive::CREATE)!==TRUE) {
exit("cannot open <$filename>\n");
}else{
echo 'zip good';
}
//$zip->addFromString("testfilephp.txt" . time(), "#1 This is a test string added as testfilephp.txt.\n");
//$zip->addFile("lib/Zend/files2.txt" ,"lib/Zend/EventManager/test.php" );
// list of files to download
$lines = file('files.txt');
// Loop through our array of files from the files.txt file
foreach ($lines as $line_num =>$file) {
//echo "Line #<b>{$line_num}</b> : " . htmlspecialchars($file) . "<br />\n";
// Add files to Zip file incliuding folder structure
$zip->addFile($file,$file);
echo $file;
}
// show number of files in new zip file and close zip archive
echo "numfiles: " . $zip->numFiles . "\n";
echo "status:" . $zip->status . "\n";
$zip->close();
Result
This creates my zip file however instead of adding all files, it only adds the last file in my files array to the zip archive! In this example that is lib/Zend/Gdata/App/AuthException.php
As you have SSH access, you could simply run this on the server:
# Change '*.php' to whatever you want to retrieve:
find . -name '*.php' -print | zip archive.zip -#
Then you can get the file archive.zip via scp or ftp.

PHP shell execution create dynamic command

Following Command search a file in a directory and zip it,it works well
$command = "cd {$root}/files && mkdir -p {$identifier} && zip -jFS -0 {$root}{$zipname} 2491/'test&.txt'";
exec($command);
But changing files as variable is not allowing shell to execute,the below code does not work
$container_name = "2491";
$files = Array ( '0' => 'test&.txt' ,'1' => 'test5.txt','2' => 'test6.txt');
$files = " " . $container_name . "/'" . implode("' " . $container_name . "/'", $files) . "'";
$files = str_replace('$', '\$', $files);
$command = "cd {$root}/files && mkdir -p {$identifier} && zip -jFS -0 {$root}{$zipname} {$files}";
exec($command);
$root,$identifier,$zipname not causing the problem,its $files What can be the issue?
Update
var_dump for $command before execution:
string(128) "cd /var/www/files && mkdir -p zip--1 && zip -jFS -0 /var/www/files/zip--1/1002_22-06022-06022-_content.zip 2491/'test&.txt'"
which if I execute as
exec("cd /var/www/files && mkdir -p zip--1 && zip -jFS -0 /var/www/files/zip--1/1002_22-06022-06022-_content.zip 2491/'test&.txt'");
runs perfectly
Error Reponse:
zip error: Nothing to do! (/var/www/files/zip--1/1002_22-06022-06022-_content.zip)
I got it fix, issue was with file name having '&' which was chanding to '&', thus breaking the command. To get it I passed through the file name with [htmlspecialchars_decode].1

PHP can't execute command from apache, but can from CLI (MaxOS X, PHP 5.3)

I want to execute shell command from PHP, running under apache. I make script, that shows all info about enviroment.
PHP Script:
<?php
$root = dirname(__FILE__);
$coffeeFile = $root . DIRECTORY_SEPARATOR . 'Script.coffee';
$jsFile = $root . DIRECTORY_SEPARATOR . 'Script.js';
echo "User: " . exec('whoami') . "\n";
echo "Which: " . exec('which coffee') . "\n";
echo "Coffee file perms: " . substr(sprintf('%o', fileperms($coffeeFile)), -4) . "\n";
echo "Js file perms: " . substr(sprintf('%o', fileperms($jsFile)), -4) . "\n";
echo "Dir perms: " . substr(sprintf('%o', fileperms($root)), -4) . "\n";
$command = "coffee -bo $root -c $coffeeFile";
exec($command, $output);
if (filemtime($coffeeFile) > filemtime($jsFile)) {
echo 'compile failed. command: ' . $command . PHP_EOL;
echo "Output: " . implode("\n", $output) . PHP_EOL;
} else {
echo 'compile success. command: ' . $command . PHP_EOL;
}
It I'll execute it from command line from _www user, it will work:
Command:
sudo -u _www php index.php
Output from CLI:
User: _www
Which: /usr/bin/coffee
Coffee file perms: 0777
Js file perms: 0777
Dir perms: 0777
compile success command: coffee -bo /Users/username/htdocs/testcase -c /Users/username/htdocs/testcase/Script.coffee
But if run it from browser, compile fails, but not errors or output is there.
Output in browser:
User: _www
Which: /usr/bin/coffee
Coffee file perms: 0777
Js file perms: 0777
Dir perms: 0777
compile failed. command: coffee -bo /Users/username/htdocs/testcase -c /Users/username/htdocs/testcase/Script.coffee
Output: /* empty array in output */
How it can be? I change my file before every execution, it need to be compiled every time. Users are the same, "which" command works, dir and files have permissions, coffee file is valid. Maybe there are some apache or php.ini settings, that locks execution of some shell commands?
Kindly check does PHP have shell_exec access given or not. Default setting shell_exec is blocked and you have edit php.ini to unblock it and restart service and do things.
Note: Providing shell access can be dangerous as it is the open invitation to the hackers to hack your machine.

php shell exec acting different to running command directly

I have a php script that attempts to remove all files from a directory structure, but preserve everything in svn. I found this command online which does the job perfectly if you plug it directly in a shell
find /my/folder/path/ -path \'*/.svn\' -prune -o -type f -exec rm {} +
Unfortunately if I perform a shell_exec in php on that command like so:
$cmd = 'find $folderPath -path \'*/.svn\' -prune -o -type f -exec rm {} +';
shell_exec($cmd);
Then all the files in my current directory that I call the php script from are deleted as well.
Can someone explain why, and how to fix the issue so that I can fix the php script so it acts like expected, removing only those files in the specified folder
The full source code is below, just in case there is perhaps a silly mistake in there that I have missed:
<?php
# This script simply removes all files from a specified folder, that aren't directories or .svn
# files. It will see if a folder path was given as a cli parameter, and if not, ask the user if they
# want to remove the files in their current directory.
$execute = false;
if (isset($argv[1]))
{
$folderPath = $argv[1];
$execute = true;
}
else
{
$folderPath = getcwd();
$answer = readline("Remove all files but not folders or svn files in $folderPath (y/n)?" . PHP_EOL);
if ($answer == 'Y' || $answer == 'y')
{
$execute = true;
}
}
if ($execute)
{
# Strip out the last / if it was given by accident as this can cause deletion of wrong files
if (substr($folderPath, -1) != '/')
{
$folderPath .= "/";
}
print "Removing files from $folderPath" . PHP_EOL;
$cmd = 'find $folderPath -path \'*/.svn\' -prune -o -type f -exec rm {} +';
shell_exec($cmd);
}
else
{
print "Ok not bothering." . PHP_EOL;
}
print "Done" . PHP_EOL;
?>
Your command looks okay. At least in shell. If you would actually troubleshoot your issue in PHP with a simple
var_dump($cmd);
You would see where your error lies:
$cmd = 'find $folderPath -path \'*/.svn\' -prune -o -type f -exec rm {} +';
Look closely. Hint: A single can't make a double for a dollar.
It all comes down to:
$cmd = 'find $folderPath -path \'*/.svn\' -prune -o -type f -exec rm {} +';
shell_exec($cmd);
Since you are using single quotes the variable $folderPath is not changed. So you are executing
find $folderPath -path '*/.svn' -prune -o -type f -exec rm {} +
instead of
find /my/folder/path/ -path \'*/.svn\' -prune -o -type f -exec rm {} +
use double quotes or $cmd = 'find '.$folderPath.' -path \'*/.svn\' -prune -o -type f -exec rm {} +';

Categories