PluginProbe ʕ •ᴥ•ʔ
Tracking Code Manager / 2.2.0
Tracking Code Manager v2.2.0
trunk 1.11.8 1.11.9 1.12.0 1.12.1 1.12.2 1.12.3 1.4 1.5 2.0.0 2.0.1 2.0.13 2.0.14 2.0.15 2.0.16 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.2.0 2.3.0 2.4.0 2.5.0 2.6.0
tracking-code-manager / includes / classes / utils / MobileDetect.php
tracking-code-manager / includes / classes / utils Last commit date
Cron.php 3 years ago Ecommerce.php 3 years ago Language.php 3 years ago Logger.php 3 years ago MobileDetect.php 3 years ago Options.php 3 years ago Plugin.php 3 years ago Properties.php 3 years ago Tracking.php 3 years ago Utils.php 2 years ago
MobileDetect.php
1401 lines
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.19
26 */
27
28 class TCMP_Mobile_Detect {
29 /**
30 * Mobile detection type.
31 *
32 * @deprecated since version 2.6.9
33 */
34 const DETECTION_TYPE_MOBILE = 'mobile';
35
36 /**
37 * Extended detection type.
38 *
39 * @deprecated since version 2.6.9
40 */
41 const DETECTION_TYPE_EXTENDED = 'extended';
42
43 /**
44 * A frequently used regular expression to extract version #s.
45 *
46 * @deprecated since version 2.6.9
47 */
48 const VER = '([\w._\+]+)';
49
50 /**
51 * Top-level device.
52 */
53 const MOBILE_GRADE_A = 'A';
54
55 /**
56 * Mid-level device.
57 */
58 const MOBILE_GRADE_B = 'B';
59
60 /**
61 * Low-level device.
62 */
63 const MOBILE_GRADE_C = 'C';
64
65 /**
66 * Stores the version number of the current release.
67 */
68 const VERSION = '2.8.19';
69
70 /**
71 * A type for the version() method indicating a string return value.
72 */
73 const VERSION_TYPE_STRING = 'text';
74
75 /**
76 * A type for the version() method indicating a float return value.
77 */
78 const VERSION_TYPE_FLOAT = 'float';
79
80 /**
81 * A cache for resolved matches
82 * @var array
83 */
84 protected $cache = array();
85
86 /**
87 * The User-Agent HTTP header is stored in here.
88 * @var string
89 */
90 protected $userAgent = null;
91
92 /**
93 * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE.
94 * @var array
95 */
96 protected $httpHeaders = array();
97
98 /**
99 * CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer.
100 * @var array
101 */
102 protected $cloudfrontHeaders = array();
103
104 /**
105 * The matching Regex.
106 * This is good for debug.
107 * @var string
108 */
109 protected $matchingRegex = null;
110
111 /**
112 * The matches extracted from the regex expression.
113 * This is good for debug.
114 * @var string
115 */
116 protected $matchesArray = null;
117
118 /**
119 * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED.
120 *
121 * @deprecated since version 2.6.9
122 *
123 * @var string
124 */
125 protected $detectionType = self::DETECTION_TYPE_MOBILE;
126
127 /**
128 * HTTP headers that trigger the 'isMobile' detection
129 * to be true.
130 *
131 * @var array
132 */
133 protected static $mobileHeaders = array(
134
135 'HTTP_ACCEPT' => array(
136 '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 ),
145 'HTTP_X_WAP_PROFILE' => null,
146 'HTTP_X_WAP_CLIENTID' => null,
147 'HTTP_WAP_CONNECTION' => null,
148 'HTTP_PROFILE' => null,
149 // Reported by Opera on Nokia devices (eg. C3).
150 'HTTP_X_OPERAMINI_PHONE_UA' => null,
151 'HTTP_X_NOKIA_GATEWAY_ID' => null,
152 'HTTP_X_ORANGE_ID' => null,
153 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
154 'HTTP_X_HUAWEI_USERID' => null,
155 // Reported by Windows Smartphones.
156 'HTTP_UA_OS' => null,
157 // Reported by Verizon, Vodafone proxy system.
158 'HTTP_X_MOBILE_GATEWAY' => null,
159 // Seen this on HTC Sensation. SensationXE_Beats_Z715e.
160 'HTTP_X_ATT_DEVICEID' => null,
161 // Seen this on a HTC.
162 'HTTP_UA_CPU' => array( 'matches' => array( 'ARM' ) ),
163 );
164
165 /**
166 * List of mobile devices (phones).
167 *
168 * @var array
169 */
170 protected static $phoneDevices = array(
171 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes
172 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+',
173 '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',
174 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6',
175 // @todo: Is 'Dell Streak' a tablet or a phone? ;)
176 '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',
177 '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',
178 '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',
179 '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|MS323)',
180 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533',
181 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile',
182 // http://www.micromaxinfo.com/mobiles/smartphones
183 // Added because the codes might conflict with Acer Tablets.
184 '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',
185 // @todo Complete the regex.
186 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ;
187 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;)
188 // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
189 // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
190 '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',
191 // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
192 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
193 // http://fr.wikomobile.com
194 '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',
195 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)',
196 // Added simvalley mobile just for fun. They have some interesting devices.
197 // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html
198 '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',
199 // Wolfgang - a brand that is sold by Aldi supermarkets.
200 // http://www.wolfgangmobile.com/
201 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q',
202 'Alcatel' => 'Alcatel',
203 'Nintendo' => 'Nintendo 3DS',
204 // http://en.wikipedia.org/wiki/Amoi
205 'Amoi' => 'Amoi',
206 // http://en.wikipedia.org/wiki/INQ
207 'INQ' => 'INQ',
208 // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
209 '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',
210 );
211
212 /**
213 * List of tablet devices.
214 *
215 * @var array
216 */
217 protected static $tabletDevices = array(
218 // @todo: check for mobile friendly emails topic.
219 'iPad' => 'iPad|iPad.*Mobile',
220 // Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
221 // @see #442
222 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
223 '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|SM-T113|SM-T335|SM-T715', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
224 // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
225 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI)\b',
226 // Only the Surface tablets with Windows RT are considered mobile.
227 // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
228 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
229 // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT
230 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
231 // Watch out for PadFone, see #132.
232 // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/
233 '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',
234 'BlackBerryTablet' => 'PlayBook|RIM Tablet',
235 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
236 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
237 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
238 // http://www.acer.ro/ac/ro/RO/content/drivers
239 // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
240 // http://us.acer.com/ac/en/US/content/group/tablets
241 // http://www.acer.de/ac/de/DE/content/models/tablets/
242 // Can conflict with Micromax and Motorola phones codes.
243 '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',
244 // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
245 // http://us.toshiba.com/tablets/tablet-finder
246 // http://www.toshiba.co.jp/regza/tablet/
247 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
248 // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
249 // http://www.lg.com/us/tablets
250 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b',
251 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
252 // Prestigio Tablets http://www.prestigio.com/support
253 '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',
254 // http://support.lenovo.com/en_GB/downloads/default.page?#
255 '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|)',
256 // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets
257 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7',
258 // http://www.yarvik.com/en/matrix/tablets/
259 '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',
260 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
261 'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2',
262 // http://www.intenso.de/kategorie_en.php?kategorie=33
263 // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate
264 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
265 // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/
266 'IRUTablet' => 'M702pro',
267 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
268 // http://www.e-boda.ro/tablete-pc.html
269 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
270 // http://www.allview.ro/produse/droseries/lista-tablete-pc/
271 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
272 // http://wiki.archosfans.com/index.php?title=Main_Page
273 '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',
274 // http://www.ainol.com/plugin.php?identifier=ainol&module=product
275 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
276 // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
277 // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
278 // http://www.sony.jp/support/tablet/
279 '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',
280 // 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
281 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
282 // db + http://www.cube-tablet.com/buy-products.html
283 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
284 // http://www.cobyusa.com/?p=pcat&pcat_id=3001
285 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
286 // http://www.match.net.cn/products.asp
287 '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',
288 // http://www.msi.com/support
289 // @todo Research the Windows Tablets.
290 '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',
291 // @todo http://www.kyoceramobile.com/support/drivers/
292 // 'KyoceraTablet' => null,
293 // @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/
294 // 'IntextTablet' => null,
295 // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
296 // http://www.imp3.net/14/show.php?itemid=20454
297 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
298 // http://www.rock-chips.com/index.php?do=prod&pid=2
299 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
300 // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
301 'FlyTablet' => 'IQ310|Fly Vision',
302 // http://www.bqreaders.com/gb/tablets-prices-sale.html
303 'bqTablet' => 'Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus',
304 // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
305 // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
306 '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',
307 // Nec or Medias Tab
308 'NecTablet' => '\bN-06D|\bN-08D',
309 // Pantech Tablets: http://www.pantechusa.com/phones/
310 'PantechTablet' => 'Pantech.*P4100',
311 // Broncho Tablets: http://www.broncho.cn/ (hard to find)
312 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
313 // http://versusuk.com/support.html
314 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
315 // http://www.zync.in/index.php/our-products/tablet-phablets
316 'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900',
317 // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
318 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
319 // https://www.nabitablet.com/
320 'NabiTablet' => 'Android.*\bNabi',
321 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
322 // French Danew Tablets http://www.danew.com/produits-tablette.php
323 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
324 // Texet Tablets and Readers http://www.texet.ru/tablet/
325 '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',
326 // Avoid detecting 'PLAYSTATION 3' as mobile.
327 'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
328 // http://www.trekstor.de/surftabs.html
329 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
330 // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets
331 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
332 // http://www.advandigital.com/index.php?link=content-product&jns=JP001
333 // because of the short codenames we have to include whitespaces to reduce the possible conflicts.
334 '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 ',
335 // http://www.danytech.com/category/tablet-pc
336 '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',
337 // http://www.galapad.net/product.html
338 'GalapadTablet' => 'Android.*\bG1\b',
339 // http://www.micromaxinfo.com/tablet/funbook
340 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
341 // http://www.karbonnmobiles.com/products_tablet.php
342 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
343 // http://www.myallfine.com/Products.asp
344 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
345 // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
346 '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',
347 // http://www.yonesnav.com/products/products.php
348 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
349 // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
350 // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html)
351 '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',
352 // http://www.gloryunion.cn/products.asp
353 // http://www.allwinnertech.com/en/apply/mobile.html
354 // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB)
355 // @todo: Softwiner tablets?
356 // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions.
357 '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
358 // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118
359 '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',
360 // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/
361 // @todo: add more tests.
362 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)',
363 // http://hclmetablet.com/India/index.php
364 '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',
365 // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html
366 'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
367 // http://www.visture.com/index.asp
368 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
369 // http://www.mijncresta.nl/tablet
370 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
371 // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309
372 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
373 // Concorde tab
374 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
375 // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/
376 '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',
377 // Modecom Tablets - http://www.modecom.eu/tablets/portal/
378 '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',
379 // Vonino Tablets - http://www.vonino.eu/tablets
380 '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',
381 // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0
382 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
383 // Storex Tablets - http://storex.fr/espace_client/support.html
384 // @note: no need to add all the tablet codes since they are guided by the first regex.
385 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
386 // Generic Vodafone tablets.
387 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7',
388 // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb
389 // Aka: http://www.essentielb.fr/
390 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
391 // Ross & Moor - http://ross-moor.ru/
392 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
393 // i-mobile http://product.i-mobilephone.com/Mobile_Device
394 'iMobileTablet' => 'i-mobile i-note',
395 // http://www.tolino.de/de/vergleichen/
396 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
397 // AudioSonic - a Kmart brand
398 // 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
399 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
400 // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/
401 // @todo: add them gradually to avoid conflicts.
402 'AMPETablet' => 'Android.* A78 ',
403 // Skk Mobile - http://skkmobile.com.ph/product_tablets.php
404 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
405 // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1
406 'TecnoTablet' => 'TECNO P9',
407 // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3
408 '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',
409 // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/
410 '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)',
411 // http://www.intracon.eu/tablet
412 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
413 // http://www.xoro.de/produkte/
414 // @note: Might be the same brand with 'Simply tablets'
415 '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',
416 // http://www1.viewsonic.com/products/computing/tablets/
417 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
418 // http://www.odys.de/web/internet-tablet_en.html
419 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
420 // http://www.captiva-power.de/products.html#tablets-en
421 'CaptivaTablet' => 'CAPTIVA PAD',
422 // IconBIT - http://www.iconbit.com/products/tablets/
423 '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',
424 // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63
425 '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',
426 // Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price
427 '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]+',
428 'JaytechTablet' => 'TPC-PA762',
429 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
430 // http://www.digma.ru/support/download/
431 // @todo: Ebooks also (if requested)
432 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
433 // http://www.evolioshop.com/ro/tablete-pc.html
434 // http://www.evolio.ro/support/downloads_static.html?cat=2
435 // @todo: Research some more
436 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
437 // @todo http://www.lavamobiles.com/tablets-data-cards
438 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b',
439 'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382',
440 // https://www.celkonmobiles.com/?_a=categoryphones&sid=2
441 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b',
442 // http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab
443 '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',
444 // http://www.mi.com/en
445 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b',
446 // http://www.nbru.cn/index.html
447 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One',
448 // http://navroad.com/products/produkty/tablety/
449 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI',
450 // http://leader-online.com/new_site/product-category/tablets/
451 // http://www.leader-online.net.au/List/Tablet
452 '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',
453 // http://www.datawind.com/ubislate/
454 'UbislateTablet' => 'UbiSlate[\s]?7C',
455 // http://www.pocketbook-int.com/ru/support
456 'PocketBookTablet' => 'Pocketbook',
457 // http://www.tesco.com/direct/hudl/
458 'Hudl' => 'Hudl HT7S3|Hudl 2',
459 // http://www.telstra.com.au/home-phone/thub-2/
460 'TelstraTablet' => 'T-Hub2',
461 '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',
462 );
463
464 /**
465 * List of mobile Operating Systems.
466 *
467 * @var array
468 */
469 protected static $operatingSystems = array(
470 'AndroidOS' => 'Android',
471 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
472 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
473 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
474 // @reference: http://en.wikipedia.org/wiki/Windows_Mobile
475 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;',
476 // @reference: http://en.wikipedia.org/wiki/Windows_Phone
477 // http://wifeng.cn/?r=blog&a=view&id=106
478 // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
479 // http://msdn.microsoft.com/library/ms537503.aspx
480 // https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
481 'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;',
482 'iOS' => '\biPhone.*Mobile|\biPod|\biPad',
483 // http://en.wikipedia.org/wiki/MeeGo
484 // @todo: research MeeGo in UAs
485 'MeeGoOS' => 'MeeGo',
486 // http://en.wikipedia.org/wiki/Maemo
487 // @todo: research Maemo in UAs
488 'MaemoOS' => 'Maemo',
489 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135
490 'webOS' => 'webOS|hpwOS',
491 'badaOS' => '\bBada\b',
492 'BREWOS' => 'BREW',
493 );
494
495 /**
496 * List of mobile User Agents.
497 *
498 * @var array
499 */
500 protected static $browsers = array(
501 // @reference: https://developers.google.com/chrome/mobile/docs/user-agent
502 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
503 'Dolfin' => '\bDolfin\b',
504 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+',
505 'Skyfire' => 'Skyfire',
506 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+
507 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile',
508 'Bolt' => 'bolt',
509 'TeaShark' => 'teashark',
510 'Blazer' => 'Blazer',
511 // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
512 'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari',
513 // http://en.wikipedia.org/wiki/Midori_(web_browser)
514 //'Midori' => 'midori',
515 'Tizen' => 'Tizen',
516 'UCBrowser' => 'UC.*Browser|UCWEB',
517 'baiduboxapp' => 'baiduboxapp',
518 'baidubrowser' => 'baidubrowser',
519 // https://github.com/serbanghita/Mobile-Detect/issues/7
520 'DiigoBrowser' => 'DiigoBrowser',
521 // http://www.puffinbrowser.com/index.php
522 'Puffin' => 'Puffin',
523 // http://mercury-browser.com/index.html
524 'Mercury' => '\bMercury\b',
525 // http://en.wikipedia.org/wiki/Obigo_Browser
526 'ObigoBrowser' => 'Obigo',
527 // http://en.wikipedia.org/wiki/NetFront
528 'NetFront' => 'NF-Browser',
529 // @reference: http://en.wikipedia.org/wiki/Minimo
530 // http://en.wikipedia.org/wiki/Vision_Mobile_Browser
531 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger',
532 );
533
534 /**
535 * Utilities.
536 *
537 * @var array
538 */
539 protected static $utilities = array(
540 // Experimental. When a mobile device wants to switch to 'Desktop Mode'.
541 // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
542 // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
543 // https://developers.facebook.com/docs/sharing/best-practices
544 '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',
545 'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2',
546 'DesktopMode' => 'WPDesktop',
547 'TV' => 'SonyDTV|HbbTV', // experimental
548 'WebKit' => '(webkit)[ /]([\w.]+)',
549 // @todo: Include JXD consoles.
550 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\b',
551 'Watch' => 'SM-V700',
552 );
553
554 /**
555 * All possible HTTP headers that represent the
556 * User-Agent string.
557 *
558 * @var array
559 */
560 protected static $uaHttpHeaders = array(
561 // The default User-Agent string.
562 'HTTP_USER_AGENT',
563 // Header can occur on devices using Opera Mini.
564 'HTTP_X_OPERAMINI_PHONE_UA',
565 // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
566 'HTTP_X_DEVICE_USER_AGENT',
567 'HTTP_X_ORIGINAL_USER_AGENT',
568 'HTTP_X_SKYFIRE_PHONE',
569 'HTTP_X_BOLT_PHONE_UA',
570 'HTTP_DEVICE_STOCK_UA',
571 'HTTP_X_UCBROWSER_DEVICE_UA',
572 );
573
574 /**
575 * The individual segments that could exist in a User-Agent string. VER refers to the regular
576 * expression defined in the constant self::VER.
577 *
578 * @var array
579 */
580 protected static $properties = array(
581
582 // Build
583 'Mobile' => 'Mobile/[VER]',
584 'Build' => 'Build/[VER]',
585 'Version' => 'Version/[VER]',
586 'VendorID' => 'VendorID/[VER]',
587
588 // Devices
589 'iPad' => 'iPad.*CPU[a-z ]+[VER]',
590 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
591 'iPod' => 'iPod.*CPU[a-z ]+[VER]',
592 //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
593 'Kindle' => 'Kindle/[VER]',
594
595 // Browser
596 'Chrome' => array( 'Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]' ),
597 'Coast' => array( 'Coast/[VER]' ),
598 'Dolfin' => 'Dolfin/[VER]',
599 // @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference
600 'Firefox' => 'Firefox/[VER]',
601 'Fennec' => 'Fennec/[VER]',
602 // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
603 // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
604 'IE' => array( 'IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]' ),
605 // http://en.wikipedia.org/wiki/NetFront
606 'NetFront' => 'NetFront/[VER]',
607 'NokiaBrowser' => 'NokiaBrowser/[VER]',
608 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ),
609 'Opera Mini' => 'Opera Mini/[VER]',
610 'Opera Mobi' => 'Version/[VER]',
611 'UC Browser' => 'UC Browser[VER]',
612 'MQQBrowser' => 'MQQBrowser/[VER]',
613 'MicroMessenger' => 'MicroMessenger/[VER]',
614 'baiduboxapp' => 'baiduboxapp/[VER]',
615 'baidubrowser' => 'baidubrowser/[VER]',
616 'Iron' => 'Iron/[VER]',
617 // @note: Safari 7534.48.3 is actually Version 5.1.
618 // @note: On BlackBerry the Version is overwriten by the OS.
619 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ),
620 'Skyfire' => 'Skyfire/[VER]',
621 'Tizen' => 'Tizen/[VER]',
622 'Webkit' => 'webkit[ /][VER]',
623
624 // Engine
625 'Gecko' => 'Gecko/[VER]',
626 'Trident' => 'Trident/[VER]',
627 'Presto' => 'Presto/[VER]',
628
629 // OS
630 'iOS' => ' \bi?OS\b [VER][ ;]{1}',
631 'Android' => 'Android [VER]',
632 'BlackBerry' => array( 'BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]' ),
633 'BREW' => 'BREW [VER]',
634 'Java' => 'Java/[VER]',
635 // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
636 // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
637 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]' ),
638 'Windows Phone' => 'Windows Phone [VER]',
639 'Windows CE' => 'Windows CE/[VER]',
640 // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
641 'Windows NT' => 'Windows NT [VER]',
642 'Symbian' => array( 'SymbianOS/[VER]', 'Symbian/[VER]' ),
643 'webOS' => array( 'webOS/[VER]', 'hpwOS/[VER];' ),
644 );
645
646 /**
647 * Construct an instance of this class.
648 *
649 * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored.
650 * If left empty, will use the global _SERVER['HTTP_*'] vars instead.
651 * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT
652 * from the $headers array instead.
653 */
654 public function __construct(
655 array $headers = null,
656 $userAgent = null
657 ) {
658 $this->setHttpHeaders( $headers );
659 $this->setUserAgent( $userAgent );
660 }
661
662 /**
663 * Get the current script version.
664 * This is useful for the demo.php file,
665 * so people can check on what version they are testing
666 * for mobile devices.
667 *
668 * @return string The version number in semantic version format.
669 */
670 public static function getScriptVersion() {
671 return self::VERSION;
672 }
673
674 /**
675 * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers.
676 *
677 * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract
678 * the headers. The default null is left for backwards compatibilty.
679 */
680 public function setHttpHeaders( $httpHeaders = null ) {
681 // use global _SERVER if $httpHeaders aren't defined
682 if ( ! is_array( $httpHeaders ) || ! count( $httpHeaders ) ) {
683 $httpHeaders = $_SERVER;
684 }
685
686 // clear existing headers
687 $this->httpHeaders = array();
688
689 // Only save HTTP headers. In PHP land, that means only _SERVER vars that
690 // start with HTTP_.
691 foreach ( $httpHeaders as $key => $value ) {
692 if ( substr( $key, 0, 5 ) === 'HTTP_' ) {
693 $this->httpHeaders[ $key ] = $value;
694 }
695 }
696
697 // In case we're dealing with CloudFront, we need to know.
698 $this->setCfHeaders( $httpHeaders );
699 }
700
701 /**
702 * Retrieves the HTTP headers.
703 *
704 * @return array
705 */
706 public function getHttpHeaders() {
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 // are we using PHP-flavored headers?
722 if ( strpos( $header, '_' ) === false ) {
723 $header = str_replace( '-', '_', $header );
724 $header = strtoupper( $header );
725 }
726
727 // test the alternate, too
728 $altHeader = 'HTTP_' . $header;
729
730 //Test both the regular and the HTTP_ prefix
731 if ( isset( $this->httpHeaders[ $header ] ) ) {
732 return $this->httpHeaders[ $header ];
733 } elseif ( isset( $this->httpHeaders[ $altHeader ] ) ) {
734 return $this->httpHeaders[ $altHeader ];
735 }
736
737 return null;
738 }
739
740 public function getMobileHeaders() {
741 return self::$mobileHeaders;
742 }
743
744 /**
745 * Get all possible HTTP headers that
746 * can contain the User-Agent string.
747 *
748 * @return array List of HTTP headers.
749 */
750 public function getUaHttpHeaders() {
751 return self::$uaHttpHeaders;
752 }
753
754
755 /**
756 * Set CloudFront headers
757 * http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
758 *
759 * @param array $cfHeaders List of HTTP headers
760 *
761 * @return boolean If there were CloudFront headers to be set
762 */
763 public function setCfHeaders( $cfHeaders = null ) {
764 // use global _SERVER if $cfHeaders aren't defined
765 if ( ! is_array( $cfHeaders ) || ! count( $cfHeaders ) ) {
766 $cfHeaders = $_SERVER;
767 }
768
769 // clear existing headers
770 $this->cloudfrontHeaders = array();
771
772 // Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that
773 // start with cloudfront-.
774 $response = false;
775 foreach ( $cfHeaders as $key => $value ) {
776 if ( substr( strtolower( $key ), 0, 16 ) === 'http_cloudfront_' ) {
777 $this->cloudfrontHeaders[ strtoupper( $key ) ] = $value;
778 $response = true;
779 }
780 }
781
782 return $response;
783 }
784
785 /**
786 * Retrieves the cloudfront headers.
787 *
788 * @return array
789 */
790 public function getCfHeaders() {
791 return $this->cloudfrontHeaders;
792 }
793
794 /**
795 * Set the User-Agent to be used.
796 *
797 * @param string $userAgent The user agent string to set.
798 *
799 * @return string|null
800 */
801 public function setUserAgent( $userAgent = null ) {
802 // Invalidate cache due to #375
803 $this->cache = array();
804
805 if ( false === empty( $userAgent ) ) {
806 return $this->userAgent = $userAgent;
807 } else {
808 $this->userAgent = null;
809 foreach ( $this->getUaHttpHeaders() as $altHeader ) {
810 if ( false === empty( $this->httpHeaders[ $altHeader ] ) ) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
811 $this->userAgent .= $this->httpHeaders[ $altHeader ] . ' ';
812 }
813 }
814
815 if ( ! empty( $this->userAgent ) ) {
816 return $this->userAgent = trim( $this->userAgent );
817 }
818 }
819
820 if ( count( $this->getCfHeaders() ) > 0 ) {
821 return $this->userAgent = 'Amazon CloudFront';
822 }
823 return $this->userAgent = null;
824 }
825
826 /**
827 * Retrieve the User-Agent.
828 *
829 * @return string|null The user agent if it's set.
830 */
831 public function getUserAgent() {
832 return $this->userAgent;
833 }
834
835 /**
836 * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or
837 * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set.
838 *
839 * @deprecated since version 2.6.9
840 *
841 * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default
842 * parameter is null which will default to self::DETECTION_TYPE_MOBILE.
843 */
844 public function setDetectionType( $type = null ) {
845 if ( null == $type ) {
846 $type = self::DETECTION_TYPE_MOBILE;
847 }
848
849 if ( self::DETECTION_TYPE_MOBILE != $type && self::DETECTION_TYPE_EXTENDED != $type ) {
850 return;
851 }
852
853 $this->detectionType = $type;
854 }
855
856 public function getMatchingRegex() {
857 return $this->matchingRegex;
858 }
859
860 public function getMatchesArray() {
861 return $this->matchesArray;
862 }
863
864 /**
865 * Retrieve the list of known phone devices.
866 *
867 * @return array List of phone devices.
868 */
869 public static function getPhoneDevices() {
870 return self::$phoneDevices;
871 }
872
873 /**
874 * Retrieve the list of known tablet devices.
875 *
876 * @return array List of tablet devices.
877 */
878 public static function getTabletDevices() {
879 return self::$tabletDevices;
880 }
881
882 /**
883 * Alias for getBrowsers() method.
884 *
885 * @return array List of user agents.
886 */
887 public static function getUserAgents() {
888 return self::getBrowsers();
889 }
890
891 /**
892 * Retrieve the list of known browsers. Specifically, the user agents.
893 *
894 * @return array List of browsers / user agents.
895 */
896 public static function getBrowsers() {
897 return self::$browsers;
898 }
899
900 /**
901 * Retrieve the list of known utilities.
902 *
903 * @return array List of utilities.
904 */
905 public static function getUtilities() {
906 return self::$utilities;
907 }
908
909 /**
910 * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*().
911 *
912 * @deprecated since version 2.6.9
913 *
914 * @return array All the rules (but not extended).
915 */
916 public static function getMobileDetectionRules() {
917 static $rules;
918
919 if ( ! $rules ) {
920 $rules = array_merge(
921 self::$phoneDevices,
922 self::$tabletDevices,
923 self::$operatingSystems,
924 self::$browsers
925 );
926 }
927
928 return $rules;
929
930 }
931
932 /**
933 * Method gets the mobile detection rules + utilities.
934 * The reason this is separate is because utilities rules
935 * don't necessary imply mobile. This method is used inside
936 * the new $detect->is('stuff') method.
937 *
938 * @deprecated since version 2.6.9
939 *
940 * @return array All the rules + extended.
941 */
942 public function getMobileDetectionRulesExtended() {
943 static $rules;
944
945 if ( ! $rules ) {
946 // Merge all rules together.
947 $rules = array_merge(
948 self::$phoneDevices,
949 self::$tabletDevices,
950 self::$operatingSystems,
951 self::$browsers,
952 self::$utilities
953 );
954 }
955
956 return $rules;
957 }
958
959 /**
960 * Retrieve the current set of rules.
961 *
962 * @deprecated since version 2.6.9
963 *
964 * @return array
965 */
966 public function getRules() {
967 if ( self::DETECTION_TYPE_EXTENDED == $this->detectionType ) {
968 return self::getMobileDetectionRulesExtended();
969 } else {
970 return self::getMobileDetectionRules();
971 }
972 }
973
974 /**
975 * Retrieve the list of mobile operating systems.
976 *
977 * @return array The list of mobile operating systems.
978 */
979 public static function getOperatingSystems() {
980 return self::$operatingSystems;
981 }
982
983 /**
984 * Check the HTTP headers for signs of mobile.
985 * This is the fastest mobile check possible; it's used
986 * inside isMobile() method.
987 *
988 * @return bool
989 */
990 public function checkHttpHeadersForMobile() {
991 foreach ( $this->getMobileHeaders() as $mobileHeader => $matchType ) {
992 if ( isset( $this->httpHeaders[ $mobileHeader ] ) ) {
993 if ( is_array( $matchType['matches'] ) ) {
994 foreach ( $matchType['matches'] as $_match ) {
995 if ( strpos( $this->httpHeaders[ $mobileHeader ], $_match ) !== false ) {
996 return true;
997 }
998 }
999
1000 return false;
1001 } else {
1002 return true;
1003 }
1004 }
1005 }
1006
1007 return false;
1008
1009 }
1010
1011 /**
1012 * Magic overloading method.
1013 *
1014 * @method boolean is[...]()
1015 * @param string $name
1016 * @param array $arguments
1017 * @return mixed
1018 * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is'
1019 */
1020 public function __call( $name, $arguments ) {
1021 // make sure the name starts with 'is', otherwise
1022 if ( substr( $name, 0, 2 ) !== 'is' ) {
1023 throw new BadMethodCallException( "No such method exists: $name" );
1024 }
1025
1026 $this->setDetectionType( self::DETECTION_TYPE_MOBILE );
1027
1028 $key = substr( $name, 2 );
1029
1030 return $this->matchUAAgainstKey( $key );
1031 }
1032
1033 /**
1034 * Find a detection rule that matches the current User-agent.
1035 *
1036 * @param null $userAgent deprecated
1037 * @return boolean
1038 */
1039 protected function matchDetectionRulesAgainstUA( $userAgent = null ) {
1040 // Begin general search.
1041 foreach ( $this->getRules() as $_regex ) {
1042 if ( empty( $_regex ) ) {
1043 continue;
1044 }
1045
1046 if ( $this->match( $_regex, $userAgent ) ) {
1047 return true;
1048 }
1049 }
1050
1051 return false;
1052 }
1053
1054 /**
1055 * Search for a certain key in the rules array.
1056 * If the key is found then try to match the corresponding
1057 * regex against the User-Agent.
1058 *
1059 * @param string $key
1060 *
1061 * @return boolean
1062 */
1063 protected function matchUAAgainstKey( $key ) {
1064 // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
1065 $key = strtolower( $key );
1066 if ( false === isset( $this->cache[ $key ] ) ) {
1067
1068 // change the keys to lower case
1069 $_rules = array_change_key_case( $this->getRules() );
1070
1071 if ( false === empty( $_rules[ $key ] ) ) {
1072 $this->cache[ $key ] = $this->match( $_rules[ $key ] );
1073 }
1074
1075 if ( false === isset( $this->cache[ $key ] ) ) {
1076 $this->cache[ $key ] = false;
1077 }
1078 }
1079
1080 return $this->cache[ $key ];
1081 }
1082
1083 /**
1084 * Check if the device is mobile.
1085 * Returns true if any type of mobile device detected, including special ones
1086 * @param null $userAgent deprecated
1087 * @param null $httpHeaders deprecated
1088 * @return bool
1089 */
1090 public function isMobile( $userAgent = null, $httpHeaders = null ) {
1091 if ( $httpHeaders ) {
1092 $this->setHttpHeaders( $httpHeaders );
1093 }
1094
1095 if ( $userAgent ) {
1096 $this->setUserAgent( $userAgent );
1097 }
1098
1099 // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
1100 if ( 'Amazon CloudFront' == $this->getUserAgent() ) {
1101 $cfHeaders = $this->getCfHeaders();
1102 if ( array_key_exists( 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders ) && 'true' == $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] ) {
1103 return true;
1104 }
1105 }
1106
1107 $this->setDetectionType( self::DETECTION_TYPE_MOBILE );
1108
1109 if ( $this->checkHttpHeadersForMobile() ) {
1110 return true;
1111 } else {
1112 return $this->matchDetectionRulesAgainstUA();
1113 }
1114
1115 }
1116
1117 /**
1118 * Check if the device is a tablet.
1119 * Return true if any type of tablet device is detected.
1120 *
1121 * @param string $userAgent deprecated
1122 * @param array $httpHeaders deprecated
1123 * @return bool
1124 */
1125 public function isTablet( $userAgent = null, $httpHeaders = null ) {
1126 // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
1127 if ( 'Amazon CloudFront' == $this->getUserAgent() ) {
1128 $cfHeaders = $this->getCfHeaders();
1129 if ( array_key_exists( 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders ) && 'true' == $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] ) {
1130 return true;
1131 }
1132 }
1133
1134 $this->setDetectionType( self::DETECTION_TYPE_MOBILE );
1135
1136 foreach ( self::$tabletDevices as $_regex ) {
1137 if ( $this->match( $_regex, $userAgent ) ) {
1138 return true;
1139 }
1140 }
1141
1142 return false;
1143 }
1144
1145 /**
1146 * This method checks for a certain property in the
1147 * userAgent.
1148 * @todo: The httpHeaders part is not yet used.
1149 *
1150 * @param string $key
1151 * @param string $userAgent deprecated
1152 * @param string $httpHeaders deprecated
1153 * @return bool|int|null
1154 */
1155 public function is( $key, $userAgent = null, $httpHeaders = null ) {
1156 // Set the UA and HTTP headers only if needed (eg. batch mode).
1157 if ( $httpHeaders ) {
1158 $this->setHttpHeaders( $httpHeaders );
1159 }
1160
1161 if ( $userAgent ) {
1162 $this->setUserAgent( $userAgent );
1163 }
1164
1165 $this->setDetectionType( self::DETECTION_TYPE_EXTENDED );
1166
1167 return $this->matchUAAgainstKey( $key );
1168 }
1169
1170 /**
1171 * Some detection rules are relative (not standard),
1172 * because of the diversity of devices, vendors and
1173 * their conventions in representing the User-Agent or
1174 * the HTTP headers.
1175 *
1176 * This method will be used to check custom regexes against
1177 * the User-Agent string.
1178 *
1179 * @param $regex
1180 * @param string $userAgent
1181 * @return bool
1182 *
1183 * @todo: search in the HTTP headers too.
1184 */
1185 public function match( $regex, $userAgent = null ) {
1186 $match = (bool) preg_match( sprintf( '#%s#is', $regex ), ( false === empty( $userAgent ) ? $userAgent : $this->userAgent ), $matches );
1187 // If positive match is found, store the results for debug.
1188 if ( $match ) {
1189 $this->matchingRegex = $regex;
1190 $this->matchesArray = $matches;
1191 }
1192
1193 return $match;
1194 }
1195
1196 /**
1197 * Get the properties array.
1198 *
1199 * @return array
1200 */
1201 public static function getProperties() {
1202 return self::$properties;
1203 }
1204
1205 /**
1206 * Prepare the version number.
1207 *
1208 * @todo Remove the error supression from str_replace() call.
1209 *
1210 * @param string $ver The string version, like "2.6.21.2152";
1211 *
1212 * @return float
1213 */
1214 public function prepareVersionNo( $ver ) {
1215 $ver = str_replace( array( '_', ' ', '/' ), '.', $ver );
1216 $arrVer = explode( '.', $ver, 2 );
1217
1218 if ( isset( $arrVer[1] ) ) {
1219 $arrVer[1] = @str_replace( '.', '', $arrVer[1] ); // @todo: treat strings versions.
1220 }
1221
1222 return (float) implode( '.', $arrVer );
1223 }
1224
1225 /**
1226 * Check the version of the given property in the User-Agent.
1227 * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
1228 *
1229 * @param string $propertyName The name of the property. See self::getProperties() array
1230 * keys for all possible properties.
1231 * @param string $type Either self::VERSION_TYPE_STRING to get a string value or
1232 * self::VERSION_TYPE_FLOAT indicating a float value. This parameter
1233 * is optional and defaults to self::VERSION_TYPE_STRING. Passing an
1234 * invalid parameter will default to the this type as well.
1235 *
1236 * @return string|float The version of the property we are trying to extract.
1237 */
1238 public function version( $propertyName, $type = self::VERSION_TYPE_STRING ) {
1239 if ( empty( $propertyName ) ) {
1240 return false;
1241 }
1242
1243 // set the $type to the default if we don't recognize the type
1244 if ( self::VERSION_TYPE_STRING != $type && self::VERSION_TYPE_FLOAT != $type ) {
1245 $type = self::VERSION_TYPE_STRING;
1246 }
1247
1248 $properties = self::getProperties();
1249
1250 // Check if the property exists in the properties array.
1251 if ( true == isset( $properties[ $propertyName ] ) ) {
1252
1253 // Prepare the pattern to be matched.
1254 // Make sure we always deal with an array (string is converted).
1255 $properties[ $propertyName ] = (array) $properties[ $propertyName ];
1256
1257 foreach ( $properties[ $propertyName ] as $propertyMatchString ) {
1258
1259 $propertyPattern = str_replace( '[VER]', self::VER, $propertyMatchString );
1260
1261 // Identify and extract the version.
1262 preg_match( sprintf( '#%s#is', $propertyPattern ), $this->userAgent, $match );
1263
1264 if ( false == empty( $match[1] ) ) {
1265 $version = ( self::VERSION_TYPE_FLOAT == $type ? $this->prepareVersionNo( $match[1] ) : $match[1] );
1266
1267 return $version;
1268 }
1269 }
1270 }
1271
1272 return false;
1273 }
1274
1275 /**
1276 * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants.
1277 *
1278 * @return string One of the self::MOBILE_GRADE_* constants.
1279 */
1280 public function mobileGrade() {
1281 $isMobile = $this->isMobile();
1282
1283 if (
1284 // 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)
1285 $this->is( 'iOS' ) && $this->version( 'iPad', self::VERSION_TYPE_FLOAT ) >= 4.3 ||
1286 $this->is( 'iOS' ) && $this->version( 'iPhone', self::VERSION_TYPE_FLOAT ) >= 4.3 ||
1287 $this->is( 'iOS' ) && $this->version( 'iPod', self::VERSION_TYPE_FLOAT ) >= 4.3 ||
1288
1289 // 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)
1290 // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
1291 // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
1292 // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
1293 ( $this->version( 'Android', self::VERSION_TYPE_FLOAT ) > 2.1 && $this->is( 'Webkit' ) ) ||
1294
1295 // 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)
1296 $this->version( 'Windows Phone OS', self::VERSION_TYPE_FLOAT ) >= 7.5 ||
1297
1298 // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10)
1299 $this->is( 'BlackBerry' ) && $this->version( 'BlackBerry', self::VERSION_TYPE_FLOAT ) >= 6.0 ||
1300 // Blackberry Playbook (1.0-2.0) - Tested on PlayBook
1301 $this->match( 'Playbook.*Tablet' ) ||
1302
1303 // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0)
1304 ( $this->version( 'webOS', self::VERSION_TYPE_FLOAT ) >= 1.4 && $this->match( 'Palm|Pre|Pixi' ) ) ||
1305 // Palm WebOS 3.0 - Tested on HP TouchPad
1306 $this->match( 'hp.*TouchPad' ) ||
1307
1308 // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices
1309 ( $this->is( 'Firefox' ) && $this->version( 'Firefox', self::VERSION_TYPE_FLOAT ) >= 18 ) ||
1310
1311 // Chrome for Android - Tested on Android 4.0, 4.1 device
1312 ( $this->is( 'Chrome' ) && $this->is( 'AndroidOS' ) && $this->version( 'Android', self::VERSION_TYPE_FLOAT ) >= 4.0 ) ||
1313
1314 // Skyfire 4.1 - Tested on Android 2.3 device
1315 ( $this->is( 'Skyfire' ) && $this->version( 'Skyfire', self::VERSION_TYPE_FLOAT ) >= 4.1 && $this->is( 'AndroidOS' ) && $this->version( 'Android', self::VERSION_TYPE_FLOAT ) >= 2.3 ) ||
1316
1317 // Opera Mobile 11.5-12: Tested on Android 2.3
1318 ( $this->is( 'Opera' ) && $this->version( 'Opera Mobi', self::VERSION_TYPE_FLOAT ) >= 11.5 && $this->is( 'AndroidOS' ) ) ||
1319
1320 // Meego 1.2 - Tested on Nokia 950 and N9
1321 $this->is( 'MeeGoOS' ) ||
1322
1323 // Tizen (pre-release) - Tested on early hardware
1324 $this->is( 'Tizen' ) ||
1325
1326 // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
1327 // @todo: more tests here!
1328 $this->is( 'Dolfin' ) && $this->version( 'Bada', self::VERSION_TYPE_FLOAT ) >= 2.0 ||
1329
1330 // UC Browser - Tested on Android 2.3 device
1331 ( ( $this->is( 'UC Browser' ) || $this->is( 'Dolfin' ) ) && $this->version( 'Android', self::VERSION_TYPE_FLOAT ) >= 2.3 ) ||
1332
1333 // Kindle 3 and Fire - Tested on the built-in WebKit browser for each
1334 ( $this->match( 'Kindle Fire' ) ||
1335 $this->is( 'Kindle' ) && $this->version( 'Kindle', self::VERSION_TYPE_FLOAT ) >= 3.0 ) ||
1336
1337 // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
1338 $this->is( 'AndroidOS' ) && $this->is( 'NookTablet' ) ||
1339
1340 // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7
1341 $this->version( 'Chrome', self::VERSION_TYPE_FLOAT ) >= 16 && ! $isMobile ||
1342
1343 // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7
1344 $this->version( 'Safari', self::VERSION_TYPE_FLOAT ) >= 5.0 && ! $isMobile ||
1345
1346 // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7
1347 $this->version( 'Firefox', self::VERSION_TYPE_FLOAT ) >= 10.0 && ! $isMobile ||
1348
1349 // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
1350 $this->version( 'IE', self::VERSION_TYPE_FLOAT ) >= 7.0 && ! $isMobile ||
1351
1352 // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
1353 $this->version( 'Opera', self::VERSION_TYPE_FLOAT ) >= 10 && ! $isMobile
1354 ) {
1355 return self::MOBILE_GRADE_A;
1356 }
1357
1358 if (
1359 $this->is( 'iOS' ) && $this->version( 'iPad', self::VERSION_TYPE_FLOAT ) < 4.3 ||
1360 $this->is( 'iOS' ) && $this->version( 'iPhone', self::VERSION_TYPE_FLOAT ) < 4.3 ||
1361 $this->is( 'iOS' ) && $this->version( 'iPod', self::VERSION_TYPE_FLOAT ) < 4.3 ||
1362
1363 // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
1364 $this->is( 'Blackberry' ) && $this->version( 'BlackBerry', self::VERSION_TYPE_FLOAT ) >= 5 && $this->version( 'BlackBerry', self::VERSION_TYPE_FLOAT ) < 6 ||
1365
1366 //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
1367 ( $this->version( 'Opera Mini', self::VERSION_TYPE_FLOAT ) >= 5.0 && $this->version( 'Opera Mini', self::VERSION_TYPE_FLOAT ) <= 7.0 &&
1368 ( $this->version( 'Android', self::VERSION_TYPE_FLOAT ) >= 2.3 || $this->is( 'iOS' ) ) ) ||
1369
1370 // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
1371 $this->match( 'NokiaN8|NokiaC7|N97.*Series60|Symbian/3' ) ||
1372
1373 // @todo: report this (tested on Nokia N71)
1374 $this->version( 'Opera Mobi', self::VERSION_TYPE_FLOAT ) >= 11 && $this->is( 'SymbianOS' )
1375 ) {
1376 return self::MOBILE_GRADE_B;
1377 }
1378
1379 if (
1380 // Blackberry 4.x - Tested on the Curve 8330
1381 $this->version( 'BlackBerry', self::VERSION_TYPE_FLOAT ) <= 5.0 ||
1382 // Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
1383 $this->match( 'MSIEMobile|Windows CE.*Mobile' ) || $this->version( 'Windows Mobile', self::VERSION_TYPE_FLOAT ) <= 5.2 ||
1384
1385 // Tested on original iPhone (3.1), iPhone 3 (3.2)
1386 $this->is( 'iOS' ) && $this->version( 'iPad', self::VERSION_TYPE_FLOAT ) <= 3.2 ||
1387 $this->is( 'iOS' ) && $this->version( 'iPhone', self::VERSION_TYPE_FLOAT ) <= 3.2 ||
1388 $this->is( 'iOS' ) && $this->version( 'iPod', self::VERSION_TYPE_FLOAT ) <= 3.2 ||
1389
1390 // Internet Explorer 7 and older - Tested on Windows XP
1391 $this->version( 'IE', self::VERSION_TYPE_FLOAT ) <= 7.0 && ! $isMobile
1392 ) {
1393 return self::MOBILE_GRADE_C;
1394 }
1395
1396 // All older smartphone platforms and featurephones - Any device that doesn't support media queries
1397 // will receive the basic, C grade experience.
1398 return self::MOBILE_GRADE_C;
1399 }
1400 }
1401