dotenv 在生产中需要 .env 文件

Posted

技术标签:

【中文标题】dotenv 在生产中需要 .env 文件【英文标题】:dotenv requires .env file on production 【发布时间】:2015-08-19 03:39:20 【问题描述】:

我在 php 中使用 dotenv 来管理环境设置(不是 lavarel,但我标记了它,因为 lavarel 也使用 dotenv)

我已将 .env 从代码库中排除,并为所有其他合作者添加了 .env.example

dotenv的github页面上:

phpdotenv 是为开发环境而设计的,一般不应该在生产环境中使用。在生产环境中,应该设置实际的环境变量,这样就不会在每个请求上加载 .env 文件的开销。这可以通过使用 Vagrant、chef 或 Puppet 等工具的自动化部署过程来实现,也可以使用 Pagodabox 和 Heroku 等云主机手动设置。

我不明白的是,我得到了以下异常:

PHP Fatal error: Uncaught exception 'InvalidArgumentException' with message 'Dotenv: Environment file .env not found or not readable.

这与文档中所说的“应设置实际的环境变量,以便在每个请求上没有加载 .env 文件的开销”相矛盾。

所以问题是 dotenv 是否有任何原因引发该异常和/或我错过了什么?首先,与其他 dotenv 库(ruby)相比,行为是不同的

我可以轻松解决这个不太好的解决方案:

if(getenv('APPLICATION_ENV') !== 'production')  /* or staging */
    $dotenv = new Dotenv\Dotenv(__DIR__);
    $dotenv->load();

我认为最好的解决方案,但我认为 dotenv 应该处理这个问题。

$dotenv = new Dotenv\Dotenv(__DIR__);
//Check if file exists the same way as dotenv does it
//See classes DotEnv\DotEnv and DotEnv\Loader
//$filePath = $dotenv->getFilePath(__DIR__); 
//This method is protected so extract code from method (see below)

$filePath = rtrim(__DIR__, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR . '.env';
//both calls are cached so (almost) no performance loss
if(is_file($filePath) && is_readable($filePath)) 
    $dotenv->load();

【问题讨论】:

如果你不在生产服务器上使用 .env ,那么你如何设置你的环境变量呢? 【参考方案1】:

Dotenv 是围绕一个想法构建的,即它将仅用于开发环境。因此,它总是期望存在.env 文件。

您不喜欢的解决方案是使用 Dotenv 的推荐方式。看来,它won't change in near future。项目问题跟踪器中的相关讨论:https://github.com/vlucas/phpdotenv/issues/63#issuecomment-74561880

请注意,Mark offers 有一种适用于生产/暂存环境的好方法,它跳过文件加载,但不验证

$dotenv = new Dotenv\Dotenv();
if(getenv('APP_ENV') === 'development') 
    $dotenv->load(__DIR__);

$dotenv->required('OTHER_VAR');

【讨论】:

啊,我可以使用$dotenv->required(),它可以以任何方式工作,这很好。我猜getenv('APP_ENV'); 更安全?我想我会选择适合当前项目的文件检查。谢谢! @SanderVisser 你说getenv('APP_ENV') 更安全是什么意思? 它会阻止在生产环境中加载 .env 文件,即使它存在。 当我想到。开发环境是使用 vagrant 和 puppet 构建的,因此可以使用一些合理的开发默认值来跳过 dotenv 的一次性步骤。这就是我选择文件检查方法的原因。但将这两种方法结合起来并不是什么大问题【参考方案2】:

如果您在创建 APP_ENV 变量时遇到问题,此代码会更简单:

$dotenv = new Dotenv\Dotenv(__DIR__);
if(file_exists(".env")) 
    $dotenv->load();

【讨论】:

【参考方案3】:

也对此进行了调查,我目前的解决方案是使用 Lumen's way(截至 2016 年 6 月 6 日),即 suggested in a discussion:

try 
    (new Dotenv\Dotenv(__DIR__.'/../'))->load();
 catch (Dotenv\Exception\InvalidPathException $e) 
    //

如果需要,您仍然可以进行一些额外的异常处理(例如,使用默认值或进行一些验证。

【讨论】:

这违背了“没有在每个请求上加载 .env 文件的开销”的目的 @MassimilianoArione 使用DotEnv at all 会产生在每个请求上加载.env 文件的开销,因此您的评论实际上适用于使用@987654326 的整个前提@,而不仅仅是这个答案。

以上是关于dotenv 在生产中需要 .env 文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在开发和生产中设置 dotenv?

process.env.NODE_ENV === "开发" 即使在生产中

您应该使用 Babel 配置中的 `env` 部分在生产中禁用 react-transform-hmr

在生产中禁用 graphiql

如何将私钥内容放入 dotenv .env 文件中以用于 lumen 应用程序?

在生产中处理我的反应应用程序中的图像