PHPからデータベースへ接続する方法について

採用はこちら

目次

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には、それぞれ特徴があります。

項目PDOMySQLi
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への接続では、localhost127.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からデータベースへ接続する方法についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次