[ホーム] -> [Aache + PHP + PostgreSQL 実験室]

PHP と PostgreSQL

PostgreSQL 用関数

PHP には、PostgreSQL 用の関数が用意されています。この関数を使うことによって、PHP で PostgreSQL に接続し、中のデータを取り出し、表示することができるようになります。では、PostgreSQL に接続するための関数には、どのようなものがあるでしょうか? まず、PHP のマニュアルを見てください。その中に、pg_ で始まっている関数がいくつかあるでしょう。それが、PostgreSQL とのやり取りで使う関数群です。この中で良く使う関数は、pg_connect() pg_query() pg_fetch_row() pg_num_rows() pg_close() 辺でしょう。

connect_resource = pg_connect(connect_string)

PostgreSQL に接続するための関数です。引数の connect_string は、「キー=値」のペアをスペースで区切って指定します。キーには、「dbname, port, host, tty, options, user, password」が指定できます。それぞれ、データベース名、ポート番号、ホスト名(IP アドレス)、オプション、ユーザ名、パスワードを意味します。

例えば、「wwwdb」といデータベースに接続するには、「pg_connect("dbname=wwwdb")」とします。PostgreSQL が他のマシンで動いている場合は、「pg_connect("dbname=wwwdb port=5432 host=dbserver user=wwwuser password=PfDsk9d")」とします。これだと、「dbserver 上でポート5432で待ち受けている PostgreSQL にユーザ wwwuser、パスワード PfDsk9dで接続します。

この関数は、戻り値として接続リソースを返します。この接続リソースが、以降の、pg_* 関数を使用する際に必要になります。C 言語で言う、ファイルディスクリプタみたいなものです。pg_query 関数などで使用されるので、この値を変数にとっておく必要があります。

ちなみに、Apache と、PostgreSQL が同じマシンで動いている場合は、dbname だけを指定するだけで接続できます。この場合ユーザは Apache の User で指定したユーザで接続されます。PostgreSQL に接続用のユーザを作成してあれば、dbnameuser を指定してください(パスワードは必要ないはずです)。

result_resource = pg_query(connect_resource, sql_string)

SQL 文を実行するための関数です。select、insert、update などのSQL 文を実行できます。もし SQL 文の実行が失敗した場合は、FALSE が返ります。それ以外の場合は、pg_Result() 関数などのような、ほかの関数で使用される結果リソースが返されます。したがって、この関数の戻り値は、必ず変数に保存しておく必要があります。

array = pg_fetch_row(result_resource, row_number)

pg_query 関数で select 文を発行したとき、結果が返されますが、それから実際の値を取り出すための関数です。行番号を指定しすると、その行の値が配列として返ってきます。最初のカラム(列)が配列の 0 に、二番目のカラムが配列の1 に、と言う風になっています。

array = pg_fetch_array(result_resource[, row_number[, type]])

pg_fetch_row 関数とほぼ同じですが、こちらは、返ってきた配列をカラム名でアクセスできます。pg_fetch_row に比べて、大きなコストがかかるわけではないようです(マニュアルによると)。個人的には、はじめからカラム名が分かっている場合は、0, 1 の様な番号より、カラム名での参照の方をお勧めします。これは、SQL 文を変更したとき、select するカラムの順番を変えてしまうと、番号による参照はとても悲惨なことが起きるからです。

row_count = pg_num_rows(result_resource)

pg_query 関数で select 文を発行したとき、結果が返されますが、そのとき返された結果のレコード件数です。

pg_close(connet_resource)

PostgreSQL との接続を切断します。

messages = pg_last_error(connect_resource)

最後に起きたエラーのエラーメッセージを取得します。

使い方とサンプル

それでは、具体的な使い方に入っていきましょう。基本的な流れは、pg_connect で接続し pg_query で SQL 文を実行する。もし、その SQL 文が select 文ならば、pg_num_rows で何件抽出したか調べ、pg_fetch_row で実際の値を取り出す。最後に、pg_close で、接続を切断する。という流れになります。ここでは、PostgreSQL のデータベース名を列挙するサンプルを作ってみましょう。PostgreSQL 内に作られたデータベースは、pg_database と言う名のシステムカタログより取得することができます。まず、次のような html ファイルを用意します。

<html>
  <head>
    <title>Database List</title>
  </head>
  
  <body>
    <h1>Database List</h1>
  </body>
</html>

この中の、「データベース一覧」の後に、データベース名を列挙しようと思います。

<html>
  <head>
    <title>Database List</title>
  </head>

  <body>
    <h1>Database List</h1>
    <?php
      $con = pg_connect("dbname=template1");
      $rs = pg_query($con, "select datname from pg_database");
      $maxrows = pg_num_rows($rs);
      for ($i = 0; $i < $maxrows; $i++) {
        $row = pg_fetch_row($rs, $i);
        echo("$row[0]<br>\n");
      }
      pg_close($con);
    ?>
  </body>
</html>

pg_connect の引数には、自分の環境の PostgreSQL に存在するデータベース名とユーザ名を指定してください。「template1」と言う名のデータベースは存在するはずですが、ユーザ名は変えてください。

何となく、方法がわかって頂けたでしょうか。このサンプルでは、あらゆるエラー処理を省いていました。本来ならば、pg_connect が成功したかどうか、pg_query が成功したかどうかなどを、調べなければなりません。ここでは、そのエラー処理の方法は解説しません。そんな難しいことではありません。上のと同じソースのサンプル1と、それにエラー処理を加えたサンプル2を用意しておきましたので、それを参考にしてください。

ユーザの要求に答える

さて、次は、ユーザの指定したテーブルの一覧を表示するようなページをつくってみたいと思います。ここでは、テーブルのデータを表示するのに、<table> タグを使って見たいと思います。したがって、表示されるデータは、次のようになります。

テーブル内容
カラム1 カラム2 カラム3
データ1-1 データ1-2 データ1-3
データ2-1 データ2-2 データ2-3

ここで、ちょっと疑問に思うのは、カラムの数と名前でしょう。ユーザが指定したテーブルを表示するわけですから、SQL 文は、「select * from テーブル」となりますが、このとき返されるカラムの数や、カラム名はどうやったらわかるのでしょう。実は、pg_num_fields、pg_field_name という関数が用意されています。

column_maxnums = pg_num_fields(result_resource)

関数で select 文を発行したとき、結果が返されますが、そのとき返された結果のカラムの数です。

column_name = pg_field_name(result_resource, column_num)
pg_query で、select 文を発行した場合に返される結果リソースと、カラム番号を指定すると、そのカラムの名前が返されます。カラム番号は 0 からです。

必要なページは、2ページです。ユーザにテーブル名を入力させるページとその入力されたデータを元にテーブル内のデータを表示するページです。まず、簡単なテーブル名を入力させるページを用意しましょう。データベース名を入力させるテキストボックスと、テーブル名を入力させるテキストボックス、それに実行ボタン (submit) とクリアボタンをのあるページをつくります。サンプルを作ったので、それを見てください。

<form> タグの action オプションには、テーブルの内容を表示するための PHP ファイルを指定します。この例では、table.php というファイルを指定しています。また、各入力項目(テキストボックス)は、きちんと名前をつけるようにしましょう(name オプションを指定する)。そうしないと、呼び出された側の table.php では、値を受け取れないですからね。

サンプルをみると、「@」というマークが pg_connect 関数と、pg_query 関数の頭についています。これは何かというと、PHP のエラー表示を抑制するものです。今まで、PHP が吐き出すエラーメッセージを何回か見たことがあるかと思いますが、「@」を付けた関数では、その表示をしないようにするものです。例えば、存在しないテーブルを pg_query 関数を使って selectしたとき、普通は PHP が「何行目がエラーです」とメッセージを吐きます。しかし、「@」を付けることによって、そこではエラーを表示しません。もちろん、エラーを表示しないからと言って、無いテーブルのデータを表示できるわけではありませんから、pg_query の戻り値を見てエラーかどうかを判断して、独自のメッセージを表示して、処理を終了するようにしています。

エラー制御

今回は、ユーザが入力して、それを元にデータを表示するというものです。この手のページ(プログラム)を作る際には、常に頭にいれておかなければならないことがあります。それは、「不確定な要素に対する処理」です。さて、今回のページは2ページですが、その中に、「不確定な要素」は、大きく2点あります。

  1. データベースからデータを取得する
  2. ユーザが入力する

1番目のデータベースからデータを取得することに関しては、今回に限って言えば、エラーの起きる可能性は、PostgreSQL に接続する部分です。経験的に言って、他のデータベースに比べ、PostgreSQL は、サーバ部分がちょっと落ちやすい(異常終了しやすい)のです。もちろん、普通にしていれば落ちることはありませんが、本当に時々、変なSQL 文を送りつけたときに、サーバ部分が落っこちます。もちろん、最近のバージョンは殆んど無くなりましたが・・・。もう一つ接続できない可能性としては、リソースを使い果たしている場合です。どうやら、PostgreSQL は、クライアントからの1接続に対して、ファイルディスクリプタを 30 ほど消費するようで、同時接続数が多い場合には、ファイルディスクリプタが足らなくなって、接続がうまくいかない場合があるようです。頻繁に起きる場合は、カーネルの再構築をする必要があるかも知れません。もっとも、この1番目の可能性は、非常に低いと言って良いかも知れません。

問題は、2番目の方です。というのも、「ユーザは何を入力するかわからない」からです。したがって、ここの処理をきちんと忘れずにしなければなりません。サンプルでは、データベース名と、テーブル名の両方に値が入力されていなければ、エラーメッセージを表示するようにしました。また、存在しないテーブルを入力されたときは、独自にエラー制御を行い、その旨を表示するようにしてあります。

今回、エラーの制御に当たって、「@」を使いましたが、もう一つ、error_reporting 関数を使う方法もあります。「@」が、一つの関数にたいしてなのに対し、error_reporting関数は、スクリプトコードのブロックに対して有効です。

error_reporting(0);

上のように、引数に 0 を与えてやることにより、それ以降の関数で起きたエラー表示を抑制します。これは、error_reporting 関数の引数に E_ALL & ~E_NOTICE(マニュアル参照) を与えて呼び出すまで有効です。今回、これを使用せず、「@」を使用したのは、エラーを起こしそうな関数は、pg_connect と、pg_queryだけだったからです。もちろん、他の関数もエラーを起こす可能性はあるのですが、その場合は、コーディングミスの可能性が高く、それ以外でエラーが起きる可能性は、低いはずです。

まとめ

PostgreSQL にアクセスする関数として、pg_ で始まる関数が沢山用意されていますが、初めのうちはここで説明したもの以外を使うことは殆んど無いと思います。そして、説明してきた通り、それほど難しくありません。それよりも重要なのは、全体の処理の流れや、エラー処理をどうするかです。もっとも、これは、PHP というより、プログラミング全般の常識であり、他の言語をやっている方なら、わざわざ言うまでもないでしょう。今回の例題は、処理もかなり簡単で、サンプル自体も結構手抜きですが、本来なら、もっと厳密なエラー処理を入れる必要があるかもしれません。

問題が起きたとき、PHP と PostgreSQL のどちらのエラーかが分りにくいので、人によっては、プログラミングしにくいかも知れません。ただ、これは慣れの問題です。PHP がエラーを起こしたのか(構文エラーとか)、あるいは PostgreSQL がエラーを起こしたのか(SQL 文のエラーであったり)を的確に判断できるようになると、プログラミングが楽になると思います。それには、どちらが、どの部分を担当しているかをきちんと把握していることが大切です。もちろん、PostgreSQL や PHP のソースを読めるのなら、それに越したことはありませんが(私は無理 ;-p)、そうでなくても、一度、頭で整理しておけば、それだけでも全然違います。PostgreSQL や PHP は、結構バージョンがどんどん上がるので、そのバージョンアップの作業だけでも結構大変かとは思いますが、色々しているうちに、スキルも上がります。暇をみて、ドキュメントなんかにも目を通すと、面白い発見があるかも知れません。

ホームへ