Skip to content

(Process) Passing a new environment variable is problematic on Debian distros #18796

Closed
@totten

Description

@totten

Use case: You want to use Process to launch a subprocess. The sub-process requires an extra environment variable (eg CHILDVAR=somevalue), but any other environment variables (such as PATH, TMPDIR, SSH_AUTH_SOCK, ad nauseum) should be passed-through without modification. In the contract for Process::__construct(), the only way to pass a new variable is to append it to $_ENV, e.g.

$p = new Process($command, $cwd, $_ENV + array("CHILDVAR"=>"somevalue"));

That is intuitive, but it does not work in Debian-based distros because it relies on $_ENV. In Debian's PHP packages, the php.ini sets variables_order=GPCS which kills $_ENV. (By contrast, upstream php.net defaults to variables_order=EGPCS which supports $_ENV.). To see this in action, run this on any PHP CLI:

php -d variables_order=EGPCS -r 'print_r($_ENV);'
php -d variables_order=GPCS -r 'print_r($_ENV);'

A few ideas for resolving this problem -- none of which seem pretty:

  1. Downstream code should guard all references to $_ENV and generate warnings about variables_order. (Problem: That sucks for a large portion of the user community which runs on Debian/Ubuntu.)
  2. Complain to debian.org, ubuntu.com, etal, and haggle with them about fixing the defaults. I suspect that they've confused variables_order with the inter-related option request_order. (Problem: Even if they agree to change it, there's a large install base on old/past releases.)
  3. Complain to php.net and ask for an API that reliably provides all environment variables. (Problem: Install-base.)
  4. Change the contract of Process to allow adding new variables. (Problem: Compatibility break?)
  5. Distribute a new helper function/class to approximate $_ENV. E.g.
namespace Symfony\Process;

class Environment
{
    /**
     * Get a list of all environment variables.
     *
     * This is loosely equivalent to $_ENV; however, $_ENV does not work
     * in some common configurations.
     *
     * @return array
     *   Example: $result['PATH'] === '/usr/local/bin:/usr/bin:/bin'
     */
    public static function get()
    {
        // Wishful thinking: return $_ENV;

        // Some systems -- such as Debian and Ubuntu -- disable $_ENV by
        // default (by setting `variables_order=GPCS`), which makes it harder
        // to write well-behaved CLI scripts which propagate the environment
        // content.

        // This is silly policy and most likely an accident of history --
        // e.g.  `variables_order` was introduced in PHP 5.0; the better
        // alternative `request_order` didn't appear until PHP 5.3.

        // Regardless, the information is still available -- getenv($key) can
        // return values for specific variables, and `$_SERVER` contains an
        // amalgamation of 'environment' and 'server' variables.  To make an
        // accurate(ish) list, we need to filter $_SERVER using getenv().

        // See also: http://php.net/manual/en/ini.core.php#ini.variables-order

        $env = array();
        foreach (array_keys($_SERVER) as $key) {
            $value = getenv($key);
            if ($value !== null && $value !== false) {
                $env[$key] = $value;
            }
        }
        return $env;
    }
}

print_r(Environment::get());

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions