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

dotenv not using real system env vars when they exist although specified in .env doc, but it works in a Command #54464

Open
leroy0211 opened this issue Apr 2, 2024 · 6 comments

Comments

@leroy0211
Copy link

Symfony version(s) affected

5.4 -> 7.0

Description

When I specify a variable in .env file like FOOBAR and give it some default value. And I specify that same variable FOOBAR as system variable in a docker container, it doesn't use the system variable. Although the documentation in the .env file specifies:

# Real environment variables win over .env files.

I can't seem to wrap my head around it, because on the command line it works perfectly fine.

Second when you run bin/console debug:dotenv the env variable specified on system level is not shown anymore. When I remove the system variable, it perfectly shows in the bin/console debug:dotenv.

Am I missing something? Or could anybody lead me to the correct documentation?

How to reproduce

#.env 

FOOBAR=default
# services.yaml
parameters:
    my_foobar: '%env(FOOBAR)%'
# src/Controller/DefaultController.php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Routing\Attribute\Route;

class DefaultController extends AbstractController
{
    public function __construct(
        #[Autowire('%my_foobar%')]
        private string $foobar = ""
    ) {}

    #[Route("/")]
    public function index()
    {
        return $this->json(['foobar' => $this->foobar]);
    }
}
# src/Command/DefaultCommand.php

namespace App\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

#[AsCommand("app:debug")]
class DefaultCommand extends Command
{
    public function __construct(
        #[Autowire('%my_foobar%')]
        private string $foobar = ""
    )
    {
        parent::__construct(null);
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $output->writeln($this->foobar);

        return Command::SUCCESS;
    }
}
# Dockerfile 

FROM php:8.3-apache

ENV APP_ENV=prod
ENV APP_DEBUG=0

ENV APACHE_DOCUMENT_ROOT=/var/www/html/public/
ENV COMPOSER_ALLOW_SUPERUSER=1

RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf

COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

RUN sed -i -e 's/80/8080/g' -e 's/443/8443/g' /etc/apache2/ports.conf \
   && find /etc/apache2/sites-available/ -type f -exec sed -i -e 's/:80/:8080/g' -e 's/:443/:8443/g' {} \;

EXPOSE 8080

Run a docker container with env FOOBAR=system.

Now if you go to http://localhost:[port] you will see {"foobar":"default"}. When you run bin/console app:debug from within the container you will see system.

Possible Solution

No response

Additional Context

No response

@leroy0211
Copy link
Author

Update:

When I remove the FOOBAR="default" line from the .env file it shows the system env variable value without me having to specify the SetEnv in the apache vhost.

@dmaicher
Copy link
Contributor

dmaicher commented Apr 3, 2024

Maybe related to https://www.php.net/manual/en/ini.core.php#ini.variables-order ? 🤔 What is the value used via apache? Is it different from the value used on cli?

@leroy0211
Copy link
Author

leroy0211 commented Apr 4, 2024

I guess you mean the variables_order value in php.ini. It's the same in apache as in cli. Both use GPCS because I've copied the php.ini-production to php.ini. It seems that by default php uses EGPCS, but the production and development ini set GPCS.

I've changed it back to the default EGPCS and now the variable is loaded from the system env as expected.

Because I now know what to look for, it seems this issue is related to #45266. However, I couldn't find any documentation for it. Maybe add some documentation to https://symfony.com/doc/current/setup/web_server_configuration.html#apache ?

[update]
php.ini's documentation:

[..] because ENV is not as commonly used as the others, ENV is not recommended on productions servers. You
can still get access to the environment variables through getenv() should you
need to.

Since symfony/dotenv uses $_ENV this production suggested setting is not suitable.

@leroy0211
Copy link
Author

An update to setting the variables_order=EGPCS php.ini setting for apache and cli.
Whenever I run bin/phpunit from inside the container, it's using the system environment variable for APP_ENV, which is APP_ENV=dev, although the phpunit.xml.dist file specifies

<server name="APP_ENV" value="test" force="true" />

To run the testcases from inside the container I have to run it like:

APP_ENV=test bin/phpunit 

I need to run the testcases from inside the container, because it's using several php extensions, which otherwise fail when these are not installed.

@dmaicher
Copy link
Contributor

dmaicher commented Apr 7, 2024

You might want to try

<env name="APP_ENV" value="test" force="true" />

@leroy0211
Copy link
Author

If I replace

<server name="APP_ENV" value="test" force="true" />

with

<env name="APP_ENV" value="test" force="true" />

I got an error that the KERNEL_CLASS environment variable must be set.

If I add them both like so:

<server name="APP_ENV" value="test" force="true" />
<env name="APP_ENV" value="test" force="true" />

Then it's working as expected.

However, this seems wrong to me. And all because I copied over the php.ini-production to php.ini to set the default production ini settings.

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

No branches or pull requests

4 participants