1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Xoops\Core;
13:
14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
28:
29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40:
41: class HttpRequest
42: {
43: 44: 45:
46: protected $params;
47:
48:
49: 50: 51: 52: 53: 54: 55:
56: protected $detectors = array(
57: 'get' => array('env' => 'REQUEST_METHOD', 'value' => 'GET'),
58: 'post' => array('env' => 'REQUEST_METHOD', 'value' => 'POST'),
59: 'put' => array('env' => 'REQUEST_METHOD', 'value' => 'PUT'),
60: 'delete' => array('env' => 'REQUEST_METHOD', 'value' => 'DELETE'),
61: 'head' => array('env' => 'REQUEST_METHOD', 'value' => 'HEAD'),
62: 'options' => array('env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'),
63: 'safemethod'=> array('env' => 'REQUEST_METHOD', 'options' => array('GET', 'HEAD')),
64: 'ssl' => array('env' => 'HTTPS', 'value' => 1),
65: 'ajax' => array('env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'),
66: 'flash' => array('env' => 'HTTP_USER_AGENT', 'pattern' => '/^(Shockwave|Adobe) Flash/'),
67: 'mobile' => array(
68: 'env' => 'HTTP_USER_AGENT',
69: 'options' => array(
70: 'Android',
71: 'AvantGo',
72: 'BlackBerry',
73: 'DoCoMo',
74: 'Fennec',
75: 'iPod',
76: 'iPhone',
77: 'iPad',
78: 'J2ME',
79: 'MIDP',
80: 'NetFront',
81: 'Nokia',
82: 'Opera Mini',
83: 'Opera Mobi',
84: 'PalmOS',
85: 'PalmSource',
86: 'portalmmm',
87: 'Plucker',
88: 'ReqwirelessWeb',
89: 'SonyEricsson',
90: 'Symbian',
91: 'UP\\.Browser',
92: 'webOS',
93: 'Windows CE',
94: 'Windows Phone OS',
95: 'Xiino'
96: )
97: ),
98: 'robot' => array(
99: 'env' => 'HTTP_USER_AGENT',
100: 'options' => array(
101:
102: 'Googlebot',
103: 'msnbot',
104: 'Slurp',
105: 'Yahoo',
106:
107: 'Arachnoidea',
108: 'ArchitextSpider',
109: 'Ask Jeeves',
110: 'B-l-i-t-z-Bot',
111: 'Baiduspider',
112: 'BecomeBot',
113: 'cfetch',
114: 'ConveraCrawler',
115: 'ExtractorPro',
116: 'FAST-WebCrawler',
117: 'FDSE robot',
118: 'fido',
119: 'geckobot',
120: 'Gigabot',
121: 'Girafabot',
122: 'grub-client',
123: 'Gulliver',
124: 'HTTrack',
125: 'ia_archiver',
126: 'InfoSeek',
127: 'kinjabot',
128: 'KIT-Fireball',
129: 'larbin',
130: 'LEIA',
131: 'lmspider',
132: 'Lycos_Spider',
133: 'Mediapartners-Google',
134: 'MuscatFerret',
135: 'NaverBot',
136: 'OmniExplorer_Bot',
137: 'polybot',
138: 'Pompos',
139: 'Scooter',
140: 'Teoma',
141: 'TheSuBot',
142: 'TurnitinBot',
143: 'Ultraseek',
144: 'ViolaBot',
145: 'webbandit',
146: 'www\\.almaden\\.ibm\\.com\\/cs\\/crawler',
147: 'ZyBorg',
148: )
149: ),
150: );
151:
152: 153: 154:
155: private function __construct()
156: {
157: switch (strtolower($this->getEnv('REQUEST_METHOD'))) {
158: case 'get':
159: $params = $_GET;
160: break;
161: case 'put':
162: parse_str(file_get_contents('php://input'), $put);
163: $params = array_merge($_GET, $put);
164: break;
165: default:
166: $params = array_merge($_GET, $_POST);
167: }
168: $this->params = $params;
169: }
170:
171: 172: 173: 174: 175:
176: public static function getInstance()
177: {
178: static $instance;
179: if (!isset($instance)) {
180: $thisClass = get_called_class();
181: $instance = new $thisClass();
182: }
183: return $instance;
184: }
185:
186: 187: 188: 189: 190: 191: 192:
193: public function getHeader($name = null)
194: {
195: if ($name === null) {
196: return $name;
197: }
198:
199:
200: if ($res = $this->getEnv('HTTP_' . strtoupper(str_replace('-', '_', $name)))) {
201: return $res;
202: }
203:
204:
205:
206: if (function_exists('apache_request_headers')) {
207: $headers = apache_request_headers();
208: if (!empty($headers[$name])) {
209: return $headers[$name];
210: }
211: }
212: return null;
213: }
214:
215: 216: 217: 218: 219:
220: public function getScheme()
221: {
222: return $this->getEnv('HTTPS') ? 'https' : 'http';
223: }
224:
225: 226: 227: 228: 229:
230: public function getHost()
231: {
232: return $this->getEnv('HTTP_HOST') ? (string) $this->getEnv('HTTP_HOST') : 'localhost';
233: }
234:
235: 236: 237: 238: 239:
240: public static function getUri()
241: {
242: if (empty($_SERVER['PHP_SELF']) || empty($_SERVER['REQUEST_URI'])) {
243:
244: $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'];
245: if (!empty($_SERVER['QUERY_STRING'])) {
246: $_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
247: }
248: return $_SERVER['REQUEST_URI'];
249: }
250: return isset($_SERVER['ORIG_REQUEST_URI']) ? $_SERVER['ORIG_REQUEST_URI'] : $_SERVER['REQUEST_URI'];
251: }
252:
253: 254: 255: 256: 257:
258: public function getReferer()
259: {
260: return $this->getEnv('HTTP_REFERER') ? $this->getEnv('HTTP_REFERER') : '';
261: }
262:
263: 264: 265: 266: 267:
268: public function getScriptName()
269: {
270: return $this->getEnv('SCRIPT_NAME')
271: ? $this->getEnv('SCRIPT_NAME')
272: : ($this->getEnv('ORIG_SCRIPT_NAME') ? $this->getEnv('ORIG_SCRIPT_NAME') : '');
273: }
274:
275: 276: 277: 278: 279:
280: public function getDomain()
281: {
282: $host = $this->getHost();
283: $domain = \Xoops::getInstance()->getBaseDomain($host, false);
284: return is_null($domain) ? $host : $domain;
285: }
286:
287: 288: 289: 290: 291:
292: public function getSubdomains()
293: {
294: $host = $this->getHost();
295: $pdp = \Xoops::getInstance()->getBaseDomain($host, true, true);
296: $subdomain = $pdp->subdomain;
297: return is_null($subdomain) ? '' : $subdomain;
298: }
299:
300: 301: 302: 303: 304: 305: 306: 307:
308: public function getClientIp($considerProxy = false)
309: {
310: $default = (array_key_exists('REMOTE_ADDR', $_SERVER)) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
311:
312: if (!$considerProxy) {
313: return $default;
314: }
315:
316: $keys = array(
317: 'HTTP_CLIENT_IP',
318: 'HTTP_X_FORWARDED_FOR',
319: 'HTTP_X_FORWARDED',
320: 'HTTP_X_CLUSTER_CLIENT_IP',
321: 'HTTP_FORWARDED_FOR',
322: 'HTTP_FORWARDED',
323: );
324: foreach ($keys as $key) {
325: if (array_key_exists($key, $_SERVER) === true) {
326: foreach (explode(',', $_SERVER[$key]) as $ip) {
327: $ip = trim($ip);
328: if (false !== filter_var(
329: $ip,
330: FILTER_VALIDATE_IP,
331: FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
332: )) {
333: return $ip;
334: }
335: }
336: }
337: }
338:
339: return $default;
340: }
341:
342: 343: 344: 345: 346:
347: public function getUrl()
348: {
349: $url = $this->getScheme() . "://" . $this->getHost();
350: $port = $this->getEnv('SERVER_PORT');
351: if (80 != $port) {
352: $url .= ":{$port}";
353: }
354: return $url . $this->getUri();
355: }
356:
357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371:
372: public function getEnv($name, $default = null)
373: {
374: if ($name === 'HTTPS') {
375: if (isset($_SERVER['HTTPS'])) {
376: return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
377: }
378: return (strpos($this->getEnv('SCRIPT_URI'), 'https://') === 0);
379: }
380:
381: if ($name === 'SCRIPT_NAME' && !isset($_SERVER[$name])) {
382: if ($this->getEnv('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) {
383: return $_ENV['SCRIPT_URL'];
384: }
385: }
386:
387: if ($name === 'REMOTE_ADDR' && !isset($_SERVER[$name])) {
388: $address = $this->getEnv('HTTP_PC_REMOTE_ADDR');
389: if ($address !== null) {
390: return $address;
391: }
392: }
393:
394: $val = null;
395: if (isset($_SERVER[$name])) {
396: $val = $_SERVER[$name];
397: } elseif (isset($_ENV[$name])) {
398: $val = $_ENV[$name];
399: }
400:
401: if ($val !== null) {
402: return $val;
403: }
404:
405: switch ($name) {
406: case 'SCRIPT_FILENAME':
407: $val = preg_replace('#//+#', '/', $this->getEnv('PATH_TRANSLATED'));
408: return preg_replace('#\\\\+#', '\\', $val);
409: break;
410: case 'DOCUMENT_ROOT':
411: $name = $this->getEnv('SCRIPT_NAME');
412: $filename = $this->getEnv('SCRIPT_FILENAME');
413: $offset = 0;
414: if (!strpos($name, '.php')) {
415: $offset = 4;
416: }
417: return substr($filename, 0, -(strlen($name) + $offset));
418: break;
419: case 'PHP_SELF':
420: return str_replace($this->getEnv('DOCUMENT_ROOT'), '', $this->getEnv('SCRIPT_FILENAME'));
421: break;
422: case 'CGI_MODE':
423: return (PHP_SAPI === 'cgi');
424: break;
425: case 'HTTP_BASE':
426: $host = $this->getEnv('HTTP_HOST');
427: $val = \Xoops::getInstance()->getBaseDomain($host);
428: if (is_null($val)) {
429: return $default;
430: } else {
431: return '.' . $val;
432: }
433: break;
434: }
435: return $default;
436: }
437:
438: 439: 440: 441: 442: 443: 444:
445: public static function getFiles($name)
446: {
447: if (empty($_FILES)) {
448: return array();
449: }
450:
451: if (isset($_FILES[$name])) {
452: return $_FILES[$name];
453: }
454:
455: if (false === $pos = strpos($name, '[')) {
456: return array();
457: }
458:
459: $base = substr($name, 0, $pos);
460: $key = str_replace(array(']', '['), array('', '"]["'), substr($name, $pos + 1, -1));
461: $code = array(sprintf('if (!isset($_FILES["%s"]["name"]["%s"])) return array();', $base, $key));
462: $code[] = '$file = array();';
463: foreach (array('name', 'type', 'size', 'tmp_name', 'error') as $property) {
464: $code[] = sprintf('$file["%1$s"] = $_FILES["%2$s"]["%1$s"]["%3$s"];', $property, $base, $key);
465: }
466: $code[] = 'return $file;';
467:
468: return eval(implode(PHP_EOL, $code));
469: }
470:
471: 472: 473: 474: 475: 476: 477: 478: 479:
480: public function is($type)
481: {
482: $type = strtolower($type);
483: if (!isset($this->detectors[$type])) {
484: return false;
485: }
486: $detect = $this->detectors[$type];
487: if (isset($detect['env'])) {
488: return $this->detectByEnv($detect);
489: } elseif (isset($detect['param'])) {
490: return $this->detectByParam($detect);
491: } elseif (isset($detect['callback']) && is_callable($detect['callback'])) {
492: return call_user_func($detect['callback'], $this);
493: }
494: return false;
495: }
496:
497: 498: 499: 500: 501: 502: 503:
504: protected function detectByEnv($detect)
505: {
506: if (isset($detect['value'])) {
507: return (bool) $this->getEnv($detect['env']) == $detect['value'];
508: } elseif (isset($detect['pattern'])) {
509: return (bool) preg_match($detect['pattern'], $this->getEnv($detect['env']));
510: } elseif (isset($detect['options'])) {
511: $pattern = '/' . implode('|', $detect['options']) . '/i';
512: return (bool) preg_match($pattern, $this->getEnv($detect['env']));
513: }
514: return false;
515: }
516:
517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527:
528: protected function detectByParam($detect)
529: {
530: $name = $detect['param'];
531: $value = $detect['value'];
532: return isset($this->params[$name]) ? $this->params[$name] == $value : false;
533: }
534:
535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561:
562: public function addDetector($name, $options)
563: {
564: $name = strtolower($name);
565: if (isset($this->detectors[$name]) && isset($options['options'])) {
566: $options = \Xoops\Utils::arrayRecursiveMerge($this->detectors[$name], $options);
567: }
568: $this->detectors[$name] = $options;
569: }
570:
571: 572: 573: 574: 575: 576: 577:
578: public function clientAcceptsType($mediaType)
579: {
580: $accepts = $this->getAcceptMediaTypes();
581:
582: $mediaType = trim($mediaType);
583: if (isset($accepts[$mediaType])) {
584: return true;
585: }
586: list($type) = explode('/', $mediaType);
587: if (isset($accepts[$type.'/*'])) {
588: return true;
589: }
590:
591: return isset($accepts['*/*']);
592: }
593:
594: 595: 596: 597: 598: 599: 600:
601: public function getAcceptMediaTypes()
602: {
603: $types = array();
604: $accept = $this->getHeader('ACCEPT');
605:
606: if (!empty($accept)) {
607: $entries = explode(',', $accept);
608: foreach ($entries as $e) {
609: $mt = explode(';q=', $e);
610: if (!isset($mt[1])) {
611: $mt[1] = 1.0;
612: }
613: $types[trim($mt[0])] = (float) $mt[1];
614: }
615:
616:
617: arsort($types, SORT_NUMERIC);
618: }
619:
620: return($types);
621: }
622:
623: 624: 625: 626: 627: 628: 629:
630: public function getAcceptedLanguages()
631: {
632: $languages = array();
633: $accept = $this->getHeader('ACCEPT_LANGUAGE');
634:
635: if (!empty($accept)) {
636: $entries = explode(',', $accept);
637: foreach ($entries as $e) {
638: $l = explode(';q=', $e);
639: if (!isset($l[1])) {
640: $l[1] = 1.0;
641: }
642: $languages[trim($l[0])] = (float) $l[1];
643: }
644:
645:
646: arsort($languages, SORT_NUMERIC);
647: }
648:
649: return($languages);
650: }
651: }
652: