【问题标题】:How important is it really to check every array index in PHP?检查 PHP 中的每个数组索引到底有多重要?
【发布时间】:2011-02-15 16:59:03
【问题描述】:

我正在做一个相当大的项目,其中有很多地方存在如下代码:

function foo($a, $b, $c, $d, $e, $f) {
    $clean = array();
    $mysql = array();

    $clean['a'] = htmlentities($a);
    $clean['b'] = htmlentities($b);
    $clean['c'] = htmlentities($c);
    $clean['d'] = htmlentities($d);
    //...

    $mysql['a'] = mysql_real_escape_string($clean['a']);
    $mysql['b'] = mysql_real_escape_string($clean['b']);
    $mysql['c'] = mysql_real_escape_string($clean['c']);
    $mysql['d'] = mysql_real_escape_string($clean['d']);
    //...

    //construct and execute an SQL query using the data in $mysql
    $query = "INSERT INTO a_table
              SET a='{$mysql['a']}',
                  b='{$mysql['b']}',
                  c='{$mysql['c']}',
                  d='{$mysql['d']}'";
}

显然,这会在 PHP 中针对未定义的索引引发大量警告。

真的需要重写代码如下吗?

function foo($a, $b, $c, $d, $e, $f) {
    $clean = array();
    $mysql = array();

    $clean['a'] = htmlentities($a);
    $clean['b'] = htmlentities($b);
    $clean['c'] = htmlentities($c);
    $clean['d'] = htmlentities($d);
    //...

    $mysql['a'] = (isset($clean['a'])) ? mysql_real_escape_string($clean['a']) : mysql_real_escape_string($a);
    $mysql['b'] = (isset($clean['b'])) ? mysql_real_escape_string($clean['b']) : mysql_real_escape_string($b);
    $mysql['c'] = (isset($clean['c'])) ? mysql_real_escape_string($clean['c']) : mysql_real_escape_string($c);
    $mysql['d'] = (isset($clean['d'])) ? mysql_real_escape_string($clean['d']) : mysql_real_escape_string($d);
    //...

    //construct and execute an SQL query using the data in $mysql
    if (isset($mysql['a']) and isset($mysql['b']) and isset($mysql['c']) and isset($mysql['d'])) {
        $query = "INSERT INTO a_table
                  SET a='{$mysql['a']}',
                      b='{$mysql['b']}',
                      c='{$mysql['c']}',
                      d='{$mysql['d']}'";
    }

}

【问题讨论】:

  • 好吧,如果你真的设置了每个$clean['something'],那么你应该不会收到通知。顺便说一句,你有很多重复。考虑使用循环或array_map:php.net/manual/en/function.array-map.php

标签: php validation isset correctness


【解决方案1】:

如果你使用,你可以大大简化你的功能:

function foo($a, $b, $c, $d, $e, $f) {

    $args = func_get_args();   // or build an array() manually

    $args = array_map("htmlentities", $args);
    $args = array_map("mysql_real_escape_string", $args);

    list($a, $b, $c, $d, $e, $f) = $args;

在显示位置的 isset() 检查似乎完全没用。变量已定义。

【讨论】:

  • 鉴于检查似乎毫无意义,将检查排除在外会带来哪些风险?添加这些检查的唯一原因似乎是为了防止 PHP 发出不必要的警告 - 或者这更像是一种以错误方式做事的情况?
  • @Jon:从表面上看:htmlentities() 调用应该是可选的。因此,issets() 不是为了防止通知/警告,而是作为对正确数据源的后备。恕我直言,实际问题似乎是数据保存在不同的变量中,无论如何都是在链中处理的。
【解决方案2】:

有必要有这样一个硬编码的功能吗?

我用这个:

function insert_array($table, $data) {  
    $cols = '(';
    $values = '(';
    foreach ($data as $key=>$value) { 
        $value = mysql_real_escape_string($value);
        $cols .= "$key,";  
        $values .= "'$value',";  
    }
    $cols = rtrim($cols, ',').')';
    $values = rtrim($values, ',').')';  
    $sql = "INSERT INTO $table $cols VALUES $values";
    mysql_query($sql) or die(mysql_error());
}

然后插入数据不管其名称和列使用:

$data = array('id' => 1, 'name' => 'Bob', 'url' => 'foo.com');
insert_array('users', $data);

【讨论】:

  • 有用的想法,但在这种情况下不是——为了简单起见,我删除了我们通常做的额外数据操作。并且所有函数参数不一定与表列匹配。
【解决方案3】:

是的,如果数组索引或变量不存在 php 给出警告/通知。

正确的方法是在使用 isset() 函数之前检查每个变量。

最好在使用前检查它们。

【讨论】:

  • 不适用于这种情况,所有$a,$b,$c,$d都是定义的函数参数
【解决方案4】:

您需要检查可能存在或不存在的索引。但是,您的代码非常混乱,您的真实代码看起来可能完全不同。在这个示例代码中,密钥显然是存在的,只是您自己创建的。

  1. 在您的示例中,您可以将 mysql_real_escape_string 部分移动到您检查变量的 if 中,那么您已经知道它们存在。

  2. 这里没有理由使用数组,你可以将它们存储在同一个变量中。

  3. XSS-Protection(htmltentities(),注意这还不够)应该在显示数据之前完成,而不是在你的示例中存储之前完成。只有一个原因是你最终会得到多次编码/转义的东西。恶意 HTML/JS 不会对您的数据库造成损害。

【讨论】:

    【解决方案5】:

    如果您的项目非常大,那么未定义的索引可能会成为一场噩梦,尤其是当它们保存由用户输入生成的数据时,尤其是在没有良好的堆栈跟踪错误报告的情况下。这是因为在请求之间传递数据时,无法保证它是在其原始入口点设置的,因此您最终需要对 null 或空值进行大量冗余检查。

    您可能想检查您在此处尝试完成的任务是否不能通过将此功能转换为对象来更好地实现。您用 $a $b 和 $c 表示的值可以很容易地变成对象属性,并且一个 save() 方法可以将状态保存到数据库中。

    除此之外,您还可以通过使用 foreach 循环更快、更连贯地执行检查。只需通过其键迭代数据并在循环体内执行真正的转义和 htmlentities。

    http://php.net/manual/en/control-structures.foreach.php

    我还建议将 HTMLPurifier 用于您的 XSS 过滤,因为通常 htmlentites 是不够的,尤其是对于接受将用户内容放置在 Web 应用程序中的公共表单。

    http://htmlpurifier.org/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-27
      • 2019-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-18
      • 2015-01-22
      • 2011-02-05
      相关资源
      最近更新 更多