よくある掲示板を1から積み上げて作る〜導入〜

## 本記事の概要

掲示板の作成を通して
MVC について学びたいという初心者が
[github.com/sait0928/bbs](https://github.com/sait0928/bbs) 
↑このリポジトリについて
初期のコミットから段階を追って振り返りつつ、
記事を作成することで復習し
理解を深めたい、
ということで作成した記事でございます。
複数に分けて投稿していく予定です。


## 筆者はどのくらいのレベルなのかという話

- プログラマのアルバイトを半年ほど経験
- うち研修3ヶ月、実務は3ヶ月ほど
- 退社してから1年ほどブランクあり
- PHP, DB, 仮想マシンは使ったことがある
- HTML は最低限書ける
- レベルはおそらく底辺


## 環境構築で参考にした記事・サイト

### 仮想マシンの準備

- [【Linux環境構築】VagrantとVirtualBoxとは？使い方を初心者向けに解説！](https://kitsune.blog/linux-environment)
- [CentOS 7にPHP 7.4をインストール（Remi's RPM repository）](https://qiita.com/witchcraze/items/d559541797fab3dc49d6)
- [CentOS7にMySQL8.0をインストール](https://qiita.com/zaburo/items/7518a432d915c061983f)
- [Apache httpd 2.4 を CentOS 7 に yum でインストールする手順](https://weblabo.oscasierra.net/apache-installing-apache24-yum-centos7-1/)

### 仮想マシン上のファイルをホストで扱いたい

- [【Vagrant】【Mac×CentOS7】ホストOSとゲストOS間での共有フォルダ設定](https://qiita.com/zamakei1016/items/03bc12f9db626f7259cb)
- [CentOS7 SELinuxを一時的/永続的に無効化/有効化する](https://qiita.com/ucan-lab/items/92710e4863287c53d94a)


## やることリストを書いていく

最初はとにかくシンプルなものを作る
(いきなり色々やろうとするとテンションが上がらない)

```
## 掲示板を作る
- データベース
- フォーム部分
- 表示部分
```

機能や部品、必要なテーブルについても考える

```
## ユーザーが使える機能
- フォームから送信する
- 投稿を表示する
## 必要な部品
- 投稿用テキストボックス
- 投稿用ボタン
- 投稿表示リスト
## データベース
- 投稿id
- 投稿内容
```


## 実際に作っていく

### まずはHTMLだけ

本来[PDO](https://www.php.net/manual/ja/book.pdo.php)を使って
テーブルから `SELECT` してくる部分は
適当に固定値を埋めて
形だけ作ってしまえ、ということで

```index.php
<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta charset="UTF-8">
		<title>掲示板</title>
	</head>
	<body>
		<h1>掲示板</h1>
		<div id="form">
			<form action="" method="POST">
				<textarea name="text" id="" cols="50" rows="5"></textarea>
				<input type="submit" value="投稿">
			</form>
		</div>
		<div id="posts">
			<table>
				<tr>
					<th>投稿ID</th>
					<th>投稿内容</th>
				</tr>
				<?php for($i = 0; $i < 10; $i++) : ?>
				<tr>
					<td>id</td>
					<td>text</td>
				</tr>
				<?php endfor; ?>
			</table>
		</div>
	</body>
</html>
```

### テーブルを作る

```posts.sql
create table posts(
    id int auto_increment,
    post varchar(255) not null,
    primary key (id)
);
```

### PDOを書いていく

PDOがなんなのか分からない、という方は
こちらの記事を見ると良いです。
↓
- [【PHP超入門】クラス～例外処理～PDOの基礎](https://qiita.com/7968/items/6f089fec8dde676abb5b)

まずはテーブルから記事を取得してくる処理

```index.php
<?php

$dsn = 'mysql:dbname=bbs;host=localhost';
$user = 'root';
$pass = '';

try {
	$dbh = new PDO($dsn, $user, $pass);
	$stmt = $dbh->query('SELECT * FROM posts ORDER BY id DESC');
	$posts = $stmt->fetchAll();
} catch(PDOException $e) {
	$error = $e->getMessage();
	echo $error;
}

?>
<!DOCTYPE html>
<!-- 以下html -->
```

ここで取得した posts を
html で表示できるように書いていきます。

```index.php
<table>
	<tr>
		<th>投稿ID</th>
		<th>投稿内容</th>
	</tr>
	<?php foreach($posts as $post) : ?>
	<tr>
		<td><?php echo $post['id']; ?></td>
		<td><?php echo nl2br(htmlspecialchars($post['post'])); ?></td>
	</tr>
	<?php endforeach; ?>
</table>
```

値のエスケープを忘れないようにしましょう。
また、`htmlspecialchars()` は
必ず html 出力時に行うようにしましょう。
↓
[【脆弱性対策におけるhtmlspecialchars()の使用箇所について】](https://ja.stackoverflow.com/questions/2408/%E8%84%86%E5%BC%B1%E6%80%A7%E5%AF%BE%E7%AD%96%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bhtmlspecialchars%E3%81%AE%E4%BD%BF%E7%94%A8%E7%AE%87%E6%89%80%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

ちなみに、
PDO 使用の際に
`could not find driver`
というエラーが出たので、
こちらの記事を参考に解決いたしました。
↓
[【PDOで could not find driver が出たとき】](https://qiita.com/oginom/items/5268fb19eeb80debb0ea)


続いてフォームで送信したテキストを
テーブルに書き込む処理です。
先ほど `SELECT` の際に生成した PDO インスタンスを
使いまわします。

```index.php
try {
	$dbh = new PDO($dsn, $user, $pass);

	// 記事書き込み部分
	if($_SERVER['REQUEST_METHOD'] === 'POST') {
		$text = $_POST['text'];
		$stmt = $dbh->prepare('INSERT INTO posts (post) VALUES (:post)');
		$stmt->bindParam(':post', $text, PDO::PARAM_STR);
		$stmt->execute();
	}
	// 記事書き込み終わり

	$stmt = $dbh->query('SELECT * FROM posts ORDER BY id DESC');
	$posts = $stmt->fetchAll();
} catch(PDOException $e) {
	$error = $e->getMessage();
	echo $error;
}
```

途中で `prepare()` を使って
`:post` というプレースホルダを作っておき
後から値をバインドしていますが、
これはSQLインジェクションという脆弱性への対策です。
↓
[SQLインジェクションとクエリの書き方について考える](https://qiita.com/nagimaruxxx/items/f52629044033e47e078e)

これでこじんまりとした掲示板は完成しました。


## あとがき 〜今後の作業の流れ〜

初心者のうちに書いた初心者目線の記事はある程度需要がありそう
ということで Qiita デビュー作でした。

ここからは、
良くないと思われる部分を修正したり、
機能を追加したりしつつ、
関数分割できるものは分割したり、
ある程度まとまってきたら
Model, View, Controller に分けてみたり、
そのようにして
なんだかフレームワークで見たことのある構成に
していくという流れになります。

数ヶ月前を振り返りつつの解説になるため
何を悩んでいたか忘れている部分もありますが、
色々な方にツッコんでいただきつつ
初心者向けの記事に仕上げていきたいと思っております。