こちらの記事は、「PHPで掲示板サイトを作ってみよう」という記事の回答編になります。
気になる方は、以下のリンクよりご覧ください。
課題1 投稿内容一覧に、投稿時間を表示させましょう。
答え
index.phpでのデータ出力部分に
<div>投稿時間:<?php echo $loop['created_at']?></div>
を追記できていれば正解です。
解説
DBにあるデータを表示するまでの流れは、
2. データの登録を確認
3. データを取得
4. 取得したデータを表示
の流れです。
今回の投稿時間の表示は、すでにデータ取得まで済んでいるため、ここでやることは、すでに登録されている投稿時間を表示するだけです。
まずは、念の為、DBに登録されていることを確認しましょう。
mysql -u root -p sample
これで、MySQLにログイン後、sampleDBを選択している状態になります。
select * from post limit 1;
sampleDB内のpostテーブルのデータを1つ取得し、全てのカラムを表示させます。
created_atというカラムを確認すると、確かに日付が登録されていることが確認できたかと思います。
DBから投稿内容を取得する際に発行しているSQL文を見てみると、
$regist = $pdo->prepare("SELECT * FROM post");
と書いてあります。
これは、postテーブル(投稿一覧)から全てのカラム(*)を取得することを表しているため、created_atカラムも取得できているということになります。
そのため、ここで行うことは、そのデータを画面上に表示するだけです。
他の部分と同じように表示させてみましょう。
<section>
<h2>投稿内容一覧</h2>
<?php foreach($regist as $loop):?>
<div>No:<?php echo $loop['id']?></div>
<div>名前:<?php echo $loop['name']?></div>
<div>投稿内容:<?php echo $loop['contents']?></div>
<div>投稿時間:<?php echo $loop['created_at']?></div>
<div>------------------------------------------</div>
<?php endforeach;?>
</section>
ここでは、取得したデータが$registに格納されており、データを一つずつforeach文で回して、出力しています。
配列内にどんなデータが存在するか確認したい場合は、以下のように記述することで確認が可能です。
var_dump($regist);
課題2 最新の投稿20件までを新しい順に表示するように書き換えましょう。
答え
index.phpのデータ取得部分を
$regist = $pdo->prepare("SELECT * FROM post order by created_at DESC limit 20");
に書き換えれていれば正解です。
解説
こちらは、SQL文を書き換える問題です。
ここでは、処理を2つに分けて考えるとわかりやすいと思います。
2. 順番を投稿日時の新しい順に入れ替える。
答えでは、使用するSQL文を「SELECT * FROM post order by created_at DESC limit 20」に変更していました。
ここの意味は、
黄色:データ取得件数を最大20件に制限する
赤線:created_atカラムを基準に降順に並び替えを行う。
このような意味になっています。
もし、データ取得後のデータの順番を入れ替え、件数制限もしたという人がいれば、一応、正解ではありますが、あまり望ましくはありません。
この場合、掲示板のデータを全件取得した後に処理をしますので、掲示板のデータが1000件あれば、無駄にその1000件を取得していることになります。
そのため、取得する時点で制限してあげる方が好ましいでしょう。
課題3 投稿送信時の動作を変更。
答え
フォームの送信先をsend.phpからindex.phpに変更。
<form action="index.php" method="post">
その後、send.phpで使用していたDBへの書き込み処理をコピペして、index.phpに貼り付け。
書き込みは、index.phpにPOSTがあった場合のみにしたいので、書き込み処理をif文で囲みます。
if($_POST){
$id = null;
$name = $_POST["name"];
$contents = $_POST["contents"];
date_default_timezone_set('Asia/Tokyo');
$created_at = date("Y-m-d H:i:s");
//DB接続情報を設定します。
$pdo = new PDO(
"mysql:dbname=sample;host=localhost","root","",array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET `utf8`")
);
//ここで「DB接続NG」だった場合、接続情報に誤りがあります。
if ($pdo) {
echo "DB接続OK";
} else {
echo "DB接続NG";
}
//SQLを実行。
$regist = $pdo->prepare("INSERT INTO post(id, name, contents, created_at) VALUES (:id,:name,:contents,:created_at)");
$regist->bindParam(":id", $id);
$regist->bindParam(":name", $name);
$regist->bindParam(":contents", $contents);
$regist->bindParam(":created_at", $created_at);
$regist->execute();
//ここで「登録失敗」だった場合、SQL文に誤りがあります。
if ($regist) {
echo "登録成功";
} else {
echo "登録失敗";
}
}
解説
ここは、ほとんど解説がいらないと思います。
send.phpでしていた「POSTされたデータをDBに書き込む」処理をindex.phpに写し、フォームの送信先をindex.phpに変えています。
また、POSTされた時のみ書き込み処理を走らせたいので、
if($_POST){
としています。
課題4 フォームの入力値が空だった場合、送信できないようにする。
答え
index.phpの内容を全て載せておきます。
<?php
$errors = [];
if($_POST){
$id = null;
$name = $_POST["name"];
$contents = $_POST["contents"];
if(null === $name){
$errors[] .= "名前を入力してください";
}
if(null === $contents){
$errors[] .= "投稿内容を入力してください";
}
if(!$errors){
date_default_timezone_set('Asia/Tokyo');
$created_at = date("Y-m-d H:i:s");
//DB接続情報を設定します。
$pdo = new PDO(
"mysql:dbname=sample;host=localhost","root","",array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET `utf8`")
);
//ここで「DB接続NG」だった場合、接続情報に誤りがあります。
if ($pdo) {
echo "DB接続OK";
} else {
echo "DB接続NG";
}
//SQLを実行。
$regist = $pdo->prepare("INSERT INTO post(id, name, contents, created_at) VALUES (:id,:name,:contents,:created_at)");
$regist->bindParam(":id", $id);
$regist->bindParam(":name", $name);
$regist->bindParam(":contents", $contents);
$regist->bindParam(":created_at", $created_at);
$regist->execute();
//ここで「登録失敗」だった場合、SQL文に誤りがあります。
if ($regist) {
echo "登録成功";
} else {
echo "登録失敗";
}
}
}
//DB接続情報を設定します。
$pdo = new PDO(
"mysql:dbname=sample;host=localhost","root","",array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET `utf8`")
);
//ここで「DB接続NG」だった場合、接続情報に誤りがあります。
if ($pdo) {
echo "DB接続OK";
} else {
echo "DB接続NG";
}
//SQLを実行。
$regist = $pdo->prepare("SELECT * FROM post order by created_at DESC limit 20");
$regist->execute();
//ここで「登録失敗」だった場合、SQL文に誤りがあります。
if ($regist) {
echo "登録成功";
} else {
echo "登録失敗";
}
?>
<!-- 追記1ここまで -->
<!DOCTYPE html>
<meta charset="UTF-8">
<title>掲示板サンプル</title>
<h1>掲示板サンプル</h1>
<section>
<h2>新規投稿</h2>
<div id="error"><?php foreach($errors as $error){echo $error.'<br>';}?></div>
<form action="index.php" method="post">
名前 : <input type="text" name="name" value=""><br>
投稿内容: <input type="text" name="contents" value=""><br>
<button type="submit">投稿</button>
</form>
</section>
<!-- 追記2ここから -->
<section>
<h2>投稿内容一覧</h2>
<?php foreach($regist as $loop):?>
<div>No:<?php echo $loop['id']?></div>
<div>名前:<?php echo $loop['name']?></div>
<div>投稿内容:<?php echo $loop['contents']?></div>
<div>投稿時間:<?php echo $loop['created_at']?></div>
<div>------------------------------------------</div>
<?php endforeach;?>
</section>
<!-- 追記2ここまで -->
解説
もし名前が入力されていなければ、$errors変数にエラーメッセージを追加しています。
if(!$name){
$errors[] .= "名前を入力してください";
}
内容($contents)に対しても、同様の処理をし、$errorsにメッセージが入っていなければDBへの書き込み処理を実施するようにしています。
また、エラーメッセージの表示は、$errorsに配列として保存されたエラーメッセージを出力するためにforeach文で書き出しを行なっています。
<div id="error"><?php foreach($errors as $error){echo $error.'<br>';}?></div>
課題5 投稿をajaxで処理する。
答え
これについても、全てのコードを載せておきます。
まずは、index.php。
<?php
require_once "send.php";
$regist = getPostData();
?>
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>掲示板サンプル</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<h1>掲示板サンプル</h1>
<section>
<h2>新規投稿</h2>
<div id="error"></div>
名前 : <input type="text" name="name" value="" id="name"><br>
投稿内容: <input type="text" name="contents" value="" id="contents"><br>
<button type="submit" id="send">投稿</button>
</section>
<section>
<h2>投稿内容一覧</h2>
<div id="post-data">
<?php foreach($regist as $loop):?>
<div>No:<?php echo $loop['id']?></div>
<div>名前:<?php echo $loop['name']?></div>
<div>投稿内容:<?php echo $loop['contents']?></div>
<div>投稿時間:<?php echo $loop['created_at']?></div>
<div>------------------------------------------</div>
<?php endforeach;?>
</div>
</section>
<script>
document.getElementById('send').onclick = function(){
let name = $('#name').val();
let contents = $('#contents').val();
$.ajax({
url: "send.php",
type: "post",
dataType: "text",
data:{'name': name, 'contents': contents}
}).done(function (response) {
let res = JSON.parse(response);
let html = '';
if(!res['error']){
res.forEach( val => {
html +=
`<div>No:${val['id']}</div>
<div>名前:${val['name']}</div>
<div>投稿内容:${val['contents']}</div>
<div>投稿時間:${val['created_at']}</div>
<div>------------------------------------------</div>`;
});
$('#post-data').html(html);
$('#error').html('');
$('#name').val('');
$('#contents').val('');
}else{
res['error'].forEach( val => {
html += val + '<br>';
});
$('#error').html(html);
}
}).fail(function (xhr,textStatus,errorThrown) {
alert('error');
});
}
</script>
send.php
<?php
$errors = [];
if($_POST){
$id = null;
$name = $_POST["name"];
$contents = $_POST["contents"];
if(!$name){
$errors[] .= "名前を入力してください";
}
if(!$contents){
$errors[] .= "投稿内容を入力してください";
}
if(!$errors){
date_default_timezone_set('Asia/Tokyo');
$created_at = date("Y-m-d H:i:s");
//DB接続情報を設定します。
$pdo = new PDO(
"mysql:dbname=sample;host=localhost","root","",array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET `utf8`")
);
//SQLを実行。
$regist = $pdo->prepare("INSERT INTO post(id, name, contents, created_at) VALUES (:id,:name,:contents,:created_at)");
$regist->bindParam(":id", $id);
$regist->bindParam(":name", $name);
$regist->bindParam(":contents", $contents);
$regist->bindParam(":created_at", $created_at);
$regist->execute();
$res = [];
$post_data = getPostData();
$cnt = 0;
foreach($post_data as $loop){
$res[$cnt]['id'] = $loop['id'];
$res[$cnt]['name'] = $loop['name'];
$res[$cnt]['contents'] = $loop['contents'];
$res[$cnt]['created_at'] = $loop['created_at'];
$cnt++;
}
echo json_encode($res);
}else{
echo json_encode(['error' => $errors]);
}
}
function getPostData(){
//DB接続情報を設定します。
$pdo = new PDO(
"mysql:dbname=sample;host=localhost","root","",array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET `utf8`")
);
//SQLを実行。
$regist = $pdo->prepare("SELECT * FROM post order by created_at DESC limit 20");
$regist->execute();
return $regist;
}
?>
解説
変更点が多いので、細かな説明は省きます。
投稿送信時に、ajaxでDBへの登録、DBから取得の処理をし、掲示板の内容を最新の状態に変更するようにしています。
今回の課題は、ただデータの登録をajaxで行うだけでなく、更新した情報を受け取り、javascriptからHTMLを生成する必要があったため、少し難しかったと思います。
※ 課題6については省略させていただきます。
今後の学習について
今回、実践したPHP掲示板は、フレームワークを一切使用しませんでしたが、業務でWebサービスを作る場合には、フレームワークを使うことがほとんどです。
そのため、今度はLaravelやCakePHPなどといったフレームワークを使用した開発に挑戦してみると良いと思います。