如何在 laravel 中以编程方式即时设置 .env 值
Posted
技术标签:
【中文标题】如何在 laravel 中以编程方式即时设置 .env 值【英文标题】:How to set .env values in laravel programmatically on the fly 【发布时间】:2017-03-19 21:50:34 【问题描述】:我有一个自定义 CMS,我在 Laravel 中从头开始编写,并希望在用户设置后从控制器设置 env
值,即数据库详细信息、邮件详细信息、常规配置等,并希望用户可以灵活地使用我正在制作的 GUI 随时更改它们。
所以我的问题是,当我需要控制器时,如何将用户收到的值写入.env
文件。
在旅途中构建.env
文件是个好主意还是有其他解决方法?
提前致谢。
【问题讨论】:
根据我的观点,不应修改 env 变量,因为 env 变量不是为修改而进行的,而是应该以稳健的值指导应用程序。你应该尝试另一个技巧/黑客来实现你的目标。 我同意@SaumyaRastogi...环境变量不应该被修改 @SaumyaRastogi 我需要这个来通过复制随机生成的应用程序令牌来更轻松地安装 repo,我需要将它存储在.env
中。所以有合法用途。
@totymedli 我不认为这是一个合法的用途,而是使用像 php artisan some_command
这样的 laravel 命令。 Laravel 还使用php artisan key:generate
为应用程序生成随机密钥。也许这对你有帮助!
@SaumyaRastogi 我用那个。我从那里设置了.env
文件。密钥生成到数据库。如果不将其复制到 .env
文件中,我将不得不在每个请求中获取它。
【参考方案1】:
由于 Laravel 使用配置文件来访问和存储 .env
数据,您可以使用 config()
方法即时设置这些数据:
config(['database.connections.mysql.host' => '127.0.0.1']);
要获取此数据,请使用config()
:
config('database.connections.mysql.host')
要在运行时设置配置值,请将数组传递给
config
助手
https://laravel.com/docs/5.3/configuration#accessing-configuration-values
【讨论】:
config(['something'=> 'data']); return env('something');
这是我在控制器中设置的方式,但它没有返回任何内容。
您不需要使用env()
。只需使用config()
设置数据,然后使用config('something')
获取数据。
我使用此方法在运行时设置了我的数据库凭据,并且还从 .env 文件中删除了它,但它采用默认值,即。 forge@localhost 所以这个方法行不通,我不只是想进行配置,我什至想设置环境变量,如数据库详细信息、邮件详细信息等
这意味着您在尝试设置数据时使用了错误的路径。请举例说明您在做什么,然后我会为您提供帮助。
config(['DB_HOST'=> '127.0.0.1']); config(['DB_PORT'=> '3306']); config(['DB_DATABASE'=> 'qbi_cms']); config(['DB_USERNAME'=> 'root']); config(['DB_PASSWORD'=> '']); Auth::routes();
这是我的路线文件【参考方案2】:
小心!并非 laravel .env 中的所有变量都存储在配置环境中。 要覆盖真实的 .env 内容,只需使用:
putenv ("CUSTOM_VARIABLE=hero");
如常读取,env('CUSTOM_VARIABLE') 或 env('CUSTOM_VARIABLE', 'devault')
注意:根据应用程序的哪个部分使用 env 设置,您可能需要提前设置变量,方法是将其放入 index.php 或 bootstrap.php 文件中。对于环境设置的某些包/使用而言,在您的应用服务提供商中设置它可能为时已晚。
【讨论】:
如果您/真的/必须在运行时更改 env 值,这似乎比破解文件内容更好。 这对于代理工作的单元测试非常有用,您将再次使用模板并希望设置由于 phpunit.xml 静态而无法解决的奇怪环境 请注意,这不会在 laravel 中编辑实际的 .env 文件,并且可以用实际 .env 文件中的值替换为下一个请求 这是最好的答案。我正在使用它来更改 APP_URL,因为我有域名别名,并且 APP_URL 需要设置为 $_SERVER['HTTP_HOST']【参考方案3】:根据乔希的回答。我需要一种方法来替换 .env
文件中的键值。
但与 josh 的回答不同,我根本不想依赖于知道当前值或配置文件中可访问的当前值。
因为我的目标是替换 Laravel Envoy 使用的值,它根本不使用配置文件,而是直接使用 .env
文件。
这是我的看法:
public function setEnvironmentValue($envKey, $envValue)
$envFile = app()->environmentFilePath();
$str = file_get_contents($envFile);
$oldValue = strtok($str, "$envKey=");
$str = str_replace("$envKey=$oldValue", "$envKey=$envValue\n", $str);
$fp = fopen($envFile, 'w');
fwrite($fp, $str);
fclose($fp);
用法:
$this->setEnvironmentValue('DEPLOY_SERVER', 'forge@122.11.244.10');
【讨论】:
strtok()
部分对我不起作用。我将其替换为:$oldValue = env($envKey);
@PiotrSuchanek 这不适用于使用双引号的变量,例如:KEY="Something with spaces or variables $KEY2"
。见better solution in my answer。【参考方案4】:
基于 totymedli 的回答。
如果需要一次更改多个环境变量值,您可以传递一个数组(键->值)。将添加以前不存在的任何键并返回一个布尔值,以便您测试是否成功。
public function setEnvironmentValue(array $values)
$envFile = app()->environmentFilePath();
$str = file_get_contents($envFile);
if (count($values) > 0)
foreach ($values as $envKey => $envValue)
$str .= "\n"; // In case the searched variable is in the last line without \n
$keyPosition = strpos($str, "$envKey=");
$endOfLinePosition = strpos($str, "\n", $keyPosition);
$oldLine = substr($str, $keyPosition, $endOfLinePosition - $keyPosition);
// If key does not exist, add it
if (!$keyPosition || !$endOfLinePosition || !$oldLine)
$str .= "$envKey=$envValue\n";
else
$str = str_replace($oldLine, "$envKey=$envValue", $str);
$str = substr($str, 0, -1);
if (!file_put_contents($envFile, $str)) return false;
return true;
【讨论】:
嗯.. 我正在尝试使用它,但 .env 文件永远不会更新为我作为值传递的内容。没有错误或任何东西,真的很奇怪。在这个线程中尝试了其他一些解决方案,但没有一个有效。知道是什么原因造成的吗?【参考方案5】:更简化:
public function putPermanentEnv($key, $value)
$path = app()->environmentFilePath();
$escaped = preg_quote('='.env($key), '/');
file_put_contents($path, preg_replace(
"/^$key$escaped/m",
"$key=$value",
file_get_contents($path)
));
或作为助手:
if ( ! function_exists('put_permanent_env'))
function put_permanent_env($key, $value)
$path = app()->environmentFilePath();
$escaped = preg_quote('='.env($key), '/');
file_put_contents($path, preg_replace(
"/^$key$escaped/m",
"$key=$value",
file_get_contents($path)
));
【讨论】:
【参考方案6】:#更简单的覆盖.env的方法你可以这样做
$_ENV['key'] = 'value';
【讨论】:
感谢@bty_cj 的回答,我相信很多人会觉得这很有用。【参考方案7】:tl;博士
基于vesperknight's answer,我创建了一个不使用strtok
或env()
的解决方案。
private function setEnvironmentValue($envKey, $envValue)
$envFile = app()->environmentFilePath();
$str = file_get_contents($envFile);
$str .= "\n"; // In case the searched variable is in the last line without \n
$keyPosition = strpos($str, "$envKey=");
$endOfLinePosition = strpos($str, PHP_EOL, $keyPosition);
$oldLine = substr($str, $keyPosition, $endOfLinePosition - $keyPosition);
$str = str_replace($oldLine, "$envKey=$envValue", $str);
$str = substr($str, 0, -1);
$fp = fopen($envFile, 'w');
fwrite($fp, $str);
fclose($fp);
说明
这不使用可能对某些人不起作用的strtok
,或不适用于双引号.env
变量的env()
,这些变量被评估并插入嵌入变量
KEY="Something with spaces or variables $KEY2"
【讨论】:
这将修改#CACHE_DRIVER=...(如果已注释)而不是未注释的(真实的)【参考方案8】:如果您希望将这些设置保存到环境文件中以便稍后再次加载它们(即使配置被缓存),您可以使用这样的函数。我将把安全警告放在那里,对这样的方法的调用应该被严格保护,并且用户输入应该被正确地清理。
private function setEnvironmentValue($environmentName, $configKey, $newValue)
file_put_contents(App::environmentFilePath(), str_replace(
$environmentName . '=' . Config::get($configKey),
$environmentName . '=' . $newValue,
file_get_contents(App::environmentFilePath())
));
Config::set($configKey, $newValue);
// Reload the cached config
if (file_exists(App::getCachedConfigPath()))
Artisan::call("config:cache");
它的使用示例是;
$this->setEnvironmentValue('APP_LOG_LEVEL', 'app.log_level', 'debug');
$environmentName
是环境文件中的key(例如..APP_LOG_LEVEL)
$configKey
是用于在运行时访问配置的密钥(例如 ..app.log_level (tinker config('app.log_level')
)。
$newValue
当然是您希望保留的新值。
【讨论】:
你能告诉我我应该把这段代码添加到哪个文件吗? 它说找不到配置 确保文件顶部有use Config;
【参考方案9】:
基于 totymedli 的回答和 Oluwafisayo 的回答。
我设置了一些修改来更改 .env 文件,它在 Laravel 5.8 中工作得很好,但是当我更改它之后,.env 文件被修改了,我可以看到在我用 php artisan serve 重新启动后变量没有改变,所以我试图清除缓存和其他,但我看不到解决方案。
public function setEnvironmentValue(array $values)
$envFile = app()->environmentFilePath();
$str = file_get_contents($envFile);
$str .= "\r\n";
if (count($values) > 0)
foreach ($values as $envKey => $envValue)
$keyPosition = strpos($str, "$envKey=");
$endOfLinePosition = strpos($str, "\n", $keyPosition);
$oldLine = substr($str, $keyPosition, $endOfLinePosition - $keyPosition);
if (is_bool($keyPosition) && $keyPosition === false)
// variable doesnot exist
$str .= "$envKey=$envValue";
$str .= "\r\n";
else
// variable exist
$str = str_replace($oldLine, "$envKey=$envValue", $str);
$str = substr($str, 0, -1);
if (!file_put_contents($envFile, $str))
return false;
app()->loadEnvironmentFrom($envFile);
return true;
所以它使用函数 setEnvironmentValue 正确地重写了 .env 文件,但是 Laravel 如何在不重新启动系统的情况下重新加载新的 .env 文件?
我正在寻找这方面的信息,我发现了
Artisan::call('cache:clear');
但在本地它不起作用!对我来说,但是当我上传代码并在我的服务中进行测试时,它可以正常工作。
我在 Larave 5.8 中对其进行了测试并在我的服务中工作...
当您有一个包含多个单词且单独带有空格的变量时,这可能是一个提示,我所做的解决方案
public function update($variable, $value)
if ($variable == "APP_NAME" || $variable == "MAIL_FROM_NAME")
$value = "\"$value\"";
$values = array(
$variable=>$value
);
$this->setEnvironmentValue($values);
Artisan::call('config:clear');
return true;
【讨论】:
【参考方案10】:Tailor Otwell 使用此代码生成 laravel 应用程序密钥并设置其值(代码已修改为示例目的):
$escaped = preg_quote('='.config('broadcasting.default'), '/');
file_put_contents(app()->environmentFilePath(), preg_replace("/^BROADCAST_DRIVER$escaped/m", 'BROADCAST_DRIVER='.'pusher',
file_get_contents(app()->environmentFilePath())
));
您可以在密钥生成类中找到代码:
Illuminate\Foundation\Console\KeyGenerateCommand
【讨论】:
【参考方案11】:如果您不需要将更改保存到 .env 文件,您可以简单地使用以下代码:
\Illuminate\Support\Env::getRepository()->set('APP_NAME','New app name');
【讨论】:
似乎对我不起作用;在返回视图的控制器方法中使用上面的代码,在视图中调用echo env("APP_NAME")
,清除缓存,没有变化。
它在控制器方法中适用于我,然后在 Laravel 版本 8.42.0 的视图中回显【参考方案12】:
如果你想临时改变它(例如为了测试),这应该适用于 Laravel 8:
<?php
namespace App\Helpers;
use Dotenv\Repository\Adapter\ImmutableWriter;
use Dotenv\Repository\AdapterRepository;
use Illuminate\Support\Env;
class DynamicEnvironment
public static function set(string $key, string $value)
$closure_adapter = \Closure::bind(function &(AdapterRepository $class)
$closure_writer = \Closure::bind(function &(ImmutableWriter $class)
return $class->writer;
, null, ImmutableWriter::class);
return $closure_writer($class->writer);
, null, AdapterRepository::class);
return $closure_adapter(Env::getRepository())->write($key, $value);
用法:
App\Helpers\DynamicEnvironment::set("key_name", "value");
【讨论】:
【参考方案13】:你可以使用这个包 https://github.com/ImLiam/laravel-env-set-command
然后使用 Artisan Facade 调用 artisan 命令,例如:
Artisan::call('php artisan env:set app_name Example')
【讨论】:
我真的不喜欢这个解决方案,因为它更新了 .env 文件。但如果这就是你要找的东西,那就太棒了。【参考方案14】:PHP 8 解决方案
此解决方案使用env()
,因此仅应在未缓存配置时运行。
/**
* @param string $key
* @param string $value
*/
protected function setEnvValue(string $key, string $value)
$path = app()->environmentFilePath();
$env = file_get_contents($path);
$old_value = env($key);
if (!str_contains($env, $key.'='))
$env .= sprintf("%s=%s\n", $key, $value);
else if ($old_value)
$env = str_replace(sprintf('%s=%s', $key, $old_value), sprintf('%s=%s', $key, $value), $env);
else
$env = str_replace(sprintf('%s=', $key), sprintf('%s=%s',$key, $value), $env);
file_put_contents($path, $env);
【讨论】:
如何改进写入.env
文件的其他半打答案?【参考方案15】:
使用下面的函数更改 .env 文件 laravel 中的值
public static function envUpdate($key, $value)
$path = base_path('.env');
if (file_exists($path))
file_put_contents($path, str_replace(
$key . '=' . env($key), $key . '=' . $value, file_get_contents($path)
));
【讨论】:
【参考方案16】:此函数更新现有键的新值或将新键=值添加到文件末尾
function setEnv($envKey, $envValue)
$path = app()->environmentFilePath();
$escaped = preg_quote('='.env($envKey), '/');
//update value of existing key
file_put_contents($path, preg_replace(
"/^$envKey$escaped/m",
"$envKey=$envValue",
file_get_contents($path)
));
//if key not exist append key=value to end of file
$fp = fopen($path, "r");
$content = fread($fp, filesize($path));
fclose($fp);
if (strpos($content, $envKey .'=' . $envValue) == false && strpos($content, $envKey .'=' . '\"'.$envValue.'\"') == false)
file_put_contents($path, $content. "\n". $envKey .'=' . $envValue);
【讨论】:
【参考方案17】:此解决方案基于 Elias Tutungi 提供的解决方案,它接受多个值更改并使用 Laravel 集合,因为 foreach 很糟糕
function set_environment_value($values = [])
$path = app()->environmentFilePath();
collect($values)->map(function ($value, $key) use ($path)
$escaped = preg_quote('='.env($key), '/');
file_put_contents($path, preg_replace(
"/^$key$escaped/m",
"$key=$value",
file_get_contents($path)
));
);
return true;
【讨论】:
【参考方案18】:您可以使用我从互联网上找到的这种自定义方法,
/**
* Calls the method
*/
public function something()
// some code
$env_update = $this->changeEnv([
'DB_DATABASE' => 'new_db_name',
'DB_USERNAME' => 'new_db_user',
'DB_HOST' => 'new_db_host'
]);
if($env_update)
// Do something
else
// Do something else
// more code
protected function changeEnv($data = array())
if(count($data) > 0)
// Read .env-file
$env = file_get_contents(base_path() . '/.env');
// Split string on every " " and write into array
$env = preg_split('/\s+/', $env);;
// Loop through given data
foreach((array)$data as $key => $value)
// Loop through .env-data
foreach($env as $env_key => $env_value)
// Turn the value into an array and stop after the first split
// So it's not possible to split e.g. the App-Key by accident
$entry = explode("=", $env_value, 2);
// Check, if new key fits the actual .env-key
if($entry[0] == $key)
// If yes, overwrite it with the new one
$env[$env_key] = $key . "=" . $value;
else
// If not, keep the old one
$env[$env_key] = $env_value;
// Turn the array back to an String
$env = implode("\n", $env);
// And overwrite the .env with the new data
file_put_contents(base_path() . '/.env', $env);
return true;
else
return false;
【讨论】:
【参考方案19】:替换 .env 文件函数中的单个值:
/**
* @param string $key
* @param string $value
* @param null $env_path
*/
function set_env(string $key, string $value, $env_path = null)
$value = preg_replace('/\s+/', '', $value); //replace special ch
$key = strtoupper($key); //force upper for security
$env = file_get_contents(isset($env_path) ? $env_path : base_path('.env')); //fet .env file
$env = str_replace("$key=" . env($key), "$key=" . $value, $env); //replace value
/** Save file eith new content */
$env = file_put_contents(isset($env_path) ? $env_path : base_path('.env'), $env);
本地(laravel)使用示例:set_env('APP_VERSION', 1.8)
。
使用自定义路径的示例:set_env('APP_VERSION', 1.8, $envfilepath)
。
【讨论】:
以上是关于如何在 laravel 中以编程方式即时设置 .env 值的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Swift 中以编程方式在水平线上设置约束? [关闭]