* * The default request properties are: * * - **url** - The URL being requested * - **base** - The parent subdirectory of the URL * - **method** - The request method (GET, POST, PUT, DELETE) * - **referrer** - The referrer URL * - **ip** - IP address of the client * - **ajax** - Whether the request is an AJAX request * - **scheme** - The server protocol (http, https) * - **user_agent** - Browser information * - **type** - The content type * - **length** - The content length * - **query** - Query string parameters * - **data** - Post parameters * - **cookies** - Cookie parameters * - **files** - Uploaded files * - **secure** - Connection is secure * - **accept** - HTTP accept parameters * - **proxy_ip** - Proxy IP address of the client */ class Request { /** * URL being requested */ public string $url; /** * Parent subdirectory of the URL */ public string $base; /** * Request method (GET, POST, PUT, DELETE) */ public string $method; /** * Referrer URL */ public string $referrer; /** * IP address of the client */ public string $ip; /** * Whether the request is an AJAX request */ public bool $ajax; /** * Server protocol (http, https) */ public string $scheme; /** * Browser information */ public string $user_agent; /** * Content type */ public string $type; /** * Content length */ public int $length; /** * Query string parameters */ public Collection $query; /** * Post parameters */ public Collection $data; /** * Cookie parameters */ public Collection $cookies; /** * Uploaded files */ public Collection $files; /** * Whether the connection is secure */ public bool $secure; /** * HTTP accept parameters */ public string $accept; /** * Proxy IP address of the client */ public string $proxy_ip; /** * HTTP host name */ public string $host; /** * Stream path for where to pull the request body from */ private string $stream_path = 'php://input'; /** * Raw HTTP request body */ public string $body = ''; /** * Constructor. * * @param array $config Request configuration */ public function __construct(array $config = []) { // Default properties if (empty($config)) { $config = [ 'url' => str_replace('@', '%40', self::getVar('REQUEST_URI', '/')), 'base' => str_replace(['\\', ' '], ['/', '%20'], \dirname(self::getVar('SCRIPT_NAME'))), 'method' => self::getMethod(), 'referrer' => self::getVar('HTTP_REFERER'), 'ip' => self::getVar('REMOTE_ADDR'), 'ajax' => 'XMLHttpRequest' === self::getVar('HTTP_X_REQUESTED_WITH'), 'scheme' => self::getScheme(), 'user_agent' => self::getVar('HTTP_USER_AGENT'), 'type' => self::getVar('CONTENT_TYPE'), 'length' => intval(self::getVar('CONTENT_LENGTH', 0)), 'query' => new Collection($_GET), 'data' => new Collection($_POST), 'cookies' => new Collection($_COOKIE), 'files' => new Collection($_FILES), 'secure' => 'https' === self::getScheme(), 'accept' => self::getVar('HTTP_ACCEPT'), 'proxy_ip' => self::getProxyIpAddress(), 'host' => self::getVar('HTTP_HOST'), ]; } $this->init($config); } /** * Initialize request properties. * * @param array $properties Array of request properties * * @return self */ public function init(array $properties = []): self { // Set all the defined properties foreach ($properties as $name => $value) { $this->$name = $value; } // Get the requested URL without the base directory // This rewrites the url in case the public url and base directories match // (such as installing on a subdirectory in a web server) // @see testInitUrlSameAsBaseDirectory if ('/' !== $this->base && '' !== $this->base && 0 === strpos($this->url, $this->base)) { $this->url = substr($this->url, \strlen($this->base)); } // Default url if (empty($this->url)) { $this->url = '/'; } else { // Merge URL query parameters with $_GET $_GET = array_merge($_GET, self::parseQuery($this->url)); $this->query->setData($_GET); } // Check for JSON input if (0 === strpos($this->type, 'application/json')) { $body = $this->getBody(); if ('' !== $body) { $data = json_decode($body, true); if (is_array($data)) { $this->data->setData($data); } } } return $this; } /** * Gets the body of the request. * * @return string Raw HTTP request body */ public function getBody(): string { $body = $this->body; if ('' !== $body) { return $body; } $method = self::getMethod(); if ('POST' === $method || 'PUT' === $method || 'DELETE' === $method || 'PATCH' === $method) { $body = file_get_contents($this->stream_path); } $this->body = $body; return $body; } /** * Gets the request method. */ public static function getMethod(): string { $method = self::getVar('REQUEST_METHOD', 'GET'); if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) { $method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']; } elseif (isset($_REQUEST['_method'])) { $method = $_REQUEST['_method']; } return strtoupper($method); } /** * Gets the real remote IP address. * * @return string IP address */ public static function getProxyIpAddress(): string { $forwarded = [ 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', ]; $flags = \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE; foreach ($forwarded as $key) { if (\array_key_exists($key, $_SERVER)) { sscanf($_SERVER[$key], '%[^,]', $ip); if (false !== filter_var($ip, \FILTER_VALIDATE_IP, $flags)) { return $ip; } } } return ''; } /** * Gets a variable from $_SERVER using $default if not provided. * * @param string $var Variable name * @param mixed $default Default value to substitute * * @return mixed Server variable value */ public static function getVar(string $var, $default = '') { return $_SERVER[$var] ?? $default; } /** * This will pull a header from the request. * * @param string $header Header name. Can be caps, lowercase, or mixed. * @param string $default Default value if the header does not exist * * @return string */ public static function getHeader(string $header, $default = ''): string { $header = 'HTTP_' . strtoupper(str_replace('-', '_', $header)); return self::getVar($header, $default); } /** * Gets all the request headers * * @return array */ public static function getHeaders(): array { $headers = []; foreach ($_SERVER as $key => $value) { if (0 === strpos($key, 'HTTP_')) { // converts headers like HTTP_CUSTOM_HEADER to Custom-Header $key = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5))))); $headers[$key] = $value; } } return $headers; } /** * Parse query parameters from a URL. * * @param string $url URL string * * @return array> */ public static function parseQuery(string $url): array { $params = []; $args = parse_url($url); if (isset($args['query'])) { parse_str($args['query'], $params); } return $params; } /** * Gets the URL Scheme * * @return string 'http'|'https' */ public static function getScheme(): string { if ( (isset($_SERVER['HTTPS']) && 'on' === strtolower($_SERVER['HTTPS'])) || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO']) || (isset($_SERVER['HTTP_FRONT_END_HTTPS']) && 'on' === $_SERVER['HTTP_FRONT_END_HTTPS']) || (isset($_SERVER['REQUEST_SCHEME']) && 'https' === $_SERVER['REQUEST_SCHEME']) ) { return 'https'; } return 'http'; } }