# 投稿内容をデータベースから取得して表示する

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

demoa

# 本セクションの流れ

  1. 投稿内容をデータベースから取得する。
  2. データベースから取得した情報を表示する。

# 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');
}
?>

~~

1
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();
1
2

投稿内容の情報をデータベースから取得する処理を実装しています。 PDO クラスで用意されているqueryメソッドを使うために、~/src/db_connect.phpで生成したPDOインスタンス($dbh)を利用しています。

~/src/db_connect.php の PDO インスタンス生成箇所

$dbh = new PDO($dsn, $dbUser, $dbPass);
1

データベースから投稿内容を取得するだけであれば、ユーザからの入力情報を SQL 文に含める必要がないため、ここではqueryメソッドを利用しています。

PHP 公式ドキュメント_PDO::query (opens new window)

(SELECT 文) テーブルからデータを参照する

テーブルに含まれる特定のカラムを指定してデータを参照する場合は次のように記述します。カラム名を指定せず *(アスタリスク) を記述すると、全カラムを指定した場合と同じ結果となります。

SELECT カラム名1, カラム名2 FROM tbl_name;
(SELECT * FROM tbl_name;) // 全てのカラムを参照できる。
1
2

query と prepare の違い

SELECT 文のように、単純なデータ取得を行う SQL 文を実行する場合は query メソッドを利用します。

$dbh->query('SELECT * FROM posts;');
1

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();
1
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');
}
1
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>

    ~~

1
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>
1
2
3

DB から取得した件数を表示しています。

  • 11,12 行目
<?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { ?>
  <?php $lines = explode("\n", $row['message']); ?>
1
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 } ?>
1
2
3

explode()によって$row['message']を改行文字"\n"ごとに分割し、foreach()による繰り返し処理で展開・表示しています。

こうすることで、ユーザが入力したメッセージに含まれる改行を反映して表示しています。

# 動作確認

  • 投稿内容の一覧が表示されている状態
スクリーンショット 2022-07-24 19 49 20
  • 表示件数の表示
スクリーンショット 2022-07-24 19 49 25
  • 投稿したデータが表示される挙動

demoa

  • フォームからデータベースへ入力内容を追加できている状態
スクリーンショット 2022-07-24 19 52 45

# 最終的なコードとファイル構成

~~/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>
1
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
1
2
3
4
5
6
7
8
9
10
11
12