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(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などといったフレームワークを使用した開発に挑戦してみると良いと思います。

コメント一覧
  1. あら より:

    もし宜しければ、問6のcssのソースコードも教えていただけないでしょうか?

  2. 匿名 より:

    匿名掲示板を作りたいのですがうまくいきません。sendでエラーがでます。どうしたらいいですか?

    • took より:

      どの辺りで躓いておりますでしょうか。
      エラー内容等、情報のわかるものを貼っていただければ確認します。

  3. akasa1254 より:

    複数の掲示板を作る際、どの部分を変更すればいいのでしょうか

    • took より:

      この記事では複数の掲示板を作ることを目的としていないです。
      掲示板の投稿ページを作成する演習となるので、掲示板を一覧表示するページの作成や、ユーザが新規掲示板の追加を行う処理等は別途作成する必要があります。

コメントを残す

CAPTCHA


関連キーワード