ホームページ >データベース >mysql チュートリアル >SQL インジェクションを回避するために PDO を使用して mysql にクエリを実行する方法
従来の mysql_connect および mysql_query メソッドを使用してデータベースに接続してクエリを実行する場合、フィルタリングが厳密でないと SQL インジェクションのリスクがあります。 mysql_real_escape_string() 関数はユーザーが送信した値をフィルタリングするために使用できますが、これにも欠陥があります。 PHPのPDO拡張機能のprepareメソッドを使用することで、SQLインジェクションのリスクを回避できます。
PDO (PHP Data Object) は、PHP5 に追加された主要な新機能です。PHP 5 より前には、php4/php3 には、php_mysql.dll など、さまざまなデータベースに接続して処理するためのデータベース拡張機能が多数含まれていたためです。 PHP6 もデフォルトで PDO を使用して接続し、mysql 拡張機能が補助として使用されます。公式アドレス: http://php.net/manual/en/book.pdo.php
1. PDO の設定
PDO 拡張機能を使用する前に、まず php でこの拡張機能を有効にする必要があります。 ini、「extension=php_pdo.dll」の前の「;」番号を削除します。データベースに接続する場合は、PDO に関連するデータベース拡張子 (通常は php_pdo_mysql) の前の「;」番号も削除する必要があります。 .dll が使用されます)、Apache サーバーを再起動できます。
extension=php_pdo.dll extension=php_pdo_mysql.dll
2. PDO は mysql データベースに接続します
$dbh = new PDO("mysql:host=localhost;dbname=mydb","root","password");
データベースへの長い接続を使用したい場合は、最後に次のパラメータを追加できます。
3. PDO 設定プロパティ
PDO には 3 つのエラー処理メソッドがあります:
PDO::ERrmODE_SILENT はエラー メッセージを表示せず、エラー コードのみを設定します
PDO::ERrmODE_WARNING は警告エラーを表示します
PDO::ERrmODE_EXCEPTION は例外をスローします
次のステートメントを使用して、例外をスローするエラー処理メソッドを設定できます
$dbh = new PDO("mysql:host=localhost;dbname=mydb","root","password","array(PDO::ATTR_PERSISTENT => true) "); $dbh = null; //(释放)
データベースが異なると、返されるフィールド名の大文字と小文字の処理が異なるため、PDO は PDO を提供します::ATTR_CASE 設定項目 (PDO::CASE_LOWER、PDO ::CASE_NATURAL、PDO::CASE_UPPER を含む) を使用して、返されるフィールド名の大文字と小文字を決定します。
PDO::ATTR_ORACLE_NULLS タイプ (PDO::NULL_NATURAL、PDO::NULL_EmpTY_STRING、PDO::NULL_TO_STRING を含む) を設定して、データベースから返される NULL 値に対応する値を php で指定します。
4. 一般的な PDO メソッドとその応用
PDO::query() は主に記録された結果を返す操作、特に SELECT 操作に使用されます
PDO::exec() INSERT、UPDATE、その他の操作など、結果セットを返さない操作の場合、
PDO::prepare() は主に前処理操作です。前処理の SQL ステートメント。このメソッドはパラメーターをバインドでき、非常に強力です (SQL インジェクションの防止はこれに依存します)
PDO::lastInsertId() は最後の挿入操作を返し、主キーの列の型は最後に自動インクリメントされます。 ID
PDOStatement::fetch() はレコードの取得に使用されます
PDOStatement::fetchAll() はすべてのレコードをコレクションに取得するために使用されます
PDOStatement::fetchColumn() は取得に使用されます結果フィールドで指定された最初のレコード、デフォルトは最初のフィールドです
PDOStatement::rowCount(): 主に、PDO::query() および PDO の DELETE、INSERT、および UPDATE 操作の影響を受ける結果セットに使用されます::prepare()。PDO::exec() メソッドおよび SELECT 操作では無効です。
5.PDO 操作 MYSQL データベース インスタンス
$db->setAttribute(PDO::ATTR_ERrmODE, PDO::ERrmODE_EXCEPTION);
<?php $pdo = new PDO("mysql:host=localhost;dbname=mydb","root",""); if($pdo -> exec("insert into mytable(name,content) values('fdipzone','123456')")){ 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 ); } ?>
prepare メソッド:パラメータ化されたクエリ:
<?php $sql="select count(*) from table"; $num = $dbh->query($sql)->fetchColumn(); ?>
PDO の使用 MySQL データベースにアクセスする場合、デフォルトでは実際のプリペアド ステートメントは使用されません。この問題を解決するには、準備されたステートメントのエミュレーション効果を無効にする必要があります。 PDO を使用してリンクを作成する例を次に示します:
<?php $dbh = new PDO('mysql:dbname=mydb;host=127.0.0.1;charset=utf8', 'root', 'pass'); $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 'utf8'"); $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 = '1,2,3,4,5,6'; 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中文网。
相关推荐:
关于HTML5 localStorage and sessionStorage 之间的区别
以上がSQL インジェクションを回避するために PDO を使用して mysql にクエリを実行する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。