如何在 PHP 中正确解析 .env 格式(X=Y)配置文件为关联数组

本文介绍一种健壮、兼容性强的 php 方法,用于读取无节标题的 `.env` 文件(如 `key=value` 形式),准确提取键值对并忽略注释与空行,特别处理含多个等号(如 base64 密钥)的特殊情况。

.env 文件虽常被误认为是标准 INI 文件,但其实际格式并不符合 parse_ini_file() 的语法要求——该函数强制依赖节(section)定义(如 [section]),且对值中出现的多个 = 号(如 APP_KEY=base64:xxx=yyy=zzz)会解析失败,导致返回 false。直接 include() 更不可取,因其将文件当作 PHP 代码执行,存在严重安全风险(如任意代码注入)且无法返回结构化数据。

因此,推荐采用手动逐行解析策略,兼顾安全性、鲁棒性与可维护性。核心逻辑如下:

  1. 使用 file() 读取文件为行数组,并自动跳过空行与保留换行符;
  2. 对每行去除首尾空白,跳过以 # 或 ; 开头的注释行;
  3. 精确识别第一个 = 位置,将左侧作为键(key),右侧全部作为值(value),从而兼容密钥、URL、JSON 片段等含多等号的合法值;
  4. 自动过滤空键,避免无效条目。

以下是生产就绪的完整实现:

function loadEnvFile(string $filepath): array
{
    if (!is_file($filepath) || !is_readable($filepath)) {
        throw new InvalidArgumentException("Cannot read .env file: {$filepath}");
    }

    $data = [];
    $lines = file($filepath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

    foreach ($lines as $line) {
        $line = trim($line);

        // 跳过空行和注释行(支持 # 和 ; 开头)
        if (empty($line) || str_starts_with($line, '#') || str_starts_with($line, ';')) {
            continue;
        }

        // 查找第一个等号位置,确保值中可含多个 =
        $pos = strpos($line, '=');
        if ($pos === false) {
            continue; // 跳过无等号的异常行
        }

        $key   = trim(substr($line, 0, $pos));
        $value = trim(substr($line, $pos + 1));

        // 可选:移除值两端的引号(兼容带单/双引号的 .env 写法)
        if (strlen($value) >= 2 && ($value[0] === '"' && $value[-1] === '"') || 
                                   ($value[0] === "'" && $value[-1] === "'")) {
            $value = substr($value, 1, -1);
        }

        if ($key !== '') {
            $data[$key] = $value;
        }
    }

    return $data;
}

// 使用示例
try {
    $env = loadEnvFile(__DIR__ . '/../../.env');
    print_r($env);
} catch (InvalidArgumentException $e) {
    error_log('Failed to load .env: ' . $e->getMessage());
}

优势说明

  • 安全:不执行任何外部代码,杜绝 include() 类风险;
  • 兼容:正确处理 APP_KEY=base64:...=、APP_URL=https://example.com/path?x=y&z=w 等复杂值;
  • 健壮:跳过注释、空行、无等号行,避免崩溃;
  • 可扩展:已内置引号剥离逻辑,适配 Laravel / Symfony 等主流框架的 .env 写法。

⚠️ 注意事项

  • 切勿将 .env 文件置于 Web 可访问目录(如 public/),防止敏感信息泄露;
  • 生产环境建议使用环境变量替代文件读取(如通过 putenv() + getenv()),更高效且安全;
  • 如需深度集成(如变量插值、多环境继承),建议使用成熟库如 vlucas/phpdotenv,本方案适用于轻量、无依赖场景。

通过以上方法,你即可稳定、清晰地将 .env 配置加载为 PHP 关联数组,为后续应用初始化、数据库连接或 API 配置提供可靠数据源。