memo(m) cgi(u) PHP(p) 改良版MySQL

改良版MySQLモジュール(MySQLi)

MySQLiの概要

MySQLi(MySQL improved)はPHP5以降で利用できるMySQLの操作に関する関数群を提供する拡張モジュールで、MySQL 4.1.3以降の新機能を利用できるよう開発されたものである。旧来のMySQLモジュールと比較して、以下の特徴を備えている[1]

従来型MySQLモジュールによる記述をMySQLiモジュールによるに変換するには、手続き型インタフェースを使った方が楽かも知れません。多くの場合、関数の前半部を「mysql_」から「mysqli_」に変更するだけで済むでしょう。但し、いくつかの関数でデータベース接続ハンドルの指定の位置が変わります。従来型では最後の引数に指定していたのに対し、MySQLiでは最初の引数として指定する必要があります[2]

【MySQL】
$mysql = mysql_connect('localhost','user','pass');
mysql_select_db('sampledb');
$result_src = mysql_query('SELECT * FROM sampletbl',$mysql);
$result = mysql_fetch_assoc($result_src);
print_r($result);

【MySQLi】
$mysqli = mysqli_connect('localhost','user','pass','sampledb');
$result_src = mysqli_query($mysqli,'SELECT * FROM sampletbl');
$result = mysqli_fetch_assoc($result_src);
print_r($result);

MySQLiを利用するにはビルド時に有効となるよう指定しておく必要がある[3]

目次(改良版MySQLモジュール)に戻る

結果の受け取り方〜BufferedとUnbuffered

データベースに問い合わせた結果の受け取り方には「Buffered」と「Unbuffered」の2種類がある。Bufferedは結果を一度に受け取る方法。サーバの負担は小さくなるが、結果が多いとメモリ不足に陥る恐れがある。Unbufferedは結果を1つずつ受け取る方法。サーバには負担をかけるがクライアント側でメモリ不足が起きる可能性は減る。一般的には「Buffered」を使い、結果が大量になるなど「Buffered」で支障がある場合にのみ「Unbuffered」を使うことが推奨される[4]

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

プリペアドステートメント(prepared statement)によりMySQLサーバに接続することができる。これを使うと以下の利点がある。

プリペアドステートメントを使った手順は以下の通り。

  1. データベース接続(mysqli::__construct
  2. ステートメント準備(mysqli_stmt::prepare
  3. (必要なら)パラメータの接続(mysqli_stmt::bind_param
  4. ステートメント実行(mysqli_stmt::execute
  5. (必要なら)結果変数を接続(mysqli_stmt::bind_result
  6. (必要なら)値の取得(mysqli_stmt::fetch
  7. ステートメントを閉じる(mysqli_stmt::close
  8. 接続を閉じる(mysqli::close
【例】オブジェクト指向型
<?php
/* 1. データベース接続 */
$mysqli = new mysqli("example.com", "user", "password", "database");
if ($mysqli->connect_errno) {
    echo "MySQLデータベースへの接続に失敗しました: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
    exit;
}
/* 2. ステートメント準備 */
if (!($stmt = $mysqli->prepare("INSERT INTO test(id) VALUES (?)"))) {
    echo "準備に失敗しました: (" . $mysqli->errno . ") " . $mysqli->error;
}
/* 3. パラメータの接続 */
$id = 1;
if (!$stmt->bind_param("i", $id)) {
    echo "パラメータの接続に失敗しました: (" . $stmt->errno . ") " . $stmt->error;
}
/* 4. ステートメント実行 */
if (!$stmt->execute()) {
    echo "実行に失敗しました: (" . $stmt->errno . ") " . $stmt->error;
}

/* 2. ステートメント準備 */
if (!($stmt = $mysqli->prepare("SELECT id FROM test"))) {
    echo "準備に失敗しました: (" . $mysqli->errno . ") " . $mysqli->error;
}
/* 4. ステートメント実行 */
if (!$stmt->execute()) {
    echo "実行に失敗しました: (" . $stmt->errno . ") " . $stmt->error;
}
/* 5. 結果変数を接続 */
if (!$stmt->bind_result($id)) {
    echo "実行に失敗しました: (" . $stmt->errno . ") " . $stmt->error;
}
/* 6. 値を取得 */
while ($stmt->fetch()) {
    printf("%s\n",$id);
}
/* 7. ステートメントを閉じる */
$stmt->close();
/* 8. 接続を閉じる */
$mysqli->close();
?>
【例】手続き型
<?php
/* 1. データベース接続 */
$link = mysqli_connect("example.com", "user", "password", "database");
if (mysqli_connect_errno()) {
    echo "MySQLデータベースへの接続に失敗しました: (" . mysqli_connect_errno() . ") " . mysqli_connect_error();
    exit;
}
/* 2. ステートメント準備 */
$stmt = mysqli_prepare($link,"INSERT INTO test(id) VALUES (?)");
if (!$stmt) {
    echo "準備に失敗しました: (" . mysqli_errno($link) . ") " . mysqli_error($link);
}
/* 3. パラメータの接続 */
$id = 1;
if (!(mysqli_stmt_bind_param($stmt,"i", $id))) {
    echo "パラメータの接続に失敗しました: (" . mysqli_stmt_errno($stmt) . ") " . mysqli_stmt_error($stmt);
}
/* 4. ステートメント実行 */
if (!(mysqli_stmt_execute($stmt))) {
    echo "実行に失敗しました: (" . mysqli_stmt_errno($stmt) . ") " . mysqli_stmt_error($stmt);
}

/* 2. ステートメント準備 */
$stmt = mysqli_prepare($link,"SELECT id FROM test");
if (!$stmt) {
    echo "準備に失敗しました: (" . mysqli_errno($link) . ") " . mysqli_error($link);
}
/* 4. ステートメント実行 */
if (!(mysqli_stmt_execute($stmt))) {
    echo "実行に失敗しました: (" . mysqli_stmt_errno($stmt) . ") " . mysqli_stmt_error($stmt);
}
/* 5. 結果変数を接続 */
if (!(mysqli_stmt_bind_result($id))) {
    echo "実行に失敗しました: (" . mysqli_stmt_errno($stmt) . ") " . mysqli_stmt_error($stmt);
}
/* 6. 値を取得 */
while (mysqli_stmt_fetch($stmt)) {
    printf("%s\n",$id);
}
/* 7. ステートメントを閉じる */
mysqli_stmt_close($stmt);
/* 8. 接続を閉じる */
mysqli_close($link);
?>

MySQLサーバへの接続(mysqli_connect)

MySQL版のコマンドmysql_connectについてはこちら

mysqli::__constructによりMySQLサーバに接続することができる。手続き型とオブジェクト指向型の2通りの書き方ができる。

手続き型の場合、mysqli_connect関数を実行する。オブジェクト指向型の場合、mysqliクラスのオブジェクトを作成する。

<オブジェクト指向型>
【書式】
new mysqli (MySQLサーバ名,MySQLユーザ名,MySQLユーザのパスワード,MySQLデータベース名,MySQL接続先ポート番号,MySQL接続ソケット名)
【返り値】
MySQL サーバーへの接続を表すオブジェクト
※接続に失敗してもオブジェクトが返される。
 接続が失敗したかどうかを確認するにはmysqli_connect_error()関数、またはmysqli->connect_errorプロパティを使用する。

<手続き型>
【書式】
mysqli_connect (MySQLサーバ名,MySQLユーザ名,MySQLユーザのパスワード,MySQLデータベース名,MySQL接続先ポート番号,MySQL接続ソケット名)
【返り値】
MySQL サーバーへの接続リソース(リンクid)
【例】ローカルシステムのmydbにユーザdbuser、パスワードdbpassで接続
<オブジェクト指向型>
$mysqli = new mysqli('localhost','dbuser','dbpass','mydb');
<手続き型>
$link = mysqli_connect('localhost','dbuser','dbpass','mydb');
MySQLサーバ名

接続先MySQLサーバを示すホスト名または IP アドレスを指定する。この引数に NULL または "localhost" を指定するとローカルホストが指定されたものとみなされる。もし可能な場合、TCP/IP プロトコルの代わりに パイプが使用される。

ホストの前に「p:」をつけると、持続的な接続を開く。接続プールから開いた接続上で mysqli_change_user() が自動的にコールされる。

データ型は文字列。指定がない場合の既定値は設定オプション「mysqli.default_host」の返す値。

MySQLユーザ名
MySQLユーザ名。データ型は文字列。指定がない場合の既定値は設定オプション「mysqli.default_user」の返す値。
MySQLユーザのパスワード
MySQLユーザのパスワード。データ型は文字列。指定がない場合の既定値は設定オプション「mysqli.default_pw」の返す値? 値の指定を省略するか、または NULL を指定した場合、パスワードが設定されていないユーザであった場合にのみ接続を試みる。このことを利用して、パスワードが指定されたかどうかで異なる権限を設定することができる。
MySQLデータベース名
MySQLサーバ接続後、クエリ実行先となるデータベース名を指定する。データ型は文字列。指定がない場合の既定値は「」(空文字列=未指定)。
MySQL接続先ポート番号
MySQLサーバ接続の際使用する接続先ポート番号。データ型は整数。指定がない場合の既定値は設定オプション「mysqli.default_port」の返す値(3306?)。
MySQL接続ソケット名
MySQLサーバ接続の際使用するソケットの名前、またはパイプ名。データ型は文字列。指定がない場合の既定値は設定オプション「mysqli.default_socket」の返す値。なお、この引数を指定してもMySQL サーバーへの 接続時の型を明示的に定義することにはならない。MySQL サーバーへの 接続方法は host 引数で定義される。

目次(改良版MySQLモジュール)に戻る

MySQLサーバへの接続終了(mysqli_close)

MySQL版のコマンドmysql_closeについてはこちら

mysqli::closeはMySQLサーバへの接続を切断する。手続き型とオブジェクト指向型の2通りの書き方ができる。

<オブジェクト指向型>
【書式】
mysqliオブジェクト->close();

<手続き型>
【書式】
mysql_close(MySQLデータベースリンクid)

【返り値】
MySQL接続切断成功→true
それ以外→false
MySQLデータベースリンクid
【手続き型のみ】mysqli_connect、またはmysqli_initによって開かれたMySQL接続id。

目次(改良版MySQLモジュール)に戻る

文字コードを設定(mysqli_set_charset)

mysqli_set_charsetはデータベースサーバーとのデータの送受信に使用する文字コードを指定する。

【書式】オブジェクト指向型
mysqli->set_charset(文字コード名)

【書式】手続き型
mysqli_set_charset (リンクid,文字コード名)

【返り値】
設定に成功→TRUE
失敗→FALSE
文字コード名
文字コード名を指定。指定できる文字コード名はMySQL がサポートする文字セットの一覧を参照。
リンクid
手続き型のみ。mysqli_connectまたはmysqli_initが返すMySQL サーバーへの接続リソース(リンクid)

MySQLデータベースの選択(mysqli_select_db)

MySQL版のコマンドmysql_select_dbについてはこちら

mysqli_select_dbはクエリを実行するためのデフォルトデータベースを変更する。書式は以下の通り。なおデフォルトデータベースはmysqli_connectでも指定可能。

【書式】オブジェクト指向型
mysqli->select_db(データベース名)

【書式】手続き型
mysqli_select_db (リンクid,データベース名)

【返り値】
データベースの選択に成功→TRUE
失敗→FALSE
データベース名
選択するデータベース名を示す文字列。
リンクid
手続き型のみ。mysqli_connectまたはmysqli_initが返すMySQL サーバーへの接続リソース(リンクid)

mysqlプロンプトでコマンド「USE 'データベース名'」を実行することに相当(→MySQL関係 - 使用データベース選択)。

目次(改良版MySQLモジュール)に戻る

クエリ送信(mysqli_query)

MySQL版のコマンドmysql_queryについてはこちら

mysqli_queryは、MySQLサーバに対してクエリを送信する。書式は以下の通り。

【書式】オブジェクト指向型
mysqli->query(クエリ文字列,結果モード)

【書式】手続き型
mysqli_query(リンクid,クエリ文字列,結果モード)

【返り値】
SELECT、SHOW、DESCRIBE、EXPLAINなど結果を返すクエリ:成功→mysqli_resultオブジェクト(結果リソース)、失敗→false
INSERT、UPDATE、DELETE、DROPなど結果を返さないクエリ:成功→true、失敗→false
※テーブルに対するアクセス権がない場合などもfalseが返る
リンクid
手続き型のみ。mysqli_connectまたはmysqli_initが返すMySQL サーバーへの接続リソース(リンクid)
クエリ文字列
クエリ文字列。外部からの入力値に基づく場合、mysql_real_escape_stringを用いてエスケープ処理をすべき。
結果モード

定数「MYSQLI_USE_RESULT」または「MYSQLI_STORE_RESULT」 のどちらかで指定。指定がない場合の既定値は「MYSQLI_STORE_RESULT」。

「MYSQLI_USE_RESULT」を指定すると、mysqli_free_result()を実行するまで、以降のmysqli_queryの実行に対して「Commands out of sync」エラーを返す。

MYSQLI_ASYNC (mysqlnd で使用可能) を使用すると、クエリを非同期実行できるようになります。 このクエリの結果を取得するには mysqli_poll() を使用します。

事例はこちら

目次(改良版MySQLモジュール)に戻る

結果1件受信(mysqli_fetch_array/assoc/row)

MySQL版のコマンドmysql_fetch_array/assoc/rowについてはこちら

mysqli_fetch_arraymysqli_fetch_rowmysqli_fetch_assocは、mysqli_queryで発行したクエリ要求の結果を1件ずつ取得する。返り値となる配列のキーは以下の通り。1件取得するとポインタが次へ移動し、再度コマンドを発行すると次の1件が返る。もうこれ以上条件にマッチする結果がない場合や、1件もヒットしなかった場合はNULLが返る。

【書式】オブジェクト指向型
mysqli_result::fetch_array(結果の配列様式);

【書式】手続き型
mysqli_fetch_array(結果リソース,結果の配列様式)

【返り値】
結果がある時→取得行に対応する配列
結果がもうない時→NULL
※MySQL関数ではfalseが返されていた
コマンド 内容
添字配列 連想配列
mysqli_fetch_array(結果リソース,MYSQL_BOTH)
mysqli_fetch_array(結果リソース,MYSQL_NUM)
mysqli_fetch_row(結果リソース)
mysqli_fetch_array(結果リソース,MYSQL_ASSOC)
mysqli_fetch_assoc(結果リソース)

結果が必要なくなったら、mysqli_free_resultでメモリを開放する方がよい。

添字配列
0からの連番整数を添字とする配列
例:
Array
(
  [0] => 1
  [1] => 2000
  [2] => 1
  [3] => ミオグロビン
  [4] => Myoglobin
)
連想配列
カラム名を添字とする配列
例:
Array
(
  [momid] => 1
  [year] => 2000
  [month] => 1
  [janame] => ミオグロビン
  [enname] => Myoglobin
)
両方
添字キーと連想キーの両方を持つ配列
例:
Array
(
  [0] => 1
  [1] => 2000
  [2] => 1
  [3] => ミオグロビン
  [4] => Myoglobin
  [momid] => 1
  [year] => 2000
  [month] => 1
  [janame] => ミオグロビン
  [enname] => Myoglobin
)
mysql> SELECT pdbid,ec FROM ec;
+-------+----------+
| pdbid | ec       |
+-------+----------+
| 1ldm  | 1.1.1.27 |
| 2jhg  | 1.1.1.1  |
| 8cat  | 1.11.1.6 |
| 1ppi  | 3.2.1.1  |
| 1ca2  | 4.2.1.1  |
+-------+----------+

<pdb.php>
<?php
#- mysql接続
$link = mysqli_connect('localhost','hoge',NULL,'pdb');
#- クエリ文定義
$query_str = "SELECT pdbid,ec FROM ec WHERE pdbid='2jhg'";
#- クエリ文発行
$result_src = mysqli_query($link,$query_str);
#- 結果1件取得
$result = mysqli_fetch_array($result_src);
echo "2jhg:\n";
print_r($result);

$query_str = "SELECT pdbid,ec FROM ec WHERE pdbid='9jhg'";
$result_src = mysqli_query($link,$query_str);
$result = mysqli_fetch_array($result_src);
echo "9jhg:\n";
print_r($result);
?>

<結果>
2jhg:
Array
(
  [pdbid] => 2jhg
  [ec] => 1.1.1.1
)
9jhg:
Array
(
)

目次(改良版MySQLモジュール)に戻る

結果用に確保されたメモリの開放(mysqli_free_result)

mysqli_free_resultは結果用に確保されたメモリを開放する。

【書式】オブジェクト指向型
mysqli_result::free()
mysqli_result::close()
mysqli_result::free_result()

【書式】手続き型
mysqli_free_result(結果リソース)

【返り値】なし

目次(改良版MySQLモジュール)に戻る

MySQLiの事例

オブジェクト指向型の例

$ cat test_object.php
<?php  
/* MySQLサーバに接続
 * 接続先ホストは localhost
 * MySQL接続ユーザ名はmuser
 * MySQL接続ユーザパスワードはmpass
 * 接続先データベース名はmydb
 */
$mysqli = new mysqli('localhost','muser','mpass','mydb');

/* 
 * 接続に失敗したらエラー番号とエラー内容を出力して終了
 */
if ($mysqli->connect_error) {
  die('Connect Error (' . $mysqli->connect_errno . ') '
          . $mysqli->connect_error);
}

/* 
 * PHP 5.2.9 および PHP 5.3.0 以前との互換を保つ方法は以下の通り
 */
if (mysqli_connect_error()) {
    die('Connect Error (' . mysqli_connect_errno() . ') '
            . mysqli_connect_error());
}
echo 'MySQLデータベースオープンに成功しました。' . $mysqli->host_info . "\n";

/* 既定の文字コードをutf-8にセット */
$mysqli->set_charset("utf8");

/* クエリ文字列定義 */
$query_str = 'SELECT * from kintetsu_nara';
/* クエリ送信成功 */
if ($result = $mysqli->query($query_str)) {
  /* 結果がなくなるまで受信 */
  while (($row = $result->fetch_assoc()) != NULL) {
    echo sprintf('%s:%s',$row['sid'],$row['sname'])."\n";
  } 
  /* 結果用に確保されたメモリの開放 */
  $result->free();
}
/* MySQLサーバへの接続終了 */
$mysqli->close();

手続き型の例

$ cat test_procedure.php
<?php  
/* MySQLサーバに接続
 * 接続先ホストは localhost
 * MySQL接続ユーザ名はmuser
 * MySQL接続ユーザパスワードはmpass
 * 接続先データベース名はmydb
 */
$link = mysqli_connect('localhost','muser','mpass','mydb');

/* 
 * 接続に失敗したらエラー番号とエラー内容を出力して終了
 */
if (mysqli_connect_error()) {
    die('Connect Error (' . mysqli_connect_errno() . ') '
            . mysqli_connect_error());
}
echo 'MySQLデータベースオープンに成功しました。' . mysqli_get_host_info($link) . "\n";

/* 既定の文字コードをutf-8にセット */
mysqli_set_charset("utf8");

/* クエリ文字列定義 */
$query_str = 'SELECT * from kintetsu_nara';
/* クエリ送信成功 */
if ($result = mysqli_query($link,$query_str)) {
  /* 結果がなくなるまで受信 */
  while (($row = mysqli_fetch_assoc($result)) != NULL) {
    echo sprintf('%s:%s',$row['sid'],$row['sname'])."\n";
  } 
  /* 結果用に確保されたメモリの開放 */
  mysqli_free($result);
}
/* MySQLサーバへの接続終了 */
mysqli_close($link);

実行結果

$ php test_object.php
MySQLデータベースオープンに成功しました。Localhost via UNIX socket
A01:大阪難波
A02:近鉄日本橋
A03:大阪上本町
A04:鶴橋
A05:今里
A06:布施
A07:河内永和
A08:河内小阪
A09:八戸ノ里
A10:若江岩田
A11:東花園
A12:河内花園
A13:瓢箪山
A14:枚岡
A15:額田
A16:石切
A17:生駒
A18:東生駒
A19:富雄
A20:学園前
A21:菖蒲池
A26:大和西大寺
A27:新大宮
A28:近鉄奈良

目次(改良版MySQLモジュール)に戻る