[BUGFIX] ClientUtility does not detect Internet Explorer 11
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Utility / ClientUtility.php
1 <?php
2 namespace TYPO3\CMS\Core\Utility;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2009-2013 Oliver Hader <oliver@typo3.org>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Class to handle and determine browser specific information.
31 *
32 * @author Oliver Hader <oliver@typo3.org>
33 */
34 class ClientUtility {
35
36 /**
37 * Generates an array with abstracted browser information
38 *
39 * @param string $userAgent The useragent string, \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('HTTP_USER_AGENT')
40 * @return array Contains keys "browser", "version", "system
41 */
42 static public function getBrowserInfo($userAgent) {
43 // Hook: $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/div/class.t3lib_utility_client.php']['getBrowserInfo']:
44 $getBrowserInfoHooks = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/div/class.t3lib_utility_client.php']['getBrowserInfo'];
45 if (is_array($getBrowserInfoHooks)) {
46 foreach ($getBrowserInfoHooks as $hookFunction) {
47 $returnResult = TRUE;
48 $hookParameters = array(
49 'userAgent' => &$userAgent,
50 'returnResult' => &$returnResult
51 );
52 // need reference for third parameter in \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction,
53 // so create a reference to NULL
54 $null = NULL;
55 $hookResult = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($hookFunction, $hookParameters, $null);
56 if ($returnResult && is_array($hookResult) && count($hookResult)) {
57 return $hookResult;
58 }
59 }
60 }
61 $userAgent = trim($userAgent);
62 $browserInfo = array(
63 'useragent' => $userAgent
64 );
65 // Analyze the userAgent string
66 // Declare known browsers to look for
67 $known = array(
68 'msie',
69 'firefox',
70 'webkit',
71 'opera',
72 'netscape',
73 'konqueror',
74 'gecko',
75 'chrome',
76 'safari',
77 'seamonkey',
78 'navigator',
79 'mosaic',
80 'lynx',
81 'amaya',
82 'omniweb',
83 'avant',
84 'camino',
85 'flock',
86 'aol'
87 );
88 $matches = array();
89 $pattern = '#(?P<browser>' . join('|', $known) . ')[/ ]+(?P<version>[0-9]+(?:\\.[0-9]+)?)#';
90 // Find all phrases (or return empty array if none found)
91 if (!preg_match_all($pattern, strtolower($userAgent), $matches)) {
92 // Microsoft Internet-Explorer 11 does not have a sign of "MSIE" or so in the useragent.
93 // All checks from the pattern above fail here. Look for a special combination of
94 // "Mozilla/5.0" in front, "Trident/7.0" in the middle and "like Gecko" at the end.
95 // The version (revision) is given as "; rv:11.0" in the useragent then.
96 unset($matches);
97 $pattern = '#mozilla/5\\.0 \\(.*trident/7\\.0.*; rv:(?P<version>[0-9]+(?:\\.[0-9]+)?)\\) like gecko#i';
98 if (preg_match_all($pattern, $userAgent, $matches)) {
99 $browserInfo['browser'] = 'msie';
100 $browserInfo['version'] = $matches['version'][0];
101 $browserInfo['all'] = array('msie' => $matches['version'][0]);
102 } else {
103 $browserInfo['browser'] = 'unknown';
104 $browserInfo['version'] = '';
105 $browserInfo['all'] = array();
106 }
107 } else {
108 // Since some UAs have more than one phrase (e.g Firefox has a Gecko phrase,
109 // Opera 7,8 have a MSIE phrase), use the last one found (the right-most one
110 // in the UA). That's usually the most correct.
111 // For IE use the first match as IE sends multiple MSIE with version, from higher to lower.
112 $lastIndex = count($matches['browser']) - 1;
113 $browserInfo['browser'] = $matches['browser'][$lastIndex];
114 $browserInfo['version'] = $browserInfo['browser'] === 'msie' ? $matches['version'][0] : $matches['version'][$lastIndex];
115 // But return all parsed browsers / version in an extra array
116 $browserInfo['all'] = array();
117 for ($i = 0; $i <= $lastIndex; $i++) {
118 if (!isset($browserInfo['all'][$matches['browser'][$i]])) {
119 $browserInfo['all'][$matches['browser'][$i]] = $matches['version'][$i];
120 }
121 }
122 // Replace gecko build date with version given by rv
123 if (isset($browserInfo['all']['gecko'])) {
124 preg_match_all('/rv:([0-9\\.]*)/', strtolower($userAgent), $version);
125 if ($version[1][0]) {
126 $browserInfo['all']['gecko'] = $version[1][0];
127 }
128 }
129 }
130 $browserInfo['all_systems'] = array();
131 if (strstr($userAgent, 'Win')) {
132 // Windows
133 if (strstr($userAgent, 'Windows NT 6.2') || strstr($userAgent, 'Windows NT 6.3')) {
134 $browserInfo['all_systems'][] = 'win8';
135 $browserInfo['all_systems'][] = 'winNT';
136 } elseif (strstr($userAgent, 'Windows NT 6.1')) {
137 $browserInfo['all_systems'][] = 'win7';
138 $browserInfo['all_systems'][] = 'winNT';
139 } elseif (strstr($userAgent, 'Windows NT 6.0')) {
140 $browserInfo['all_systems'][] = 'winVista';
141 $browserInfo['all_systems'][] = 'winNT';
142 } elseif (strstr($userAgent, 'Windows NT 5.1')) {
143 $browserInfo['all_systems'][] = 'winXP';
144 $browserInfo['all_systems'][] = 'winNT';
145 } elseif (strstr($userAgent, 'Windows NT 5.0')) {
146 $browserInfo['all_systems'][] = 'win2k';
147 $browserInfo['all_systems'][] = 'winNT';
148 } elseif (strstr($userAgent, 'Win98') || strstr($userAgent, 'Windows 98')) {
149 $browserInfo['all_systems'][] = 'win98';
150 } elseif (strstr($userAgent, 'Win95') || strstr($userAgent, 'Windows 95')) {
151 $browserInfo['all_systems'][] = 'win95';
152 } elseif (strstr($userAgent, 'WinNT') || strstr($userAgent, 'Windows NT')) {
153 $browserInfo['all_systems'][] = 'winNT';
154 } elseif (strstr($userAgent, 'Win16') || strstr($userAgent, 'Windows 311')) {
155 $browserInfo['all_systems'][] = 'win311';
156 }
157 } elseif (strstr($userAgent, 'Mac')) {
158 if (strstr($userAgent, 'iPad') || strstr($userAgent, 'iPhone') || strstr($userAgent, 'iPod')) {
159 $browserInfo['all_systems'][] = 'iOS';
160 $browserInfo['all_systems'][] = 'mac';
161 } else {
162 $browserInfo['all_systems'][] = 'mac';
163 }
164 } elseif (strstr($userAgent, 'Android')) {
165 $browserInfo['all_systems'][] = 'android';
166 $browserInfo['all_systems'][] = 'linux';
167 } elseif (strstr($userAgent, 'Linux')) {
168 $browserInfo['all_systems'][] = 'linux';
169 } elseif (strstr($userAgent, 'BSD')) {
170 $browserInfo['all_systems'][] = 'unix_bsd';
171 } elseif (strstr($userAgent, 'SGI') && strstr($userAgent, ' IRIX ')) {
172 $browserInfo['all_systems'][] = 'unix_sgi';
173 } elseif (strstr($userAgent, ' SunOS ')) {
174 $browserInfo['all_systems'][] = 'unix_sun';
175 } elseif (strstr($userAgent, ' HP-UX ')) {
176 $browserInfo['all_systems'][] = 'unix_hp';
177 } elseif (strstr($userAgent, 'CrOS')) {
178 $browserInfo['all_systems'][] = 'chrome';
179 $browserInfo['all_systems'][] = 'linux';
180 }
181 return $browserInfo;
182 }
183
184 /**
185 * Returns the version of a browser; Basically getting doubleval() of the input string,
186 * stripping of any non-numeric values in the beginning of the string first.
187 *
188 * @param string $version A string with version number, eg. "/7.32 blablabla
189 * @return double Returns double value, eg. "7.32
190 */
191 static public function getVersion($version) {
192 return doubleval(preg_replace('/^[^0-9]*/', '', $version));
193 }
194
195 /**
196 * Gets a code for a browsing device based on the input useragent string.
197 *
198 * @param string $userAgent The useragent string, \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('HTTP_USER_AGENT')
199 * @return string Code for the specific device type
200 */
201 static public function getDeviceType($userAgent) {
202 // Hook: $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/div/class.t3lib_utility_client.php']['getDeviceType']:
203 $getDeviceTypeHooks = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/div/class.t3lib_utility_client.php']['getDeviceType'];
204 if (is_array($getDeviceTypeHooks)) {
205 foreach ($getDeviceTypeHooks as $hookFunction) {
206 $returnResult = TRUE;
207 $hookParameters = array(
208 'userAgent' => &$userAgent,
209 'returnResult' => &$returnResult
210 );
211 // need reference for third parameter in \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction,
212 // so create a reference to NULL
213 $null = NULL;
214 $hookResult = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($hookFunction, $hookParameters, $null);
215 if ($returnResult && is_string($hookResult) && !empty($hookResult)) {
216 return $hookResult;
217 }
218 }
219 }
220 $userAgent = strtolower(trim($userAgent));
221 $deviceType = '';
222 // pda
223 if (strstr($userAgent, 'avantgo')) {
224 $deviceType = 'pda';
225 }
226 // wap
227 $browser = substr($userAgent, 0, 4);
228 $wapviwer = substr(stristr($userAgent, 'wap'), 0, 3);
229 if ($wapviwer == 'wap' || $browser == 'noki' || $browser == 'eric' || $browser == 'r380' || $browser == 'up.b' || $browser == 'winw' || $browser == 'wapa') {
230 $deviceType = 'wap';
231 }
232 // grabber
233 if (strstr($userAgent, 'g.r.a.b.') || strstr($userAgent, 'utilmind httpget') || strstr($userAgent, 'webcapture') || strstr($userAgent, 'teleport') || strstr($userAgent, 'webcopier')) {
234 $deviceType = 'grabber';
235 }
236 // robots
237 if (strstr($userAgent, 'crawler') || strstr($userAgent, 'spider') || strstr($userAgent, 'googlebot') || strstr($userAgent, 'searchbot') || strstr($userAgent, 'infoseek') || strstr($userAgent, 'altavista') || strstr($userAgent, 'diibot')) {
238 $deviceType = 'robot';
239 }
240 return $deviceType;
241 }
242
243 }