2011-02-24 85 views
10

有一些我不完全理解它是在mysqli preparequeryMySQLi:查询VS准备

这一个是用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(); 
     } 
    } 

这是一个有准备绑定 - 执行具有更好的安全性我认为,

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(); 
    } 

然而,无论是这两种方法的返回相同的结果,

$mysqli = new database(DB_HOST,DB_USER,DB_PASS,DB_NAME); 

$sql = " 
SELECT * 
FROM root_contacts_cfm 
ORDER BY cnt_id DESC 
"; 
print_r($mysqli->fetch_assoc_stmt($sql)); 

print_r($mysqli->fetch_assoc($sql)); 

他们打印:

Array 
(
    [cnt_id] => 2 
    [cnt_email1] => [email protected] 
    [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] => [email protected] 
    [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_assoc_stmt里面的方法我不使用fetch_assoc可言。可能根本没有机会使用prepare使用不同的方式返回结果。

所以,我的问题是因为使用prepare好于query,为什么要存在fetch_assoc?我们不应该忘记它,或不应该php.net已弃用? fetch_all也是一样 - 我们为什么要把它放在第一位!

谢谢。

回答

21

当您使用参数动态生成查询时,Prepared语句优于普通SQL查询。在你的例子中,你的SQL不包含任何变量,所以使用普通查询或准备语句在功能上是等效的。

当你必须改变参数的值,则WHERE子句中,例如,然后准备语句会给你增加安全性:

... 
WHERE col1 = ? AND col2 = ? 

但是当你的查询简单,固定的,它可能需要较少代码使用$mysqli->query($sql)以及fetch_assoc()。使用直接查询而不是准备好的语句并不是普遍不好的做法,因为有些人可能会相信。当您的查询需要参数化时,或者必须重复编译和执行相同的查询时,您才能从准备好的语句中受益。

+0

相当能说明问题。 – 2011-02-24 18:15:50

+0

谢谢。它是有道理的... – laukok 2011-02-24 19:05:57

+0

应该指出,虽然准备好的语句确实处理重复的查询,但它们也提供了出众的注入保护,所以即使在我不需要重复查询时也可以使用它们。 – meteorainer 2011-05-18 02:35:45

0

对不起,这不是一个答案,但我不够好,实际上留下评论。

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

while($stmt->fetch()) { 

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

} 

然后函数应该结束:

return $return_array;