如何使用引号转义php exec()命令

时间:2009-08-10 16:36:44

标签: php escaping exec exiv2

我在Linux上使用Exiv2命令行工具来编辑图像元数据,如下所示:

exiv2 -M"set Iptc.Application2.Caption String This is my caption....." modify IMG.jpg

我想使用用户提供的标题从PHP执行此操作。如果用户没有输入任何特殊字符,这将有效:

exec('/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String '.$caption.'" modify IMG.jpg');

我需要允许用户使用特殊字符,例如单引号和双引号。我想使用escapeshellcmd()来防止恶意数据。我怎样才能正确地逃避命令和参数以使其有效?我尝试了很多选择,但我做不到。

3 个答案:

答案 0 :(得分:5)

是的,这是一个难题,因为该命令使用的是非标准的shell参数(就像它自己的小元语言一样)。 ImageMagick有同样的问题。

如果您只是在双引号字符串中使用escapeshellarg(),则它将变为无用。 escapeshellcmd()确实转义所有特殊字符,并且可以安全地用于双引号字符串。因此,您需要对其周围的单引号进行硬编码,以使其正常工作。

exec('/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String \'' . escapeshellcmd($caption) . '\'" modify IMG.jpg');

escapeshellarg()在单引号字符串中不起作用的原因是:

# 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...

答案 1 :(得分:0)

使用heredoc怎么样?

$str = <<<'EOD'
/usr/local/bin/exiv2 -M "set Iptc.Application2.Caption String $options" modify IMG.jpg
EOD;
exec($str);

要修改它以使用excapeshellcmd():

$options = excapeshellcmd($caption);
$command = <<<'EOD'
/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String $options" modify IMG.jpg
EOD;
exec($command);

答案 2 :(得分:0)

由于Exiv2的非标准shell参数,要获得正确处理用户提供的引号的简单而强大的解决方案并不容易。另一种解决方案可能更加可靠,易于维护,性能损失很小。

将Exiv2指令写入文件cmds.txt,然后调用:

exiv2 -m cmds.txt IMG.jpg

阅读文件中的说明。

更新:我已经实现了这种方法,它不需要转义用户提供的数据。此数据直接写入由Exiv2读入的文本文件。 Exiv2命令文件格式非常简单并且以换行符终止,不允许在值内转义,因此我需要做的就是阻止换行符,但我还是不允许这样做。