Skip to content

Usage of $_SERVER vs $_ENV #44

Open

Description

@aik099

Current state:

  • using <server ... in phpunit.xml.dist file to define default settings for test suite
  • using $_SERVER in test suite to use the above-defined settings

Problem:

Inability to override the above settings during GitHub Actions builds because we can set environment variables (readable through $_ENV) and not server variables (readable through $_SERVER).

Solution

Do so Find & Replace in the phpunit.xml.dist on GitHub Actions instead of providing environment variables like DRIVER_URL and such, that don't override what phpunit.xml.dist defines.

Activity

  1. uuf6429 commented on Nov 5, 2024

    @uuf6429
    Member

    Firstly, we shouldn't use $_ENV or $_SERVER, we should use getenv() instead.

    Secondly, I'm sorry but I don't understand the solution - what do you want to replace? The linked PR doesn't make a lot of sense to me, since the browser will almost always by different.

    Additionally, it's not clear to me why the PHPUnit XML should use <server> or <env> - that I cannot judge. My feeling is that using <env> allows overriding by cli env vars whereas <server> doesn't allow overriding?

  2. aik099 commented on Nov 5, 2024

    @aik099
    MemberAuthor

    Firstly, we shouldn't use $_ENV or $_SERVER, we should use getenv() instead.

    I also like getenv better (not sure though how it is different from $_ENV). However, it will introduce a BC break for other drivers, because we need to replace $_SERVER usages in the driver-testsuite repo as well.

    Secondly, I'm sorry but I don't understand the solution - what do you want to replace? The linked PR doesn't make a lot of sense to me, since the browser will almost always by different.

    Replace <server name="WEB_FIXTURES_HOST" value="http://host.docker.internal:8002"/> with a host needed by a GitHub Actions.

    Additionally, it's not clear to me why the PHPUnit XML should use <server> or <env> - that I cannot judge. ...

    Because this is the only way to configure how test suite runs (e.g. what browser to use for testing, how to map paths inside Document Root and such stuff).

    ... My feeling is that using <env> allows overriding by cli env vars whereas <server> doesn't allow overriding?

    According to PHPUnit documentation using <env.... will change $_ENV (and getenv result) unless such environment variable is provided externally.

    Example 1:

    1. I have <env name="WEB_FIXTURES_HOST" value="http://host.docker.internal:8002"/> in the PHPUnit config file
    2. I run PHPUnit as vendor/bin/phpunit
    3. the getenv / $_ENV would have WEB_FIXTURES_HOST key as http://host.docker.internal:8002

    Example 2:

    1. I have <env name="WEB_FIXTURES_HOST" value="http://host.docker.internal:8002"/> in the PHPUnit config file
    2. I run PHPUnit as WEB_FIXTURES_HOST="my-custom-host:80" vendor/bin/phpunit
    3. the getenv / $_ENV would have WEB_FIXTURES_HOST key as my-custom-host:80

    If I had used <server instead of <env such a trick wouldn't have worked.

  3. uuf6429 commented on Nov 5, 2024

    @uuf6429
    Member

    And we want example 2 to work, right? Then the phpunit xml should be using env, not server?

    I also like getenv better (not sure though how it is different from $_ENV).

    $_ENV is always case sensitive (because of normal PHP array access), but getenv is case-insensitive depending on OS. e.g. $_ENV['PATH'] breaks on Windows, but getenv('PATH') is more cross-platform.

    getenv is also more convenient, because you don't have to use isset/empty($_ENV).

    getenv is theoretically slower (because of function call), but the benefits are worth it.

  4. aik099 commented on Nov 5, 2024

    @aik099
    MemberAuthor

    And we want example 2 to work, right? Then the phpunit xml should be using env, not server?

    Yes, but to make it work all usages of $_SERVER in the test suite (not only driver code) must be replaced at least with $_ENV.

    As I said above that would be a BC break for all other drivers using the same test suite.

  5. stof commented on Nov 5, 2024

    @stof
    Member

    env variables are readable through $_SERVER in PHP. We are already relying on that in other drivers when needed: https://github.com/minkphp/MinkSelenium2Driver/blob/db44be5055cb1dfcd323c7b375ff7cf97c187de9/.github/workflows/tests.yml#L87
    And we do it also in the current driver:

    SELENIUM_VERSION: ${{ matrix.selenium }}
    DRIVER_URL: http://localhost:4444/wd/hub
    WEB_FIXTURES_HOST: http://host.docker.internal:8002
    WEB_FIXTURES_BROWSER: ${{ matrix.browser }}
    DRIVER_MACHINE_BASE_PATH: /fixtures/

    Note also that getenv is not thread safe. This is not an issue for usages in the testsuite though. but it might be an issue in driver code (as we don't control how it is used)

  6. aik099 commented on Nov 5, 2024

    @aik099
    MemberAuthor

    env variables are readable through $_SERVER in PHP. We are already relying on that in other drivers when needed: https://github.com/minkphp/MinkSelenium2Driver/blob/db44be5055cb1dfcd323c7b375ff7cf97c187de9/.github/workflows/tests.yml#L87

    This works only, when you don't have corresponding ENV var defined in PHPUnit config file:

    <server name="WEB_FIXTURES_HOST" value="http://host.docker.internal:8002"/>

    This way if we define default env var values in PHPUnit config file they can't overridden via the environment given to PHPUnit runner itself.

  7. aik099 commented on Oct 6, 2026

    @aik099
    MemberAuthor

    @stof, I've checked what PHPUnit 9 actually does with <server> and <env> when the same variable also comes from the shell (ENV_TEST set to PHPUNIT_OVERRIDE in the XML and to ENV_OVERRIDE or nothing in the shell):

    XML Shell getenv() $_SERVER $_ENV
    <server> PHPUNIT_OVERRIDE ENV_OVERRIDE ENV_OVERRIDE PHPUNIT_OVERRIDE –
    <server> PHPUNIT_OVERRIDE none false PHPUNIT_OVERRIDE –
    <env> PHPUNIT_OVERRIDE ENV_OVERRIDE ENV_OVERRIDE ENV_OVERRIDE ENV_OVERRIDE
    <env> PHPUNIT_OVERRIDE none PHPUNIT_OVERRIDE unset PHPUNIT_OVERRIDE

    So env vars do reach $_SERVER as you said, but an active <server> in phpunit.xml.dist overwrites them (row 1). And <env> never writes $_SERVER, so switching the XML to <env> alone would break $_SERVER reads when nothing comes from the shell (row 4).

    Reading getenv() first and falling back to $_SERVER gives the right value in all 4 cases: the shell/CI value wins, and the XML value is the default.

    Proposed method for AbstractConfig in driver-testsuite (replacing direct $_SERVER reads there):

    /**
     * @param string $name
     *
     * @return string|null
     */
    protected function getEnvVar($name)
    {
        $value = getenv($name);
    
        if (false === $value) {
            $value = $_SERVER[$name] ?? null;
        }
    
        return \is_string($value) ? $value : null;
    }

    Defaults stay at the call site, e.g. $this->getEnvVar('WEB_FIXTURES_HOST') ?? 'http://localhost:8002', so PHPStan sees a string there. In drivers the browser default would then live only in their getBrowserName().

    It doesn't break drivers still using <server> (rows 1-2), so they could move to <env> at their own pace. All drivers require mink/driver-testsuite as dev-master, so composer update brings the method in, and the only order requirement is to merge it in driver-testsuite before switching a driver's XML to <env>.

  8. aik099 commented on Oct 6, 2026

    @aik099
    MemberAuthor

    This way both developers version phpunit.xml and phunit.xml.dist of driver (with <env or <server) keeps working (and doesn't suddenly fail if use only getenv without $_SERVER fallback).

    We then could update driver's own phpunit.xml.dist to always-enabled-<env instead of sometimes-enabled-<server when we want.

  9. aik099 commented on Oct 24, 2026

    @aik099
    MemberAuthor

    @stof, to get this moving, which option do you prefer?

    A. Pure getenv(). driver-testsuite replaces $_SERVER reads with getenv(), and drivers switch <server> to <env> in phpunit.xml.dist. Local phpunit.xml files still using <server> stop working. Drivers' CI breaks between the driver-testsuite merge and each driver's .dist update, because dev-master is pulled right away.

    B. Same end state, with a bridge. minkphp/driver-testsuite#118 reads getenv() first and falls back to $_SERVER, with an E_USER_DEPRECATED when the value only came from $_SERVER. Drivers switch to <env> at their own pace, and people with a local <server> config get a message telling them what to change. Once all drivers have switched, the fallback is removed, leaving pure getenv().

    In both cases I'd document <env> usage in the driver-testsuite README.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions