Php MySQLi:查询VS准备

Php MySQLi:查询VS准备,php,data-binding,mysqli,fetch,Php,Data Binding,Mysqli,Fetch,在mysqli中,有一点我不太理解,那就是prepare和query 这一个正在使用mysqli::query来处理查询,并且已知它缺乏安全性: public function fetch_assoc($query) { $result = parent::query($query); //$result = self::preparedStatement($query); if($result) {

在mysqli中,有一点我不太理解,那就是
prepare
query

这一个正在使用
mysqli::query
来处理查询,并且已知它缺乏安全性:

public function fetch_assoc($query)
    {
        $result = parent::query($query);
        //$result = self::preparedStatement($query);
        if($result) 
        {
            return $result->fetch_assoc();
        } 
        else
        {
            # call the get_error function
            return self::get_error();
            # or:
            # return $this->get_error();
        }
    }
...
WHERE col1 = ? AND col2 = ?
这是一个具有prepare bind execute的,我认为它具有更好的安全性

public function fetch_assoc_stmt($sql,$types = null,$params = null)
    {
        # create a prepared statement
        $stmt = parent::prepare($sql);

        # bind parameters for markers
        # but this is not dynamic enough...
        //$stmt->bind_param("s", $parameter);

        if($types&&$params)
        {
            $bind_names[] = $types;
            for ($i=0; $i<count($params);$i++) 
            {
                $bind_name = 'bind' . $i;
                $$bind_name = $params[$i];
                $bind_names[] = &$$bind_name;
            }
            $return = call_user_func_array(array($stmt,'bind_param'),$bind_names);
        }

        # execute query 
        $stmt->execute();

        # these lines of code below return one dimentional array, similar to mysqli::fetch_assoc()
        $meta = $stmt->result_metadata(); 

        while ($field = $meta->fetch_field()) { 
            $var = $field->name; 
            $$var = null; 
            $parameters[$field->name] = &$$var; 
        }

        call_user_func_array(array($stmt, 'bind_result'), $parameters); 

        while($stmt->fetch()) 
        { 
            return $parameters;  
        }

        # close statement
        $stmt->close();
    }
他们打印了这张照片:

Array
(
    [cnt_id] => 2
    [cnt_email1] => lau@xx.net
    [cnt_email2] => 
    [cnt_fullname] => Lau T
    [cnt_firstname] => Thiam
    [cnt_lastname] => Lau
    [cnt_organisation] => 
    [cnt_website] => 
    [cnt_biography] => 
    [cnt_gender] => 
    [cnt_birthday] => 
    [cnt_address] => 
    [cnt_postcode] => 
    [cnt_telephone] => 
    [cnt_note] => 
    [cnt_key] => 
    [cat_id] => 
    [tcc_id] => 
    [cnt_suspended] => 0
    [cnt_created] => 2011-02-04 00:00:00
    [cnt_updated] => 2011-02-04 13:54:36
)
Array
(
    [cnt_id] => 2
    [cnt_email1] => lau@xx.net
    [cnt_email2] => 
    [cnt_fullname] => Lau T
    [cnt_firstname] => Thiam
    [cnt_lastname] => Lau
    [cnt_organisation] => 
    [cnt_website] => 
    [cnt_biography] => 
    [cnt_gender] => 
    [cnt_birthday] => 
    [cnt_address] => 
    [cnt_postcode] => 
    [cnt_telephone] => 
    [cnt_note] => 
    [cnt_key] => 
    [cat_id] => 
    [tcc_id] => 
    [cnt_suspended] => 0
    [cnt_created] => 2011-02-04 00:00:00
    [cnt_updated] => 2011-02-04 13:54:36
)
您应该注意到,在
fetch\u assoc\u stmt
方法中,我根本没有使用
fetch\u assoc
。可能根本不可能使用它,因为
prepare
使用不同的方法返回结果

所以,我的问题是,既然使用
prepare
query
好,那么
fetch\u assoc
为什么要存在呢?难道我们不应该忘记它,或者php.net不应该弃用它吗??这与
fetch_all
是一样的-为什么我们首先要有它


谢谢。

当您使用参数动态生成查询时,准备好的语句比普通SQL查询更可取。在您的示例中,SQL不包含变量,因此使用普通查询或预处理语句在功能上是等效的

当您必须更改参数值时,例如在
WHERE
子句中,准备好的语句将为您提供额外的安全性:

public function fetch_assoc($query)
    {
        $result = parent::query($query);
        //$result = self::preparedStatement($query);
        if($result) 
        {
            return $result->fetch_assoc();
        } 
        else
        {
            # call the get_error function
            return self::get_error();
            # or:
            # return $this->get_error();
        }
    }
...
WHERE col1 = ? AND col2 = ?

但是,当您的查询简单且固定时,使用
$mysqli->query($sql)
以及
fetch\u assoc()
可能需要更少的代码。使用直接查询而不是预先准备好的语句并不是一种普遍的坏习惯,正如一些人可能认为的那样。当您的查询需要参数化时,或者当同一查询必须反复编译和执行时,您将从准备好的语句中获益。

很抱歉,这不是一个答案,但我没有足够好的能力来真正留下评论

看起来您的第二个函数中有一个bug。对于返回多行的查询,您的代码无法正常工作。返回语句不应该是:

while($stmt->fetch()) {

    //to dereference
    $row_copy = $parameters;
    $return_array[] = $row_copy;

}
然后函数应以以下内容结束:

return $return_array;

需要注意的是,虽然准备好的语句确实可以处理重复的查询,但它们也提供了非常好的注入保护,所以即使我不需要重复查询,我也会使用它们。准备好的语句是否比:real_escape_string?提供了更好的安全性?@StevenByrne我不能说它们本质上比正确使用的转义更安全(取决于数据库驱动程序和一些其他配置因素)但是预处理语句强制您确保变量已经参数化,而您很容易忘记调用字符串转义函数,或者不小心重构代码以禁用它等等。另请参见-特别是如果正在进行预处理语句仿真,则语句并不是真的更安全,但是如果数据库本身正在进行参数化r代换