PHP の学習: 第 1 回 アカウントを登録し、承認を求めるファイルをアップロードし、承認されたファイルを表示してダウンロードする

このチュートリアルは、単純なワークフロー・アプリケーションの構築プロセスを通して PHP の使用方法を説明する 3 部構成のシリーズ「PHP の学習」の第 1 回です。今回のチュートリアルでは、HTML フォームを使用する基本的な PHP ページの作成手順と、データベースへのアクセス方法を説明します。

Nicholas Chase, Founder, NoTooMi

Nicholas Chase は、NoTooMi の創設者および作成者です。大手企業の技術文書作成の他、Lucent Technologies、Sun Microsystems、Oracle、Tampa Bay Buccaneers などの企業の Web サイト開発に従事してきました。高校の物理教師、低レベル放射性廃棄物施設のマネージャー、オンライン SF 雑誌の編集者、マルチメディア・エンジニア、Oracle インストラクター、そして双方向通信の会社での最高技術責任者としての経歴があります。『XML Primer Plus』(Sams、2002年) をはじめ、複数の本の著者でもあります。



2012年 11月 29日

始める前に

シリーズ第 1 回では、基本的な PHP の構文、フォームと関数、そして PHP アプリケーションで MySQL やその他のデータベースに接続してデータベースを使用する方法を学びます。

このチュートリアルについて

このチュートリアルでは、PHP を使用して単純なワークフロー・アプリケーションを構築する手順を説明します。サンプル・アプリケーションでは、ユーザーがアカウントを登録し、承認を求めるファイルをアップロードし、承認されたファイルを表示してダウンロードすることができます。管理者として指定されたユーザーは、アップロードされたファイルを表示して承認し、すべてのユーザーに対してそのファイルを使用可能にすることができます。シリーズの第 2 回第 3 回では、HTTP パスワード保護、XML、JSON、その他関連する課題について探ります。

このチュートリアルの内容は以下のとおりです。

  • 基本的なページの作成方法
  • 変数、ループ、if-then 文
  • 関数
  • データベースへの接続方法
  • インクルード・ファイルの使用方法
  • ツール

このチュートリアルの対象読者

PHP を使用して Web ベースのアプリケーションを構築する方法を学びたいと思っているプログラマーは、この 3 回からなるチュートリアル・シリーズの第 1 回から始めてください。PHP はスクリプト・ベースの言語で、習得するのは簡単ながらも、この言語に備わる堅牢な機能を使って複雑なアプリケーションを構築することができます。今回のチュートリアルでは、HTML フォームを使用した基本的な PHP の作成手順を説明します。また、データベースにアクセスする方法についても説明します。

前提条件

このチュートリアルでは、読者に PHP を使用した経験がないことを前提とします。HTML の概念を十分に理解していると役に立ちますが、実際にはこのチュートリアルでは PHP 以外のプログラミングは必要ありません。チュートリアルで使用するソース・コードは自由にダウンロードすることができます。

システム要件

Web サーバー、PHP、そしてインストールされていて使用できる状態のデータベースが必要です。ホスティング・アカウントを使用している場合は、サーバーに PHP V5 がインストール済みで、MySQL データベースにアクセスできる限り、そのアカウントを使用することができます。そうでない場合は、以下のパッケージをダウンロードしてインストールしてください。

XAMPP
Windows、Linux、あるいは Mac のどれを使用しているかに関わらず、このチュートリアルに必要なすべてのソフトウェアを取得するのに最も簡単な方法は、Web サーバー、PHP、MySQL データベース・エンジンをまとめてパッケージ化した XAMPP をインストールすることです。この方法を選ぶとしたら、XAMPP をインストールした後、コントロール・パネルを実行して Apache および MySQL プロセスを起動するだけで準備は完了です。各種の構成要素を個別にインストールするという選択肢もありますが、その場合には、すべてが連動するように構成する必要があることを念頭に置いてください。XAMPP をインストールする方法では、この構成ステップまでが行われます。
Web server
XAMPP を使用しないことにした場合、Web サーバーにはいくつかの選択肢があります。PHP 5.4 を使用しているとしたら (このチュートリアルを作成している時点では、XAMPP では PHP 5.3.8 のみが使用されています)、テストには組み込み Web サーバーを使用することができます。ただし、本番用には Apache Web サーバーのバージョン 2.x を使用することを前提とします。
PHP 5.x
XAMPP を使用しない場合、PHP 5.x を別途ダウンロードする必要があります。標準ディストリビューションには、このチュートルアルに必要なすべてのものが含まれています。ダウンロードするのはバイナリーで構いません。このチュートリアルには (PHP のコード自体に手を加えたいというのでない限り)、ソースは不要です。このチュートリアルは、PHP 5.3.8 を前提に作成してテストしました。
MySQL
このプロジェクトの一環としてデータをデータベースに保存する必要があるため、データベースも必要です。データベースについても同じく、XAMPP をインストールしてある場合にはインストール手順をスキップすることができますが、必要に応じてデータベースを別途インストールするのでも構いません。このチュートリアルでは、MySQL に焦点を合わせます。PHP では、MySQL が一般的に使用されているためです。MySQL を選択する場合は、Community Server をダウンロードしてインストールすることができます。

基本的な PHP の構文

このセクションでは、PHP でページを作成する際の基礎を見ていきます。次のセクションで、HTML フォームを使用して PHP に情報を送信する方法を説明するので、その前に、基本のタスクを行う方法を知っておく必要があります。

基本的な PHP のページ

まずはテキスト・エディターを開いて、最も基本的な PHP のページを作成します (リスト 1 を参照)。

リスト 1. 基本的な PHP のページ
<html>
   <title>Workflow Registration</title>
   <body>
      <p>You entered:</p>
      <p><?php echo "Some Data"; ?></p>
   </body>
</html>

上記のコードは全体としては、1 つの PHP セクションが含まれた単純な HTML ページです。サーバーは「<?php」というシンボルを検出すると、これをそのままブラウザーに送信するのではなく、このシンボルに続くコマンドを評価することだと理解します。サーバーは、「?>」というシンボルで示されたセクションの終わりに達するまで、命令 (この後すぐに説明します) に従います。

上記の例では、echo というコマンドが 1 つあるだけです。これは、指定したテキストを出力するようサーバーに指示するコマンドです。つまり、このページを保存してからブラウザーで呼び出すと (追って、この作業を行います)、ブラウザーはリスト 2 に示すページを受け取ることになります。

リスト 2. ブラウザーが受け取る PHP のページ
<html>
   <title>Workflow Registration</title>
   <body>
      <p>You entered:</p>
      <p>Some Data</p>
   </body>
</html>

実際の動作を確かめるには、このファイルを registration_action.php という名前で保存して、サーバーのドキュメント・ルートにファイルを移動してください。XAMPP でドキュメント・ルートに該当するディレクトリーは <XAMPP_HOME>/htdocs です (Apache では、おそらく /var/www/html となります)。

このページを呼び出すには、Web ブラウザーを開いて http://localhost/registration_action.php を指定します。これにより、図 1 のような画面が表示されます。

図 1. echo コマンドによる出力
echo コマンドによる出力

おめでとうございます。PHP を使って初めてのページを作成できました。これが、この言語で行う他のすべての作業の基礎となります。

変数

変数は、データのプレースホルダーです。変数に値を代入すると、それ以降は PHP が変数を検出する度に、その変数に代入された値を使用します。例えば、上記で作成したページをリスト 3 のように変更するとします。

リスト 3. PHP ページで変数を使用する
<html>
   <title>Workflow Registration</title>
   <body>
      <p>You entered:</p>

         <?php
         $username = "nick";
         $password = "mypassword";

         echo "<p>Username = " . $username . "</p>";
         echo "<p>Password = " . $password . "</p>";
      ?>

   </body>
</html>

第一に注目する点は、各行がセミコロン (;) で終わっていることです。また、ピリオド (.) がテキストを「連結」する手段であることにも注目してください。ピリオドを使用して、「ストリング」(テキストの塊) をいくつでも結合することができます。

変数についてもう 1 つ言っておくと、PHP では、変数名の大/小文字が区別されます。したがって、例えば $UserName$UserName とは異なる変数です。

見つけにくいエラーを防ぐには、一貫した命名規則 (すべての変数を小文字にするなど) に従うのが効果的です。

ファイルを保存して (必要な場合は保存したファイルをアップロードして)、ブラウザーを最新の表示に更新すると、図 2 のような画面が表示されます。

図 2. 最新の表示に更新後のブラウザー
最新の表示に更新後のブラウザー

次の話題に進む前に、特殊な変数について取り上げておきます。

定数

変数の値は何度でも変更できますが、値が変更されないことを見込んで変数を設定したい場合もあります。そのようなアイテムは変数とは呼ばれず、「定数」と呼ばれます。例えば、各ページのタイトルを表す定数を定義することもできます (リスト 4 を参照)。

リスト 4. 定数を定義する
<?php
   define("PAGE_TITLE", "Workflow Registration");
?>
<html>
   <title><?php echo PAGE_TITLE ?></title>
   <body>
      <p>You entered:</p>
      ...

(今は、たいしたことがないように思えるかもしれませんが、この先、この定義を複数のページで使用できることがわかります。)

上記では、定数の名前とその値を定義していることに注目してください。定数を定義した後にその値を変更しようとすると、エラーが返されます。

また、title 要素などで定数を参照するときには、ドル記号は付けずに、定数の名前だけを使用します。定数にはどんな名前を付けても構いませんが、慣例では、すべて大文字を使用することになっています。

今後、オブジェクトについて学ぶときに、これよりも若干簡潔に定数を指定する方法を説明します。

より簡単な出力方法

これまでは echo コマンドを使用して情報を出力しましたが、1 つのデータを出力するだけの場合、このコマンドを使用するのは多少面倒です。

幸い、PHP にはそれよりも簡単な方法が用意されています。それは、出力演算子である <?= ?> 構成体を使用して、出力する情報を指定するという方法です (リスト 5 を参照)。

リスト 5. 出力演算子を使用する
<?php
   define("PAGE_TITLE", "Workflow Registration");
?>
<html>
   <title><?= PAGE_TITLE ?></title>
   <body>
      <p>You entered:</p>
      ...

出力演算子を使用する場合には、出力する情報の後にセミコロンを続けないでください。

後で、if-then 文などの他の基本的な PHP 構成体についても学びます。これらの構成体は、アプリケーションを構築する際に必要になります。


PHP とフォーム

このセクションでは、配列、そしてフォーム・データを扱う方法を学びます。また、ループや if-then 文など、PHP スクリプトのフローを制御する方法についても探っていきます。

PHP でフォームを作成して使用する

PHP は、Web プログラミング言語として開発されました。実のところ、PHP はコマンドラインから実行することもできますが、この言語が Web アプリケーション以外の分野で使用されることはめったにありません。要するに、PHP プログラマーとして行う最も一般的なタスクは、Web フォームを使用することだと言えます。

Web フォームは、HTML を使用して作成します。ユーザーがフォームを送信すると、ブラウザーは情報の「配列」をサーバーに送信します。

HTML でフォームを作成する

まずは、アプリケーションの登録ページを作成するところから始めます。最終的には、この登録ページにユーザーが情報を入力し、ページを作成した側でその情報を「検証」(つまり、情報の完全性をチェック) してからデータベースに保存することになります。今の時点で作成するのは、単なる基本的なフォームです。registration.php という名前のファイルを新規に作成し、リスト 6 に記載する内容を追加してください。

リスト 6. 登録ページを作成する
<html>
   <head><title>Workflow System</title></head>
   <body>
      <h1>Register for an Account:</h1>

      <form action="registration_action.php" method="GET">

         Username: <input type="text" name="name" /><br />
         Email: <input type="text" name="email" /><br />
         Password: <input type="password" name="pword" /><br />
         <input type="submit" value="GO" />

      </form>

   </body>
</html>

これで、フォームが出来上がりました (フォームは form 要素内に含まれています)。このフォームは、2 つのテキスト入力、パスワード入力、そして送信ボタンがあるだけのシンプルなものです。このファイルを、ドキュメント・ルート (registration_action.php が置かれているディレクトリー) に保存します。ブラウザーで http://localhost/registration.php を指定してファイルを開き、各フィールドに入力すると、図 3 のような画面になります。

図 3. アカウント登録フォーム
アカウント登録フォーム

パスワード・ボックスには、入力している実際の内容は表示されません。フォームを構成するこのタイプの要素は、誰かが肩越しに見ても機密情報が漏れることのないよう、情報を見えなくすることが意図されています。一方、「GO」ボタンをクリックすると何が起こるのでしょうか。

フォームを送信する

フォームを作成するときに、実際の form 要素を <form action="registration_action.php" method="GET"> として作成しました。

この要素には、2 つの情報が含まれています。1 つは、ブラウザーに対して action で指定しているデータの「送信先」です。この例の場合、前に作成した registration_action.php ページにデータが送信されます。もう 1 つの情報は、ブラウザーに対して method で指定しているデータの「送信方法」です。

これがどのように機能するのかを見てみましょう。何らかのデータを入力して (まだ入力していない場合)、「GO」ボタンをクリックしてください。すると、図 4 のような結果になります。

図 4. データの出力
データの出力

上記の図では、正しい情報が表示されていないように見えます (これは、実際に送信した情報ではありません)。しかしそれはまだ、送信されるデータを調べるようにページを調整していないためです。一方、URL を見ると、http://localhost/registration_action.php?name=nickChase&email=nickchase%40noTooMi.com&pwor d=asupersecretpassword となっています。

URL には、名前が付けられた各フォーム要素の名前と値のペアがアンパサンドで区切られて含まれていることに注目してください。URL がこのようになっているのは、GET メソッドを使用したからです。GET メソッドは、このような方法でデータを送信するよう、ブラウザーに指示します。「POST を使用する」で説明するように、POST メソッドはこれとは異なる方法でデータを送信します。それを説明する前に、このデータを実際に PHP ページ内で取得する方法を見てみます。

フォーム・データにアクセスする

フォームを送信したら、そのデータが実際の応答ページ registration_action.php に取り込まれるようにしなければなりません。それには、このファイルの内容をリスト 7 のように変更します。

リスト 7. データを応答ページに取り込む
...
   <body>
      <p>You entered:</p>

      <?php
         $username = $_GET['name'];
         $password = $_GET['pword'];s

         echo "<p>Username = " . $username . "</p>";
         echo "<p>Password = " . $password . "</p>";
      ?>

   </body>
</html>

上記では、指定された要素の値を $_GET 配列から抽出しています。配列については後で詳しく説明するとして、ここではブラウザーを最新の表示に更新すると実際に入力した情報が表示されることに注目してください (図 5 を参照)。

図 5. ブラウザーに表示された正しい情報
ブラウザーに表示された正しい情報

要素の名前を指定することで、送信したどの情報でも抽出することができます。ただし、これは配列であるため、データを取り出す方法は他にもあります。

配列

PHP では配列 (値のリスト) を作成することができます。配列を使用すれば、簡単に値のグループを一度にまとめて参照することができます。例えば、値の配列を作成して、これらの値をまとめてページに出力することができます (リスト 8 を参照)

リスト 8. 値の配列を作成する
$formnames = array("name", "email", "pword");
echo "0=".$formnames[0]."<br />";
echo "1=".$formnames[1]."<br />";
echo "2=".$formnames[2]."<br />";

array() 関数が返す値は、この関数に渡された値の配列です (関数については後で詳しく説明します。ここでは、「関数を呼び出すと、変数に代入した値が関数によって返される」ということを理解しておいてください)。

最初の値の「インデックス」は 1 ではなく、0 であることに注意してください。また、目的の値を指定するために、配列変数の名前の後に、角括弧で囲んだインデックスを追加している点にも注目してください。このスクリプトによって、リスト 9 の出力が生成されます。

リスト 9. 配列の出力
0=name<br />
1=email<br />
2=pword<br />

このアクションは、フォームの値にアクセスする方法と似ています。これは決して偶然ではありません。$_GET 変数は、「連想」配列と呼ばれる特殊な配列であり、この配列では、各値に対して、数値のインデックスの代わりにキーが指定されます。

フォームを送信すると、基本的にはリスト 10 に示す配列が作成されます。

リスト 10. フォームを送信すると作成される配列
$_GET = array("name" => "roadnick",
 "email" => "ibmquestions@nicholaschase.com",
 pword" => "supersecretpassword");

上記コードが、連想配列の個々の値を $_GET["name"] のようにして抽出できるようにする仕組みです。ただし、このようなコードを個々に作成する必要はありません。

番号で配列情報を取得する

連想配列はデータを扱う際に極めて重宝しますが、配列がどのような構造になっているのかわからない場合はよくあります。例えば、クエリーから連想配列を受け取る汎用のデータベース・ルーチンを作成する場合などです。

幸い PHP には、開発者を多少楽にしてくれる 2 つの関数が用意されています (リスト 11 を参照)

リスト 11. array_keys() 関数と array_values() 関数
...
<body>
   <p>You entered:</p>

      <?php
      $form_names = array_keys($_GET);
      $form_values = array_values($_GET);

      echo "<p>" . $form_names[0] . " = " . $form_values[0] . "</p>";
      echo "<p>" . $form_names[1] . " = " . $form_values[1] . "</p>";
      echo "<p>" . $form_names[2] . " = " . $form_values[2] . "</p>"; 
   ?>

</body>
...

array_keys() および array_values() 関数は、それぞれ通常の数値配列で情報を返すので、これらの配列を使用すれば、数値インデックスを使用してデータを抽出することができます (図 6 を参照)。

図 6. 数値インデックスを使用してデータを抽出するための配列
数値インデックスによるデータの抽出

けれども、さらに便利な方法があるはずです。例えば、実際に値が何個あるのかわからない場合を考えてみてください。PHP では、連想配列を処理する方法がいくつかあります。そのうち最も便利な方法は、どの情報が既知であるかによって決まります。次は、これと同じタスクを行う他の 2 つの方法を見ていきます。

for-next ループを使用する

PHP で極めて一般的なタスクの 1 つに、複数の値のループ処理があります。このタスクは、for-next ループを使って簡単に行うことができます。for-next ループは、定義に従って数々の値を調べていきます。リスト 12 に記載するこのループの一例を見てください。

リスト 12. for-next ループ
for ($i = 0; $i < 10; $i++) {
   echo $i . " ";
}

PHP はまず、値 0$i に割り当てます。これが、ループの先頭に指定されているからです。$i が 10 より小さい値である限りループは続き、PHP はループの実行ごとに $i の値を 1 ずつインクリメント (加算) します。上記の出力は以下のとおりです。

0 1 2 3 4 5 6 7 8 9

これが何を意味するかと言うと、$_GET 配列に含まれる値の個数を知ることができれば (それは可能です)、リスト 13 のように、フォームで指定された値のすべてを簡単にループ処理できるということです。

リスト 13. フォームで指定されたすべての値をループ処理する
...
<body>
   <p>You entered:</p>

   <?php
      $form_names = array_keys($_GET);
      $form_values = array_values($_GET);

         for ($i = 0; $i < sizeof($_GET); $i++) {
         echo "<p>".$form_names[$i]." = " . $form_values[$i] . "</p>";
      }     
   ?>

</body>
...

sizeof() 関数は、$_GET 配列に含まれる値の個数を返します。そのデータを使用して、ループをいつ停止するかを指定することができます (図 7 を参照)。

図 7. sizeof 関数を使用してループを停止する
sizeof 関数を使用してループを停止する

連想配列としての $_GET を使用する場合には、まだもう 1 つの方法があります。それは、foreach ループです。

foreach ループを使用する

PHP では連想配列が一般的に使われることから、この言語には、キーと値を抽出するプロセスを経ることなく簡単にデータにアクセスする方法も用意されています。キーと値を抽出する代わりに foreach ループを使用すれば、配列を直接操作することができます。一例として、リスト 14 のコードを見てください。

リスト 14. foreach ループを使用する
...
   $form_values = array_values($_GET);

   foreach ($_GET as $value) {
      echo "<p>" . $value . "</p>";
   }
?>
...

初めてループを実行するときに、PHP は $_GET 配列の最初の値を取り、その値を $value に代入して出力します。その後は、ループの先頭に戻って次の値を $value に代入するという処理を $_GET に含まれる値ごとに続けます (これが、このループという名前の由来です)。最終的な結果は、リスト 15 の出力となります。

リスト 15. foreach ループによる出力
<p>roadnick</p>
<p>ibmquestions@nicholaschase.com</p>
<p>supersecretpassword</p>

さらに便利なことに、値とキーを抽出することもできます (リスト 16 を参照)。

リスト 16. 値とキーを抽出する
...
   $form_values = array_values($_GET);

   foreach ($_GET as $key=>$value) {
      echo "<p>" . $key . " = " . $value . "</p>";
   }
?>
...

上記のコードによる結果は、元の結果と同じです (図 8 を参照)。

図 8. 元の結果
元の結果

フォームの複数の値

フォームの値を話題にするときには、度々持ち上がってくる、ある状況を取り上げないわけにはいきません。それは、フォームの複数の値が同じ名前を持つ場合です。例えば、ユーザーはパスワードとして入力している値を見ることができないため、パスワードに誤りがないことを確認するために、ユーザーにパスワードを 2 回入力させる必要があります。それには、リスト 17 のコードを registration.php に追加します。

リスト 17. フォームの中で同じ名前を持つ複数の値
...
Username: <input type="text" name="name" /><br />
Email: <input type="text" name="email" /><br />
Password: <input type="password" name="pword[]" /><br />
Password (again): <input type="password" name="pword[]" /><br />
<input type="submit" value="GO" />
...

pword フィールドの名前が少し変更されていることに注目してください。複数の値を取得しようとしていることから、パスワード自体を配列として扱わなければなりません。それは当然、配列の値も配列であることを意味します。したがって、この時点でフォームを送信すると、次の URL が作成されます。http://localhost/registration_action.php?name=nickChase&email=nickchase%40noTooMi.com &pword%5B%5D=asupersecretpassword&pword%5B%5D=asupersecretpassword

(値 %5B%5D は、URL エンコードされた [] です)。

フォームを送信することは、配列を作成することと同じです (リスト 18 を参照)。

リスト 18. フォームの送信によって作成される配列
$passwords = array("asupersecretpassword", "asupersecretpassword");
$_GET = array("name"=>"nickChase",
                "email"=>"nickChase@noTooMi.com",
                "pword"=>$passwords);

つまり、パスワードの値を確認する必要がある場合には、これらの値に数値配列としてアクセスする必要があるということです (リスト 19)。

リスト 19. 数値配列としてパスワード値にアクセスする
...
foreach ($_GET as $key=>$value) {
   echo "<p>".$key." = " . $value . "</p>";
}

$passwords = $_GET["pword"];
echo "First password = ".$passwords[0];
echo "<br />";
echo "Second password = ".$passwords[1];
...

フォームを送信すると (またはページを最新の表示に更新すると)、違いが見えてきます (図 9 を参照)。

図 9. 送信されたフォーム
送信されたフォーム

パスワード・フィールドは「Array」として出力されるようになりましたが、パスワードの値には直接アクセスできることに注目してください。

GET を使用する場合と POST を使用する場合の違い

これまでは、GET メソッドを使ってデータを送信しました。この送信方法だと、前に目にしたようにデータがそのまま URL に含まれます。データが含まれる URL が適切であることもあれば、そうでないこともあります。この方法は、例えばリンクを使ったフォームの送信をシミュレーションする場合に使用することができます。しかし、大量のデータ (例えば、ユーザーがコメントを入力できる textarea からのデータ) を送信するとしたら、目標を達成する最善の方法にはなりません。その理由の 1 つは、Web サーバーは GET リクエストで受け入れる文字数に制限を設けているのが通常だからです。

もう 1 つの理由として、優れた手法および標準の要件では、「副次作用」のある操作や、実際に何らかの「処理を行う」操作には決して GET を使用しないように規定しています。例えば、今まで説明した例では画面上のデータを見ているだけなので、副次作用による操作への影響はありません。けれども、最終的にはこのデータをデータベースに追加することになります。データベースにデータを追加するということは、本質的には副次作用です。

多くの Web プログラマーはこの特定の制約を認識していませんが、これが問題につながる場合もあります。特に URL として GET を使用する場合には、ユーザーがページにブックマークを付けたために、あるいは検索エンジンが実際にはデータベースを更新していること、または他のアクションを行っていることを認識せずに URL に索引を付けたために、システムが操作を何度も繰り返すことになりかねません。

このような場合には、代わりに POST を使用する必要があります。


POST を使用する

GET メソッドの代わりに POST メソッドを使用するのは、実に簡単なことです。まず必要な作業として、registration.php ページをリスト 20 の太字部分のように変更します。

リスト 20. 登録ページで GET の代わりに POST メソッドを使用する
...
<h1>Register for an Account:</h1>
<form action="registration_action.php" method="POST">

   Username: <input type="text" name="name" /><br />
...

フォームを送信すると、URL は以下のように簡潔になります。

http://localhost/registration_action.php

データを取得するには、2 つの方法があります。1 つは、registration_action.php で $_GET 配列ではなく $_POST 配列を使用するという方法です (リスト 21 を参照)。

リスト 21. $_POST 配列を使用してデータを取得する
...
<body>
   <p>You entered:</p>

   <?php
      foreach ($_POST as $key=>$value) {
         echo "<p>".$key." = " . $value . "</p>";
      }

      $passwords = $_POST["pword"];
      echo "First password = ".$passwords[0];
      echo "<br />";
      echo "Second password = ".$passwords[1];
   ?>
</body>
...

$_POST 配列を操作する方法は、$_GET 配列を操作したときとまったく同じです。

このメソッドの利点は、スクリプトが対象としているものを正確に制御できるところにあります。一方、欠点としては、URL に何かを挿入してデバッグを行うとしたら、スクリプトを変更しなければならないことが挙げられます。この問題を回避する一般的な方法は、第 3 の配列 $_REQUEST を使用することです。これにより、渡されたデータを両方の場所に組み込むことができます (リスト 22 を参照)。

リスト 22. デバッグ用に $_REQUEST 配列を使用する
...
   <?php
      foreach ($_REQUEST as $key=>$value) {
         echo "<p>".$key." = " . $value . "</p>";
      }

      $passwords = $_REQUEST["pword"];
      echo "First password = ".$passwords[0];
...

エラーのチェック: if-then 文

作業を進める前に、ユーザーにパスワードを 2 度入力するように求めても、両方の入力が一致していることを確かめなければ意味がありません。これを確かめるには、リスト 23 に示すように if-then 文を使用します。

リスト 23. if-then 文を使用する
...
$passwords = $_POST["pword"];
echo "First password = ".$passwords[0];
echo "<br />";
echo "Second password = ".$passwords[1];

if ($passwords[0] == $passwords[1]) {
   echo "<p>Passwords match. Thank you.</p>";
} else {
   echo "<p>Passwords don't match. Please try again.</p>";
}
...

if-then 文の中では、括弧で囲まれた式 (この例では $passwords[0] == $passwords[1]) が真 (true) の場合、PHP は最初の波括弧内の文を実行し、偽 (false) の場合には実行しません。この例には、式が偽 (false) の場合に取るべき代替アクションも含まれています。

1 つの等号で $passwords[0] = $passwords[1] とする代わりに、二重の等号を使って $passwords[0] == $passwords[1] としていることに注目してください。二重の等号は、比較演算子です。この比較演算子は、2 つが等しいかどうかを検出します。1 つの等号は、代入演算子です。1 つの等号を使用して上記の文を実行すると、PHP は $passwords[1] の値を単純に $passwords[0] に代入するだけなので、明らかにここでの目的を果たしません。

この例では、2 つのパスワードが一致しなければ、ページがユーザーに警告を出します (図 10 を参照)。

図 10. パスワードが一致しないと出される警告
パスワードが一致しない場合

他の便利な演算子には、and 演算子 (&&) と or 演算子 (||) もあります。リスト 24 に、この 2 つの演算子の使用例を示します。

リスト 24. and 演算子と or 演算子
if (($today == "Monday") && ($status == "Not a holiday")) {
   echo "GO TO WORK!!!";
}

上記の例で式が真 (true) になるのは、今日が月曜日であり、かつ休日でない場合のみです。and 演算子の代わりに or 演算子を使用した場合、いずれかの要素が真 (true) であれば、式は真 (true) になります。


関数

ここからは、少し掘り下げた内容として、PHP で関数を実装して時間を節約する方法を探ります。


関数を作成する

規模の大きいアプリケーションを構築していると、何度も使用する (アクション、計算処理、その他の) コード・セクションに出くわすのが一般的です。

このような場合、コードを抜粋して、それを使用して「関数」を作成すると有効です。例えば、パスワードの検証については、その処理を取り出して別個の関数にすることができます (リスト 25 を参照)。

リスト 25. 関数を作成する
...
<body>
   <p>You entered:</p>

   <?php

      function checkPasswords($firstPass, $secondPass){

         if ($firstPass == $secondPass) {
            echo "<p>Passwords match. Thank you.</p>";
         } else {
            echo "<p>Passwords don't match. Please try again.</p>";
         }

      }

      foreach ($_POST as $key=>$value) {
         echo "<p>".$key." = " . $value . "</p>";
      }

      $passwords = $_POST["pword"];
      echo "First password = ".$passwords[0];
      echo "<br />";
      echo "Second password = ".$passwords[1];

   ?>
</body>

...

サーバーがこのページを処理するときに function キーワードに遭遇すると、コードのそのセクションは明示的に要求されるまで実行してはならないことを認識します。したがって、図 11 を見るとわかるように、このページでは最初に foreach ループが実行されることに変わりありません。

図 11. foreach ループの実行
foreach ループの実行

次に、実際に関数を使用する方法を説明します。

関数を呼び出す

関数を呼び出すには、関数の名前に括弧の対を続けます。この例のように引数を要求する場合は、括弧の中に引数を含めます (リスト 26 を参照)。

リスト 26. 関数を呼び出す
...
<body>
   <p>You entered:</p>

      <?php

      function checkPasswords($firstPass, $secondPass){
         if ($firstPass == $secondPass) {
            echo "<p>Passwords match. Thank you.</p>";
         } else {
            echo "<p>Passwords don't match. Please try again.</p>";
         }
      }

      foreach ($_POST as $key=>$value) {
         echo "<p>".$key." = " . $value . "</p>";
      }

      $passwords = $_POST["pword"];
      echo "First password = ".$passwords[0];
      echo "<br />";
      echo "Second password = ".$passwords[1];

      checkPasswords($passwords[0], $passwords[1]);

   ?>
</body>

...

PHP がこのページを実行するときには、最初に foreach ループを実行し、パスワードを出力した後、2 つのパスワード入力を引数として渡して checkPasswords() 関数を実行します (図 12 を参照)。(配列を渡して、関数の中で個々の値を抽出することもできます。)

図 12. foreach ループの後に実行される checkPasswords() 関数
checkPasswords() の実行

この関数の目的はコードのチャンクを実行することであり、値を返すことではないため、他の言語でプログラミングをした経験がある人からしてみれば、この関数はどちらかというと「サブルーチン」のように見なせるかもしれません。次で説明するように、関数はサブルーチンとして使用することも、値を返すために使用することもできます。

値を返す

関数はコードのチャンクを実行するために使用するだけでなく、何らかのアクションを実行して値を返すために使用すると有益な場合もよくあります。例えば、検証用の関数を作成し、その中でいくつかのアクションを実行してから、問題があるかどうかを示す値を返すようにすることができます (リスト 27 を参照)。

リスト 27. 値を返す
...
<body>
   <p>You entered:</p>

   <?php
         function validate($allSubmitted){

         $message = "";

         $passwords = $allSubmitted["pword"];
         $firstPass = $passwords[0];
         $secondPass = $passwords[1];
         $username = $allSubmitted["name"];

         if ($firstPass != $secondPass) {
            $message = $message."Passwords don't match<br />";
         }
         if (strlen($username) < 5 || strlen($username) > 50){
            $message = $message."Username must be \
            between 5 and 50 characters<br />";
         }

         if ($message == ""){
            $message = "OK";
         }

         return $message;

      }


      function checkPasswords($firstPass, $secondPass){

...

上記の関数は、引数として$_POST 配列を取り、そこから検証対象の情報を抽出します。空の $message ストリングから始めて、パスワードが一致しない場合、または (string length (ストリング長) を表す strlen() 関数から返される) ユーザー名の長さが誤っている場合には、$message ストリングにテキストを追加します。パスワードが一致して、ユーザー名の長さも正しければ、空のままの $message ストリングに値 “OK” を代入します。次で説明するように、この値はページの本体の中で調べることができます。

データを検証する

ユーザーの入力が適切であるかどうかに応じて値を返す関数を作成したので、今度は関数によって返された値をテストします (リスト 28 を参照)。

リスト 28. データを検証する
...
   echo "<br />";
   echo "Second password = ".$passwords[1];

      if (validate($_POST) == "OK") {
      echo "<p>Thank you for registering!</p>";
   } else {
      echo "<p>There was a problem with your registration:</p>";
      echo validate($_POST);
      echo "<p>Please try again.</p>";
   } 

?>
...

if-then 文の中で、validate() 関数から返された値がチェックされます。値が “OK” であれば、簡単なありがとう (Thank you…) のメッセージが表示され、そうでなければ、値として返されたメッセージそのものが表示されます (図 13 を参照)

図 13. 警告メッセージの表示
警告メッセージの表示

まず注意すべき点は、この手法が大きく功を奏するのは、特定の結果をテストする場合です。すべての条件を if-then 文に含めようとした場合、いかに混沌とした状態になるかを想像してみてください。また、上記の例では関数を 2 回呼び出していますが、それでは非効率です。本番アプリケーションでは、操作を不必要に繰り返すのではなく、戻り値を変数に代入してから、その変数をチェックすることになります。

データに問題がないことを知る方法が用意できたので、次はそのデータをデータベースに格納することができます。


データベースに接続してデータベースを使用する方法

PHP アプリケーションの多くには、データベースを使用する必要があります。これが、このセクションで取り上げる内容です。


データベースを選択する (または選択しない): PDO (PHP Data Object) を使用する

MySQL は無料で入手することができ、PHP のホスティング・プランやディストリビューションの多くにその構成が組み込まれているため、大半の PHP アプリケーションでは概して MySQL がデータベースとして選択されています。それはそれで構わないのですが、最終的なコードが MySQL に固有のコードになってしまうという問題があります。

残念なことに、それは将来データベースを変更する必要が生じた場合 (例えば、Sqlite、IBM DB2、または Oracle などに変更する場合)、データベース関連のコードを作成し直さなければならないことを意味します。幸い、PDO (PHP Data Object) が登場し、PHP のバージョン 5.3 からコア・インストールに組み込まれるようになったことにより、特定のデータベースに縛られずに PHP でデータベース関連のコードを作成できるようになっています。

その仕組みを説明すると、まず、PDO を使用してデータベース・アクセス・コードを作成してから、データベース固有の PDO ドライバーを組み込みます。これで、変更するデータベースに対応するドライバーを組み込んでデータベースへの「接続ストリング」を変更するだけで、データベースを変更できるようになります。

この例では、PDO を使用して MySQL データベースに接続します。XAMPP を使用しているとしたら、追加の構成を行う必要はありません。MySQL ドライバーはデフォルトで有効になっています。XAMPP を使用していない場合には、php.ini ファイルで extension=php_pdo.dll および extension=php_pdo_mysql.dll の行がコメントアウトされていないことを確認してください。

これらの dll はすでに、php.ini ファイルに extension_dir として指定されているロケーションに置かれているはずです。

次は、データベースそのものを扱います。


セットアップする

先に進む前に必要な作業として、データベースを作成してテーブルを追加し、そのテーブルへのアクセス権を持つ新規ユーザーを作成します。

XAMPP をインストールしてある場合、MySQL コンソールにアクセスするにはリスト 29 に記載するコマンドを入力します。

リスト 29. MySQL コンソールにアクセスする
cd <XAMPP_HOME>
mysql/bin/mysql -h localhost -u root

(MySQL を別途インストールして、root ユーザーのパスワードを作成した場合には、-p パラメーターを追加し、プロンプトに応じてパスワードを入力する必要があります)。

コンソールにアクセスしたら、リスト 30 に記載するコードを入力します。

リスト 30. データベースを作成する
create database workflow;

use workflow;

create table users (id int auto_increment primary key, username varchar(50),
                    email varchar(255), password varchar(50));

show tables;

最終的な出力は、リスト 31 のようになります。

リスト 31. 最終出力
>+--------------------+
| Tables_in_workflow |
+--------------------+
| users              |
+--------------------+
1 row in set (0.00 sec)

最後に、ユーザー名を wfuser、パスワードを wfpass として新規ユーザーを追加します (リスト 32 を参照)。

リスト 32. 新規ユーザーを追加する
GRANT ALL PRIVILEGES ON *.* TO 'wfuser'@'localhost'
IDENTIFIED BY 'wfpass' WITH GRANT OPTION;

これで、実際にデータベースを使用する作業に取り掛かることができます。

データベースに接続する

何らかのデータベース操作を必要としない大規模な Web アプリケーションを作成することは、事実上、不可能です。このサンプル・アプリケーションでは MySQL データベースを使用して、ユーザー名とパスワードの情報を保管します。そのためにこのセクションで行う作業として、送信されたユーザー名が一意であるかどうかを確認し、一意である場合にはそのデータをテーブルに挿入する機能を登録アクション・ページに追加します。このセクションでは、データベースに保管されている情報を表示する方法についても説明します。最終的には、アプリケーションのログイン・ページを作成することになります。

まずは、「セットアップする」で作成した workflow データベースに接続します (リスト 33 を参照)。

リスト 33. workflow データベースに接続する
...
if (validate($_POST) == "OK") {

   $dbh = new PDO('mysql:host=localhost;dbname=workflow', 'wfuser', 'wfpass');

   echo "<p>Thank you for registering!</p>";

} else {
   echo "<p>There was a problem with your registration:</p>";
...

上記では、$dbh という新規オブジェクトを作成しています。オブジェクトについては、このシリーズの今後のチュートリアルで詳しく学びますが、現時点では、オブジェクトとは、使用する関数の集合のことであると考えてください。

このオブジェクトは、データベースの「接続ストリング」(mysql:host=localhost;dbname=workflow) に加え、MySQL データベースに接続するためのユーザー名とパスワードを使用します (接続ストリングのタイプは、データベースによって異なります)。

何も問題がなければ、オブジェクトを破棄するか (この後、説明します)、ページの処理が終了するまで、接続はオープン状態のままになります。

次は、ユーザー・データを挿入します。

レコードを挿入する

今度は、前の手順で作成した users テーブルにデータを追加します。データを追加するには、対象のテーブルにデータを挿入する SQL 文を作成してから、その文を実行します。

SQL 文の形式は、リスト 34 に記載するとおりです。

リスト 34. テーブルにデータを挿入する SQL 文
insert into users (username, email, password) values
                  ('roadnick', 'ibmquestions@nicholaschase.com', 'supersecretpassword')

テーブルを作成するときに特別の注意を払っていたとしたら、id 列はどうなっているか疑問に思っていることでしょう。この最初の列は、AUTO_INCREMENT として指定したので、上記の例のようにこの列への入力を省略すると、MySQL はこの列に、次に使用可能な整数を自動的に取り込みます。

ただし、実際にデータを挿入するには、単に insert 文を作成するだけでは済みません。以前は、リスト 35 のような処理を行うのが一般的な方法でした。

リスト 35. かつてのデータ挿入方法
$sql = "insert into users (username, email, password) values \
                  ('".$_POST["name"]."', '".$_POST["email"]."', '".$passwords[0]."')

けれども、このような構成体は、「SQL インジェクション」と呼ばれるハッキング手法に悪用されやすく、データが盗まれたり、削除されたりする可能性があります。データベースに直接アクセスするのではなく、PDO を使用することの利点の 1 つは、このリスクを排除する「プリペアド・ステートメント」を簡単に使用できることです。これから、プリペアド・ステートメントがどのように機能するかを説明します。

以下のステートメントを作成 (準備) する必要があります (リスト 36 を参照)。

リスト 36. ステートメントを作成する
...
if (validate($_POST) == "OK") {

   $dbh = new PDO('mysql:host=localhost;dbname=workflow', 'wfuser', 'wfpass');

   $stmt = $dbh->prepare("insert into users (username, email, password) \
                                        values (:name, :email, :pword)");

   echo "<p>Thank you for registering!</p>";

} else {
   echo "<p>There was a problem with your registration:</p>";
...

構成体 -> に注目してください。これが、オブジェクトの関数またはプロパティーを参照する方法です。この例では、データベースに対し、3 つのパラメーターを持つ insert 文を準備するように指示しています。

次に必要なのは、変数をパラメーターに「バインド」することです (リスト 37 を参照)。

リスト 37. 変数をパラメーターにバインドする
...
   $stmt = $dbh->prepare("insert into users (username, email, password) \
                                        values (?, ?, ?)");

   $stmt->bindParam(1, $name);
   $stmt->bindParam(2,  $email);
   $stmt->bindParam(3, $pword);

   echo "<p>Thank you for registering!</p>";

} else {
...

このステップでデータベースに指示している内容は、変数に格納されている値を取り、それをその特定のパラメーターとして使用するというものです。次に、値を設定して、このステートメントを実行します (リスト 38 を参照)。

リスト 38. 値を設定してステートメントを実行する
...
   $stmt = $dbh->prepare("insert into users (username, email, password) \
                                        values (?, ?, ?)");

   $stmt->bindParam(1, $name);
   $stmt->bindParam(2,  $email);
   $stmt->bindParam(3, $pword);

   $name = $_POST["name"];
   $email = $_POST["email"];
   $pword = $passwords[0];

   $stmt->execute();

   echo "<p>Thank you for registering!</p>";

} else {
...

上記の結果として、データベースは適切な値を使用してクエリーを実行しながらも、SQL インジェクション攻撃を受けるリスクがなくなります (特定の文字をエスケープするなどの適切なステップは、バックエンドで行われます)。

この方法を使用するもう 1 つの利点は、プリペアド・ステートメントを再利用できることです。新しい値を $name$email$pword の各変数に代入するだけで、ステートメントを再実行することができます。

データベースに情報が追加されたので、次は、データベースから情報を取得する方法を説明します。

レコードを選択する

現時点で、データベースにデータを追加できるようになりましたが、ユーザー名が一意であることを調べるにはどうすればよいのでしょうか?今のところその手段は実装されていませんが、これに対応するには、実際にデータを挿入する前に、users テーブルをチェックします (リスト 39 を参照)。

リスト 39. ユーザー名が一意であることを確認する
...
if (validate($_POST) == "OK") {
    $dbh = new PDO('mysql:host=localhost;dbname=workflow', 'wfuser', 'wfpass');

    $checkUserStmt = $dbh->prepare("select * from users where username = ?");
    $checkUserStmt->bindParam(1, $name);
    $name = $_POST["name"];
    $checkUserStmt->execute();

    if ($checkUserStmt->rowCount() == 0) {    

        $stmt = $dbh->prepare("insert into users (username, email, password)\
                                          values (?, ?, ?)");
...
        echo "<p>Thank you for registering!</p>";

    } else {

        echo "There is already a user with that name: <br />";

    } 

} else {
...

上記では、最初に作成したときと同じ方法でプリペアド・ステートメントを作成していますが、execute() 関数は少し理解しづらいように見えるかもしれません。いろいろ考えてみた結果、何の処理も行っていないように思えるかもしれませんが、それは違います。ここで行っているのは、クエリー (つまり、ユーザーによって入力されたユーザー名が格納されているデータベース行があるかどうか) を満たすデータをステートメントに取り込むという処理です。

データベースがレコードを検出したかどうかを調べるには、rowCount() 関数をチェックします。この関数は、クエリーが見つけた行の数を返します。クエリーが行を見つけたとしたら、ユーザー名は一意でないことになります。

実際には、このステートメントにはクエリーを満たすすべての行に関するすべての情報が格納されます。次は、この一連の結果を取得します。

結果を取得する

あるユーザーがすでに存在するユーザー名を入力した場合に、既存のすべてのユーザー名が表示されるようなことは、実際にはもちろん「絶対に」ありませんが、ここでは敢えてそれを行って、そのような処理を行う方法を説明します。

前のセクションでプリペアド・ステートメントを使用する方法を説明しましたが、信頼できないデータ (ユーザーが送信したユーザー名やその他の情報など) を使用していない場合には、クエリーを直接実行するという方法を選択することができます (リスト 40 を参照)。

リスト 40. クエリーを直接実行する
...
    } else {

        echo "<p>There is already a user with that name: </p>";

        $users = $dbh->query("SELECT * FROM users");
        $row = $users->fetch();
        echo $row["username"] . " -- " . $row["email"] . "<br />";

    }
...

最初のステップは、クエリーを実行することで $users にデータを取り込むステートメントです。これにより、users テーブルのすべての行が選択されます。

次に、fetch() 関数を使用して単一の行を取り出します。この関数は、単一の行のデータを含む連想配列を返します。キーは列名と同じなので、$row 配列の該当する値を要求することによって、行のデータを非常に簡単に出力することができます。

しかし、この例で扱っているのは 1 つの行だけです。すべてのデータにアクセスするにはどうすればよいのでしょう?

すべての結果を表示する: while ループ

すべてのデータを表示するには、フェッチする行がある限り、ページに行をフェッチさせ続けなければなりません。そのためにセットアップできるのが、while ループです (リスト 41 を参照)。

リスト 41. while ループをセットアップする
                    ...
                          $users = $dbh->query("SELECT * FROM users");
        while ($row = $users->fetch()) {
            echo $row["username"] . " -- " . $row["email"] . "<br />";
        }       
                    ...

PHP はまず始めに、行に対して fetch() を試行します。フェッチに成功すると結果は真 (true) となり、その行の情報を表示します。失敗した場合、つまり fetch() の対象となる行がなくなった場合には、式が偽 (false) を返し、それによって while ループが終了します。

その結果、現存するすべてのアカウントのリストが表示されます (図 14 を参照)。

図 14. テーブルに含まれる複数の行の表示
テーブルに含まれる複数の行の表示

データベース接続を閉じる

作業を進める前に、オープンしたデータベース接続を確実にクローズする必要があります。それには、データベースに接続している PDO オブジェクトを破棄します (リスト 42 を参照)。

リスト 42. PDO オブジェクトを破棄する
...
            echo $row["username"] . " -- " . $row["email"] . "<br />";
        }
    }

     $dbh = null;

} else {
    echo "<p>There was a problem with your registration:</p>";
...

次は、これまでの作業を少し整理します。


整理: ファイルのインクルード

これまでに作成したスクリプトは、1 つの PHP ファイルに必要なコードをすべて含めた自己完結型のスクリプトでした。このセクションでは、コードを複数のファイルに整理する方法を説明します。具体的には、コードから、複数のページで使用しているセクションを抜き出して、それを別個のファイルに入れ、そのファイルを元のページにインクルードします。

インクルード・ファイルを使用する理由

PHP でのファイルのインクルードには、2 つの観点があります。1 つは、インターフェース要素などのサポート・ファイルをインクルードすること、もう 1 つは、ページ内で呼び出される関数などの非常に重要なファイルをインクルードすることです。

定義をインクルードする

最初に、最終的にインクルードするファイルを作成するところから始めます。Web サイトを作成するときに必ず最初に必要となる作業は、主要なインターフェース要素を含めたヘッダーおよびフッターのファイルを作成することです。こうすることで、コーディング作業が終わるまで各ページの外観を心配することなく、いくらでもページを作成することができます。ヘッダーとフッターのインクルード・ファイルを作成するときに、インターフェースを 1 度作成しておけば、サイト全体が瞬時に更新されるようになります。

まずは、top.txt という名前のファイルを作成し、リスト 43 に記載するコードを追加してください。

リスト 43. top.txt ファイルを作成する
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
    <title>Workflow Manager</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
  </head>
  <body>
    <div id="wrapper"><div id="bg"><div id="header"></div>
      <div id="page"><div id="container"><div id="banner"></div>
        <div id="nav1">
          <ul style='float: left'>
            <li><a href="#" shape="rect">Home</a></li>
            <li><a href="#" shape="rect">Upload</a></li>
            <li><a href="#" shape="rect">Files</a></li>
          </ul>
        </div>
        <div id="content">
          <div id="center">

bottom.txt と名付けた別のファイルを作成して、リスト 44 の内容を追加します。

リスト 44. bottom.txt
          </div>
        </div>
      </div>
    </div></div></div>
  </body>
</html>

両方のファイルを、registration.php と同じディレクトリーに保存します。「ダウンロード」の PHPPart1SampleFiles.zip に含まれる images ディレクトリーと style.css ファイルも、そのディレクトリーにコピーしてください。top.txt の HTML コードは、このディレクトリーとファイルを参照します。

ファイルをインクルードする

次の作業は、上記で作成したファイルを登録ページに追加することです。registration.php をリスト 45 のように編集してください。

リスト 45. top.txt と bottom.txt を登録ページに追加する
<?php

   include("top.txt");

?>

<h1>Register for an Account:</h1>
<form action="registration_action.php" method="POST">
   
   Username: <input type="text" name="name" /><br />
   Email: <input type="text" name="email" /><br />
   Password: <input type="password" name="pword[]" /><br />
   Password (again): <input type="password" name="pword[]" /><br />
   <input type="submit" value="GO" />

</form>

<?php

   include("bottom.txt");

?>

通常はページのコンテンツを囲んでいる HTML が取り除かれて、作成した 2 つのファイルをインクルードするためのコマンドに置き換えられていることに注目してください。早速、このアクションの成果を見てみましょう。

結果

ブラウザーで登録ページに戻ると、ページの外観はかなり違って見えるはずです (図 15 を参照)。

図 15. 登録ページの新しい外観
登録ページの新しい外観

ページでソースの表示を実行すると、3 つすべてのファイルが出力にマージされていることがわかります (リスト 46 を参照)。

リスト 46. 出力にマージされた複数のファイル
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
    <title>Workflow Manager</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
  </head>
  <body>
    <div id="wrapper"><div id="bg"><div id="header"></div>
      <div id="page"><div id="container"><div id="banner"></div>
        <div id="nav1">
          <ul style='float: left'>
            <li><a href="#" shape="rect">Home</a></li>
            <li><a href="#" shape="rect">Upload</a></li>
            <li><a href="#" shape="rect">Files</a></li>
          </ul>
        </div>
        <div id="content">
          <div id="center">
<h1>Register for an Account:</h1>
<form action="registration_action.php" method="POST">

   Username: <input type="text" name="name" /><br />
   Email: <input type="text" name="email" /><br />
   Password: <input type="password" name="pword[]" /><br />
   Password (again): <input type="password" name="pword[]" /><br />
   <input type="submit" value="GO" />

</form>

          </div>
        </div>
      </div>
    </div></div></div>
  </body>
</html>

registration_action.php でも同じ変更を行ってからフォームを送信すると、この変更がすぐに反映されることを確認できます。

このページは芸術品のように美しいとは言えませんが、それでも問題ありません。後で、デザイナーに見栄えを良くしてもらうことができます。その場合、サイトのすべてのページを変更する代わりに、インクルード・ファイルを一度変更するだけで済みます。

ファイルを要求する

PHP がインターフェース・ファイルを見つけられなければ、もちろんそれは問題ですが、アプリケーションの機能だけを心配しているとしたら必ずしも大惨事ではありません。PHP は include() 関数で指定されたファイルを見つけられない場合、警告メッセージを表示してページの処理を続行します。

けれども、インクルード・ファイルを見つけることができないと大惨事になる場合もあります。例えば validate() スクリプトを別個のファイルに抜き出して、そのファイルを registration_action.php ファイルにインクルードすることができます。PHP がこのファイルを見つけられなければ、それは問題になります。このページに含まれる関数をページ内で呼び出せなくなるためです。このような問題を避けるには、include() の代わりに require() 関数を使用することができます (リスト 47 を参照)。

リスト 47. require() 関数を使用する
<?php

   include("top.txt");
require("scripts.txt");

?>

<p>You entered:</p>

<?php
   foreach ($_POST as $key=>$value) {
      echo "<p>".$key." = " . $value . "</p>";
   }

   $passwords = $_POST["pword"];
   echo "First password = ".$passwords[0];
   echo "<br />";
   echo "Second password = ".$passwords[1];

   if (validate($_POST) == "OK") {
      echo "<p>Thank you for registering!</p>";
...

この場合、PHP は必要なページを見つけられないと、致命的エラーを送信して処理を停止します。

重複を避ける

別のファイルにインクルードされるファイル自体にファイルをインクルードすることを防ぐものはありません。実のところ、これらのインクルード・ファイルが散在していると混乱した状態になり、うっかりして同じファイルを何度もインクルードしてしまう可能性があります。このような重複は、インターフェース要素が複数回出現したり、関数や定数の二重定義によってエラーが発生したりする原因になります。重複を避けるために、PHP には特殊なバージョンの include() 関数と require() 関数が用意されています。例えば、registration_action.php ファイルがインクルード・ファイルを一度だけロードすることを確実にするには、リスト 48 のようにします。

リスト 48. registration_action.php ファイルがインクルード・ファイルを一度だけロードされることを確実にする
<?php
   include_once("top.txt");
   require_once("scripts.txt");
?>

<p>You entered:</p>

<?php
...

PHP は include_once() または require_once() 関数を検出すると、そのファイルがすでにページにインクルードされていないことを確認した上で、ファイルをインクルードします。


まとめ

このチュートリアルでは、PHP を使用して Web ベースのアプリケーションを構築するプロセスを開始しました。PHP スクリプトの基本的な構文を学んだ後、その構文を使用して HTML フォームからの入力を受け入れるページを作成しました。フォームを処理する際に、変数、if-then 文、ループなどの基本的な構造を概説し、数値配列、連想配列、そしてこれらの配列のデータにアクセスする方法についても学びました。さらに、SQL 文を作成して実行することによって MySQL データベースに対してデータの保管および取得を行う方法や、各データ行を表す配列を扱う方法、さらにはインクルード・ファイルを使用する方法について学びました。

このチュートリアル・シリーズの目的は、ワークフロー・アプリケーションを構築する例を通して、PHP の使用方法を教えることです。この第 1 回で開始したアプリケーション構築プロセスでは、ユーザーが新しいアカウントを登録できるようにした後、そのアカウントをデータベースに保管しました。今後のチュートリアルでは、HTTP でのパスワード保護やその他の重要な課題を取り上げ、皆さんが PHP 開発者になるまでの道のりを支援します。


ダウンロード

内容ファイル名サイズ
Part 1 source codePHPPart1SampleFiles.zip62KB

参考文献

学ぶために

製品や技術を入手するために

  • XAMPP をダウンロードしてください。
  • PHP をダウンロードしてください。
  • MySQL をダウンロードしてください。
  • IBM 試用版ソフトウェアを使用して、開発者専用のソフトウェアを使って次のオープンソース開発プロジェクトを革新してください。IBM 試用版ソフトウェアは、ダウンロードまたは DVD で入手できます。

議論するために

  • 他の developerWorks ユーザーとのつながりを持つと同時に、開発者によるブログ、フォーラム、グループ、ウィキを調べてください。developerWorks コミュニティーで、Real world open source グループの構築を手伝ってください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Linux
ArticleID=847098
ArticleTitle=PHP の学習: 第 1 回 アカウントを登録し、承認を求めるファイルをアップロードし、承認されたファイルを表示してダウンロードする
publish-date=11292012