我在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()来防止恶意数据。我怎样才能正确地逃避命令和参数以使其有效?我尝试了很多选择,但我做不到。
答案 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命令文件格式非常简单并且以换行符终止,不允许在值内转义,因此我需要做的就是阻止换行符,但我还是不允许这样做。