laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.21k stars 10.9k forks source link

.env issue with PHP thread-safe #7354

Closed bioteck closed 9 years ago

bioteck commented 9 years ago

I noticed a problem with functions putenv() and getenv() when PHP is thread-safe: if a URL is called before another is completed, its environment variables will be reset when the first script is finished. It's problematic with ajax requests, or simply if a user opens several links too quickly in new tabs (for example).

You can reproduce this bug by using WampServer, or any other server with PHP thread-safe, and creating two routes in "app/Http/routes.php":

Route::get('test1', function()
{
    sleep(5);

    return 'APP_ENV: '.env('APP_ENV');
});

Route::get('test2', function()
{
    sleep(5);

    return 'APP_ENV: '.env('APP_ENV');
});

Then call "test1", and while it's sleeping, call "test2". "test1" will display "APP_ENV: local", but "test2" will display "APP_ENV: "

env_var_issue

This problem occurred with getenv(), but $_ENV and $_SERVER are not affected. So it can be resolved by using Dotenv::findEnvironmentVariable(), which uses $_ENV in priority, instead of getenv() in helper env():

$value = Dotenv::findEnvironmentVariable($key);

if ($value === null) return value($default);

The call of Dotenv::makeMutable() is also needed in bootstrapper "DetectEnvironment.php":

try
{
    Dotenv::makeMutable();
    Dotenv::load($app['path.base'], $app->environmentFile());
}
catch (InvalidArgumentException $e)
{
    //
}
GrahamCampbell commented 9 years ago

Please open an issue on the phpdotenv repo.

bioteck commented 9 years ago

But it's not a phpdotenv issue! It's a PHP issue. However, I open an issue on Laravel because it can be solved in the way I explained. Why ignore my issue while I suggest a solution?

GrahamCampbell commented 9 years ago

There's nothing we can realistically do about it.

GrahamCampbell commented 9 years ago

Wait, what? If you've got a solution, then feel free to send a pull. That would be awesome! :)

Issues aren't very helpful to us.

neomerx commented 9 years ago

@bioteck Have you noticed? You should choose where to post issues depending on whether you have solution. :+1:

crynobone commented 9 years ago

There's nothing we can realistically do about it.

Change env() to use Dotenv::findEnvironmentVariable($key) instead of getenv($key)?

GrahamCampbell commented 9 years ago

@crynobone I actually already privately discussed this via email, and it's clear that I was too hastily to dismiss this, but we're very much happy to receive pull requests to address this :)

fkomaralp commented 6 years ago

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 handlemethod.

Or you can use the AppBefore middleware's handlemethod. 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,
devcircus commented 6 years ago

@fkomaralp Laravel automatically calls the load method for you when the framework boots.

JustinShift commented 2 years ago

If anyone is interested this issues only started happening to us when we set clear_env = yes in the PHP-FPM pool config. We still testing to confirm but thought I would post it here in case it helps somebody else.