PHP

PHPとMySQL接続|仕組み・手順・最小コードを解説

暗い画面のプログラムコードのイメージ
要点: PHPとMySQLを接続してデータを表示する流れを解説。PDOの最小コード、プレースホルダの理由、よくある接続エラーの直し方まで実践的に案内します。

この記事でできること

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_dbexample_user正式名は作成後の表示をコピーする
4つの接続情報ホスト名・DB名・ユーザー・パスワードホスト名は環境の案内表示に従う
テキストエディタUTF-8(BOMなし)保存SQLもPHPも同じ文字コードで統一する
ブラウザとHTTPS無料SSL有効化後のhttps確認フォーム拡張前に必須に近い準備

私たちはPHP 8.3MySQL 8 / MariaDB 11.4無料SSL、FTP・オンラインファイルマネージャー・5GB NVMeストレージ転送無制限・VistaPanel・Cron・phpMyAdmin・Softaculous 400+アプリをご用意しています。ぜひ無料プランでお試しください。DB個数や上限はプランで変わるため、料金ページと管理画面の表示で確認してください。

前提のSQLは4命令です。SELECT(取り出し)INSERT(追加)UPDATE(更新)DELETE(削除)です。PHP側はPDOの prepareexecutefetch の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.phpdetail.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 10prepareexecutefetchAll
条件検索SELECT ... WHERE title LIKE :q:q%語% を束縛する
追加INSERT INTO posts (title) VALUES (:title)値を直接埋め込まない
更新・削除UPDATE ... WHERE id=:idWHERE の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点を順に確認する

設定値の見直しは4情報→紐付け→テーブルの順です。コードを疑う前に正式名のコピペから確認します。

症状・文面例確認点対処
Access denied/接続できませんでしたユーザー名・パスワード・権限DBへユーザーが追加され権限付与済みか確認し、パスワードを再設定して db.php も更新する
Unknown databaseDB名の綴り・未作成作成後の正式名をコピーし直し、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が基準です。公式マニュアルで非推奨かを確認してから使います。

次に読む記事

出典・参考資料

  • 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は避けます。詳しくは本文の注意点で解説します。

更新履歴: 公開 2026-09-03 / 最終更新 2026-09-09。技術仕様・対応バージョンは変更されるため、重要な設定は公式ドキュメントも併せて確認してください。

PHPを無料サーバーで動かす

読むだけより1ファイル動かす方が速いです。無料サーバーで表示確認まで進みましょう。

動かし方を読む 他の記事を探す