ホームページ > バックエンド開発 > PHPチュートリアル > PDO を使用して PHP で MySQL にクエリを実行し、SQL インジェクションのリスクを回避する方法_PHP チュートリアル

PDO を使用して PHP で MySQL にクエリを実行し、SQL インジェクションのリスクを回避する方法_PHP チュートリアル

WBOY
リリース: 2016-07-21 15:11:47
オリジナル
737 人が閲覧しました

従来の mysql_connect および mysql_query メソッドを使用してデータベースに接続してクエリを実行する場合、フィルタリングが厳密でないと SQL インジェクションのリスクがあり、Web サイトが攻撃されて制御不能になります。 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 の設定
データベースに接続するには、PHP.ini でこの拡張機能を有効にする必要があります。データベース拡張子 (通常は php_pdo_mysql.dll が使用されます) の前にある PDO 関連の「;」記号も削除し、Apache サーバーを再起動する必要があります。

コードをコピー コードは次のとおりです:

extension=php_pdo.dll
extension=php_pdo_mysql.dll

2. PDO は mysql データベースに接続します
コードをコピー コードは次のとおりです:

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

を使用する場合、デフォルトは長い接続ではありません。データベースへの接続が長い場合は、最後に次のパラメータを追加する必要があります:
コードをコピーします コードは次のとおりです:

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

3. PDO 設定プロパティ

1) PDO には 3 つのエラー処理方法があります:

• PDO::ERrmODE_SILENT はエラー メッセージを表示せず、エラー コードのみを設定します
• PDO::ERrmODE_WARNING は警告エラーを表示します
• PDO::ERrmODE_EXCEPTION は例外をスローします

次のステートメントを使用して、例外をスローするエラー処理メソッドを設定できます

コードをコピーします コードは次のとおりです:

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

Dang PDO::ERrmODE_SILENT に設定すると、errorCode() または errorInfo() を呼び出すことでエラー情報を取得できます。もちろん、他の状況でも使用できます。

2) データベースが異なると、返されるフィールド名の大文字と小文字の処理が異なるため、PDO には、返されるフィールド名の大文字と小文字を決定するための PDO::ATTR_CASE 設定項目 (PDO::CASE_LOWER、PDO::CASE_NATURAL、PDO::CASE_UPPER を含む) が用意されています。 。

3) 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() は主に前処理操作であり、$rs->execute() を介して前処理で SQL ステートメントを実行する必要があります。強力 (SQL インジェクションの防止はこれに依存します)
PDO::lastInsertId() は最後の挿入操作を返します。主キーの列の型は最後に自動インクリメントされた ID です
PDOStatement::fetch() はレコードを取得するために使用されます
PDOStatement: :fetchAll() は、すべてのレコードセットをコレクションに取得します
PDOStatement::fetchColumn() は、結果で指定された最初のレコードのフィールドを取得します。デフォルトは最初のフィールドです
PDOStatement::rowCount(): 主にPDO に使用: :query() および PDO::prepare() の DELETE、INSERT、および UPDATE 操作の影響を受ける結果セットは、PDO::exec() メソッドおよび SELECT 操作では無効です。

5. PDO は MYSQL データベース インスタンスを操作します

コードをコピーします コードは次のとおりです:

$pdo = new PDO("mysql:host=localhost;dbname=db_demo", "root" ,"");
if($pdo -> exec("db_demo(name,content) に挿入 value('title','content')")){
echo "挿入成功!";
echo $pdo -> lastinsertid();
}
?>

コードをコピーします コードは次のとおりです:

$pdo = new PDO("mysql:host=localhost;dbname=db_demo","root","");
$rs = $pdo -> query("select * from test" );
$rs->setFetchMode(PDO::FETCH_ASSOC); //連想配列形式
//$rs->setFetchMode(PDO::FETCH_NUM) //数値インデックス配列形式
while($row = $ rs -> fetch()){
print_r($row);
}
?>

コードをコピー コードは次のとおりです:

foreach( $db -> query( "SELECT * FROM feeds" ) as $row )
{
print_r( $row );
}
?>

データの行数を数えます
コードをコピーします コードは次のとおりです:

$sql="select count(*) from test";
$num = $dbh->query($sql)->fetchColumn();

メソッドを準備します
コードをコピー コードは次のとおりです:

$stmt = $dbh->prepare("select * from test");
if ($stmt->execute()) {
while ( $row = $stmt->fetch()) {
print_r($row);
}
}

パラメータ化されたクエリを準備します
コードをコピーします コードは次のとおりです:

$stmt = $dbh->prepare("select * from test where name = ?");
if ($stmt->execute(array("david"))) {
while ($row = $stmt->fetch (PDO::FETCH_ASSOC)) {
print_r($row);
}
}

【重要なポイント、SQL インジェクションを防ぐ方法について話しましょう】

PDO を使用して MySQL データベースにアクセスする場合、デフォルトでは実際のプリペアド ステートメントは使用されません。この問題を解決するには、準備されたステートメントのエミュレーション効果を無効にする必要があります。以下は、PDO を使用してリンクを作成する例です。

コードをコピーします コードは次のとおりです:

$dbh = new PDO('mysql:dbname=dbtest;host=127.0.0.1; charset=utf8', 'user' , 'pass');
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

setAttribute() この行は必須であり、シミュレートされたプリペアドステートメントを無効にするように PDO に指示し、実数のペアステートメントを使用します。これにより、SQL ステートメントと対応する値が mysql サーバーに渡される前に PHP によって解析されなくなります (考えられるすべての悪意のある SQL インジェクション攻撃を無効にします)。構成ファイルで文字セット属性 (charset=utf8) を設定できますが、古いバージョンの PHP (

完全なコード使用例を見てみましょう:

コードをコピーします コードは次のとおりです:

$dbh = new PDO("mysql:host=localhost; dbname=demo", "user ", "pass" );
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //プリペアドステートメントのシミュレーション効果を無効にする
$dbh->exec("set names 'utf8'");
$sql="名前 = ? およびパスワード = ? のテストから * を選択";
$stmt = $dbh->prepare($sql);
$exeres = $stmt->execute(array($testname, $ pass));
if ($exeres) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
print_r($row);
}
}
$dbh = null;

上記のコードは SQL インジェクションを防ぐことができます。なぜ?

prepare() が呼び出されるとき、クエリ ステートメントはデータベース サーバーに送信されます。この時点では、プレースホルダー? のみが送信され、execute() が呼び出されるとき、ユーザーによって送信されるデータはありません。ユーザーによる送信はデータベースに個別に送信され、SQL 攻撃者は両者に独立した攻撃を行う可能性はありません。

ただし、次の状況には注意する必要があります。PDO では SQL インジェクションを防ぐことができません。

1. プレースホルダー ? を次のような値のセットに置き換えることはできません:


コードは次のとおりです: SELECT * FROM blog WHERE userid IN ( ? );
2. 次のようなデータ テーブル名や列名をプレースホルダーに置き換えることはできません:


コードをコピーします
コードは次のとおりです: SELECT * FROM blog ORDER BY ?;
3プレースホルダー ? を他の SQL 構文に置き換えることはできません:


コードをコピーします
コードは次のとおりです:

SELECT EXTRACT( ? FROM datetime_column) AS variable_datetime_element FROM blog;

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/326795.html技術記事従来の mysql_connect および mysql_query メソッドを使用してデータベースに接続してクエリを実行する場合、フィルタリングが厳密でないと SQL インジェクションのリスクがあり、Web サイトが攻撃されて制御不能になります。それは可能ですが...
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート