1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette\Web;
13:
14: use Nette,
15: Nette\String;
16:
17:
18:
19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37:
38: class HttpRequest extends Nette\Object implements IHttpRequest
39: {
40:
41: protected $query;
42:
43:
44: protected $post;
45:
46:
47: protected $files;
48:
49:
50: protected $cookies;
51:
52:
53: protected $uri;
54:
55:
56: protected $originalUri;
57:
58:
59: protected $headers;
60:
61:
62: protected $uriFilter = array(
63: PHP_URL_PATH => array('#/{2,}#' => '/'),
64: 0 => array(),
65: );
66:
67:
68: protected $encoding;
69:
70:
71:
72:
73:
74:
75:
76: 77: 78: 79:
80: final public function getUri()
81: {
82: if ($this->uri === NULL) {
83: $this->detectUri();
84: }
85: return $this->uri;
86: }
87:
88:
89:
90: 91: 92: 93: 94:
95: public function setUri(UriScript $uri)
96: {
97: $this->uri = clone $uri;
98: $this->query = NULL;
99: $this->uri->canonicalize();
100: $this->uri->freeze();
101: return $this;
102: }
103:
104:
105:
106: 107: 108: 109:
110: final public function getOriginalUri()
111: {
112: if ($this->originalUri === NULL) {
113: $this->detectUri();
114: }
115: return $this->originalUri;
116: }
117:
118:
119:
120: 121: 122: 123: 124: 125: 126:
127: public function addUriFilter($pattern, $replacement = '', $component = NULL)
128: {
129: $pattern = '#' . $pattern . '#';
130: $component = $component === PHP_URL_PATH ? PHP_URL_PATH : 0;
131:
132: if ($replacement === NULL) {
133: unset($this->uriFilter[$component][$pattern]);
134: } else {
135: $this->uriFilter[$component][$pattern] = $replacement;
136: }
137: $this->uri = NULL;
138: }
139:
140:
141:
142: 143: 144: 145:
146: final public function getUriFilters()
147: {
148: return $this->uriFilter;
149: }
150:
151:
152:
153: 154: 155: 156:
157: protected function detectUri()
158: {
159: $uri = $this->uri = new UriScript;
160: $uri->scheme = $this->isSecured() ? 'https' : 'http';
161: $uri->user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
162: $uri->password = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
163:
164:
165: if (isset($_SERVER['HTTP_HOST'])) {
166: $pair = explode(':', $_SERVER['HTTP_HOST']);
167:
168: } elseif (isset($_SERVER['SERVER_NAME'])) {
169: $pair = explode(':', $_SERVER['SERVER_NAME']);
170:
171: } else {
172: $pair = array('');
173: }
174:
175: $uri->host = $pair[0];
176:
177: if (isset($pair[1])) {
178: $uri->port = (int) $pair[1];
179:
180: } elseif (isset($_SERVER['SERVER_PORT'])) {
181: $uri->port = (int) $_SERVER['SERVER_PORT'];
182: }
183:
184:
185: if (isset($_SERVER['REQUEST_URI'])) {
186: $requestUri = $_SERVER['REQUEST_URI'];
187:
188: } elseif (isset($_SERVER['ORIG_PATH_INFO'])) {
189: $requestUri = $_SERVER['ORIG_PATH_INFO'];
190: if (isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != '') {
191: $requestUri .= '?' . $_SERVER['QUERY_STRING'];
192: }
193: } else {
194: $requestUri = '';
195: }
196:
197: $tmp = explode('?', $requestUri, 2);
198: $this->originalUri = new Uri($uri);
199: $this->originalUri->path = $tmp[0];
200: $this->originalUri->query = isset($tmp[1]) ? $tmp[1] : '';
201: $this->originalUri->freeze();
202:
203: $requestUri = preg_replace(array_keys($this->uriFilter[0]), array_values($this->uriFilter[0]), $requestUri);
204: $tmp = explode('?', $requestUri, 2);
205: $uri->path = preg_replace(array_keys($this->uriFilter[PHP_URL_PATH]), array_values($this->uriFilter[PHP_URL_PATH]), $tmp[0]);
206: $uri->query = isset($tmp[1]) ? $tmp[1] : '';
207:
208:
209: $uri->canonicalize();
210: $uri->path = String::fixEncoding($uri->path);
211:
212:
213: $filename = isset($_SERVER['SCRIPT_FILENAME']) ? basename($_SERVER['SCRIPT_FILENAME']) : NULL;
214: $scriptPath = '';
215:
216: if (isset($_SERVER['SCRIPT_NAME']) && basename($_SERVER['SCRIPT_NAME']) === $filename) {
217: $scriptPath = rtrim($_SERVER['SCRIPT_NAME'], '/');
218:
219: } elseif (isset($_SERVER['PHP_SELF']) && basename($_SERVER['PHP_SELF']) === $filename) {
220: $scriptPath = $_SERVER['PHP_SELF'];
221:
222: } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $filename) {
223: $scriptPath = $_SERVER['ORIG_SCRIPT_NAME'];
224:
225: } elseif (isset($_SERVER['PHP_SELF'], $_SERVER['SCRIPT_FILENAME'])) {
226:
227: $path = $_SERVER['PHP_SELF'];
228: $segs = explode('/', trim($_SERVER['SCRIPT_FILENAME'], '/'));
229: $segs = array_reverse($segs);
230: $index = 0;
231: $last = count($segs);
232: do {
233: $seg = $segs[$index];
234: $scriptPath = '/' . $seg . $scriptPath;
235: $index++;
236: } while (($last > $index) && (FALSE !== ($pos = strpos($path, $scriptPath))) && (0 != $pos));
237: }
238:
239:
240: if (strncmp($uri->path, $scriptPath, strlen($scriptPath)) === 0) {
241:
242: $uri->scriptPath = $scriptPath;
243:
244: } elseif (strncmp($uri->path, $scriptPath, strrpos($scriptPath, '/') + 1) === 0) {
245:
246: $uri->scriptPath = substr($scriptPath, 0, strrpos($scriptPath, '/') + 1);
247:
248: } elseif (strpos($uri->path, basename($scriptPath)) === FALSE) {
249:
250: $uri->scriptPath = '/';
251:
252: } elseif ((strlen($uri->path) >= strlen($scriptPath))
253: && ((FALSE !== ($pos = strpos($uri->path, $scriptPath))) && ($pos !== 0))) {
254:
255:
256:
257: $uri->scriptPath = substr($uri->path, 0, $pos + strlen($scriptPath));
258:
259: } else {
260: $uri->scriptPath = $scriptPath;
261: }
262:
263: $uri->freeze();
264: }
265:
266:
267:
268:
269:
270:
271:
272: 273: 274: 275: 276: 277: 278:
279: final public function getQuery($key = NULL, $default = NULL)
280: {
281: if ($this->query === NULL) {
282: $this->initialize();
283: }
284:
285: if (func_num_args() === 0) {
286: return $this->query;
287:
288: } elseif (isset($this->query[$key])) {
289: return $this->query[$key];
290:
291: } else {
292: return $default;
293: }
294: }
295:
296:
297:
298: 299: 300: 301: 302: 303: 304:
305: final public function getPost($key = NULL, $default = NULL)
306: {
307: if ($this->post === NULL) {
308: $this->initialize();
309: }
310:
311: if (func_num_args() === 0) {
312: return $this->post;
313:
314: } elseif (isset($this->post[$key])) {
315: return $this->post[$key];
316:
317: } else {
318: return $default;
319: }
320: }
321:
322:
323:
324: 325: 326: 327:
328: public function getPostRaw()
329: {
330: return file_get_contents('php://input');
331: }
332:
333:
334:
335: 336: 337: 338: 339:
340: final public function getFile($key)
341: {
342: if ($this->files === NULL) {
343: $this->initialize();
344: }
345: $args = func_get_args();
346: return Nette\ArrayTools::get($this->files, $args);
347: }
348:
349:
350:
351: 352: 353: 354:
355: final public function getFiles()
356: {
357: if ($this->files === NULL) {
358: $this->initialize();
359: }
360:
361: return $this->files;
362: }
363:
364:
365:
366: 367: 368: 369: 370: 371:
372: final public function getCookie($key, $default = NULL)
373: {
374: if ($this->cookies === NULL) {
375: $this->initialize();
376: }
377:
378: if (func_num_args() === 0) {
379: return $this->cookies;
380:
381: } elseif (isset($this->cookies[$key])) {
382: return $this->cookies[$key];
383:
384: } else {
385: return $default;
386: }
387: }
388:
389:
390:
391: 392: 393: 394:
395: final public function getCookies()
396: {
397: if ($this->cookies === NULL) {
398: $this->initialize();
399: }
400:
401: return $this->cookies;
402: }
403:
404:
405:
406: 407: 408: 409: 410: 411:
412: public function setEncoding($encoding)
413: {
414: if (strcasecmp($encoding, $this->encoding)) {
415: $this->encoding = $encoding;
416: $this->query = $this->post = $this->cookies = $this->files = NULL;
417: }
418: return $this;
419: }
420:
421:
422:
423: 424: 425: 426:
427: public function initialize()
428: {
429: $filter = (!in_array(ini_get("filter.default"), array("", "unsafe_raw")) || ini_get("filter.default_flags"));
430:
431: parse_str($this->getUri()->query, $this->query);
432: if (!$this->query) {
433: $this->query = $filter ? filter_input_array(INPUT_GET, FILTER_UNSAFE_RAW) : (empty($_GET) ? array() : $_GET);
434: }
435: $this->post = $filter ? filter_input_array(INPUT_POST, FILTER_UNSAFE_RAW) : (empty($_POST) ? array() : $_POST);
436: $this->cookies = $filter ? filter_input_array(INPUT_COOKIE, FILTER_UNSAFE_RAW) : (empty($_COOKIE) ? array() : $_COOKIE);
437:
438: $gpc = (bool) get_magic_quotes_gpc();
439: $enc = (bool) $this->encoding;
440: $old = error_reporting(error_reporting() ^ E_NOTICE);
441: $nonChars = '#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u';
442:
443:
444:
445: if ($gpc || $enc) {
446: $utf = strcasecmp($this->encoding, 'UTF-8') === 0;
447: $list = array(& $this->query, & $this->post, & $this->cookies);
448: while (list($key, $val) = each($list)) {
449: foreach ($val as $k => $v) {
450: unset($list[$key][$k]);
451:
452: if ($gpc) {
453: $k = stripslashes($k);
454: }
455:
456: if ($enc && is_string($k) && (preg_match($nonChars, $k) || preg_last_error())) {
457:
458:
459: } elseif (is_array($v)) {
460: $list[$key][$k] = $v;
461: $list[] = & $list[$key][$k];
462:
463: } else {
464: if ($gpc && !$filter) {
465: $v = stripSlashes($v);
466: }
467: if ($enc) {
468: if ($utf) {
469: $v = String::fixEncoding($v);
470:
471: } else {
472: if (!String::checkEncoding($v)) {
473: $v = iconv($this->encoding, 'UTF-8//IGNORE', $v);
474: }
475: $v = html_entity_decode($v, ENT_QUOTES, 'UTF-8');
476: }
477: $v = preg_replace($nonChars, '', $v);
478: }
479: $list[$key][$k] = $v;
480: }
481: }
482: }
483: unset($list, $key, $val, $k, $v);
484: }
485:
486:
487:
488: $this->files = array();
489: $list = array();
490: if (!empty($_FILES)) {
491: foreach ($_FILES as $k => $v) {
492: if ($enc && is_string($k) && (preg_match($nonChars, $k) || preg_last_error())) continue;
493: $v['@'] = & $this->files[$k];
494: $list[] = $v;
495: }
496: }
497:
498: while (list(, $v) = each($list)) {
499: if (!isset($v['name'])) {
500: continue;
501:
502: } elseif (!is_array($v['name'])) {
503: if ($gpc) {
504: $v['name'] = stripSlashes($v['name']);
505: }
506: if ($enc) {
507: $v['name'] = preg_replace($nonChars, '', String::fixEncoding($v['name']));
508: }
509: $v['@'] = new HttpUploadedFile($v);
510: continue;
511: }
512:
513: foreach ($v['name'] as $k => $foo) {
514: if ($enc && is_string($k) && (preg_match($nonChars, $k) || preg_last_error())) continue;
515: $list[] = array(
516: 'name' => $v['name'][$k],
517: 'type' => $v['type'][$k],
518: 'size' => $v['size'][$k],
519: 'tmp_name' => $v['tmp_name'][$k],
520: 'error' => $v['error'][$k],
521: '@' => & $v['@'][$k],
522: );
523: }
524: }
525:
526: error_reporting($old);
527: }
528:
529:
530:
531:
532:
533:
534:
535: 536: 537: 538:
539: public function getMethod()
540: {
541: return isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : NULL;
542: }
543:
544:
545:
546: 547: 548: 549: 550:
551: public function isMethod($method)
552: {
553: return isset($_SERVER['REQUEST_METHOD']) ? strcasecmp($_SERVER['REQUEST_METHOD'], $method) === 0 : FALSE;
554: }
555:
556:
557:
558: 559: 560: 561:
562: public function isPost()
563: {
564: return $this->isMethod('POST');
565: }
566:
567:
568:
569: 570: 571: 572: 573: 574: 575:
576: final public function getHeader($header, $default = NULL)
577: {
578: $header = strtolower($header);
579: $headers = $this->getHeaders();
580: if (isset($headers[$header])) {
581: return $headers[$header];
582: } else {
583: return $default;
584: }
585: }
586:
587:
588:
589: 590: 591: 592:
593: public function getHeaders()
594: {
595: if ($this->headers === NULL) {
596:
597: if (function_exists('apache_request_headers')) {
598: $this->headers = array_change_key_case(apache_request_headers(), CASE_LOWER);
599: } else {
600: $this->headers = array();
601: foreach ($_SERVER as $k => $v) {
602: if (strncmp($k, 'HTTP_', 5) == 0) {
603: $k = substr($k, 5);
604: } elseif (strncmp($k, 'CONTENT_', 8)) {
605: continue;
606: }
607: $this->headers[ strtr(strtolower($k), '_', '-') ] = $v;
608: }
609: }
610: }
611: return $this->headers;
612: }
613:
614:
615:
616: 617: 618: 619:
620: final public function getReferer()
621: {
622: $uri = self::getHeader('referer');
623: return $uri ? new Uri($uri) : NULL;
624: }
625:
626:
627:
628: 629: 630: 631:
632: public function isSecured()
633: {
634: return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off');
635: }
636:
637:
638:
639: 640: 641: 642:
643: public function isAjax()
644: {
645: return $this->getHeader('X-Requested-With') === 'XMLHttpRequest';
646: }
647:
648:
649:
650: 651: 652: 653:
654: public function getRemoteAddress()
655: {
656: return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL;
657: }
658:
659:
660:
661: 662: 663: 664:
665: public function getRemoteHost()
666: {
667: if (!isset($_SERVER['REMOTE_HOST'])) {
668: if (!isset($_SERVER['REMOTE_ADDR'])) {
669: return NULL;
670: }
671: $_SERVER['REMOTE_HOST'] = getHostByAddr($_SERVER['REMOTE_ADDR']);
672: }
673:
674: return $_SERVER['REMOTE_HOST'];
675: }
676:
677:
678:
679: 680: 681: 682: 683:
684: public function detectLanguage(array $langs)
685: {
686: $header = $this->getHeader('accept-language');
687: if (!$header) return NULL;
688:
689: $s = strtolower($header);
690: $s = strtr($s, '_', '-');
691: rsort($langs);
692: preg_match_all('#(' . implode('|', $langs) . ')(?:-[^\s,;=]+)?\s*(?:;\s*q=([0-9.]+))?#', $s, $matches);
693:
694: if (!$matches[0]) {
695: return NULL;
696: }
697:
698: $max = 0;
699: $lang = NULL;
700: foreach ($matches[1] as $key => $value) {
701: $q = $matches[2][$key] === '' ? 1.0 : (float) $matches[2][$key];
702: if ($q > $max) {
703: $max = $q; $lang = $value;
704: }
705: }
706:
707: return $lang;
708: }
709:
710: }
711: