Contents
PHP で MySQL に接続する際の最新情報と移行ポイント
PHP7 以降、mysql_* 系関数は 完全に削除 されました。現在は標準拡張として提供されている mysqli と PDO_MySQL を利用します。本稿では、両者の概要・選択基準・実装例に加えて、公式ドキュメントへの参照、php.ini の設定ポイント、エラーハンドリングのベストプラクティスをまとめます。
この記事は PHP 8.2 を前提に作成していますが、PHP 7.4 以上でも同様に適用できます。
1️⃣ mysql_* 系関数の廃止経緯(公式情報)
| 項目 | 内容 | 参考 |
|---|---|---|
| 非推奨化 (Deprecated) | PHP 5.5 で mysql_connect() 等が 非推奨 とされました。 |
https://www.php.net/manual/ja/migration71.deprecated.php |
| 完全削除 (Removed) | PHP 7.0 で関数自体が削除され、コードは致命的エラーになります。 | https://www.php.net/manual/ja/migration70.removed-functions.php |
mysql_* が提供できなかった主な機能は プレースホルダー未対応、例外ベースのエラーハンドリングが不可、utf8mb4 への完全対応が難しい ことです。これらを補完する形で mysqli と PDO が推奨されています。
2️⃣ mysqli と PDO の比較表
| 項目 | mysqli | PDO |
|---|---|---|
| 対応 DB | MySQL 系専用 | 40 種類以上(MySQL, PostgreSQL, SQLite, SQL Server …) |
| プリペアドステートメント | サポート (オブジェクト/手続き型) | 完全サポート、名前付きプレースホルダーあり |
| エラーモード | mysqli_report() で例外化可能。デフォルトは戻り値チェック。 |
デフォルトで 例外 (PDOException) が投げられる (ERRMODE_EXCEPTION) |
| トランザクション制御 | $mysqli->begin_transaction(), commit(), rollback() |
$pdo->beginTransaction(), commit(), rollBack() |
| 永続接続 (persistent) | p: プレフィックスで有効化可能。 |
PDO::ATTR_PERSISTENT => true で有効化 |
| 学習コスト | MySQL に特化しているため低め。 | 複数 DB を扱う場合は学習が必要。 |
| 推奨シーン | 小〜中規模の MySQL 専用アプリ、既存コードのリファクタリング | マルチDB 対応、フレームワーク共通基盤、大規模プロジェクト |
結論:
- MySQL のみで完結するシンプルな案件 → mysqli が手軽。
- 将来的に他 DB へ拡張したい、または フレームワーク/ライブラリと統一的に使う → PDO を選択。
3️⃣ 実装例 ― エラーハンドリングを含む接続コード
3.1 mysqli(オブジェクト指向)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?php // -------------------------------------------------- // ① 設定は .env や環境変数から取得するのがベスト // -------------------------------------------------- $host = $_ENV['DB_HOST'] ?? '127.0.0.1'; $user = $_ENV['DB_USER'] ?? 'db_user'; $pass = $_ENV['DB_PASS'] ?? ''; $db = $_ENV['DB_NAME'] ?? 'sample_db'; $port = $_ENV['DB_PORT'] ?? 3306; // -------------------------------------------------- // ② エラーモードを例外化(開発・本番どちらでも安全) // -------------------------------------------------- mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); try { $mysqli = new mysqli($host, $user, $pass, $db, (int)$port); // 文字セットは接続直後に必ず設定(utf8mb4 が推奨) $mysqli->set_charset('utf8mb4'); } catch (mysqli_sql_exception $e) { // パスワード等機密情報は除外してログ出力 error_log('[MySQLi] Connect failed: ' . $e->getMessage()); // 本番環境では画面にエラーメッセージを表示しない exit('データベース接続に失敗しました。管理者へお問い合わせください。'); } |
ポイント
- mysqli_report() により 例外 (mysqli_sql_exception) がスローされ、if ($mysqli->connect_errno) のような戻り値チェックが不要になります。
- set_charset('utf8mb4') は MySQL 側の文字セット設定であり、PHP の default_charset とは別です。
3.2 PDO(例外モード)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php $dsn = sprintf( 'mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', $_ENV['DB_HOST'] ?? '127.0.0.1', (int)($_ENV['DB_PORT'] ?? 3306), $_ENV['DB_NAME'] ?? 'sample_db' ); $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 必ず例外化 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, // ネイティブプリペアドステートメント使用 PDO::ATTR_PERSISTENT => false, // 必要なら true に変更可 ]; try { $pdo = new PDO($dsn, $_ENV['DB_USER'] ?? 'db_user', $_ENV['DB_PASS'] ?? '', $options); } catch (PDOException $e) { error_log('[PDO] Connect failed: ' . $e->getMessage()); exit('データベース接続に失敗しました。管理者へお問い合わせください。'); } |
ポイント
- DSN の charset=utf8mb4 が MySQL 接続時の文字セットで、PHP の出力エンコーディングには影響しません。
- ATTR_EMULATE_PREPARES => false にすると MySQL のネイティブプリペアドステートメントが利用でき、パフォーマンスとセキュリティが向上します。
4️⃣ php.ini の重要設定(公式マニュアル参照)
| 設定項目 | 推奨値 / 説明 | 公式ページ |
|---|---|---|
default_charset |
UTF-8(出力エンコーディング)※ MySQL 用の文字セットは接続時に指定する | https://www.php.net/manual/ja/ini.core.php#ini.default-charset |
mysqli.default_socket |
Unix ソケットのフルパス(例: /var/run/mysqld/mysqld.sock) |
https://www.php.net/manual/ja/mysqli.configuration.php#ini.mysqli.default-socket |
pdo_mysql.default_socket |
同上 | https://www.php.net/manual/ja/pdo-mysql.configuration.php#ini.pdo-mysql.default-socket |
mysqli.reconnect |
Off(自動再接続は非推奨、手動で再接続ロジックを実装) | https://www.php.net/manual/ja/mysqli.configuration.php#ini.mysqli.reconnect |
log_errors / error_log |
本番環境は On、ログファイルは /var/log/php_errors.log など安全な場所へ |
https://www.php.net/manual/ja/errorfunc.configuration.php |
4‑1️⃣ default_charset の誤解を防ぐ
default_charset = "utf8mb4"と書くと PHP が内部的に utf8mb4 を文字列エンコーディングとして扱う という意味になり、実際にはサポート外です。- 正しくは
default_charset = "UTF-8"とし、データベース側の文字セットは接続コード(set_charset('utf8mb4')または DSN のcharset=utf8mb4)で指定します。
4‑2️⃣ mysqli.reconnect の実情
PHP 8 系でも 設定項目自体は残存していますが、公式ドキュメントは「非推奨かつ期待通りに動作しないケースが多い」旨を警告しています。したがって Off にして、接続失敗時は例外捕捉で再試行ロジックを書く ことが安全です。
5️⃣ よくある MySQL 接続エラーと対処法
| エラーコード | 意味・シンボル | 主な原因 | 推奨チェック項目 |
|---|---|---|---|
| 2002 | CR_CONNECTION_ERROR(接続タイムアウト) |
サーバーダウン、ポートミス、ソケットパス不一致 | netstat -tlnp・php.ini の default_socket を確認 |
| 1045 | ER_ACCESS_DENIED_ERROR(認証失敗) |
ユーザー名/パスワード誤り、ホスト制限 | SELECT User, Host FROM mysql.user; で権限確認 |
| 2006 | CR_SERVER_GONE_ERROR(サーバ切断) |
アイドルタイムアウト、ネットワーク障害 | mysqli_options($link, MYSQLI_OPT_CONNECT_TIMEOUT, 5); 等でタイムアウト短縮 |
| 2013 | CR_SERVER_LOST(通信エラー) |
大量データ転送中の切断、ファイアウォール | MySQL の max_allowed_packet 拡張、クエリ分割 |
| 1049 | ER_BAD_DB_ERROR(DB 不在) |
DB 名ミス・削除済み | SHOW DATABASES; で実在確認 |
実務ヒント:エラーが発生したタイミング(接続直後、クエリ実行時)をログに残すと原因特定が格段に速くなります。
6️⃣ 環境別チェックリスト
6‑1️⃣ 開発環境
display_errors = On→ デバッグ情報を画面に出力log_errors = On、ログローテーション設定(例:logrotate)
6‑2️⃣ 本番環境
display_errors = Off(情報漏洩防止)log_errors = On、エラーログは 権限 600 にし、外部から直接閲覧不可にする.envファイルは.gitignoreに必ず追加
6‑3️⃣ Docker / コンテナ環境での注意点
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# docker-compose.yml の例 services: php: image: php:8.2-fpm environment: - DB_HOST=mysql - DB_PORT=3306 - DB_NAME=sample_db - DB_USER=db_user - DB_PASS=s3cr3t! volumes: - ./src:/var/www/html |
- コンテナ間通信は TCP(
host: mysql)になるため、hostにコンテナ名を指定。 - ソケット接続が必要な場合は
volumes:で MySQL のソケットファイルを共有します。
7️⃣ エラーログのベストプラクティス(機密情報除去付き)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php function log_mysql_error(\Throwable $e, string $context = ''): void { // パスワード等は正規表現でマスク $msg = preg_replace('/password=([^;]+)/i', 'password=*****', $e->getMessage()); $log = sprintf( "[%s] %s %s (Code:%d)", date('Y-m-d H:i:s'), $context, $msg, $e->getCode() ); error_log($log); } // 使用例(mysqli) try { // ... 接続処理 } catch (\Throwable $e) { log_mysql_error($e, 'MySQLi Connect'); exit('データベース接続に失敗しました。管理者へお問い合わせください。'); } |
- 例外捕捉は必ず行う(
mysqli_report()で例外化すれば統一感が出ます)。 - ログには スタックトレースや機密情報を含めないようにフィルタリングする関数を作成し、全体で使い回すと保守性が向上します。
8️⃣ WordPress 等 CMS の接続エラー切り分けフロー
| 手順 | 内容 |
|---|---|
| 1️⃣ デバッグモード有効化 | wp-config.php に define('WP_DEBUG', true); define('SAVEQUERIES', true); を追加 |
| 2️⃣ プラグイン無効化 | wp-content/plugins のフォルダ名を一時的に変更し、全プラグインを停止 |
| 3️⃣ テーマ切替 | デフォルトテーマ(例:Twenty Twenty‑Four)へ切り替え |
| 4️⃣ DB 設定再確認 | .env または wp-config.php の DB_HOST, DB_USER, DB_PASSWORD, DB_NAME が正しいか |
| 5️⃣ エラーログ確認 | /var/log/php_errors.log やサーバーの Apache/Nginx ログで「MySQLi Connect Error」や「PDOException」を検索 |
| 6️⃣ 再現テスト | 同じ環境(ローカル・ステージング)で同一設定を再度実行し、エラーが再現するか確認 |
ポイント:プラグインが独自に
mysqli_connect()を呼び出すケースは多く、設定ミスや古いライブラリが原因になることがあります。上記手順で解消しない場合は該当プラグインの開発者へ問い合わせるか、代替プラグインを検討してください。
9️⃣ .env と最小権限ユーザーによる安全な認証情報管理
9‑1️⃣ .env の雛形(Git 管理外)
|
1 2 3 4 5 6 7 |
# .env (プロジェクトルート) DB_HOST=127.0.0.1 DB_PORT=3306 DB_NAME=sample_db DB_USER=app_user DB_PASS=SuperSecret123! |
9‑2️⃣ PHP 側での読み込み(vlucas/phpdotenv 推奨)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php require_once __DIR__.'/vendor/autoload.php'; $dot = Dotenv\Dotenv::createImmutable(__DIR__); $dot->load(); // 環境変数が $_ENV に展開される // 例: PDO 接続に利用 $dsn = sprintf( 'mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', $_ENV['DB_HOST'], (int)$_ENV['DB_PORT'], $_ENV['DB_NAME'] ); |
9‑3️⃣ MySQL 側の最小権限ユーザー作成例
|
1 2 3 4 |
CREATE USER 'app_user'@'%' IDENTIFIED BY 'SuperSecret123!'; GRANT SELECT, INSERT, UPDATE, DELETE ON sample_db.* TO 'app_user'@'%'; FLUSH PRIVILEGES; |
- 必要最低限の権限だけを付与することで、万が一認証情報が漏洩しても被害範囲を限定できます。
- 定期的にパスワードをローテーションし、変更後は
.envを更新・デプロイパイプラインで自動反映させると運用負荷が減ります。
📚 まとめ
| 項目 | 要点 |
|---|---|
廃止された mysql_* 関数 |
PHP 7.0 で完全削除。公式マニュアルを必ず参照。 |
| mysqli vs PDO | MySQL 専用は mysqli、複数 DB 対応や統一コードベースは PDO が最適。 |
| 接続コード | 例外化 (mysqli_report() / ATTR_ERRMODE) と utf8mb4 設定を必ず行う。 |
| php.ini の留意点 | default_charset = "UTF-8"、mysqli.reconnect = Off、ソケットパスは正確に設定。 |
| エラーハンドリング | 例外捕捉+機密情報マスクしたログ出力を徹底。 |
| .env と最小権限 | 認証情報はコードから分離し、DB ユーザーは必要最低限の権限だけ付与。 |
| 公式ドキュメント | すべての設定・関数は https://www.php.net/ 系列で確認すること。 |
以上を実装・運用に取り入れることで、MySQL 接続エラーの迅速な診断と安全なデータベース連携が実現できます。ぜひプロジェクトに合わせてカスタマイズし、安定した PHP アプリケーション開発に活かしてください。