需要注意的是,使用 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 = 'bash 解释的字符串,空格:# & ; ` | * ? ~ < > ^ ( ) [ ] { } $ \ \x0A \xFF. \' " %'.PHP_EOL.
'bash 解释的字符串,无空格:#&;`|*?~<>^()[]{}$\\x0A\xFF.\'\"%'.PHP_EOL.
'bash 解释的字符串,以反斜杠开头:\# \& \; \` \| \* \? \~ \< \> \^ \( \) \[ \] \{ \} \$ \\\ \\\x0A \\\xFF. \\\' \" \%'.PHP_EOL.
'printf 代码:% \ (用于构成 %.0#-*+d,或 \\ \a \b \f \n \r \t \v \" \? \062 \0062 \x032 \u0032 和 \U00000032)';
echo "我们正在测试的字符串是:".PHP_EOL.$test.PHP_EOL;
$cmd = $test;
$cmd = str_replace(array('\\', '%'), array('\\\\', '%%'), $test);
$cmd = escapeshellarg($cmd);
echo PHP_EOL."这是使用给定转义机制的输出:".PHP_EOL;
echo `printf $cmd | cat`.PHP_EOL;
echo PHP_EOL."它们应该完全匹配".PHP_EOL;
?>