shell_exec not working in php even after all the permissions - php

I have been trying to execute a shell script that executes a perl program and i am doing that using the shell_exec() in php.
I have given all the permissions to the folders as well as the executables. Also, shell_exec() is not disabled in the php.ini. I have even tried using the 2>&1 after the command. Kindly help.
Following is the code.
<?php
if(isset($_POST['EI']) && isset($_POST['OP']) && isset($_POST['GC']) && isset($_POST['PA']) && isset($_POST['HT']) && isset($_POST['AB'])) {
$data = 'Option entered by user :'.$_POST['OP'] . "\n" . 'The Threshold for GC is :'.$_POST['GC'] . "\n" . 'The Threshold for PA is :'.$_POST['PA'] . "\n" . 'The Threshold for HT is :'.$_POST['HT'] . "\n" . 'The Threshold for AB is :'.$_POST['AB'] . "\n" . 'The email id of the user is :'.$_POST['EI'] . "\n";
$ret = file_put_contents('/..path../out.txt', $data);
if($ret === false) {
die('There was an error writing this file');
} else {
echo "$ret bytes written to file";
}
} else {
die('no post data to process');
}
$output=shell_exec("./testing.sh");
?>

Related

PHP in Windows: add an environment variable for User or Machine

I am trying to update the Path environment variable in Windows with a PHP script, but if I use putenv() it doesn't change. I can get the paths list in the Path variable but I am not able to update it.
Another problem is that if I use getenv('Path') to get the paths list, I have a unique string with all paths merged from the Path variable of User and of the Machine.
I'm wondering if there is a better way to do that, maybe acting directly in the registry key to update User Path variable.
UPDATE
I think I found out a half-solution, but it doesn't work as expected.
What do I want to do?
I just want to make a script that allow me to switch from a PHP version to another changing the Path variable.
I made the script, it seems to work and the Path variable is successfully updated, but even if I close and reopen the cmd prompt if I type php -v it doesn't seems to get the updated var. If I open the Environment Variables windows, then open the "Path" variable and click on Ok and Ok again, then the refresh is got but the cmd prompt.
This is very strange to me, and if I have to do this everytime, then script loose its benefit...
I recorded a video, I hope it explain the problem better than my English...
https://1drv.ms/v/s!Ao2s4w8xSxBSh7RY4y5pB8u1g_QFSQ
This is the code of the script:
// Load PHP available versions
$laragon_php_paths = 'D:\www-servers\laragon\bin\php';
$php_paths = scandir($laragon_php_paths);
$path_var_name = "Path";
// Backup before doing a disaster
$date = new DateTime();
exec('REG EXPORT HKCU\Environment BackupUserEnvironment_' . $date->format('YmdHisv') . '.reg');
// Load registry key of user's Path environment variable
exec('REG QUERY HKCU\Environment /v ' . $path_var_name, $output, $result);
$path = explode(' ', $output[2]);
$path_array = explode(';', $path[count($path) - 1]);
// Get the current PHP Version and get the key of the item of the PHP bin path
foreach ($path_array as $key => $path_item) {
if (strpos($path_item, $laragon_php_paths) !== false) {
$the_key = $key;
$current_php_version = substr($path_item, strrpos($path_item, '\\') + 1);
}
}
echo 'Available PHP versions:' . PHP_EOL . PHP_EOL;
$i = 0;
foreach ($php_paths as $dir) {
if ($dir === '.' || $dir === '..') continue;
echo ' [' . ++$i . '] ' . $dir;
if ($dir === $current_php_version) {
echo ' [Current version]';
}
echo PHP_EOL;
}
// Get file descriptor for stdin
echo PHP_EOL;
echo 'Select a PHP version: ';
$fd = fopen('php://stdin', 'r');
$choice = (int) fgets($fd);
echo PHP_EOL;
// Check if choice is between 1 and number of choices
if ($choice > 0 && $choice <= $i) {
// Change the original php version with the new one
$new_php_version = $php_paths[$choice + 1];
$path_array[$the_key] = $laragon_php_paths . '\\' . $new_php_version;
echo 'PHP version changed to: ' . $new_php_version . PHP_EOL;
} else {
echo 'No allowed choice, nothing changed.';
echo PHP_EOL;
}
// Escape some chars for cmd
$new_path_var = str_replace(['%', ' '], ['^%', '" "'], implode(';', $path_array));
$cmd = 'REG ADD HKCU\Environment /f /t REG_EXPAND_SZ /v ' . $path_var_name . ' /d ' . $new_path_var;
// Execute
exec($cmd);

User not allowed to use crontab

I want to edit cron tab daily to delete / add some jobs .. so I added cron job ( helper job ) to run php script to handle these edits.
When I run this script by browser works fine .. but when it runs using the helper job not running and I receive notification mail from cpanel with this error :
Please note I am on shared hosting plan with C-Panel so I have no root access .. but the code working fine when run from browser.
Error:
You (dcfn35c8st1b) are not allowed to use this program (crontab)
See crontab(1) for more information
You (dcfn35c8st1b) are not allowed to use this program (crontab)
See crontab(1) for more information
You (dcfn35c8st1b) are not allowed to use this program (crontab)
See crontab(1) for more information
You (dcfn35c8st1b) are not allowed to use this program (crontab)
See crontab(1) for more information
You (dcfn35c8st1b) are not allowed to use this program (crontab)
See crontab(1) for more information
PHP Script:
exec('crontab -l', $crontab);
$record_found = false;
foreach($crontab as $key => $value){
if(strpos($value, 'record_extra.php') !== false){
//echo $key . ' ' . $value . '<br>';
unset($crontab[$key]);
$record_found = true;
}
if(strpos($value, 'record.php') !== false){
//echo $key . ' ' . $value . '<br>';
unset($crontab[$key]);
}
}
if($record_found){
file_put_contents('/tmp/crontab.txt', arrayToString($crontab) . $firstJob.PHP_EOL);
if(exec('crontab /tmp/crontab.txt')){
//echo 'success <br>';
} else {
//echo 'error <br>';
}
$output = shell_exec('crontab -l');
file_put_contents('/tmp/crontab.txt', $output . $secondJob.PHP_EOL);
if(exec('crontab /tmp/crontab.txt')){
//echo 'success <br>';
} else {
//echo 'error <br>';
}
} else {
$output = shell_exec('crontab -l');
file_put_contents('/tmp/crontab.txt', $output . $firstJob.PHP_EOL);
if(exec('crontab /tmp/crontab.txt')){
//echo 'success <br>';
} else {
//echo 'error <br>';
}
$output = shell_exec('crontab -l');
file_put_contents('/tmp/crontab.txt', $output . $secondJob.PHP_EOL);
if(exec('crontab /tmp/crontab.txt')){
//echo 'success <br>';
} else {
//echo 'error <br>';
}
}
Need your help.
Thanks in advance.
Seems like the user isn't allowed to run crontab. Look into the files "/etc/cron.allow" and "/etc/cron.deny". If cron.allow exists, then only users in that list can use crontab. Users in cron.deny, can't use. If neither exist then only root user can use crontab.
I've looked at numerous "can't run crontab" posts and none of them addressed my problem. I want to report my unique solution.
My service provider copied my system to another place, and apparently they literally used the "cp" command to do it, which meant that no setuid bits were preserved. /usr/bin/crontab was one of several files for which I had to restore the setuid bit.
You can't run crontab if it doesn't have the setuid bit set.

How to use system command in php?

I am working on a PHP code as shown below in which conversion of mp4 into mp3 is happening at Line B.
I have added if block after system command to print Conversion Completed on the webpage once the conversion is complete but it doesn't seem to work.
Php code:
if (isset($_POST['id']))
{
for($i=0; $i <count($mp4_files); $i++) {
if($i == $_POST['id']) {
$f = $mp4_files[$i];
$parts = pathinfo($f);
switch ($parts['extension'])
{
case 'mp4' :
$filePath = $src_dir . DS . $f;
print_r($f); // Line A
system('ffmpeg -i ' . $filePath . ' -map 0:2 -ac 1 ' . $destination_dir . DS . $parts['filename'] . '.mp3', $result); // Line B
if($result)
{
echo "Conversion Completed";
}
}
}
}
}
Problem Statement:
I am wondering what changes I should make in the PHP code above so that once the conversion is complete; on the webpage, it should print Conversion Completed.
You can use shell_exec to get a return value and then put that in an if statement like this
$output = shell_exec('ffmpeg -i ' . $filePath . ' -map 0:2 -ac 1 ' . $destination_dir . DS . $parts['filename'] . '.mp3');
if ($output) {
echo "Conversion Completed!";
// or redirect here
}
Also, make sure to sanitize your inputs as they are exposed to a CLI interface.

PHP using phpseclib - exec(ls...) command doesn't find a file that was just created and exists on the disk

Using phpseclib from my PHP application, I am running a perl .pl script which creates a file on the remote server's drive/folder in one of the exec() commands. This works fine and the file exists. The next exec() does an 'ls' command to retrieve the full filename which contains a date/time stamp on the end of the file name that is unknown. When it runs, it doesn't find the file when it is there and I can see it when doing a manual 'ls' on the Linux system. I believe it might be a timing issue, so I also included a sleep 15 in between creation and doing the 'ls' command, but this did not resolve the issue. And if I run the program again, creating a 2nd file, then the 'ls' returns the filename for the first file I generated. I didn't see an fclose in the documentation, but did see it in some other posts here that might lead me to believe this might also be the issue. Has anyone else experienced this issue and how did you resolve? Thanks.
Updated: Code snippet added....
$ssh2->login(LINUX_USER,LINUX_PASS);
$connected = $ssh2->isAuthenticated();
if ($connected) {
//$_SESSION['feedback'] .= "Connection and authentication successful to " . LINUX_SVR . ".<br>";
$cmd_string = "/usr/bin/perl-report.pl " . LINUX_ENV . " " . $parm1 . " " . $parm2;
$error = $ssh2->exec($cmd_string);
if ($error) {
$_SESSION['feedback'] .= "Unable to execute command to create the Report - contact Operations with this error.<br>";
$_SESSION['feedback'] .= $ssh2->getLog();
} else {
$_SESSION['feedback'] .= "Report successfully created for ID " . $parm2 . ".<br>";
//get the full name of the file created
$cmd_string = "sleep 15";
$ssh2->exec($cmd_string);
$cmd_string = "ls /root/Report-" . $parm1 . "-" . $parm2 . "-" . $date . "*";
$error = $ssh2->exec($cmd_string);
if (empty($error)) {
$_SESSION['feedback'] .= "Unable to execute command to obtain report name - contact Operations with this error.<br>";
$_SESSION['feedback'] .= $ssh2->getLog();
} else {
$filename = $ssh2->exec($cmd_string);
$filename = substr($filename, 6, strlen($filename));
$_SESSION['feedback'].= "The file name created is " . $filename . "<br>";
//verify that the filename is valid
if (substr($filename,0,7)=="Report-") {
//mail the attachment to the emailaddr
$cmd_string = "echo 'Requested Report attached.' | mail -s '" . $filename . "' -a '/root/" . $filename . "' " . $emailaddr . "\n";
$error = $ssh2->exec($cmd_string);
if ($error) {
$_SESSION['feedback'] .= "Unable to successfully email the requested report - contact Operations with this error.<br>";
$_SESSION['feedback'] .= $ssh2->getLog();
} else {
$_SESSION['feedback'] .= "Report successfully emailed to " . $emailaddr . ". Process complete.<br>";
$_SESSION['feedback'] .= $ssh2->getLog();
}
} else {
$_SESSION['feedback'] .= "Unable to email attachment as filename is invalid - contact Operations with this error.<br>";
$_SESSION['feedback'] .= $ssh2->getLog();
}
}
}
} else {
$_SESSION['feedback'] .= "Connection and authentication failed to " . LINUX_SVR . ".<br>";
}
//disconnect when done
$ssh2->reset();
$ssh2->disconnect();
}

PHP LFTP data mirror output

I'm using a Linux local computer and need to backup/mirror some very large file structures regularly. I only have access to SFTP.
I was after a simple one click solution. I originally tried to write the little script in BASH but I've never used it before and am not up to scratch with the syntax so I resorted to PHP. (I do understand PHP is not designed for this kind of work, but I'm on a tight time scale and don't have the time to get into BASH atm)
<?php
//init
parse_str(implode('&', array_slice($argv, 1)), $_GET);
$error = array();
$lPrefix = '/home/hozza/Sites/';
$archiveLocation = '/home/hozza/Backups/';
$lDir = isset($_GET['l']) ? $_GET['l'] : $error[] = 'Local Directory Required';
$rDir = isset($_GET['r']) ? $_GET['r'] : $error[] = 'Remote Directory Required';
$bookmark = isset($_GET['b']) ? $_GET['b'] : $error[] = 'lftp Bookmark Required';
//Check for args
if(count($error) == 0) {
$archiveName = end(explode('/', $lDir)) . '_' . date('Y-m-d_H-i');
//Validate local dir
if(is_dir($lPrefix . $lDir)) {
//preserve Sublime Text 2 config SFTP files
$ST2_SFTP_conf = false;
if(file_exists($lPrefix . $lDir . '/sftp-config.json')) {
$ST2_SFTP_conf = file_get_contents($lPrefix . $lDir . '/sftp-config.json');
unlink($lPrefix . $lDir . '/sftp-config.json');
}
//Start mirror
$lftOutput = explode("\n", shell_exec('lftp -e "mirror -e -p --parallel=10 --log=' . $archiveLocation . 'logs/' . $archiveName . '.txt ' . $rDir . '/ ' . $lPrefix . $lDir . '/; exit top" ' . $bookmark));
//Tar regardless of lftp error or success
$tarOutput = shell_exec('cd ' . $lPrefix . ' && tar -czf ' . $archiveLocation . $archiveName . '.tar.gz ' . $lDir);
//Output completion or errors
shell_exec('notify-send -i gnome-network-properties -t 0 "Mirror & Archive Complete" "' . $archiveName . '\n\n' . implode('\n', $lftOutput) . $tarOutput . '"');
//put back ST2 SFTP conf
if($ST2_SFTP_conf != false) file_put_contents($lPrefix . $lDir . '/sftp-config.json', $ST2_SFTP_conf);
exit;
}
else shell_exec('notify-send -i error -t 0 "Mirror & Archive Error" "' . date('Y-m-d') . ' ' . date('H-i') . '\n' . $lDir . ' \n Does not exist! D:"');
}
else shell_exec('notify-send -i error -t 0 "Mirror & Archive Error" "' . date('Y-m-d') . ' ' . date('H-i') . '\n' . implode('\n', $error) . '"');
?>
It can be run for many sites via a short-cut like so...
terminator -T "Mirror & Archive" -e "php ~/Programs/mirror.php l=local-dir_path r=./ b=lftp-bookmark-name"
If no password is in the LFTP bookmark (there shouldn’t be as it's stored in plain text) the terminal prompts for a password, after the script has run, a nice notification is given with some info about files/folders/speed etc.
However, when the script is running in a terminal, only the "input password" bit is output to the terminal, I would like all the output displayed in the terminal (normally that would display what file/folder is currently working with etc.)
Anyone know how to do that?
IIRC the reason that you see the password prompt output to the terminal is that it is using stderr. You could try redirecting stdout to stderr for your commands which should show you the 'real-time' progress. Tack this on to the end of the shell_exec() command: 1>&2
ie:
shell_exec('lftp -e "mirror -e -p --parallel=10 --log=' . $archiveLocation . 'logs/' . $archiveName . '.txt ' . $rDir . '/ ' . $lPrefix . $lDir . '/; exit top" ' . $bookmark . ' 1>&2')
However, this will preclude you from having anything returned by shell_exec for logging purposes. What I would suggest is something like:
$log_stem = '/tmp/' . time() . '_'; // ie: /tmp/1357581737_
$lfOutfile = $log_stem . 'lftp.log';
$tarOutfile = $log_stem . 'tar.log';
shell_exec('lftp -blah | tee ' . $lfOutfile ' 1>&2' );
shell_exec('tar -blah | tee ' . $tarOutfile ' 1>&2' );
$lfOut = file_get_contents($lfOutfile);
$tarOut = file_get_contetns(tarOutfile);
// remove tmp files
unlink($lfOutfile);
unlink($tarOutfile);
Which will capture a copy of the output to a file before redirecting the output to stderr so you can watch it live.
However, if you want to run this via cron I would recommend against writing anything to stderr that is not an error, otherwise cron will send a warning email every time it is run.
I think the last answer was close:
Either this:
shell_exec('lftp -blah |& tee ' . $lfOutfile );
shell_exec('tar -blah |& tee ' . $tarOutfile );
Or if that still doesn't work try this:
shell_exec('lftp -blah 2>&1 | tee ' . $lfOutfile );
shell_exec('tar -blah 2>&1 | tee ' . $tarOutfile );

Categories