システム作成 - PHP入門
目次
- PHP入門
- PHPの概要
- PHP環境のインストール(XAMPP)・PHPの設定
- PHPの基本・簡単なプログラム
- 文法1
- 文法2
- 様々な関数を使う
- フォームの基本
- システム作成
- オブジェクト指向
- データベースとSQL
- PHPでMySQLを使う
- ブログを作る
- ECサイト(ショッピングサイト)を作る
このページの内容
はじめに
PHPでウェブの仕事をする際に、1ページで終わる仕事はほとんどありません。通常は複数のページを有機的に組み合わせて、ひとつの大きなシステムとして構築して行きます。この章ではそのようなシステム作成に役立つ技術を解説して行きます。その後、システムの例として会員制サイトを作成します。require文
require文を使うと、その場にパラメータで指定したファイルを挿入することができます。挿入するファイルはHTMLでもPHPでも構いません。require文のサンプルプログラム
以下のプログラムは、echoで「こんにちは」と表示した直後にrequire文によってrequire1b.phpの内容を挿入しています。require1.php
<?php
echo "こんにちは";
require "require1b.php";
?>
require1b.php
<?php
echo "山田さん";
?>
require文を使うと、ウェブサイトで共通な部分、例えばヘッダやフッタ、サイドバーなどを一度書くだけで全ページに適用する、といったことが出来ます。require文と似たようなはたらきの「include」文もあります。違いは、指定したファイルが存在しなかった場合、include文は動作を続行しますが、require文はそこで止まります。
ウェブサイトのパーツを共通化する
次に、require文を使ってウェブサイトのパーツを共通化するサンプルをひとつ作成してみましょう。以下のソースは、「require2_1.php」と「require2_2.php」の2つのページをリンクによって行き来できます。require2_1.php
<?php require "require2_header.php" ?>
ページ1<br><br>
<a href="require2_2.php">ページ2へ</a>
<?php require "require2_footer.php" ?>
require2_2.php
<?php require "require2_header.php" ?>
ページ2<br><br>
<a href="require2_1.php">ページ1へ</a>
<?php require "require2_footer.php" ?>
require2_header.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>複数ページサンプル</title>
<style>
#header, #footer {
background-color: #fed;
height: 50px;
font-size: 30px;
}
#main {
background-color: #eee;
}
</style>
</head>
<body>
<div id="header">ヘッダ</div>
<div id="main">
require2_footer.php
</div>
<div id="footer">フッタ</div>
</body>
</html>
両方のページでヘッダ部分(require2_header.php)とフッタ部分(require2_footer.php)をrequire文によって取り込んでいます。これにより、ヘッダ部分とフッタ部分を共通化することができ、ページを増やしても同じヘッダとフッタをすぐに適用できます。また、ヘッダやフッタの変更が入っても、一箇所だけの変更で済みます。ヘッダ部分では、前章までは省略していたDOCTYPE宣言やhtmlタグ、headタグ、bodyタグも追加して正しいHTML文書にしています。
複数ページの場合、スタイルシートは外部CSSにして共通化することが多いのですが、このようにrequire文で共通化することも(あまりやりませんが)できます。
ページのソースを見て、require文による取り込みが働いているか確認してみましょう。
システム全体の共通ファイルを使う
次に、require文の典型的な使い方をもうひとつ試してみましょう。システム全体で使う関数や変数をひとつのファイルに定義しておき、複数のソースからそのファイルをrequire文で取り込んで使うのです。
require3_common.php
<?php
define("BASE_DIR", "http://localhost/php/");
function h($str) {
return htmlspecialchars($str, ENT_QUOTES);
}
?>
require3_1.php
<?php
require "require3_common.php";
echo h("<h1>見出し</h1>");
echo "<br>";
echo BASE_DIR . 'pic1.jpg';
?>
require3_2.php
<?php
require "require3_common.php";
echo h("<p>段落</p>");
echo "<br>";
echo BASE_DIR . 'pic2.jpg';
?>
このプログラムでは、共通ファイルが「require3_common.php」になり、定数BASE_DIRと関数hを定義しています。関数hは、htmlspecialchars関数を呼び出してその結果を返す関数です。htmlspecialchars関数はとてもよく使うのですが、名前が長いので短くし、ついでに第2引数にENT_QUOTESも設定して安全性を高めています。このような既存の関数をくるんで(ラップ)使いやすくする関数を「ラッパー関数」と言う場合もあります。
もうひとつ、BASE_DIRという定数を定義しています。開発中と本番で環境が変わることは良くあります。例えば開発中の画像の置き場所が「http://localhost/php/」で、本番では「http://example.com/php/」だった場合、もし画像をフルパスで指定していた場合は、全てのソースファイルを検索して本番用に書きなおさなければなりません。そこでこのようにBASE_DIRという定数を作って、画像を参照するときは必ずこの定数を介すようにすれば、本番環境でもBASE_DIRの値のみを書き換えれば全てのソースに反映されるわけです。
クッキー
クッキーとは、ウェブサーバ側からクライアント(ブラウザ)に送られる任意のデータで、一定時間クライアント側で保存されます。会員制のサイトで「一週間ログインしたままにする」などの機能はクッキーで実現しています。クッキーはsetcookie関数を使い、第1引数にクッキー名、第2引数に保存する値、第3引数に有効期限を書きます。有効期限はUnixタイムスタンプ秒で設定します。例えば「time() + 60」ならば現在時刻から一分後に有効期限が切れてクッキーが削除されます。
クッキーにセットされた値はスーパーグローバル変数「$_COOKIE」に配列形式で入ります。$_COOKIE[クッキー名]で値が取得できます。
クッキーのサンプルプログラム
以下のプログラムはクッキーを使ったサンプルです。cookie1.phpを一度だけ開いて、その後cookie1b.phpを何度か開いてみてください。60秒経ったらクッキーが削除されてメッセージが変わります。cookie1.php
<?php
setcookie('men', 'うどん', time() + 60);
echo "クッキーをセットしました。";
?>
cookie1b.php
<?php
if (isset($_COOKIE['men'])) {
echo "クッキーは{$_COOKIE['men']}です。";
} else {
echo "クッキーはセットされていません。";
}
?>
cookie1.phpでは、setcookie関数で名前「men」のクッキーに「うどん」という値を、現在時刻+60秒後までを有効期限としてセットしています。cookie1b.phpでは、isset関数でクッキー「men」が存在するか調べ、存在していたらクッキーの値を表示しています。isset関数は、引数で指定した変数が存在するかどうか調べる関数です。
正規表現
会員登録ページなどを作る際、フォームに書かれた値が正しいかチェックする必要があります。文字をひとつひとつするのは大変なので、一気にチェックしてくれる「正規表現」という便利な書式があります。ここでは少し正規表現について学んで行きましょう。入力文字列が整数かどうかをチェックする
以下のプログラムは、テキストボックスに書かれた文字が整数かどうかチェックします。regex1.php
<form action="regex1.php" method="post">
整数を入力してください
<input type="text" name="num">
<input type="submit">
</form>
<?php
if (isset($_POST['num'])) {
if (preg_match('/\D/', $_POST['num'])) {
echo "整数ではありません。";
} else {
echo "整数です。";
}
}
?>
「preg_match」関数は、第1引数で指定した正規表現の「パターン」に従って第2引数の文字列をチェックし、文字列がパターンに該当すれば(「マッチ」と言います)、TRUEを返します。正規表現パターンは「/」で挟みます。他の文字列でも構いませんが、「/」が多く使われます。「\D」は、「数値以外の文字が1文字」という意味です。つまり、POSTされた文字列に数値以外の文字が1文字でもあればマッチし、「整数ではありません」と表示されます。
ただ、右のプログラムは、マイナスの数でも整数ではないと判断されて正確ではありません。その場合、パターンを「/[^-\d]/」と変更してください。[^…]は中に書かれた文字のどれとも等しくないもの、という意味です。\dは数値です。つまりこのパターンは「マイナス記号または数値以外の1文字」にマッチします。
郵便番号・電話番号・メールアドレスをチェックする
以下のプログラムは、郵便番号と電話番号とメールアドレスをチェックして、正しければメッセージを表示します。regex2.php
<form action="regex2.php" method="post">
郵便番号 <input type="text" name="zip"><br>
電話番号 <input type="text" name="tel"><br>
e-mail <input type="text" name="mail"><br>
<input type="submit" name="submit">
</form>
<?php
if (isset($_POST['submit'])) {
if (preg_match('/^\d{3}-\d{4}$/', $_POST['zip'])) {
echo "郵便番号です。<br>";
}
if (preg_match('/^0\d{1,4}-\d{1,4}-\d{4}$/', $_POST['tel'])) {
echo "電話番号です。<br>";
}
if (preg_match('/^.+@.+\..+$/', $_POST['mail'])) {
echo "たぶんメールアドレスです。<br>";
}
}
?>
if (preg_match('/^\d{3}-\d{4}$/', $_POST['zip'])) {
郵便番号をチェックしている部分です。最初の「^」は文字列の先頭を表し、最後の「$」は文字列の最後を表します。「\d」は数値、「{n}」は直前の文字のn文字の繰り返しになります。まとめると「先頭から、数値3文字、次にハイフン、次に数値4文字で終わる文字列」にマッチします。
if (preg_match('/^0\d{1,4}-\d{1,4}-\d{4}$/', $_POST['tel'])) {
電話番号をチェックしている部分です。「{n, m}」は「直前の文字のn文字以上m文字以下」にマッチします。まとめると「先頭から、ゼロ、次に数値が1~4文字、次にハイフン、次に数値が1~4文字、次にハイフン、次に数値4文字で終わる文字列」にマッチします。
if (preg_match('/^.+@.+\..+$/', $_POST['mail'])) {
メールアドレスをチェックしている部分です。メールアドレスの厳密なチェックはとても難しいので、簡単な判断にしています。「.」は任意の文字1文字にマッチします。「+」は直前の文字の1文字以上です。「\.」は、ドットそのものです。ドットが正規表現で特別な意味を表すので、ドットそのものを表す場合はこのようにエスケープします。まとめると「先頭から、任意の文字が1文字以上、次にアットマーク、次に任意の文字が1文字以上、次にドット、次に任意の文字が1文字以上で終わる文字列」にマッチします。メール送信
お問い合わせフォームや、商品購入後の通知など、メールの機能を使うシステムも数多くあります。この節ではPHPからメールを送信する方法について解説します。Mercuryメールサーバ
今回はXAMPPに搭載されているメールサーバ「Mercury/32」を使ってメール送信を行ってみましよう。XAMPP Control PanelからMercuryの行の「Start」ボタンを押してメールサーバを起動してください。メール送信のテストプログラム
メール送信テストを行うプログラムを以下に示します。mail1.php
<?php
$from = "newuser@localhost";
$to = "newuser@localhost";
$subject = "メールテスト";
$body = "メールテストです。\nメールテストです。";
mb_send_mail($to, $subject, $body, "From: $from");
?>
$fromに送信元のメールアドレス、$toに送信先のメールアドレスを入れます。Mercuryのデフォルトで仮のユーザー「newuser」が作成されているのでそれを使います。メールサーバはローカルで動いているので@の後ろは「localhost」になります。$subjectにはメールの件名、$bodyには本文を入れます。mb_send_mailは日本語でメールを送る関数です。第1引数に送信先、第2引数に件名、第3引数に本文、第4引数に追加ヘッダを指定します。追加ヘッダに「From: 送信元のメールアドレス」を追加すると送信元のメールアドレスを指定できます。
実行すると画面には何も表示されませんが、メールは送られます。送信されたメールは、「C:\xampp\MercuryMail\MAIL\newuser」フォルダに拡張子「CNM」のファイルとして保存されます。テキストエディタで開いて確認してみてください。
受信メール確認
Received: from spooler by localhost (Mercury/32 v4.62); 9 Jun 2011 12:50:41 +0900
X-Envelope-To: <newuser@localhost>
Return-path: <newuser@localhost>
Received: from naga-PC (127.0.0.1) by localhost (Mercury/32 v4.62) ID MG000001; 9 Jun 2011 12:50:33 +0900
Date: Thu, 09 Jun 2011 05:50:33 +0200
Subject: =?ISO-2022-JP?B?GyRCJWEhPCVrJUYlOSVIGyhC?=
To: newuser@localhost
From: newuser@localhost
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit
メールテストです。
メールテストです。
受信(POP3)の設定
MercuryはPOP3サーバも起動するので、送られたメールをメールソフトで受信することもできます。メールソフトの設定を以下のようにするとメールを受け取ることができます。POP3サーバ | localhost(または 127.0.0.1) |
メールアドレス | newuser@localhost |
アカウント名 | newuser |
パスワード | wampp |
このように受信されます。
送信ができない場合
送信がうまく行かない場合は、XAMPP Control PanelからMercuryの行の「Admin」ボタンを押してMercuryのウインドウからログを確認してください。必要なウインドウは、「Mercury SMTP Server」と「Mercury Core Process」の2つです。また、メニューの「Configuration」から「Manage local users」を選ぶと、メールを送受信するユーザーを追加・削除・修正することができます。
ローカルではなく、外にメール配信をしたい場合は、php.iniの
SMTP = localhost
の行の値を変更してメールサーバのアドレスを指定してください。ページ間データの受け渡し(隠しフィールド)
ウェブページは「HTTP」というプロトコル(送受信の取り決め)によって送られます。HTTPはページ単位のプロトコルなので、PHPの変数は違うページに行くと消えてしまいます。なので複数ページでデータをやり取りする場合は特別な仕組みが必要です。GET/POSTメソッドによる受け渡し
2ページ間だけのデータならば、フォームによるGETまたはPOSTメソッドによって受け渡すことができます。以下のプログラムは、今までに何度が出てきたパターンですが、POSTメソッドによって2ページ目にテキストボックスのデータを送信しています。
pagedata1.html
<form action="pagedata1b.php" method="post">
お名前 <input type="text" name="namae">
<input type="submit">
</form>
pagedata1b.php
<?php
$namae = htmlspecialchars($_POST['namae']);
echo "$namae さんですね。";
?>
隠しフィールドによる受け渡し
しかし実際のシステムでは2ページで終わり、ということはほとんどありません。2ページ目には確認ページをはさみ、3ページ目以降で確定することが多いでしょう。その場合、2ページ目から3ページ目へは、フォームのデータが送られませんので、データを渡すことができません。そのようなときに使える手法として「隠しフィールド」があります。では途中に確認ページをはさんだ例を示します。
pagedata2.html
<form action="pagedata2b.php" method="post">
お名前 <input type="text" name="namae">
<input type="submit">
</form>
pagedata2b.php
<?php
$namae = htmlspecialchars($_POST['namae']);
echo "本当に{$namae}さんですか?";
?>
<form action="pagedata2c.php" method="post">
<input type="hidden" name="namae" value="<?php echo $namae ?>">
<input type="submit" value="そうです">
</form>
pagedata2c.php
<?php
$namae = htmlspecialchars($_POST['namae']);
echo "{$namae}さんですね。";
?>
このソースでは、入力フォーム(pagedata2.html)から確認ページ(pagedata2b.php)へはPOSTデータ「namae」が渡されるので、$_POST['namae']を参照して確認ページでそれを表示することができます。しかし、3ページ目の確定ページ(pagedata2c.php)へはPOSTデータ「namae」が渡されないので、pagedata2b.phpのフォーム内に
<input type="hidden" name="namae" value="<?php echo $namae ?>">
このように隠しフィールド(hidden)を作り、nameを「namae」、valueにテキストボックスから渡されたデータを入れて、3ページ目にもデータを渡すことができるようにしています。2ページ目に記述された$_POST['namae']はテキストボックスから渡された値、3ページ目に記述された$_POST['namae']は隠しフィールドから渡された値であることに注意してください。
ページ間データの受け渡し(セッション)
隠しフィールドによるデータのやり取りは、フォーム部品が多くなるとそれだけ隠しフィールドが増えてしまって煩雑になります。PHPには「セッション」という、変数のように簡単にデータをやり取りする仕組みが備わっています。以下のプログラムは、セッションを使った簡単なページ間データやり取りの例です。
session1.php
<?php
session_start();
$_SESSION['men'] = 'うどん';
echo "セッション変数menに「{$_SESSION['men']}」をセットしました。<br>";
?>
<a href="session1b.php">次ページへ</a>
session1b.php
<?php
session_start();
echo "セッション変数menの値は「{$_SESSION['men']}」です。";
?>
セッションを使うページでは、最初に「session_start」関数を呼び出してセッションを開始する必要があります。php.iniの「session.auto_start」を1にしてセッションを自動的に開始することもできます。セッションの開始したページでは、スーパーグローバル変数「$_SESSION」を参照してセッション変数の読み書きができます。上記プログラムでは$_SESSION['men']にデータを代入して、次のページで読み出しています。
セッションは、通常ブラウザが閉じられるまで有効です。php.iniの「session.cookie_lifetime」の値を変更してセッションの有効期限を変えることもできます。
会員制サイトの作成
ここまで学んだ機能を用いて、認証ページのある会員制サイトを作成してみましょう。以下の6つのソースを、phpフォルダの配下にmemberフォルダを作ってそこに格納してください。ブラウザで「http://localhost/php/member/」を開くとサイトが立ち上がります。
member/index.php
<?php
session_start();
$page = @$_GET['p'];
if (!$page) $page = 'top';
if (!preg_match('/^[a-z]{1,8}$/', $page)) exit();
if (!isset($_SESSION['name'])) {
$page = 'login';
if (isset($_POST['id'])) {
if ($_POST['id'] == 'tanaka' && $_POST['pw'] == 'tanaka') {
$_SESSION['name'] = '田中';
$page = 'top';
}
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>秘密倶楽部</title>
<style>
h1 {
margin: 0;
}
#header, #footer {
background-color: #fed;
height: 60px;
padding: 10px;
}
#main {
background-color: #eee;
padding: 10px;
}
</style>
</head>
<body>
<div id="header">
<h1>秘密倶楽部へようこそ</h1>
</div>
<div id="main">
<?php
require "$page.php";
?>
</div>
<div id="footer">
<a href="?p=top">トップページ</a> |
<a href="?p=party">秘密のパーティー</a> |
<a href="?p=journey">秘密のジャーニー</a> |
<a href="?p=logout">ログアウト</a>
</div>
</body>
</html>
member/login.php
<form action="index.php" method="post">
ID<br><input type="text" name="id"><br>
パスワード<br><input type="password" name="pw"><br>
<input type="submit" value="送信">
</form>
member/top.php
<?php echo $_SESSION['name'] ?>さん、秘密倶楽部へようこそ!
member/party.php
<?php echo $_SESSION['name'] ?>さん、ここは秘密のパーティーページです。
member/journey.php
<?php echo $_SESSION['name'] ?>さん、ここは秘密のジャーニーページです。
member/logout.php
<?php
$_SESSION['name'] = null;
?>
ログアウトしました。
今回は仮に「田中」さんのみの会員情報を作っています。ログイン画面が立ち上がったら、ID、パスワード共「tanaka」でログインしてください。ブラウザを開いている間はフッタから会員ページを自由に行き来できるようになります。index.phpの解説
全てのページはindex.phpを経由し、各ページの名前はGETパラメータ「p」で判別するようになっています。
$page = @$_GET['p'];
if (!$page) $page = 'top';
ページ名を取得して$pageに代入しています。ページ名が無い場合は「top」を代入します。
if (!preg_match('/^[a-z]{1,8}$/', $page)) exit();
ページ名が正しいものかチェックしています。この正規表現パターンは「アルファベットの小文字1~8文字」にマッチします。GETパラメータは簡単に改ざんされてしまうので、ここでチェックしているのです。
if (!isset($_SESSION['name'])) {
$page = 'login';
ログイン中かどうかのチェックをしています。今回はセッション変数nameが設定されていればログイン中だと見なしています。ログイン中でなければ$pageに「login」を代入してログインページに飛ぶようにします。
if (isset($_POST['id'])) {
if ($_POST['id'] == 'tanaka' && $_POST['pw'] == 'tanaka') {
$_SESSION['name'] = '田中';
$page = 'top';
}
}
このif文の条件が満たされるのは、ログインフォームでIDとパスワードを書いたときです。IDとパスワードが「tanaka」に一致していれば、セッション変数nameを設定し、$pageに「top」を代入してトップページに飛ぶようにします。
require "$page.php";
ここでページ名に対応するPHPを取り込んでいます。
<a href="?p=top">トップページ</a> |
<a href="?p=party">秘密のパーティー</a> |
<a href="?p=journey">秘密のジャーニー</a> |
<a href="?p=logout">ログアウト</a>
各ページへのリンクです。「?p=top」は「index.php?p=top」の省略形です。