## 複数のステートメント

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_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    $mysqli = new mysqli("example.com", "user", "password", "database");
    $result = $mysqli->query("SELECT 1; DROP TABLE mysql.user");
    ?>

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

    PHP Fatal error:  Uncaught mysqli_sql_exception: 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()
- mysqli::multi_query()
- mysqli::next_result()
- mysqli::more_results()

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open