このエントリーをはてなブックマークに追加
スポンサーリンク

PHP応用

データーベースとPHPを連動

PHPはサーバーサイドで実行させるスクリプトです。ですので、JavaScriptのようにリロードなしで画面を書き換える事はできません。しかし、サーバー側で処理するが故に、サーバー自身やサーバー側のローカルネットにしかないデーターベースへのアクセスが可能です。

なので、PHPはしばしば業務系・・・すなはち、遠方にある顧客からの注文を受けたり、遠方にある仕入先に発注したりする際に用いられます。PHPではデーターベースと連動して使うものだ、と言ってしまっても過言ではないでしょう。

応用編では、PHPプログラマとしてほぼ必須であるデーターベースと連動して使う方法について説明します。

データーベースに接続

データーベースへのアクセスをする時は、まずデーターベースへコネクトしなければなりません。ここでは、既にデーターベースがwebサーバー自身にインストールされている、またはwebサーバーからデーターベースサーバーへ接続可能な状況になっているものとして話を進めます。

ここでは、PostgreSQLかMySQLかのいずれかを使うものとして話を進めていきます。
・PosrgreSQLの場合
$id=pg_connect("host=ホスト名 dbname=データーベース名 user=ユーザー名 password=パスワード")
・MySQLの場合
$id=mysql_connect("ホスト名", "ユーザー名", "パスワード");
MySQLでは引数にデーターベース名がありません。接続後に、mysql_select_db("データーベース名")で選択するか、あるいは、mysql_db_query("データーベース名","クエリー")関数を使って選択します。

ユーザーは事前に作成しておきます。MySQLの場合、
grant 権限 on データーベース名.テーブル名 to ユーザー名@ホスト名;
set password for ユーザー名=old_password('パスワード');
パスワードは、grant all privileges on *.* to ユーザー名@ホスト名 identified by 'パスワード' with grant option;という風にユーザー作成と同時に設定したかったのですが、この文を書いてる時点のバージョンのPHPでは、MySQL4.1以降の方式で暗号化されたパスワードに対応していません。なので、上記の例のように一旦パスワードなしでユーザーを作成してから、old_password句を用いて4.0以下と互換形式で暗号化されたパスワードを使うように指定します。

権限にはselectやinsertなどを指定しますが、all privilegesと書けば「全部」という意味になります。データーベース名、テーブル名の所も、*.*と書けば「全部のDBで全部のテーブル」という意味になります。ホスト名はwebサーバーがDBサーバーも兼ねてる場合はlocalhostとします。

PostgreSQLではパスワードはユーザー単位でpg_shadowというファイルで管理されています。また、pg_hba.confでローカルからパスワードなしてアクセス許可がされている場合は、PHPからの接続の際にもパスワードの指定が不要になります。ただし、セキュリティーの上あまりよろしくないので、PHPからPostgreSQLに接続するユーザーをあらかじめ作っておき、パスワードも設定しておきましょう。PostgreSQLでユーザーを作成し、パスワードを設定するには、
create user ユーザー名;
alter user ユーザー名 with password 'パスワード';
とします。ユーザーを作るだけなら、コマンドラインからcreateuserを使うという方法もあります。

データーベースサーバーにコネクトが成功すると、コネクションIDを返します。コネクションIDをprint 文で表示させると、Resource id #35みたいに表示されます。つまりTRUEです。失敗したときは、NULLが返りますのでFALSEです。なので、以下のようにしてエラー処理を作ります。
if ($id=mysql_connect("ホスト名", "ユーザー名", "パスワード")) {
        コネクトに成功した時の処理;
} else {
        コネクトに失敗した時の処理;
        exit();
}
コネクトに成功した時の処理が特にない場合は、単にセミコロンのみを書いておいても良いですし、if (!($id=mysql_connect("ホスト名", "ユーザー名", "パスワード")))のように「偽だったら」という条件文にして、エラー処理のみを書くという手もあります。

ステートメントの実行

データーベースを操作するためには、SELECTやINSERT、UPDATE等のステートメントを実行する必要があります。したがって、PHPプログラマーはデーターベースのSQL文についても熟知しておく必要があります。

しかしながら、この章ではステートメントそのものについては説明しませんので、別途データーベース入門PostgreSQL入門を読んでおいてください。

ここでは、ステートメントの実行方法のみを説明します。

・PostgreSQLの場合
$sql="select * from テーブル名";
$result = pg_query($id, $sql);
・MySQLの場合
$sql="select * from テーブル名";
$result = mysql_query($id, $sql);
idの指定は省略する事ができます。省略した時は、最後にコネクトしたデーターベースに対してクエリーが実行されます。データーベースが1つしかない、あるいは、主に接続するデーターベースが決まっている場合はidを省略しても大丈夫ですが、そのプロジェクトで将来的に複数データーベースに接続する可能性がある場合は、idを指定しておいた方が、後々の変更点が少なくて済みます。

ステートメントが失敗すると結果ID($result)にFALSEが入りますので、pg_errormessage($id)関数を使ってエラーの原因を表示させるようにすると、デバッグが楽になります。

例)$result値が偽ならエラーの原因を表示
if (!$result=pg_query($id, $sql)) {
      printf("%s<br>\n", pg_errormessage($id) );
      printf("書き込みに失敗しました。<br>\n");
      printf("ブラウザの【←戻る】で戻ってください<br>\n");
}
コラム pg_queryとpg_exec

PHP3の頃は、PostgreSQLのステートメントを実行する命令は「pg_exec」でした。実際、現バージョンでもpg_execで通用するし、PHP3の時代に作られたプログラムを流用したものには、pg_execという命令が今でも使われていると思います。

しかし、現バージョンのPHPでは、どのデーターベース関数も、データーベースサーバーに対してステートメントを与える、あるいは、ステートメントを与えると同時に実行する場合は「xx_query」、あらかじめ与えておいたステートメントの実行のみをする場合は「xx_execute」という風に関数名を統一する動きがあります。

なので、これからプログラムを作る場合は、関数名はpg_queryに統一するようにしましょう。

オブジェクトを使ったデーターの取り出し

ステートメントが成功すると、結果ID($result)が「真」になります。ここで、結果ID($result)を使って変数に格納します。

・PostgreSQLの場合
$Object=pg_fetch_object($result,行番号);
$列名=$Object->列名;
・MySQLの場合
mysql_data_seek($result,行番号);
$Object=mysql_fetch_object($result);
$列名=$Object->列名;
MySQLでは、いったんmysql_data_seekで "何行目のデーターを必要としているのか" を、ポインタを移動させてからオブジェクトに格納します。そのため、MySQLの方が1行程長くなります。

この例では、列名と同じ名前の変数に値を入れてます。こうしておくと、ソースの可読性が高まりますが、同じ名前の変数を別の用途で使いたい事もあるでしょうから、$DB_列名みたいにデーターベースから取り出した変数には特定の接頭語をつけておくと、バグの可能性が少なくなります。

データーをダイレクトに取り出す

データーをダイレクトに取り出す事ができます。これは、結果が数行に渡るわけではなく、たいてい1個だけの場合(合計値を得たい場合など)は、こちらの方が便利です。
・PostgreSQLの場合
$列名=pg_fetch_result ( $result , 行番号, フィールド);
・MySQLの場合
$列名=mysql_result ( $result, 行番号, フィールド);
フィールドには、列名を指定できますが、列番号を指定する事もできます。(列番号の先頭は0です)

この関数は、行番号を「0」に固定して使う場合には便利です。たとえば、total値を得たい場合、得たい結果は0行目の0列目に決まっているので、pg_fetch_result($result,0,0)のように書くことができます。

ただ、結果が多い場合にこの関数を何度もコールしなければならず、また、データーベースから取り出した値が0や空文字だった場合に偽になってしまうため、エラーがほとんど起こらないであろう場所で、結果を1個だけ欲しい場合以外は使わない方が良いです。

データーを配列で取り出す

・PostgreSQLの場合、
$DB_data=pg_fetch_row($result,行番号);
または
$DB_data=pg_fetch_array($result,行番号);
・MySQLの場合
mysql_data_seek($result,行番号);
$DB_data=mysql_fetch_row($result);
または
mysql_data_seek($result,行番号);
$DB_data=mysql_fetch_array($result);
この例では、$DB_data[0]には1列目、$DB_data[1]には2列目、$DB_data[2]には3列目………、の順に値が入ります。xxxx_fech_rowと、xxxx_fech_arrayの違いは、xxxx_fech_arrayの方は連想配列にも値がセットされるという点です。つまり、xxxx_fech_arrayを使った場合は、$DB_data["列名"]としても値が取り出せるようになるという事です。

もし、数字配列しか使う事ができないとしたら、後から仕様変更で取得する列が増えたり減ったりした場合、その都度列番号を変えなければなりません。「後からの仕様変更」これは、プログラマーにとって最も怖いものであり、頻繁に発生する事です。あとから取得する列が増えるか減るかした場合に、もし普通の配列としてデーターを取り出している箇所があると、取り出すカラムと変数の関係がズレてしまいます。なので、変数に代入している箇所全てを書き直さねばならないのですが、どうしても直し漏れが発生してしまいます。

なので、プログラムというものは、できる事なら後からの仕様変更でもバグが出にくい構造になってなくてはなりません。というわけで、xxxx_fech_rowよりも、 xxxx_fech_arrayを使った方が、添え字に直接列名を記述することができ、後から列が増えてもさほど影響のないプログラムになります。

※注意
fetch_arrayで連想配列を使う場合に注意しなければならないのは、大文字と小文字の扱いです。PostgreSQLではいくらCREATE文を大文字で書いても、内部では全部小文字として扱われますので、キーワードは小文字で指定しなければなりません。しかし、MySQLでは大文字と小文字を区別しますので、CREATEした通りの大文字小文字の組み合わせで指定しなければなりません。また、オラクルでは列名は全部大文字になります。

メモリを開放する

データーベースからデータを取得した後、データーの取得に使ったメモリを開放します。

・PosegreSQLの場合
pg_free_result($result)
・MySQLの場合
mysql_free_result($result)
Cでは使ったメモリーは不要になれば開放するのが普通ですし、Perlでも特に常駐プロセスを作る際などは、使ったハンドルは随時解放するように作ると思います。しかし、PHPではこの手続きはさほど必要としません。それは、PHPがページ単位でブラウザに情報を表示させる事を主としているため、大抵の場合、メモリがあふれる程の巨大データーを扱う事もないし、まして、メモリに常駐して何かの制御を行う事も稀です。

なので、PHPでブラウザにデーターベースから取得した結果をを表示させる程度の目的であれば、メモリーを明示的に開放する必要はほとんどありません。なぜなら、プログラム終了時にPHPの方で自動的にメモリを開放するためです。実際、筆者の経験上pg_free_result関数を使わなかったせいでトラブルになった事はありません。

しかし、使ったメモリは必ず開放するという習慣はつけておかないと、PHP以外の言語を扱う際に思わぬバグになったりしますので、なるべくpg_free_resultは入れておく方がベターです。pg_free_result_を省略するにしても、「大してメモリは消費してないし、プログラム終了時に自動的に開放されるので、あえて省略した」と、意味がわかった上で省略するようにしましょう。

データーベースとのコネクトを終了する

・PostgreSQLの場合
pg_close($id);
・MySQLの場合
mysql_close($id);
データーベースとのコネクトを閉じます。実際は、そのプログラムが終了した地点で自動的にクローズが行われるため、明示的にクローズする必要はありませんが、明示的にクローズした方が、データーベース処理の終了部を発見しやすくなり、ソースの可読性が高くなります。

8ビット〜16ビット機が主流の時代からプログラムを作っていた人はよくわかっていると思いますが、昔はオープンしたファイルをクローズしないで終了してしまうと、データーが破損してしまう事がよくありました。というより、昔はファイルをクローズしないでプログラムが終了した場合、大抵ファイルが壊れました。BASICならINPUT PAST ENDが出てファイルが開けなくなるし、COBOLならエラー153が出てプログラムが停止してしまった事でしょう。

今はファイルをクローズしないと破損してしまうような言語はほぼないと思います。データーベースにしろファイルにしろ、今はプログラム終了時に言語(ランタイム)やOSの方でファイルを閉じてくれますから。とはいえ、苦難の道を歩んできた(?)8ビット機からのプログラマーとしては、開いているハンドルは最後にはクローズして終わらせたいです。

という事で、プログラムの最後にはpg_closeやmysql_closeを入れるようにしましょう。

最後に

PHP + PosegreSQL(またはMySQL)が使える環境では、データーベースと連動したさまざまなインターネットアプリが、これまで以上に楽に作れるようになります。

今までCD-ROM等でパッケージ販売されていたソフトも、これからはどんどんASP化してくることでしょう。
スポンサーリンク