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