taitokissの備忘録

調べたことを忘れないように書き留めています。

PHPでMySQLデータベースに接続する (mysql・mysqli 手続き型 編)

PHPMySQLもやり出したところなので、いろいろ調べている。
しかし、参考とするサイトが多く、また作者の書き方やプログラミングの癖などがあるようなので、自分なりにまとめておかないとわけが分からなくなる。全くの初心者と言っていいほどなのでどこから手を付けるべきか悩んだのだが。

 

taitokiss.hatenablog.com


上の記事でMySQLコンソールからデータベースを作成したので、それにPHPからアクセスしてみることにした。

具体的には、PHPからSELECT文を発行し、データベースの内容を表示するという単純な事を試してみた。

ただ、その方法には幾通りかあり、PHPのバージョンにより使えない関数があるなど、どこかに書いておかないと忘れそうなことがたくさんあった。

 

1.処理の流れ

 PHPMySQLデータベースに登録されたデータを表示する手順としては、

  MySQLへ接続

  データベースの選択

  SELECT文の発行

  データの取得

  取得データの表示

  MySQLの切断

となる。

 

2.数種類の処理系

 プログラミング方法として「手続き型」と「オブジェクト型」の2種類がある。

 また、用いることができるAPIには

  mysql_系 手続き型のみ

  mysqli_系 手続き型 オブジェクト型

  PDO_MySQL オブジェクト型

 の3種類がある。

 古い mysql 拡張モジュールは PHP 5.5.0 で非推奨となり、PHP 7 で削除されたので、mysqli か PDO_MySQL のどちらかを使うことが推奨されている。

  参照:PHP: どの API を使うか - Manual

 比較の意味でそれぞれの書き方を書いておきたい。

 

3.データベースの用意

 データベース名:uriage
 ユーザー名:testuser
 パスワード:testuser
 テーブル名:shouhin

 テーブル構成:
  id  name
  1   テレビ
  2   DVD
  3  パソコン
  4  プリンタ
  5   HDD
  6  ラジオ

 の内容でデータベースが用意されているものとする。

 

4.mysql_系での処理

  新規での開発には使用することはないと思うが、古いPHP処理系を使ったり、過去に作られたもののメンテナンスを行うために書いておく。
 この処理系は、手続き型だけである。

mysql_系 手続き型でのデータベースへの接続サンプル

  4行目 $link = mysql_connect("localhost", "testuser", "testuser")
 mysql_connect( server, username, password )
 MySQL サーバーへの接続をオープンあるいは再利用する。
 成功した場合に MySQLリンクID を、失敗した場合に FALSE を返す。

10行目 $db = mysql_select_db("uriage")
 mysql_select_db( database_name [, link_identifier ] )
 指定したリンクID が指すサーバー上のデータベースを、アクティブなデータベースに設定する。
 指定しない場合、mysql_connect() により直近にオープンされたリンク。
 成功した場合に TRUE を、失敗した場合に FALSE を返す。

16行目 mysql_set_charset("utf8")
 mysql_set_charset ( $charset [, link_identifier ] )
 クライアントの文字セットを設定する。
 成功した場合に TRUE を、失敗した場合に FALSE を返す。
 日本語などのマルチバイト文字は文字化けに悩まされる事が多いので、とりあえず記述しておく。尚、mysql_query関数を使って、SQL文「SET NAMES '文字コード'」を実行するのはセキュリティ上まずいので使わないこと。

19行目 $result = mysql_query("SELECT id, name FROM shouhin")

 mysql_query( query [, link_identifier ] )
 ひとつのクエリを送信する (複数クエリの送信はサポートしない)。
 送信先は、link_identifier で指定したサーバー上にある現在アクティブなデータベース。
 指定されない場合、mysql_connect() により直近にオープンされたリンク。
 SELECT, SHOW, DESCRIBE, EXPLAIN、その他結果セットを返す文では、
  成功した場合に resource を、エラー時には FALSE を返す。
 それ以外のSQL文 INSERT, UPDATE, DELETE, DROP などでは、
  成功した場合に TRUE 、エラー時に FALSE を返す。
 返された結果にアクセスするためには、
  結果リソースを mysql_fetch_array() やその他の関数に渡す。
 SELECT 文によって返された行の数を知るには mysql_num_rows() を用いる。
 また DELETE, INSERT, REPLACE, または UPDATE 文で
  変更された行の数を 知るには mysql_affected_rows() を用いる。
 クエリが参照するテーブルにアクセスする権限がない場合も FALSE が返される。

25行目 $row = mysql_fetch_assoc($result)
 mysql_fetch_assoc( result )
 取得した行に対応する連想配列を返し、内部のデータポインタを前に進める。
 取得した行に対応する文字列の連想配列を返す。
 行がもうない場合には FALSE を返す。

31行目 $close = mysql_close($link)
 mysql_close( link_identifier )
 指定した link_identifier が指す MySQLデータベースへの非持続的リンクを閉じる。link_identifier が指定されない場合、最後にオープンされたリンクが使用される。
持続的でない MySQL接続や結果セットは、PHPスクリプトの実行が終了する時点で自動的に破棄される。 そのため、オープンした接続をクローズしたり結果セットを開放したりすることは必須ではない。
 成功した場合に TRUE を、失敗した場合に FALSE を返す。

 

5.mysqli_系での処理 

 このAPI は手続き型、オブジェクト指向型の両方が使える。
 通常は、オブジェクト指向の方がよりモダンに、 きっちりとしたコードを書ける。

5-1 手続き型での処理

mysqli_系 データベースへの接続サンプル(手続き型)

  4行目 $link = mysqli_connect("localhost", "testuser", "testuser")
 mysqli_connect( host, username, password )
 実行中の MySQL サーバーへの接続をオープンする。
 MySQL サーバーへの接続を表すオブジェクトを返す。
 故に、接続に成功したかを確認するには mysqli_connect_error() 関数の返り値が空文字か、mysqli_connect_errno() の返り値が整数「0」以外かの判定を行う必要がある。

10行目 $db = mysqli_select_db($link, "uriage")
 mysqli_select_db( link, dbname )
 データベース接続に対してクエリを実行する際に使用するデフォルトのデータベースを設定する。この関数は、接続のデフォルトデータベースを変更する際にのみ使用。
 成功した場合に TRUE を、失敗した場合に FALSE を返す。

19行目 $result = mysqli_query($link, "SELECT id, name FROM shouhin")
 mysqli_query( link, query )
 データベースに対してクエリを実行する。
 失敗した場合に FALSE を返す。SELECT, SHOW, DESCRIBE, EXPLAIN が成功した場合、mysqli_resultオブジェクトを返す。それ以外のクエリが成功した場合、TRUE を返す。

25行目 $row = mysqli_fetch_assoc($result)
 mysqli_fetch_assoc( result )
 取得した行に対応する連想配列を返す。
 もしもう行がない場合には NULL を返す。

31行目 $close = mysqli_close($link)
 mysqli_close( link )
 既に開いているデータベース接続を閉じる。
 持続的でない MySQL 接続や結果セットは、PHP スクリプトの実行が終了する時点で自動的に破棄される。 
 成功した場合に TRUE を、失敗した場合に FALSE を返す。

 単純に mysql_系 を使ったサンプルを mysqli_系に書き直すとこのようになる。
mysqli_select_db() での デフォルトデータベースの設定は、mysqli_connect() で指定ができ、mysqli_select_db() は省略することができる。
 書き直すと以下のようになる。

mysqli_系 データベースへの接続サンプル2(手続き型)

通常はこちらを使うようですし、まとまっていてスッキリしています。

 

5-2 手続き型でプリペアドステートメントを使う

・プリペアドステートメントとは?
これは、実行したいSQLコンパイルした 一種のテンプレートのようなもので、パラメータ変数を使用することでSQLをカスタマイズすることが可能となっている。

プリペアドステートメントには2つの大きな利点がある。
クエリのパースが必要なのは最初の一回だけで、パラメータを指定して何度でもクエリを実行することができること。
そしてなんといっても、SQL文とパラメータを別々にDBに渡すので、SQLインジェクションを防げるということ。
そのため、特に理由がない限りはプリペアドステートメントでの記述が推奨されている。

 

mysqli_系 データベースへの接続サンプル3(手続き型でプリペアドステートメントを使う)

13行目 $stmt = mysqli_prepare($link, "SELECT id, name FROM shouhin WHERE id >= ?")
 mysqli_prepare( link, query )
 SQLクエリを準備し、後でそのステートメントを操作するために使用するステートメントハンドルを返す。クエリは、単一のSQL 文である必要がある。
 「?(パラメータマーカ)」は、ステートメントの実行や行の取得の前にmysqli_stmt_bind_param() や mysqli_stmt_bind_result() を使用して変数にバインドする必要がある。
 ステートメントオブジェクトを返す。エラー時には FALSE を返す。
「?(パラメータマーカ)」のように後から実際の値を挿入するために仮に確保したものを「プレースホルダ」という方が一般的みたい。

16行目 mysqli_stmt_bind_param($stmt, "i", $id)
 mysqli_stmt_bind_param( stmt, types, var1, var2, ... )
 変数を SQLステートメントのパラメータマーカにバインドする。この変数は、mysqli_prepare() に渡されたものである。
 成功した場合に TRUE を、失敗した場合に FALSE を返す。

22行目 mysqli_stmt_execute($stmt)
 事前に mysqli_prepare() で用意されたクエリを実行する。パラメータマーカが存在する場合、その内容は自動的に適切なデータに置き換えられる。
 ステートメントが UPDATE、DELETE あるいは INSERT であった場合、変更された行の総数は mysqli_stmt_affected_rows() を使用することで取得可能。同様に、クエリが結果セットを返す場合は mysqli_stmt_fetch() を使用できる。
 この関数を使用した場合、他のクエリを実行する前に mysqli_stmt_fetch() を使用する必要がある。
 成功した場合に TRUE を、失敗した場合に FALSE を返す。

25行目 mysqli_stmt_bind_result($stmt, $id, $name)
 mysqli_stmt_bind_result( stmt, types, var1, var2, ... )
 結果セットのカラムを変数にバインドする。
データを取得するために mysqli_stmt_fetch() がコールされた場合、MySQLバインドされたカラムのデータを var1, ... に格納します。
全てのカラムを、mysqli_stmt_execute() をコールしてから mysqli_stmt_fetch() をコールするまでの間にバインドしておく必要がある。カラムの型に応じて、バインド変数の型も対応する PH の型に自動的に変換される。
 カラムのバインドや再バインドはいつでも可能で、たとえ結果セットを途中まで取得した後であっても可能。新しくバインドした内容が効力を発揮するのは、次に mysqli_stmt_fetch() がコールされたときからである。

28行目 mysqli_stmt_fetch($stmt)
 プリペアドステートメントから結果を読み込み、mysqli_stmt_bind_result() でバインドした変数に格納する。
 mysqli_stmt_fetch() をコールする前に、全てのカラムがバインド済みである必要があることに注意。

 

 ついでに、複数回 mysqli_stmt_execute( stmt ) を用いた時のサンプルも書いておこう。

mysqli_系 データベースへの接続サンプル4(手続き型でプリペアドステートメントを使う)

繰り返し部分を関数に分けたが、これでいいかな? 

次からオブジェクト指向型での扱い方になるが、長くなるので記事を分けることにする。