Как установить значения.env в laravel программно "на лету"

У меня есть пользовательская CMS, которую я пишу с нуля в Laravel и хочу установить значения env то есть данные базы данных, данные о почтовом отправлении, общую конфигурацию и т.д. Из контроллера после того, как пользователь настроится и хочет дать пользователю гибкость, чтобы изменить их на ходу используя графический интерфейс, который я создаю.

Поэтому мой вопрос заключается в том, как написать значения, полученные от пользователя, в .env файл, когда мне нужно от контроллера.

И неплохо ли построить файл .env на ходу или есть ли что-нибудь еще?

Заранее спасибо.

Ответ 1

На основании тотемедли ответ.

Там, где требуется изменить несколько значений переменных среды, вы можете передать массив (key-> значение). Любой ключ, отсутствующий ранее, будет добавлен, и будет возвращено значение bool, чтобы вы могли проверить его на успешность.

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;

}

Ответ 2

Поскольку 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

Ответ 3

Осторожно! Не все переменные в laravel.env хранятся в среде конфигурации. Для перезаписи реального содержимого .env используйте просто:

putenv ("CUSTOM_VARIABLE = hero");

Чтобы читать как обычно, env ('CUSTOM_VARIABLE') или env ('CUSTOM_VARIABLE', 'devault')

ПРИМЕЧАНИЕ. В зависимости от того, какая часть вашего приложения использует настройку env, вам может потребоваться установить переменную заранее, поместив ее в файл index.php или bootstrap.php. Установка его в вашем сервис-провайдере приложения может быть слишком поздней для некоторых пакетов/использования настроек env.

Ответ 4

На основе ответа Джоша. Мне нужен был способ заменить значение ключа внутри .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', '[email protected]');

Ответ 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

Если вы хотите, чтобы эти параметры сохранялись в файле среды, чтобы они были загружены позже (даже если кеширование конфигурации), вы можете использовать такую функцию. Я поставлю там предостережение о безопасности, которое вызывает метод, подобный этому, должен быть жестко закрыт, а пользовательский ввод должен быть правильно обработан.

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 - это, конечно, новое значение, которое вы хотите сохранить.

Ответ 7

ТЛ; др

На основе ответа 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 с двойными .env которые оцениваются, а также интерполирует встроенные переменные

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

Ответ 8

Вы можете использовать этот пакет https://github.com/ImLiam/laravel-env-set-command

затем используйте Artisan Facade для вызова команд ремесленника, например:

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

Ответ 9

Это решение основано на решении, предоставленном Элиасом Тутунги, оно принимает множественные изменения значений и использует коллекцию 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;
    }

Ответ 10

На основании тотемедли ответа и ответа Олувафисайо.

Я установил небольшую модификацию, чтобы изменить файл .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;
}

Таким образом, он корректно перезаписывает файл .env с помощью функции setEnvironmentValue, но как 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;
    }

Ответ 11

Замените значение signle в файловой функции .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)