複数のステートメント

MySQL は、ひとつのステートメントの文字列に、 複数のステートメントを埋め込むことをオプションでサポートしています。 しかし、そうするためには特別な操作が必要です。

複数のステートメント、 またはマルチクエリーは、 mysqli::multi_query() を使って実行する必要があります。 文字列に埋め込まれる個々のステートメントは、 セミコロンで区切ります。 実行されたステートメントによって返される全ての結果セットは、 取得されなければいけません。

MySQL サーバは、 結果セットを返すステートメントと、 返さないステートメントを、 ひとつの複数のステートメントに埋め込むことができます。

例1 複数のステートメント

<?php

mysqli_report
(MYSQLI_REPORT_ERROR MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com""user""password""database");

$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");

$sql "SELECT COUNT(*) AS _num FROM test;
        INSERT INTO test(id) VALUES (1); 
        SELECT COUNT(*) AS _num FROM test; "
;

$mysqli->multi_query($sql);

do {
    if (
$result $mysqli->store_result()) {
        
var_dump($result->fetch_all(MYSQLI_ASSOC));
        
$result->free();
    }
} while (
$mysqli->next_result());

上の例の出力は以下となります。

array(1) {
  [0]=>
  array(1) {
    ["_num"]=>
    string(1) "0"
  }
}
array(1) {
  [0]=>
  array(1) {
    ["_num"]=>
    string(1) "1"
  }
}

セキュリティ上の考慮

mysqli::query()mysqli::real_query() は、 サーバで複数のクエリを処理するための接続フラグを設定しません。 複数のステートメントを使うことで、 SQLインジェクション攻撃の被害を軽減するためには、 追加のAPI呼び出しが必要です。 攻撃者は、; DROP DATABASE mysql; SELECT SLEEP(999) のようなステートメントを追加しようとするかもしれません。 攻撃者がステートメントにSQLを追加することに成功したが、 mysqli::multi_query がそれを使わなければ、 サーバは挿入された、有害なSQLステートメントを実行することはありません。

例2 SQLインジェクション

<?php
$mysqli 
= new mysqli("example.com""user""password""database");
$result $mysqli->query("SELECT 1; DROP TABLE mysql.user");
if (!
$result) {
    echo 
"Error executing query: (" $mysqli->errno ") " $mysqli->error;
}
?>

上の例の出力は以下となります。

Error executing query: (1064) You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax 
to use near 'DROP TABLE mysql.user' at line 1

プリペアドステートメント

プリペアドステートメントを複数のステートメントで使うことは、 サポートされていません。

参照

関連キーワード:  ステートメント, 複数, mysqli, query, array, サーバ, サポート, 追加, multi, 実行