PHPとMariaDB(MySQL)で掲示板の作成①
2021-07-20

PHPを使ってデータベースを操作し、掲示板を作成しようと思います。
とりあえず、各プログラム文の意味を知っておいた方が良いと思いますので、分かりやすく1つのPHPファイルでまとめたいと思います。
※ただしリロードした際に2重投稿を起こすので、次回2つのPHPファイルに分けたスタンダードな掲示板を作成します。
初めに
掲示板の投稿から表示までのおおまかな流れ
①HTMLのformタグで作成された投稿フォームからPOSTメソッドでデータが送信される
②PHPでPOSTのデータを受け取り
③PHPでデータベースに接続
④PHPでデータベース内のテーブルを読み込み、POSTで受け取った内容を書き込み
⑤PHPでテーブルの内容を画面に表示させる
だいたいこのような流れとなります。
掲示板の作成
投稿フォーム
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content=
"width=device-width, initial-scale=1.0">
<title>掲示板</title>
<link rel="stylesheet" href=
"css/style.css">
</head>
<body>
<form method="post"> <!--form-->
<p>名前</p>
<input type="text" name="a">
<p>コメント</p>
<textarea name="b"></textarea>
<input type="submit" value="送信">
</form> <!--ここまで-->
</body>
</html>
ドキュメントルートにphpファイルを作成します。head部分の説明は割愛します。
fromタグが投稿フォームの記述になります。
POST送信するので、メソッドでPOSTを指定します。
input type=text は小さな入力欄が出来ます。今回は名前の入力欄として使います。name="a"というのは、textで入力したデータに"a"という名前を付けています。
textareaは、大きめの入力欄が出来ます。今回はコメント入力欄として使いましす。これにもデータに名前を付けておきます。
input type=submit は、ボタンが生成されて、valueでボタンの中に文字を入れる事ができます。
この状態で一度サーバー(localhost)にアクセスすると、下のような画面になっているはずです。ただ、今の段階ではPHPを使っていませんし、データベースもつながってないので、ボタンを押してもなにも起こりません。
PHPでPOSTデータ受け取り
</form> <?php $a = htmlspecialchars($_POST["a"], ENT_QUOTES); $b = htmlspecialchars($_POST["b"], ENT_QUOTES);
form閉じタグの下からphp文を埋め込んでいきます。
$a,$bの変数を作り、フォームからのPOSTデータを代入します。
$_POST["]は、phpで用意されている「POSTデータを受け取る関数」です。つまり、今回の場合だと名前はa、コメントはb、に紐づけされているので、引数にそれを渡し、変数に代入しています。
それと大事なのが、「htmlspecialchars...ENT_QUOTES」です。これは掲示板のコメント入力時に「不正なhtmlタグの埋め込み」を防止する役割を果たしています。
例えば背景の色を真っ黒にされたり、文字の大きさをとんでもない大きさに変更されたりする恐れがあります。htmlのタグを無効化する記述になるので、必須です。
PHPでデータベースに接続
$db = new PDO("mysql:host=localhost;
dbname=keiji", "root", "");
POSTデータの受け取り後、データベースに接続する記述を入れます。
「PDOオブジェクト」というものを作成するのですが、上記のように、「new PDO()」と記述し、引数には「ホスト名(サーバー名)」「データベース名」「ユーザー名」「パスワード」を記述します。
今回だと、左から順に「localhost」「keiji」「root」「なし」となります。
XAMPPの場合、デフォルトではユーザー名はroot、パスワードは無しとなっているはずです。
あとはこの記述を変数に代入しておきます。今回は$dbとします。
PHPでデータベース内のテーブル読み込み、POSTで受け取った内容を書き込み
$db->query("INSERT INTO tb1
(no,name,messege,time)
VALUES (NULL,'$a','$b',NOW())");
少し長いので改行していますが、これで1つの文になります。
->query は、query()の関数を実行する記述となります。
INSERT INTO テーブル名(カラム名)で、データベースに登録している任意のテーブルの情報を読み込んでいます。
VALUES(カラムに渡す値)で、読み込んだテーブルに値を書き込みします。
つまり、POSTされたデータを、データベースに書き込む記述ですね。
今回であれば、テーブルのカラムの内容は左から順に「番号」「名前」「コメント」「日時」になっているので、VALUESで「NULL(空の値)」「$a」「$b」「NOW()(POSTされた時刻の値)」を入れています。
気を付ける点が、もともと存在する関数(NULLとNOW)については「’」で囲む必要がなく、変数は「’」で囲む必要があることです。
番号については、NULLとしても1.2.3と順番に番号が割り振られます。
これでフォームから投稿された内容がデータベースに反映されます。
PHPでテーブルの内容を画面に表示させる
$n =
$db -> query
("SELECT * FROM tb1 ORDER BY no DESC");
while ($i = $n -> fetch()) {
print "{$i['no']}: {$i['name']}
{$i['time']}<br>"
.nl2br($i['messege'])."<hr>";
}
?>
最後に、テーブルに書き込まれている情報を画面に表示させる記述をいれます。
query関数の引数に「SERECT * FROM テーブル名」で、テーブルの情報を全て取り出しています。
「BY INT型カラム DESC」で、番号に紐づいているレコードを「降順」で取り出すことが可能です。(これをしなければ昇順になります。)
SNSでは基本新着が上に足されていくので、そのようにする場合はこの記述が必要ですね。
これを一旦、新しく作った変数に代入します。(今回は$n)
その後、whileのループ文で、テーブル内のデータを表示させます。
先ほど代入したテーブルの内容を、「fetch()」関数で実行しています。
これは、「レコードが無くなるまでレコードを1つづつ抜きだす」関数になります。これをwhileの条件に入れているので、$nのレコードが無くなるまで、下部のprintが実効されます。
つまり、$nのレコードを降順で1つづつ抜きだし、$iの変数に入れて、レコードが無くなるまで指定した内容で$iをprintさせる。という事になります。
printの上部は、左から順に「番号」「名前」「時間」を表示させて改行の<br>を入れてます。
下部に「nl2br」とありますが、これはフォームの入力時の改行を表示に反映させる関数です。つまりコメントの改行をそのまま反映させるにはこれが必要です。あと<br>で改行させているので、下部は「.」でつなぐ事が必要です。
<hr>は、表示されるレコード毎に下線を入れて見栄え良くするためのタグです。
掲示板テスト
いくつか問題はありますが、一応今回のコードをまとめます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width,
initial-scale=1.0">
<title>掲示板</title>
<link rel="stylesheet" href=
"css/style.css">
</head>
<body>
<form method="post">
<p>名前</p>
<input type="text" name="a">
<p>コメント</p>
<textarea name="b"></textarea>
<input type="submit" value="送信">
<br><br>
</form>
<?php
$a = htmlspecialchars($_POST["a"],
ENT_QUOTES);
$b = htmlspecialchars($_POST["b"],
ENT_QUOTES);
$db = new PDO("mysql:host=localhost;
dbname=keiji", "root", "");
$db->query("INSERT INTO tb1
(no,name,messege,time)
VALUES (NULL,'$a','$b',NOW())");
$n = $db -> query
("SELECT * FROM tb1 ORDER BY no DESC");
while ($i = $n -> fetch()) {
print "{$i['no']}:
{$i['name']} {$i['time']}<br>"
.nl2br($i['messege'])."<hr>";
}
?>
</body>
</html>
それでは、この状態でlocalhostに接続してみます。すると、下記のエラー表示が出ます。
23.24行目、POSTデータの受け取りの部分です。これは、「変数未定義」の為にエラーとなっています。つまり、初回はPOST["a"]、POST["b"]が空の状態なのでエラー表示が出てしまうのです。
これは一度フォームで入力、送信する事で消えますが、一度ページから離れてしまうと、次回接続時の一回目にはまた必ず表示されてしまいます。
また、名前やコメントを「空白」でも送信出来てしまいます。
これが1つ目の問題です。
こういった場合の回避方法としては、「empty」関数を使ったif文があります。
変数未定義、空送信を回避する方法「empty」を使う
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content=
"width=device-width, initial-scale=1.0">
<title>掲示板</title>
<link rel="stylesheet" href=
"css/style.css">
</head>
<body>
<form method="post">
<p>名前</p>
<input type="text" name="a">
<p>コメント</p>
<textarea name="b"></textarea>
<input type="submit" value="送信">
<br><br>
</form>
<?php
if(!empty($_POST["a"]) &&
!empty($_POST["b"])) {//空でなければ真
$a = htmlspecialchars($_POST["a"],
ENT_QUOTES);
$b = htmlspecialchars($_POST["b"],
ENT_QUOTES);
$db = new PDO("mysql:host=localhost;
dbname=keiji", "root", "");
$db->query("INSERT INTO tb1
(no,name,messege,time)
VALUES (NULL,'$a','$b',NOW())");
$n = $db -> query
("SELECT * FROM tb1 ORDER BY no DESC");
while ($i = $n -> fetch()) {
print "{$i['no']}:
{$i['name']} {$i['time']}<br>"
.nl2br($i['messege'])."<hr>";
}
} else { //POSTが空の場合の処理
$db = new PDO
("mysql:host=localhost;
dbname=keiji", "root", "");
$n = $db -> query
("SELECT * FROM tb1 ORDER BY no DESC");
while ($i = $n -> fetch()) {
print "{$i['no']}:
{$i['name']} {$i['time']}<br>"
.nl2br($i['messege'])."<hr>";
}
}
?>
</body>
</html>
php文の先頭にif文を付け足します。
empty関数は、引数の中身が空の状態かを確認できます。したがって、この場合だと!emptyなので、POST[a]とPOST[b]が空でなければ真の処理になり、空であれば偽のelse処理となります。
つまり、未定義変数の場合が無くなるので、エラーは消えます。
さらに、未定義=入力が無しとみなせるので、空白での送信も出来なくなります。
少々長ったらしくなりますが、こういった回避方法もあります。
しかし、まだ問題があります。
一度コメントを送信した後、ページをリロードすると同じコメントが再度送信されてしまいます。2重送信ですね。
これはPOSTのデータをデータベースに書き込んだ後、中身を消すといった事で回避できそうですが、出来ません。ブラウザに記憶されているためです。
一応回避する方法は、ある事はあるみたいですが、「セッションの管理」「cookieの管理」など、少し敷居が高いので、一番手軽に対策できる「POST送信後のページ移動」が良いと思われます。
コメント送信後にページ移動し「コメント送信出来ました」みたいな表示が出るスタンダードな掲示板です。
これを次回まとめようと思います。