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

Inconsistency in environment variables #972

Closed
mateusfmello opened this issue Aug 12, 2024 · 6 comments
Closed

Inconsistency in environment variables #972

mateusfmello opened this issue Aug 12, 2024 · 6 comments
Labels
bug Something isn't working

Comments

@mateusfmello
Copy link

What happened?

Apparently FrankenPHP is launching two Goroutines, where one has the environment variables and the other does not, generating this error:

{"level":"info","ts":1723499343.966919,"msg":"[error] Warning: Undefined array key \"QNT_PUBLICACOES_POR_PAGINA\"","syslog_level":"notice"}
{"level":"info","ts":1723499344.042241,"msg":"[error] Warning: Undefined array key \"APP_ENV\"","syslog_level":"notice"}

{"level":"info","ts":1723499344.2245831,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_ip":"172.23.0.4","remote_port":"47056","client_ip":"172.23.0.4","proto":"HTTP/1.1","method":"GET","host":"XXXXX","uri":"/publicacoes?ultimoVisto=384","headers":{"Upgrade-Insecure-Requests":["1"],"X-Forwarded-Server":["5b8a887a3712"],"Accept-Encoding":["gzip, br"],"Cf-Ray":["8b23ac518da602eb-GRU"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"X-Forwarded-Host":["XXXXX"],"X-Forwarded-Proto":["https"],"Cf-Ipcountry":["BR"],"Sec-Fetch-Dest":["document"],"Sec-Fetch-User":["?1"],"Cookie":["REDACTED"],"Priority":["u=0, i"],"X-Forwarded-For":["172.71.10.159"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8"],"Cf-Connecting-Ip":["XXXXX"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-Site":["none"],"X-Forwarded-Port":["443"],"X-Real-Ip":["XXXXX"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64; rv:129.0) Gecko/20100101 Firefox/129.0"],"Accept-Language":["pt-BR"],"Cdn-Loop":["cloudflare"]}},"bytes_read":0,"user_id":"","duration":0.382732846,"size":31264,"status":200,"resp_headers":{"Permissions-Policy":["browsing-topics=()"],"Server":["Caddy"],"Cache-Control":["no-cache, private"],"Date":["Mon, 12 Aug 2024 21:49:04 GMT"],"Content-Type":["application/json"],"Content-Encoding":["br"],"Vary":["Accept-Encoding"]}}

When it is executed by the routine that has the environment variables, the log is just this:

{"level":"info","ts":1723499345.9641595,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_ip":"172.23.0.4","remote_port":"47056","client_ip":"172.23.0.4","proto":"HTTP/1.1","method":"GET","host":"XXXXX","uri":"/publicacoes?ultimoVisto=384","headers":{"User-Agent":["Mozilla/5.0 (X11; Linux x86_64; rv:129.0) Gecko/20100101 Firefox/129.0"],"Cdn-Loop":["cloudflare"],"X-Forwarded-Port":["443"],"X-Forwarded-Server":["5b8a887a3712"],"X-Forwarded-For":["172.71.10.159"],"X-Forwarded-Host":["XXXXX"],"X-Forwarded-Proto":["https"],"X-Real-Ip":["XXXXX"],"Accept-Encoding":["gzip, br"],"Accept-Language":["pt-BR"],"Cf-Connecting-Ip":["XXXXX"],"Cf-Ray":["8b23ac6009b402eb-GRU"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8"],"Cf-Ipcountry":["BR"],"Sec-Fetch-Site":["none"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-User":["?1"],"Upgrade-Insecure-Requests":["1"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Cookie":["REDACTED"],"Priority":["u=0, i"],"Sec-Fetch-Dest":["document"]}},"bytes_read":0,"user_id":"","duration":0.021481712,"size":31266,"status":200,"resp_headers":{"Date":["Mon, 12 Aug 2024 21:49:05 GMT"],"Content-Type":["application/json"],"Content-Encoding":["br"],"Vary":["Accept-Encoding"],"Permissions-Policy":["browsing-topics=()"],"Server":["Caddy"],"Cache-Control":["no-cache, private"]}}

And the system works normally.

If you keep refreshing the page (F5), the result is like this:

1st request = error
2nd request = success
3rd request = error
4th request = success
5th request = error
6th request = success

In other words, it alternates between the application that has all the environment variables and the other that does not.

In my infrastructure there is only one docker container running my application, so the requests always fall into the same container, including the logs reported here are from the same container.

The problem occurs both on my development machine (x86_64) and on my server (aarch64) in Oracle Cloud.

I use Cloudflare, which is responsible for generating the SSL, but it requires that my server also has a valid SSL, which is a reverse proxy using Traefik, which generates the SSL with Let's Encrypt and within the container the SSL is disabled SERVER_NAME=my-domain:80. But in the development environment, access is made directly to the localhost:8008 container.

My configuration is the same as this repository dunglas/symfony-docker, i only disabled Mercure for Caddy.

I'm using Symfony 7

Build Type

Docker (Debian Bookworm)

Worker Mode

Yes

Operating System

GNU/Linux

CPU Architecture

x86_64

PHP configuration

https://github.com/dunglas/symfony-docker/tree/main

Relevant log output

No response

@mateusfmello mateusfmello added the bug Something isn't working label Aug 12, 2024
@dunglas
Copy link
Owner

dunglas commented Aug 12, 2024

Can you show the PHP code that triggers this error please?

@mateusfmello
Copy link
Author

mateusfmello commented Aug 12, 2024

This is a method to generate the correct API URL, where in the production environment it adds HTTPS and in development it adds HTTP.

public static function getURLAPI(Request $request): string {

		$schemaURL = 'http' . (strtolower($_ENV['APP_ENV']) === 'prod' ? 's' : '') . '://';
		$url       = $schemaURL . $request->getHost();

		if ($request->getPort() != 80 && $request->getPort() != 443)
			$url .= ':' . $request->getPort();

		return $url . $request->getPathInfo();
	}

You can access this link and you will see that in proximaPagina each time the page is updated it will be with HTTPS and the next with HTTP, when it is with HTTP it gives the error in the log:

{"level":"info","ts":1723499344.042241,"msg":"[error] Warning: Undefined array key \"APP_ENV\"","syslog_level":"notice"}

Running cat .env.local.php gives this result:

<?php

// This file was generated by running "composer dump-env prod"

return array (
  'APP_ENV' => 'prod',
  'SYMFONY_DOTENV_PATH' => './.env',
  'SOURCE_COMMIT' => 'XXXXX',
  'COOLIFY_FQDN' => 'XXXXX',
  'COOLIFY_URL' => 'XXXXX',
  'COOLIFY_BRANCH' => 'XXXXX',
  'COOLIFY_CONTAINER_NAME' => 'XXXXX',
  'APP_SECRET' => 'XXXXX',
  'CORS_ALLOW_ORIGIN' => '^https://(www.)?XXXXX.com.br$',
  'DATABASE_URL' => 'XXXXX',
  'JWT_PASSPHRASE' => 'XXXXX',
  'JWT_PUBLIC_KEY' => 'XXXXX',
  'JWT_SECRET_KEY' => 'XXXXX',
  'JWT_TEMPO_VIDA' => 'XXXXX',
  'QNT_PUBLICACOES_POR_PAGINA' => '20',
  'SERVER_NAME' => 'api.aposentadoriadoinss.com.br:80',
  'STORAGE_BUCKET' => 'XXXXX',
  'STORAGE_ENDERECO' => 'XXXXX',
  'STORAGE_ENDERECO_IMAGENS' => 'XXXXX/imagens',
  'STORAGE_KEY' => 'XXXXX',
  'STORAGE_REGIAO' => 'XXXXX',
  'STORAGE_SECRET' => 'XXXXX',
  'TINY_PNG_KEY' => 'XXXXX',
  'PORT' => '80',
  'HOST' => '0.0.0.0',
);

Running echo $APP_ENV gives this result:

prod

These commands were run inside the resulting container from Dockerfile

@withinboredom
Copy link
Collaborator

Does the error still happen when you use getenv() or $_SERVER instead of $_ENV?

Note: getenv isn't thread safe, so if you have things changing the environment during runtime (like a dotenv module), you could end up with a segfault.

@withinboredom
Copy link
Collaborator

withinboredom commented Aug 13, 2024

Here's an example script:

<?php

while(frankenphp_handle_request(function() {
    $value = $_ENV['stuff'] ?? null;
    echo "_ENV: $value\n";

    $value = getenv('stuff');
    echo "getenv: $value\n";

    $value = $_SERVER['stuff'] ?? null;
    echo "_SERVER: $value\n";
})) {}

And the output:

// sudo stuff="abcs" ./frankenphp php-server --worker worker.php,2

> curl -k http://localhost/worker.php
_ENV:
getenv: abcs
_SERVER: abcs

Note: if I set php.ini's variable_order to EGPCS, then it is always filled:

❯ curl -k http://localhost/worker.php
_ENV: abcs
getenv: abcs
_SERVER: abcs

I can't reproduce your issue.

@mateusfmello
Copy link
Author

I added variables_order = EGPCS to 10-app.ini and it apparently solved the problem, now that is a bit strange considering that this configuration is the PHP default, so in theory it should already be working, according to the documentation.

I'll leave this noted so I can check it next week with a standard project. If I can reproduce the problem, I'll upload the project here on Github along with the PR to add the line variables_order = EGPCS.

@boedy
Copy link

boedy commented Sep 16, 2024

I just tried running the sample Symfony project, but I'm noticing that the $_ENV superglobal is never populated with the dotenv configuration. Instead al variables defined in .env seem to be available under the $_SERVER superglobal only.

I've also explicitly set variables_order = EGPCS.

Running this script does seem to populate $_ENV`:

<?php

// Boot your app
require __DIR__.'/vendor/autoload.php';

use Symfony\Component\Dotenv\Dotenv;

while(frankenphp_handle_request(function() {
   $dotenv = new Dotenv();
   $dotenv->load(__DIR__.'/.env');
   $value = $_ENV['APP_ENV'] ?? null;
   echo "_ENV: $value\n";

   $value = getenv('stuff');
   echo "getenv: $value\n";

   $value = $_SERVER['stuff'] ?? null;
   echo "_SERVER: $value\n";
})) {}

Edit:
Looking at the Symfony runtime it seems variables coming from DotEnv are explicitly merged with $_SERVER. Adding a second line $_ENV += $server. Doesn't seem to make a difference though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants