How to set .env values in laravel programmatically on the fly

PhpLaravelEnvironment Variables

Php Problem Overview


I have a custom CMS that I am writing from scratch in Laravel and want to set env values i.e. database details, mailer details, general configuration, etc from controller once the user sets up and want to give user the flexibility to change them on the go using the GUI that I am making.

So my question is how do I write the values received from user to the .env file as an when I need from the controller.

And is it a good idea to build the .env file on the go or is there any other way around it?

Thanks in advance.

Php Solutions


Solution 1 - Php

Since Laravel uses config files to access and store .env data, you can set this data on the fly with config() method:

config(['database.connections.mysql.host' => '127.0.0.1']);

To get this data use config():

config('database.connections.mysql.host')

>To set configuration values at runtime, pass an array to the config helper

https://laravel.com/docs/5.3/configuration#accessing-configuration-values

Solution 2 - Php

Watch out! Not all variables in the laravel .env are stored in the config environment. To overwrite real .env content use simply:

putenv ("CUSTOM_VARIABLE=hero");

To read as usual, env('CUSTOM_VARIABLE') or env('CUSTOM_VARIABLE', 'devault')

NOTE: Depending on which part of your app uses the env setting, you may need to set the variable early by placing it into your index.php or bootstrap.php file. Setting it in your app service provider may be too late for some packages/uses of the env settings.

Solution 3 - Php

Based on josh's answer. I needed a way to replace the value of a key inside the .env file.

But unlike josh's answer, I did not want to depend on knowing the current value or the current value being accessible in a config file at all.

Since my goal is to replace values that are used by Laravel Envoy which doesn't use a config file at all but instead uses the .env file directly.

Here's my take on it:

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);
}

Usage:

$this->setEnvironmentValue('DEPLOY_SERVER', '[email protected]');

Solution 4 - Php

More simplified:

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)
    ));
}

or as helper:

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)
        ));
    }
}

Solution 5 - Php

Based on totymedli's answer.

Where it is required to change multiple enviroment variable values at once, you could pass an array (key->value). Any key not present previously will be added and a bool is returned so you can test for success.

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;
    
}

Solution 6 - Php

#more simple way to cover .env you can do like this

$_ENV['key'] = 'value';

Solution 7 - Php

tl;dr

Based on vesperknight's answer I created a solution that doesn't use strtok or 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);
}

Explanation

This doesn't use strtok that might not work for some people, or env() that won't work with double-quoted .env variables which are evaluated and also interpolates embedded variables

KEY="Something with spaces or variables ${KEY2}"

Solution 8 - Php

In the event that you want these settings to be persisted to the environment file so they be loaded again later (even if the configuration is cached), you can use a function like this. I'll put the security caveat in there, that calls to a method like this should be gaurded tightly and user input should be sanitized properly.

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");
    }
}

An example of it's use would be;

$this->setEnvironmentValue('APP_LOG_LEVEL', 'app.log_level', 'debug');

$environmentName is the key in the environment file (example.. APP_LOG_LEVEL)

$configKey is the key used to access the configuration at runtime (example.. app.log_level (tinker config('app.log_level')).

$newValue is of course the new value you wish to persist.

Solution 9 - Php

If you don't need to save your changes to .env file, you could simply user this code :

\Illuminate\Support\Env::getRepository()->set('APP_NAME','New app name');

Solution 10 - Php

If you want to change it temporarily (e.g. for a test), this should work for 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);
    }
}

Usage:

App\Helpers\DynamicEnvironment::set("key_name", "value");

Solution 11 - Php

Based on totymedli's answer and Oluwafisayo's answer.

I set a little modification to change the .env file, It works too fine in Laravel 5.8, but when after I changed it the .env file was modificated I could see variables did not change after I restart with php artisan serve, so I tried to clear cache and others but I can not see a solution.

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;
}

So it rewrites correctly the .env file with the funtion setEnvironmentValue, but How can Laravel reload the new .env without to restart the system?

I was looking information about that and I found

    Artisan::call('cache:clear');

but in local it does not work! for me, but when I uploaded the code and test in my serve it works to fine.

I tested it in Larave 5.8 and worked in my serve...

This could be a tip when you have a variable with more than one word and separetly with a space, the solution i did

    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;
    }

Solution 12 - Php

Tailor Otwell generate the laravel application key and set its value using this code (code modified for example purpose):

$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())
));

You can find the code in the key generation class: Illuminate\Foundation\Console\KeyGenerateCommand

Solution 13 - Php

you can use this package https://github.com/ImLiam/laravel-env-set-command

then use Artisan Facade to call artisan commands ex:

Artisan::call('php artisan env:set app_name Example')

Solution 14 - Php

PHP 8 solution

This solution is using env() so should only be run when the configuration is NOT cached.

/**
 * @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);
}

Solution 15 - Php

this function update new value of existing key or add new key=value to end of file

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);
  }
}

Solution 16 - Php

This solution builds upon the one provided by Elias Tutungi, it accepts multiple value changes and uses a Laravel Collection because foreach's are gross

    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;
    }

Solution 17 - Php

You can use this custom method i located from internet ,

  /**
 * 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;
        }
    }

Solution 18 - Php

use the function below to change values in .env file 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)
        ));
    }
}

Solution 19 - Php

Replace single value in .env file function:

/**
 * @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);
}

Example to local (laravel) use: set_env('APP_VERSION', 1.8).

Example to use custom path: set_env('APP_VERSION', 1.8, $envfilepath).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChintan PalanView Question on Stackoverflow
Solution 1 - PhpAlexey MezeninView Answer on Stackoverflow
Solution 2 - PhpOliver MasloView Answer on Stackoverflow
Solution 3 - PhpvesperknightView Answer on Stackoverflow
Solution 4 - PhpElias TutungiView Answer on Stackoverflow
Solution 5 - PhpOluwafisayoView Answer on Stackoverflow
Solution 6 - Phpbty_cjView Answer on Stackoverflow
Solution 7 - PhptotymedliView Answer on Stackoverflow
Solution 8 - PhpJoshView Answer on Stackoverflow
Solution 9 - PhpJukeboxView Answer on Stackoverflow
Solution 10 - PhpGizmoView Answer on Stackoverflow
Solution 11 - Phpiohan sandovalView Answer on Stackoverflow
Solution 12 - PhpYassine QoraicheView Answer on Stackoverflow
Solution 13 - PhpAhmed AtouiView Answer on Stackoverflow
Solution 14 - PhpangauberView Answer on Stackoverflow
Solution 15 - Phpmf340View Answer on Stackoverflow
Solution 16 - PhpRandy AllenView Answer on Stackoverflow
Solution 17 - PhpAbd AbughazalehView Answer on Stackoverflow
Solution 18 - PhpziggybabaView Answer on Stackoverflow
Solution 19 - PhpMwspace LLCView Answer on Stackoverflow