1<?php 2 3/** 4 * Request handling 5 * @package framework 6 * @subpackage request 7 */ 8 9/** 10 * Data request details 11 * 12 * This is an interface to HTTP request details. All request data 13 * must be white-listed and sanitized by module set filters. 14 */ 15class Hm_Request { 16 17 /* sanitized $_POST variables */ 18 public $post = array(); 19 20 /* sanitized $_GET variables */ 21 public $get = array(); 22 23 /* sanitized $_COOKIE variables */ 24 public $cookie = array(); 25 26 /* sanitized $_SERVER variables */ 27 public $server = array(); 28 29 /* $_ENV variables (fallback for missing $_SERVER vals) */ 30 private $env = array(); 31 32 /* request type. either AJAX or HTTP */ 33 public $type = ''; 34 35 /* PHP sapi method used for the request */ 36 public $sapi = ''; 37 38 /* Output format, either Hm_Format_JSON or Hm_Format_HTML5 */ 39 public $format = ''; 40 41 /* bool indicating if the request was over SSL/TLS */ 42 public $tls = false; 43 44 /* bool indicating if this looks like a mobile OS request */ 45 public $mobile = false; 46 47 /* URL path */ 48 public $path = ''; 49 50 /* allowed AJAX output field names defined by module sets */ 51 public $allowed_output = array(); 52 53 /* bool indicating unknown input data */ 54 public $invalid_input_detected = false; 55 56 /* invalid input fields */ 57 public $invalid_input_fields = array(); 58 59 /* uploaded file details */ 60 public $files = array(); 61 62 /* module filters */ 63 public $filters = array(); 64 65 /* HTTP request method */ 66 public $method = false; 67 68 /* force mobile ui */ 69 private $always_mobile = false; 70 71 /** 72 * Process request details 73 * @param array $filters list of input filters from module sets 74 * @param object $config site config object 75 */ 76 public function __construct($filters, $config) { 77 if ($config->get('always_mobile_ui', false)) { 78 $this->always_mobile = true; 79 } 80 $this->filters = $filters; 81 $this->filter_request_input(); 82 $this->get_other_request_details(); 83 $this->files = $_FILES; 84 if (!$config->get('disable_empty_superglobals', false)) { 85 $this->empty_super_globals(); 86 } 87 Hm_Debug::add('Using sapi: '.$this->sapi); 88 Hm_Debug::add('Request type: '.$this->type); 89 Hm_Debug::add('Request path: '.$this->path); 90 Hm_Debug::add('TLS request: '.intval($this->tls)); 91 Hm_Debug::add('Mobile request: '.intval($this->mobile)); 92 } 93 94 /** 95 * Sanitize and filter user and server input 96 * @return void 97 */ 98 private function filter_request_input() { 99 if (array_key_exists('allowed_server', $this->filters)) { 100 $this->server = $this->filter_input(INPUT_SERVER, $this->filters['allowed_server']); 101 $this->env = $this->filter_input(INPUT_ENV, $this->filters['allowed_server']); 102 } 103 if (array_key_exists('allowed_post', $this->filters)) { 104 $this->post = $this->filter_input(INPUT_POST, $this->filters['allowed_post']); 105 } 106 if (array_key_exists('allowed_get', $this->filters)) { 107 $this->get = $this->filter_input(INPUT_GET, $this->filters['allowed_get']); 108 } 109 if (array_key_exists('allowed_cookie', $this->filters)) { 110 $this->cookie = $this->filter_input(INPUT_COOKIE, $this->filters['allowed_cookie']); 111 } 112 } 113 114 /** 115 * Collect other useful details about a request 116 * @return void 117 */ 118 private function get_other_request_details() { 119 $this->sapi = php_sapi_name(); 120 if (array_key_exists('allowed_output', $this->filters)) { 121 $this->allowed_output = $this->filters['allowed_output']; 122 } 123 if (array_key_exists('REQUEST_URI', $this->server)) { 124 $this->path = $this->get_clean_url_path($this->server['REQUEST_URI']); 125 } 126 if (array_key_exists('REQUEST_METHOD', $this->server)) { 127 $this->method = $this->server['REQUEST_METHOD']; 128 } 129 elseif (array_key_exists('REQUEST_METHOD', $this->env)) { 130 $this->method = $this->env['REQUEST_METHOD']; 131 $this->server = $this->env; 132 } 133 $this->get_request_type(); 134 $this->is_tls(); 135 $this->is_mobile(); 136 } 137 138 /** 139 * Empty out super globals. 140 * @return void 141 */ 142 private function empty_super_globals() { 143 $_POST = array(); 144 $_SERVER = array(); 145 $_GET = array(); 146 $_COOKIE = array(); 147 $_FILES = array(); 148 $_REQUEST = array(); 149 $_ENV = array(); 150 $GLOBALS = array(); 151 } 152 153 /** 154 * Filter specified input against module defined filters 155 * @param type string the type of input (POST, GET, COOKIE, etc) 156 * @param filters array list of input filters from module sets 157 * @return array filtered input data 158 */ 159 public function filter_input($type, $filters) { 160 $data = Hm_Functions::filter_input_array($type, $filters); 161 if ($data === false || $data === NULL) { 162 return array(); 163 } 164 return $data; 165 } 166 167 /** 168 * Look at the HTTP_USER_AGENT value and set a mobile OS flag 169 * @return void 170 */ 171 private function is_mobile() { 172 if ($this->always_mobile) { 173 $this->mobile = true; 174 return; 175 } 176 if (array_key_exists('HTTP_USER_AGENT', $this->server)) { 177 if (preg_match("/(iphone|ipod|ipad|android|blackberry|webos)/i", $this->server['HTTP_USER_AGENT'])) { 178 $this->mobile = true; 179 } 180 } 181 } 182 183 /** 184 * Determine if a request was done over TLS 185 * @return void 186 */ 187 private function is_tls() { 188 if (array_key_exists('HTTPS', $this->server) && strtolower($this->server['HTTPS']) == 'on') { 189 $this->tls = true; 190 } 191 elseif (array_key_exists('REQUEST_SCHEME', $this->server) && strtolower($this->server['REQUEST_SCHEME']) == 'https') { 192 $this->tls = true; 193 } 194 } 195 196 /** 197 * Determine the request type, either AJAX or HTTP 198 * @return void 199 */ 200 private function get_request_type() { 201 if ($this->is_ajax()) { 202 $this->type = 'AJAX'; 203 $this->format = 'Hm_Format_JSON'; 204 } 205 else { 206 $this->type = 'HTTP'; 207 $this->format = 'Hm_Format_HTML5'; 208 } 209 } 210 211 /** 212 * Determine if a request is an AJAX call 213 * @return bool true if the request is from an AJAX call 214 */ 215 public function is_ajax() { 216 return array_key_exists('HTTP_X_REQUESTED_WITH', $this->server) && strtolower($this->server['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'; 217 } 218 219 /** 220 * Make sure a url path is sane 221 * @param string $uri path to check 222 * @return string clean url path 223 */ 224 private function get_clean_url_path($uri) { 225 if (strpos($uri, '?') !== false) { 226 $parts = explode('?', $uri, 2); 227 $path = $parts[0]; 228 } 229 else { 230 $path = $uri; 231 } 232 $path = str_replace('index.php', '', $path); 233 if (substr($path, -1) != '/') { 234 $path .= '/'; 235 } 236 return $path; 237 } 238} 239