2009-08-10 93 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命令文件格式非常簡單,並且以換行符終止,不允許在值內轉義,所以我需要做的就是防止換行符通過,這是我不允許的。