ピックアップ記事
PHPで掲示板サイトを作ってみよう【回答編】

こちらの記事は、「PHPで掲示板サイトを作ってみよう」という記事の回答編になります。

気になる方は、以下のリンクよりご覧ください。

 

課題1 投稿内容一覧に、投稿時間を表示させましょう。

答え

index.phpでのデータ出力部分に

<div>投稿時間:<?php echo $loop['created_at']?></div>

を追記できていれば正解です。

 

解説

DBにあるデータを表示するまでの流れは、

1. データを登録
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つに分けて考えるとわかりやすいと思います。

1. 投稿内容の取得件数を20件に制限する。
2. 順番を投稿日時の新しい順に入れ替える。

 

答えでは、使用するSQL文を「SELECT * FROM post order by created_at DESC limit 20」に変更していました。

ここの意味は、

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(!$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`")
        );
        //ここで「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などといったフレームワークを使用した開発に挑戦してみると良いと思います。

おすすめの記事