PHPからデータベースへ接続する方法
PHPからデータベースへ接続する場合は、主にPDOまたはMySQLiを使用します。
特にMySQLへ接続する場合、この2つが代表的な方法です。
PDOはMySQL以外のデータベースにも対応できる汎用的な仕組みで、MySQLiはMySQL専用の拡張機能です。
新しくPHPでWebアプリケーションを開発する場合は、用途に応じてPDOまたはMySQLiを選択します。
PHPからデータベースへ接続する基本的な仕組み
PHPでWebサービスを開発する場合、ユーザー情報や商品情報、記事データなどをデータベースへ保存するケースが多くあります。
たとえば、PHPとMySQLを組み合わせる場合は、PHPからPDOやMySQLiを通じてMySQLへ接続します。
基本的な流れは次のとおりです。
ブラウザ
↓
PHP
↓
PDOまたはMySQLi
↓
MySQL
↓
データの取得・登録・更新・削除
PHPからデータベースへ接続した後は、SQLを実行してデータを操作します。
PHPからMySQLへ接続する主な方法
PHPからMySQLへ接続する方法として、主にPDOとMySQLiがあります。
どちらも現在のPHPで利用できますが、特徴が異なります。
PDOとは
PDOは「PHP Data Objects」の略で、PHPからデータベースへアクセスするための共通インターフェイスです。
MySQLだけでなく、PostgreSQLやSQLiteなどにも対応できます。
ただし、PDOを利用するだけではデータベースへ接続できません。
接続するデータベースに対応したPDOドライバが必要です。
たとえば、MySQLでは主に次のドライバを利用します。
pdo_mysql
PostgreSQLなら次のドライバです。
pdo_pgsql
SQLiteなら次のドライバを利用します。
pdo_sqlite
複数種類のデータベースを扱う可能性がある場合は、PDOが使いやすいでしょう。
MySQLiとは
MySQLiは、MySQLへ接続するためのPHP拡張機能です。
MySQL専用であるため、PostgreSQLやSQLiteなどには利用できません。
一方で、MySQL固有の機能を扱いやすいという特徴があります。
MySQLだけを利用するシステムでは、MySQLiも有力な選択肢です。
PDOを使ってPHPからMySQLへ接続する方法
PDOでMySQLへ接続する場合は、PDOクラスを使用します。
基本的なコードは次のとおりです。
<?php
$host = 'localhost';
$dbname = 'sample_db';
$username = 'sample_user';
$password = 'password';
$dsn = "mysql:host={$host};dbname={$dbname};charset=utf8mb4";
try {
$pdo = new PDO(
$dsn,
$username,
$password,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
echo 'データベースへの接続に成功しました。';
} catch (PDOException $e) {
error_log($e->getMessage());
echo 'データベースへの接続に失敗しました。';
}
PDOの接続情報
PDOでMySQLへ接続する際は、主に次の情報を指定します。
$host = 'localhost';
$dbname = 'sample_db';
$username = 'sample_user';
$password = 'password';
それぞれの意味は次のとおりです。
$hostにはMySQLサーバーのホスト名を指定します。
$dbnameには接続するデータベース名を指定します。
$usernameと$passwordには、MySQLへ接続するユーザーの認証情報を指定します。
DSNとは
PDOでは、DSNを使用して接続先を指定します。
MySQLの場合は次のように記述できます。
$dsn = 'mysql:host=localhost;dbname=sample_db;charset=utf8mb4';
それぞれの指定には次の意味があります。
mysql
→ MySQL用PDOドライバ
host=localhost
→ MySQLサーバーのホスト名
dbname=sample_db
→ データベース名
charset=utf8mb4
→ 接続時の文字コード
MySQLを利用する場合は、文字コードとしてutf8mb4を指定するのが一般的です。
PDOのエラー処理を設定する
PDOでは、エラー処理の方法を設定できます。
よく使用されるのが次の設定です。
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
これを指定すると、データベース操作でエラーが発生した際に例外が発生します。
PHP 8.0以降ではPDO::ERRMODE_EXCEPTIONがデフォルトですが、コード上で明示しておくと動作が分かりやすくなります。
また、次の設定もよく利用されます。
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
これを設定すると、SELECTで取得した結果をデフォルトで連想配列として扱えます。
PHPからSELECTでデータを取得する方法
データベースへ接続した後は、SQLを使ってデータを取得できます。
たとえば、usersテーブルからユーザー情報を取得する場合は次のように記述します。
$sql = 'SELECT id, name, email FROM users';
$stmt = $pdo->query($sql);
$users = $stmt->fetchAll();
foreach ($users as $user) {
echo $user['name'];
}
固定されたSQLをそのまま実行する場合は、query()を利用できます。
条件付きSELECTではプリペアドステートメントを使う
ユーザーから受け取った値をSQL条件として使う場合は、SQL文字列へ直接連結せず、プリペアドステートメントを使用します。
たとえば、ユーザーIDを指定して検索する場合は次のように記述します。
$sql = '
SELECT id, name, email
FROM users
WHERE id = :id
';
$stmt = $pdo->prepare($sql);
$stmt->execute([
'id' => 10,
]);
$user = $stmt->fetch();
:idがプレースホルダです。
実際の値はexecute()で渡します。
SQLへ値を直接連結しない
次のように、外部入力をSQLへ直接連結する書き方は避けるべきです。
$sql = "SELECT * FROM users WHERE name = '" . $_GET['name'] . "'";
入力内容によっては、SQLインジェクションにつながる可能性があります。
代わりに次のように記述します。
$sql = 'SELECT * FROM users WHERE name = :name';
$stmt = $pdo->prepare($sql);
$stmt->execute([
'name' => $_GET['name'],
]);
プリペアドステートメントを使用することで、SQL文と値を分離して扱えます。
プレースホルダは主に値へ使用する
プリペアドステートメントのプレースホルダは、主に値を指定するために利用します。
たとえば次のような使い方です。
WHERE id = :id
一方、カラム名やテーブル名などをプレースホルダで自由に置き換えることはできません。
ORDER BYの対象カラムなどを動的に切り替える場合は、許可するカラム名をあらかじめ限定するなどの対策が必要です。
PDOでINSERTする方法
新しいデータを登録する場合はINSERTを使用します。
$sql = '
INSERT INTO users (name, email)
VALUES (:name, :email)
';
$stmt = $pdo->prepare($sql);
$stmt->execute([
'name' => '山田太郎',
'email' => 'taro@example.com',
]);
INSERTでも、外部入力を扱う場合はプレースホルダを利用します。
PDOでUPDATEする方法
既存データを更新する場合はUPDATEを使用します。
$sql = '
UPDATE users
SET name = :name,
email = :email
WHERE id = :id
';
$stmt = $pdo->prepare($sql);
$stmt->execute([
'name' => '山田次郎',
'email' => 'jiro@example.com',
'id' => 1,
]);
UPDATEではWHERE条件を付け忘れないよう注意が必要です。
WHEREを指定しないと、条件によってはテーブル内のすべての行が更新対象になります。
PDOでDELETEする方法
データを削除する場合はDELETEを使用します。
$sql = '
DELETE FROM users
WHERE id = :id
';
$stmt = $pdo->prepare($sql);
$stmt->execute([
'id' => 1,
]);
DELETEでもWHERE条件が重要です。
たとえば次のSQLを実行すると、
DELETE FROM users;
基本的にテーブル内の全行が削除対象になります。
MySQLiを使ってPHPからMySQLへ接続する方法
MySQL専用でよければ、MySQLiを使用することもできます。
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$host = 'localhost';
$username = 'sample_user';
$password = 'password';
$dbname = 'sample_db';
try {
$mysqli = new mysqli(
$host,
$username,
$password,
$dbname
);
$mysqli->set_charset('utf8mb4');
echo 'データベースへの接続に成功しました。';
} catch (mysqli_sql_exception $e) {
error_log($e->getMessage());
echo 'データベースへの接続に失敗しました。';
}
PHP 8.1以降ではMySQLiのデフォルトエラーモードが変更されていますが、mysqli_report()を明示しておくとコードの意図が分かりやすくなります。
MySQLiでプリペアドステートメントを使う
MySQLiでもプリペアドステートメントを利用できます。
$sql = '
SELECT id, name, email
FROM users
WHERE id = ?
';
$stmt = $mysqli->prepare($sql);
$id = 10;
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
?がプレースホルダです。
bind_param()のiは整数型を意味します。
PDOとMySQLiの違い
PDOとMySQLiには、それぞれ特徴があります。
| 項目 | PDO | MySQLi |
|---|---|---|
| MySQL | 対応 | 対応 |
| PostgreSQLなど | 対応可能 | 非対応 |
| SQLite | 対応 | 非対応 |
| 名前付きプレースホルダ | 対応 | 基本的に?を使用 |
| プリペアドステートメント | 対応 | 対応 |
| MySQL固有機能 | 一部対応 | 利用しやすい |
複数のデータベースへ対応する可能性があるならPDOが便利です。
MySQLだけを利用し、MySQL固有の機能を積極的に使用する場合はMySQLiも適しています。
mysql_connect()は使用しない
古いPHPコードでは、次のような記述を見かける場合があります。
mysql_connect(
'localhost',
'username',
'password'
);
しかし、旧MySQL拡張機能はPHP 5.5で非推奨となり、PHP 7.0で削除されています。
現在のPHPでは利用できません。
そのため、新規開発では次のような古い関数を使用しないようにします。
mysql_connect()
mysql_query()
mysql_real_escape_string()
代わりにPDOまたはMySQLiを利用します。
データベース接続情報をソースコードへ直接書かない
学習用コードでは、次のようにパスワードを直接記述することがあります。
$password = 'password';
しかし、本番環境では認証情報をソースコードへ直接埋め込むことは避けた方が安全です。
たとえば環境変数を利用できます。
$host = getenv('DB_HOST');
$dbname = getenv('DB_NAME');
$username = getenv('DB_USER');
$password = getenv('DB_PASSWORD');
こうすることで、Gitへソースコードを保存した際にデータベースの認証情報まで公開してしまうリスクを減らせます。
.envファイルを使う場合もGitへ登録しない
PHPフレームワークなどでは.envファイルを利用するケースがあります。
ただし、.envにデータベースのパスワードなどを保存する場合は、そのファイルをGitへコミットしないように注意が必要です。
本番環境では、クラウドのSecret ManagerやDocker Secretsなどを利用する方法もあります。
データベースエラーをそのまま画面へ表示しない
開発中は次のようにエラー内容を確認することがあります。
echo $e->getMessage();
しかし、本番環境でデータベースの詳細なエラーをそのまま利用者へ表示することは避けるべきです。
次のように、詳細な情報はログへ記録します。
catch (PDOException $e) {
error_log($e->getMessage());
echo 'システムエラーが発生しました。';
}
データベースエラーには、SQLやテーブル名、接続情報などが含まれる場合があります。
外部へ詳細情報を公開しない設計が重要です。
localhostと127.0.0.1の違いに注意する
MySQLへの接続では、localhostと127.0.0.1が必ずしも同じ接続方法になるとは限りません。
環境によっては、
localhost
を指定するとUnixソケット接続となり、
127.0.0.1
を指定するとTCP/IP接続になることがあります。
データベースへ接続できない場合は、ホスト名だけでなく接続方式の違いも確認するとよいでしょう。
Dockerではlocalhostではなくサービス名を使う場合がある
Docker ComposeでPHPとMySQLを別コンテナとして動かしている場合、PHPコンテナからMySQLコンテナへ接続するときにlocalhostを使わないケースがあります。
たとえば次の構成です。
services:
php:
# PHPコンテナ
db:
image: mysql:8
この場合、PHP側では次のように指定できます。
$host = 'db';
コンテナ内のlocalhostは基本的にそのコンテナ自身を指すため、MySQLが別コンテナにある場合はサービス名などを利用します。
PHPのデータベース拡張機能を確認する
接続情報が正しくても、PHP側に必要な拡張機能が入っていないと接続できません。
PDOでMySQLへ接続する場合は、主に次のモジュールが必要です。
PDO
pdo_mysql
MySQLiを利用する場合は、
mysqli
が必要です。
CLI環境では次のコマンドで確認できます。
php -m
表示結果に必要なモジュールが含まれているか確認します。
複数のSQLを実行する場合はトランザクションを使う
複数のSQLを一連の処理として実行する場合は、トランザクションを利用するとデータの整合性を保ちやすくなります。
たとえば、送金処理のように複数のUPDATEをまとめて成功または失敗させたい場合です。
try {
$pdo->beginTransaction();
$stmt = $pdo->prepare(
'UPDATE accounts
SET balance = balance - :amount
WHERE id = :id'
);
$stmt->execute([
'amount' => 1000,
'id' => 1,
]);
$stmt = $pdo->prepare(
'UPDATE accounts
SET balance = balance + :amount
WHERE id = :id'
);
$stmt->execute([
'amount' => 1000,
'id' => 2,
]);
$pdo->commit();
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
throw $e;
}
すべての処理が成功した場合はcommit()を実行し、途中でエラーが発生した場合はrollBack()で元に戻します。
データベースユーザーには必要最小限の権限を与える
PHPから利用するデータベースユーザーには、必要以上の権限を与えないことも重要です。
一般的なWebアプリケーションでは、用途に応じて次のような権限を使用します。
SELECT
INSERT
UPDATE
DELETE
一方で、アプリケーションから使用しないのであれば、データベースの削除やユーザー管理に関する強い権限を与える必要はありません。
必要最小限の権限だけを付与することで、万が一アプリケーションが攻撃された場合の被害を抑えやすくなります。
PHPからデータベースへ接続できない場合の確認ポイント
PHPからMySQLへ接続できない場合は、コードだけでなく周辺環境も確認する必要があります。
ホスト名を確認する
ローカル環境では次のような値が使われます。
localhost
127.0.0.1
Docker環境では、Docker Composeのサービス名が使われる場合があります。
db
mysql
database
レンタルサーバーやクラウドでは、サービス側から指定されたデータベースホスト名を使用します。
データベース名を確認する
次の値が実際のデータベース名と一致しているか確認します。
$dbname = 'sample_db';
ユーザー名とパスワードを確認する
MySQLへ接続するユーザー名とパスワードが正しいか確認します。
$username = 'sample_user';
$password = 'password';
また、ユーザーが接続元ホストからの接続を許可されているかも確認が必要です。
必要なPHP拡張機能を確認する
PDOでMySQLへ接続するならpdo_mysql、MySQLiならmysqliが必要です。
php -m
を実行し、必要な拡張機能が読み込まれているか確認します。
MySQLが起動しているか確認する
PHP側の設定が正しくても、MySQLサーバー自体が停止していれば接続できません。
Dockerを利用している場合は、MySQLコンテナが正常に起動しているかも確認します。
PHPからデータベースへ接続する際のポイント
PHPからMySQLなどのデータベースへ接続する場合は、PDOまたはMySQLiを利用します。
汎用性を重視する場合はPDO、MySQL専用の機能を利用したい場合はMySQLiが候補になります。
特に重要なのは、ユーザー入力をSQLへ直接連結せず、プリペアドステートメントを使用することです。
また、本番環境ではデータベースのパスワードをソースコードへ直接記述しない、詳細なエラーメッセージを画面へ表示しない、データベースユーザーへ必要最小限の権限だけを与えるといった対策も重要です。
PHP 8系ではPDOやMySQLiのエラー処理に関するデフォルト設定も過去のバージョンから変更されているため、古いPHPの記事を参考にする場合はバージョン差にも注意しましょう。
以上、PHPからデータベースへ接続する方法についてでした。
最後までお読みいただき、ありがとうございました。










