環境情報
- テスト環境: PHP 8.1, MySQL 8.0, Apache 2.4, macOS
- 本番環境: PHP 7.4, MySQL 5.7, Nginx 1.18, CentOS 7
- フレームワーク: Laravel 9
- デプロイツール: Deployer
はじめに
Web制作に携わるエンジニアであれば、一度は経験したことがある「テスト環境では問題ないのに、本番環境で動かない」という現象。私も先日、あるECサイトの改修中にこの問題に直面しました。テスト環境で徹底的にテストした機能が、本番環境にデプロイした瞬間に全く動作しなくなる。この記事では、その原因と具体的な解決策を、実装の手順を交えて詳しく解説します。
問題の発生
あるECサイトの商品検索機能を改良し、テスト環境で以下の確認を行いました:
- 検索結果が正しく表示される
- フィルタリングが正常に動作する
- ページネーションが機能する
- エラーハンドリングが適切
しかし、本番環境にデプロイした直後、検索機能が完全に停止。ブラウザの開発者ツールで確認すると、500エラーが返ってきていました。
原因の特定
1. PHPバージョンの違い
本番サーバーのPHPバージョンが7.4だったのに対し、テスト環境は8.1でした。PHP 8.0で非推奨となった関数を使用していたことが判明。
// 問題のコード(PHP 8.1では動作するが、7.4では非推奨)
$result = array_map(function($item) {
return str_replace(' ', '_', $item);
}, $data);
// PHP 7.4で動作する修正版
$result = array_map(function($item) {
return str_replace(' ', '_', $item);
}, $data);
実はこのコード自体は問題ありませんでしたが、別の箇所でeach()関数を使用していたことが原因でした。
// PHP 7.4で非推奨、8.0で削除されたeach()
while (list($key, $value) = each($array)) {
// 処理
}
// foreachに書き換え
foreach ($array as $key => $value) {
// 処理
}
2. ファイルパスの大文字小文字の違い
テスト環境(macOS)では大文字小文字を区別しないファイルシステムでしたが、本番環境(Linux)では区別されます。
// テスト環境では動くが、本番環境でエラー
include 'Config/Database.php'; // 実際のファイルは config/database.php
// 正しいパス
include 'config/database.php';
3. データベースの文字コード設定の差異
テスト環境ではUTF-8mb4がデフォルトでしたが、本番環境ではUTF-8のまま変更されていませんでした。
-- テスト環境のテーブル定義
CREATE TABLE products (
name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
);
-- 本番環境のテーブル定義(古いまま)
CREATE TABLE products (
name VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci
);
具体的な対策と実装手順
1. 環境変数による設定の一元管理
.envファイルを活用し、環境ごとの設定を一元管理します。
// .env.example(全環境で共通)
APP_ENV=local
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
// config/database.php
return [
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
],
],
];
2. 本番同等のステージング環境の構築
Dockerを使用して、本番環境と同一の環境を構築します。
# docker-compose.yml
version: '3.8'
services:
app:
image: php:7.4-fpm
volumes:
- ./:/var/www/html
environment:
- APP_ENV=staging
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: staging_db
3. デプロイ前の自動チェックスクリプト
#!/bin/bash
# deploy-check.sh
echo "=== 環境差異チェック ==="
# PHPバージョンチェック
PHP_VERSION=$(php -v | head -n 1 | cut -d " " -f 2 | cut -d "." -f 1-2)
echo "PHP Version: $PHP_VERSION"
# 非推奨関数の使用チェック
echo "非推奨関数チェック..."
grep -r "each(" --include="*.php" . && echo "警告: each()関数が使用されています"
grep -r "create_function(" --include="*.php" . && echo "警告: create_function()が使用されています"
# ファイルパスの大文字小文字チェック
echo "ファイルパスチェック..."
find . -name "*.php" -path "*[A-Z]*" | while read file; do
lowercase=$(echo "$file" | tr '[:upper:]' '[:lower:]')
if [ "$file" != "$lowercase" ]; then
echo "警告: 大文字を含むパス: $file"
fi
done
# データベース文字コードチェック
echo "データベース文字コードチェック..."
php -r "
\$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
\$stmt = \$pdo->query('SHOW VARIABLES LIKE \"character_set_server\"');
\$row = \$stmt->fetch();
echo 'Server charset: ' . \$row['Value'] . PHP_EOL;
"
4. 環境差異の比較表
| 項目 | テスト環境 | 本番環境 | 注意点 |
|---|---|---|---|
| PHPバージョン | 8.1 | 7.4 | 非推奨関数のチェック必須 |
| データベース | MySQL 8.0 | MySQL 5.7 | 文字コード、ストレージエンジン |
| Webサーバー | Apache | Nginx | .htaccessの非互換 |
| ファイルシステム | 大文字小文字区別なし | 区別あり | パスは常に小文字で統一 |
| OS | macOS | CentOS | パーミッション設定の違い |
5. デプロイフローの改善
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.4' # 本番環境と同じバージョン
- name: Run tests
run: |
composer install
php artisan test
- name: Deploy to staging
run: |
# ステージング環境にデプロイ
php artisan deploy staging
- name: Run integration tests on staging
run: |
# ステージング環境で結合テスト
curl -f http://staging.example.com/health-check
- name: Deploy to production
run: |
php artisan deploy production
ハマりポイントと解決策
1. PHPのバージョン互換性
PHP 7.4から8.0への移行で特に注意が必要な点:
-
each()関数の削除 -
create_function()の削除 - 型宣言の厳格化
2. データベースのマイグレーション
// データベースマイグレーション時の注意点
Schema::table('products', function (Blueprint $table) {
// 本番環境では既存データがある場合の考慮
$table->string('name', 255)->charset('utf8mb4')->change();
// インデックス追加時のロック対策
$table->index('category_id')->algorithm('INPLACE');
});
3. ファイルパスの統一ルール
// プロジェクト全体で統一するルール
class PathHelper {
public static function normalize($path) {
return strtolower(str_replace('\\', '/', $path));
}
public static function include($path) {
require_once self::normalize($path);
}
}
まとめ
テスト環境と本番環境の差異によるトラブルを防ぐためには、以下の3つの対策が効果的です:
- 環境変数による設定の一元管理 - 環境ごとの設定をコードから分離
- 本番同等のステージング環境の構築 - DockerやVagrantを活用
- デプロイ前の自動チェック - CI/CDパイプラインに組み込む
特に重要なのは、テスト環境と本番環境の差異を事前に把握し、デプロイ前に自動チェックを行うことです。これにより、人的ミスを減らし、安定したデプロイを実現できます。
あなたのプロジェクトでも、環境差異によるトラブルが発生した場合は、まずPHPバージョン、ファイルパス、データベース設定の3点を確認してみてください。そして、上記の対策を導入することで、同じミスを繰り返さないようにしましょう。
この記事を書いた人
BENTEN Web Works — 業務自動化・システム開発のフリーランスエンジニアです。
GAS / Python / RPA を使った業務自動化や、Web制作・システム開発のご相談を承っています。
「こんなこと自動化できる?」というご質問だけでもお気軽にどうぞ。
👉 BENTEN Web Works — 詳細・お問い合わせはこちら
🐦 X(旧Twitter) — 日々の知見を発信中