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

Artisan serve ignores REAL environment variables #45450

Closed
MichaelVoelkel opened this issue Dec 29, 2022 · 4 comments
Closed

Artisan serve ignores REAL environment variables #45450

MichaelVoelkel opened this issue Dec 29, 2022 · 4 comments

Comments

@MichaelVoelkel
Copy link

MichaelVoelkel commented Dec 29, 2022

  • Laravel Version: 8.82.0
  • PHP Version: 8
  • Database Driver & Version:

Description:

I run Laravel via Sail (version 8.1) and supervisord is used to serve. However, while the variables from .env clearly show up and can be used, this is not true for the REAL system/server environment variables. According to docs these should overwrite the variables but nope. I have tried everything but I cannot let my docker/supervisord inject any variables into Laravel. However, this is the normal application for docker: Inject something.

Steps To Reproduce:

My supervisord.conf is this (sail default for 8.1)

[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid

[program:php]
command=/usr/bin/bash -c "export TEST_VAR_A=100 && env && TEST_VAR_B=200 /usr/bin/php /var/www/html/artisan serve --host=0.0.0.0 --port=80"

user=sail
environment=LARAVEL_SAIL="1",TEST_VAR_C="100"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

As you can see, I add test vars at various places. I also run env above and, in the log, I see that this environment variable is correctly within the env. The environment variables are everywhere...

However, once in Laravel (whether I use getenv, check config, manually use env() function for a specific environment variable, it does not matter), I cannot access ANY of my TEST_VAR_x variables.

It cannot be so difficult to just pass in environment variables and use them in PHP? This is no issue in any other programming language/framework I know of including Python/Django, Go, Rust, custom C++, RuR, Java, JS Node, ...

The process of how environment variables go from the system/server environment into Laravel does not seem to be documented well either. Also, each google search for "environment variables" in PHP silently assumes that always .env is meant... PHP's way of adding some EXTRA variables that are actually not what the whole world understands by environment variables - thus neatly overriding a well-known and important concept and making it un-google-ble.

For anyone else reading this: My shitty workaround is for now to have some placeholder in .env file and run in supervisord a sed replacing the content of this variable.

Sorry, I'm exhausted and frustrated.

But I appreciate very much any help...

@driesvints
Copy link
Member

Hey there,

Unfortunately we don't support this version anymore. Please check out our support policy on which versions we are currently supporting. Can you please try to upgrade to the latest version and see if your problem persists? If so, please open up a new issue and we'll help you out.

Thanks!

@MateusBMP
Copy link

MateusBMP commented Jun 29, 2023

It's a function, not a bug! The Illuminate\Foundation\Console\ServeCommand define the property $passthroughVariables. See:

image

So, in startProcess method, we found this:

/**
 * Start a new server process.
 *
 * @param  bool  $hasEnvironment
 * @return \Symfony\Component\Process\Process
 */
protected function startProcess($hasEnvironment)
{
    $process = new Process($this->serverCommand(), public_path(), collect($_ENV)->mapWithKeys(function ($value, $key) use ($hasEnvironment) {
        if ($this->option('no-reload') || ! $hasEnvironment) {
            return [$key => $value];
        }

        return in_array($key, static::$passthroughVariables) ? [$key => $value] : [$key => false];
    })->all());

    $process->start($this->handleProcessOutput());

    return $process;
}

Because of this, only the environments defined in $passthroughVariables will be passed to the PHP server. Looking for the past, others projects had problems with this, like in PR #46857.

@driesvints , it is possible to reopen the issue? Or can we suggest a new feature to customize which environment variables are loaded?

Important: I'm using Laravel v10.14.1

@MateusBMP
Copy link

For documentation purposes, we can rewrite the php artisan serve command creating a new Console Command:

php artisan make:command ServeCommand

Now, extends the Illuminate\Foundation\Console\ServeCommand class, adding all the extra environments:

namespace App\Console\Commands;

use Illuminate\Foundation\Console\ServeCommand as BaseServeCommand;

class ServeCommand extends BaseServeCommand
{
    /**
     * The environment variables that should be passed from host machine to the PHP server process.
     *
     * @var string[]
     */
    public static $passthroughVariables = [
        'APP_OTHER_ENV', # The new environment
        'APP_ENV',
        'IGNITION_LOCAL_SITES_PATH',
        'LARAVEL_SAIL',
        'PATH',
        'PHP_CLI_SERVER_WORKERS',
        'PHP_IDE_CONFIG',
        'SYSTEMROOT',
        'XDEBUG_CONFIG',
        'XDEBUG_MODE',
        'XDEBUG_SESSION',
    ];
}

So, if you are using Laravel Sail, you will able to add the APP_OTHER_ENV via Docker Compose environment:

# For more information: https://laravel.com/docs/sail
version: '3'
services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.2
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.2/app
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${APP_PORT:-80}:80'
            - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
        environment:
            APP_OTHER_ENV: 'new_environment' # The new environment
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
            IGNITION_LOCAL_SITES_PATH: '${PWD}'
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
networks:
    sail:
        driver: bridge

@ctwillie
Copy link

I ended up creating a custom serve command as @MateusBMP suggested. Worked perfectly for my use case locally. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants