Within a PHP environment I am trying to execute sift (a grep-like program) to return filenames if either of the two strings matches.
// To return filenames having either string1 OR string2.
<?php
$cmd='sift.exe -l --blocksize=5000000 -Q string1^|string2 dir';
exec ($cmd);
?>
I am guessing I am unable to pass the OR operator (^|) correctly.
For matching a single string it works fine:
// To return filenames having string1
<?php
$cmd='sift.exe -l --blocksize=5000000 -Q string1 dir';
exec ($cmd);
?>
Any advice please?
The pipe symbol is being interpreted by the shell that executes your command. You either need to escape the pipe symbol, or quote the pattern argument.
Here are two solutions that work:
$cmd='sift.exe -l --blocksize=5000000 -Q string1^\|string2 dir';
$cmd="sift.exe -l --blocksize=5000000 -Q 'string1^|string2' dir";
As Bill Karwin pointed out you have to escape some characters in your command.
PHP has escapeshellcmd function to take care of that, so you code should look like:
$cmd = 'sift.exe -l --blocksize=5000000 -Q string1^|string2 dir';
$escapedCommand = escapeshellcmd($cmd);
exec ($escapedCommand);
Optionally you can use escapeshellarg function.
Look at this question to see what characters need to be escaped.
Related
I use the Exiv2 command line tool on Linux to edit image metadata like so:
exiv2 -M"set Iptc.Application2.Caption String This is my caption....." modify IMG.jpg
I want to execute this from PHP, using a caption provide by a user. This will work if the user enters no special characters:
exec('/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String '.$caption.'" modify IMG.jpg');
I need to allow the user special characters such as single and double quotes. I would like to use escapeshellcmd() to prevent malicious data. How can I correctly escape the command and the argument so that it works? I have tried many options but I can't get it right.
Yes, this is a hard problem, because the command is using non-standard shell arguments (like it's own little meta-language). ImageMagick has the same issues.
If you simply use escapeshellarg() within a double-quoted string, it is rendered useless. escapeshellcmd() does escape all special characters, and is safe for use in a double-quoted string. So you need to hard code single quotes around it to make it work right.
exec('/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String \'' . escapeshellcmd($caption) . '\'" modify IMG.jpg');
The reason escapeshellarg() will not work in a single quoted string is:
# for this input:
The smith's "; rm -rf *; echo "went to town
# after escapeshellarg()
'The smith\'s "; rm -rf *; echo "went to town'
# Works fine if left as a top-level argument
/usr/bin/command 'The smith\'s "; rm -rf *; echo "went to town'
# BUT if put in a double-quoted string:
/usr/bin/command "subcommand1 'The smith\'s "; rm -rf *; echo "went to town'"
# it is broken into 3 shell commands:
/usr/bin/command "something and 'The smith\'s ";
rm -rf *;
echo "went to town'"
# bad day...
What about using heredoc?
$str = <<<'EOD'
/usr/local/bin/exiv2 -M "set Iptc.Application2.Caption String $options" modify IMG.jpg
EOD;
exec($str);
To modify this to use excapeshellcmd():
$options = excapeshellcmd($caption);
$command = <<<'EOD'
/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String $options" modify IMG.jpg
EOD;
exec($command);
Because of Exiv2's non-standard shell arguments, it is not easy to reach a simple and robust solution to handle user-supplied quotes correctly. There is another solution that is likely to be far more reliable and easy to maintain with a small performance penalty.
Write the Exiv2 instructions to a file cmds.txt, then call:
exiv2 -m cmds.txt IMG.jpg
to read the instructions from the file.
Update: I have implemented this method and it requires no escaping of the user-supplied data. This data is written directly to a text file which is read in by Exiv2. The Exiv2 command file format is very simple and newline-terminated, allow no escaping within values, so all I need to do is prevent newlines from passing through, which I was not allowing anyway.
I have a fairly simple problem I just cannot seem to find a solution. I want to delete a line containing a certain string in all the files in a directory on my website. This string contains double quotes though. I have been trying to find a solution using backslashing but its does not work.
The string I want to replace is:session_register("c$key");
I'm using this php and unix code:
$command = "sed -i '/session_register(\"c$key\")/d;' ./*";
$output = shell_exec($command);
I want to delete this line because session_register is outdated.
It does not do anything but does not give me an error. What is the problem or how should I backslash?
Thanks a lot!
You need to double escape $ as well since $ is special regex symbol means end of input. Also use single quote instead of double for your $command string assignment.
Try this:
$command = 'sed -i.bak \'/session_register("c\\$key")/d;\' ./*';
$output = shell_exec($command);
Can anyone explain how to make this code work?
exec("ffmpeg -f concat -i <(printf "file '%s'\n" ./*.mp4) -c copy output.mp4");
I've tried to add '\' before " and ', it still didn't work.
Appreciate any help. Thanks!
You must escape double quotes and backslashes. You can do it using backslash: \
exec("ffmpeg -f concat -i <(printf \"file '%s'\\n\" ./*.mp4) -c copy output.mp4");
i know this question is super old but i had the same problem myself and couldn't find the answer anywhere
in case you are having this error on windows, to escape the special characters you have to use ^ instead of backslash
so stuff like
exec("some_application https://example.com/api.php?arg1=1&arg2=2")
won't work because of the & character, so it must become
exec("some_application https://example.com/api.php?arg1=1^&arg2=2")
I've been calling more advanced shell commands from PHP recently using shell_exec
As my commands become more complicated, I keep experiencing errors with things not being escaped properly. I want to be able to call shell_exec('echo '.$variable) and no matter what I put in $variable it will just echo it. Some things $variable could include are $ ~ ' " \n \r \c `` ( ) { } ; \
What's the best way to escape a shell command before executing it?
Does escapeshellcmd or escapeshellarg not do what you want?
shell_exec('echo '. escapeshellarg($variable));
I have a PHP program that uses a Bash script to convert a pdf. However if the filename contains spaces it is not passed through the bash script correctly.
How do you escape filenames with spaces within a bash script? Do you have to do something special to quote the filename for the "OUTFILE" variable?
Bash script:
#!/bin/bash
INFILE=$1
OUTFILE=${INFILE%.*}
gs \
-q \
-dSAFER \
-dBATCH \
-dNOPAUSE \
-sDEVICE=png256 \
-r150x150 \
-sOutputFile=${OUTFILE}.png \
${INFILE}
PHP script:
echo "converting: ".$spool.$file . "\n";
system("/home/user/bin/pdf2png.sh " . escapeshellarg($spool . $file));
Edit: I removed the quotes around the escapeshellarg() variable. This however did not fix the problem. Which I think is in the Bash script OUTFILE variable.
In the last line of your shell script, put quotes around the variable reference:
"${INFILE}"
Considering your code, I would try by, first, removing the single-quotes you are inserting arround the parameter : those shouldn't be necessary, as you are using escapeshellarg.
For instance, the temp.php file might contain :
$spool = "ab cd/";
$file = "gh ij";
system("sh ./test.sh " . escapeshellarg($spool . $file) . "");
And the test.sh :
#!/bin/bash
INFILE=$1
echo $1
With those, the output is :
$ php temp.php
ab cd/gh ij
Which looks like what you expect.
If I put back the single-quotes, like this :
system("sh ./test.sh '" . escapeshellarg($spool . $file) . "'");
The output is broken again :
$ php temp.php
ab
escapeshellarg is escaping data for you (with the right quotes and all that, depending on the operating system), you don't have to do that yourself.
To escape a file name with spaces, just use .
My Tar Ball.tar
My\ Tar\ Ball.tar
So for what you have you will either need to make sure that your arguments contain the back slashes when the script is called, or you will need to add some input checking.
Take a look at escapeshellcmd() and escapeshellarg()