PluginProbe
Team Showcase / 1.13
Team Showcase v1.13
trunk 1.0 1.1 1.11 1.13 1.14 1.15 1.16 1.17 1.18 1.19 1.2 1.20 1.21 1.21.1 1.21.2 1.21.3 1.21.4 1.21.5 1.22.0 1.22.1 1.22.10 1.22.12 1.22.13 1.22.14 All 49 releases
team / includes / Mobile_Detect.php

Mobile_Detect.php in Team Showcase 1.13, at includes/Mobile_Detect.php

1,435 lines 78.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Mobile Detect Library
4 * =====================
5 *
6 * Motto: "Every business should have a mobile detection script to detect mobile readers"
7 *
8 * Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets).
9 * It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.
10 *
11 * @author Current authors: Serban Ghita <serbanghita@gmail.com>
12 * Nick Ilyin <nick.ilyin@gmail.com>
13 *
14 * Original author: Victor Stanciu <vic.stanciu@gmail.com>
15 *
16 * @license Code and contributions have 'MIT License'
17 * More details: https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt
18 *
19 * @link Homepage: http://mobiledetect.net
20 * GitHub Repo: https://github.com/serbanghita/Mobile-Detect
21 * Google Code: http://code.google.com/p/php-mobile-detect/
22 * README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md
23 * HOWTO: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples
24 *
25 * @version 2.8.17
26 */
27 if(!class_exists('Mobile_Detect')){
28 class Mobile_Detect
29 {
30 /**
31 * Mobile detection type.
32 *
33 * @deprecated since version 2.6.9
34 */
35 const DETECTION_TYPE_MOBILE = 'mobile';
36
37 /**
38 * Extended detection type.
39 *
40 * @deprecated since version 2.6.9
41 */
42 const DETECTION_TYPE_EXTENDED = 'extended';
43
44 /**
45 * A frequently used regular expression to extract version #s.
46 *
47 * @deprecated since version 2.6.9
48 */
49 const VER = '([\w._\+]+)';
50
51 /**
52 * Top-level device.
53 */
54 const MOBILE_GRADE_A = 'A';
55
56 /**
57 * Mid-level device.
58 */
59 const MOBILE_GRADE_B = 'B';
60
61 /**
62 * Low-level device.
63 */
64 const MOBILE_GRADE_C = 'C';
65
66 /**
67 * Stores the version number of the current release.
68 */
69 const VERSION = '2.8.17';
70
71 /**
72 * A type for the version() method indicating a string return value.
73 */
74 const VERSION_TYPE_STRING = 'text';
75
76 /**
77 * A type for the version() method indicating a float return value.
78 */
79 const VERSION_TYPE_FLOAT = 'float';
80
81 /**
82 * A cache for resolved matches
83 * @var array
84 */
85 protected $cache = array();
86
87 /**
88 * The User-Agent HTTP header is stored in here.
89 * @var string
90 */
91 protected $userAgent = null;
92
93 /**
94 * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE.
95 * @var array
96 */
97 protected $httpHeaders = array();
98
99 /**
100 * CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer.
101 * @var array
102 */
103 protected $cloudfrontHeaders = array();
104
105 /**
106 * The matching Regex.
107 * This is good for debug.
108 * @var string
109 */
110 protected $matchingRegex = null;
111
112 /**
113 * The matches extracted from the regex expression.
114 * This is good for debug.
115 * @var string
116 */
117 protected $matchesArray = null;
118
119 /**
120 * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED.
121 *
122 * @deprecated since version 2.6.9
123 *
124 * @var string
125 */
126 protected $detectionType = self::DETECTION_TYPE_MOBILE;
127
128 /**
129 * HTTP headers that trigger the 'isMobile' detection
130 * to be true.
131 *
132 * @var array
133 */
134 protected static $mobileHeaders = array(
135
136 'HTTP_ACCEPT' => array('matches' => array(
137 // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
138 'application/x-obml2d',
139 // BlackBerry devices.
140 'application/vnd.rim.html',
141 'text/vnd.wap.wml',
142 'application/vnd.wap.xhtml+xml'
143 )),
144 'HTTP_X_WAP_PROFILE' => null,
145 'HTTP_X_WAP_CLIENTID' => null,
146 'HTTP_WAP_CONNECTION' => null,
147 'HTTP_PROFILE' => null,
148 // Reported by Opera on Nokia devices (eg. C3).
149 'HTTP_X_OPERAMINI_PHONE_UA' => null,
150 'HTTP_X_NOKIA_GATEWAY_ID' => null,
151 'HTTP_X_ORANGE_ID' => null,
152 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
153 'HTTP_X_HUAWEI_USERID' => null,
154 // Reported by Windows Smartphones.
155 'HTTP_UA_OS' => null,
156 // Reported by Verizon, Vodafone proxy system.
157 'HTTP_X_MOBILE_GATEWAY' => null,
158 // Seen this on HTC Sensation. SensationXE_Beats_Z715e.
159 'HTTP_X_ATT_DEVICEID' => null,
160 // Seen this on a HTC.
161 'HTTP_UA_CPU' => array('matches' => array('ARM')),
162 );
163
164 /**
165 * List of mobile devices (phones).
166 *
167 * @var array
168 */
169 protected static $phoneDevices = array(
170 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes
171 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+',
172 'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m',
173 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6',
174 // @todo: Is 'Dell Streak' a tablet or a phone? ;)
175 'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
176 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b',
177 'Samsung' => 'Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205',
178 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802)',
179 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533',
180 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile',
181 // http://www.micromaxinfo.com/mobiles/smartphones
182 // Added because the codes might conflict with Acer Tablets.
183 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b',
184 // @todo Complete the regex.
185 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ;
186 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;)
187 // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
188 // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
189 'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790',
190 // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
191 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
192 // http://fr.wikomobile.com
193 'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM',
194 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)',
195 // Added simvalley mobile just for fun. They have some interesting devices.
196 // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html
197 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b',
198 // Wolfgang - a brand that is sold by Aldi supermarkets.
199 // http://www.wolfgangmobile.com/
200 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q',
201 'Alcatel' => 'Alcatel',
202 'Nintendo' => 'Nintendo 3DS',
203 // http://en.wikipedia.org/wiki/Amoi
204 'Amoi' => 'Amoi',
205 // http://en.wikipedia.org/wiki/INQ
206 'INQ' => 'INQ',
207 // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
208 'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser',
209 );
210
211 /**
212 * List of tablet devices.
213 *
214 * @var array
215 */
216 protected static $tabletDevices = array(
217 // @todo: check for mobile friendly emails topic.
218 'iPad' => 'iPad|iPad.*Mobile',
219 // Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
220 // @see #442
221 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
222 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T360|SM-T533', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
223 // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
224 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI)\b',
225 // Only the Surface tablets with Windows RT are considered mobile.
226 // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
227 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
228 // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT
229 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
230 // Watch out for PadFone, see #132.
231 // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/
232 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C',
233 'BlackBerryTablet' => 'PlayBook|RIM Tablet',
234 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
235 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
236 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
237 // http://www.acer.ro/ac/ro/RO/content/drivers
238 // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
239 // http://us.acer.com/ac/en/US/content/group/tablets
240 // http://www.acer.de/ac/de/DE/content/models/tablets/
241 // Can conflict with Micromax and Motorola phones codes.
242 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b',
243 // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
244 // http://us.toshiba.com/tablets/tablet-finder
245 // http://www.toshiba.co.jp/regza/tablet/
246 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
247 // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
248 // http://www.lg.com/us/tablets
249 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b',
250 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
251 // Prestigio Tablets http://www.prestigio.com/support
252 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002',
253 // http://support.lenovo.com/en_GB/downloads/default.page?#
254 'LenovoTablet' => 'Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)',
255 // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets
256 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7',
257 // http://www.yarvik.com/en/matrix/tablets/
258 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b',
259 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
260 'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2',
261 // http://www.intenso.de/kategorie_en.php?kategorie=33
262 // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate
263 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
264 // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/
265 'IRUTablet' => 'M702pro',
266 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
267 // http://www.e-boda.ro/tablete-pc.html
268 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
269 // http://www.allview.ro/produse/droseries/lista-tablete-pc/
270 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
271 // http://wiki.archosfans.com/index.php?title=Main_Page
272 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b',
273 // http://www.ainol.com/plugin.php?identifier=ainol&module=product
274 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
275 // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
276 // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
277 // http://www.sony.jp/support/tablet/
278 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31',
279 // http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8
280 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
281 // db + http://www.cube-tablet.com/buy-products.html
282 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
283 // http://www.cobyusa.com/?p=pcat&pcat_id=3001
284 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
285 // http://www.match.net.cn/products.asp
286 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733',
287 // http://www.msi.com/support
288 // @todo Research the Windows Tablets.
289 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b',
290 // @todo http://www.kyoceramobile.com/support/drivers/
291 // 'KyoceraTablet' => null,
292 // @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/
293 // 'IntextTablet' => null,
294 // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
295 // http://www.imp3.net/14/show.php?itemid=20454
296 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
297 // http://www.rock-chips.com/index.php?do=prod&pid=2
298 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
299 // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
300 'FlyTablet' => 'IQ310|Fly Vision',
301 // http://www.bqreaders.com/gb/tablets-prices-sale.html
302 'bqTablet' => 'Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus',
303 // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
304 // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
305 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim',
306 // Nec or Medias Tab
307 'NecTablet' => '\bN-06D|\bN-08D',
308 // Pantech Tablets: http://www.pantechusa.com/phones/
309 'PantechTablet' => 'Pantech.*P4100',
310 // Broncho Tablets: http://www.broncho.cn/ (hard to find)
311 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
312 // http://versusuk.com/support.html
313 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
314 // http://www.zync.in/index.php/our-products/tablet-phablets
315 'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900',
316 // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
317 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
318 // https://www.nabitablet.com/
319 'NabiTablet' => 'Android.*\bNabi',
320 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
321 // French Danew Tablets http://www.danew.com/produits-tablette.php
322 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
323 // Texet Tablets and Readers http://www.texet.ru/tablet/
324 'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE',
325 // Avoid detecting 'PLAYSTATION 3' as mobile.
326 'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
327 // http://www.trekstor.de/surftabs.html
328 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
329 // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets
330 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
331 // http://www.advandigital.com/index.php?link=content-product&jns=JP001
332 // because of the short codenames we have to include whitespaces to reduce the possible conflicts.
333 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ',
334 // http://www.danytech.com/category/tablet-pc
335 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1',
336 // http://www.galapad.net/product.html
337 'GalapadTablet' => 'Android.*\bG1\b',
338 // http://www.micromaxinfo.com/tablet/funbook
339 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
340 // http://www.karbonnmobiles.com/products_tablet.php
341 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
342 // http://www.myallfine.com/Products.asp
343 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
344 // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
345 'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b',
346 // http://www.yonesnav.com/products/products.php
347 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
348 // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
349 // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html)
350 'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503',
351 // http://www.gloryunion.cn/products.asp
352 // http://www.allwinnertech.com/en/apply/mobile.html
353 // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB)
354 // @todo: Softwiner tablets?
355 // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions.
356 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G
357 // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118
358 'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10',
359 // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/
360 // @todo: add more tests.
361 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)',
362 // http://hclmetablet.com/India/index.php
363 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync',
364 // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html
365 'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
366 // http://www.visture.com/index.asp
367 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
368 // http://www.mijncresta.nl/tablet
369 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
370 // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309
371 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
372 // Concorde tab
373 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
374 // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/
375 'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042',
376 // Modecom Tablets - http://www.modecom.eu/tablets/portal/
377 'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003',
378 // Vonino Tablets - http://www.vonino.eu/tablets
379 'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b',
380 // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0
381 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
382 // Storex Tablets - http://storex.fr/espace_client/support.html
383 // @note: no need to add all the tablet codes since they are guided by the first regex.
384 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
385 // Generic Vodafone tablets.
386 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7',
387 // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb
388 // Aka: http://www.essentielb.fr/
389 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
390 // Ross & Moor - http://ross-moor.ru/
391 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
392 // i-mobile http://product.i-mobilephone.com/Mobile_Device
393 'iMobileTablet' => 'i-mobile i-note',
394 // http://www.tolino.de/de/vergleichen/
395 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
396 // AudioSonic - a Kmart brand
397 // http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72&currentPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1
398 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
399 // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/
400 // @todo: add them gradually to avoid conflicts.
401 'AMPETablet' => 'Android.* A78 ',
402 // Skk Mobile - http://skkmobile.com.ph/product_tablets.php
403 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
404 // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1
405 'TecnoTablet' => 'TECNO P9',
406 // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3
407 'JXDTablet' => 'Android.*\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b',
408 // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/
409 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)',
410 // http://www.intracon.eu/tablet
411 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
412 // http://www.xoro.de/produkte/
413 // @note: Might be the same brand with 'Simply tablets'
414 'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151',
415 // http://www1.viewsonic.com/products/computing/tablets/
416 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
417 // http://www.odys.de/web/internet-tablet_en.html
418 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
419 // http://www.captiva-power.de/products.html#tablets-en
420 'CaptivaTablet' => 'CAPTIVA PAD',
421 // IconBIT - http://www.iconbit.com/products/tablets/
422 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S',
423 // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63
424 'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi',
425 // Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price
426 'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+',
427 'JaytechTablet' => 'TPC-PA762',
428 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
429 // http://www.digma.ru/support/download/
430 // @todo: Ebooks also (if requested)
431 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
432 // http://www.evolioshop.com/ro/tablete-pc.html
433 // http://www.evolio.ro/support/downloads_static.html?cat=2
434 // @todo: Research some more
435 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
436 // @todo http://www.lavamobiles.com/tablets-data-cards
437 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b',
438 // https://www.celkonmobiles.com/?_a=categoryphones&sid=2
439 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b',
440 // http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab
441 'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b',
442 // http://www.mi.com/en
443 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b',
444 // http://www.nbru.cn/index.html
445 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One',
446 // http://navroad.com/products/produkty/tablety/
447 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI',
448 // http://leader-online.com/new_site/product-category/tablets/
449 // http://www.leader-online.net.au/List/Tablet
450 'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100',
451 // http://www.datawind.com/ubislate/
452 'UbislateTablet' => 'UbiSlate[\s]?7C',
453 // http://www.pocketbook-int.com/ru/support
454 'PocketBookTablet' => 'Pocketbook',
455 // http://www.tesco.com/direct/hudl/
456 'Hudl' => 'Hudl HT7S3',
457 // http://www.telstra.com.au/home-phone/thub-2/
458 'TelstraTablet' => 'T-Hub2',
459 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bJolla\b|\bTP750\b'
460 );
461
462 /**
463 * List of mobile Operating Systems.
464 *
465 * @var array
466 */
467 protected static $operatingSystems = array(
468 'AndroidOS' => 'Android',
469 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
470 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
471 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
472 // @reference: http://en.wikipedia.org/wiki/Windows_Mobile
473 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;',
474 // @reference: http://en.wikipedia.org/wiki/Windows_Phone
475 // http://wifeng.cn/?r=blog&a=view&id=106
476 // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
477 // http://msdn.microsoft.com/library/ms537503.aspx
478 'WindowsPhoneOS' => 'Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;',
479 'iOS' => '\biPhone.*Mobile|\biPod|\biPad',
480 // http://en.wikipedia.org/wiki/MeeGo
481 // @todo: research MeeGo in UAs
482 'MeeGoOS' => 'MeeGo',
483 // http://en.wikipedia.org/wiki/Maemo
484 // @todo: research Maemo in UAs
485 'MaemoOS' => 'Maemo',
486 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135
487 'webOS' => 'webOS|hpwOS',
488 'badaOS' => '\bBada\b',
489 'BREWOS' => 'BREW',
490 );
491
492 /**
493 * List of mobile User Agents.
494 *
495 * @var array
496 */
497 protected static $browsers = array(
498 // @reference: https://developers.google.com/chrome/mobile/docs/user-agent
499 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
500 'Dolfin' => '\bDolfin\b',
501 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+',
502 'Skyfire' => 'Skyfire',
503 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+
504 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile',
505 'Bolt' => 'bolt',
506 'TeaShark' => 'teashark',
507 'Blazer' => 'Blazer',
508 // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
509 'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari',
510 // http://en.wikipedia.org/wiki/Midori_(web_browser)
511 //'Midori' => 'midori',
512 'Tizen' => 'Tizen',
513 'UCBrowser' => 'UC.*Browser|UCWEB',
514 'baiduboxapp' => 'baiduboxapp',
515 'baidubrowser' => 'baidubrowser',
516 // https://github.com/serbanghita/Mobile-Detect/issues/7
517 'DiigoBrowser' => 'DiigoBrowser',
518 // http://www.puffinbrowser.com/index.php
519 'Puffin' => 'Puffin',
520 // http://mercury-browser.com/index.html
521 'Mercury' => '\bMercury\b',
522 // http://en.wikipedia.org/wiki/Obigo_Browser
523 'ObigoBrowser' => 'Obigo',
524 // http://en.wikipedia.org/wiki/NetFront
525 'NetFront' => 'NF-Browser',
526 // @reference: http://en.wikipedia.org/wiki/Minimo
527 // http://en.wikipedia.org/wiki/Vision_Mobile_Browser
528 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger',
529 );
530
531 /**
532 * Utilities.
533 *
534 * @var array
535 */
536 protected static $utilities = array(
537 // Experimental. When a mobile device wants to switch to 'Desktop Mode'.
538 // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
539 // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
540 // https://developers.facebook.com/docs/sharing/best-practices
541 'Bot' => 'Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom',
542 'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2',
543 'DesktopMode' => 'WPDesktop',
544 'TV' => 'SonyDTV|HbbTV', // experimental
545 'WebKit' => '(webkit)[ /]([\w.]+)',
546 // @todo: Include JXD consoles.
547 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\b',
548 'Watch' => 'SM-V700',
549 );
550
551 /**
552 * All possible HTTP headers that represent the
553 * User-Agent string.
554 *
555 * @var array
556 */
557 protected static $uaHttpHeaders = array(
558 // The default User-Agent string.
559 'HTTP_USER_AGENT',
560 // Header can occur on devices using Opera Mini.
561 'HTTP_X_OPERAMINI_PHONE_UA',
562 // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
563 'HTTP_X_DEVICE_USER_AGENT',
564 'HTTP_X_ORIGINAL_USER_AGENT',
565 'HTTP_X_SKYFIRE_PHONE',
566 'HTTP_X_BOLT_PHONE_UA',
567 'HTTP_DEVICE_STOCK_UA',
568 'HTTP_X_UCBROWSER_DEVICE_UA'
569 );
570
571 /**
572 * The individual segments that could exist in a User-Agent string. VER refers to the regular
573 * expression defined in the constant self::VER.
574 *
575 * @var array
576 */
577 protected static $properties = array(
578
579 // Build
580 'Mobile' => 'Mobile/[VER]',
581 'Build' => 'Build/[VER]',
582 'Version' => 'Version/[VER]',
583 'VendorID' => 'VendorID/[VER]',
584
585 // Devices
586 'iPad' => 'iPad.*CPU[a-z ]+[VER]',
587 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
588 'iPod' => 'iPod.*CPU[a-z ]+[VER]',
589 //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
590 'Kindle' => 'Kindle/[VER]',
591
592 // Browser
593 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'),
594 'Coast' => array('Coast/[VER]'),
595 'Dolfin' => 'Dolfin/[VER]',
596 // @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference
597 'Firefox' => 'Firefox/[VER]',
598 'Fennec' => 'Fennec/[VER]',
599 // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
600 // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
601 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'),
602 // http://en.wikipedia.org/wiki/NetFront
603 'NetFront' => 'NetFront/[VER]',
604 'NokiaBrowser' => 'NokiaBrowser/[VER]',
605 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ),
606 'Opera Mini' => 'Opera Mini/[VER]',
607 'Opera Mobi' => 'Version/[VER]',
608 'UC Browser' => 'UC Browser[VER]',
609 'MQQBrowser' => 'MQQBrowser/[VER]',
610 'MicroMessenger' => 'MicroMessenger/[VER]',
611 'baiduboxapp' => 'baiduboxapp/[VER]',
612 'baidubrowser' => 'baidubrowser/[VER]',
613 'Iron' => 'Iron/[VER]',
614 // @note: Safari 7534.48.3 is actually Version 5.1.
615 // @note: On BlackBerry the Version is overwriten by the OS.
616 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ),
617 'Skyfire' => 'Skyfire/[VER]',
618 'Tizen' => 'Tizen/[VER]',
619 'Webkit' => 'webkit[ /][VER]',
620
621 // Engine
622 'Gecko' => 'Gecko/[VER]',
623 'Trident' => 'Trident/[VER]',
624 'Presto' => 'Presto/[VER]',
625
626 // OS
627 'iOS' => ' \bi?OS\b [VER][ ;]{1}',
628 'Android' => 'Android [VER]',
629 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'),
630 'BREW' => 'BREW [VER]',
631 'Java' => 'Java/[VER]',
632 // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
633 // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
634 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'),
635 'Windows Phone' => 'Windows Phone [VER]',
636 'Windows CE' => 'Windows CE/[VER]',
637 // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
638 'Windows NT' => 'Windows NT [VER]',
639 'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'),
640 'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'),
641 );
642
643 /**
644 * Construct an instance of this class.
645 *
646 * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored.
647 * If left empty, will use the global _SERVER['HTTP_*'] vars instead.
648 * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT
649 * from the $headers array instead.
650 */
651 public function __construct(
652 array $headers = null,
653 $userAgent = null
654 ) {
655 $this->setHttpHeaders($headers);
656 $this->setUserAgent($userAgent);
657 }
658
659 /**
660 * Get the current script version.
661 * This is useful for the demo.php file,
662 * so people can check on what version they are testing
663 * for mobile devices.
664 *
665 * @return string The version number in semantic version format.
666 */
667 public static function getScriptVersion()
668 {
669 return self::VERSION;
670 }
671
672 /**
673 * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers.
674 *
675 * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract
676 * the headers. The default null is left for backwards compatibilty.
677 */
678 public function setHttpHeaders($httpHeaders = null)
679 {
680 // use global _SERVER if $httpHeaders aren't defined
681 if (!is_array($httpHeaders) || !count($httpHeaders)) {
682 $httpHeaders = $_SERVER;
683 }
684
685 // clear existing headers
686 $this->httpHeaders = array();
687
688 // Only save HTTP headers. In PHP land, that means only _SERVER vars that
689 // start with HTTP_.
690 foreach ($httpHeaders as $key => $value) {
691 if (substr($key, 0, 5) === 'HTTP_') {
692 $this->httpHeaders[$key] = $value;
693 }
694 }
695
696 // In case we're dealing with CloudFront, we need to know.
697 $this->setCfHeaders($httpHeaders);
698 }
699
700 /**
701 * Retrieves the HTTP headers.
702 *
703 * @return array
704 */
705 public function getHttpHeaders()
706 {
707 return $this->httpHeaders;
708 }
709
710 /**
711 * Retrieves a particular header. If it doesn't exist, no exception/error is caused.
712 * Simply null is returned.
713 *
714 * @param string $header The name of the header to retrieve. Can be HTTP compliant such as
715 * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the
716 * all-caps, HTTP_ prefixed, underscore seperated awesomeness.
717 *
718 * @return string|null The value of the header.
719 */
720 public function getHttpHeader($header)
721 {
722 // are we using PHP-flavored headers?
723 if (strpos($header, '_') === false) {
724 $header = str_replace('-', '_', $header);
725 $header = strtoupper($header);
726 }
727
728 // test the alternate, too
729 $altHeader = 'HTTP_' . $header;
730
731 //Test both the regular and the HTTP_ prefix
732 if (isset($this->httpHeaders[$header])) {
733 return $this->httpHeaders[$header];
734 } elseif (isset($this->httpHeaders[$altHeader])) {
735 return $this->httpHeaders[$altHeader];
736 }
737
738 return null;
739 }
740
741 public function getMobileHeaders()
742 {
743 return self::$mobileHeaders;
744 }
745
746 /**
747 * Get all possible HTTP headers that
748 * can contain the User-Agent string.
749 *
750 * @return array List of HTTP headers.
751 */
752 public function getUaHttpHeaders()
753 {
754 return self::$uaHttpHeaders;
755 }
756
757
758 /**
759 * Set CloudFront headers
760 * http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
761 *
762 * @param array $cfHeaders List of HTTP headers
763 *
764 * @return boolean If there were CloudFront headers to be set
765 */
766 public function setCfHeaders($cfHeaders = null) {
767 // use global _SERVER if $cfHeaders aren't defined
768 if (!is_array($cfHeaders) || !count($cfHeaders)) {
769 $cfHeaders = $_SERVER;
770 }
771
772 // clear existing headers
773 $this->cloudfrontHeaders = array();
774
775 // Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that
776 // start with cloudfront-.
777 $response = false;
778 foreach ($cfHeaders as $key => $value) {
779 if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') {
780 $this->cloudfrontHeaders[strtoupper($key)] = $value;
781 $response = true;
782 }
783 }
784
785 return $response;
786 }
787
788 /**
789 * Retrieves the cloudfront headers.
790 *
791 * @return array
792 */
793 public function getCfHeaders()
794 {
795 return $this->cloudfrontHeaders;
796 }
797
798 /**
799 * Set the User-Agent to be used.
800 *
801 * @param string $userAgent The user agent string to set.
802 *
803 * @return string|null
804 */
805 public function setUserAgent($userAgent = null)
806 {
807 // Invalidate cache due to #375
808 $this->cache = array();
809
810 if (false === empty($userAgent)) {
811 return $this->userAgent = $userAgent;
812 } else {
813 $this->userAgent = null;
814 foreach ($this->getUaHttpHeaders() as $altHeader) {
815 if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
816 $this->userAgent .= $this->httpHeaders[$altHeader] . " ";
817 }
818 }
819
820 if (!empty($this->userAgent)) {
821 return $this->userAgent = trim($this->userAgent);
822 }
823 }
824
825 if (count($this->getCfHeaders()) > 0) {
826 return $this->userAgent = 'Amazon CloudFront';
827 }
828 return $this->userAgent = null;
829 }
830
831 /**
832 * Retrieve the User-Agent.
833 *
834 * @return string|null The user agent if it's set.
835 */
836 public function getUserAgent()
837 {
838 return $this->userAgent;
839 }
840
841 /**
842 * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or
843 * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set.
844 *
845 * @deprecated since version 2.6.9
846 *
847 * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default
848 * parameter is null which will default to self::DETECTION_TYPE_MOBILE.
849 */
850 public function setDetectionType($type = null)
851 {
852 if ($type === null) {
853 $type = self::DETECTION_TYPE_MOBILE;
854 }
855
856 if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) {
857 return;
858 }
859
860 $this->detectionType = $type;
861 }
862
863 public function getMatchingRegex()
864 {
865 return $this->matchingRegex;
866 }
867
868 public function getMatchesArray()
869 {
870 return $this->matchesArray;
871 }
872
873 /**
874 * Retrieve the list of known phone devices.
875 *
876 * @return array List of phone devices.
877 */
878 public static function getPhoneDevices()
879 {
880 return self::$phoneDevices;
881 }
882
883 /**
884 * Retrieve the list of known tablet devices.
885 *
886 * @return array List of tablet devices.
887 */
888 public static function getTabletDevices()
889 {
890 return self::$tabletDevices;
891 }
892
893 /**
894 * Alias for getBrowsers() method.
895 *
896 * @return array List of user agents.
897 */
898 public static function getUserAgents()
899 {
900 return self::getBrowsers();
901 }
902
903 /**
904 * Retrieve the list of known browsers. Specifically, the user agents.
905 *
906 * @return array List of browsers / user agents.
907 */
908 public static function getBrowsers()
909 {
910 return self::$browsers;
911 }
912
913 /**
914 * Retrieve the list of known utilities.
915 *
916 * @return array List of utilities.
917 */
918 public static function getUtilities()
919 {
920 return self::$utilities;
921 }
922
923 /**
924 * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*().
925 *
926 * @deprecated since version 2.6.9
927 *
928 * @return array All the rules (but not extended).
929 */
930 public static function getMobileDetectionRules()
931 {
932 static $rules;
933
934 if (!$rules) {
935 $rules = array_merge(
936 self::$phoneDevices,
937 self::$tabletDevices,
938 self::$operatingSystems,
939 self::$browsers
940 );
941 }
942
943 return $rules;
944
945 }
946
947 /**
948 * Method gets the mobile detection rules + utilities.
949 * The reason this is separate is because utilities rules
950 * don't necessary imply mobile. This method is used inside
951 * the new $detect->is('stuff') method.
952 *
953 * @deprecated since version 2.6.9
954 *
955 * @return array All the rules + extended.
956 */
957 public function getMobileDetectionRulesExtended()
958 {
959 static $rules;
960
961 if (!$rules) {
962 // Merge all rules together.
963 $rules = array_merge(
964 self::$phoneDevices,
965 self::$tabletDevices,
966 self::$operatingSystems,
967 self::$browsers,
968 self::$utilities
969 );
970 }
971
972 return $rules;
973 }
974
975 /**
976 * Retrieve the current set of rules.
977 *
978 * @deprecated since version 2.6.9
979 *
980 * @return array
981 */
982 public function getRules()
983 {
984 if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) {
985 return self::getMobileDetectionRulesExtended();
986 } else {
987 return self::getMobileDetectionRules();
988 }
989 }
990
991 /**
992 * Retrieve the list of mobile operating systems.
993 *
994 * @return array The list of mobile operating systems.
995 */
996 public static function getOperatingSystems()
997 {
998 return self::$operatingSystems;
999 }
1000
1001 /**
1002 * Check the HTTP headers for signs of mobile.
1003 * This is the fastest mobile check possible; it's used
1004 * inside isMobile() method.
1005 *
1006 * @return bool
1007 */
1008 public function checkHttpHeadersForMobile()
1009 {
1010
1011 foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) {
1012 if (isset($this->httpHeaders[$mobileHeader])) {
1013 if (is_array($matchType['matches'])) {
1014 foreach ($matchType['matches'] as $_match) {
1015 if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) {
1016 return true;
1017 }
1018 }
1019
1020 return false;
1021 } else {
1022 return true;
1023 }
1024 }
1025 }
1026
1027 return false;
1028
1029 }
1030
1031 /**
1032 * Magic overloading method.
1033 *
1034 * @method boolean is[...]()
1035 * @param string $name
1036 * @param array $arguments
1037 * @return mixed
1038 * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is'
1039 */
1040 public function __call($name, $arguments)
1041 {
1042 // make sure the name starts with 'is', otherwise
1043 if (substr($name, 0, 2) !== 'is') {
1044 throw new BadMethodCallException("No such method exists: $name");
1045 }
1046
1047 $this->setDetectionType(self::DETECTION_TYPE_MOBILE);
1048
1049 $key = substr($name, 2);
1050
1051 return $this->matchUAAgainstKey($key);
1052 }
1053
1054 /**
1055 * Find a detection rule that matches the current User-agent.
1056 *
1057 * @param null $userAgent deprecated
1058 * @return boolean
1059 */
1060 protected function matchDetectionRulesAgainstUA($userAgent = null)
1061 {
1062 // Begin general search.
1063 foreach ($this->getRules() as $_regex) {
1064 if (empty($_regex)) {
1065 continue;
1066 }
1067
1068 if ($this->match($_regex, $userAgent)) {
1069 return true;
1070 }
1071 }
1072
1073 return false;
1074 }
1075
1076 /**
1077 * Search for a certain key in the rules array.
1078 * If the key is found the try to match the corresponding
1079 * regex against the User-Agent.
1080 *
1081 * @param string $key
1082 *
1083 * @return boolean
1084 */
1085 protected function matchUAAgainstKey($key)
1086 {
1087 // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
1088 $key = strtolower($key);
1089 if (false === isset($this->cache[$key])) {
1090
1091 // change the keys to lower case
1092 $_rules = array_change_key_case($this->getRules());
1093
1094 if (false === empty($_rules[$key])) {
1095 $this->cache[$key] = $this->match($_rules[$key]);
1096 }
1097
1098 if (false === isset($this->cache[$key])) {
1099 $this->cache[$key] = false;
1100 }
1101 }
1102
1103 return $this->cache[$key];
1104 }
1105
1106 /**
1107 * Check if the device is mobile.
1108 * Returns true if any type of mobile device detected, including special ones
1109 * @param null $userAgent deprecated
1110 * @param null $httpHeaders deprecated
1111 * @return bool
1112 */
1113 public function isMobile($userAgent = null, $httpHeaders = null)
1114 {
1115
1116 if ($httpHeaders) {
1117 $this->setHttpHeaders($httpHeaders);
1118 }
1119
1120 if ($userAgent) {
1121 $this->setUserAgent($userAgent);
1122 }
1123
1124 // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
1125 if ($this->getUserAgent() === 'Amazon CloudFront') {
1126 $cfHeaders = $this->getCfHeaders();
1127 if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') {
1128 return true;
1129 }
1130 }
1131
1132 $this->setDetectionType(self::DETECTION_TYPE_MOBILE);
1133
1134 if ($this->checkHttpHeadersForMobile()) {
1135 return true;
1136 } else {
1137 return $this->matchDetectionRulesAgainstUA();
1138 }
1139
1140 }
1141
1142 /**
1143 * Check if the device is a tablet.
1144 * Return true if any type of tablet device is detected.
1145 *
1146 * @param string $userAgent deprecated
1147 * @param array $httpHeaders deprecated
1148 * @return bool
1149 */
1150 public function isTablet($userAgent = null, $httpHeaders = null)
1151 {
1152 // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
1153 if ($this->getUserAgent() === 'Amazon CloudFront') {
1154 $cfHeaders = $this->getCfHeaders();
1155 if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') {
1156 return true;
1157 }
1158 }
1159
1160 $this->setDetectionType(self::DETECTION_TYPE_MOBILE);
1161
1162 foreach (self::$tabletDevices as $_regex) {
1163 if ($this->match($_regex, $userAgent)) {
1164 return true;
1165 }
1166 }
1167
1168 return false;
1169 }
1170
1171 /**
1172 * This method checks for a certain property in the
1173 * userAgent.
1174 * @todo: The httpHeaders part is not yet used.
1175 *
1176 * @param string $key
1177 * @param string $userAgent deprecated
1178 * @param string $httpHeaders deprecated
1179 * @return bool|int|null
1180 */
1181 public function is($key, $userAgent = null, $httpHeaders = null)
1182 {
1183 // Set the UA and HTTP headers only if needed (eg. batch mode).
1184 if ($httpHeaders) {
1185 $this->setHttpHeaders($httpHeaders);
1186 }
1187
1188 if ($userAgent) {
1189 $this->setUserAgent($userAgent);
1190 }
1191
1192 $this->setDetectionType(self::DETECTION_TYPE_EXTENDED);
1193
1194 return $this->matchUAAgainstKey($key);
1195 }
1196
1197 /**
1198 * Some detection rules are relative (not standard),
1199 * because of the diversity of devices, vendors and
1200 * their conventions in representing the User-Agent or
1201 * the HTTP headers.
1202 *
1203 * This method will be used to check custom regexes against
1204 * the User-Agent string.
1205 *
1206 * @param $regex
1207 * @param string $userAgent
1208 * @return bool
1209 *
1210 * @todo: search in the HTTP headers too.
1211 */
1212 public function match($regex, $userAgent = null)
1213 {
1214 $match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches);
1215 // If positive match is found, store the results for debug.
1216 if ($match) {
1217 $this->matchingRegex = $regex;
1218 $this->matchesArray = $matches;
1219 }
1220
1221 return $match;
1222 }
1223
1224 /**
1225 * Get the properties array.
1226 *
1227 * @return array
1228 */
1229 public static function getProperties()
1230 {
1231 return self::$properties;
1232 }
1233
1234 /**
1235 * Prepare the version number.
1236 *
1237 * @todo Remove the error supression from str_replace() call.
1238 *
1239 * @param string $ver The string version, like "2.6.21.2152";
1240 *
1241 * @return float
1242 */
1243 public function prepareVersionNo($ver)
1244 {
1245 $ver = str_replace(array('_', ' ', '/'), '.', $ver);
1246 $arrVer = explode('.', $ver, 2);
1247
1248 if (isset($arrVer[1])) {
1249 $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.
1250 }
1251
1252 return (float) implode('.', $arrVer);
1253 }
1254
1255 /**
1256 * Check the version of the given property in the User-Agent.
1257 * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
1258 *
1259 * @param string $propertyName The name of the property. See self::getProperties() array
1260 * keys for all possible properties.
1261 * @param string $type Either self::VERSION_TYPE_STRING to get a string value or
1262 * self::VERSION_TYPE_FLOAT indicating a float value. This parameter
1263 * is optional and defaults to self::VERSION_TYPE_STRING. Passing an
1264 * invalid parameter will default to the this type as well.
1265 *
1266 * @return string|float The version of the property we are trying to extract.
1267 */
1268 public function version($propertyName, $type = self::VERSION_TYPE_STRING)
1269 {
1270 if (empty($propertyName)) {
1271 return false;
1272 }
1273
1274 // set the $type to the default if we don't recognize the type
1275 if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) {
1276 $type = self::VERSION_TYPE_STRING;
1277 }
1278
1279 $properties = self::getProperties();
1280
1281 // Check if the property exists in the properties array.
1282 if (true === isset($properties[$propertyName])) {
1283
1284 // Prepare the pattern to be matched.
1285 // Make sure we always deal with an array (string is converted).
1286 $properties[$propertyName] = (array) $properties[$propertyName];
1287
1288 foreach ($properties[$propertyName] as $propertyMatchString) {
1289
1290 $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);
1291
1292 // Identify and extract the version.
1293 preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match);
1294
1295 if (false === empty($match[1])) {
1296 $version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]);
1297
1298 return $version;
1299 }
1300
1301 }
1302
1303 }
1304
1305 return false;
1306 }
1307
1308 /**
1309 * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants.
1310 *
1311 * @return string One of the self::MOBILE_GRADE_* constants.
1312 */
1313 public function mobileGrade()
1314 {
1315 $isMobile = $this->isMobile();
1316
1317 if (
1318 // Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0)
1319 $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 ||
1320 $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 ||
1321 $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 ||
1322
1323 // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
1324 // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
1325 // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
1326 // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
1327 ( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) ||
1328
1329 // Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8)
1330 $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 ||
1331
1332 // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10)
1333 $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 ||
1334 // Blackberry Playbook (1.0-2.0) - Tested on PlayBook
1335 $this->match('Playbook.*Tablet') ||
1336
1337 // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0)
1338 ( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) ||
1339 // Palm WebOS 3.0 - Tested on HP TouchPad
1340 $this->match('hp.*TouchPad') ||
1341
1342 // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices
1343 ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) ||
1344
1345 // Chrome for Android - Tested on Android 4.0, 4.1 device
1346 ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) ||
1347
1348 // Skyfire 4.1 - Tested on Android 2.3 device
1349 ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
1350
1351 // Opera Mobile 11.5-12: Tested on Android 2.3
1352 ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) ||
1353
1354 // Meego 1.2 - Tested on Nokia 950 and N9
1355 $this->is('MeeGoOS') ||
1356
1357 // Tizen (pre-release) - Tested on early hardware
1358 $this->is('Tizen') ||
1359
1360 // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
1361 // @todo: more tests here!
1362 $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 ||
1363
1364 // UC Browser - Tested on Android 2.3 device
1365 ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
1366
1367 // Kindle 3 and Fire - Tested on the built-in WebKit browser for each
1368 ( $this->match('Kindle Fire') ||
1369 $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) ||
1370
1371 // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
1372 $this->is('AndroidOS') && $this->is('NookTablet') ||
1373
1374 // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7
1375 $this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile ||
1376
1377 // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7
1378 $this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile ||
1379
1380 // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7
1381 $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile ||
1382
1383 // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
1384 $this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile ||
1385
1386 // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
1387 $this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile
1388 ){
1389 return self::MOBILE_GRADE_A;
1390 }
1391
1392 if (
1393 $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 ||
1394 $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 ||
1395 $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 ||
1396
1397 // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
1398 $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 ||
1399
1400 //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
1401 ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 &&
1402 ($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) ||
1403
1404 // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
1405 $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
1406
1407 // @todo: report this (tested on Nokia N71)
1408 $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS')
1409 ){
1410 return self::MOBILE_GRADE_B;
1411 }
1412
1413 if (
1414 // Blackberry 4.x - Tested on the Curve 8330
1415 $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 ||
1416 // Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
1417 $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 ||
1418
1419 // Tested on original iPhone (3.1), iPhone 3 (3.2)
1420 $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 ||
1421 $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 ||
1422 $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 ||
1423
1424 // Internet Explorer 7 and older - Tested on Windows XP
1425 $this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile
1426 ){
1427 return self::MOBILE_GRADE_C;
1428 }
1429
1430 // All older smartphone platforms and featurephones - Any device that doesn't support media queries
1431 // will receive the basic, C grade experience.
1432 return self::MOBILE_GRADE_C;
1433 }
1434 }
1435 }