How can I touch a file as sudo when using [Symfony's Filesystem][1]?
So far I have:
$fs = new Filesystem();
$confFile = sprintf('/etc/apache2/sites-available/%s.conf', $input->getArgument('name'));
$fs->touch($confFile);
But this code fails with error: Permission denied.
[1]: http://symfony.com/doc/current/components/filesystem/introduction.html
From the Symfony Filesystem component:
public function touch($files, $time = null, $atime = null)
{
foreach ($this->toIterator($files) as $file) {
$touch = $time ? #touch($file, $time, $atime) : #touch($file);
if (true !== $touch) {
throw new IOException(sprintf('Failed to touch "%s".', $file), 0, null, $file);
}
}
}
As you see there, the touch() method is just a simple wrapper around PHP's buildin touch() function. If you need to run touch with elevated rights via sudo, you have to call it directly:
shell_exec('sudo touch ' . escapeshellarg($file));
you need to change the rights on /etc/apache2/sites-available/ to add write access to apache user
HTTPDUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1`
sudo chmod +a "$HTTPDUSER allow delete,write,append,file_inherit,directory_inherit" /etc/apache2/sites-available/
Related
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);
I have inherited a magento site and the cron schedule does not work. It was set in magento with */5**** and the same in cpanel. I installed AOE Scheduler and all the emails that had been stuck in the queue came through but now I just get a message "Last heartbeat is older than XX". If I run the scheduled tasks manually the emails come through but I get a "405 Error - Not Allowed" page and I find all my file permissions have been changed to 666 (the number of the beast). I have been setting my file permissions to d - 755 and f - 644 but depending on which forum you read this could be wrong. Please help, I have been on this for days.
This is my cron.php
<?php
// Change current directory to the directory of current script
chdir(dirname(__FILE__));
require 'app/Mage.php';
if (!Mage::isInstalled()) {
echo "Application is not installed yet, please complete install wizard first.";
exit;
}
// Only for urls
// Don't remove this
$_SERVER['SCRIPT_NAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_NAME']);
$_SERVER['SCRIPT_FILENAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_FILENAME']);
Mage::app('admin')->setUseSessionInUrl(false);
umask(0);
$disabledFuncs = explode(',', ini_get('disable_functions'));
$isShellDisabled = is_array($disabledFuncs) ? in_array('shell_exec', $disabledFuncs) : true;
$isShellDisabled = (stripos(PHP_OS, 'win') === false) ? $isShellDisabled : true;
try {
if (stripos(PHP_OS, 'win') === false) {
$options = getopt('m::');
if (isset($options['m'])) {
if ($options['m'] == 'always') {
$cronMode = 'always';
} elseif ($options['m'] == 'default') {
$cronMode = 'default';
} else {
Mage::throwException('Unrecognized cron mode was defined');
}
} else if (!$isShellDisabled) {
$fileName = basename(__FILE__);
$baseDir = dirname(__FILE__);
shell_exec("/bin/sh $baseDir/cron.sh $fileName -mdefault 1 > /dev/null 2>&1 &");
shell_exec("/bin/sh $baseDir/cron.sh $fileName -malways 1 > /dev/null 2>&1 &");
exit;
}
}
Mage::getConfig()->init()->loadEventObservers('crontab');
Mage::app()->addEventArea('crontab');
if ($isShellDisabled) {
Mage::dispatchEvent('always');
Mage::dispatchEvent('default');
} else {
Mage::dispatchEvent($cronMode);
}
} catch (Exception $e) {
Mage::printException($e);
exit(1);
}
This is my cron.sh
#!/bin/sh
# location of the php binary
if [ ! "$1" = "" ] ; then
CRONSCRIPT=$1
else
CRONSCRIPT=cron.php
fi
MODE=""
if [ ! "$2" = "" ] ; then
MODE=" $2"
fi
PHP_BIN=`which php`
# absolute path to magento installation
INSTALLDIR=`echo $0 | sed 's/cron\.sh//g'`
# prepend the intallation path if not given an absolute path
if [ "$INSTALLDIR" != "" -a "`expr index $CRONSCRIPT /`" != "1" ];then
if ! ps auxwww | grep "$INSTALLDIR$CRONSCRIPT$MODE" | grep -v grep 1>/dev/null 2>/dev/null ; then
$PHP_BIN $INSTALLDIR$CRONSCRIPT$MODE &
fi
else
if ! ps auxwww | grep "$CRONSCRIPT$MODE" | grep -v grep | grep -v cron.sh 1>/dev/null 2>/dev/null ; then
$PHP_BIN $CRONSCRIPT$MODE &
fi
fi
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
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.
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 {} +';