🔰はじめての方へ

データベースが怖かった私が、PHPのファイル構成を理解するまで【コード例つき】

AI
記事内に広告が含まれています。
スポンサーリンク

Web制作の勉強をしていて、ずっと避けていたものがあります。

データベースです。

触ったら何か取り返しのつかないことが起きるんじゃないか、という気持ちがありました。

AIを使いながら学習していたのですが、出てくる言葉が英単語ばかりでした。

PDOって何なのか。

DSNって何なのか。

prepare、execute?

そもそも、なんでファイルを分けるのか。

意味がわからないまま、挫折しそうになっていました。

それでも実際にデータベースを使ったLPを作ってみたところ、自分が書いているコードが何をしているのか、ようやく少しわかってきました。

今回は「PHPでデータベースを扱う3ファイル」について、初心者目線でまとめていきます。

私自身まだ勉強中なので、拙い部分があるかと思います。同じところでつまずいている方の参考になればうれしいです。

そもそもデータベースって何なのか

私は最初、データベース=難しいもの、というイメージだけを持っていました。

でも実際に触ってみると、情報を整理して保存しておく箱のようなもので、それ自体は特別難しいものではなさそうだと理解しました。

たとえば、メーカー名のデータベースを作りたい場合。

maker テーブル

id | maker_name
-----------------
1  | メーカーA
2  | メーカーB
3  | メーカーC

こういう表を保存しておきます。

そして「id=2 のメーカー名を教えて」と聞かれたら、「メーカーBです」と返してくれる。

そういう仕組みです。

MySQL と phpMyAdmin は別のもの

ここで「そもそも、そのデータは誰が入れているのか」という疑問が出てきます。

私は見よう見まねで、phpMyAdminという画面から数値を入力しました。

データベースといえばよく聞くのがMySQLです。では、私が触ったphpMyAdminは何だったのか。

調べたところ、この2つはまったく別のものでした。

MySQL=データが保存されている倉庫

MySQLは、実際にデータを保存している場所です。

先ほどのmakerテーブルのようなデータが、この中に入っています。

phpMyAdmin=倉庫の管理画面

phpMyAdminは、その倉庫の中を見たり編集したりするための画面です。

データを追加する、修正する、削除する、SQLを書いて検索する。こういった操作ができます。

関係としては、こういう形になります。

phpMyAdmin(管理画面)
  ↓
MySQL(データが保存されている場所)

私が勘違いしていたこと

私は最初、phpMyAdmin=データベースだと思っていました。

データベース系ではphpMyAdminしか触っていなかったので、簡単じゃないかとすら思っていました…

実際には、それぞれの役割はこう分かれています。

phpMyAdmin → 操作するための画面
MySQL      → データを保存している本体
PHP        → データを取りに行く人

PHPは、倉庫にデータを取りに行く係だったわけです。

データが画面に表示されるまでの流れ

たとえば、phpMyAdminから新しく「メーカーD」を登録したとします。

id | maker_name
-----------------
1  | メーカーA
2  | メーカーB
3  | メーカーC
4  | メーカーD

この状態で、次のURLにアクセスしたときの流れです。

例:https://sample.com/?maker=3

① ユーザーが ?maker=3 でアクセス
  ↓
② data.php(データ取得ファイル)が呼ばれる
  ↓
③ db_connect.php(接続ファイル)がデータベースに接続
  ↓
④ maker テーブルから id=3 を探す
  ↓
⑤ $config['maker_name'] に値が入る
  ↓
⑥ index.php で表示される

この流れで、データベースに入れておいた情報がサイトに表示されます。

URLの「?maker=3」の部分については、後ろのほうで説明します。

使うファイルは4つ

私が今回作ったのは、データベース用のファイル3つと、実際に表示するファイル1つの合計4つです。

ファイル名は私が勝手に付けたものなので、それぞれの環境に合わせて変えて問題ないと思います。

① db_connect_secrecy.php(機密ファイル)

ホスト名、DB名、ユーザー名、パスワードを書いておくファイルです。

ここが一番大事なファイルで、GitHubに上げないこと、AIに読ませないことが必要になります。

② db_connect.php(接続ファイル)

①を読み込んで、PDOでデータベースへの接続を確立するファイルです。

③ data.php(データ取得ファイル)

②を読み込んで、URLからIDを受け取り、データベースからメーカー名を取ってくるファイルです。

④ index.php(ページ本体)

③を読み込んで、HTMLの中にメーカー名を表示するファイルです。

なんでファイルを分けるのか

最初は「なんで1つのファイルにまとめて書いちゃダメなんだろう」と思っていました。

分けてみてわかったのは、機密情報を守れることと、使い回しができることでした。

①の機密ファイルを分けると、パスワードをGitに上げずに済みますし、AIに読ませないための設定もしやすくなります。

②の接続ファイルを分けると、DB接続の処理が1箇所にまとまります。他のページでもそのまま読み込むだけで使えます。

③のデータ取得ファイルを分けると、やりたい処理だけに集中できます。

今後、別のテーブルからデータを取りたくなったときも、①と②はそのまま使い回して③だけ新しく作ればいい。

これはかなり便利だと思いました。

実際に書いたコード(4ファイル分)

まずは私が使ったコードを、そのまま載せておきます。

① db_connect_secrecy.php(機密ファイル)

<?php
$db_host = 'localhost';        // Dockerの場合は db
$db_name = 'sample_database';  // データベース名
$db_user = 'sample_user';      // ユーザー名
$db_pass = 'sample_password';  // パスワード
$db_charset = 'utf8mb4';       // 文字コード
?>

② db_connect.php(接続ファイル)

<?php
include(__DIR__ . '/db_connect_secrecy.php');

$dsn = "mysql:host={$db_host};dbname={$db_name};charset={$db_charset}";

try {
    $pdo = new PDO($dsn, $db_user, $db_pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false,
    ]);
} catch (PDOException $e) {
    die('DB接続エラー');
}
?>

③ data.php(データ取得ファイル)

<?php
include(__DIR__ . '/db_connect.php');

// ?maker=2 のようにURLパラメータからメーカーIDを取得
$maker_id = isset($_GET['maker']) ? (int)$_GET['maker'] : 1;

$stmt = $pdo->prepare('SELECT maker_name FROM maker WHERE id = :id LIMIT 1');
$stmt->execute([':id' => $maker_id]);
$maker = $stmt->fetch();

if (!$maker) {
    $stmt = $pdo->prepare('SELECT maker_name FROM maker WHERE id = 1 LIMIT 1');
    $stmt->execute();
    $maker = $stmt->fetch();
}

$config['maker_name'] = $maker ? $maker['maker_name'] : 'メーカー1';
?>

④ index.php と、実際に表示するファイル

<?php
$config = include(__DIR__ . '/config.php');
include(__DIR__ . '/data.php');
?>
<div class="hero">
    <p class="hero-maker"><?php echo $config['maker_name']; ?></p>
</div>

コードの中身を1つずつ見ていきます

①機密ファイル:パスワードを直接書いて大丈夫なのか

ここで最初に疑問が出ました。パスワードをファイルに直接書いて大丈夫なのか、ということです。

調べた範囲では、パスワードを処理のコードの中に直接書かないことが大事なようです。

接続情報だけを別ファイルに切り出しておいて、そのファイル自体を守る、という考え方だと理解しました。

GitHubを使っている場合は.gitignoreで管理対象から外す。AIを使っている場合は読ませない設定をする。

コードを書くことと同じくらい、情報を守ることも大事だと感じました。

この設定については別の記事にまとめているので、そちらも置いておきます。

【PHPファイル機密情報管理】他者に見られてしまう情報と見られないもの。AIに機密情報を読み込まれないようにする方法も解説
PHPでデータベースを利用し始めると、データベースのユーザー名やパスワードはどこに書けばいいの?ブラウザの検証ツールで他人に見られないの?CursorやClaudeなどのAIに読み込まれないようにできるの?といった疑問が出てきます。私自身も…
【GitHubパスワード管理】使うなら必須!パスワードやデータベース情報を安全に管理する方法
PHPやWordPress、Webサイト制作を学び始めると、GitHubでソースコードを管理する機会が増えてきます。しかし、その際に注意しなければならないのが「パスワードの管理」です。私も最初は、データベースのパスワードはどこに書けばいいの…

Claude Codeを使う場合には下記記事もご参照ください!

【Claude Code】機密ファイル(パスワードなど)をClaude Codeに読み込まないで欲しい時の書き方
私はAI を使用してサイトの作成をすることが多く、cursorやClaude Codeを使ってコードを修正してもらったりしています。Claude Codeは、AIがコードを読み書きしてくれるとても便利なツールです。しかし便利すぎるがゆえに、…

②接続ファイル:DSNとPDO

include(__DIR__ . ‘/db_connect_secrecy.php’);

機密ファイルを読み込む部分です。これで $db_host などの変数が使えるようになります。

$dsn = “mysql:host={$db_host};dbname={$db_name};charset={$db_charset}”;

DSNは、接続先の住所のようなものです。

どのサーバーの、どのデータベースに、どの文字コードで接続するか。それを1行にまとめた文字列だと理解しました。

$pdo = new PDO($dsn, $db_user, $db_pass);

PDOは、PHPからデータベースに接続するための道具です。

私は翻訳係のようなものだとイメージしています。

PHP
 ↓
PDO(翻訳係)
 ↓
MySQL

②接続ファイル:PDOのオプション3つ

new PDO の後ろに付いている配列の部分です。

ERRMODE_EXCEPTION:エラーが起きたらすぐにエラーを出します。黙って無視されないようにするものです。

FETCH_ASSOC:データを取ってきたとき、カラム名をキーにした配列で返してくれます。

EMULATE_PREPARES => false:SQLインジェクション対策を強くするための設定です。

②接続ファイル:try / catch とは

try と catch は、とりあえずやってみて、失敗したら対処するという書き方です。

JavaScriptのif文と何が違うのか、最初はわかりませんでした。

私は、こう整理しました。

if文は、事前に確認する。ドアが開いているか確認してから入る。

try/catchは、とりあえずやってみる。ドアを開けてみて、開かなかったら対処する。

データベースは、実際に接続してみないとサーバーが落ちているのか、パスワードが違うのかがわかりません。

だからこそ、とりあえず開けてみる書き方が向いているようです。

PHPの「$」は何なのか

$pdo のように、頭に $ が付いていることが多くて気になっていました。

PHPでは変数(値を入れる箱)を作るとき、必ず先頭に $ を付けるルールがあります。

JavaScriptの let のようなものだと考えると、少しわかりやすくなりました。

③データ取得ファイル:URLから値を受け取る

$maker_id = isset($_GET[‘maker’]) ? (int)$_GET[‘maker’] : 1;

URLからメーカーIDを取得している部分です。

$_GET は、PHPが最初から用意している特別な変数です。

URLの「?」以降の値を、自動的に取ってきてくれます。

だから、https://sample.com/?maker=3 でアクセスすると、3という値が受け取れる、というわけでした。

③データ取得ファイル:prepare / execute / fetch

ここが一番わからなかったところです。

データベースへの問い合わせは、3ステップに分かれていました。

① prepare(...)  命令書を作る(まだ実行しない)
② execute(...)  :id に実際の値を入れて実行する
③ fetch()       結果を1件取り出す

いきなり取ってくるのではなく、命令書を先に作って、値をあとから流し込むという順番になっています。

SQLの中身も分解すると、そんなに複雑ではありませんでした。

SELECT maker_name  → maker_name というカラム(列)を取ってきて
FROM maker         → maker というテーブル(表)から
WHERE id = :id     → id が指定した値のものだけ
LIMIT 1            → 1件だけ

③データ取得ファイル:「:id」はSQLインジェクション対策

この「:id」が何なのか、ずっとわかりませんでした。

調べたところ、SQLインジェクション対策のための書き方でした。

SQLインジェクションは、悪意のあるユーザーがURLに攻撃用のコードを仕込む攻撃のことです。

たとえば、こう書いてしまったとします。

$sql = "SELECT * FROM maker WHERE id = " . $_GET['maker'];

URLの値をそのままSQLにつなげているので、想定していない命令が実行される可能性があります。

テーブルを消される、といったことも起こり得るようです。

そこで、こう書きます。

WHERE id = :id

こう書いておくと、「これはデータですよ」とPDOが安全に扱ってくれます

命令ではなく、ただの値として処理してくれる、ということだと理解しました。

③データ取得ファイル:最後のデフォルト値

$config[‘maker_name’] = $maker ? $maker[‘maker_name’] : ‘メーカー1’;

データベースが完全に空だったときにだけ使われる、最後の保険です。

値は自由に変えて大丈夫です。

私がつまずいたポイント

  • phpMyAdmin=データベースだと思い込んでいた(実際は管理画面)
  • ファイルを分ける意味がわからなかった(機密の分離と、使い回しのため)
  • 「:id」を書かずにURLの値を直接つなげると、攻撃を受ける可能性がある
  • 機密ファイルは.gitignoreとAIの設定、両方で守る必要がある

まとめ

データベースについては、まだまだ学習が必要だと思っています。

それでも、避けていたころに比べれば、自分が書いているコードが何をしているのかは見えるようになりました。

データを保存しているのがMySQLで、それを見る画面がphpMyAdmin。取りに行くのがPHPで、その通訳がPDO。

この関係がわかっただけでも、コードを読むのがずいぶん楽になりました。

私と同じところで止まっている方に、少しでも届いたらうれしいです。

ここに書ききれなかった部分もあるので、気になることがあればコメントで教えていただけると助かります。

ここまで読んでくださり、ありがとうございました。