verb = \strtolower($_SERVER['REQUEST_METHOD']); // Parse put and delete requests into input variables // @codeCoverageIgnoreStart if (isset($this->{$this->verb})) { $raw = \file_get_contents('php://input'); \parse_str($raw, $this->{$this->verb}); } // Set mapping for superglobals, since // variable variables don't seem to work // with superglobals :/ $this->var_map = [ 'get' => $_GET, 'post' => $_POST, 'server' => $_SERVER, 'env' => $_ENV, 'cookie' => $_COOKIE ]; // @codeCoverageIgnoreEnd // Parse request headers from $_SERVER foreach($_SERVER as $key => $val) { if (strpos($key, 'HTTP_') === 0) { $new_key = \strtolower(\strtr($key, [ 'HTTP_' => '', '_' => '-' ])); $this->request_headers[$new_key] = $val; } } } /** * Wrapper method for input arrays * * Actually works as get,post,put,delete,cookie,server,and env functions * all wrapped up in one - because boilerplate is bad! * * @param string $name - name of input array * @param array $args - function arguments * @return mixed * @throws \DomainException */ public function __call($name, $args=[]) { // Predefine arguments for input array getters if ( ! isset($args[0])) $args[0] = NULL; if ( ! isset($args[1])) $args[1] = FILTER_SANITIZE_STRING; $index = $args[0]; $filter = $args[1]; if (isset($this->var_map[$name]) || isset($this->$name)) { // Get an input variable value return $this->get_var($name, $index, $filter); } // What kind of request are you trying to make?! throw new \DomainException('Invalid input array.'); } /** * Return header(s) sent from the request * * @param string $index * @return mixed */ public function header($index = NULL) { if ($index !== NULL) { $index = (\strtolower(\str_replace([' ', '_'], '-', $index))); if (isset($this->request_headers[$index])) { return $this->request_headers[$index]; } return NULL; } return $this->request_headers; } /** * Return parsed header(s) sent from the request * * @param string $index * @return mixed */ public function header_array($index = NULL) { if (empty($this->parsed_headers)) { $this->parsed_headers = $this->parse_headers(); } if ($index !== NULL) { $index = (str_replace([' ', '-'], '_', $index)); if (isset($this->parsed_headers[$index])) { return $this->parsed_headers[$index]; } return NULL; } return $this->parsed_headers; } /** * Convert headers to a parsed array of values * * @return array */ protected function parse_headers() { foreach($this->request_headers as $header => $value) { $has_semi = strpos($value, ';') !== FALSE; $has_comma = strpos($value, ',') !== FALSE; $has_eq = strpos($value, '=') !== FALSE; // Parse the user agent separately if ($header === 'user-agent') { $this->parsed_headers[$header] = $this->parse_user_agent($value); continue; } // Parse accept-type headers separately as well else if (strpos($header, 'accept') === 0) { $this->parsed_headers[$header] = $this->parse_accept_header($value); } // If the header has a comma, and not a semicolon, split on the comma else if ( ! $has_semi && $has_comma) { $this->parsed_headers[$header] = explode(",", $value); continue; } // Parse cookies and other headers with values like query strings else if ($has_eq && ! $has_semi) { parse_str($value, $this->parsed_headers[$header]); continue; } // Anything else, just leave it as a string else { $this->parsed_headers[$header] = $value; continue; } } return $this->parsed_headers; } /** * Parse a browser useragent into a set of useful key-value pairs * * @param string $ua_string * @return array */ protected function parse_user_agent($ua_string) { $user_agent = []; $slash_matches = []; $slash_pattern = "`[A-Z]+/[0-9]+((\.[0-9]+)+)?`i"; $paren_matches = []; $paren_pattern = "`\(.*?\)`i"; // Get all the foo/12.3 paterns from the user agent string preg_match_all($slash_pattern, $ua_string, $slash_matches); foreach($slash_matches[0] as $arr) { list($key, $version) = explode("/", $arr); $user_agent['versions'][$key] = $version; } // Get all the info from parenthasized items preg_match_all($paren_pattern, $ua_string, $paren_matches); foreach($paren_matches[0] as $arr) { $arr = str_replace(['(',')'], '', $arr); if (strpos($arr, ';') !== FALSE) { $user_agent['os'] = explode('; ', $arr); } else { $user_agent['misc'] = $arr; } } return $user_agent; } /** * Parse an accept-type header into an ordered list * of values * * @param string $value * @return array */ protected function parse_accept_header($value) { $q_types = []; // A fake value so I can shift it off to have a 1-indexed array $high_types = []; $count = 1; // Split into segments of different values $groups = explode(',', $value); foreach($groups as $group) { $group = \trim($group); $pair = explode(';q=', $group); if (count($pair) === 2) { list($val, $q) = $pair; $q_types[$q] = $val; } else { $high_types[$count] = current($pair); $count++; } } // Add an additional fake value so we can // have a 1-indexed array $high_types[$count] = 'foo'; $high_types = array_reverse($high_types); unset($high_types[0]); $output = $q_types; // Merge the arrays manually to maintain // keys, and thus ordering foreach($high_types as $k => $v) { $output[$k] = $v; } krsort($output, SORT_NUMERIC); return $output; } /** * Get superglobal or generated input array value * @param string $type - HTTP verb * @param string $index - variable in the input array * @param int $filter - PHP filter_var flag * @return mixed */ protected function get_var($type, $index=NULL, $filter=\FILTER_SANITIZE_STRING) { // Determine if superglobal or generated $var = array_key_exists($type, $this->var_map) ? $this->var_map[$type] : $this->$type; // Return the whole array if the index is null if ($index === NULL) { return ($filter !== NULL) ? \filter_var_array($var, $filter) : $var; } // Prevent errors for non-existant variables if ( ! isset($var[$index])) { return NULL; } return ($filter !== NULL) ? \filter_var($var[$index], $filter) : $var[$index]; } } // End of core/Input.php