1: <?php
2: 3: 4: 5: 6: 7: 8: 9:
10:
11: namespace Kotchasan\Http;
12:
13: 14: 15: 16: 17: 18: 19:
20: class Request extends AbstractRequest implements \Psr\Http\Message\RequestInterface
21: {
22: 23: 24:
25: private $attributes = array();
26: 27: 28: 29: 30:
31: private $cookieParams;
32: 33: 34: 35: 36:
37: private $parsedBody;
38: 39: 40: 41: 42:
43: private $queryParams;
44: 45: 46: 47: 48:
49: private $serverParams;
50: 51: 52:
53: private $uploadedFiles;
54:
55: 56: 57: 58: 59: 60: 61: 62: 63:
64: public function cookie($name, $default = '')
65: {
66: return $this->createInputItem($this->getCookieParams(), $name, $default, 'COOKIE');
67: }
68:
69: 70: 71: 72: 73:
74: public function createToken()
75: {
76: $token = \Kotchasan\Password::uniqid(32);
77: $_SESSION[$token] = array(
78: 'times' => 0,
79: 'expired' => time() + TOKEN_AGE,
80: );
81: return $token;
82: }
83:
84: 85: 86: 87: 88: 89: 90: 91: 92:
93: public function get($name, $default = null)
94: {
95: return $this->createInputItem($this->getQueryParams(), $name, $default, 'GET');
96: }
97:
98: 99: 100: 101: 102:
103: public function getAcceptableLanguages()
104: {
105: $acceptLanguages = empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? array() : explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
106: $matches = array();
107: if (!empty($acceptLanguages)) {
108: foreach ($acceptLanguages as $item) {
109: $item = array_map('trim', explode(';', $item));
110: if (isset($item[1])) {
111: $q = str_replace('q=', '', $item[1]);
112: } else {
113: if ($item[0] == '*/*') {
114: $q = 0.01;
115: } elseif (substr($item[0], -1) == '*') {
116: $q = 0.02;
117: } else {
118: $q = 1000 - count($matches);
119: }
120: }
121: $matches[(string) $q] = $item[0];
122: }
123: krsort($matches, SORT_NUMERIC);
124: $matches = array_values($matches);
125: }
126: return $matches;
127: }
128:
129: 130: 131: 132: 133: 134: 135: 136:
137: public function getAttribute($name, $default = null)
138: {
139: return isset($this->attributes[$name]) ? $this->attributes[$name] : $default;
140: }
141:
142: 143: 144: 145: 146:
147: public function getAttributes()
148: {
149: return $this->attributes;
150: }
151:
152: 153: 154: 155: 156: 157:
158: public function getClientIp()
159: {
160: if (isset($_SERVER['HTTP_CLIENT_IP'])) {
161: return $_SERVER['HTTP_CLIENT_IP'];
162: } elseif (isset($_SERVER['HTTP_FORWARDED_FOR'])) {
163: return $_SERVER['HTTP_FORWARDED_FOR'];
164: } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
165: $IParray = array_filter(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
166: return $IParray[0];
167: } elseif (isset($_SERVER['REMOTE_ADDR'])) {
168: return $_SERVER['REMOTE_ADDR'];
169: }
170: return null;
171: }
172:
173: 174: 175: 176: 177:
178: public function getCookieParams()
179: {
180: if ($this->cookieParams === null) {
181: $this->cookieParams = self::filterRequestKey($_COOKIE);
182: }
183: return $this->cookieParams;
184: }
185:
186: 187: 188: 189: 190:
191: public function getParsedBody()
192: {
193: if ($this->parsedBody === null) {
194: $this->parsedBody = self::filterRequestKey($_POST);
195: }
196: return $this->parsedBody;
197: }
198:
199: 200: 201: 202: 203:
204: public function getQueryParams()
205: {
206: if ($this->queryParams === null) {
207: $this->queryParams = self::filterRequestKey($_GET);
208: }
209: return $this->queryParams;
210: }
211:
212: 213: 214: 215: 216:
217: public function getServerParams()
218: {
219: if ($this->serverParams === null) {
220: $this->serverParams = self::filterRequestKey($_SERVER);
221: }
222: return $this->serverParams;
223: }
224:
225: 226: 227: 228: 229:
230: public function getUploadedFiles()
231: {
232: if ($this->uploadedFiles === null) {
233: $this->uploadedFiles = new \Kotchasan\Files();
234: if (isset($_FILES)) {
235: foreach ($_FILES as $name => $file) {
236: if (is_array($file['name'])) {
237: foreach ($file['name'] as $key => $value) {
238: $this->uploadedFiles->add($name.'['.$key.']', $file['tmp_name'][$key], $value, $file['type'][$key], $file['size'][$key], $file['error'][$key]);
239: }
240: } else {
241: $this->uploadedFiles->add($name, $file['tmp_name'], $file['name'], $file['type'], $file['size'], $file['error']);
242: }
243: }
244: }
245: }
246: return $this->uploadedFiles;
247: }
248:
249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259:
260: public function globals($keys, $name, $default = null)
261: {
262: foreach ($keys as $key) {
263: if ($key == 'POST') {
264: $datas = $this->getParsedBody();
265: } elseif ($key == 'GET') {
266: $datas = $this->getQueryParams();
267: } elseif ($key == 'SESSION') {
268: $datas = $_SESSION;
269: } elseif ($key == 'COOKIE') {
270: $datas = $this->getCookieParams();
271: }
272: if (isset($datas[$name])) {
273: return is_array($datas[$name]) ? new \Kotchasan\Inputs($datas[$name], $key) : new \Kotchasan\InputItem($datas[$name], $key);
274: }
275: }
276: return is_array($default) ? new \Kotchasan\Inputs($default) : new \Kotchasan\InputItem($default);
277: }
278:
279: 280: 281: 282: 283:
284: public function initSession()
285: {
286: $sessid = $this->get('sess')->toString();
287: if (!empty($sessid) && preg_match('/[a-zA-Z0-9]{20,}/', $sessid)) {
288: session_id($sessid);
289: }
290: if (defined('USE_SESSION_DATABASE') && USE_SESSION_DATABASE === true) {
291: $sess = new \Kotchasan\Session();
292: session_set_save_handler(
293: array($sess, '_open'),
294: array($sess, '_close'),
295: array($sess, '_read'),
296: array($sess, '_write'),
297: array($sess, '_destroy'),
298: array($sess, '_gc')
299: );
300: register_shutdown_function('session_write_close');
301: }
302: session_start();
303: if (!ob_get_status()) {
304: if (extension_loaded('zlib') && !ini_get('zlib.output_compression')) {
305:
306: ob_start('ob_gzhandler');
307: } else {
308: ob_start();
309: }
310: }
311: return true;
312: }
313:
314: 315: 316: 317: 318: 319:
320: public function isAjax()
321: {
322: return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
323: }
324:
325: 326: 327: 328: 329: 330:
331: public function isReferer()
332: {
333: $host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'];
334: $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
335: if (preg_match("/$host/ui", $referer)) {
336: return true;
337: } elseif (preg_match('/^(http(s)?:\/\/)(.*)(\/.*){0,}$/U', WEB_URL, $match)) {
338: return preg_match("/$match[3]/ui", $referer);
339: }
340: return false;
341: }
342:
343: 344: 345: 346: 347: 348: 349: 350: 351:
352: public function isSafe()
353: {
354: $token = $this->post('token')->toString();
355: if ($token !== null) {
356: if (isset($_SESSION[$token]) && $_SESSION[$token]['times'] < TOKEN_LIMIT && $_SESSION[$token]['expired'] > time() && $this->isReferer()) {
357: ++$_SESSION[$token]['times'];
358: return true;
359: } else {
360: unset($_SESSION[$token]);
361: }
362: }
363: return false;
364: }
365:
366: 367: 368: 369: 370: 371: 372: 373: 374: 375:
376: public function post($name, $default = null)
377: {
378: return $this->createInputItem($this->getParsedBody(), $name, $default, 'POST');
379: }
380:
381: 382: 383:
384: public function removeToken()
385: {
386: $token = $this->globals(array('POST', 'GET'), 'token', null)->toString();
387: if ($token !== null) {
388: unset($_SESSION[$token]);
389: }
390: }
391:
392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402:
403: public function request($name, $default = null, $cookie = false)
404: {
405: $from = array('POST', 'GET');
406: if ($cookie) {
407: $from[] = 'COOKIE';
408: }
409: return $this->globals($from, $name, $default);
410: }
411:
412: 413: 414: 415: 416: 417: 418: 419: 420:
421: public function server($name, $default = null)
422: {
423: return isset($_SERVER[$name]) ? $_SERVER[$name] : $default;
424: }
425:
426: 427: 428: 429: 430: 431: 432: 433: 434: 435:
436: public function session($name, $default = null)
437: {
438: return $this->createInputItem($_SESSION, $name, $default, 'SESSION');
439: }
440:
441: 442: 443: 444: 445: 446: 447: 448:
449: public function setSession($name, $value)
450: {
451: $_SESSION[$name] = $value;
452: return $this;
453: }
454:
455: 456: 457: 458: 459: 460: 461: 462:
463: public function withAttribute($name, $value)
464: {
465: $clone = clone $this;
466: $clone->attributes[$name] = $value;
467: return $clone;
468: }
469:
470: 471: 472: 473: 474: 475: 476:
477: public function withCookieParams(array $cookies)
478: {
479: $clone = clone $this;
480: $clone->cookieParams = $cookies;
481: return $clone;
482: }
483:
484: 485: 486: 487: 488: 489: 490:
491: public function withParsedBody($data)
492: {
493: $clone = clone $this;
494: $clone->parsedBody = $data;
495: return $clone;
496: }
497:
498: 499: 500: 501: 502: 503: 504:
505: public function withQueryParams(array $query)
506: {
507: $clone = clone $this;
508: $clone->queryParams = $query;
509: return $clone;
510: }
511:
512: 513: 514: 515: 516: 517: 518:
519: public function withUploadedFiles(array $uploadedFiles)
520: {
521: $clone = clone $this;
522: $clone->uploadedFiles = $uploadedFiles;
523: return $clone;
524: }
525:
526: 527: 528: 529: 530: 531: 532:
533: public function withoutAttribute($names)
534: {
535: $clone = clone $this;
536: if (is_array($names)) {
537: foreach ($names as $name) {
538: unset($clone->attributes[$name]);
539: }
540: } else {
541: unset($clone->attributes[$names]);
542: }
543: return $clone;
544: }
545:
546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556:
557: private function createInputItem($source, $name, $default, $type)
558: {
559: if (isset($source[$name])) {
560: return is_array($source[$name]) ? new \Kotchasan\Inputs($source[$name], $type) : new \Kotchasan\InputItem($source[$name], $type);
561: } elseif (preg_match('/(.*)\[(.*)\]/', $name, $match) && isset($source[$match[1]][$match[2]])) {
562: return new \Kotchasan\InputItem($source[$match[1]][$match[2]], $type);
563: }
564: return is_array($default) ? new \Kotchasan\Inputs($default) : new \Kotchasan\InputItem($default);
565: }
566:
567: 568: 569: 570: 571: 572: 573:
574: public static function filterRequestKey($source)
575: {
576: $result = array();
577: foreach ($source as $key => $values) {
578: if (preg_match('/^[a-zA-Z0-9\[\]_\-]+/', $key)) {
579: if (is_array($values)) {
580: $result[$key] = self::filterRequestKey($values);
581: } elseif ($values !== null) {
582: $result[$key] = $values;
583: }
584: }
585: }
586: return $result;
587: }
588: }
589: