Portfolio作成 ⑤ 記事投稿機能実装編

キミマチラボ

目標

① 記事一覧をMySQL化
② 記事詳細をMySQL化

① 記事一覧をMySQL化

ここで一度整理すると、

現在

データファイル(data/posts.php) へ「記事タイトル」と「記事本文」を書き込み、

<?php

$posts = [
[
// 記事のID番号
'id' => 1,
// 記事タイトル
'title' => '最初の記事',
// 記事本文
'content' => 'CMS開発開始'
],
[
// 記事のID番号
'id' => 2,
// 記事タイトル
'title' => 'PHP学習',
// 記事本文
'content' => '配列を使ってみる'
]
];

記事一覧画面(index.php) にてinclude 'data/posts.php';で読み込み、リンク付き記事タイトルとして一覧で表示しています。

<?php

include 'data/posts.php';
include 'header.php';

?>

<h2>記事一覧</h2>

<?php foreach($posts as $post): ?>

    <h3>
    <a href="post.php?id=<?php echo $post['id']; ?>">
        <?php echo $post['title']; ?>
    </a>
</h3>

<?php endforeach; ?>

<?php include 'footer.php'; ?>

修正後

「index.php にてinclude 'data/posts.php';で読み込み」の部分を、
MySQLSELECTコマンドで必要情報を呼び出し、記事一覧へ表示」という形式へと変更します。

ここまでの作業が「記事一覧をMySQL化」の目標です。

修正方法

まずは、index.phpを編集しに行きましょう。

/独自ドメイン/public_html/portfolio/index.php

へ移動。

改めてindex.phpの中身はこうなっています。

<?php

include 'data/posts.php';
include 'header.php';

?>

<h2>記事一覧</h2>

// $posts に格納されている投稿データを1件ずつ取り出して処理する
// 1回目のループでは最初の投稿、2回目は次の投稿…というように繰り返される
// 現在処理中の投稿データは $post に代入される
<?php foreach($posts as $post): ?>

    <h3>
  <!--
    投稿詳細ページ(post.php)へのリンクを作成する

    ?id= の後ろに現在の投稿IDを付与しているため、
    クリックすると該当する投稿の詳細ページを表示できる

    例:
    $post['id'] が 2 の場合
    ↓
    <a href="post.php?id=2">
-->
    <a href="post.php?id=<?php echo $post['id']; ?>">

        // 現在処理中の投稿データ($post)から
    // titleカラムの値(投稿タイトル)を取得して画面に表示する
        <?php echo $post['title']; ?>
    </a>
</h3>

<?php endforeach; ?>

<?php include 'footer.php'; ?>

include 'data/posts.php'; の部分を削除して、同じ個所に下記コードを書き込んでいきます。

<?php

// config配下の「database.php」を読み込む<データベース接続設定ファイル>
include 'config/database.php';

// 実行するSQL文を定義
// postsテーブルの全てのカラム(*)を取得、
// idの降順(大きいID=新しい投稿が先)で並べる
$sql = "
    SELECT *
    FROM posts
    ORDER BY id DESC
";

// SQLを実行する
// query()は結果セットを返し、PDOStatementオブジェクトが$stmtに格納される
$stmt = $pdo->query($sql);

// SQLの実行結果を全件取得する
// FETCH_ASSOCを指定することで、
// カラム名をキーとした連想配列として取得する
$posts = $stmt->fetchAll(PDO::FETCH_ASSOC);

include 'header.php';

?>

database.php ($pdoのつながり確認)

<?php

// データベースサーバー名
// XServerでは通常 localhost
$host = 'localhost';

// 接続するデータベース名
$dbname = 'ここにMySQLデータベース名';

// MySQLユーザー名
$username = 'ここにMySQLユーザー名';

// MySQLパスワード
$password = 'ここにMySQLパスワード';

try {

    // PDOオブジェクト作成
    // PHPとMySQLを接続するための窓口
    $pdo = new PDO(

        // 接続先情報
        "mysql:host=$host;dbname=$dbname;charset=utf8mb4",

        // ユーザー名
        $username,

        // パスワード
        $password
    );

    // エラー発生時に例外を投げる設定
    // 開発中は必須
    $pdo->setAttribute(
        PDO::ATTR_ERRMODE,
        PDO::ERRMODE_EXCEPTION
    );

} catch (PDOException $e) {

    // 接続失敗時の処理
    die(
        'データベース接続失敗: ' .
        $e->getMessage()
    );

}

一旦、index.phpの修正後確認ともう一点修正として、XSS対策の

htmlspecialchars()

の追加。

<?php

include 'config/database.php';

$sql = "
    SELECT *
    FROM posts
    ORDER BY id DESC
";

$stmt = $pdo->query($sql);

$posts = $stmt->fetchAll(PDO::FETCH_ASSOC);

include 'header.php';

?>

<h2>記事一覧</h2>

<?php foreach($posts as $post): ?>

    <h3>
    <a href="post.php?id=<?php echo $post['id']; ?>">

        <?php echo htmlspecialchars($post['title']); ?>
    </a>
</h3>

<?php endforeach; ?>

<?php include 'footer.php'; ?>

動作確認 記事一覧画面(index.php

https://kimimachilab.com/portfolio/

へアクセスして、ログイン。

Portfolio作成 ③ 管理画面編 で新規投稿画面(new-post.php)を作成し、

Portfolio作成 ④ DB接続編 で

タイトル「CMS開発日記」
本文「MySQLへの保存に成功」

を投稿しているため、既にMySQLpostsテーブルへと保存されているはずですが・・・。

よし!きちんと目標としていた「MySQLSELECTコマンドで必要情報を呼び出し、記事一覧へ表示」が達成できました!

② 記事詳細をMySQL化

記事一覧画面(index.php)のMySQL化に続いて、記事詳細画面(post.php)をMySQL化していきます。

では、現状確認から

現在

データファイル(data/posts.php)を読み込み、「記事のID番号」を取得(idが指定されていなければnullを代入)

配列データから合致したIDの投稿データを探し、保存

HTMLに合わせ、「記事タイトル」と「記事本文」を表示

<?php

// データファイル(data/posts.php)を読み込む
// このファイル内で $posts 配列が利用できるようになる
include 'data/posts.php';

// 「記事のID番号」を取得する
// 例: post.php?id=2 → $id に 2 が入る
// idが指定されていない場合は null を代入する
$id = $_GET['id'] ?? null;

// 指定されたIDの投稿を格納するための変数
// 最初は見つかっていないので null
$targetPost = null;

// $posts 配列の投稿データを1件ずつ取り出して処理する
foreach ($posts as $post) {

    // 現在の投稿IDとURLから取得したIDが一致するか確認
    if ($post['id'] == $id) {

        // 一致した投稿データを保存
        $targetPost = $post;

        // 目的の投稿が見つかったのでループを終了
        break;
    }

}

?>

<?php
// 共通ヘッダーを読み込む
include 'header.php';
?>

<!-- 「記事タイトル」を表示 -->
<h2><?php echo $targetPost['title']; ?></h2>

<!-- 「記事本文」を表示 -->
<p>
    <?php echo $targetPost['content']; ?>
</p>

<?php
// 共通フッターを読み込む
include 'footer.php';
?>

修正後

「データファイル(data/posts.php)を読み込み」の部分を、
index.phpと同じくconfig配下のデータベース接続設定ファイル(database.php)を読み込む」へ変更。

「配列データから合致したIDの投稿データを探し、保存」の部分を、
MySQLSELECTコマンドで呼び出しWHEREコマンドで必要情報を絞り込む

記事一覧画面(index.php)の時は失念していた、XSS対策SQLインジェクション対策も修正。

<?php

// データベース接続ファイルを読み込む
// このファイル内で $pdo(PDOオブジェクト)が作成されている
include 'config/database.php';

// URLパラメータから記事IDを取得する
// 例: post.php?id=3 → $id に 3 が入る
// idが指定されていない場合は null を代入
$id = $_GET['id'] ?? null;

// 指定されたIDの記事を取得するSQL文
// postsテーブルの全てのカラム(*)を取得、
// :id はプレースホルダ(後で値を埋め込むための目印)
$sql = "
    SELECT *
    FROM posts
    WHERE id = :id
";

// SQLを準備する
// prepare()を使うことでSQLインジェクション対策になる
$stmt = $pdo->prepare($sql);

// プレースホルダ :id に実際の値をセットしてSQLを実行
$stmt->execute([
    ':id' => $id
]);

// 検索結果を1件取得する
// FETCH_ASSOC を指定して連想配列として受け取る
$post = $stmt->fetch(PDO::FETCH_ASSOC);

// 共通ヘッダーを読み込む
include 'header.php';

?>

<?php if ($post): ?>
    <!-- 記事が存在する場合 -->

    <h2>
        <?php
        // 記事タイトルを表示
        // htmlspecialchars()でHTMLタグを無効化しXSSを防ぐ
        echo htmlspecialchars($post['title']);
        ?>
    </h2>

    <p>
        <?php
        // 記事本文を表示
        // htmlspecialchars() → HTMLタグを無効化
        // nl2br() → 改行コードを <br> タグに変換
        echo nl2br(htmlspecialchars($post['content']));
        ?>
    </p>

<?php else: ?>
    <!-- 指定されたIDの記事が見つからない場合 -->

    <p>記事が見つかりません。</p>

<?php endif; ?>

<?php
// 共通フッターを読み込む
include 'footer.php';
?>

動作確認 記事詳細画面(post.php

https://kimimachilab.com/portfolio/

へアクセスして、ログイン。

動作確認 記事一覧画面(index.php)で確認した画面から、
記事タイトルである「CMS開発日記」のリンクを押す。

指定しているHTML通りなら

  • ヘッター
  • 記事タイトル「CMS開発日記」
  • 記事本文「MySQLへの保存に成功」
  • フッター

の構成で表示されるはずですが・・・

よし!こちらも想定通りの表示を確認できました!

残作業

今回の作業によって不要となったフォルダ・ファイルを削除しておきましょう。

今回不要となるフォルダ・ファイルは

  • data
  • posts.php

です。

/独自ドメイン/public_html/portfolio/data/posts.php

posts.phpdata配下に配置されている構成となっているので、dataフォルダを削除しましょう。

dataフォルダを指定して、

「削除」ボタンを押す。

「完全に削除」ボタンを押す。

削除完了です。

最後に

ここまで読んでいただき、ありがとうございます。

新たな試みとして、コメントアウトの解説文をより詳しく、見分けやすいようにカラーを付けてみました。

読み解きずらくなったよ。や 見分けずらくなったよ。などございましたら、お気軽にコメントをください。

キミマチとしては、その逆のコメントが送っていただけたら非常に嬉しいですし、いただけるように精進いたします。

\ 最新情報をチェック /

コメントを残す

※ が付いている項目は必須です

CAPTCHA