Replacing mysql_* functions with PDO and prepared statements

后端 未结 4 1616
抹茶落季
抹茶落季 2020-11-27 19:59

I\'ve always done the simple connection of mysql_connect, mysql_pconnect:

$db = mysql_pconnect(\'*host*\', \'*user*\', \'*pass*\');         


        
4条回答
  •  离开以前
    2020-11-27 20:15

    Yes, :something is a named placeholder in PDO, ? is an anonymous placeholder. They allow you to either bind values one by one or all at once.

    So, basically that makes four options to provide your query with values.

    One by one with bindValue()

    This binds a concrete value to your placeholder as soon as you call it. You may even bind hard coded strings like bindValue(':something', 'foo') if desired.

    Providing a parameter type is optional (but suggested). However, since the default is PDO::PARAM_STR, you only need to specify it when it is not a string. Also, PDO will take care of the length here - there is no length parameter.

    $sql = '
      SELECT *
      FROM `users`
      WHERE
        `name` LIKE :name
        AND `type` = :type
        AND `active` = :active
    ';
    $stm = $db->prepare($sql);
    
    $stm->bindValue(':name', $_GET['name']); // PDO::PARAM_STR is the default and can be omitted.
    $stm->bindValue(':type', 'admin'); // This is not possible with bindParam().
    $stm->bindValue(':active', 1, PDO::PARAM_INT);
    
    $stm->execute();
    ...
    

    I usually prefer this approach. I find it the cleanest and most flexible.

    One by one with bindParam()

    A variable is bound to your placeholder that will be read when the query is executed, NOT when bindParam() is called. That may or may not be what you want. It comes in handy when you want to repeatedly execute your query with different values.

    $sql = 'SELECT * FROM `users` WHERE `id` = :id';
    $stm = $db->prepare($sql);
    $id = 0;
    $stm->bindParam(':id', $id, PDO::PARAM_INT);
    
    $userids = array(2, 7, 8, 9, 10);
    foreach ($userids as $userid) {
      $id = $userid;
      $stm->execute();
      ...
    }
    

    You only prepare and bind once which safes CPU cycles. :)

    All at once with named placeholders

    You just drop in an array to execute(). Each key is a named placeholder in your query (see Bill Karwins answer). The order of the array is not important.

    On a side note: With this approach you cannot provide PDO with data type hints (PDO::PARAM_INT etc.). AFAIK, PDO tries to guess.

    All at once with anonymous placeholders

    You also drop in an array to execute(), but it is numerically indexed (has no string keys). The values will replace your anonymous placeholders one by one in the order they appear in your query/array - first array value replaces first placeholder and so forth. See erm410's answer.

    As with the array and named placeholders, you cannot provide data type hints.

    What they have in common

    • All of those require you to bind/provide as much values as you have placeholders. If you bind too many/few, PDO will eat your children.
    • You don't have to take care about escaping, PDO handles that. Prepared PDO statements are SQL injection safe by design. However, that's not true for exec() and query() - you should generally only use those two for hardcoded queries.

    Also be aware that PDO throws exceptions. Those could reveal potentially sensitive information to the user. You should at least put your initial PDO setup in a try/catch block!

    If you don't want it to throw Exceptions later on, you can set the error mode to warning.

    try {
      $db = new PDO(...);
      $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING)
    } catch (PDOException $e) {
      echo 'Oops, something went wrong with the database connection.';
    }
    

提交回复
热议问题