1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Http;
9:
10: use Nette;
11: use Nette\Utils\Strings;
12:
13:
14: 15: 16:
17: class RequestFactory extends Nette\Object
18: {
19:
20: const CHARS = '\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}';
21:
22:
23: public $urlFilters = array(
24: 'path' => array('#/{2,}#' => '/'),
25: 'url' => array(),
26: );
27:
28:
29: private $binary = FALSE;
30:
31:
32: private $proxies = array();
33:
34:
35: 36: 37: 38:
39: public function setBinary($binary = TRUE)
40: {
41: $this->binary = (bool) $binary;
42: return $this;
43: }
44:
45:
46: 47: 48: 49:
50: public function setProxy($proxy)
51: {
52: $this->proxies = (array) $proxy;
53: return $this;
54: }
55:
56:
57: 58: 59: 60:
61: public function createHttpRequest()
62: {
63:
64: $url = new UrlScript;
65: $url->setScheme(!empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off') ? 'https' : 'http');
66: $url->setUser(isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '');
67: $url->setPassword(isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '');
68:
69:
70: if ((isset($_SERVER[$tmp = 'HTTP_HOST']) || isset($_SERVER[$tmp = 'SERVER_NAME']))
71: && preg_match('#^([a-z0-9_.-]+|\[[a-f0-9:]+\])(:\d+)?\z#i', $_SERVER[$tmp], $pair)
72: ) {
73: $url->setHost(strtolower($pair[1]));
74: if (isset($pair[2])) {
75: $url->setPort(substr($pair[2], 1));
76: } elseif (isset($_SERVER['SERVER_PORT'])) {
77: $url->setPort($_SERVER['SERVER_PORT']);
78: }
79: }
80:
81:
82: $requestUrl = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
83: $requestUrl = Strings::replace($requestUrl, $this->urlFilters['url']);
84: $tmp = explode('?', $requestUrl, 2);
85: $path = Url::unescape($tmp[0], '%/?#');
86: $path = Strings::fixEncoding(Strings::replace($path, $this->urlFilters['path']));
87: $url->setPath($path);
88: $url->setQuery(isset($tmp[1]) ? $tmp[1] : '');
89:
90:
91: $lpath = strtolower($path);
92: $script = isset($_SERVER['SCRIPT_NAME']) ? strtolower($_SERVER['SCRIPT_NAME']) : '';
93: if ($lpath !== $script) {
94: $max = min(strlen($lpath), strlen($script));
95: for ($i = 0; $i < $max && $lpath[$i] === $script[$i]; $i++);
96: $path = $i ? substr($path, 0, strrpos($path, '/', $i - strlen($path) - 1) + 1) : '/';
97: }
98: $url->setScriptPath($path);
99:
100:
101: $useFilter = (!in_array(ini_get('filter.default'), array('', 'unsafe_raw')) || ini_get('filter.default_flags'));
102:
103: $query = $url->getQueryParameters();
104: $post = $useFilter ? filter_input_array(INPUT_POST, FILTER_UNSAFE_RAW) : (empty($_POST) ? array() : $_POST);
105: $cookies = $useFilter ? filter_input_array(INPUT_COOKIE, FILTER_UNSAFE_RAW) : (empty($_COOKIE) ? array() : $_COOKIE);
106:
107: if (get_magic_quotes_gpc()) {
108: $post = Helpers::stripslashes($post, $useFilter);
109: $cookies = Helpers::stripslashes($cookies, $useFilter);
110: }
111:
112:
113: $reChars = '#^[' . self::CHARS . ']*+\z#u';
114: if (!$this->binary) {
115: $list = array(& $query, & $post, & $cookies);
116: while (list($key, $val) = each($list)) {
117: foreach ($val as $k => $v) {
118: if (is_string($k) && (!preg_match($reChars, $k) || preg_last_error())) {
119: unset($list[$key][$k]);
120:
121: } elseif (is_array($v)) {
122: $list[$key][$k] = $v;
123: $list[] = & $list[$key][$k];
124:
125: } else {
126: $list[$key][$k] = (string) preg_replace('#[^' . self::CHARS . ']+#u', '', $v);
127: }
128: }
129: }
130: unset($list, $key, $val, $k, $v);
131: }
132: $url->setQuery($query);
133:
134:
135:
136: $files = array();
137: $list = array();
138: if (!empty($_FILES)) {
139: foreach ($_FILES as $k => $v) {
140: if (!is_array($v) || !isset($v['name'], $v['type'], $v['size'], $v['tmp_name'], $v['error'])
141: || (!$this->binary && is_string($k) && (!preg_match($reChars, $k) || preg_last_error()))
142: ) {
143: continue;
144: }
145: $v['@'] = & $files[$k];
146: $list[] = $v;
147: }
148: }
149:
150: while (list(, $v) = each($list)) {
151: if (!isset($v['name'])) {
152: continue;
153:
154: } elseif (!is_array($v['name'])) {
155: if (get_magic_quotes_gpc()) {
156: $v['name'] = stripSlashes($v['name']);
157: }
158: if (!$this->binary && (!preg_match($reChars, $v['name']) || preg_last_error())) {
159: $v['name'] = '';
160: }
161: if ($v['error'] !== UPLOAD_ERR_NO_FILE) {
162: $v['@'] = new FileUpload($v);
163: }
164: continue;
165: }
166:
167: foreach ($v['name'] as $k => $foo) {
168: if (!$this->binary && is_string($k) && (!preg_match($reChars, $k) || preg_last_error())) {
169: continue;
170: }
171: $list[] = array(
172: 'name' => $v['name'][$k],
173: 'type' => $v['type'][$k],
174: 'size' => $v['size'][$k],
175: 'tmp_name' => $v['tmp_name'][$k],
176: 'error' => $v['error'][$k],
177: '@' => & $v['@'][$k],
178: );
179: }
180: }
181:
182:
183:
184: if (function_exists('apache_request_headers')) {
185: $headers = apache_request_headers();
186: } else {
187: $headers = array();
188: foreach ($_SERVER as $k => $v) {
189: if (strncmp($k, 'HTTP_', 5) == 0) {
190: $k = substr($k, 5);
191: } elseif (strncmp($k, 'CONTENT_', 8)) {
192: continue;
193: }
194: $headers[ strtr($k, '_', '-') ] = $v;
195: }
196: }
197:
198:
199: $remoteAddr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL;
200: $remoteHost = isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : NULL;
201:
202:
203: foreach ($this->proxies as $proxy) {
204: if (Helpers::ipMatch($remoteAddr, $proxy) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
205: $proxies = $this->proxies;
206: $xForwardedForWithoutProxies = array_filter(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']), function ($ip) use ($proxies) {
207: return !array_filter($proxies, function ($proxy) use ($ip) {
208: return Helpers::ipMatch(trim($ip), $proxy);
209: });
210: });
211: $remoteAddr = trim(end($xForwardedForWithoutProxies));
212:
213: if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
214: $xForwardedForRealIpKey = key($xForwardedForWithoutProxies);
215: $xForwardedHost = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
216: if (isset($xForwardedHost[$xForwardedForRealIpKey])) {
217: $remoteHost = trim($xForwardedHost[$xForwardedForRealIpKey]);
218: }
219: }
220: break;
221: }
222: }
223:
224:
225: $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : NULL;
226: if ($method === 'POST' && isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])
227: && preg_match('#^[A-Z]+\z#', $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])
228: ) {
229: $method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
230: }
231:
232:
233: $rawBodyCallback = function () {
234: static $rawBody;
235:
236: if (PHP_VERSION_ID >= 50600) {
237: return file_get_contents('php://input');
238:
239: } elseif ($rawBody === NULL) {
240: $rawBody = (string) file_get_contents('php://input');
241: }
242:
243: return $rawBody;
244: };
245:
246: return new Request($url, NULL, $post, $files, $cookies, $headers, $method, $remoteAddr, $remoteHost, $rawBodyCallback);
247: }
248:
249: }
250: