使用PDO时不使用预处理语句占位符也可以防止SQL注入,我们可以使用quote()方法来防止SQL注入。quote()为输入的字符串添加引号(如果有需要),并对特殊字符进行转义,且引号的风格和底层驱动适配。
虽然quote()可以通过加引号及对特殊字符处理,但在官方文档中并不建议用这个方法来防SQL注入
如果使用此函数构建 SQL 语句,强烈建议使用 PDO::prepare() 配合参数构建,而不是用 PDO::quote() 把用户输入的数据拼接进 SQL 语句。 使用 prepare 语句处理参数,不仅仅可移植性更好,而且更方便、免疫 SQL 注入;相对于拼接 SQL 更快,客户端和服务器都能缓存编译后的 SQL 查询。
下面来看看预处理语句prepare()占位符的使用
prepare()中的占位符有两种形式
①冒号‘:’加关键字:(建议使用)
<?php header('content-type:text/html;charset=utf-8'); $username="testuser1"; $email="testuser1@qq.com"; try{ $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); $sql='select * from test_pdo where username=:username and email=:email'; $stm = $pdo->prepare($sql); $stm->execute(array(':username'=>$username,':email'=>$email)); //rowCount 返回受影响的行数 echo $stm->rowCount(); }catch(PDOException $e){ echo $e->getMessage(); }
②问号‘?’占位符:
<?php header('content-type:text/html;charset=utf-8'); $username="testuser1"; $email="testuser1@qq.com"; try{ $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); $sql='select * from test_pdo where username=? and email=?'; $stm = $pdo->prepare($sql); $stm->execute(array($username,$email)); //rowCount 返回受影响的行数 echo $stm->rowCount(); }catch(PDOException $e){ echo $e->getMessage(); }
在使用问号‘?’占位符时,在execute()中的数组参数需要注意参数的顺序,要与对应问号一致,比如第一个问号对应的是'username',array()中的第一个也必须是'username'的参数值。
在上面的占位符介绍案例中,参数是通过execute()绑定并执行的,其实PDO中有另外一个专门绑定参数的方法——bindParam(),bindParam()方法可以一次绑定多次执行sql语句,如果下次的参数值不一样也只需要重新给定参数值即可,此时的execute()无须传递任何参数。
PDOStatement::bindParam ( mixed $parameter , mixed &$variable [, int $data_type = PDO::PARAM_STR [, int $length [, mixed $driver_options ]]] ) : bool
执行成功时返回 TRUE, 或者在失败时返回 FALSE。
参数说明:
parameter 参数标识符。对于使用命名占位符的预处理语句,应是类似 :name 形式的参数名。对于使用问号占位符的预处理语句,应是以1开始索引的参数位置。 variable 绑定到 SQL 语句参数的 PHP 变量名。 data_type 使用 PDO::PARAM_* 常量明确地指定参数的类型。要从一个存储过程中返回一个 INOUT 参数,需要为 data_type 参数使用按位或操作符去设置 PDO::PARAM_INPUT_OUTPUT 位。 length 数据类型的长度。为表明参数是一个存储过程的 OUT 参数,必须明确地设置此长度。 driver_options
在实际使用中,大多数情况下只需给定前两个或三个参数
①冒号‘:’占位符绑定参数:(建议使用)
<?php header('content-type:text/html;charset=utf-8'); try{ $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); $sql="INSERT test_pdo(username,password,email) VALUES(:username,:password,:email)"; $stmt=$pdo->prepare($sql); $stmt->bindParam(":username",$username,PDO::PARAM_STR); $stmt->bindParam(":password",$password,PDO::PARAM_STR); $stmt->bindParam(":email",$email); $username='testuser11'; $password='123456'; $email='testuser11@qq.com'; $stmt->execute(); $username='testuser22'; $password='123456'; $email='testuser22@qq.com'; $stmt->execute(); echo $stmt->rowCount(); }catch(PDOException $e){ echo $e->getMessage(); }
②问号‘?’占位符绑定参数:
<?php header('content-type:text/html;charset=utf-8'); try{ $pdo=new PDO('mysql:host=localhost;dbname=test','root','root'); $sql="INSERT test_pdo(username,password,email) VALUES(?,?,?)"; $stmt=$pdo->prepare($sql); $stmt->bindParam(1,$username,PDO::PARAM_STR); $stmt->bindParam(2,$password,PDO::PARAM_STR); $stmt->bindParam(3,$email); $username='testuser33'; $password='123456'; $email='testuser11@qq.com'; $stmt->execute(); $username='testuser44'; $password='123456'; $email='testuser22@qq.com'; $stmt->execute(); echo $stmt->rowCount(); }catch(PDOException $e){ echo $e->getMessage(); }
问号‘?’占位符在使用时需要注意参数顺序问题,因此,在实际项目中建议使用冒号‘:’加关键字形式的占位符,清楚明了,不易出错。