00メニュー > 01はじめてのMySQL > 02MySQLの基礎知識 > 03MySQLを使いこなす > 04MySQL+PHPの基礎 > 05MySQL+PHPの実践 > 06Appendix

21ちょつと実用掲示板の作成(備忘録)→ > 01p > 02p > 03p > 04p > 05p > END

05MySQL+PHPの実践

PHPを使ってMySQLへアクセスできるようになったら、今度は簡単なWebアプリケションを作ってMySQLと連携してみましよう。ここでは、PHPとMySQLと連携してみましよう。ここでは、PHPとMySQLを使って掲示板の作成、そしてインターンネットに公開するときの注意点など勉強します。
☆CHAPTER19⇒PHPとMySQLで簡単掲示板を作る
☆CHAPTER20⇒インターネットに公開するときの対策
★CHAPTER21⇒ちょつと実用掲示板の作成

★CHAPTER21⇒ちょつと実用掲示板の作成(p471)★

  ここでは、ある程度実用に耐えうる掲示板を作成します。ここまで学んだ技術の集大成です。難しい部分もあるかもしれませんが、1つ1つの記述の意味を調べて、知識を整理してみます。

(1)《ちょっと実用になる掲示板を作る p471》

ある程度実用となる「ちょっと実用掲示板」を紹介します。 コメントを入れておきますので、コードを読みながら、その意味と役割を考えて下さい。 以下のようなPHPスクリプトファイルなどで構成されます。 PHPがMySQLと連携する上で、変数は欠かすことのできない大切な役割を果たします。
c:\
\xampp
  \htdocs
    keizi_top.php----------トップページ
    keizi_.php------------スレッドごとのレス表示
    keizi_seach.php-------キーワード検索
    keizi_syokika.php------データをリセット
  \data
    db_info.php-----------データベースの各種情報
  \pic
    oya.gif---------------トップページの用の画像

●keizi_top.php

掲示板のトップページです。現在存在するスレッド名と、その作成日時を表示します。スレッド名にはハイパーリンクが設定され、クリックすると「各スレッド」ごとの一覧に飛びます。 スレッド名を入力して、新たなスレッドを作ることもできます。 また、メッセージを検索する「keizi_search.php」へのハイパーリンクもあります。

●keizi.php

スレッドごとのレスを表示します。該当するスレッドにある、すべてのレス内容(レス作成者名、メッセージ、作成日時)を表示します。表示するスレッドの、レスを投稿することができます。トップページの「スレッド一覧」(keizi_top.php)へのリンクがあります。

●keizi_search.php

キーワードを入力すると、すべてのスレッドからそのキーワードを含むメッセージを検索し、その一覧を表示します。

●keizi_syokika.php

データをリセットするためのページです。呼び出すと、利用している2つのテーブルからレコードを削除し、連続番号機能を初期化します。(AUTO_INCREMENT=0)。どこからもリンクを張らずに、単独で実行するものとします。

●db_info.php

サーバー名、ユーザー名、パスワード、データベース名が入力されている読み込み用のスクリプトファイルが、「db_info.php」ここでは、公開されない「data」ファイルに保存するものとします。 【画像 図21-1ちょっと実用掲示板構造概念図】

(1-1)<「ちょっと実用掲示板」で使う画像の準備>

この掲示板では、画像ファイル「oya.gif」を使用しています。公開されるフォルダに(ここではc\xampp\htdocs)に、コピーしておいてください。

(2)《「ちょっと実用掲示板」で使うテーブルの作成 p000》

「ちょっと実用掲示板」で使うテーブルは、次の「tbj0」「tbj1」の2つです。

(2-1)<「tbj0」(スレッドのテーブル)>

テーブル「tbj0」は、スレッドのデータを保管します。

●テーブル「tbj0」のカラム(p475_1)

カラム名⇒内容
①guru⇒スレッドのグループ番号を入力する。INT型で連続番号機能を設定し、勝手に通し番号が付くようにしている。
②sure⇒スレッド名の入力用で、データ型をVARCHAR(30)とした。
③niti⇒スレッドを作成した日時を入力する。MySQLの関数NOW()で自動的に入力する。データ型はDATETIMEにしてある。
④aipi⇒送信してきたクライアントのIPアドレスを保管する。ブラウザには表示せずに、何かあったときの記録として残しておくことにする。ここではとりあえず、20文字の文字列VARCHAR(20)を設定している。

●テーブル「tbj0」の構成(p475_2)

カラム名⇒guru⇒sure⇒niti⇒aipi
属性⇒INT⇒VARCHAR(30)⇒DATETIME⇒VARCHAR(20)
   ⇒AUTO_INCREMENT
   ⇒PRIMARY KEY

(2-2)<「tbj1」(メッセージのテーブル)>

テーブル「tbj1」は、すべてのスレッドのレスを総合的に保管します。

●テーブル「tbj1」のカラム(p475_3)

カラム名⇒内容
①bang⇒すべてのスレッドに存在するレスの通し番号を保管する。INT型で連続番号機能を設定
②nama⇒書き込みする人の氏名(ハンドル名)が入力されることを想定している。データ型はVARCHAR(30)
③mess⇒メッセージを入力する。デーだ型はTEXT
④niti⇒レコードを挿入したときの日時を入力する。テーブル「tbj0」と同様に、MySQLの関数NOW()で自動的に入力する。
⑤guru⇒グループ番号を保管する。テーブル「tbj0」に結合するときのキーとして使う。データ型はINT
⑥aipi⇒テーブル「tbj0」と同様に、送信してきたクライアントのIPアドレスを保管する。

●テーブル「tbj1」の構成(p476)

カラム名⇒bang⇒nama⇒mess⇒niti⇒guru⇒aipi
属性⇒INT⇒VARCHAR(30)⇒TEXT⇒DATETIME⇒INT⇒VARCHAR(20)
⇒AUTO_INCREMENT
   ⇒PRIMARY KEY

(3)《トップページ(スレッド作成・一覧表示)の作成 p000》

では、トップページ「keizi_top.php」を作成しましょう。
「keizi_top.php」にアクセスすると、スレッドの一覧を表示します。テキストボックスに新規スレッド名を入力してボタンをクリックすると、自分自身(keizi_top.php)を呼び出して、スレッドを作成します。また、下端のリンクから検索ページ「keizi_search.php」に行くことができます。
なお、「/**・・・**//」はコメント文になります。

(3-1)<「keizi_top.php」のリスト>

<?php
/*************** データベース情報等の読み込み ***************/
require_once("data/db_info.php");

/*************** データベースへ接続、データベース選択 ***************/
$s=mysql_connect($SERV,$USER,$PASS) or die("失敗しました");
mysql_select_db($DBNM);


/*************** タイトル、画像等の表示 ***************/
print <<<eot1
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html;charset=Shift_JIS">---→①
<TITLE>SQLカフェのページ</TITLE>
</HEAD>
<BODY BGCOLOR="lightsteelblue">
<IMG SRC="pic/oya.gif">-----②
<FONT SIZE="7" COLOR="indigo">
 SQLカフェ掲示板だよ~
</FONT>
<BR><BR>
見たいスレッドの番号をクリックしてください
<HR>
<FONT SIZE="5">
(スレッド一覧)
</FONT>
<BR>
eot1;

/*************** クライアントIPアドレス取得 ***************/
$ip=getenv("REMOTE_ADDR");

/*************** スレッドのタイトル(su)にデータがあればtbj0に挿入 ***************/
$su_d=htmlspecialchars($_GET["su"]);-----③
if($su_d<>""){
mysql_query("INSERT INTO tbj0 (sure,niti,aipi) VALUES ('$su_d',now(),'$ip')");
}

/*************** tbj0の全データ抽出 ***************/
$re=mysql_query("SELECT * FROM tbj0");
while($kekka=mysql_fetch_array($re)){
print <<<eot2
<A HREF="keizi.php?gu=$kekka[0]">$kekka[0] $kekka[1]</A>-----④
<BR>
$kekka[2]作成<BR><BR>
eot2;
}

/*************** データベース切断 ***************/
mysql_close($s);

/*************** スレッド名入力用表示、トップ等へのリンク ***************/
print <<<eot3
<HR>
<FONT size="5">
(スレッド作成)
</FONT>
<BR>
新しくスレッドを作るときは、ここでどうぞ!
<BR>
<FORM METHOD="GET" ACTION="keizi_top.php">
新しく作るスレッドのタイトル
<INPUT TYPE='text' NAME='su' SIZE='50'>-----⑤
<BR>
<INPUT TYPE="submit" VALUE="作成">
</FORM>
<HR>
<FONT SIZE="5">
(メッセージ検索)
</FONT>
<A HREF="keizi_search.php">検索するときはここをクリック</a>-----⑥
<HR>
</BODY>
</HTML>
eot3;

?>

●「keizi_top.php」リストの解説

●①<META http-equiv="Content-Type" content="text/html;charset=Shift_JIS">
ページの文字コードを設定するタグです。シフトJISに設定しています。日本語EUCを設定する場合は「charset=EUC_JP」とします。
●②<IMG SRC="pic/oya.gif">
<IMG>タグでは、画像を挿入します。SRC属性で画像ファイルの場所を指定します。

●③$su_d=htmlspecialchars($_GET["su"]);
⑤の<INPUT>タグによるテキストボックスには、新規スレッド名を入力します。この値を受け取り、変数「$su_d」に代入します。不正を防ぐため、htmlspecialchars関数を使いタグを無効化します。

●④<A HREF="keizi.php?gu=$kekka[0]">$kekka[0] $kekka[1]</A>
HREF属性で「keizi.php」へリンクに「?gu=$kekka[0]」の記述を加えます。これで、グループ番号をGETメソッドで送信で送信できます。
$kekka[0]はクエリ「SELECT * FROM tbj0」で表示されるデータの先頭カラムguru(スレッドのグループ番号)の値、また$kekka[1]は2番目のカラムsure(スレッド名)の値です。
※<A HREF="keizi.php?gu=$kekka[0]">$kekka[0] $kekka[1]</A>により、$kekka[0](グループ番号)と$kekka[1](スレッド名)が表示されます。この文字にグループ番号を付けて「keizi.php」へのリンクが設定されます。
※たとえばグループ番号3のスレッドにアクセスするときは、アドレスバーには「http://localhost/keizi.php?gu=3」と表示されます。
○スレッド一覧書き出し部分は、以下のようになります。
【画像p479】

●⑤<INPUT TYPE='text' NAME='su' SIZE='50'>

●⑥<A HREF="keizi_search.php">検索するときはここをクリック</a>

(3-2)<「keizi_top.php」の構造>

もう一度、詳しく「keizi_top.php」の構造をみてみましょう。 【省略】

(4)《スレッドごとのページ(レス入力・一覧表示)の作成 p000》

スレッドごとのメッセージを表示するページ「keizi.php」を作成します。 アクセスすると、該当のスレッドのメッセージが表示されます。下の方にあるテキストボックスに氏名とメッセージを入力してボタンをクリックすると、自分自身(keizi.php)を呼び出して、メッセージを書き込みます。 また、下端のリンクからはスレッド一覧「keizi_top.php」に行くことができます。

(4-1)<「keizi.php」のリスト>

<?php
/*************** データベース情報等の読み込み ***************/
require_once("data/db_info.php");

/*************** データベースへ接続、データベース選択 ***************/
$s=mysql_connect($SERV,$USER,$PASS) or die("失敗しました");
mysql_select_db($DBNM);

/*************** スレッドグループ番号(gu)を取得し$gu_dに代入 ***************/
$gu_d=$_GET["gu"];-----①

/*************** $gu_dに数字以外が含まれていたら処理を中止 ***************/
if(preg_match("/[^0-9]/",$gu_d)){
print <<<eot1
不正な値が入力されています<BR>
<A HREF="keizi_top.php">ここをクリックしてスレッド一覧に戻ってください</A>
eot1;

/*************** $gu_dに数字以外が含まれていない、正常な値での処理 ***************/
}elseif(preg_match("/[0-9]/",$gu_d)){

/*************** 名前とメッセージを取得してタグを削除 ***************/
$na_d= htmlspecialchars($_GET["na"]);-----①
$me_d= htmlspecialchars($_GET["me"]);

/*************** IPアドレス取得 ***************/
$ip=getenv("REMOTE_ADDR");

/*************** スレッドグループ番号(gu)に一致するレコードを表示 ***************/
$re=mysql_query("SELECT sure FROM tbj0 WHERE guru=$gu_d");-----②
$kekka=mysql_fetch_array($re);

/*************** スレッド内容の表示文字列$sure_comを作成 ***************/
$sure_com="「".$gu_d." ".$kekka[0]."」";-----③

/*************** スレッド表示のタイトル等書き出し ***************/
print <<<eot2
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html;charset=Shift_JIS">-----④
<TITLE>SQLカフェ $sure_com スレッド</TITLE>
</HEAD>
<BODY BGCOLOR="darkgray">
<FONT SIZE="7" COLOR="indigo">
$sure_com スレッド!
</FONT>
<BR><BR>
<FONT SIZE="5">
$sure_com のメッセージ
</FONT>
<BR>
eot2;

/*************** 名前($na_d)が入力されていればtbj1にレコード挿入 ***************/
if($na_d<>""){
mysql_query("INSERT INTO tbj1 VALUES (0,'$na_d','$me_d',now(),$gu_d,'$ip')");-----⑤
}

/*************** 水平線表示 ***************/
print "<HR>";


/*************** 日時の順にレスデータを表示 ***************/
$re=mysql_query("SELECT * FROM tbj1 WHERE guru=$gu_d ORDER BY niti");


$i=1;
while($kekka=mysql_fetch_array($re)){

print "$i($kekka[0]):<U>$kekka[1]</U>:$kekka[3] <BR>";
print nl2br($kekka[2]);-----⑥
print "<BR><BR>";
$i++;
}

/*************** データベース切断 ***************/
mysql_close($s);

print <<<eot3
<HR>
<FONT SIZE="5">
$sure_com にメッセージを書くときはここにどうぞ
</FONT>
<FORM METHOD="GET" ACTION="keizi.php">
名前 <INPUT TYPE="text" NAME="na"><BR>
メッセージ<BR>
<TEXTAREA NAME="me" ROWS="10" COLS="70"></TEXTAREA>-----⑦
<BR>
<INPUT TYPE="hidden" NAME="gu" VALUE=$gu_d>-----⑧
<INPUT TYPE="submit" VALUE="送信">
</FORM>
<HR>
<A HREF="keizi_top.php">スレッド一覧に戻る</A>
</BODY>
</HTML>
eot3;

/*************** $gu_dに数字以外も、数字も含まれていないときの処理 ***************/
}else{
print "スレッドを選択してください。<BR>";
print "<A HREF='keizi_top.php'>ここをクリックしてスレッド一覧に戻ってください</A>";
}

?>

「keizi.php」リストの解説

●①$gu_d=$_GET["gu"];
すべてのレスを保管するテーブル「tbj1」のカラム「guru」「nama」「mess」の各データが「gu」「na」「me」の「データを識別する名前」でGET送信されます。
これを「$gu_d=$_GET["gu"]」などで受け取り、「$gu_d」などの変数に代入します。
トップページの「keizi_top.php」からも、guの「データを識別する名前」でGET送信されたデータを受け取っています。
氏名(na)とメッセージ(me)は、不正入力を防ぐため、htmlspecialchars関数を使ってを無効化しています。
●②$re=mysql_query("SELECT sure FROM tbj0 WHERE guru=$gu_d");
「$gu_d」は、スレッドのグループ番号です。テーブル「tbj0」から送られてきたグループ番号に一致するスレッド名(カラム「sure」)を表示するSQL文を発行します。

●③$sure_com="「".$gu_d." ".$kekka[0]."」";
「.$gu_d」はグループ番号、「$kekka[0].」は②のカラム「sure」のスレッド名です。
この2つを「.」で結合した文字列が「$sure_com」です。

●④<META http-equiv="Content-Type" content="text/html;charset=Shift_JIS">
文字コードを設定する<META>タグです。「シフトJIS」を設定します。日本語EUCを設定する場合、「charset=EUC-JP」とします。

●⑤mysql_query("INSERT INTO tbj1 VALUES (0,'$na_d','$me_d',now(),$gu_d,'$ip')");
レスを保管するテーブル「tb1」の各カラム「bang」「nama」「mess」「niti」「guru」「aipi」に、それぞれ「0」、氏名($na_d)、メッセージ($_me_d)、現在の日時(now())、グループ番号($gu_d)、IPアドレス($ip)を入れます。AUTO_INCREMENTが設定してある「bang」では、「0」を入れると連続番号が自動で入力されます。

●⑥print nl2br($kekka[2]);
「$kekka[2]」は、テキストエリアに入力されたメッセージの内容です。この文字列に改行が入っている場合は、実際の表示も改行させるのが「nl2br」関数です。

●⑦<TEXTAREA NAME="me" ROWS="10" COLS="70"></TEXTAREA>
「<TEXTAREA>~</TEXTAREA>」は、テキストエリアを設定するタグです。NAMEで「データを識別する名前」を、「ROWS」で改行、「COLS」で1行の文字数を設定します。
テキストエリア内での改行には「nl2br」関数を使って改行タグを入れます。

●⑧<INPUT TYPE="hidden" NAME="gu" VALUE=$gu_d>
タイプ属性に「hidden」を指定した場合、ブラウザには何も表示されませんが、VALUE属性で指定された値が送信されます。この例では、「gu」という「データ識別のための名前」で、「$gu_d」の値(グループ番号)が自動的に送信されます。

(4-2)<「keizi.php」の構造>

もう一度詳しく「keizi.php」の構造を見て見ましょう。 《省略》

(5)《メッセージの検索ページの作成 p492》

すべてのスレッドの全メッセージから、キーワードを検索するページ「keizi_search.php」です。テキストボックスにキーワードを入力してボタンをクリックすると自分自身(keizi_search.php)を呼び出して検索を実行し、抽出したレコードを表示します。また、下端のリンクからはスレッド一覧「keizi_top.php」に戻ることができます。

(5-1)<「keizi_search.php」のリスト>

<?php
/*************** データベース情報等の読み込み ***************/
require_once("data/db_info.php");

/*************** データベースへ接続、データベース選択 ***************/
$s=mysql_connect($SERV,$USER,$PASS) or die("失敗しました");
mysql_select_db($DBNM);

/*************** タイトル等の表示 ***************/
print <<<eot1
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html;charset=Shift_JIS">-----①
<TITLE>SQLカフェ 検索のページ</TITLE>
</HEAD>
<BODY BGCOLOR="orange">
<HR>
<FONT SIZE="5">
(検索結果はこちらに)
</FONT>
<BR>
eot1;

/*************** 検索文字列を取得してタグを削除 ***************/
$se_d=htmlspecialchars($_GET["se"]);-----②

/*************** 検索文字列($se_d)にデータがあれば検索処理 ***************/
if($se_d<>""){

/*************** 検索のSQL文 テーブルtbj1にtbj0を結合 ***************/
$str=<<<eot2
SELECT tbj1.bang,tbj1.nama,tbj1.mess,tbj0.sure-----③
FROM tbj1
JOIN tbj0
ON
tbj1.guru=tbj0.guru
WHERE tbj1.mess LIKE "%$se_d%"
eot2;

/*************** 検索クエリを実行 ***************/
$re=mysql_query($str);
while($kekka=mysql_fetch_array($re)){
print " $kekka[0] : $kekka[1] : $kekka[2] ( $kekka[3] )";
print "<BR><BR>";
}
}

/*************** データベース切断 ***************/
mysql_close($s);

/*************** 検索文字列入力用表示、トップへのリンク ***************/
print <<<eot3
<HR>
メッセージに含まれる文字を入力してください!
<BR>
<FORM METHOD="GET" ACTION="keizi_search.php">
検索する文字列
<INPUT TYPE="text" NAME="se">
<BR>
<INPUT TYPE="submit" VALUE="検索">
</FORM>
<BR>
<A HREF="keizi_top.php">
スレッド一覧に戻る
</A>
</BODY>
</HTML>
eot3;
?>

「keizi_search.php」リストの解説

●<META http-equiv="Content-Type" content="text/html;charset=Shift_JIS">
文字コードを設定する<META>タグです。「シフトJIS」を設定しています。日本語EUCを設定する場合、「charset=EUC-JP」としてください。
●$se_d=htmlspecialchars($_GET["se"]);
「se」の「データを識別する名前」で送られてきた検索のキーワードを受け取り、変数「$se_d」②代入します。

●SELECT tbj1.bang,tbj1.nama,tbj1.mess,tbj0.sure~WHERE tbj1.mess LIKE "%$se_d%"
レスの番号、氏名、メッセージ、スレッド名を、テーブル「tbj1」に「tbj0」を結合させて検索します。結合キーは、2つのテーブルのグループ番号「guru」です。
変数「$se_d」は検索のキーワードで、この前後に「%」を付けると、このキーワードを含むメッセージをすべて検索します。

(5-2)<「keizi_search.php」の構造>

《詳細省略》

(6)《データベース情報読み込み元ファイルの作成 p497》

サーバー名、ユーザー名、パスワード、データベース名が入力されているファイル「db_info.php」です。自分の利用する形に適宣データを変更してください。ここでは公開されない「data」フォルダに保存するものとします。

■db_info.php

<?php
$SERV="localhost";
$USER="root";
$PASS="1234";
$DBNM="db1";
?>

(7)《データリセット用ページの作成 p497》

データをリセットする仕組みも作っておきましょう。次のスクリプトは、テーブル「tbj0」および「tbj1」のすべてのレコードを削除し、「AUTO_INCREMENT」をセットするものです。

(7-1)<「keizi_syokika.php」のリスト>

■keizi_syokika.php

<?php
require_once("data/db_info.php");
$s=mysql_connect($SERV,$USER,$PASS) or die("失敗しました");
mysql_select_db($DBNM);

mysql_query("DELETE FROM tbj0");
mysql_query("DELETE FROM tbj1");
mysql_query("ALTER TABLE tbj0 AUTO_INCREMENT=0");
mysql_query("ALTER TABLE tbj1 AUTO_INCREMENT=0");

print "SQLカフェのテーブルを初期化しました";

mysql_close($s);

?>

(7-2)<「keizi_syokika.php」の構造>

詳細省略

<まとめ>

●簡易掲示板システムの構成
●スレッドを処理する機能
●レスを処理する機能
●簡易掲示板の最低限のセキュリティ対応

<チェック>

□keizi_top.phpを中心とした掲示板システムの構造を理解している
□keizi_top.phpの処理手順を理解している
□keizi_search.phpの処理手順を理解している
□テーブル「tbj0」および「tbj1」を初期化する手順を理解している

<練習問題>

問題1
次のPHPスクリプトを作成します。

■「keizi_kanri.ph」

<?php
/*************** データベース情報等の読み込み ***************/
require_once("data/db_info.php");

/*************** データベースへ接続、データベース選択 ***************/
$s=mysql_connect($SERV,$USER,$PASS) or die("失敗しました");
mysql_select_db($DBNM);

/*************** テーブルtbj1をSELECT ***************/
$re=mysql_query("SELECT * FROM tbj1 ORDER BY niti");

/*************** クエリの結果書き出し ***************/
$i=1;
while($kekka=mysql_fetch_array($re)){
print "$i($kekka[0]):$kekka[1]:$kekka[3] GP:$kekka[4] IP:$kekka[5]<BR>";
print nl2br($kekka[2]);
print "<BR><BR>";
$i++;
}

/*************** データベース切断 ***************/
mysql_close($s);
?>

【実行結果】

未処理