關於 echo 的使用有一個需要注意的怪癖。如果您想要執行一個從 STDIN 接收輸入的命令,您通常會這樣做
<?php $output = shell_exec("echo $input | /the/command"); ?>
不幸的是,這是一個 *壞主意*,並且會使您的腳本無法移植,在某些系統上會產生很難追蹤的錯誤。根據伺服器的設定方式,/bin/sh 要嘛會呼叫 /bin/bash,要嘛會呼叫 /bin/dash,而這些的 echo 版本非常不同。永遠不要使用 echo;請改用 printf,它是穩定的。您要如何針對 printf 跳脫?這樣做
<?php
$input = '要*精確地*傳遞給命令的字串';
//只跳脫 PHP 解析器所需的內容;我們想要
//PHP 將資料儲存在緩衝區中的字串
//精確地傳遞到命令的 stdin 緩衝區。
$cmd = str_replace(array('\\', '%'), array('\\\\', '%%'), $input);
$cmd = escapeshellarg($cmd);
$output = shell_exec("printf $cmd | /path/to/command");
?>
對於偏執狂,這個嚴苛的測試驗證了 shell 跳脫和 printf 自己的跳脫都已正確處理。請安心使用!
<?php
$test = 'stuff bash interprets, space: # & ; ` | * ? ~ < > ^ ( ) [ ] { } $ \ \x0A \xFF. \' " %'.PHP_EOL.
'stuff bash interprets, no space: #&;`|*?~<>^()[]{}$\\x0A\xFF.\'\"%'.PHP_EOL.
'stuff bash interprets, with leading backslash: \# \& \; \` \| \* \? \~ \< \> \^ \( \) \[ \] \{ \} \$ \\\ \\\x0A \\\xFF. \\\' \" \%'.PHP_EOL.
'printf codes: % \ (used to form %.0#-*+d, or \\ \a \b \f \n \r \t \v \" \? \062 \0062 \x032 \u0032 and \U00000032)';
echo "These are the strings we are testing with:".PHP_EOL.$test.PHP_EOL;
$cmd = $test;
$cmd = str_replace(array('\\', '%'), array('\\\\', '%%'), $test);
$cmd = escapeshellarg($cmd);
echo PHP_EOL."This is the output using the escaping mechanism given:".PHP_EOL;
echo `printf $cmd | cat`.PHP_EOL;
echo PHP_EOL."They should match exactly".PHP_EOL;
?>