サーチ…


前書き

mysqliインターフェースは、 mysqlインターフェースの改良版(「MySQL改良拡張版」を意味します)です。これはバージョン5.5では廃止され、バージョン7.0では削除されました。 mysqliの拡張機能は、MySQLの改良された拡張機能であり、MySQLシステムバージョン4.1.3以降の新機能を利用するために開発されました。 mysqli拡張機能はPHPバージョン5以降に含まれています。

備考

特徴

mysqliインターフェイスにはいくつかの利点があり、mysql拡張機能よりも重要な機能拡張があります:

  • オブジェクト指向インタフェース
  • プリペアドステートメントのサポート
  • 複数のステートメントのサポート
  • トランザクションのサポート
  • 強化されたデバッグ機能
  • 組み込みサーバーのサポート

古いプロシージャスタイルと新しいオブジェクト指向プログラミング(OOP)スタイルの2つのインターフェイスを備えています。廃止予定のmysqlは手続き型インタフェースしかないため、オブジェクト指向のスタイルが好まれることがよくあります。しかし、新しいスタイルはOOPの力のために有利です。

代替案

データベースにアクセスするためのmysqliインタフェースの代わりに、より新しいPHP Data Objects(PDO)インタフェースがあります。これは、OOPスタイルのプログラミングだけであり、MySQLタイプのデータベース以外にもアクセスできます。

MySQLi connect

オブジェクト指向スタイル

サーバーに接続する

$conn = new mysqli("localhost","my_user","my_password");

デフォルトのデータベースを設定します。 $conn->select_db("my_db");

データベースに接続する

$conn = new mysqli("localhost","my_user","my_password","my_db");

手続き型スタイル

サーバーに接続する

$conn = mysqli_connect("localhost","my_user","my_password");

デフォルトのデータベースを設定します: mysqli_select_db($conn, "my_db");

データベースに接続する

$conn = mysqli_connect("localhost","my_user","my_password","my_db");

データベース接続の確認

オブジェクト指向スタイル

if ($conn->connect_errno > 0) {
    trigger_error($db->connect_error);
} // else: successfully connected

手続き型スタイル

if (!$conn) {
   trigger_error(mysqli_connect_error());
} // else: successfully connected

MySQLiクエリー

query関数は有効なSQL文字列を受け取り、データベース接続$connに対して直接実行します

オブジェクト指向スタイル

$result = $conn->query("SELECT * FROM `people`");

手続き型スタイル

$result = mysqli_query($conn, "SELECT * FROM `people`");

注意

一般的な問題は、単にクエリを実行し、それが動作することを期待する(つまり、 mysqli_stmtオブジェクトを返す)ということです。この関数は文字列だけを取るので、まず自分でクエリを作成します。 SQLに何か間違いがあると、MySQLコンパイラは失敗しfalseこの時点で、この関数はfalseを返しfalse

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
$row = $result->fetch_assoc();

$resultfalseであり、オブジェクトではないため、上記のコードはE_FATALエラーを生成します。

PHP致命的なエラー:非オブジェクト上のメンバ関数fetch_assoc()を呼び出します。

手続き上のエラーは類似していますが、致命的ではありません。なぜなら、我々は単に関数の期待に反しているからです。

$row = mysqli_fetch_assoc($result); // same query as previous

PHPから次のメッセージが表示されます

mysqli_fetch_array()は、パラメータ1がmysqli_result、booleanが指定されているとみなします。

あなたは最初にテストをすることでこれを避けることができます

if($result) $row = mysqli_fetch_assoc($result);

ループスルーMySQLiの結果

PHPは、結果からデータを取得し、 whileステートメントを使用してループすることを容易にします。次の行を取得できなかった場合はfalse返し、ループが終了します。これらの例は

オブジェクト指向スタイル

while($row = $result->fetch_assoc()) {
    var_dump($row);
}

手続き型スタイル

while($row = mysqli_fetch_assoc($result)) {
    var_dump($row);
}

結果から正確な情報を得るために、以下を使用できます。

while ($row = $result->fetch_assoc()) {
    echo 'Name and surname: '.$row['name'].' '.$row['surname'].'<br>';
    echo 'Age: '.$row['age'].'<br>'; // Prints info from 'age' column
}

接続を閉じる

データベースのクエリが終了したら、リソースを解放するために接続を閉じることをお勧めします。

オブジェクト指向スタイル

$conn->close();

手続き型スタイル

mysqli_close($conn);

注意 :サーバーへの接続は、スクリプトの実行が終了すると直ちに閉じられます。ただし、クローズ接続機能を明示的に呼び出すことで以前は閉じられている場合を除きます。

使用例:結果をフェッチした後に実行するスクリプトの処理量が多く、完全な結果セットを取得した場合は、必ず接続を終了する必要があります。もしそうでなければ、Webサーバーが大量に使用されているときにMySQLサーバーが接続制限に達する可能性があります。

MySQLiでの準備文

SQLインジェクション攻撃からSQLステートメントを保護するために準備されたステートメントがなぜ役立つのかの完全な説明は、「 パラメーター化されたクエリによるSQLインジェクションの防止 」を参照してください。

$conn変数はMySQLiオブジェクトです。詳細は、 MySQLi connectの例を参照してください。

どちらの例でも、 $sql

$sql = "SELECT column_1 
    FROM table 
    WHERE column_2 = ? 
        AND column_3 > ?";

?後で提供する値を表します。タイプに関係なく、プレースホルダの引用符は必要ありません。クエリーのデータ部分には、 SETVALUESWHEREという意味のプレースホルダーのみを提供することもできます。 SELECTまたはFROM部分でプレースホルダを使用することはできません。

オブジェクト指向スタイル

if ($stmt = $conn->prepare($sql)) {
  $stmt->bind_param("si", $column_2_value, $column_3_value);
  $stmt->execute();

  $stmt->bind_result($column_1);
  $stmt->fetch();
  //Now use variable $column_1 one as if it were any other PHP variable
  $stmt->close();
}

手続き型スタイル

if ($stmt = mysqli_prepare($conn, $sql)) {
  mysqli_stmt_bind_param($stmt, "si", $column_2_value, $column_3_value);
  mysqli_stmt_execute($stmt);
  // Fetch data here
  mysqli_stmt_close($stmt);
}

最初のパラメータ$stmt->bind_paramかの2番目のパラメータmysqli_stmt_bind_param SQLクエリ内の対応するパラメータのデータ型によって決定されます。

パラメータバインドされたパラメータのデータ型
i 整数
d ダブル
s 文字列
b ブロブ

パラメータのリストは、クエリで指定された順序にする必要があります。この例では、 siは最初のパラメータcolumn_2 = ?が文字列であり、2番目のパラメータcolumn_3 > ?が整数であることを意味します。

データを取得する方法については、準備された文からデータを取得する方法を参照してください。

エスケープ文字列

エスケープ文字列は、クエリに挿入するためにデータを保護する古い( そして安全性の低い )方法です。これは、 MySQLの関数mysql_real_escape_string()を使って処理し、データを消毒します(つまり、PHPはエスケープしていません)。 MySQLi APIはこの関数への直接アクセスを提供します

$escaped = $conn->real_escape_string($_GET['var']);
// OR
$escaped = mysqli_real_escape_string($conn, $_GET['var']);

この時点では、MySQLがダイレクトクエリで安全に使用できると考える文字列があります

$sql = 'SELECT * FROM users WHERE username = "' . $escaped . '"';
$result = $conn->query($sql);

それでなぜこれは準備された声明ほど安全ではないのですか?安全だと思われる文字列を生成するためにMySQLを騙す方法があります。次の例を考えてみましょう

$id = mysqli_real_escape_string("1 OR 1=1");    
$sql = 'SELECT * FROM table WHERE id = ' . $id;

1 OR 1=1はMySQLがエスケープするデータを表していませんが、まだSQLインジェクションを表しています。安全でないデータを返す場所を表す他の例もあります。問題は、MySQLのエスケープ機能がデータをSQL構文に準拠せるように設計されていることです。 MySQLがSQL命令のユーザデータを混乱させないようにするためのものではありません。

MySQLi Insert ID

AUTO_INCREMENT列を持つ表のINSERT問合せによって生成された最後のIDを戻します。

オブジェクト指向スタイル

$id = $conn->insert_id;

手続き型スタイル

$id = mysqli_insert_id($conn);

接続に前のクエリがなかった場合、またはクエリがAUTO_INCREMENT値を更新しなかった場合はゼロを返します。

行を更新するときにIDを挿入する

AUTO_INCREMENT idは、新しい行が保存(または挿入)されたときにのみ返されるため、通常、 UPDATE文は挿入IDを返しません。新しいIDを更新する1つの方法は、更新のためにINSERT ... ON DUPLICATE KEY UPDATE構文を使用することです。

以下の例のセットアップ:

CREATE TABLE iodku (
    id INT AUTO_INCREMENT NOT NULL,
    name VARCHAR(99) NOT NULL,
    misc INT NOT NULL,
    PRIMARY KEY(id),
    UNIQUE(name)
) ENGINE=InnoDB;

INSERT INTO iodku (name, misc)
    VALUES
    ('Leslie', 123),
    ('Sally', 456);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0
+----+--------+------+
| id | name   | misc |
+----+--------+------+
|  1 | Leslie |  123 |
|  2 | Sally  |  456 |
+----+--------+------+

IODKUが「更新」をLAST_INSERT_ID() 、関連するid取得するLAST_INSERT_ID()

$sql = "INSERT INTO iodku (name, misc)
    VALUES
    ('Sally', 3333)            -- should update
    ON DUPLICATE KEY UPDATE    -- `name` will trigger "duplicate key"
    id = LAST_INSERT_ID(id),
    misc = VALUES(misc)";
$conn->query($sql);
$id = $conn->insert_id;        -- picking up existing value (2)

IODKUが「挿入」を実行し、 LAST_INSERT_ID()が新しいid取得する場合:

$sql = "INSERT INTO iodku (name, misc)
    VALUES
    ('Dana', 789)            -- Should insert
    ON DUPLICATE KEY UPDATE
    id = LAST_INSERT_ID(id),
    misc = VALUES(misc);
$conn->query($sql);
$id = $conn->insert_id;      -- picking up new value (3)

結果のテーブルの内容:

SELECT * FROM iodku;
+----+--------+------+
| id | name   | misc |
+----+--------+------+
|  1 | Leslie |  123 |
|  2 | Sally  | 3333 |  -- IODKU changed this
|  3 | Dana   |  789 |  -- IODKU added this
+----+--------+------+

MySQLiでのSQLのデバッグ

したがって、あなたのクエリは失敗しました( MySQLi$connをどのように作成したかを参照してください)

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail

何が起こったのかをどうやって見つけますか? $resultfalseなので、助けにはならない。ありがたいことに、connect $connは、MySQLが私たちに失敗のことを教えてくれたことを教えてくれます

trigger_error($conn->error);

手続き型

trigger_error(mysqli_error($conn));

あなたは次のようなエラーが発生するはずです

テーブル 'my_db.non_existent_table'は存在しません

準備されたステートメントからデータを取得する方法

準備文

クエリの準備と実行の方法については、MySQLiのPrepared statementsを参照してください。

結果のバインディング

オブジェクト指向スタイル

$stmt->bind_result($forename);

手続き型スタイル

mysqli_stmt_bind_result($stmt, $forename);

bind_resultを使用するbind_resultの問題は、使用される列を指定するためにステートメントが必要であることです。つまり、上記のようにクエリを実行するには、 SELECT forename FROM usersようになっている必要がありSELECT forename FROM users 。より多くの列を含めるには、単にそれらをパラメータとしてbind_result関数に追加します(SQLクエリに追加することを確認してください)。

どちらの場合も、 forenameカラムを$forename変数に代入しています。これらの関数は、割り当てたい列数だけ引数をとります。関数は参照によって束縛されるため、代入は1回だけ行われます。

次のようにループすることができます:

オブジェクト指向スタイル

while ($stmt->fetch())
    echo "$forename<br />";

手続き型スタイル

while (mysqli_stmt_fetch($stmt))
    echo "$forename<br />";

これの欠点は、一度に多くの変数を割り当てる必要があることです。これにより、大規模なクエリを追跡することが困難になります。 MySQLネイティブドライバ( mysqlnd )がインストールされている場合は、 get_resultを使用するだけです。

オブジェクト指向スタイル

$result = $stmt->get_result();

手続き型スタイル

$result = mysqli_stmt_get_result($stmt);

mysqli_resultオブジェクトを取得しているので、作業がはるかに簡単です。これは、 mysqli_queryが返すオブジェクトと同じです。つまり、 通常の結果ループを使用してデータを取得できます。


mysqlnd場合はどうすればいいですか?

そうであれば@Sophivorusはあなたにこのすばらしい答えを取り上げました。

この関数は、サーバーにインストールされていないget_resultタスクを実行できます。結果をループして連想配列を作成するだけです

function get_result(\mysqli_stmt $statement)
{
    $result = array();
    $statement->store_result();
    for ($i = 0; $i < $statement->num_rows; $i++)
    {
        $metadata = $statement->result_metadata();
        $params = array();
        while ($field = $metadata->fetch_field())
        {
            $params[] = &$result[$i][$field->name];
        }
        call_user_func_array(array($statement, 'bind_result'), $params);
        $statement->fetch();
    }
    return $result;
}

mysqli_fetch_assoc()を使用しているかのように、関数を使用してこのような結果を得ることができます。

<?php
$query = $mysqli->prepare("SELECT * FROM users WHERE forename LIKE ?");
$condition = "J%";
$query->bind_param("s", $condition);
$query->execute();
$result = get_result($query);

while ($row = array_shift($result)) {
    echo $row["id"] . ' - ' . $row["forename"] . ' ' . $row["surname"] . '<br>';
}

mysqlndドライバを使用していた場合と同じ出力が得られますが、 mysqlndする必要はありません。これは、システムに上記のドライバをインストールできない場合に非常に便利です。このソリューションを実装するだけです。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow