sed不适用于PHP exec函数

时间:2010-01-12 12:47:24

标签: php sed

echo "sed -i 's/NULL/\\N/g' ".$_REQUEST['para'].".sql";

以上陈述有效。但是当我在这样的执行官中使用它时失败了......

exec("sed -i 's/NULL//\/\/\N/g' ".$_REQUEST['para'].".sql");

3 个答案:

答案 0 :(得分:5)

你应该使用反斜杠来逃避反斜杠,而不是使用正斜杠,如下所示:

exec("sed -i 's/NULL/\\\\N/g' ".$_REQUEST['para'].".sql");

编辑我写的答案没有看代码实际上做了什么。不要这样做,因为$_REQUEST['para']可以是用户想要的任何内容,可以用于code injection。正如另一个答案所示,使用PHP函数。

答案 1 :(得分:3)

虽然这完全取决于你,但我的建议是不要不必要地调用系统命令。在PHP中,您可以使用preg_replace()来执行sed。

的功能
preg_replace("/NULL/","\\N",file_get_contents("$_REQUEST['para']"."sql") )

答案 2 :(得分:1)

基于ghostdog的想法,这里的代码实际上会做你想要的(他发布的原始代码实际上没有读取文件的内容):

//basename protects against directory traversal
//ideally we should also do a is_writable() check   
$file = basename($_REQUEST['para'].".sql");
$text = file_get_contents($file); 
$text = str_replace('NULL', '\\N', $text); //no need for a regex
file_put_contents($file, $text);

然而,诚然,如果有问题的文件超过几兆,这是不可取的,因为整个文件将被读入内存。你可以用块读取它,但这会变得更复杂:

$file = basename($_REQUEST['para'].".sql");
$tmpFile = tempnam("/tmp", "FOO");
$in = fopen($file, 'r');
$tmp = fopen($tmpFile, 'w');
while($line = fgets($in)) {
  $line = str_replace('NULL', '\\N', $line);
  fputs($tmp, $line);
}
fclose($tmp);
fclose($in);
rename($tmpFile, $file);

如果文件是100+ meg,老实说,像你一样直接调用sed会更快。当谈到大文件时,尝试使用其等效的PHP重现像sed / grep这样的工具的开销是不值得的。但是,如果您打算这样做,至少需要采取一些措施来保护自己:

采取一些基本步骤来保护amnom的代码:

$file = basename($_REQUEST['para'].".sql");
if(!is_writable($file))
  throw new Exception('bad filename');
exec("sed -i 's/NULL/\\\\N/g' ".escapeshellarg($file));
  1. 首先,我们调用basename,它 从我们的文件名中删除任何路径 (例如,如果攻击者提交了 字符串'/ etc / passwd',我们至少 现在将它们限制在文件中 'passwd'在当前的工作中 目录
  2. 接下来,我们确保文件位于 事实上,可写。如果没有,我们 不应继续
  3. 最后,我们在文件上转义了hellarg()。如果不这样做,则允许任意命令执行。例如,如果攻击者提交了字符串/etc/passwd; rm -rf /; #,您最终会得到命令sed 's/blah/blah/' /etc/passwd; rm -rf /; #.sql。应该清楚的是,虽然这个确切的命令可能不起作用,但找到一个实际上是微不足道的命令。