背景

  • 其实这个过程分为了好几个阶段

需求阶段1

  • 受制于Laravel的一丢丢限制,需要在不同的域名下,使用不同的配置,故产生需求。

需求阶段2

  • 在反向的情况下需要使用不同的配置,应该是属于需求阶段1的需求扩展。

需求阶段3

  • 在开发场景下,在不同的电脑上每次开发,需要同步各处的env,但是env配置是不加入git库的,导致一时间无法获取正确的env配置,消耗过多时间去操作。
  • 尤其是其中一台电脑很久没有开机过了,导致配置变更过大,特别是新增的env配置,很容易忽略,由此产生了env同步的需求。

过程

  • 万般无奈,在网上发了求助帖,各种复杂方案都有,由于开发项目env配置的低敏感度,加上均为私人库,最后获得了一个指定env配置的方案。

方案特点

  • 本地快速切换:改一下别名即可(生产环境也支持,一般不会去切换而已)
  • 兼容框架原有的.env模式:只要代码不动,就是原有模式
  • 生产环境无需改造:不影响生产环境的运行,使用只要改代码即可
  • 支持多种模式:目前支持指定模式、域名模式、反代模式三种模式

特别说明

  • 本方案只是一个偷懒的方案,并不是什么完美的解决方案,所以不喜勿喷,如果想要更好效果可以参考ApolloNacos等其他方案!!!

代码与说明

  • bootstrap/文件夹下新建文件env.php,代码如下
<?php

// 环境处理
/* @var Illuminate\Foundation\Application $app */
if (is_file(__DIR__ . '/../.env.local_set')) {
    // 本地指定形式
    $suffix = '.local.' . file_get_contents(__DIR__ . '/../.env.local_set');
} else {
    // 非Console环境下
    $suffix = '';
    if (!$app->runningInConsole()) {
        if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
            // 反代形式
            $suffix = '.' . 'forwarded';
        } else {
            // 域名形式
            if (empty($_SERVER['SERVER_NAME'])) {
                die('[error] no host');
            }
            $suffix = '.' . $_SERVER['SERVER_NAME'];
        }
    }
}
// 判断文件存在并写入环境配置
if (is_file(__DIR__ . '/../.env' . $suffix)) {
    $app->loadEnvironmentFrom('.env' . $suffix);
}
  • 修改文件bootstrap/app.php
// 原先的代码
$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
// 新增的代码,仅需一行即可
require_once __DIR__ . '/env.php'; // 引入多env配置文件
  • 在根目录新建.env.local_set文件,下面会说明。
  • 在根目录新建.env.local_set.example文件,作用类似于.env.example
  • 最后修改根目录中的.gitignore文件,在.env的最下面添加如下的几行代码
  • 这块的代码可以根据自己的需求自定义
.env.* 
!.env.example
!.env.local_set.example
!.env.local.*
  • 如上示例代码所示,生产环境下,可以添加.env.env.域名.env.forwarded(反向代理专用),该类env文件均不会被添加到git库中。
  • 新建的.env.local.*(*代表任意字符,用于识别环境,可以是电脑别名、代号、生产环境、测试环境等等任意字符),该类文件均会被添加到git库。
  • 新建的.env.local_set是用于.env.local.*的指定环境,里面的内容写上.env.local.*中的*即可。
  • 代码优先级,指定环境>反向代理环境>多域名环境>普通环境(即加载默认的**.env**)
  • 其中指定环境下,命令行模式会使用指定环境下的env文件,其他情况下会使用正常的.env文件,此处考虑到服务器上跑的任务调度,队列等服务只在一台服务器上处理。
  • 有新的指定env引入,只需要新建对应的.env.local.*并提交即可。
  • Enjoy it.

ThinkPHP教程

  • 由于ThinkPHP文档里已经写了,有专用函数用于设置ENV,故改造起来很简单。这边只写出了改造文件的教程,其他参考Laravel的教程即可。
  • 根目录新建env.php文件
<?php

/* @var think\App $app */
// 环境处理
if (is_file(__DIR__ . '/.env.local_set')) {
    // 本地指定形式
    $envName = 'local.' . file_get_contents(__DIR__ . '/.env.local_set');
} else {
    // 非Console环境下
    $envName = '';
    if (!$app->runningInConsole()) {
        if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
            // 反代形式
            $envName = 'forwarded';
        } else {
            // 域名形式
            if (empty($_SERVER['SERVER_NAME'])) {
                die('[error] no host');
            }
            $envName = $_SERVER['SERVER_NAME'];
        }
    }
}

if (is_file(__DIR__ . '/.env.' . $envName)) {
    $app->setEnvName($envName);
}
  • 修改public/index.php文件
...
// 执行HTTP应用并响应
$app = new App();
require __DIR__ . '/../env.php'; // 引入多env配置文件
$http = $app->http;
// $http = (new App())->http;
...
  • 修改根目录think文件
...
// 应用初始化
$app = new App();
require __DIR__ . '/env.php'; // 引入多env配置文件
$app->console->run();
// (new App())->console->run();

示例

线上环境多域名及反代示例

  • 现有生产环境域名www.abc.com和生产环境域名www.def.com,以及反代环境www.xyz.com
  • 在服务器上新建.env.www.abc.com.env.www.def.com文件,此时使用相应的文件访问时,使用的即为对应的配置文件。如果域名对应的文件不存在,则默认加载.env文件。

指定环境示例

  • 现有本地开发环境dev和本地开发环境test
  • 新建.env.local.dev.env.local.test,并提交到git库。
  • .env.local_set文件中将里面的内容改为dev,此时项目的env文件使用的是.env.local.dev文件,如果需要切换到test,在.env.local_set文件中将里面的内容改为test即可。
  • 如果无.env.local_set文件,或者.env.local_set文件里无内容,或者.env.local_set的内容无对应匹配文件,则默认加载.env文件。
Last modification:September 22nd, 2023 at 04:32 pm
如果觉得我的文章对你有用,请随意赞赏