Packages

  • Nette
    • Application
    • Caching
    • Collections
    • Config
    • Forms
    • IO
    • Loaders
    • Mail
    • Reflection
    • Security
    • Templates
    • Web
  • None
  • PHP

Classes

  • NFtp
  • NHtml
  • NHttpContext
  • NHttpRequest
  • NHttpResponse
  • NHttpUploadedFile
  • NSession
  • NSessionNamespace
  • NUri
  • NUriScript
  • NUser

Interfaces

  • IHttpRequest
  • IHttpResponse
  • IUser

Exceptions

  • NFtpException
  • Overview
  • Package
  • Class
  • Tree
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  * @package Nette\Web
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * HttpRequest provides access scheme for request sent via HTTP.
 17:  *
 18:  * @author     David Grudl
 19:  *
 20:  * @property   NUriScript $uri
 21:  * @property-read NUri $originalUri
 22:  * @property-read array $query
 23:  * @property-read array $post
 24:  * @property-read string $postRaw
 25:  * @property-read array $files
 26:  * @property-read array $cookies
 27:  * @property-read string $method
 28:  * @property-read array $headers
 29:  * @property-read NUri $referer
 30:  * @property-read string $remoteAddress
 31:  * @property-read string $remoteHost
 32:  * @property-read bool $secured
 33:  * @package Nette\Web
 34:  */
 35: class NHttpRequest extends NObject implements IHttpRequest
 36: {
 37:     /** @var array */
 38:     protected $query;
 39: 
 40:     /** @var array */
 41:     protected $post;
 42: 
 43:     /** @var array */
 44:     protected $files;
 45: 
 46:     /** @var array */
 47:     protected $cookies;
 48: 
 49:     /** @var NUriScript {@link NHttpRequest::getUri()} */
 50:     protected $uri;
 51: 
 52:     /** @var NUri  {@link NHttpRequest::getOriginalUri()} */
 53:     protected $originalUri;
 54: 
 55:     /** @var array  {@link NHttpRequest::getHeaders()} */
 56:     protected $headers;
 57: 
 58:     /** @var array */
 59:     protected $uriFilter = array(
 60:         PHP_URL_PATH => array('#/{2,}#' => '/'), // '%20' => ''
 61:         0 => array(), // '#[.,)]$#' => ''
 62:     );
 63: 
 64:     /** @var string */
 65:     protected $encoding;
 66: 
 67: 
 68: 
 69:     /********************* URI ****************d*g**/
 70: 
 71: 
 72: 
 73:     /**
 74:      * Returns URL object.
 75:      * @return NUriScript
 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:      * Sets URL object.
 89:      * @param  NUriScript
 90:      * @return NHttpRequest  provides a fluent interface
 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:      * Returns URL object.
105:      * @return NUri
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:      * Sets request URI filter.
119:      * @param  string  pattern to search for
120:      * @param  string  string to replace
121:      * @param  int     PHP_URL_PATH or NULL
122:      * @return void
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:      * Returns request URI filter.
141:      * @return array
142:      */
143:     final public function getUriFilters()
144:     {
145:         return $this->uriFilter;
146:     }
147: 
148: 
149: 
150:     /**
151:      * Detects uri, base path and script path of the request.
152:      * @return void
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:         // host & port
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:         // path & query
182:         if (isset($_SERVER['REQUEST_URI'])) { // Apache, IIS 6.0
183:             $requestUri = $_SERVER['REQUEST_URI'];
184: 
185:         } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0 (PHP as CGI ?)
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:         // normalized uri
206:         $uri->canonicalize();
207:         $uri->path = NString::fixEncoding($uri->path);
208: 
209:         // detect base URI-path - inspired by Zend Framework (c) Zend Technologies USA Inc. (http://www.zend.com), new BSD license
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']; // 1and1 shared hosting compatibility
221: 
222:         } elseif (isset($_SERVER['PHP_SELF'], $_SERVER['SCRIPT_FILENAME'])) {
223:             // Backtrack up the script_filename to find the portion matching php_self
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:         // Does the scriptPath have anything in common with the request_uri?
237:         if (strncmp($uri->path, $scriptPath, strlen($scriptPath)) === 0) {
238:             // whole $scriptPath in URL
239:             $uri->scriptPath = $scriptPath;
240: 
241:         } elseif (strncmp($uri->path, $scriptPath, strrpos($scriptPath, '/') + 1) === 0) {
242:             // directory portion of $scriptPath in URL
243:             $uri->scriptPath = substr($scriptPath, 0, strrpos($scriptPath, '/') + 1);
244: 
245:         } elseif (strpos($uri->path, basename($scriptPath)) === FALSE) {
246:             // no match whatsoever; set it blank
247:             $uri->scriptPath = '/';
248: 
249:         } elseif ((strlen($uri->path) >= strlen($scriptPath))
250:             && ((FALSE !== ($pos = strpos($uri->path, $scriptPath))) && ($pos !== 0))) {
251:             // If using mod_rewrite or ISAPI_Rewrite strip the script filename
252:             // out of scriptPath. $pos !== 0 makes sure it is not matching a value
253:             // from PATH_INFO or QUERY_STRING
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:     /********************* query, post, files & cookies ****************d*g**/
266: 
267: 
268: 
269:     /**
270:      * Returns variable provided to the script via URL query ($_GET).
271:      * If no key is passed, returns the entire array.
272:      * @param  string key
273:      * @param  mixed  default value
274:      * @return mixed
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:      * Returns variable provided to the script via POST method ($_POST).
297:      * If no key is passed, returns the entire array.
298:      * @param  string key
299:      * @param  mixed  default value
300:      * @return mixed
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:      * Returns HTTP POST data in raw format (only for "application/x-www-form-urlencoded").
323:      * @return string
324:      */
325:     public function getPostRaw()
326:     {
327:         return file_get_contents('php://input');
328:     }
329: 
330: 
331: 
332:     /**
333:      * Returns uploaded file.
334:      * @param  string key (or more keys)
335:      * @return NHttpUploadedFile
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:      * Returns uploaded files.
350:      * @return array
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:      * Returns variable provided to the script via HTTP cookies.
365:      * @param  string key
366:      * @param  mixed  default value
367:      * @return mixed
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:      * Returns variables provided to the script via HTTP cookies.
390:      * @return array
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:      * Recursively converts and checks encoding.
405:      * @param  array
406:      * @param  string
407:      * @return NHttpRequest  provides a fluent interface
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; // reinitialization required
414:         }
415:         return $this;
416:     }
417: 
418: 
419: 
420:     /**
421:      * Initializes $this->query, $this->files, $this->cookies and $this->files arrays
422:      * @return void
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:         // remove fucking quotes and check (and optionally convert) encoding
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:                         // invalid key -> ignore
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:         // structure $files and create HttpUploadedFile objects
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:     /********************* method & headers ****************d*g**/
529: 
530: 
531: 
532:     /**
533:      * Returns HTTP request method (GET, POST, HEAD, PUT, ...). The method is case-sensitive.
534:      * @return string
535:      */
536:     public function getMethod()
537:     {
538:         return isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : NULL;
539:     }
540: 
541: 
542: 
543:     /**
544:      * Checks if the request method is the given one.
545:      * @param  string
546:      * @return bool
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:      * Checks if the request method is POST.
557:      * @return bool
558:      */
559:     public function isPost()
560:     {
561:         return $this->isMethod('POST');
562:     }
563: 
564: 
565: 
566:     /**
567:      * Return the value of the HTTP header. Pass the header name as the
568:      * plain, HTTP-specified header name (e.g. 'Accept-Encoding').
569:      * @param  string
570:      * @param  mixed
571:      * @return mixed
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:      * Returns all HTTP headers.
588:      * @return array
589:      */
590:     public function getHeaders()
591:     {
592:         if ($this->headers === NULL) {
593:             // lazy initialization
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:      * Returns referrer.
615:      * @return NUri|NULL
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:      * Is the request is sent via secure channel (https).
627:      * @return bool
628:      */
629:     public function isSecured()
630:     {
631:         return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off');
632:     }
633: 
634: 
635: 
636:     /**
637:      * Is AJAX request?
638:      * @return bool
639:      */
640:     public function isAjax()
641:     {
642:         return $this->getHeader('X-Requested-With') === 'XMLHttpRequest';
643:     }
644: 
645: 
646: 
647:     /**
648:      * Returns the IP address of the remote client.
649:      * @return string
650:      */
651:     public function getRemoteAddress()
652:     {
653:         return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL;
654:     }
655: 
656: 
657: 
658:     /**
659:      * Returns the host of the remote client.
660:      * @return string
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:      * Parse Accept-Language header and returns prefered language.
678:      * @param  array   Supported languages
679:      * @return string
680:      */
681:     public function detectLanguage(array $langs)
682:     {
683:         $header = $this->getHeader('accept-language');
684:         if (!$header) return NULL;
685: 
686:         $s = strtolower($header);  // case insensitive
687:         $s = strtr($s, '_', '-');  // cs_CZ means cs-CZ
688:         rsort($langs);             // first more specific
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: 
Nette Framework 0.9.7 (for PHP 5.2) API documentation generated by ApiGen 2.3.0