需要注意的是,关于 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;
?>