# 投稿内容をデータベースから取得して表示する
データベースへ保存した情報を index.php の中で取得し、ユーザに見える形で表示する状態を目指します。

# 本セクションの流れ
- 投稿内容をデータベースから取得する。
- データベースから取得した情報を表示する。
# 1. 投稿内容をデータベースから取得する。
~~/public/index.php に以下のコードを追加します。
<?php
session_start();
require_once(__DIR__ . '/../src/db_connect.php');
if (isset($_POST['action_type']) && $_POST['action_type']) {
if ($_POST['action_type'] === 'insert') {
require(__DIR__ . '/../src/insert_message.php');
} else if ($_POST['action_type'] === 'delete') {
require(__DIR__ . '/../src/delete_message.php');
}
}
require(__DIR__ . '/../src/session_values.php');
$stmt = $dbh->query('SELECT * FROM posts ORDER BY created_at DESC;');
$message_length = $stmt->rowCount();
function convertTz($datetime_text)
{
$datetime = new DateTime($datetime_text);
$datetime->setTimezone(new DateTimeZone('Asia/Tokyo'));
return $datetime->format('Y/m/d H:i:s');
}
?>
~~
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- 15-16 行目
$stmt = $dbh->query('SELECT * FROM posts ORDER BY created_at DESC;');
$message_length = $stmt->rowCount();
2
投稿内容の情報をデータベースから取得する処理を実装しています。
PDO クラスで用意されているqueryメソッドを使うために、~/src/db_connect.phpで生成したPDOインスタンス($dbh)を利用しています。
~/src/db_connect.php の PDO インスタンス生成箇所
$dbh = new PDO($dsn, $dbUser, $dbPass);
データベースから投稿内容を取得するだけであれば、ユーザからの入力情報を SQL 文に含める必要がないため、ここではqueryメソッドを利用しています。
PHP 公式ドキュメント_PDO::query (opens new window)
(SELECT 文) テーブルからデータを参照する
テーブルに含まれる特定のカラムを指定してデータを参照する場合は次のように記述します。カラム名を指定せず *(アスタリスク) を記述すると、全カラムを指定した場合と同じ結果となります。
SELECT カラム名1, カラム名2 FROM tbl_name;
(SELECT * FROM tbl_name;) // 全てのカラムを参照できる。
2
query と prepare の違い
SELECT 文のように、単純なデータ取得を行う SQL 文を実行する場合は query メソッドを利用します。
$dbh->query('SELECT * FROM posts;');
INSERT 文のように、ユーザからの入力を含めた SQL 文を実行する場合は prepare メソッドを利用します。
// ユーザからの入力情報を含むSQL文の作成
$query = 'INSERT INTO posts (author_name, message) VALUES (:author_name, :message)';
// ユーザの入力情報をSQL文に含める準備
$stmt = $dbh->prepare($query);
// SQL文にユーザからの入力情報を代入
$stmt->bindValue(':author_name', $input_author_name, PDO::PARAM_STR);
$stmt->bindValue(':message', $input_message, PDO::PARAM_STR);
// ユーザからの入力情報を含んだSQLを実行
$stmt->execute();
2
3
4
5
6
7
8
9
ここでは、SELECT * FROM posts ORDER BY created_at DESC;としているため、posts テーブルからデータが作成された日時(created_at)の降順並び替え(DESC)でデータを取得してます。
$message_length = $stmt->rowCount();では、rowCount()を用いて、クエリ処理後に作用した行数を取得し、$message_lengthに格納しています。
rowCount()は SELECT(参照)以外にも、INSERT(挿入)、UPDATE(更新)、DELETE(削除)の処理によって作用した行数を返します。
- 18-23 行目
function convertTz($datetime_text)
{
$datetime = new DateTime($datetime_text);
$datetime->setTimezone(new DateTimeZone('Asia/Tokyo'));
return $datetime->format('Y/m/d H:i:s');
}
2
3
4
5
6
タイムゾーンの設定と取得した日時のフォーマットを行っています。
タイムゾーンとは、同じ標準時刻を使用する地域や区分のことを指します。世界中にあるそれぞれのサーバが異なるタイムゾーンを利用すると、システムや通信に影響を及ぼす可能性があります。
そのため、ここではAsia/Tokyoのタイムゾーンに設定を行い、さらに、2001-03-10 17:16:18(MySQL の DATETIME フォーマット)形式になるようフォーマットを指定を行います。
PHP 公式ドキュメント_DateTime::format (opens new window)
# 2. データベースから取得した情報を表示する。
~~/public/index.php に以下のコードを追加します。
~~
<hr class="page-divider" />
<div class="message-list-cover">
<small>
<?php echo $message_length; ?> 件の投稿
</small>
<?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { ?>
<?php $lines = explode("\n", $row['message']); ?>
<div class="message-item">
<div class="message-title">
<div><?php echo htmlspecialchars($row['author_name'], ENT_QUOTES); ?></div>
<small><?php echo convertTz($row['created_at']); ?></small>
<div class="spacer"></div>
<form action="/" method="post" style="text-align:right">
<input type="hidden" name="id" value="<?php echo $row['id']; ?>" />
<input type="hidden" name="action_type" value="delete" />
<button type="submit" class="message-delete-button">削除</button>
</form>
</div>
<?php foreach ($lines as $line) { ?>
<p class="message-line"><?php echo htmlspecialchars($line, ENT_QUOTES); ?></p>
<?php } ?>
</div>
<?php } ?>
</div>
~~
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
- 7-9 行目
<small>
<?php echo $message_length; ?> 件の投稿
</small>
2
3
DB から取得した件数を表示しています。
- 11,12 行目
<?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { ?>
<?php $lines = explode("\n", $row['message']); ?>
2
データベースから取得したデータを $row へ格納し、while による繰り返し処理で展開し、メッセージの一覧を表示しています。
while 文は「指定の条件を満たすまでのループ処理」が可能であるため、取得したデータ $stmt->fetch(PDO::FETCH_ASSOC の数だけ繰り返し処理を行います。
- 24-26 行目
<?php foreach ($lines as $line) { ?>
<p class="message-line"><?php echo htmlspecialchars($line, ENT_QUOTES); ?></p>
<?php } ?>
2
3
explode()によって$row['message']を改行文字"\n"ごとに分割し、foreach()による繰り返し処理で展開・表示しています。
こうすることで、ユーザが入力したメッセージに含まれる改行を反映して表示しています。
# 動作確認
- 投稿内容の一覧が表示されている状態
- 表示件数の表示
- 投稿したデータが表示される挙動

- フォームからデータベースへ入力内容を追加できている状態
# 最終的なコードとファイル構成
~~/public/index.php
<?php
session_start();
require_once(__DIR__ . '/../src/db_connect.php');
if (isset($_POST['action_type']) && $_POST['action_type']) {
if ($_POST['action_type'] === 'insert') {
require(__DIR__ . '/../src/insert_message.php');
}
}
require(__DIR__ . '/../src/session_values.php');
$stmt = $dbh->query('SELECT * FROM posts ORDER BY created_at DESC;');
$message_length = $stmt->rowCount();
function convertTz($datetime_text)
{
$datetime = new DateTime($datetime_text);
$datetime->setTimezone(new DateTimeZone('Asia/Tokyo'));
return $datetime->format('Y/m/d H:i:s');
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="robots" content="noindex" />
<title>ひとこと掲示板</title>
<link rel="stylesheet" href="./assets/main.css" />
</head>
<body>
<div class="page-cover">
<p class="page-title">ひとこと掲示板</p>
<hr class="page-divider" />
<div class="form-cover">
<form action="/" method="post">
<div class="form-input-title">投稿者ニックネーム</div>
<input type="text" name="author_name" maxlength="40" value="<?php echo htmlspecialchars($messages['input_pre_author_name'], ENT_QUOTES); ?>" class="input-author-name" />
<?php if ($messages['input_error_author_name'] !== '') { ?>
<div class="form-input-error">
<?php echo $messages['input_error_author_name']; ?>
</div>
<?php } ?>
<div class="form-input-title">投稿内容<small>(必須)</small></div>
<textarea name="message" class="input-message"><?php echo htmlspecialchars($messages['input_pre_message'], ENT_QUOTES); ?></textarea>
<?php if ($messages['input_error_message'] !== '') { ?>
<div class="form-input-error">
<?php echo $messages['input_error_message']; ?>
</div>
<?php } ?>
<input type="hidden" name="action_type" value="insert" />
<button type="submit" class="input-submit-button">投稿する</button>
</form>
</div>
<hr class="page-divider" />
<div class="message-list-cover">
<small>
<?php echo $message_length; ?> 件の投稿
</small>
<?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { ?>
<?php $lines = explode("\n", $row['message']); ?>
<div class="message-item">
<div class="message-title">
<div><?php echo htmlspecialchars($row['author_name'], ENT_QUOTES); ?></div>
<small><?php echo convertTz($row['created_at']); ?></small>
<div class="spacer"></div>
<form action="/" method="post" style="text-align:right">
<input type="hidden" name="id" value="<?php echo $row['id']; ?>" />
<input type="hidden" name="action_type" value="delete" />
<button type="submit" class="message-delete-button">削除</button>
</form>
</div>
<?php foreach ($lines as $line) { ?>
<p class="message-line"><?php echo htmlspecialchars($line, ENT_QUOTES); ?></p>
<?php } ?>
</div>
<?php } ?>
</div>
</div>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
ファイル構成
.
├── docker-compose.yml
├── php
│ └── Dockerfile
├── public
│ ├── assets
│ │ └── main.css
│ └── index.php
└── src
├── db_connect.php
├── insert_message.php
└── session_values.php
2
3
4
5
6
7
8
9
10
11
12