PHP 애플리케이션에서 환경변수가 제대로 로드되지 않거나 적용되지 않는 문제는 매우 흔합니다. 다양한 원인과 해결책을 알아보겠습니다.
가장 기본적인 .env 파일 로더를 직접 구현합니다.
<?php
class EnvLoader {
public static function load($path = null) {
$envFile = $path ?: __DIR__ . '/../.env';
if (!file_exists($envFile)) {
throw new Exception(".env file not found at: $envFile");
}
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (strpos($line, '#') === 0 || strpos($line, '=') === false) {
continue;
}
list($key, $value) = explode('=', $line, 2);
$key = trim($key);
$value = trim($value, '"\'');
// 이미 설정된 환경변수는 덮어쓰지 않음
if (!isset($_ENV[$key])) {
$_ENV[$key] = $value;
putenv("$key=$value");
}
}
}
}
// 사용법
EnvLoader::load();
개발, 스테이징, 프로덕션 환경별로 다른 .env 파일을 로드합니다.
<?php
class Environment {
public static function load() {
$env = $_SERVER['APP_ENV'] ?? 'development';
$basePath = __DIR__ . '/../';
$envFiles = [
$basePath . '.env',
$basePath . ".env.$env",
$basePath . '.env.local'
];
foreach ($envFiles as $file) {
if (file_exists($file)) {
self::loadEnvFile($file);
}
}
}
private static function loadEnvFile($file) {
$lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (self::isComment($line) || !self::hasEquals($line)) {
continue;
}
self::setEnvironmentVariable($line);
}
}
private static function setEnvironmentVariable($line) {
list($key, $value) = explode('=', $line, 2);
$key = trim($key);
$value = self::parseValue(trim($value));
$_ENV[$key] = $value;
$_SERVER[$key] = $value;
putenv("$key=$value");
}
private static function parseValue($value) {
// 따옴표 제거
if (preg_match('/^"(.*)"$/', $value, $matches)) {
return $matches[1];
}
// 불린 값 처리
if (in_array(strtolower($value), ['true', 'false'])) {
return strtolower($value) === 'true';
}
return $value;
}
}
PHP-FPM에서 환경변수가 전달되지 않는 문제를 해결합니다.
; 환경변수 전달 설정
clear_env = no
; 또는 특정 환경변수만 전달
clear_env = yes
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
; 애플리케이션 환경변수
env[APP_ENV] = production
env[DB_HOST] = localhost
env[DB_NAME] = myapp
편리한 환경변수 접근을 위한 헬퍼 함수를 만듭니다.
<?php
class EnvHelper {
public static function get($key, $default = null) {
$value = $_ENV[$key] ?? $_SERVER[$key] ?? getenv($key);
if ($value === false) {
return $default;
}
return self::castValue($value);
}
public static function required($key) {
$value = self::get($key);
if ($value === null) {
throw new Exception("Required environment variable '$key' is not set");
}
return $value;
}
public static function bool($key, $default = false) {
$value = self::get($key, $default);
if (is_bool($value)) {
return $value;
}
return in_array(strtolower($value), ['true', '1', 'yes', 'on']);
}
public static function int($key, $default = 0) {
return (int) self::get($key, $default);
}
private static function castValue($value) {
// 불린 값 변환
if (in_array(strtolower($value), ['true', 'false'])) {
return strtolower($value) === 'true';
}
// 숫자 값 변환
if (is_numeric($value)) {
return strpos($value, '.') !== false ? (float) $value : (int) $value;
}
return $value;
}
}
필수 환경변수가 설정되었는지 검증합니다.
<?php
class EnvValidator {
private static $requiredVars = [
'DB_HOST',
'DB_NAME',
'DB_USER',
'DB_PASSWORD',
'APP_KEY'
];
public static function validate() {
$missing = [];
foreach (self::$requiredVars as $var) {
if (empty(EnvHelper::get($var))) {
$missing[] = $var;
}
}
if (!empty($missing)) {
throw new Exception('Missing required environment variables: ' . implode(', ', $missing));
}
return true;
}
public static function validateTypes() {
$validations = [
'DB_PORT' => 'integer',
'APP_DEBUG' => 'boolean',
'CACHE_TTL' => 'integer'
];
foreach ($validations as $var => $type) {
$value = EnvHelper::get($var);
if ($value !== null && !self::validateType($value, $type)) {
throw new Exception("Environment variable '$var' must be of type $type");
}
}
}
private static function validateType($value, $type) {
switch ($type) {
case 'integer':
return is_numeric($value);
case 'boolean':
return in_array(strtolower($value), ['true', 'false', '1', '0']);
default:
return true;
}
}
}
Docker 컨테이너에서 환경변수를 올바르게 처리합니다.
<?php
class DockerEnvLoader {
public static function load() {
// Docker secrets 처리
self::loadDockerSecrets();
// 환경변수 파일 처리
self::loadEnvFiles();
}
private static function loadDockerSecrets() {
$secretsDir = '/run/secrets';
if (!is_dir($secretsDir)) {
return;
}
$secrets = scandir($secretsDir);
foreach ($secrets as $secret) {
if ($secret === '.' || $secret === '..') {
continue;
}
$secretPath = $secretsDir . '/' . $secret;
$secretValue = trim(file_get_contents($secretPath));
$envKey = strtoupper($secret);
$_ENV[$envKey] = $secretValue;
putenv("$envKey=$secretValue");
}
}
private static function loadEnvFiles() {
$envFile = '/app/.env';
if (file_exists($envFile)) {
EnvLoader::load($envFile);
}
}
}
성능 향상을 위한 환경변수 캐싱 시스템입니다.
<?php
class EnvCache {
private static $cache = [];
private static $loaded = false;
public static function get($key, $default = null) {
if (!self::$loaded) {
self::loadAll();
}
return self::$cache[$key] ?? $default;
}
private static function loadAll() {
// 시스템 환경변수 로드
foreach ($_ENV as $key => $value) {
self::$cache[$key] = $value;
}
// .env 파일 로드
if (file_exists('.env')) {
$lines = file('.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (strpos($line, '=') !== false && strpos($line, '#') !== 0) {
list($key, $value) = explode('=', $line, 2);
self::$cache[trim($key)] = trim($value, '"\'');
}
}
}
self::$loaded = true;
}
}
환경변수 문제를 진단하는 도구입니다.
<?php
function debugEnvironment() {
echo "=== Environment Variables Debug ===\n\n";
echo "1. PHP SAPI: " . php_sapi_name() . "\n";
echo "2. Current working directory: " . getcwd() . "\n";
echo "3. Script location: " . __DIR__ . "\n\n";
echo "4. .env file status:\n";
$envFiles = ['.env', '.env.local', '.env.production'];
foreach ($envFiles as $file) {
$path = __DIR__ . '/../' . $file;
echo " $file: " . (file_exists($path) ? 'EXISTS' : 'NOT FOUND') . "\n";
}
echo "\n5. Environment variables:\n";
$envVars = ['APP_ENV', 'DB_HOST', 'DB_NAME', 'DB_USER'];
foreach ($envVars as $var) {
$value = $_ENV[$var] ?? $_SERVER[$var] ?? getenv($var) ?: 'NOT SET';
echo " $var: $value\n";
}
echo "\n6. All $_ENV variables:\n";
foreach ($_ENV as $key => $value) {
echo " $key: $value\n";
}
}
debugEnvironment();
애플리케이션 부트스트랩에서 자동으로 환경변수를 로드합니다.
<?php
// 환경변수 자동 로딩
spl_autoload_register(function($class) {
if ($class === 'EnvLoader') {
require_once __DIR__ . '/../src/EnvLoader.php';
}
});
// 애플리케이션 시작 시 환경변수 로드
try {
EnvLoader::load();
EnvValidator::validate();
} catch (Exception $e) {
error_log("Environment loading failed: " . $e->getMessage());
if (EnvHelper::get('APP_ENV') !== 'production') {
die("Environment configuration error: " . $e->getMessage());
}
}
이러한 해결책들을 조합하여 사용하면 환경변수 미적용 문제를 효과적으로 해결할 수 있습니다. 특히 환경변수 검증과 디버깅 도구를 함께 사용하면 문제를 빠르게 진단하고 해결할 수 있습니다.