Maison  >  Article  >  base de données  >  Comment utiliser PDO pour interroger MySQL afin d'éviter l'injection SQL

Comment utiliser PDO pour interroger MySQL afin d'éviter l'injection SQL

jacklove
jackloveoriginal
2018-06-09 14:03:501643parcourir

Lors de l'utilisation des méthodes traditionnelles mysql_connect et mysql_query pour se connecter et interroger la base de données, si le filtrage n'est pas strict, il existe un risque d'injection SQL. Bien que la fonction mysql_real_escape_string() puisse être utilisée pour filtrer les valeurs soumises par l'utilisateur, elle présente également des défauts. En utilisant la méthode de préparation de l'extension PDO de PHP, vous pouvez éviter le risque d'injection SQL.

PDO (PHP Data Object) est une nouvelle fonctionnalité majeure ajoutée à PHP5, car avant PHP 5, php4/php3 disposait de nombreuses extensions de base de données pour se connecter et se connecter à chaque base de données Processing. , tel que php_mysql.dll. PHP6 utilisera également PDO pour se connecter par défaut, et l'extension mysql sera utilisée comme auxiliaire. Adresse officielle : http://php.net/manual/en/book.pdo.php

1. Configuration PDO

Avant d'utiliser l'extension PDO, vous devez d'abord activer cette extension. Dans php.ini, supprimez le ";" devant "extension=php_pdo.dll". pour supprimer le ";" devant l'extension de base de données liée à PDO ";" (généralement php_pdo_mysql.dll est utilisé), puis redémarrez le serveur Apache.

extension=php_pdo.dll 
extension=php_pdo_mysql.dll

2. PDO se connecte à la base de données MySQL

$dbh = new PDO("mysql:host=localhost;dbname=mydb","root","password");

La connexion par défaut n'est pas longue, si vous souhaitez utiliser une connexion longue à la base de données, vous pouvez ajouter les paramètres suivants à la fin :

$dbh = new PDO("mysql:host=localhost;dbname=mydb","root","password","array(PDO::ATTR_PERSISTENT => true) "); 
$dbh = null; //(释放)

3. Propriétés de réglage du PDO

PDO dispose de trois méthodes de gestion des erreurs :

PDO::ERrmODE_SILENT n'affiche pas les informations d'erreur, définit uniquement le code d'erreur

PDO ::ERrmODE_WARNING affiche une erreur d'avertissement

PDO::ERrmODE_EXCEPTION lève une exception

Vous pouvez utiliser l'instruction suivante pour définir la méthode de gestion des erreurs sur lancer une exception

$db->setAttribute(PDO::ATTR_ERrmODE, PDO::ERrmODE_EXCEPTION);

Étant donné que différentes bases de données gèrent différemment la casse des noms de champs renvoyés, PDO fournit l'élément de paramètre PDO::ATTR_CASE (y compris PDO::CASE_LOWER, PDO::CASE_NATURAL , PDO::CASE_UPPER) pour déterminer le nom du champ renvoyé en majuscules et en minuscules.

Spécifiez la valeur correspondante en php pour la valeur NULL renvoyée par la base de données en définissant le type PDO::ATTR_ORACLE_NULLS (y compris PDO::NULL_NATURAL, PDO::NULL_EmpTY_STRING, PDO::NULL_TO_STRING ).

4. Méthodes PDO courantes et leurs applications

PDO::query() est principalement utilisé pour les opérations d'enregistrement. qui renvoient des résultats, en particulier les opérations SELECT

PDO::exec() sont principalement destinés aux opérations qui ne renvoient pas de jeu de résultats, telles que INSERT, UPDATE et d'autres opérations

PDO::prepare() est principalement une opération de prétraitement. Vous devez utiliser $rs->execute() pour exécuter l'instruction SQL dans le prétraitement. Cette méthode peut lier des paramètres et est relativement puissante (. empêcher l'injection SQL Fiez-vous simplement à ceci)

PDO::lastInsertId() renvoie la dernière opération d'insertion, le type de colonne de clé primaire est le dernier ID d'auto-incrémentation

PDOStatement::fetch() est utilisé pour obtenir un enregistrement

PDOStatement::fetchAll() est utilisé pour obtenir tous les jeux d'enregistrements dans une collection

PDOStatement::fetchColumn() est un champ du premier enregistrement spécifié dans le résultat de la récupération. La valeur par défaut est le premier champ

PDOStatement::rowCount. () : principalement utilisé. Le jeu de résultats affecté par les opérations DELETE, INSERT et UPDATE sur PDO::query() et PDO::prepare() n'est pas valide pour la méthode PDO::exec() et l'opération SELECT.


5.Opération PDO Instance de base de données MYSQL

<?php 
$pdo = new PDO("mysql:host=localhost;dbname=mydb","root",""); 
if($pdo -> exec("insert into mytable(name,content) values(&#39;fdipzone&#39;,&#39;123456&#39;)")){ 
echo "insert success"; 
echo $pdo -> lastinsertid(); 
} 
?>
<?php 
$pdo = new PDO("mysql:host=localhost;dbname=mydb","root",""); 
$rs = $pdo -> query("select * from table"); 
$rs->setFetchMode(PDO::FETCH_ASSOC); //关联数组形式
//$rs->setFetchMode(PDO::FETCH_NUM); //数字索引数组形式
while($row = $rs -> fetch()){ 
    print_r($row); 
} 
?>
<?php
foreach( $db->query( "SELECT * FROM table" ) as $row )
{
    print_r( $row );
}
?>

Statistiques Combien y a-t-il de lignes de données :

<?php
$sql="select count(*) from table";
$num = $dbh->query($sql)->fetchColumn();
?>

méthode de préparation :

e7aacce4249b65e0c0c47d847f142e63prepare("select * from table");
if ($query->execute()) {
    while ($row = $query->fetch()) {
        print_r($row);
    }
}
?>

requête paramétrée de préparation :

<?php
$query = $dbh->prepare("select * from table where id = ?");
if ($query->execute(array(1000))) { 
    while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
        print_r($row);
    }
}
?>

Lors de l'utilisation de PDO pour accéder à la base de données MySQL, les véritables instructions préparées ne sont pas utilisées par défaut. Pour résoudre ce problème, vous devez désactiver les effets d'émulation des instructions préparées. Voici un exemple d'utilisation de PDO pour créer un lien :

<?php
$dbh = new PDO(&#39;mysql:dbname=mydb;host=127.0.0.1;charset=utf8&#39;, &#39;root&#39;, &#39;pass&#39;);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
?>

setAttribute()这一行是强制性的,它会告诉 PDO 禁用模拟预处理语句,并使用 real parepared statements 。这可以确保SQL语句和相应的值在传递到mysql服务器之前是不会被PHP解析的(禁止了所有可能的恶意SQL注入攻击)。

虽然你可以配置文件中设置字符集的属性(charset=utf8),但是需要格外注意的是,老版本的 PHP( < 5.3.6)在DSN中是忽略字符参数的。

完整的代码使用实例:

<?php
$dbh = new PDO("mysql:host=localhost; dbname=mydb", "root", "pass");
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //禁用prepared statements的仿真效果
$dbh->exec("set names &#39;utf8&#39;"); 
$sql="select * from table where username = ? and password = ?";
$query = $dbh->prepare($sql); 
$exeres = $query->execute(array($username, $pass)); 
if ($exeres) { 
    while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
        print_r($row);
    }
}
$dbh = null;
?>

上面这段代码就可以防范sql注入。为什么呢?

当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符 ? 发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,它们是分开传送的,两者独立的,SQL攻击者没有一点机会。

但是我们需要注意的是以下几种情况,PDO并不能帮助你防范SQL注入。

不能让占位符 ? 代替一组值,这样只会获取到这组数据的第一个值,如:

select * from table where userid in ( ? );

如果要用in來查找,可以改用find_in_set()实现

$ids = &#39;1,2,3,4,5,6&#39;;
select * from table where find_in_set(userid, ?);

不能让占位符代替数据表名或列名,如:

select * from table order by ?;

不能让占位符 ? 代替任何其他SQL语法,如:

select extract( ? from addtime) as mytime from table;

本篇文章如何使用PDO查询mysql避免SQL注入的方法,更多相关内容请关注php中文网。

相关推荐:

关于php 双向队列类的讲解

php heredoc 与 nowdoc之间的区别与特点

关于HTML5 localStorage and sessionStorage 之间的区别

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn