[英]How to set .env values in laravel programmatically on the fly
我有一个自定义 CMS,我在 Laravel 中从头开始编写,并希望在用户设置后从控制器设置env
值,即数据库详细信息、邮件详细信息、一般配置等,并希望为用户提供随时随地更改它们的灵活性使用我正在制作的 GUI。
所以我的问题是,当我需要控制器时,如何将从用户收到的值写入.env
文件。
在旅途中构建.env
文件是个好主意还是有其他解决方法?
由于 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
小心! 并非 laravel .env 中的所有变量都存储在配置环境中。 要覆盖真正的 .env 内容,只需使用:
putenv ("CUSTOM_VARIABLE=hero");
像往常一样阅读 env('CUSTOM_VARIABLE') 或 env('CUSTOM_VARIABLE', 'devault')
注意:根据应用程序的哪个部分使用 env 设置,您可能需要通过将其放入 index.php 或 bootstrap.php 文件来提前设置变量。 对于 env 设置的某些包/用途而言,在您的应用服务提供商中设置它可能为时已晚。
基于乔希的回答。 我需要一种方法来替换.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');
基于 totymedli 的回答。
如果需要一次更改多个环境变量值,您可以传递一个数组 (key->value)。 之前不存在的任何键都将被添加并返回一个布尔值,以便您可以测试是否成功。
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;
}
更简化:
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)
));
}
}
根据vesperknight 的回答,我创建了一个不使用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}"
#更简单的方法来覆盖 .env 你可以这样做
$_ENV['key'] = 'value';
如果您希望将这些设置持久化到环境文件中,以便稍后再次加载它们(即使配置已缓存),您可以使用这样的功能。 我将把安全警告放在那里,对这样的方法的调用应该受到严格的保护,并且应该正确地清理用户输入。
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
是环境文件中的关键(例如.. APP_LOG_LEVEL)
$configKey
是用于在运行时访问配置的键(例如.. app.log_level (tinker config('app.log_level')
)。
$newValue
当然是您希望保留的新值。
基于 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;
}
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
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 文件,您可以简单地使用以下代码:
\Illuminate\Support\Env::getRepository()->set('APP_NAME','New app name');
如果您想临时更改它(例如用于测试),这应该适用于 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");
使用下面的函数更改 .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)
));
}
}
此函数更新现有键的新值或将新的键=值添加到文件末尾
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);
}
}
$envFile = app()->environmentFilePath();
$_ENV['APP_NAME'] = "New Project Name";
$txt= "";
foreach ($_ENV as $key => $value) {
$txt .= $key."=".$value."\n"."\n";
}
file_put_contents($envFile,$txt);
我创建它是为了在命令package:install
中使用,以自动将 .env 键值对添加到 .env 文件。
/**
* Set .env key-value pair
*
* @param array $keyPairs Desired key name
* @return void
*/
public function saveArrayToEnv(array $keyPairs)
{
$envFile = app()->environmentFilePath();
$newEnv = file_get_contents($envFile);
$newlyInserted = false;
foreach ($keyPairs as $key => $value) {
// Make sure key is uppercase (can be left out)
$key = Str::upper($key);
if (str_contains($newEnv, "$key=")) {
// If key exists, replace value
$newEnv = preg_replace("/$key=(.*)\n/", "$key=$value\n", $newEnv);
} else {
// Check if spacing is correct
if (!str_ends_with($newEnv, "\n\n") && !$newlyInserted) {
$newEnv .= str_ends_with($newEnv, "\n") ? "\n" : "\n\n";
$newlyInserted = true;
}
// Append new
$newEnv .= "$key=$value\n";
}
}
$fp = fopen($envFile, 'w');
fwrite($fp, $newEnv);
fclose($fp);
}
你传递给它一个关联数组:
$keyPairs = [
'KEY' => 'VALUE',
'API_KEY' => 'XXXXXX-XXXXXX-XXXXX'
]
它将添加它们或用给定值替换给定键的值。 当然还有改进的余地,比如检查数组是否实际上是一个关联数组。 但这适用于 Laravel 命令类中的硬编码内容。
你可以使用这个包https://github.com/ImLiam/laravel-env-set-command
然后使用 Artisan Facade 调用 artisan 命令,例如:
Artisan::call('php artisan env:set app_name Example')
此解决方案建立在 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;
}
您可以使用我从互联网上找到的这个自定义方法,
/**
* 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;
}
}
替换 .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)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.