PHP実習:ひとこと掲示板を作ろう
昨夜はストレスの赴くまま、久しぶりに引っ張り出した「Horizon Zero Dawn」をずっとやっておりました…。敵を誘い出して罠にはめていくの楽しい…。
今日は第11章のまとめとしてひとこと掲示板を作る。その前に…
第11章-04
まとめの前準備として、関数のみを分離したファイルを作成しておく。
ファイル名は「functions.php」とし、以下のコードを書いていく。
<?php
function html_escape($word){
//クライアントからフォームへの入力値を出力する場合、必ず行う処理
return htmlspecialchars($word,ENT_QUOTES,'UTF-8');
}function get_post($key){
//POSTデータ取得用
if (isset($_POST[$key])) {
$var=trim($_POST[$key]);
return $var;
}
}function check_words($word,$length){
//空文字 or 文字数が制限よりも多かった場合はFalseを返す
if(mb_strlen($word)===0){
return FALSE;
} elseif(mb_strlen($word)>$length){
return FALSE;
} else{
return TRUE;
}
}function get_db_connect(){
// MySQL接続用関数
try{
$dsn='mysql:dbname=board;host=localhost;charset=utf8'
$user='root';
$password='';
$dbh=new PDO($dsn,$user,$password);
} catch(PDOExeption $e){
echo ($e->getMessage());
die();
}
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
return $dbh;
}
これを作って使うファイルで読み込みを行えば、データベースの接続も「$dbh=get_db_connect();」とだけ書けば済むようになる。
第11章ー05
いよいよひとこと掲示板を作る実習に入る。「名前」「ひとこと」「日時」が書き込めるようにし、日時については自動取得する。制作の流れは以下の通り。
- ひとことを登録するテーブル(board)を作る
- 関数ファイルを読み込み、HTMLファイルも別に分ける
- フォームにはバリデーションをつけ、文字数に問題があった場合はエラーを出す
要件定義は以下の通り。
- 名前欄は50文字まで、コメント欄は200字まで、どちらも入力必須
- フォームからのデータ挿入時にはbindValue()を使う
- 入力データを出力するときは、先ほど作ったhtml_escape()を使う
まず、MySQLでテーブルを作成する。
だいぶ手順を忘れているので、今回はデータベースから分けることにした。
MySQL起動
mysql -u root
データベース作成
create database board;
ユーザー設定
grant all on board.* to vagrant@localhost identified by 'abc123';
データベースへ入る
use board;
テーブル作成
create table board(
id int not null auto_increment primary key,
name varchar(50),
comment text,
created datetime
);
データ型でtextを指定した場合、文字数が無制限になる。今回はPHP側でバリデーションをかける。投稿日時を記録するためのフィールドを「created」としたが、これはデータ型をdatetimeと指定している。「0000-00-00 00:00:00」という形で文字列を挿入しないとエラーになるので注意。
次に、先ほど用意したfunctions.phpに新しい関数を追2つ追加する。
function insert_comment($dbh,$name,$comment){
//Insertクエリ実行
$date=date('Y-m-d H:i:s');
$sql="INSERT INTO board (name,comment,created) values (:name,:comment,'{$date}')";
$stmt=$dbh->prepare($sql);
$stmt->bindvalue(':name',$name,PDO::PARAM_STR);
$stmt->bindvalue(':comment',$comment,PDO::PARAM_STR);
if (!$stmt->execute()) {
return 'データの書き込みに失敗しました。';
}
}
これはコメントを書き込む関数である。データベース接続時に取得した$dbh(切符)を必ず渡すこと。$nameと$commentはPOSTデータを取得後に渡すものである。現在日時取得はデータベースに合わせ、「Y-m-d H:i:s」とすれば「0000-00-00 00:00:00」の形で取得できる。$dateはクライアントからの入力値ではないため、そのまま連結させることが可能。
function select_comments($dbh){
$data=;
$sql="SELECT name,comment,created FROM board";
$stmt=$dbh->prepare($sql);
$stmt->execute();
while ($row=$stmt->fetch(PDO::FETCH_ASSOC)) {
$data=$row;
}
return $data;
}
データを取得する関数である。先ほどと同じく、$dbhを渡す。「select * from ~」と書くことにより、少しではあるがデータベースへの負担を軽くする。$dataは二次元配列、そのままreturnする。
ここから正式なサービスへ近づけていく。まずはindex.phpを作成し、functions.phpを組み込む。
<?php
// 関数ファイルを読み込む
repuire_once('./functions.php');
// ここに処理の流れを書く
// HTMLファイル読み込み
include_once('view.php');
view.phpも空白でいいので作成しておく。view.phpにはHTMLを記述していくが、echoなども使うのでPHPファイルとして作成しておく。
require_once()とinclude_once()はともにファイルを読み込むコードだが、require_once()は読み込んだ途中のコードにエラーがあっても処理を続行し、include_once()はエラーがあれば処理が止まるという違いがある。
ここで処理の流れを確認。
- データベースに接続
- フォームのデータを取得してバリデーション
- データを挿入
- データベースから表示用のデータを引き出す
- 出力
特に3と4が逆にならないよう注意が必要である。
index.phpにデータベース接続のための処理を書いていく。
repuire_once('./functions.php');
$errs=; //エラー文格納用の配列初期化
$data=; //データベースから引き出すデータの格納用配列
$dbh=get_db_connect(); //データベース接続
前はかなり長かったが、今回からはすっきり。
次に、入力値の検証とデータ挿入の処理を作成する。
$dbh=get_db_connect(); //データベース接続
if ($_SERVER['REQUEST_METHOD']==='POST') {
$name=get_post('name');
$comment=get_post('comment');
if (!check_words($name,50)) {
$errs='お名前欄を修正してください。';
}
if (!check_words($comment,200)) {
$errs='コメント欄を修正してください。';
}
if (count($errs)===0) {
$result=insert_comment($dbh,$name,$comment);
}
作成したget_post()でデータを種痘する。これでtrim()も自動的に行われる。check_words()でfalseが返ってきたらデータ挿入派でいない。$errsにエラーメッセージを格納し、$errsの要素が存在しない場合はinsert_data()を実行する。
次に、入力値の検証とデータ挿入を作成する。
if ($_SERVER['REQUEST_METHOD']==='POST') {
//中略
}
$data=select_comments($dbh);
include_once('view.php');
データの取得は必ず行うので、if ($_SERVER['REQUEST_METHOD']==='POST')の外に書く。
最後にview.phpのプログラムを作成する。ここまでで表示データの取得は終えているので、出力に関わる部分を作成する。
<html>
<body>
<h1>ひとこと掲示板</h1>
<table border="1">
<tr style="background-color:orange"><th>名前</th><th>コメント</th><th>時刻</th></tr>
<?php if (count($data)):
foreach($data as $row): ?>
<tr>
<td><?php echo html_escape($row['name']); ?></td>
<td><?php echo nl2br(html_escape($row['comment'])); ?></td>
<td><?php echo $row['created']; ?></td>
</tr>
<?php endforeach;
endif; ?>
</table>
<?php if(count($errs)) {
foreach($errs as $err){
echo '<p stype="color:red">'.$err.'</p>';
}
}?><form action="" method="POST">
<p>お名前*<input type="text" name="name">(50文字まで)</p>
<p>ひとこと*<textarea name="comment" rows="4" cols="40"></textarea>(200文字まで)</p>
<input type="submit" value="書き込む">
</form>
</body>
</html>
$dataの要素が存在する場合はforeach()を使って出力する。include_once()ではboard.phpで種痘した$dataのデータは引き継がれている。フォームからの入力値は出力前に必ず無毒化する必要があるので、html_escape()を使用する。コメントには改行コードが含まれる可能性もあるので、さらにnl2br()も必要となる。エラーがあった場合はどこの入力欄にエラーがあったのかを赤文字で表示するようにする。
コードはこれで完成なので、index.phpにアクセスして動作をテストする。
こんな感じで表示されるようになった。
今回はここまで。