この記事でできること
PHPからMySQLへ接続し、記事一覧をSELECTで取り出してHTML表示するところまで進めます。用語の整理はMySQLとは、DB未作成の場合はDB作成手順を先に済ませます。表示確認の土台はPHPの動かし方です。
完成形のファイル構成は3点です。db.php(接続専用)、list.php(一覧表示)、posts テーブル(保存先)です。検索付き一覧まで拡張してもファイル構成は変えず、list.php に条件分岐を足すだけで済みます。私たちはPHP公式マニュアル(php.net)のPDO項目とMySQL公式ドキュメントを参考にまとめました。
必要なもの・前提条件
| 必要なもの | 具体例・設定値 | 備考 |
|---|---|---|
| PHPが動く公開環境 | PHP 8.3をご用意している環境 | 管理画面の表示に従う |
| MySQLのDBとユーザー | example_db、example_user | 正式名は作成後の表示をコピーする |
| 4つの接続情報 | ホスト名・DB名・ユーザー・パスワード | ホスト名は環境の案内表示に従う |
| テキストエディタ | UTF-8(BOMなし)保存 | SQLもPHPも同じ文字コードで統一する |
| ブラウザとHTTPS | 無料SSL有効化後のhttps確認 | フォーム拡張前に必須に近い準備 |
私たちはPHP 8.3、MySQL 8 / MariaDB 11.4、無料SSL、FTP・オンラインファイルマネージャー・5GB NVMeストレージ・転送無制限・VistaPanel・Cron・phpMyAdmin・Softaculous 400+アプリをご用意しています。ぜひ無料プランでお試しください。DB個数や上限はプランで変わるため、料金ページと管理画面の表示で確認してください。
前提のSQLは4命令です。SELECT(取り出し)、INSERT(追加)、UPDATE(更新)、DELETE(削除)です。PHP側はPDOの prepare→execute→fetch の3手順に固定すると覚えやすくなります。値の受け渡しは必ずプレースホルダ(:title などの名前付き、または ?)を使います。
詳細手順:接続から一覧表示までの8歩
手順1:DB・ユーザーを作成し4情報を控える 管理画面でDBとDBユーザーを作成し、ユーザーをDBへ紐付けて権限を付与します。ホスト名・DB名・ユーザー名・パスワードの4点を控えます。接頭辞が付く場合があるため、表示された正式名をコピーします。詳しくはDB作成手順の通りです。
手順2:posts テーブルを作成する
管理画面のDB操作項目(一般例としてphpMyAdmin等の表示)またはSQL実行欄で、次のSQLを実行します。文字セットは utf8mb4 に統一します。
-- posts作成・テスト行登録・確認をまとめて実行する
CREATE TABLE IF NOT EXISTS posts (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
body TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 手順3:一覧確認用の仮データ2件
INSERT INTO posts (title, body) VALUES
('初投稿', '一覧表示のテスト1行目です'),
('二回目の投稿', '一覧表示のテスト2行目です');
-- 登録内容の確認
SELECT id, title, created_at FROM posts ORDER BY id DESC LIMIT 10;
手順4:db.php(接続専用ファイル)を作る
接続処理だけを別ファイルに分けます。ファイル名は db.php とします。こうすると list.php や detail.php から使い回せます。
手順5:list.php(一覧表示)を作る
後述のコード全文を使います。公開フォルダの db.php と同じ階層に置きます。
手順6:ブラウザで https://あなたのURL/list.php を開く
投稿タイトルが箇条書きで出れば成功です。出ない場合はエラー表で切り分けます。
手順7:検索条件付き表示へ拡張する
?q=投稿 のような検索語を受け取り、プレースホルダで LIKE 検索します。文字列結合でSQLを組み立てないのが要点です。具体例はコード解説で示します。
手順8:登録処理(INSERT)を別ファイルで足す
add.php(入力)と add-post.php(登録実行)に分けます。登録実行側も prepare+プレースホルダで書きます。完成後はWordPressのような「PHP+DBの完成形」と見比べると理解が深まります。
CRUDとPDOの対応は下表の通りです。
| やりたいこと | SQL例 | PDOの要点 |
|---|---|---|
| 一覧取り出し | SELECT ... ORDER BY id DESC LIMIT 10 | prepare→execute→fetchAll |
| 条件検索 | SELECT ... WHERE title LIKE :q | :q に %語% を束縛する |
| 追加 | INSERT INTO posts (title) VALUES (:title) | 値を直接埋め込まない |
| 更新・削除 | UPDATE ... WHERE id=:id | WHERE のIDも束縛する |
コード全文と解説:db.phpとlist.php
1つ目は db.php です。接続だけを担当し、HTMLは書きません。
<?php
// db.php:接続専用。HTMLは書かない
$host = 'localhost'; // 環境の案内表示に従う。決め打ちしない
$db = 'example_db'; // 作成後に表示された正式名を使う
$user = 'example_user';
$pass = 'STRONG_PASSWORD_HERE'; // 実際の値に置き換える。共有・公開厳禁
try {
$pdo = new PDO(
"mysql:host={$host};dbname={$db};charset=utf8mb4",
$user,
$pass,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]
);
} catch (PDOException $e) {
// 本番では詳細を見せない。ログで確認する
error_log('DB connect failed: ' . $e->getMessage());
http_response_code(500);
echo '接続できませんでした。設定を確認してください。';
exit;
}
警告:パスワード等の秘密情報をソースコードへ直書きしたまま、公開リポジトリへpushしたり、権限の緩い共有で配布したりしないでください。この例の
'STRONG_PASSWORD_HERE'は仮値です。実運用では接続ファイルを公開範囲外に置く、環境変数や管理画面の安全な保管手段を使う、ファイル権限を確認する、の3点を合わせて行います。
2つ目は list.php です。通常一覧と検索付き一覧の両対応で、出力はすべて htmlspecialchars します。
<?php
require __DIR__ . '/db.php';
$q = isset($_GET['q']) ? trim($_GET['q']) : '';
if ($q === '') {
$stmt = $pdo->prepare('SELECT id, title, created_at FROM posts ORDER BY id DESC LIMIT 20');
$stmt->execute();
} else {
// LIKE検索もプレースホルダで渡す。文字列結合でSQLを作らない
$stmt = $pdo->prepare('SELECT id, title, created_at FROM posts WHERE title LIKE :q ORDER BY id DESC LIMIT 20');
$stmt->execute([':q' => '%' . $q . '%']);
}
$rows = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>記事一覧</title>
</head>
<body>
<h1>記事一覧</h1>
<form method="get" action="./list.php">
<input type="text" name="q" value="<?= htmlspecialchars($q, ENT_QUOTES, 'UTF-8') ?>">
<button type="submit">検索</button>
</form>
<ul>
<?php foreach ($rows as $r): ?>
<li><?= htmlspecialchars($r['title'], ENT_QUOTES, 'UTF-8') ?>(<?= htmlspecialchars($r['created_at'], ENT_QUOTES, 'UTF-8') ?>)</li>
<?php endforeach; ?>
</ul>
<?php if (empty($rows)): ?>
<p>該当する記事がありません。</p>
<?php endif; ?>
</body>
</html>
検索語の表示部分もエスケープしています。$_GET['q'] をそのまま value に出すと、検索語に仕込まれたHTMLが実行されるためです。INSERT側(add-post.php)の核も同じ形です。
登録実行側(add-post.php)の核は、INSERT INTO posts (title, body) VALUES (:title, :body) を prepare し、:title と :body に変数を束縛して execute する形です。
ID指定の詳細表示(detail.php?id=3)では :id を (int) に整形した上で束縛し、存在しないIDでは404相当の表示にします。値の検証(空文字・文字数・形式)をPHP側で行う点も、PHP基礎記事の入力検査の考え方と同じです。
よくあるエラーと解決:6症状の切り分け表
設定値の見直しは4情報→紐付け→テーブルの順です。コードを疑う前に正式名のコピペから確認します。
| 症状・文面例 | 確認点 | 対処 |
|---|---|---|
| Access denied/接続できませんでした | ユーザー名・パスワード・権限 | DBへユーザーが追加され権限付与済みか確認し、パスワードを再設定して db.php も更新する |
| Unknown database | DB名の綴り・未作成 | 作成後の正式名をコピーし直し、DB作成手順に戻って存在確認する |
| Could not find driver | 環境のPDO対応 | 管理画面のPHP情報表示と公式マニュアルを確認し、対応環境・バージョンで動かす |
| 文字化け(???や菱形) | charset不一致 | 接続 charset=utf8mb4、テーブル utf8mb4、PHP保存UTF-8、meta charset を統一する |
| テーブルがない/Table doesn’t exist | テーブル作成漏れ・DB違い | 接続先DB名とテーブル一覧を確認し、CREATE TABLEを正しいDBで実行する |
| 検索語で表示が崩れる | エスケープ漏れ | htmlspecialchars(..., ENT_QUOTES, 'UTF-8') の付け忘れを確認し、入力値・DB値の両方を無害化する |
補足として、本番のエラー詳細表示は避けます。$e->getMessage() を画面に出すと、DB名や構成が漏れます。上例のように error_log へ記録し、画面には定型文だけ出します。公開前の土台はHTML公開とSSLの基礎記事も参照してください。
完了チェックリスト
- DB・ユーザーが作成され、ユーザーがDBへ紐付け・権限付与されている
-
postsテーブルがutf8mb4で作成され、テスト行がSELECTで確認できる -
db.phpの4情報が正式名のコピーで埋まり、list.phpと同階層にある -
https://あなたのURL/list.phpで一覧が表示される - 検索語
q付きでも表示が崩れず、該当なし時の表示も確認した - すべての出力に
htmlspecialchars、すべてのSQL値渡しにプレースホルダを使った - エラー時に詳細文を画面に出さず、ログで確認する構成にした
- パスワードを共有・公開場所に置いていない
注意点・セキュリティ
- SQLに値を直接埋め込まない:検索語・ID・タイトルはすべてプレースホルダに束縛します。
LIKE '%'.$q.'%'のような結合は避けます。 - 出力はDB由来も無害化する:投稿タイトルや検索語の再表示はすべて
htmlspecialcharsします。 - 本番のエラー詳細表示は避ける:例外文は
error_logへ記録し、画面には定型文だけ出します。 - 秘密情報の保管を見直す:接続ファイルの公開範囲と権限を確認し、公開リポジトリへのpushやチャットでの平文共有を避けます。
- 権限は必要最小限にする:管理画面で付与する権限は用途に絞り、不要な管理権限を付けないのが基本です。管理画面の表示に従って進めてください。
- 古い接続関数のコピペに注意する:PDOが基準です。公式マニュアルで非推奨かを確認してから使います。
次に読む記事
- DB作成手順 — 4情報を揃える作成と権限付与の手順
- MySQLとは — テーブル・SQL・文字コードの用語整理
- PHPの動かし方 —
hello.php表示とエラー切り分けの復習 - WordPress始め方 — 自動設置を使う場合のDB扱いの違い
出典・参考資料
- PHP公式マニュアル(php.net):PDO、プレースホルダ、
htmlspecialchars、例外処理の仕様 - MySQL公式ドキュメント:SQL構文、文字セット(
utf8mb4)、InnoDBの基本 - 無料プランの内容は料金ページをご覧ください。分からなければ私たちがサポートします。まずは無料プランで実際に触って確かめてみてください。
よくある質問
PDOとは?
PHPからDBへ安全に接続する標準的な窓口です。prepareとプレースホルダで値を渡し、SQLインジェクションを防ぎます。PHP公式マニュアルのPDO項目が正確な仕様です。
接続できないときは?
ホスト名・DB名・ユーザー・パスワードの4点と、DB自体の作成有無、ユーザー紐付けの順に確認します。エラー文を訪問者に見せず、ログと設定値で切り分けます。
無料サーバーでもDB連携できる?
FreeHostBoxではMySQL 8/MariaDB 11.4をご用意しています。個数や上限は料金ページと管理画面の表示で確認してください。ぜひ無料プランでお試しください。
SQLに値を直接書いてはいけないの?
検索語やIDを文字列結合で埋め込むとSQLインジェクションの原因になります。:titleのようなプレースホルダに値を束縛する書き方を徹底します。
文字化けするのはなぜ?
接続文字コード・テーブル文字コード・保存形式・HTMLのmeta指定のいずれかの不一致が原因です。接続時にcharset=utf8mb4を指定し、テーブルもutf8mb4に統一します。
パスワードはどこに書くの?
接続用の別ファイルにまとめ、公開範囲を限定して保管します。共有や公開リポジトリへのpushは避けます。詳しくは本文の注意点で解説します。
PHPを無料サーバーで動かす
読むだけより1ファイル動かす方が速いです。無料サーバーで表示確認まで進みましょう。