Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.0] Environment variables sometimes return null #8191

Closed
tylercubell opened this issue Mar 26, 2015 · 58 comments
Closed

[5.0] Environment variables sometimes return null #8191

tylercubell opened this issue Mar 26, 2015 · 58 comments

Comments

@tylercubell
Copy link

tylercubell commented Mar 26, 2015

If you make requests fast enough some or all environment variables return null.

To reproduce:

  1. Install fresh L5.
  2. Edit /app/Http/Controllers/WelcomeController.php
  3. Add dd(env('APP_ENV')); in the index function.
  4. Make a bunch of requests in quick succession, i.e. hold down F5 for 2 seconds in a browser.

This bug occurs for me using WAMP 2.5 x64 (latest) on Windows 7.

@GrahamCampbell
Copy link
Member

Duplicate. This is a known issue with php. We've discussed it here before. Feel free to search for the issue.

@tylercubell
Copy link
Author

For anyone else wondering why this happens:

866a8cf#commitcomment-9767647

#7354

#8187

@tylercubell
Copy link
Author

Is there anyone working on a fix at PHP? I can't rely on the whole .env system if it's going to randomly crap out on me.

Is the only workaround to hard-code values into config files right now?

@crynobone
Copy link
Member

Another workaround is to use php artisan config:cache for your production environment.

@tylercubell
Copy link
Author

The artisan command didn't work for me. The same behavior still happens.

@crynobone
Copy link
Member

The artisan command didn't work for me. The same behavior still happens.

You mean dd(env('APP_ENV')); behaviour? Obviously that expected which why I said "for your production environment". https://github.com/laravel/framework/blob/5.0/src/Illuminate/Foundation/Bootstrap/DetectEnvironment.php#L28

@tylercubell
Copy link
Author

So to be clear:

  1. In, say, /app/config/app.php add:
    'env' => env('APP_ENV')
  1. Cache the config files using php artisan config:cache

  2. Instead of calling env('APP_ENV'); use \Config::get('app.env'); to avoid the issue.

  3. Use config:cache for every deployment.

This is like death by 1001 papercuts, just one more thing to worry about. Why was this feature added before the PHP bug was fixed? I don't get it...

@crynobone
Copy link
Member

I don't get why would you need to cache APP_ENV, you cache other value such as DB_USERNAME, QUEUE_DRIVER etc. This way your app remain working all the time as this code is already resolved in the cached config.php.

Why was this feature added

http://12factor.net/config

Why not use PHP (just like Laravel 4)?

Well, if that the case, you need a new "duplicate" configuration for your none PHP app, if you want to use Python or Go for some of the background/queue process.

@tylercubell
Copy link
Author

I don't need to, APP_ENV was just an example. I'm caching other things.

I'm not asking why the feature was added, I'm asking why now. Why before the PHP bug is fixed?

@llioor
Copy link

llioor commented Mar 26, 2016

Hey @tylercubell,
Is there any news about this issue?
Right now I'm setting the "production values" as default in my config files like: (db_password, *_production_password_)

It is still happening in 5.2 or someone solve the issue?
Thanks.

@P4Thi0ut
Copy link

Hi, I'm encountering the same issue here, no clear solution yet ?
I still try to believe that Laravel is a great framework, having to worry about such
issue is kind of unexpected and displeasing.

@toby1kenobi
Copy link

Please can the docs be updated, to reflect the requirement to use config:cache?! I just lost a few hours on trying to understand why env() was behaving unpredictably, which seems particularly futile now I discover it's been discussed here a few times.

@GrahamCampbell
Copy link
Member

This is documented in our upgrading guide. If there are any other places you'd like to see this in the docs, we'd be very grateful if you could send a PR please. :)

@toby1kenobi
Copy link

Thanks for the quick response! So wait, is the docs site in Gitbhub, is that what you mean?

This page https://laravel.com/docs/5.2/configuration#determining-the-current-environment makes it sound like using .env would be a great thing to do, but even in dev I'm seeing it toggle between the values I want and null (where, presumably, default values don't exist)

@llioor
Copy link

llioor commented Jun 21, 2016

From reading "Do something with dotenv finally #13906" I understand that there is not a real solution for it on Apache and what you need to do is to run: "php artisan config:cache" in commend. I think it's a MUST part in starting laravel project docs.

Thank you @GrahamCampbell for sharing with us the commend.

@aruncnt
Copy link

aruncnt commented Jun 25, 2016

same issue with me

@JJJJJJJerk
Copy link

upgrade my php to 7.0.10 function env get null value

@GrahamCampbell
Copy link
Member

This is a known issue with PHP. Make sure you run php artisan config:cache and never read env variables from outside the config files.

@JJJJJJJerk
Copy link

JJJJJJJerk commented Aug 23, 2016

run php artisan config:clear will fix the env null value drama

@GrahamCampbell
Copy link
Member

GrahamCampbell commented Aug 23, 2016

Not clear, but cache.

@hugobluefuse
Copy link

hugobluefuse commented Sep 29, 2016

Hi,

when calling \Config::get('app.env'); I'm still getting local, although I changed the env to production.
env(APP_ENV) returns null.

I'm using a thread safe php installation. Do I need to get the unsafe version?

PS: Workaround - get App:environment() from within App and pass it to the view

@decadence
Copy link
Contributor

php artisan config:cache works for me on Windows 10, PHP 5.6, Apache 2.4.
Is this bug for PHP, Windows or Apache?

@llioor
Copy link

llioor commented Oct 12, 2016

Hi @decadence ,
It is not a PHP/Windows/Apache BUG, it is a ".env" known bug which can be solved with:
php artisan config:cache as you said.

Good luck.

@milon
Copy link

milon commented Nov 9, 2016

I am facing the same issue. And the sad part is, php artisan config:cache can't fix the issue. In my development environment(Mac OS sierra, php 7.0.12, laravel 5.3) if works fine, but in my production server(Ubuntu 14.04.4, php 7.0.11, laravel 5.3), it is not working. Any solution?

@llioor
Copy link

llioor commented Nov 9, 2016

@milon
yes... try to do
php artisan config:cache

It will do php artisan cache:clear automatically.

@imbrish
Copy link
Contributor

imbrish commented Nov 9, 2017

Doing php artisan config:cache is the way to go in production, however this was bugging me a lot in local development, and thus I came up with a way to patch it.

app/Http/Kernel.php

protected function bootstrappers()
{
    // Remove original LoadEnvironmentVariables bootstrapper and prepend our custom version.
    return array_merge([
        \App\Library\Core\LoadEnvironmentVariables::class,
    ], array_diff($this->bootstrappers, [
        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    ]));
}

app/Library/Core/LoadEnvironmentVariables.php

namespace App\Library\Core;

use Dotenv\Dotenv;
use Dotenv\Exception\InvalidPathException;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables as OriginalLoadEnvironmentVariables;

class LoadEnvironmentVariables extends OriginalLoadEnvironmentVariables
{
    public function bootstrap(Application $app)
    {
        if ($app->configurationIsCached()) {
            return;
        }

        $this->checkForSpecificEnvironmentFile($app);

        try {
            (new Dotenv($app->environmentPath(), $app->environmentFile()))->overload();
        } catch (InvalidPathException $e) {
            //
        }
    }
}

app/Library/Utilities/helpers.php

function get_env($key, $default = null)
{
    // First try to obtain value from superglobals and only if that fails fall back to getenv.
    if (array_key_exists($key, $_ENV)) {
        $value = $_ENV[$key];
    }
    else if (array_key_exists($key, $_SERVER)) {
        $value = $_SERVER[$key];
    }
    else {
        $value = getenv($key);
    }

    // If variable does not exist return default value.
    if ($value === false) {
        return value($default);
    }

    // Finally parse and return the value.
    switch (strtolower($value)) {
        case 'true':
        case '(true)':
            return true;
        case 'false':
        case '(false)':
            return false;
        case 'empty':
        case '(empty)':
            return '';
        case 'null':
        case '(null)':
            return;
    }

    if (strlen($value) > 1 && Str::startsWith($value, '"') && Str::endsWith($value, '"')) {
        return substr($value, 1, -1);
    }

    return $value;
}

Then it is all about replacing default env helper with our brand new get_env.

It's good enough for my needs. I used it for some time now and haven't had any problems with env since. It works on my local dev machine on windows, but staging server didn't complain either.

@GrahamCampbell do you think it is worth a pr? Of course if problem remains, last checked on 5.4.

@tylercubell
Copy link
Author

tylercubell commented Nov 9, 2017

It's now been over two years and nothing has changed. I think this whole environment variable issue is representative of Laravel and its official packages (especially Cashier and Spark). It looks elegant at first glance but when you scratch the surface you find these types of ridiculous design decisions.

Why can't Laravel simply parse environment variables from a text file by itself? Why does it rely on an over-engineered solution that produces unstable results? I'm sorry but this is just plain stupid. Let the minority of users who care about server-level environment variables and understand the caveats opt-in instead of causing problems for the rest of us. Problem solved.

Cost > Benefit. You can clearly see that by all the StackOverflow questions and comments on this thread by now.

@brexis
Copy link

brexis commented Nov 9, 2017

@imbrish did you try to clear the cache? php artisan cache:clear
On development, you should avoid using php artisan config:cache.

@imbrish
Copy link
Contributor

imbrish commented Nov 9, 2017

@brexis how does it help to solve the env problem?

@alsilva86
Copy link

This is a shame for laravel, nobody giving a clear solution only clear and config cache suggestions

@llioor
Copy link

llioor commented Dec 12, 2017

@alsilva86 what's wrong with this solution?
php artisan config:cache
It will clear your old config and then will re-cache it.

@alsilva86
Copy link

alsilva86 commented Dec 13, 2017 via email

@bionicmaster
Copy link
Contributor

@llioor what's wrong with this solution? that doesn't apply at all to lumen, where this is happening too, we can't do config:cache or something else like that

@iamvinny
Copy link

iamvinny commented Jan 8, 2018

The only thing that worked for me (on production) was

php artisan config:clear

@imbrish
Copy link
Contributor

imbrish commented Jan 9, 2018

@iamvinny you seem to be talking about cached config not being updated when .env file is changed, then config:clear will help. But because of other issues you should keep you config cached in production, thus it's better to do config:cache which will clear and re-cache the config.

However many here experience different problem - when config is not cached multiple concurrent requests may cause env variables to be blank for some of these requests.

@vcats
Copy link

vcats commented Mar 9, 2018

run php artisan config:clear if you don't want to use the config cache else
use run php artisan config:cache

@fkomaralp
Copy link

Code from vlucas/phpdotenv repository

$dotenv = new \Dotenv\Dotenv("/var/www/html/", '.env');
$dotenv->load();

If I load my local .env file with this method my code is worked.
After remove this line my code is getting an error, because env function is not working propaply.

You need to specify this in boot function on laravel. You can create a middleware function with:

php artisan make:middleware LoadEnv

and after that you need to add the code to handle method.

Or you can use the AppBefore middleware's handle method.
Finished code is

<?php

namespace App\Http\Middleware;

use Closure;

class LoadEnv
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $dotenv = new \Dotenv\Dotenv("/var/www/html/", '.env');
        $dotenv->load();

        return $next($request);
    }
}

And you need to add middleware to Http\Kernel.php file

protected $middleware = [
        LoadEnv::class,

@kjdion84
Copy link

dotenv is so garbage.

I still don't understand why you can't just do if (file_exists('env.php')) and then have those values be an array, which gets called before the actual config files, and maps them accordingly using a helper function. You could even have your own env() helper function which checks to see if env array values are set and if they are use them, otherwise use the default second parameter.

Why use a library for something that can literally be less than 10 lines of code?

@gutitrombotto
Copy link

Hi! I had the same problem; when I enable cache (artisan config:cache) the env() helper function does not work. So I have created my own function to parse the .env file and i have replaced every call to env() function by my own function.
I don't know if this is not a good practice but this has resolved my problem.
If you want, i can share my simple code. I only use Dotenv library.

@llioor
Copy link

llioor commented Jun 21, 2018

@bionicmaster There is no solution for Lumen right now. The caching solution is good just for Laravel.
I think that manually loading the configuration file is the only option with Lumen.
$app->configure('app');

@llioor
Copy link

llioor commented Aug 15, 2018

The solution is to hardcode your production values into the config files and do not use an .env file in production. Dotenv specifically states it is not meant for production environments.

Wrong... the production environment values have to be protected and u can not share them on the git repository. The solution is to cache the env values with php artisan config:cache

@garygreen
Copy link
Contributor

garygreen commented Aug 16, 2018

@kjdion84

Dude. Take a chill pill. There is a solution to the multi threading problem which, as already stated by others:

  1. Caching your config correctly.
  2. Only use env() in your config files.

If you've done it right, then you wouldn't have to come on here and rant so much. Seems to me you aren't deploying or setting up your configs correctly.

Laravel won't even call dotenv if you've got your configs cached correctly.

@kejodion
Copy link

@garygreen

Caching the config does not resolve the issue, as stated several times in this thread. Only an idiot would use env() outside of config files. The only non-obtrusive fix to this issue is to simply hardcode your production values into the actual laravel config files so that this only happens in dev/testing, but then you run into the problem of committing sensitive data to VC.

Also, since your response, 3 more references were made to this issue. Clearly still happening, and no amount of condescending "uR jUsT dOiNg iT wRoNg" is going to help resolve the situation.

@garygreen
Copy link
Contributor

@kjjdion

I was responding to a guy who was CLEARLY doing it wrong as he had also posted on Reddit (and subsequently got his account banned) then came onto this github issue to rant about how terrible Dotenv & Laravel is, despite the fact that several people have pointed out his error and a fix for it.

If this was still truly a massive issue, there would be hundreds of developers coming here with the same issue and it would of been fixed by now.

With that said, if you can give steps on exactly why config:cache doesn't work for you, then the community can begin to debug and understand WHY that isn't working - it's not helpful to say it's not working without any details about your setup, PHP version, Laravel version, what your doing, code examples, etc.

@P4Thi0ut
Copy link

P4Thi0ut commented Apr 4, 2019

There is no solution for Lumen right now. The caching solution is good just for Laravel.
I think that manually loading the configuration file is the only option with Lumen.
$app->configure('app');

@llioor where do you put that call ? In the bootstrap.php file ? In your class making the DB call ?
Thank you!

@llioor
Copy link

llioor commented Apr 4, 2019

@P4Thi0ut
I added it to bootstrap/app.php:

// load config services
$app->configure('app');
$app->configure('services');
$app->configure('geoip');
$app->configure('filesystems');

@kejojedi
Copy link

Laravel 7 is out. This is still an issue. Why does a web framework need server level environment variables when it can simply be done with PHP constants?

@laravel laravel locked and limited conversation to collaborators Mar 30, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests