<commit_before><?php
/**
 * @author <NAME> <<EMAIL>>
 * @copyright 2009-2014 Vanilla Forums Inc.
 * @license MIT
 */

namespace Garden;

use JsonSerializable;

/**
 * A class that contains the information in an http request.
 */
class Request implements JsonSerializable {

    /// Constants ///
    const METHOD_HEAD = 'HEAD';
    const METHOD_GET = 'GET';
    const METHOD_POST = 'POST';
    const METHOD_PUT = 'PUT';
    const METHOD_PATCH = 'PATCH';
    const METHOD_DELETE = 'DELETE';
    const METHOD_OPTIONS = 'OPTIONS';

    /// Properties ///

    /**
     *
     * @var array The data in this request.
     */
    protected $env;

    /**
     * @var Request The currently dispatched request.
     */
    protected static $current;

    /**
     * @var array The default environment for constructed requests.
     */
    protected static $defaultEnv;

    /**
     * @var array The global environment for the request.
     */
    protected static $globalEnv;

    /**
     * Special-case HTTP headers that are otherwise unidentifiable as HTTP headers.
     * Typically, HTTP headers in the $_SERVER array will be prefixed with
     * `HTTP_` or `X_`. These are not so we list them here for later reference.
     *
     * @var array
     */
    protected static $specialHeaders = array(
        'CONTENT_TYPE',
        'CONTENT_LENGTH',
        'PHP_AUTH_USER',
        'PHP_AUTH_PW',
        'PHP_AUTH_DIGEST',
        'AUTH_TYPE'
    );

    /// Methods ///

    /**
     * Initialize a new instance of the {@link Request} class.
     *
     * @param string $url The url of the request or blank to use the current environment.
     * @param string $method The request method.
     * @param mixed $data The request data. This is the query string for GET requests or the body for other requests.
     */
    public function __construct($url = '', $method = '', $data = null) {
        if ($url) {
            $this->env = (array)static::defaultEnvironment();
            // Instantiate the request from the url.
            $this->setUrl($url);
            if ($method) {
                $this->setMethod($method);
            }
            if (is_array($data)) {
                $this->setData($data);
            }
        } else {
            // Instantiate the request from the global environment.
            $this->env = static::globalEnvironment();
            if ($method) {
                $this->setMethod($method);
            }
            if (is_array($data)) {
                $this->setData($data);
            }
        }

        static::overrideEnvironment($this->env);
    }

    /**
     * Convert a request to a string.
     *
     * @return string Returns the url of the request.
     */
    public function __toString() {
        return $this->getUrl();
    }

    /**
     * Gets or sets the current request.
     *
     * @param Request $request Pass a request object to set the current request.
     * @return Request Returns the current request if {@link Request} is null or the previous request otherwise.
     */
    public static function current(Request $request = null) {
        if ($request !== null) {
            $bak = self::$current;
            self::$current = $request;
            return $bak;
        }
        return self::$current;
    }

    /**
     * Gets or updates the default environment.
     *
     * @param string|array|null $key Specifies a specific key in the environment array.
     * If you pass an array for this parameter then you can set the default environment.
     * @param bool $merge Whether or not to merge the new value.
     * @return array|mixed Returns the value at {@link $key} or the entire environment array.
     * @throws \InvalidArgumentException Throws an exception when {@link $key} is not valid.
     */
    public static function defaultEnvironment($key = null, $merge = false) {
        if (self::$defaultEnv === null) {
            self::$defaultEnv = array(
                'REQUEST_METHOD' => 'GET',
                'X_REWRITE' => true,
                'SCRIPT_NAME' => '',
                'PATH_INFO' => '/',
                'EXT' => '',
                'QUERY' => [],
                'SERVER_NAME' => 'localhost',
                'SERVER_PORT' => 80,
                'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8',
                'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
                'HTTP_USER_AGENT' => 'Garden/0.1 (Howdy stranger)',
                'REMOTE_ADDR' => '127.0.0.1',
                'URL_SCHEME' => 'http',
                'INPUT' => [],
            );
        }

        if ($key === null) {
            return self::$defaultEnv;
        } elseif (is_array($key)) {
            if ($merge) {
                self::$defaultEnv = array_merge(self::$defaultEnv, $key);
            } else {
                self::$defaultEnv = $key;
            }
            return self::$defaultEnv;
        } elseif (is_string($key)) {
            return val($key, self::$defaultEnv);
        } else {
            throw new \InvalidArgumentException("Argument #1 for Request::globalEnvironment() is invalid.", 422);
        }
    }

    /**
     * Parse request information from the current environment.
     *
     * The environment contains keys based on the Rack protocol (see http://rack.rubyforge.org/doc/SPEC.html).
     *
     * @param mixed $key The environment variable to look at.
     * - null: Return the entire environment.
     * - true: Force a re-parse of the environment and return the entire environment.
     * - string: One of the environment variables.
     * @return array|string Returns the global environment or the value at {@link $key}.
     */
    public static function globalEnvironment($key = null) {
        // Check to parse the environment.
        if ($key === true || !isset(self::$globalEnv)) {
            self::$globalEnv = static::parseServerVariables();
        }

        if ($key) {
            return val($key, self::$globalEnv);
        }
        return self::$globalEnv;
    }

    /**
     * Parse the various server variables to build the global environment.
     *
     * @return array Returns an array suitable to be used as the {@see Request::$globalEnv}.
     * @see Request::globalEnvironment().
     */
    private static function parseServerVariables() {
        $env = static::defaultEnvironment();

        // REQUEST_METHOD.
        $env['REQUEST_METHOD'] = strtoupper(isset($_SERVER['REQUEST_METHOD']) ? val('REQUEST_METHOD', $_SERVER) : 'CONSOLE');

        // SCRIPT_NAME: This is the root directory of the application.
        $script_name = $_SERVER['SCRIPT_NAME'];
        if ($script_name && substr($script_name, -strlen('index.php')) == 0) {
            $script_name = substr($script_name, 0, -strlen('index.php'));
        } else {
            $script_name = '';
        }
        $env['SCRIPT_NAME'] = rtrim($script_name, '/');

        // PATH_INFO.
        $path = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '';

        // Strip the extension from the path.
        list($path, $ext) = static::splitPathExt($path);
        $env['PATH_INFO'] = '/' . ltrim($path, '/');
        $env['EXT'] = $ext;

        // QUERY.
        $get = $_GET;
        $env['QUERY'] = $get;

        // SERVER_NAME.
        $env['SERVER_NAME'] = array_select(
            ['HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME'],
            $_SERVER<commit_msg>Change the visibility of Request::parseServerVariables().<commit_after><?php
/**
 * @author <NAME> <<EMAIL>>
 * @copyright 2009-2014 Vanilla Forums Inc.
 * @license MIT
 */

namespace Garden;

use JsonSerializable;

/**
 * A class that contains the information in an http request.
 */
class Request implements JsonSerializable {

    /// Constants ///
    const METHOD_HEAD = 'HEAD';
    const METHOD_GET = 'GET';
    const METHOD_POST = 'POST';
    const METHOD_PUT = 'PUT';
    const METHOD_PATCH = 'PATCH';
    const METHOD_DELETE = 'DELETE';
    const METHOD_OPTIONS = 'OPTIONS';

    /// Properties ///

    /**
     *
     * @var array The data in this request.
     */
    protected $env;

    /**
     * @var Request The currently dispatched request.
     */
    protected static $current;

    /**
     * @var array The default environment for constructed requests.
     */
    protected static $defaultEnv;

    /**
     * @var array The global environment for the request.
     */
    protected static $globalEnv;

    /**
     * Special-case HTTP headers that are otherwise unidentifiable as HTTP headers.
     * Typically, HTTP headers in the $_SERVER array will be prefixed with
     * `HTTP_` or `X_`. These are not so we list them here for later reference.
     *
     * @var array
     */
    protected static $specialHeaders = array(
        'CONTENT_TYPE',
        'CONTENT_LENGTH',
        'PHP_AUTH_USER',
        'PHP_AUTH_PW',
        'PHP_AUTH_DIGEST',
        'AUTH_TYPE'
    );

    /// Methods ///

    /**
     * Initialize a new instance of the {@link Request} class.
     *
     * @param string $url The url of the request or blank to use the current environment.
     * @param string $method The request method.
     * @param mixed $data The request data. This is the query string for GET requests or the body for other requests.
     */
    public function __construct($url = '', $method = '', $data = null) {
        if ($url) {
            $this->env = (array)static::defaultEnvironment();
            // Instantiate the request from the url.
            $this->setUrl($url);
            if ($method) {
                $this->setMethod($method);
            }
            if (is_array($data)) {
                $this->setData($data);
            }
        } else {
            // Instantiate the request from the global environment.
            $this->env = static::globalEnvironment();
            if ($method) {
                $this->setMethod($method);
            }
            if (is_array($data)) {
                $this->setData($data);
            }
        }

        static::overrideEnvironment($this->env);
    }

    /**
     * Convert a request to a string.
     *
     * @return string Returns the url of the request.
     */
    public function __toString() {
        return $this->getUrl();
    }

    /**
     * Gets or sets the current request.
     *
     * @param Request $request Pass a request object to set the current request.
     * @return Request Returns the current request if {@link Request} is null or the previous request otherwise.
     */
    public static function current(Request $request = null) {
        if ($request !== null) {
            $bak = self::$current;
            self::$current = $request;
            return $bak;
        }
        return self::$current;
    }

    /**
     * Gets or updates the default environment.
     *
     * @param string|array|null $key Specifies a specific key in the environment array.
     * If you pass an array for this parameter then you can set the default environment.
     * @param bool $merge Whether or not to merge the new value.
     * @return array|mixed Returns the value at {@link $key} or the entire environment array.
     * @throws \InvalidArgumentException Throws an exception when {@link $key} is not valid.
     */
    public static function defaultEnvironment($key = null, $merge = false) {
        if (self::$defaultEnv === null) {
            self::$defaultEnv = array(
                'REQUEST_METHOD' => 'GET',
                'X_REWRITE' => true,
                'SCRIPT_NAME' => '',
                'PATH_INFO' => '/',
                'EXT' => '',
                'QUERY' => [],
                'SERVER_NAME' => 'localhost',
                'SERVER_PORT' => 80,
                'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8',
                'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
                'HTTP_USER_AGENT' => 'Garden/0.1 (Howdy stranger)',
                'REMOTE_ADDR' => '127.0.0.1',
                'URL_SCHEME' => 'http',
                'INPUT' => [],
            );
        }

        if ($key === null) {
            return self::$defaultEnv;
        } elseif (is_array($key)) {
            if ($merge) {
                self::$defaultEnv = array_merge(self::$defaultEnv, $key);
            } else {
                self::$defaultEnv = $key;
            }
            return self::$defaultEnv;
        } elseif (is_string($key)) {
            return val($key, self::$defaultEnv);
        } else {
            throw new \InvalidArgumentException("Argument #1 for Request::globalEnvironment() is invalid.", 422);
        }
    }

    /**
     * Parse request information from the current environment.
     *
     * The environment contains keys based on the Rack protocol (see http://rack.rubyforge.org/doc/SPEC.html).
     *
     * @param mixed $key The environment variable to look at.
     * - null: Return the entire environment.
     * - true: Force a re-parse of the environment and return the entire environment.
     * - string: One of the environment variables.
     * @return array|string Returns the global environment or the value at {@link $key}.
     */
    public static function globalEnvironment($key = null) {
        // Check to parse the environment.
        if ($key === true || !isset(self::$globalEnv)) {
            self::$globalEnv = static::parseServerVariables();
        }

        if ($key) {
            return val($key, self::$globalEnv);
        }
        return self::$globalEnv;
    }

    /**
     * Parse the various server variables to build the global environment.
     *
     * @return array Returns an array suitable to be used as the {@see Request::$globalEnv}.
     * @see Request::globalEnvironment().
     */
    protected static function parseServerVariables() {
        $env = static::defaultEnvironment();

        // REQUEST_METHOD.
        $env['REQUEST_METHOD'] = strtoupper(isset($_SERVER['REQUEST_METHOD']) ? val('REQUEST_METHOD', $_SERVER) : 'CONSOLE');

        // SCRIPT_NAME: This is the root directory of the application.
        $script_name = $_SERVER['SCRIPT_NAME'];
        if ($script_name && substr($script_name, -strlen('index.php')) == 0) {
            $script_name = substr($script_name, 0, -strlen('index.php'));
        } else {
            $script_name = '';
        }
        $env['SCRIPT_NAME'] = rtrim($script_name, '/');

        // PATH_INFO.
        $path = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '';

        // Strip the extension from the path.
        list($path, $ext) = static::splitPathExt($path);
        $env['PATH_INFO'] = '/' . ltrim($path, '/');
        $env['EXT'] = $ext;

        // QUERY.
        $get = $_GET;
        $env['QUERY'] = $get;

        // SERVER_NAME.
        $env['SERVER_NAME'] = array_select(
            ['HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME'],
            $_SERVER
{'fraction_non_alphanumeric': 0.13049523305084745, 'fraction_numerical': 0.005296610169491525, 'mean_word_length': 1.9958349861166205, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5852082', 'n_tokens_mistral': 4284, 'n_tokens_neox': 4119, 'n_words': 1229}