PHP shell execution create dynamic command - php

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

Related

PHP: proc_get_status exitcode is always -1 after pcntl_fork

I'm having troubles with using proc_get_status after a pcntl_fork in the parent process.
Here's an example with docker and PHP 7.4, but note the PHP version does not matter, the result is the same from at least PHP 7.2 to PHP 8.1.
Setup
Dockerfile
FROM php:7.4
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions pcntl
Run: docker build -t php-pcntl-7.4 .
test.php
<?php
if ($argv[1] ?? false) {
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
if ($pid === -1) {
throw new \RuntimeException('fork failed');
}
if ($pid === 0) {
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
throw new \Exception('child should be ignored');
}
pcntl_waitpid($pid, $childStatusCode);
}
function runCommand(string $command): void
{
$pipes = [];
$proc = proc_open($command, [['pipe', 'r'],['pipe', 'w'],['pipe', 'w']], $pipes);
do {
if (isset($status)) {
usleep(300000);
}
$status = proc_get_status($proc);
} while ($status['running']);
echo 'Command: ' . $command . PHP_EOL;
echo 'last proc_get_status exitcode: ' . $status['exitcode'] . PHP_EOL;
echo PHP_EOL;
}
echo 'PHP version: ' . PHP_VERSION . PHP_EOL;
runCommand('/bin/echo test');
runCommand('/bin/false');
Test without running a fork before
Run: docker run -it --rm -v $PWD:/workdir -w /workdir php-pcntl-7.4 php test.php
Output:
PHP version: 7.4.28
Command: /bin/echo test
last proc_get_status exitcode: 0
Command: /bin/false
last proc_get_status exitcode: 1
Test with running a fork before
Run: docker run -it --rm -v $PWD:/workdir -w /workdir php-pcntl-7.4 php test.php 1
Output:
PHP version: 7.4.28
Command: /bin/echo test
last proc_get_status exitcode: -1
Command: /bin/false
last proc_get_status exitcode: -1
Does anyone have an idea of why the exitcode is always -1, and if there is a workaround ?

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);

trying to create a ftp user with permissions

So I'm trying to create a ftp user and give him permissions to a specific directory, but the user is not being created. When I echo the commands the directory is created and the permissions are given to the user but when i try to log with the credentials created it's not working. Please take a look. What am I doing wrong ?
$randomNum = substr(str_shuffle("0123456789abcdefghijklmnopqrstvwxyz"), 0, 8);
$randomPass = substr(str_shuffle("0123456789abcdefghijklmnopqrstvwxyz"), 0, 6);
$src = $request->path;
$dest = "/home/$randomNum";
echo $ssh->exec("mkdir $dest\n");
echo $ssh->exec("useradd -m -d $dest $randomNum\n");
echo $ssh->exec("passwd $randomNum\n");
echo $ssh->read('New password:');
echo $ssh->write($randomPass."\n");
echo $ssh->exec("nice -n 19 cp -Rf $src $dest && chown -Rf $randomNum:$randomNum $dest && exit\n");
$ssh->disconnect();
Assuming that randomNum is the username, randomPass the password and dest the home directory,
Change this:
echo $ssh->exec("mkdir $dest\n");
echo $ssh->exec("useradd -m -d $dest $randomNum\n");
echo $ssh->exec("passwd $randomNum\n");
echo $ssh->read('New password:');
echo $ssh->write($randomPass."\n");
echo $ssh->exec("nice -n 19 cp -Rf $src $dest && chown -Rf $randomNum:$randomNum $dest && exit\n");
To this:
$ssh->exec("useradd -M " . $randomNum. " -d " . $dest);
$ssh->exec("echo \"" . $randomNum . ":" . $randomPass . "\" | sudo chpasswd");
$ssh->exec("chown -R " . $randomNum . ":" . $randomNum . " " . $dest);
From your code:
echo $ssh->exec("passwd $randomNum\n");
echo $ssh->read('New password:');
echo $ssh->write($randomPass."\n");
For that command, in particular, you'd need to enable PTY mode for the reads / writes to work. You can do so by doing $ssh->enablePTY() before the command. It might not be a bad idea to do $ssh->disablePTY() after the command, however.
Also, echo $ssh->write($randomPass."\n");... that's not really gonna have the desired effect. $ssh->write just returns true or false depending on the success or failure of the write command.

7zip command executes from command line but not within php script

I am attempting to write a script which automatically unzips 7zip archives. I'm able to get the command to run from the command prompt, but it doesn't work when running from within the php script.
Here's what I have in terms of code:
$filefolder = "F:/dev/";
$filename = "archive.7z";
$filepath = $filefolder . $filename;
$unzip = "cmd /c 7z x " . $filePath . " -o" . $fileFolder . " -spf";
print_r($unzip . "<br>"); //checking to make sure the command is formed correctly
exec($unzip, $outcome, $rtnStatus);
print_r($outcome);
print_r($rtnStatus);
The following is returned for $outcome and $rtnStatus:
Array ( )
1
What am I missing here?

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