2009-08-10 135 views
2

我使用Linux上的Exiv2命令行工具来编辑图像元数据,像这样:由如何逃避PHP的exec()命令用引号

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()来防止恶意数据。我怎样才能正确地逃避命令和参数,使其工作?我尝试了很多选择,但我无法做到。

回答

4

是的,这是一个难题,因为该命令使用非标准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... 
+0

谢谢,这对于理解问题非常有帮助。看起来像exiv2通过允许exiv2命令(设计为写入文件)也可以作为shell参数写成快捷方式,从而获得了非标准shell参数。 – Liam 2009-08-11 11:44:27

+0

哦,我试过这个,并没有保留用户输入的双引号。单引号的荣誉虽然在我的输入中更为常见! – Liam 2009-08-11 11:52:16

0

什么?

要修改此使用excapeshellcmd():

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

因为Exiv2的非标准的shell参数的,这是不容易达到一个简单而强大的解决方案,以正确处理用户提供的报价。还有另一种解决方案可能更加可靠,易于维护,性能损失小。

写Exiv2的说明文件cmds.txt,然后调用:

exiv2 -m cmds.txt IMG.jpg 

从文件中读取指令。

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