1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
21: class Horde_Browser
22: {
23: 24: 25: 26: 27:
28: protected $_majorVersion = 0;
29:
30: 31: 32: 33: 34:
35: protected $_minorVersion = 0;
36:
37: 38: 39: 40: 41:
42: protected $_browser = '';
43:
44: 45: 46: 47: 48:
49: protected $_agent = '';
50:
51: 52: 53: 54: 55:
56: protected $_lowerAgent = '';
57:
58: 59: 60: 61: 62:
63: protected $_accept = '';
64:
65: 66: 67: 68: 69:
70: protected $_platform = '';
71:
72: 73: 74: 75: 76:
77: protected $_robotAgents = array(
78:
79: 'Googlebot',
80: 'msnbot',
81: 'bingbot',
82: 'Slurp',
83: 'Yahoo',
84:
85: 'appie',
86: 'Arachnoidea',
87: 'ArchitextSpider',
88: 'Ask Jeeves',
89: 'B-l-i-t-z-Bot',
90: 'Baiduspider',
91: 'BecomeBot',
92: 'cfetch',
93: 'ConveraCrawler',
94: 'ExtractorPro',
95: 'FAST-WebCrawler',
96: 'FDSE robot',
97: 'fido',
98: 'findlinks',
99: 'Francis',
100: 'geckobot',
101: 'Gigabot',
102: 'Girafabot',
103: 'grub-client',
104: 'Gulliver',
105: 'HTTrack',
106: 'ia_archiver',
107: 'iaskspider',
108: 'iCCrawler',
109: 'InfoSeek',
110: 'kinjabot',
111: 'KIT-Fireball',
112: 'larbin',
113: 'LEIA',
114: 'lmspider',
115: 'lwp-trivial',
116: 'Lycos_Spider',
117: 'Mediapartners-Google',
118: 'MSRBOT',
119: 'MuscatFerret',
120: 'NaverBot',
121: 'OmniExplorer_Bot',
122: 'polybot',
123: 'Pompos',
124: 'RufusBot',
125: 'Scooter',
126: 'Seekbot',
127: 'sogou spider',
128: 'sproose',
129: 'Teoma',
130: 'TheSuBot',
131: 'TurnitinBot',
132: 'Twiceler',
133: 'Ultraseek',
134: 'Vagabondo/Kliksafe',
135: 'ViolaBot',
136: 'voyager',
137: 'W3C-checklink',
138: 'webbandit',
139: 'www.almaden.ibm.com/cs/crawler',
140: 'yacy',
141: 'ZyBorg',
142: );
143:
144: 145: 146: 147: 148:
149: protected $_robotAgentRegexp = null;
150:
151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161:
162: protected $_mobileAgents = array(
163: 'Blackberry',
164: 'Blazer',
165: 'Handspring',
166: 'iPhone',
167: 'iPod',
168: 'Kyocera',
169: 'LG',
170: 'Motorola',
171: 'Nokia',
172: 'Palm',
173: 'PlayStation Portable',
174: 'Samsung',
175: 'Smartphone',
176: 'SonyEricsson',
177: 'Symbian',
178: 'WAP',
179: 'Windows CE',
180: );
181:
182: 183: 184: 185: 186: 187:
188: protected $_tvAgents = array(
189: 'Nintendo Wii',
190: 'Playstation 3',
191: 'WebTV',
192: );
193:
194: 195: 196: 197: 198:
199: protected $_mobile = false;
200:
201: 202: 203: 204: 205:
206: protected $_features = array(
207: 'frames' => true,
208: 'html' => true,
209: 'images' => true,
210: 'java' => true,
211: 'javascript' => true,
212: 'tables' => true
213: );
214:
215: 216: 217: 218: 219:
220: protected $_quirks = array();
221:
222: 223: 224: 225: 226: 227:
228: protected $_images = array('jpeg', 'gif', 'png', 'pjpeg', 'x-png', 'bmp');
229:
230: 231: 232: 233: 234: 235:
236: public function __construct($userAgent = null, $accept = null)
237: {
238: $this->match($userAgent, $accept);
239: }
240:
241: 242: 243: 244: 245: 246: 247:
248: public function match($userAgent = null, $accept = null)
249: {
250:
251: if (is_null($userAgent)) {
252: if (isset($_SERVER['HTTP_USER_AGENT'])) {
253: $this->_agent = trim($_SERVER['HTTP_USER_AGENT']);
254: }
255: } else {
256: $this->_agent = $userAgent;
257: }
258: $this->_lowerAgent = Horde_String::lower($this->_agent);
259:
260:
261: if (is_null($accept)) {
262: if (isset($_SERVER['HTTP_ACCEPT'])) {
263: $this->_accept = Horde_String::lower(trim($_SERVER['HTTP_ACCEPT']));
264: }
265: } else {
266: $this->_accept = Horde_String::lower($accept);
267: }
268:
269:
270: if (isset($_SERVER['HTTP_ACCEPT_CHARSET'])) {
271: $this->setFeature('utf', strpos(Horde_String::lower($_SERVER['HTTP_ACCEPT_CHARSET']), 'utf') !== false);
272: }
273:
274: if (empty($this->_agent)) {
275: return;
276: }
277:
278: $this->_setPlatform();
279:
280:
281: $agent = $this->_agent;
282: $lowerAgent = $this->_lowerAgent;
283:
284: if (strpos($lowerAgent, 'iemobile') !== false ||
285: strpos($lowerAgent, 'mobileexplorer') !== false ||
286: strpos($lowerAgent, 'openwave') !== false) {
287: $this->setFeature('frames', false);
288: $this->setFeature('javascript', false);
289: $this->setQuirk('avoid_popup_windows');
290: $this->setMobile(true);
291:
292: if (preg_match('|iemobile[/ ]([0-9.]+)|', $lowerAgent, $version)) {
293: list($this->_majorVersion, $this->_minorVersion) = explode('.', $version[1]);
294: if ($this->_majorVersion >= 7) {
295:
296: $this->setBrowser('msie');
297: $this->setFeature('javascript');
298: $this->setFeature('xmlhttpreq');
299: $this->setFeature('ajax');
300: $this->setFeature('dom');
301: $this->setFeature('utf');
302: $this->setFeature('rte');
303: $this->setFeature('cite');
304: }
305: }
306: } elseif (strpos($lowerAgent, 'opera mini') !== false ||
307: strpos($lowerAgent, 'operamini') !== false) {
308: $this->setBrowser('opera');
309: $this->setFeature('frames', false);
310: $this->setFeature('javascript');
311: $this->setQuirk('avoid_popup_windows');
312: $this->setMobile(true);
313: } elseif (preg_match('|Opera[/ ]([0-9.]+)|', $agent, $version)) {
314: $this->setBrowser('opera');
315: list($this->_majorVersion, $this->_minorVersion) = explode('.', $version[1]);
316: $this->setFeature('javascript');
317: $this->setQuirk('no_filename_spaces');
318:
319: 320:
321: if (preg_match('/; (120x160|240x280|240x320|320x320)\)/', $agent)) {
322: $this->setMobile(true);
323: }
324:
325: if ($this->_majorVersion >= 7) {
326: if ($this->_majorVersion >= 8) {
327: $this->setFeature('xmlhttpreq');
328: $this->setFeature('javascript', 1.5);
329: }
330: if ($this->_majorVersion >= 9) {
331: $this->setFeature('dataurl', 4100);
332: if ($this->_minorVersion >= 5) {
333: $this->setFeature('ajax');
334: $this->setFeature('rte');
335: }
336: }
337: $this->setFeature('dom');
338: $this->setFeature('iframes');
339: $this->setFeature('accesskey');
340: $this->setFeature('optgroup');
341: $this->setQuirk('double_linebreak_textarea');
342: }
343: } elseif (strpos($lowerAgent, 'elaine/') !== false ||
344: strpos($lowerAgent, 'palmsource') !== false ||
345: strpos($lowerAgent, 'digital paths') !== false) {
346: $this->setBrowser('palm');
347: $this->setFeature('images', false);
348: $this->setFeature('frames', false);
349: $this->setFeature('javascript', false);
350: $this->setQuirk('avoid_popup_windows');
351: $this->setMobile(true);
352: } elseif ((preg_match('|MSIE ([0-9.]+)|', $agent, $version)) ||
353: (preg_match('|Internet Explorer/([0-9.]+)|', $agent, $version))) {
354: $this->setBrowser('msie');
355: $this->setQuirk('cache_ssl_downloads');
356: $this->setQuirk('cache_same_url');
357: $this->setQuirk('break_disposition_filename');
358:
359: if (strpos($version[1], '.') !== false) {
360: list($this->_majorVersion, $this->_minorVersion) = explode('.', $version[1]);
361: } else {
362: $this->_majorVersion = $version[1];
363: $this->_minorVersion = 0;
364: }
365:
366: 367:
368: if (($this->_majorVersion < 7) &&
369: preg_match('/windows/i', $agent)) {
370: $this->setQuirk('png_transparency');
371: }
372:
373: 374: 375:
376: if (preg_match('/; (120x160|240x280|240x320|320x320)\)/', $agent)) {
377: $this->setMobile(true);
378: }
379:
380: $this->setFeature('xmlhttpreq');
381:
382: switch ($this->_majorVersion) {
383: default:
384: case 10:
385: case 9:
386: case 8:
387: case 7:
388: $this->setFeature('javascript', 1.4);
389: $this->setFeature('ajax');
390: $this->setFeature('dom');
391: $this->setFeature('iframes');
392: $this->setFeature('utf');
393: $this->setFeature('rte');
394: $this->setFeature('homepage');
395: $this->setFeature('accesskey');
396: $this->setFeature('optgroup');
397: if ($this->_majorVersion != 7) {
398: $this->setFeature('cite');
399: $this->setFeature('dataurl', ($this->_majorVersion == 8) ? 32768 : true);
400: }
401: break;
402:
403: case 6:
404: $this->setFeature('javascript', 1.4);
405: $this->setFeature('dom');
406: $this->setFeature('iframes');
407: $this->setFeature('utf');
408: $this->setFeature('rte');
409: $this->setFeature('homepage');
410: $this->setFeature('accesskey');
411: $this->setFeature('optgroup');
412: $this->setQuirk('scrollbar_in_way');
413: $this->setQuirk('broken_multipart_form');
414: $this->setQuirk('windowed_controls');
415: break;
416:
417: case 5:
418: if ($this->getPlatform() == 'mac') {
419: $this->setFeature('javascript', 1.2);
420: $this->setFeature('optgroup');
421: $this->setFeature('xmlhttpreq', false);
422: } else {
423:
424: $this->setFeature('javascript', 1.4);
425: $this->setFeature('dom');
426: if ($this->_minorVersion >= 5) {
427: $this->setFeature('rte');
428: $this->setQuirk('windowed_controls');
429: }
430: }
431: $this->setFeature('iframes');
432: $this->setFeature('utf');
433: $this->setFeature('homepage');
434: $this->setFeature('accesskey');
435: if ($this->_minorVersion == 5) {
436: $this->setQuirk('break_disposition_header');
437: $this->setQuirk('broken_multipart_form');
438: }
439: break;
440:
441: case 4:
442: $this->setFeature('javascript', 1.2);
443: $this->setFeature('accesskey');
444: $this->setFeature('xmlhttpreq', false);
445: if ($this->_minorVersion > 0) {
446: $this->setFeature('utf');
447: }
448: break;
449:
450: case 3:
451: $this->setFeature('javascript', 1.1);
452: $this->setQuirk('avoid_popup_windows');
453: $this->setFeature('xmlhttpreq', false);
454: break;
455: }
456: } elseif (preg_match('|ANTFresco/([0-9]+)|', $agent, $version)) {
457: $this->setBrowser('fresco');
458: $this->setFeature('javascript', 1.1);
459: $this->setQuirk('avoid_popup_windows');
460: } elseif (strpos($lowerAgent, 'avantgo') !== false) {
461: $this->setBrowser('avantgo');
462: $this->setMobile(true);
463: } elseif (preg_match('|Konqueror/([0-9]+)\.?([0-9]+)?|', $agent, $version) ||
464: preg_match('|Safari/([0-9]+)\.?([0-9]+)?|', $agent, $version)) {
465: $this->setBrowser('webkit');
466: $this->setQuirk('empty_file_input_value');
467: $this->setQuirk('no_hidden_overflow_tables');
468: $this->setFeature('dataurl');
469:
470: if (strpos($agent, 'Mobile') !== false ||
471: strpos($agent, 'Android') !== false ||
472: strpos($agent, 'SAMSUNG-GT') !== false ||
473: ((strpos($agent, 'Nokia') !== false ||
474: strpos($agent, 'Symbian') !== false) &&
475: strpos($agent, 'WebKit') !== false) ||
476: (strpos($agent, 'N900') !== false &&
477: strpos($agent, 'Maemo Browser') !== false) ||
478: (strpos($agent, 'MeeGo') !== false &&
479: strpos($agent, 'NokiaN9') !== false)) {
480:
481: $this->setFeature('frames', false);
482: $this->setFeature('javascript');
483: $this->setQuirk('avoid_popup_windows');
484: $this->setMobile(true);
485: }
486:
487: $this->_majorVersion = $version[1];
488: if (isset($version[2])) {
489: $this->_minorVersion = $version[2];
490: }
491:
492: if (stripos($agent, 'Chrome/') !== false) {
493:
494: $this->setFeature('ischrome');
495: $this->setFeature('rte');
496: $this->setFeature('utf');
497: $this->setFeature('javascript', 1.4);
498: $this->setFeature('ajax');
499: $this->setFeature('dom');
500: $this->setFeature('iframes');
501: $this->setFeature('accesskey');
502: $this->setFeature('xmlhttpreq');
503: $this->setQuirk('empty_file_input_value', 0);
504:
505: if (preg_match('|Chrome/([0-9.]+)|i', $agent, $version_string)) {
506: list($this->_majorVersion, $this->_minorVersion) = explode('.', $version_string[1], 2);
507: }
508: } elseif (stripos($agent, 'Safari/') !== false &&
509: $this->_majorVersion >= 60) {
510:
511: $this->setFeature('issafari');
512:
513:
514:
515: if (preg_match('|Version/([0-9.]+)|', $agent, $version_string)) {
516: list($this->_majorVersion, $this->_minorVersion) = explode('.', $version_string[1], 2);
517: $this->_minorVersion = intval($this->_minorVersion);
518: $this->setFeature('ajax');
519: $this->setFeature('rte');
520: } elseif ($this->_majorVersion >= 412) {
521: $this->_majorVersion = 2;
522: $this->_minorVersion = 0;
523: } else {
524: if ($this->_majorVersion >= 312) {
525: $this->_minorVersion = 3;
526: } elseif ($this->_majorVersion >= 124) {
527: $this->_minorVersion = 2;
528: } else {
529: $this->_minorVersion = 0;
530: }
531: $this->_majorVersion = 1;
532: }
533:
534: $this->setFeature('utf');
535: $this->setFeature('javascript', 1.4);
536: $this->setFeature('dom');
537: $this->setFeature('iframes');
538: if ($this->_majorVersion > 1 || $this->_minorVersion > 2) {
539:
540: $this->setFeature('accesskey');
541: $this->setFeature('xmlhttpreq');
542: }
543: } else {
544:
545: $this->setFeature('javascript', 1.1);
546: $this->setFeature('iskonqueror');
547: switch ($this->_majorVersion) {
548: case 4:
549: case 3:
550: $this->setFeature('dom');
551: $this->setFeature('iframes');
552: if ($this->_minorVersion >= 5 ||
553: $this->_majorVersion == 4) {
554: $this->setFeature('accesskey');
555: $this->setFeature('xmlhttpreq');
556: }
557: break;
558: }
559: }
560: } elseif (preg_match('|Mozilla/([0-9.]+)|', $agent, $version)) {
561: $this->setBrowser('mozilla');
562: $this->setQuirk('must_cache_forms');
563:
564: list($this->_majorVersion, $this->_minorVersion) = explode('.', $version[1]);
565: switch ($this->_majorVersion) {
566: default:
567: case 5:
568: if ($this->getPlatform() == 'win') {
569: $this->setQuirk('break_disposition_filename');
570: }
571: $this->setFeature('javascript', 1.4);
572: $this->setFeature('ajax');
573: $this->setFeature('dom');
574: $this->setFeature('accesskey');
575: $this->setFeature('optgroup');
576: $this->setFeature('xmlhttpreq');
577: $this->setFeature('cite');
578: if (preg_match('|rv:(.*)\)|', $agent, $revision)) {
579: if (version_compare($revision[1], '1', '>=')) {
580: $this->setFeature('iframes');
581: }
582: if (version_compare($revision[1], '1.3', '>=')) {
583: $this->setFeature('rte');
584: }
585: if (version_compare($revision[1], '1.8.1', '>=')) {
586: $this->setFeature('dataurl');
587: }
588: if (version_compare($revision[1], '10.0', '>=')) {
589: $this->setFeature('utf');
590: }
591: }
592: if (stripos($agent, 'mobile') !== false) {
593: $this->setMobile(true);
594: }
595: break;
596:
597: case 4:
598: $this->setFeature('javascript', 1.3);
599: $this->setQuirk('buggy_compression');
600: break;
601:
602: case 3:
603: case 2:
604: case 1:
605: case 0:
606: $this->setFeature('javascript', 1);
607: $this->setQuirk('buggy_compression');
608: break;
609: }
610: } elseif (preg_match('|Lynx/([0-9]+)|', $agent, $version)) {
611: $this->setBrowser('lynx');
612: $this->setFeature('images', false);
613: $this->setFeature('frames', false);
614: $this->setFeature('javascript', false);
615: $this->setQuirk('avoid_popup_windows');
616: } elseif (preg_match('|Links \(([0-9]+)|', $agent, $version)) {
617: $this->setBrowser('links');
618: $this->setFeature('images', false);
619: $this->setFeature('frames', false);
620: $this->setFeature('javascript', false);
621: $this->setQuirk('avoid_popup_windows');
622: } elseif (preg_match('|HotJava/([0-9]+)|', $agent, $version)) {
623: $this->setBrowser('hotjava');
624: $this->setFeature('javascript', false);
625: } elseif (strpos($agent, 'UP/') !== false ||
626: strpos($agent, 'UP.B') !== false ||
627: strpos($agent, 'UP.L') !== false) {
628: $this->setBrowser('up');
629: $this->setFeature('html', false);
630: $this->setFeature('javascript', false);
631: $this->setFeature('hdml');
632: $this->setFeature('wml');
633:
634: if (strpos($agent, 'GUI') !== false &&
635: strpos($agent, 'UP.Link') !== false) {
636: 637: 638:
639: $this->setQuirk('ow_gui_1.3');
640: }
641: $this->setMobile(true);
642: } elseif (strpos($agent, 'Xiino/') !== false) {
643: $this->setBrowser('xiino');
644: $this->setFeature('hdml');
645: $this->setFeature('wml');
646: $this->setMobile(true);
647: } elseif (strpos($agent, 'Palmscape/') !== false) {
648: $this->setBrowser('palmscape');
649: $this->setFeature('javascript', false);
650: $this->setFeature('hdml');
651: $this->setFeature('wml');
652: $this->setMobile(true);
653: } elseif (strpos($agent, 'Nokia') !== false) {
654: $this->setBrowser('nokia');
655: $this->setFeature('html', false);
656: $this->setFeature('wml');
657: $this->setFeature('xhtml');
658: $this->setMobile(true);
659: } elseif (strpos($agent, 'Ericsson') !== false) {
660: $this->setBrowser('ericsson');
661: $this->setFeature('html', false);
662: $this->setFeature('wml');
663: $this->setMobile(true);
664: } elseif (strpos($agent, 'Grundig') !== false) {
665: $this->setBrowser('grundig');
666: $this->setFeature('xhtml');
667: $this->setFeature('wml');
668: $this->setMobile(true);
669: } elseif (strpos($agent, 'NetFront') !== false) {
670: $this->setBrowser('netfront');
671: $this->setFeature('xhtml');
672: $this->setFeature('wml');
673: $this->setMobile(true);
674: } elseif (strpos($lowerAgent, 'wap') !== false) {
675: $this->setBrowser('wap');
676: $this->setFeature('html', false);
677: $this->setFeature('javascript', false);
678: $this->setFeature('hdml');
679: $this->setFeature('wml');
680: $this->setMobile(true);
681: } elseif (strpos($lowerAgent, 'docomo') !== false ||
682: strpos($lowerAgent, 'portalmmm') !== false) {
683: $this->setBrowser('imode');
684: $this->setFeature('images', false);
685: $this->setMobile(true);
686: } elseif (preg_match('|BlackBerry.*?/([0-9.]+)|', $agent, $version)) {
687: list($this->_majorVersion, $this->_minorVersion) = explode('.', $version[1]);
688: $this->setBrowser('blackberry');
689: $this->setFeature('html', false);
690: $this->setFeature('javascript', false);
691: $this->setFeature('hdml');
692: $this->setFeature('wml');
693: $this->setMobile(true);
694: if ($this->_majorVersion >= 5 ||
695: ($this->_majorVersion == 4 && $this->_minorVersion >= 6)) {
696: $this->setFeature('ajax');
697: $this->setFeature('iframes');
698: $this->setFeature('javascript', 1.5);
699: $this->setFeature('dom');
700: $this->setFeature('xmlhttpreq');
701: }
702: } elseif (strpos($agent, 'MOT-') !== false) {
703: $this->setBrowser('motorola');
704: $this->setFeature('html', false);
705: $this->setFeature('javascript', false);
706: $this->setFeature('hdml');
707: $this->setFeature('wml');
708: $this->setMobile(true);
709: } elseif (strpos($lowerAgent, 'j-') !== false) {
710: $this->setBrowser('mml');
711: $this->setMobile(true);
712: }
713: }
714:
715: 716: 717: 718: 719: 720:
721: protected function _setPlatform()
722: {
723: if (strpos($this->_lowerAgent, 'wind') !== false) {
724: $this->_platform = 'win';
725: } elseif (strpos($this->_lowerAgent, 'mac') !== false) {
726: $this->_platform = 'mac';
727: } else {
728: $this->_platform = 'unix';
729: }
730: }
731:
732: 733: 734: 735: 736:
737: public function getPlatform()
738: {
739: return $this->_platform;
740: }
741:
742: 743: 744: 745: 746:
747: public function setBrowser($browser)
748: {
749: $this->_browser = $browser;
750: }
751:
752: 753: 754: 755: 756: 757: 758:
759: public function isBrowser($browser)
760: {
761: return ($this->_browser === $browser);
762: }
763:
764: 765: 766: 767: 768:
769: public function setMobile($mobile)
770: {
771: $this->_mobile = (bool)$mobile;
772: }
773:
774: 775: 776: 777: 778:
779: public function isMobile()
780: {
781: return $this->_mobile;
782: }
783:
784: 785: 786: 787: 788:
789: public function isRobot()
790: {
791: if (is_null($this->_robotAgentRegexp)) {
792: $regex = array();
793: foreach ($this->_robotAgents as $r) {
794: $regex[] = preg_quote($r, '/');
795: }
796: $this->_robotAgentRegexp = '/' . implode('|', $regex) . '/';
797: }
798:
799: return (bool)preg_match($this->_robotAgentRegexp, $this->_agent);
800: }
801:
802: 803: 804: 805: 806:
807: public function getBrowser()
808: {
809: return $this->_browser;
810: }
811:
812: 813: 814: 815: 816:
817: public function getMajor()
818: {
819: return $this->_majorVersion;
820: }
821:
822: 823: 824: 825: 826:
827: public function getMinor()
828: {
829: return $this->_minorVersion;
830: }
831:
832: 833: 834: 835: 836:
837: public function getVersion()
838: {
839: return $this->_majorVersion . '.' . $this->_minorVersion;
840: }
841:
842: 843: 844: 845: 846:
847: public function getAgentString()
848: {
849: return $this->_agent;
850: }
851:
852: 853: 854: 855: 856: 857: 858: 859: 860: 861: 862: 863: 864: 865: 866: 867: 868: 869: 870: 871: 872: 873: 874:
875: public function setQuirk($quirk, $value = true)
876: {
877: if ($value) {
878: $this->_quirks[$quirk] = $value;
879: } else {
880: unset($this->_quirks[$quirk]);
881: }
882: }
883:
884: 885: 886: 887: 888: 889: 890:
891: public function hasQuirk($quirk)
892: {
893: return !empty($this->_quirks[$quirk]);
894: }
895:
896: 897: 898: 899: 900: 901: 902:
903: public function getQuirk($quirk)
904: {
905: return isset($this->_quirks[$quirk])
906: ? $this->_quirks[$quirk]
907: : null;
908: }
909:
910: 911: 912: 913: 914: 915: 916: 917: 918: 919: 920: 921: 922: 923: 924: 925: 926: 927: 928: 929: 930: 931: 932: 933: 934: 935: 936: 937:
938: public function setFeature($feature, $value = true)
939: {
940: if ($value) {
941: $this->_features[$feature] = $value;
942: } else {
943: unset($this->_features[$feature]);
944: }
945: }
946:
947: 948: 949: 950: 951: 952: 953:
954: public function hasFeature($feature)
955: {
956: return !empty($this->_features[$feature]);
957: }
958:
959: 960: 961: 962: 963: 964: 965:
966: public function getFeature($feature)
967: {
968: return isset($this->_features[$feature])
969: ? $this->_features[$feature]
970: : null;
971: }
972:
973: 974: 975: 976: 977:
978: public function usingSSLConnection()
979: {
980: return ((isset($_SERVER['HTTPS']) &&
981: ($_SERVER['HTTPS'] == 'on')) ||
982: getenv('SSL_PROTOCOL_VERSION'));
983: }
984:
985: 986: 987: 988: 989:
990: public function getHTTPProtocol()
991: {
992: return (isset($_SERVER['SERVER_PROTOCOL']) && ($pos = strrpos($_SERVER['SERVER_PROTOCOL'], '/')))
993: ? substr($_SERVER['SERVER_PROTOCOL'], $pos + 1)
994: : null;
995: }
996:
997: 998: 999: 1000: 1001:
1002: public function getIPAddress()
1003: {
1004: return empty($_SERVER['HTTP_X_FORWARDED_FOR'])
1005: ? $_SERVER['REMOTE_ADDR']
1006: : $_SERVER['HTTP_X_FORWARDED_FOR'];
1007: }
1008:
1009: 1010: 1011: 1012: 1013: 1014: 1015:
1016: public static function allowFileUploads()
1017: {
1018: if (!ini_get('file_uploads') ||
1019: (($dir = ini_get('upload_tmp_dir')) &&
1020: !is_writable($dir))) {
1021: return 0;
1022: }
1023:
1024: $filesize = ini_get('upload_max_filesize');
1025: switch (strtolower(substr($filesize, -1, 1))) {
1026: case 'k':
1027: $filesize = intval(floatval($filesize) * 1024);
1028: break;
1029:
1030: case 'm':
1031: $filesize = intval(floatval($filesize) * 1024 * 1024);
1032: break;
1033:
1034: case 'g':
1035: $filesize = intval(floatval($filesize) * 1024 * 1024 * 1024);
1036: break;
1037:
1038: default:
1039: $filesize = intval($filesize);
1040: break;
1041: }
1042:
1043: $postsize = ini_get('post_max_size');
1044: switch (strtolower(substr($postsize, -1, 1))) {
1045: case 'k':
1046: $postsize = intval(floatval($postsize) * 1024);
1047: break;
1048:
1049: case 'm':
1050: $postsize = intval(floatval($postsize) * 1024 * 1024);
1051: break;
1052:
1053: case 'g':
1054: $postsize = intval(floatval($postsize) * 1024 * 1024 * 1024);
1055: break;
1056:
1057: default:
1058: $postsize = intval($postsize);
1059: break;
1060: }
1061:
1062: return min($filesize, $postsize);
1063: }
1064:
1065: 1066: 1067: 1068: 1069: 1070: 1071: 1072: 1073: 1074: 1075:
1076: public function wasFileUploaded($field, $name = null)
1077: {
1078: if (is_null($name)) {
1079: $name = 'file';
1080: }
1081:
1082: if (!($uploadSize = self::allowFileUploads())) {
1083: throw new Horde_Browser_Exception(Horde_Browser_Translation::t("File uploads not supported."));
1084: }
1085:
1086:
1087: $index = Horde_Array::getArrayParts($field, $base, $keys);
1088:
1089: if ($index) {
1090:
1091: $keys_path = array_merge(array($base, 'error'), $keys);
1092: $error = Horde_Array::getElement($_FILES, $keys_path);
1093:
1094:
1095: $keys_path = array_merge(array($base, 'tmp_name'), $keys);
1096: $tmp_name = Horde_Array::getElement($_FILES, $keys_path);
1097: } else {
1098:
1099: if (!isset($_FILES[$field])) {
1100: throw new Horde_Browser_Exception(Horde_Browser_Translation::t("No file uploaded"), UPLOAD_ERR_NO_FILE);
1101: }
1102: $error = $_FILES[$field]['error'];
1103: $tmp_name = $_FILES[$field]['tmp_name'];
1104: }
1105:
1106: if (empty($_FILES) || ($error == UPLOAD_ERR_NO_FILE)) {
1107: throw new Horde_Browser_Exception(sprintf(Horde_Browser_Translation::t("There was a problem with the file upload: No %s was uploaded."), $name), UPLOAD_ERR_NO_FILE);
1108: } elseif (($error == UPLOAD_ERR_OK) && is_uploaded_file($tmp_name)) {
1109: if (!filesize($tmp_name)) {
1110: throw new Horde_Browser_Exception(Horde_Browser_Translation::t("The uploaded file appears to be empty. It may not exist on your computer."), UPLOAD_ERR_NO_FILE);
1111: }
1112:
1113: } elseif (($error == UPLOAD_ERR_INI_SIZE) ||
1114: ($error == UPLOAD_ERR_FORM_SIZE)) {
1115: throw new Horde_Browser_Exception(sprintf(Horde_Browser_Translation::t("There was a problem with the file upload: The %s was larger than the maximum allowed size (%d bytes)."), $name, min($uploadSize, Horde_Util::getFormData('MAX_FILE_SIZE'))), $error);
1116: } elseif ($error == UPLOAD_ERR_PARTIAL) {
1117: throw new Horde_Browser_Exception(sprintf(Horde_Browser_Translation::t("There was a problem with the file upload: The %s was only partially uploaded."), $name), $error);
1118: }
1119: }
1120:
1121: 1122: 1123: 1124: 1125: 1126: 1127: 1128:
1129: public function ($filename = 'unknown', $cType = null,
1130: $inline = false, $cLength = null)
1131: {
1132:
1133: $filename = str_replace(array("\r\n", "\r", "\n"), ' ', $filename);
1134:
1135:
1136: if ($this->hasQuirk('no_filename_spaces')) {
1137: $filename = strtr($filename, ' ', '_');
1138: }
1139:
1140: 1141:
1142: if ($this->isBrowser('msie')) {
1143: if (($pos = strrpos($filename, '.'))) {
1144: $filename = strtr(substr($filename, 0, $pos), '.', '_') . substr($filename, $pos);
1145: }
1146:
1147:
1148: $filename = rawurlencode($filename);
1149: }
1150:
1151:
1152: if ($inline) {
1153: if (!is_null($cType)) {
1154: header('Content-Type: ' . trim($cType));
1155: } elseif ($this->isBrowser('msie')) {
1156: header('Content-Type: application/x-msdownload');
1157: } else {
1158: header('Content-Type: application/octet-stream');
1159: }
1160: header('Content-Disposition: inline; filename="' . $filename . '"');
1161: } else {
1162: if ($this->isBrowser('msie')) {
1163: header('Content-Type: application/x-msdownload');
1164: } elseif (!is_null($cType)) {
1165: header('Content-Type: ' . trim($cType));
1166: } else {
1167: header('Content-Type: application/octet-stream');
1168: }
1169:
1170: if ($this->hasQuirk('break_disposition_header')) {
1171: header('Content-Disposition: filename="' . $filename . '"');
1172: } else {
1173: header('Content-Disposition: attachment; filename="' . $filename . '"');
1174: }
1175: }
1176:
1177: 1178:
1179: if (!is_null($cLength) &&
1180: !in_array('ob_gzhandler', ob_list_handlers())) {
1181: header('Content-Length: ' . $cLength);
1182: }
1183:
1184:
1185: if ($this->hasQuirk('cache_ssl_downloads')) {
1186: header('Expires: 0');
1187: header('Cache-Control: must-revalidate');
1188: header('Pragma: public');
1189: }
1190: }
1191:
1192: 1193: 1194: 1195: 1196: 1197: 1198:
1199: public function isViewable($mimetype)
1200: {
1201: $mimetype = Horde_String::lower($mimetype);
1202: list($type, $subtype) = explode('/', $mimetype);
1203:
1204: if (!empty($this->_accept)) {
1205: $wildcard_match = false;
1206:
1207: if (strpos($this->_accept, $mimetype) !== false) {
1208: return true;
1209: }
1210:
1211: if (strpos($this->_accept, '*/*') !== false) {
1212: $wildcard_match = true;
1213: if ($type != 'image') {
1214: return true;
1215: }
1216: }
1217:
1218: 1219: 1220:
1221: if ($this->isBrowser('mozilla') &&
1222: ($mimetype == 'image/pjpeg') &&
1223: (strpos($this->_accept, 'image/jpeg') !== false)) {
1224: return true;
1225: }
1226:
1227: if (!$wildcard_match) {
1228: return false;
1229: }
1230: }
1231:
1232: if (!$this->hasFeature('images') || ($type != 'image')) {
1233: return false;
1234: }
1235:
1236: return in_array($subtype, $this->_images);
1237: }
1238:
1239: }
1240: