PluginProbe ʕ •ᴥ•ʔ
Premium Addons for Elementor – Powerful Elementor Templates & Widgets / 4.11.34
Premium Addons for Elementor – Powerful Elementor Templates & Widgets v4.11.34
4.11.83 4.11.82 4.11.80 4.11.81 4.11.79 4.11.78 4.11.77 4.11.76 4.11.75 3.20.5 4.11.69 3.20.6 4.11.7 3.20.7 4.11.70 3.20.8 4.11.71 3.20.9 4.11.72 3.21.1 4.11.73 3.21.2 4.11.74 3.21.3 4.11.8 3.21.4 4.11.9 3.21.5 4.2.0 3.21.6 4.2.1 3.3.0 4.2.2 3.3.1 4.2.3 3.3.2 4.2.4 3.3.3 4.2.5 3.3.4 4.2.6 3.3.5 4.2.7 3.3.6 4.2.8 3.3.7 4.2.9 3.3.8 4.3.0 3.3.9 4.3.1 3.4.0 4.3.2 3.4.1 4.3.3 3.4.2 4.3.4 3.4.3 4.3.5 3.4.4 4.3.6 3.4.5 4.3.7 3.4.6 4.3.8 3.4.7 4.3.9 3.4.8 4.4.0 3.4.9 4.4.1 3.5.0 4.4.2 3.5.1 4.4.3 3.5.2 4.4.4 3.5.3 4.4.5 3.5.4 4.4.6 3.5.5 4.4.7 3.5.6 4.4.8 3.5.7 4.4.9 3.5.8 4.5.0 3.5.9 4.5.1 3.6.0 4.5.2 3.6.1 4.5.3 3.6.2 4.5.4 3.6.3 4.5.5 3.6.4 4.5.6 3.6.5 4.5.7 3.6.6 4.5.8 3.6.7 4.5.9 3.6.8 4.6.0 3.6.9 4.6.1 3.7.0 4.7.0 3.7.1 4.7.1 3.7.2 4.7.2 3.7.3 4.7.3 3.7.4 4.7.4 3.7.5 4.7.5 3.7.6 4.7.6 3.7.7 4.7.7 3.7.8 4.7.8 3.7.9 4.7.9 3.8.0 4.8.0 3.8.1 4.8.1 3.8.2 4.8.10 3.8.3 4.8.11 3.8.4 4.8.2 3.8.5 4.8.3 3.8.6 4.8.4 3.8.7 4.8.5 3.8.8 4.8.6 3.8.9 4.8.7 3.9.0 4.8.8 3.9.1 4.8.9 3.9.2 4.9.0 3.9.3 4.9.0-beta1 3.9.4 4.9.0-beta2 3.9.5 4.9.1 3.9.6 4.9.10 3.9.7 4.9.11 3.9.8 4.9.12 3.9.9 4.9.13 4.0.1 4.9.14 4.0.3 4.9.15 4.0.4 4.9.16 4.0.5 4.9.17 4.0.6 4.9.18 4.0.7 4.9.19 4.0.8 4.9.2 4.0.9 4.9.20 4.1.0 4.9.21 4.1.1 4.9.22 4.1.2 4.9.23 4.1.3 4.9.24 trunk 4.1.4 4.9.25 1.0 4.1.5 4.9.26 1.01 4.1.6 4.9.27 1.02 4.1.7 4.9.28 1.03 4.1.8 4.9.29 1.04 4.1.9 4.9.3 1.05 4.10.0 4.9.30 1.06 4.10.1 4.9.31 1.07 4.10.10 4.9.32 1.08 4.10.11 4.9.33 1.09 4.10.12 4.9.34 2.0 4.10.13 4.9.35 2.0.1 4.10.14 4.9.36 2.0.2 4.10.15 4.9.37 2.0.3 4.10.16 4.9.38 2.0.4 4.10.17 4.9.39 2.0.5 4.10.18 4.9.4 2.0.6 4.10.19 4.9.40 2.0.7 4.10.2 4.9.41 2.0.8 4.10.20 4.9.42 2.0.9 4.10.21 4.9.43 2.1.0 4.10.22 4.9.45 2.1.1 4.10.23 4.9.46 2.1.2 4.10.24 4.9.47 2.1.3 4.10.25 4.9.48 2.1.4 4.10.26 4.9.49 2.1.5 4.10.27 4.9.5 2.1.5-beta1 4.10.28 4.9.50 2.1.6 4.10.29 4.9.51 2.1.7 4.10.3 4.9.52 2.1.8 4.10.30 4.9.53 2.1.9 4.10.31 4.9.54 2.2.0 4.10.32 4.9.55 2.2.1 4.10.33 4.9.56 2.2.2 4.10.34 4.9.57 2.2.3 4.10.35 4.9.6 2.2.4 4.10.36 4.9.7 2.2.5 4.10.37 4.9.8 2.2.6 4.10.38 4.9.9 2.2.7 4.10.39 2.2.8 4.10.4 2.2.9 4.10.40 2.3.0 4.10.41 2.3.1 4.10.42 2.3.2 4.10.43 2.3.3 4.10.44 2.3.4 4.10.45 2.3.5 4.10.46 2.3.6 4.10.47 2.3.7 4.10.48 2.3.8 4.10.49 2.3.9 4.10.5 2.4.0 4.10.50 2.4.1 4.10.51 2.5.0 4.10.52 2.5.1 4.10.53 2.5.2 4.10.54 2.5.3 4.10.55 2.5.4 4.10.56 2.5.5 4.10.57 2.5.6 4.10.58 2.5.7 4.10.59 2.5.8 4.10.6 2.5.9 4.10.60 2.6.0 4.10.61 2.6.1 4.10.62 2.6.2 4.10.63 2.6.3 4.10.64 2.6.4 4.10.65 2.6.5 4.10.66 2.6.6 4.10.67 2.6.7 4.10.68 2.6.8 4.10.69 2.6.9 4.10.7 2.7.0 4.10.70 2.7.1 4.10.71 2.7.2 4.10.72 2.7.3 4.10.73 2.7.4 4.10.74 2.7.5 4.10.75 2.7.6 4.10.76 2.7.7 4.10.77 2.7.8 4.10.78 2.7.9 4.10.79 2.8.0 4.10.8 2.8.1 4.10.80 2.8.2 4.10.81 2.8.3 4.10.82 2.8.4 4.10.83 2.8.5 4.10.84 2.8.6 4.10.85 2.8.7 4.10.86 2.8.8 4.10.87 2.8.9 4.10.88 2.9.0 4.10.89 2.9.1 4.10.9 2.9.2 4.10.90 2.9.3 4.11.0 2.9.4 4.11.1 2.9.5 4.11.10 2.9.6 4.11.11 2.9.7 4.11.12 2.9.8 4.11.13 2.9.9 4.11.14 3.0.0 4.11.15 3.0.1 4.11.16 3.0.2 4.11.17 3.0.3 4.11.18 3.0.4 4.11.19 3.0.5 4.11.2 3.0.6 4.11.20 3.0.7 4.11.21 3.0.8 4.11.22 3.0.9 4.11.23 3.1.0 4.11.24 3.1.1 4.11.25 3.1.2 4.11.26 3.1.3 4.11.27 3.1.4 4.11.28 3.1.5 4.11.29 3.1.6 4.11.3 3.1.7 4.11.30 3.1.8 4.11.31 3.1.9 4.11.32 3.10.0 4.11.33 3.10.1 4.11.34 3.10.2 4.11.35 3.10.3 4.11.36 3.10.4 4.11.37 3.10.5 4.11.38 3.10.6 4.11.39 3.10.7 4.11.4 3.10.8 4.11.40 3.10.9 4.11.41 3.11.0 4.11.42 3.11.1 4.11.43 3.11.2 4.11.44 3.11.3 4.11.45 3.11.4 4.11.46 3.11.5 4.11.47 3.11.6 4.11.48 3.11.7 4.11.49 3.11.8 4.11.5 3.11.9 4.11.50 3.12.0 4.11.51 3.12.1 4.11.52 3.12.2 4.11.53 3.12.3 4.11.54 3.2.0 4.11.55 3.2.1 4.11.56 3.2.2 4.11.57 3.2.3 4.11.58 3.2.4 4.11.59 3.2.5 4.11.6 3.2.6 4.11.60 3.2.7 4.11.61 3.2.8 4.11.62 3.2.9 4.11.63 3.20.0 4.11.64 3.20.1 4.11.65 3.20.2 4.11.66 3.20.3 4.11.67 3.20.4 4.11.68
premium-addons-for-elementor / includes / pa-display-conditions / mobile-detector.php
premium-addons-for-elementor / includes / pa-display-conditions Last commit date
conditions 9 months ago lang-locale.php 9 months ago mobile-detector.php 9 months ago pa-controls-handler.php 9 months ago
mobile-detector.php
1467 lines
1 <?php
2
3 /**
4 * Mobile Detect Library
5 * Motto: "Every business should have a mobile detection script to detect mobile readers"
6 *
7 * PA_Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets).
8 * It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.
9 *
10 * Homepage: http://mobiledetect.net
11 * GitHub: https://github.com/serbanghita/Mobile-Detect
12 * README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md
13 * CONTRIBUTING: https://github.com/serbanghita/Mobile-Detect/blob/master/docs/CONTRIBUTING.md
14 * KNOWN LIMITATIONS: https://github.com/serbanghita/Mobile-Detect/blob/master/docs/KNOWN_LIMITATIONS.md
15 * EXAMPLES: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples
16 *
17 * @license https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt MIT License
18 * @author Serban Ghita <serbanghita@gmail.com>
19 * @author Nick Ilyin <nick.ilyin@gmail.com>
20 * Original author: Victor Stanciu <vic.stanciu@gmail.com>
21 *
22 * @version 2.8.36
23 */
24 class PA_Mobile_Detect {
25
26 /**
27 * Mobile detection type.
28 *
29 * @deprecated since version 2.6.9
30 */
31 const DETECTION_TYPE_MOBILE = 'mobile';
32
33 /**
34 * Extended detection type.
35 *
36 * @deprecated since version 2.6.9
37 */
38 const DETECTION_TYPE_EXTENDED = 'extended';
39
40 /**
41 * A frequently used regular expression to extract version #s.
42 *
43 * @deprecated since version 2.6.9
44 */
45 const VER = '([\w._\+]+)';
46
47 /**
48 * Top-level device.
49 */
50 const MOBILE_GRADE_A = 'A';
51
52 /**
53 * Mid-level device.
54 */
55 const MOBILE_GRADE_B = 'B';
56
57 /**
58 * Low-level device.
59 */
60 const MOBILE_GRADE_C = 'C';
61
62 /**
63 * Stores the version number of the current release.
64 */
65 const VERSION = '2.8.36';
66
67 /**
68 * A type for the version() method indicating a string return value.
69 */
70 const VERSION_TYPE_STRING = 'text';
71
72 /**
73 * A type for the version() method indicating a float return value.
74 */
75 const VERSION_TYPE_FLOAT = 'float';
76
77 /**
78 * A cache for resolved matches
79 *
80 * @var array
81 */
82 protected $cache = array();
83
84 /**
85 * The User-Agent HTTP header is stored in here.
86 *
87 * @var string
88 */
89 protected $userAgent = null;
90
91 /**
92 * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE.
93 *
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 *
101 * @var array
102 */
103 protected $cloudfrontHeaders = array();
104
105 /**
106 * The matching Regex.
107 * This is good for debug.
108 *
109 * @var string
110 */
111 protected $matchingRegex = null;
112
113 /**
114 * The matches extracted from the regex expression.
115 * This is good for debug.
116 *
117 * @var string
118 */
119 protected $matchesArray = null;
120
121 /**
122 * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED.
123 *
124 * @deprecated since version 2.6.9
125 *
126 * @var string
127 */
128 protected $detectionType = self::DETECTION_TYPE_MOBILE;
129
130 /**
131 * HTTP headers that trigger the 'isMobile' detection
132 * to be true.
133 *
134 * @var array
135 */
136 protected static $mobileHeaders = array(
137
138 'HTTP_ACCEPT' => array(
139 'matches' => array(
140 // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
141 'application/x-obml2d',
142 // BlackBerry devices.
143 'application/vnd.rim.html',
144 'text/vnd.wap.wml',
145 'application/vnd.wap.xhtml+xml',
146 ),
147 ),
148 'HTTP_X_WAP_PROFILE' => null,
149 'HTTP_X_WAP_CLIENTID' => null,
150 'HTTP_WAP_CONNECTION' => null,
151 'HTTP_PROFILE' => null,
152 // Reported by Opera on Nokia devices (eg. C3).
153 'HTTP_X_OPERAMINI_PHONE_UA' => null,
154 'HTTP_X_NOKIA_GATEWAY_ID' => null,
155 'HTTP_X_ORANGE_ID' => null,
156 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
157 'HTTP_X_HUAWEI_USERID' => null,
158 // Reported by Windows Smartphones.
159 'HTTP_UA_OS' => null,
160 // Reported by Verizon, Vodafone proxy system.
161 'HTTP_X_MOBILE_GATEWAY' => null,
162 // Seen this on HTC Sensation. SensationXE_Beats_Z715e.
163 'HTTP_X_ATT_DEVICEID' => null,
164 // Seen this on a HTC.
165 'HTTP_UA_CPU' => array( 'matches' => array( 'ARM' ) ),
166 );
167
168 /**
169 * List of mobile devices (phones).
170 *
171 * @var array
172 */
173 protected static $phoneDevices = array(
174 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes
175 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+|\b(BBA100|BBB100|BBD100|BBE100|BBF100|STH100)\b-[0-9]+',
176 'Pixel' => '; \bPixel\b',
177 '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|Android [0-9.]+; Pixel',
178 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6',
179 // @todo: Is 'Dell Streak' a tablet or a phone? ;)
180 'Dell' => 'Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
181 '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|XT1068|XT1092|XT1052',
182 'Samsung' => '\bSamsung\b|SM-G950F|SM-G955F|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|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F|SM-G610F|SM-G981B',
183 '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|M257)|LM-G710',
184 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533',
185 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile',
186 'NokiaLumia' => 'Lumia [0-9]{3,4}',
187 // http://www.micromaxinfo.com/mobiles/smartphones
188 // Added because the codes might conflict with Acer Tablets.
189 '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',
190 // @todo Complete the regex.
191 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ;
192 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;)
193 // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
194 // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
195 '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',
196 // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
197 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
198 // http://fr.wikomobile.com
199 'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM',
200 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)',
201 // Added simvalley mobile just for fun. They have some interesting devices.
202 // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html
203 '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',
204 // Wolfgang - a brand that is sold by Aldi supermarkets.
205 // http://www.wolfgangmobile.com/
206 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q',
207 'Alcatel' => 'Alcatel',
208 'Nintendo' => 'Nintendo (3DS|Switch)',
209 // http://en.wikipedia.org/wiki/Amoi
210 'Amoi' => 'Amoi',
211 // http://en.wikipedia.org/wiki/INQ
212 'INQ' => 'INQ',
213 'OnePlus' => 'ONEPLUS',
214 // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
215 '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',
216 );
217
218 /**
219 * List of tablet devices.
220 *
221 * @var array
222 */
223 protected static $tabletDevices = array(
224 // @todo: check for mobile friendly emails topic.
225 'iPad' => 'iPad|iPad.*Mobile',
226 // Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
227 // @see #442
228 // @todo Merge NexusTablet into GoogleTablet.
229 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
230 // https://en.wikipedia.org/wiki/Pixel_C
231 'GoogleTablet' => 'Android.*Pixel C',
232 '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-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835|SM-T830|SM-T837V|SM-T720|SM-T510|SM-T387V|SM-P610|SM-T290|SM-T515|SM-T590|SM-T595|SM-T725|SM-T817P|SM-P585N0|SM-T395|SM-T295|SM-T865|SM-P610N|SM-P615|SM-T970', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
233 // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
234 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\b|Android.*Silk/[0-9.]+ like Chrome/[0-9.]+ (?!Mobile)',
235 // Only the Surface tablets with Windows RT are considered mobile.
236 // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
237 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
238 // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT
239 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
240 // Watch out for PadFone, see #132.
241 // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/
242 '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 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\bP027\b|\bP024\b|\bP00C\b',
243 'BlackBerryTablet' => 'PlayBook|RIM Tablet',
244 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
245 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
246 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
247 // http://www.acer.ro/ac/ro/RO/content/drivers
248 // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
249 // http://us.acer.com/ac/en/US/content/group/tablets
250 // http://www.acer.de/ac/de/DE/content/models/tablets/
251 // Can conflict with Micromax and Motorola phones codes.
252 '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|\bA3-A20\b|\bA3-A30',
253 // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
254 // http://us.toshiba.com/tablets/tablet-finder
255 // http://www.toshiba.co.jp/regza/tablet/
256 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
257 // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
258 // http://www.lg.com/us/tablets
259 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b',
260 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
261 // Prestigio Tablets http://www.prestigio.com/support
262 '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',
263 // http://support.lenovo.com/en_GB/downloads/default.page?#
264 'LenovoTablet' => 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304X|TB-X304F|TB-X304L|TB-X505F|TB-X505L|TB-X505X|TB-X605F|TB-X605L|TB-8703F|TB-8703X|TB-8703N|TB-8704N|TB-8704F|TB-8704X|TB-8704V|TB-7304F|TB-7304I|TB-7304X|Tab2A7-10F|Tab2A7-20F|TB2-X30L|YT3-X50L|YT3-X50F|YT3-X50M|YT-X705F|YT-X703F|YT-X703L|YT-X705L|YT-X705X|TB2-X30F|TB2-X30L|TB2-X30M|A2107A-F|A2107A-H|TB3-730F|TB3-730M|TB3-730X|TB-7504F|TB-7504X',
265 // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets
266 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7',
267 // http://www.yarvik.com/en/matrix/tablets/
268 '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',
269 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
270 'ArnovaTablet' => '97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2',
271 // http://www.intenso.de/kategorie_en.php?kategorie=33
272 // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate
273 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
274 // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/
275 'IRUTablet' => 'M702pro',
276 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
277 // http://www.e-boda.ro/tablete-pc.html
278 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
279 // http://www.allview.ro/produse/droseries/lista-tablete-pc/
280 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
281 // http://wiki.archosfans.com/index.php?title=Main_Page
282 // @note Rewrite the regex format after we add more UAs.
283 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b',
284 // http://www.ainol.com/plugin.php?identifier=ainol&module=product
285 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
286 'NokiaLumiaTablet' => 'Lumia 2520',
287 // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
288 // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
289 // http://www.sony.jp/support/tablet/
290 '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|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712',
291 // 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
292 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
293 // db + http://www.cube-tablet.com/buy-products.html
294 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
295 // http://www.cobyusa.com/?p=pcat&pcat_id=3001
296 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
297 // http://www.match.net.cn/products.asp
298 '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|MID4X10',
299 // http://www.msi.com/support
300 // @todo Research the Windows Tablets.
301 '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',
302 // @todo http://www.kyoceramobile.com/support/drivers/
303 // 'KyoceraTablet' => null,
304 // @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/
305 // 'IntextTablet' => null,
306 // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
307 // http://www.imp3.net/14/show.php?itemid=20454
308 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
309 // http://www.rock-chips.com/index.php?do=prod&pid=2
310 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
311 // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
312 'FlyTablet' => 'IQ310|Fly Vision',
313 // http://www.bqreaders.com/gb/tablets-prices-sale.html
314 'bqTablet' => 'Android.*(bq)?.*\b(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))\b|Maxwell.*Lite|Maxwell.*Plus',
315 // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
316 // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
317 '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|M2-A01L|BAH-L09|BAH-W09|AGS-L09|CMR-AL19',
318 // Nec or Medias Tab
319 'NecTablet' => '\bN-06D|\bN-08D',
320 // Pantech Tablets: http://www.pantechusa.com/phones/
321 'PantechTablet' => 'Pantech.*P4100',
322 // Broncho Tablets: http://www.broncho.cn/ (hard to find)
323 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
324 // http://versusuk.com/support.html
325 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
326 // http://www.zync.in/index.php/our-products/tablet-phablets
327 'ZyncTablet' => 'z1000|Z99 2G|z930|z990|z909|Z919|z900', // Removed "z999" because of https://github.com/serbanghita/Mobile-Detect/issues/717
328 // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
329 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
330 // https://www.nabitablet.com/
331 'NabiTablet' => 'Android.*\bNabi',
332 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
333 // French Danew Tablets http://www.danew.com/produits-tablette.php
334 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
335 // Texet Tablets and Readers http://www.texet.ru/tablet/
336 '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',
337 // Avoid detecting 'PLAYSTATION 3' as mobile.
338 'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
339 // http://www.trekstor.de/surftabs.html
340 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
341 // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets
342 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
343 // http://www.advandigital.com/index.php?link=content-product&jns=JP001
344 // because of the short codenames we have to include whitespaces to reduce the possible conflicts.
345 '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 ',
346 // http://www.danytech.com/category/tablet-pc
347 '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',
348 // http://www.galapad.net/product.html ; https://github.com/serbanghita/Mobile-Detect/issues/761
349 'GalapadTablet' => 'Android [0-9.]+; [a-z-]+; \bG1\b',
350 // http://www.micromaxinfo.com/tablet/funbook
351 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
352 // http://www.karbonnmobiles.com/products_tablet.php
353 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
354 // http://www.myallfine.com/Products.asp
355 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
356 // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
357 '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',
358 // http://www.yonesnav.com/products/products.php
359 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
360 // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
361 // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html)
362 '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',
363 // http://www.gloryunion.cn/products.asp
364 // http://www.allwinnertech.com/en/apply/mobile.html
365 // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB)
366 // @todo: Softwiner tablets?
367 // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions.
368 '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
369 // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118
370 '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',
371 // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/
372 // @todo: add more tests.
373 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027',
374 // http://hclmetablet.com/India/index.php
375 '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',
376 // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html
377 'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
378 // http://www.visture.com/index.asp
379 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
380 // http://www.mijncresta.nl/tablet
381 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
382 // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309
383 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
384 // Concorde tab
385 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
386 // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/
387 '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',
388 // Modecom Tablets - http://www.modecom.eu/tablets/portal/
389 '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',
390 // Vonino Tablets
391 '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',
392 // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0
393 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
394 // Storex Tablets - http://storex.fr/espace_client/support.html
395 // @note: no need to add all the tablet codes since they are guided by the first regex.
396 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
397 // Generic Vodafone tablets.
398 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497|VFD 1400',
399 // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb
400 // Aka: http://www.essentielb.fr/
401 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
402 // Ross & Moor - http://ross-moor.ru/
403 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
404 // i-mobile http://product.i-mobilephone.com/Mobile_Device
405 'iMobileTablet' => 'i-mobile i-note',
406 // http://www.tolino.de/de/vergleichen/
407 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
408 // AudioSonic - a Kmart brand
409 // 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
410 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
411 // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/
412 // @todo: add them gradually to avoid conflicts.
413 'AMPETablet' => 'Android.* A78 ',
414 // Skk Mobile - http://skkmobile.com.ph/product_tablets.php
415 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
416 // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1
417 'TecnoTablet' => 'TECNO P9|TECNO DP8D',
418 // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3
419 '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',
420 // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/
421 '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)',
422 // http://www.intracon.eu/tablet
423 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
424 // http://www.xoro.de/produkte/
425 // @note: Might be the same brand with 'Simply tablets'
426 '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',
427 // http://www1.viewsonic.com/products/computing/tablets/
428 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
429 // https://www.verizonwireless.com/tablets/verizon/
430 'VerizonTablet' => 'QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1',
431 // http://www.odys.de/web/internet-tablet_en.html
432 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
433 // http://www.captiva-power.de/products.html#tablets-en
434 'CaptivaTablet' => 'CAPTIVA PAD',
435 // IconBIT - http://www.iconbit.com/products/tablets/
436 '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',
437 // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63
438 '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',
439 // Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price
440 '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]+|V10 \b4G\b',
441 'JaytechTablet' => 'TPC-PA762',
442 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
443 // http://www.digma.ru/support/download/
444 // @todo: Ebooks also (if requested)
445 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
446 // http://www.evolioshop.com/ro/tablete-pc.html
447 // http://www.evolio.ro/support/downloads_static.html?cat=2
448 // @todo: Research some more
449 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
450 // @todo http://www.lavamobiles.com/tablets-data-cards
451 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b',
452 // http://www.breezetablet.com/
453 'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712',
454 // http://www.mpmaneurope.com/en/products/internet-tablets-14/android-tablets-14/
455 'MpmanTablet' => 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010',
456 // https://www.celkonmobiles.com/?_a=categoryphones&sid=2
457 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b',
458 // http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab
459 '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',
460 'MediacomTablet' => 'M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA',
461 // http://www.mi.com/en
462 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b',
463 // http://www.nbru.cn/index.html
464 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One',
465 // http://navroad.com/products/produkty/tablety/
466 // http://navroad.com/products/produkty/tablety/
467 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI',
468 // http://leader-online.com/new_site/product-category/tablets/
469 // http://www.leader-online.net.au/List/Tablet
470 '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',
471 // http://www.datawind.com/ubislate/
472 'UbislateTablet' => 'UbiSlate[\s]?7C',
473 // http://www.pocketbook-int.com/ru/support
474 'PocketBookTablet' => 'Pocketbook',
475 // http://www.kocaso.com/product_tablet.html
476 'KocasoTablet' => '\b(TB-1207)\b',
477 // http://global.hisense.com/product/asia/tablet/Sero7/201412/t20141215_91832.htm
478 'HisenseTablet' => '\b(F5281|E2371)\b',
479 // http://www.tesco.com/direct/hudl/
480 'Hudl' => 'Hudl HT7S3|Hudl 2',
481 // http://www.telstra.com.au/home-phone/thub-2/
482 'TelstraTablet' => 'T-Hub2',
483 '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|\bTP750\b|\bQTAQZ3\b|WVT101|TM1088|KT107',
484 );
485
486 /**
487 * List of mobile Operating Systems.
488 *
489 * @var array
490 */
491 protected static $operatingSystems = array(
492 'AndroidOS' => 'Android',
493 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
494 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
495 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
496 // @reference: http://en.wikipedia.org/wiki/Windows_Mobile
497 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Windows Mobile|Windows Phone [0-9.]+|WCE;',
498 // @reference: http://en.wikipedia.org/wiki/Windows_Phone
499 // http://wifeng.cn/?r=blog&a=view&id=106
500 // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
501 // http://msdn.microsoft.com/library/ms537503.aspx
502 // https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
503 'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;',
504 'iOS' => '\biPhone.*Mobile|\biPod|\biPad|AppleCoreMedia',
505 // https://en.wikipedia.org/wiki/IPadOS
506 'iPadOS' => 'CPU OS 13',
507 // @reference https://en.m.wikipedia.org/wiki/Sailfish_OS
508 // https://sailfishos.org/
509 'SailfishOS' => 'Sailfish',
510 // http://en.wikipedia.org/wiki/MeeGo
511 // @todo: research MeeGo in UAs
512 'MeeGoOS' => 'MeeGo',
513 // http://en.wikipedia.org/wiki/Maemo
514 // @todo: research Maemo in UAs
515 'MaemoOS' => 'Maemo',
516 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135
517 'webOS' => 'webOS|hpwOS',
518 'badaOS' => '\bBada\b',
519 'BREWOS' => 'BREW',
520 );
521
522 /**
523 * List of mobile User Agents.
524 *
525 * IMPORTANT: This is a list of only mobile browsers.
526 * Mobile Detect 2.x supports only mobile browsers,
527 * it was never designed to detect all browsers.
528 * The change will come in 2017 in the 3.x release for PHP7.
529 *
530 * @var array
531 */
532 protected static $browsers = array(
533 // 'Vivaldi' => 'Vivaldi',
534 // @reference: https://developers.google.com/chrome/mobile/docs/user-agent
535 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
536 'Dolfin' => '\bDolfin\b',
537 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+$|Coast/[0-9.]+',
538 'Skyfire' => 'Skyfire',
539 // Added "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764
540 'Edge' => '\bEdgiOS\b|Mobile Safari/[.0-9]* Edge',
541 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+
542 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS',
543 'Bolt' => 'bolt',
544 'TeaShark' => 'teashark',
545 'Blazer' => 'Blazer',
546 // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
547 // Excluded "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764
548 'Safari' => 'Version((?!\bEdgiOS\b).)*Mobile.*Safari|Safari.*Mobile|MobileSafari',
549 // http://en.wikipedia.org/wiki/Midori_(web_browser)
550 // 'Midori' => 'midori',
551 // 'Tizen' => 'Tizen',
552 'WeChat' => '\bMicroMessenger\b',
553 'UCBrowser' => 'UC.*Browser|UCWEB',
554 'baiduboxapp' => 'baiduboxapp',
555 'baidubrowser' => 'baidubrowser',
556 // https://github.com/serbanghita/Mobile-Detect/issues/7
557 'DiigoBrowser' => 'DiigoBrowser',
558 // http://www.puffinbrowser.com/index.php
559 // https://github.com/serbanghita/Mobile-Detect/issues/752
560 // 'Puffin' => 'Puffin',
561 // http://mercury-browser.com/index.html
562 'Mercury' => '\bMercury\b',
563 // http://en.wikipedia.org/wiki/Obigo_Browser
564 'ObigoBrowser' => 'Obigo',
565 // http://en.wikipedia.org/wiki/NetFront
566 'NetFront' => 'NF-Browser',
567 // @reference: http://en.wikipedia.org/wiki/Minimo
568 // http://en.wikipedia.org/wiki/Vision_Mobile_Browser
569 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger',
570 // @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser)
571 'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon',
572 );
573
574 /**
575 * Utilities.
576 *
577 * @var array
578 */
579 protected static $utilities = array(
580 // Experimental. When a mobile device wants to switch to 'Desktop Mode'.
581 // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
582 // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
583 // https://developers.facebook.com/docs/sharing/webmasters/crawler/
584 'Bot' => 'Googlebot|facebookexternalhit|Google-AMPHTML|s~amp-validator|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom|contentkingapp|AspiegelBot',
585 'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2',
586 'DesktopMode' => 'WPDesktop',
587 'TV' => 'SonyDTV|HbbTV', // experimental
588 'WebKit' => '(webkit)[ /]([\w.]+)',
589 // @todo: Include JXD consoles.
590 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\b',
591 'Watch' => 'SM-V700',
592 );
593
594 /**
595 * All possible HTTP headers that represent the
596 * User-Agent string.
597 *
598 * @var array
599 */
600 protected static $uaHttpHeaders = array(
601 // The default User-Agent string.
602 'HTTP_USER_AGENT',
603 // Header can occur on devices using Opera Mini.
604 'HTTP_X_OPERAMINI_PHONE_UA',
605 // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
606 'HTTP_X_DEVICE_USER_AGENT',
607 'HTTP_X_ORIGINAL_USER_AGENT',
608 'HTTP_X_SKYFIRE_PHONE',
609 'HTTP_X_BOLT_PHONE_UA',
610 'HTTP_DEVICE_STOCK_UA',
611 'HTTP_X_UCBROWSER_DEVICE_UA',
612 );
613
614 /**
615 * The individual segments that could exist in a User-Agent string. VER refers to the regular
616 * expression defined in the constant self::VER.
617 *
618 * @var array
619 */
620 protected static $properties = array(
621
622 // Build
623 'Mobile' => 'Mobile/[VER]',
624 'Build' => 'Build/[VER]',
625 'Version' => 'Version/[VER]',
626 'VendorID' => 'VendorID/[VER]',
627
628 // Devices
629 'iPad' => 'iPad.*CPU[a-z ]+[VER]',
630 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
631 'iPod' => 'iPod.*CPU[a-z ]+[VER]',
632 // 'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
633 'Kindle' => 'Kindle/[VER]',
634
635 // Browser
636 'Chrome' => array( 'Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]' ),
637 'Coast' => array( 'Coast/[VER]' ),
638 'Dolfin' => 'Dolfin/[VER]',
639 // @reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox
640 'Firefox' => array( 'Firefox/[VER]', 'FxiOS/[VER]' ),
641 'Fennec' => 'Fennec/[VER]',
642 // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
643 // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
644 'Edge' => 'Edge/[VER]',
645 'IE' => array( 'IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]' ),
646 // http://en.wikipedia.org/wiki/NetFront
647 'NetFront' => 'NetFront/[VER]',
648 'NokiaBrowser' => 'NokiaBrowser/[VER]',
649 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ),
650 'Opera Mini' => 'Opera Mini/[VER]',
651 'Opera Mobi' => 'Version/[VER]',
652 'UCBrowser' => array( 'UCWEB[VER]', 'UC.*Browser/[VER]' ),
653 'MQQBrowser' => 'MQQBrowser/[VER]',
654 'MicroMessenger' => 'MicroMessenger/[VER]',
655 'baiduboxapp' => 'baiduboxapp/[VER]',
656 'baidubrowser' => 'baidubrowser/[VER]',
657 'SamsungBrowser' => 'SamsungBrowser/[VER]',
658 'Iron' => 'Iron/[VER]',
659 // @note: Safari 7534.48.3 is actually Version 5.1.
660 // @note: On BlackBerry the Version is overwriten by the OS.
661 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ),
662 'Skyfire' => 'Skyfire/[VER]',
663 'Tizen' => 'Tizen/[VER]',
664 'Webkit' => 'webkit[ /][VER]',
665 'PaleMoon' => 'PaleMoon/[VER]',
666 'SailfishBrowser' => 'SailfishBrowser/[VER]',
667
668 // Engine
669 'Gecko' => 'Gecko/[VER]',
670 'Trident' => 'Trident/[VER]',
671 'Presto' => 'Presto/[VER]',
672 'Goanna' => 'Goanna/[VER]',
673
674 // OS
675 'iOS' => ' \bi?OS\b [VER][ ;]{1}',
676 'Android' => 'Android [VER]',
677 'Sailfish' => 'Sailfish [VER]',
678 'BlackBerry' => array( 'BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]' ),
679 'BREW' => 'BREW [VER]',
680 'Java' => 'Java/[VER]',
681 // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
682 // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
683 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]' ),
684 'Windows Phone' => 'Windows Phone [VER]',
685 'Windows CE' => 'Windows CE/[VER]',
686 // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
687 'Windows NT' => 'Windows NT [VER]',
688 'Symbian' => array( 'SymbianOS/[VER]', 'Symbian/[VER]' ),
689 'webOS' => array( 'webOS/[VER]', 'hpwOS/[VER];' ),
690 );
691
692 /**
693 * Construct an instance of this class.
694 *
695 * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored.
696 * If left empty, will use the global _SERVER['HTTP_*'] vars instead.
697 * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT
698 * from the $headers array instead.
699 */
700 public function __construct(
701 array $headers = null,
702 $userAgent = null
703 ) {
704 $this->setHttpHeaders( $headers );
705 $this->setUserAgent( $userAgent );
706 }
707
708 /**
709 * Get the current script version.
710 * This is useful for the demo.php file,
711 * so people can check on what version they are testing
712 * for mobile devices.
713 *
714 * @return string The version number in semantic version format.
715 */
716 public static function getScriptVersion() {
717 return self::VERSION;
718 }
719
720 /**
721 * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers.
722 *
723 * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract
724 * the headers. The default null is left for backwards compatibility.
725 */
726 public function setHttpHeaders( $httpHeaders = null ) {
727 // use global _SERVER if $httpHeaders aren't defined
728 if ( ! is_array( $httpHeaders ) || ! count( $httpHeaders ) ) {
729 $httpHeaders = $_SERVER;
730 }
731
732 // clear existing headers
733 $this->httpHeaders = array();
734
735 // Only save HTTP headers. In PHP land, that means only _SERVER vars that
736 // start with HTTP_.
737 foreach ( $httpHeaders as $key => $value ) {
738 if ( substr( $key, 0, 5 ) === 'HTTP_' ) {
739 $this->httpHeaders[ $key ] = $value;
740 }
741 }
742
743 // In case we're dealing with CloudFront, we need to know.
744 $this->setCfHeaders( $httpHeaders );
745 }
746
747 /**
748 * Retrieves the HTTP headers.
749 *
750 * @return array
751 */
752 public function getHttpHeaders() {
753 return $this->httpHeaders;
754 }
755
756 /**
757 * Retrieves a particular header. If it doesn't exist, no exception/error is caused.
758 * Simply null is returned.
759 *
760 * @param string $header The name of the header to retrieve. Can be HTTP compliant such as
761 * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the
762 * all-caps, HTTP_ prefixed, underscore seperated awesomeness.
763 *
764 * @return string|null The value of the header.
765 */
766 public function getHttpHeader( $header ) {
767 // are we using PHP-flavored headers?
768 if ( strpos( $header, '_' ) === false ) {
769 $header = str_replace( '-', '_', $header );
770 $header = strtoupper( $header );
771 }
772
773 // test the alternate, too
774 $altHeader = 'HTTP_' . $header;
775
776 // Test both the regular and the HTTP_ prefix
777 if ( isset( $this->httpHeaders[ $header ] ) ) {
778 return $this->httpHeaders[ $header ];
779 } elseif ( isset( $this->httpHeaders[ $altHeader ] ) ) {
780 return $this->httpHeaders[ $altHeader ];
781 }
782
783 return null;
784 }
785
786 public function getMobileHeaders() {
787 return self::$mobileHeaders;
788 }
789
790 /**
791 * Get all possible HTTP headers that
792 * can contain the User-Agent string.
793 *
794 * @return array List of HTTP headers.
795 */
796 public function getUaHttpHeaders() {
797 return self::$uaHttpHeaders;
798 }
799
800
801 /**
802 * Set CloudFront headers
803 * http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
804 *
805 * @param array $cfHeaders List of HTTP headers
806 *
807 * @return boolean If there were CloudFront headers to be set
808 */
809 public function setCfHeaders( $cfHeaders = null ) {
810 // use global _SERVER if $cfHeaders aren't defined
811 if ( ! is_array( $cfHeaders ) || ! count( $cfHeaders ) ) {
812 $cfHeaders = $_SERVER;
813 }
814
815 // clear existing headers
816 $this->cloudfrontHeaders = array();
817
818 // Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that
819 // start with cloudfront-.
820 $response = false;
821 foreach ( $cfHeaders as $key => $value ) {
822 if ( substr( strtolower( $key ), 0, 16 ) === 'http_cloudfront_' ) {
823 $this->cloudfrontHeaders[ strtoupper( $key ) ] = $value;
824 $response = true;
825 }
826 }
827
828 return $response;
829 }
830
831 /**
832 * Retrieves the cloudfront headers.
833 *
834 * @return array
835 */
836 public function getCfHeaders() {
837 return $this->cloudfrontHeaders;
838 }
839
840 /**
841 * @param string $userAgent
842 * @return string
843 */
844 private function prepareUserAgent( $userAgent ) {
845 $userAgent = trim( $userAgent );
846 $userAgent = substr( $userAgent, 0, 500 );
847 return $userAgent;
848 }
849
850 /**
851 * Set the User-Agent to be used.
852 *
853 * @param string $userAgent The user agent string to set.
854 *
855 * @return string|null
856 */
857 public function setUserAgent( $userAgent = null ) {
858 // Invalidate cache due to #375
859 $this->cache = array();
860
861 if ( false === empty( $userAgent ) ) {
862 return $this->userAgent = $this->prepareUserAgent( $userAgent );
863 } else {
864 $this->userAgent = null;
865 foreach ( $this->getUaHttpHeaders() as $altHeader ) {
866 if ( false === empty( $this->httpHeaders[ $altHeader ] ) ) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
867 $this->userAgent .= $this->httpHeaders[ $altHeader ] . ' ';
868 }
869 }
870
871 if ( ! empty( $this->userAgent ) ) {
872 return $this->userAgent = $this->prepareUserAgent( $this->userAgent );
873 }
874 }
875
876 if ( count( $this->getCfHeaders() ) > 0 ) {
877 return $this->userAgent = 'Amazon CloudFront';
878 }
879 return $this->userAgent = null;
880 }
881
882 /**
883 * Retrieve the User-Agent.
884 *
885 * @return string|null The user agent if it's set.
886 */
887 public function getUserAgent() {
888 return $this->userAgent;
889 }
890
891 /**
892 * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or
893 * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set.
894 *
895 * @deprecated since version 2.6.9
896 *
897 * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default
898 * parameter is null which will default to self::DETECTION_TYPE_MOBILE.
899 */
900 public function setDetectionType( $type = null ) {
901 if ( $type === null ) {
902 $type = self::DETECTION_TYPE_MOBILE;
903 }
904
905 if ( $type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED ) {
906 return;
907 }
908
909 $this->detectionType = $type;
910 }
911
912 public function getMatchingRegex() {
913 return $this->matchingRegex;
914 }
915
916 public function getMatchesArray() {
917 return $this->matchesArray;
918 }
919
920 /**
921 * Retrieve the list of known phone devices.
922 *
923 * @return array List of phone devices.
924 */
925 public static function getPhoneDevices() {
926 return self::$phoneDevices;
927 }
928
929 /**
930 * Retrieve the list of known tablet devices.
931 *
932 * @return array List of tablet devices.
933 */
934 public static function getTabletDevices() {
935 return self::$tabletDevices;
936 }
937
938 /**
939 * Alias for getBrowsers() method.
940 *
941 * @return array List of user agents.
942 */
943 public static function getUserAgents() {
944 return self::getBrowsers();
945 }
946
947 /**
948 * Retrieve the list of known browsers. Specifically, the user agents.
949 *
950 * @return array List of browsers / user agents.
951 */
952 public static function getBrowsers() {
953 return self::$browsers;
954 }
955
956 /**
957 * Retrieve the list of known utilities.
958 *
959 * @return array List of utilities.
960 */
961 public static function getUtilities() {
962 return self::$utilities;
963 }
964
965 /**
966 * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*().
967 *
968 * @deprecated since version 2.6.9
969 *
970 * @return array All the rules (but not extended).
971 */
972 public static function getMobileDetectionRules() {
973 static $rules;
974
975 if ( ! $rules ) {
976 $rules = array_merge(
977 self::$phoneDevices,
978 self::$tabletDevices,
979 self::$operatingSystems,
980 self::$browsers
981 );
982 }
983
984 return $rules;
985 }
986
987 /**
988 * Method gets the mobile detection rules + utilities.
989 * The reason this is separate is because utilities rules
990 * don't necessary imply mobile. This method is used inside
991 * the new $detect->is('stuff') method.
992 *
993 * @deprecated since version 2.6.9
994 *
995 * @return array All the rules + extended.
996 */
997 public function getMobileDetectionRulesExtended() {
998 static $rules;
999
1000 if ( ! $rules ) {
1001 // Merge all rules together.
1002 $rules = array_merge(
1003 self::$phoneDevices,
1004 self::$tabletDevices,
1005 self::$operatingSystems,
1006 self::$browsers,
1007 self::$utilities
1008 );
1009 }
1010
1011 return $rules;
1012 }
1013
1014 /**
1015 * Retrieve the current set of rules.
1016 *
1017 * @deprecated since version 2.6.9
1018 *
1019 * @return array
1020 */
1021 public function getRules() {
1022 if ( $this->detectionType == self::DETECTION_TYPE_EXTENDED ) {
1023 return self::getMobileDetectionRulesExtended();
1024 } else {
1025 return self::getMobileDetectionRules();
1026 }
1027 }
1028
1029 /**
1030 * Retrieve the list of mobile operating systems.
1031 *
1032 * @return array The list of mobile operating systems.
1033 */
1034 public static function getOperatingSystems() {
1035 return self::$operatingSystems;
1036 }
1037
1038 /**
1039 * Check the HTTP headers for signs of mobile.
1040 * This is the fastest mobile check possible; it's used
1041 * inside isMobile() method.
1042 *
1043 * @return bool
1044 */
1045 public function checkHttpHeadersForMobile() {
1046
1047 foreach ( $this->getMobileHeaders() as $mobileHeader => $matchType ) {
1048 if ( isset( $this->httpHeaders[ $mobileHeader ] ) ) {
1049 if ( isset( $matchType['matches'] ) && is_array( $matchType['matches'] ) ) {
1050 foreach ( $matchType['matches'] as $_match ) {
1051 if ( strpos( $this->httpHeaders[ $mobileHeader ], $_match ) !== false ) {
1052 return true;
1053 }
1054 }
1055
1056 return false;
1057 } else {
1058 return true;
1059 }
1060 }
1061 }
1062
1063 return false;
1064 }
1065
1066 /**
1067 * Magic overloading method.
1068 *
1069 * @method boolean is[...]()
1070 * @param string $name
1071 * @param array $arguments
1072 * @return mixed
1073 * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is'
1074 */
1075 public function __call( $name, $arguments ) {
1076 // make sure the name starts with 'is', otherwise
1077 if ( substr( $name, 0, 2 ) !== 'is' ) {
1078 throw new BadMethodCallException( "No such method exists: $name" );
1079 }
1080
1081 $this->setDetectionType( self::DETECTION_TYPE_MOBILE );
1082
1083 $key = substr( $name, 2 );
1084
1085 return $this->matchUAAgainstKey( $key );
1086 }
1087
1088 /**
1089 * Find a detection rule that matches the current User-agent.
1090 *
1091 * @param null $userAgent deprecated
1092 * @return boolean
1093 */
1094 protected function matchDetectionRulesAgainstUA( $userAgent = null ) {
1095 // Begin general search.
1096 foreach ( $this->getRules() as $_regex ) {
1097 if ( empty( $_regex ) ) {
1098 continue;
1099 }
1100
1101 if ( $this->match( $_regex, $userAgent ) ) {
1102 return true;
1103 }
1104 }
1105
1106 return false;
1107 }
1108
1109 /**
1110 * Search for a certain key in the rules array.
1111 * If the key is found then try to match the corresponding
1112 * regex against the User-Agent.
1113 *
1114 * @param string $key
1115 *
1116 * @return boolean
1117 */
1118 protected function matchUAAgainstKey( $key ) {
1119 // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
1120 $key = strtolower( $key );
1121 if ( false === isset( $this->cache[ $key ] ) ) {
1122
1123 // change the keys to lower case
1124 $_rules = array_change_key_case( $this->getRules() );
1125
1126 if ( false === empty( $_rules[ $key ] ) ) {
1127 $this->cache[ $key ] = $this->match( $_rules[ $key ] );
1128 }
1129
1130 if ( false === isset( $this->cache[ $key ] ) ) {
1131 $this->cache[ $key ] = false;
1132 }
1133 }
1134
1135 return $this->cache[ $key ];
1136 }
1137
1138 /**
1139 * Check if the device is mobile.
1140 * Returns true if any type of mobile device detected, including special ones
1141 *
1142 * @param null $userAgent deprecated
1143 * @param null $httpHeaders deprecated
1144 * @return bool
1145 */
1146 public function isMobile( $userAgent = null, $httpHeaders = null ) {
1147
1148 if ( $httpHeaders ) {
1149 $this->setHttpHeaders( $httpHeaders );
1150 }
1151
1152 if ( $userAgent ) {
1153 $this->setUserAgent( $userAgent );
1154 }
1155
1156 // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
1157 if ( $this->getUserAgent() === 'Amazon CloudFront' ) {
1158 $cfHeaders = $this->getCfHeaders();
1159 if ( array_key_exists( 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders ) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true' ) {
1160 return true;
1161 }
1162 }
1163
1164 $this->setDetectionType( self::DETECTION_TYPE_MOBILE );
1165
1166 if ( $this->checkHttpHeadersForMobile() ) {
1167 return true;
1168 } else {
1169 return $this->matchDetectionRulesAgainstUA();
1170 }
1171 }
1172
1173 /**
1174 * Check if the device is a tablet.
1175 * Return true if any type of tablet device is detected.
1176 *
1177 * @param string $userAgent deprecated
1178 * @param array $httpHeaders deprecated
1179 * @return bool
1180 */
1181 public function isTablet( $userAgent = null, $httpHeaders = null ) {
1182 // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
1183 if ( $this->getUserAgent() === 'Amazon CloudFront' ) {
1184 $cfHeaders = $this->getCfHeaders();
1185 if ( array_key_exists( 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders ) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true' ) {
1186 return true;
1187 }
1188 }
1189
1190 $this->setDetectionType( self::DETECTION_TYPE_MOBILE );
1191
1192 if ( ! isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
1193 return false;
1194 }
1195
1196 $device = sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) );
1197
1198 foreach ( self::$tabletDevices as $_regex ) {
1199 if ( $this->match( $_regex, $device ) ) {
1200 return true;
1201 }
1202 }
1203
1204 return false;
1205 }
1206
1207 /**
1208 * This method checks for a certain property in the
1209 * userAgent.
1210 *
1211 * @todo: The httpHeaders part is not yet used.
1212 *
1213 * @param string $key
1214 * @param string $userAgent deprecated
1215 * @param string $httpHeaders deprecated
1216 * @return bool|int|null
1217 */
1218 public function is( $key, $userAgent = null, $httpHeaders = null ) {
1219 // Set the UA and HTTP headers only if needed (eg. batch mode).
1220 if ( $httpHeaders ) {
1221 $this->setHttpHeaders( $httpHeaders );
1222 }
1223
1224 if ( $userAgent ) {
1225 $this->setUserAgent( $userAgent );
1226 }
1227
1228 $this->setDetectionType( self::DETECTION_TYPE_EXTENDED );
1229
1230 return $this->matchUAAgainstKey( $key );
1231 }
1232
1233 /**
1234 * Some detection rules are relative (not standard),
1235 * because of the diversity of devices, vendors and
1236 * their conventions in representing the User-Agent or
1237 * the HTTP headers.
1238 *
1239 * This method will be used to check custom regexes against
1240 * the User-Agent string.
1241 *
1242 * @param $regex
1243 * @param string $userAgent
1244 * @return bool
1245 *
1246 * @todo: search in the HTTP headers too.
1247 */
1248 public function match( $regex, $userAgent = null ) {
1249 $match = (bool) preg_match( sprintf( '#%s#is', $regex ), ( false === empty( $userAgent ) ? $userAgent : $this->userAgent ), $matches );
1250 // If positive match is found, store the results for debug.
1251 if ( $match ) {
1252 $this->matchingRegex = $regex;
1253 $this->matchesArray = $matches;
1254 }
1255
1256 return $match;
1257 }
1258
1259 /**
1260 * Get the properties array.
1261 *
1262 * @return array
1263 */
1264 public static function getProperties() {
1265 return self::$properties;
1266 }
1267
1268 /**
1269 * Prepare the version number.
1270 *
1271 * @todo Remove the error supression from str_replace() call.
1272 *
1273 * @param string $ver The string version, like "2.6.21.2152";
1274 *
1275 * @return float
1276 */
1277 public function prepareVersionNo( $ver ) {
1278 $ver = str_replace( array( '_', ' ', '/' ), '.', $ver );
1279 $arrVer = explode( '.', $ver, 2 );
1280
1281 if ( isset( $arrVer[1] ) ) {
1282 $arrVer[1] = @str_replace( '.', '', $arrVer[1] ); // @todo: treat strings versions.
1283 }
1284
1285 return (float) implode( '.', $arrVer );
1286 }
1287
1288 /**
1289 * Check the version of the given property in the User-Agent.
1290 * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
1291 *
1292 * @param string $propertyName The name of the property. See self::getProperties() array
1293 * keys for all possible properties.
1294 * @param string $type Either self::VERSION_TYPE_STRING to get a string value or
1295 * self::VERSION_TYPE_FLOAT indicating a float value. This parameter
1296 * is optional and defaults to self::VERSION_TYPE_STRING. Passing an
1297 * invalid parameter will default to the this type as well.
1298 *
1299 * @return string|float The version of the property we are trying to extract.
1300 */
1301 public function version( $propertyName, $type = self::VERSION_TYPE_STRING ) {
1302 if ( empty( $propertyName ) ) {
1303 return false;
1304 }
1305
1306 // set the $type to the default if we don't recognize the type
1307 if ( $type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT ) {
1308 $type = self::VERSION_TYPE_STRING;
1309 }
1310
1311 $properties = self::getProperties();
1312
1313 // Check if the property exists in the properties array.
1314 if ( true === isset( $properties[ $propertyName ] ) ) {
1315
1316 // Prepare the pattern to be matched.
1317 // Make sure we always deal with an array (string is converted).
1318 $properties[ $propertyName ] = (array) $properties[ $propertyName ];
1319
1320 foreach ( $properties[ $propertyName ] as $propertyMatchString ) {
1321
1322 $propertyPattern = str_replace( '[VER]', self::VER, $propertyMatchString );
1323
1324 // Identify and extract the version.
1325 preg_match( sprintf( '#%s#is', $propertyPattern ), $this->userAgent, $match );
1326
1327 if ( false === empty( $match[1] ) ) {
1328 $version = ( $type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo( $match[1] ) : $match[1] );
1329
1330 return $version;
1331 }
1332 }
1333 }
1334
1335 return false;
1336 }
1337
1338 /**
1339 * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants.
1340 *
1341 * @return string One of the self::MOBILE_GRADE_* constants.
1342 */
1343 public function mobileGrade() {
1344 $isMobile = $this->isMobile();
1345
1346 if (
1347 // 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)
1348 $this->is( 'iOS' ) && $this->version( 'iPad', self::VERSION_TYPE_FLOAT ) >= 4.3 ||
1349 $this->is( 'iOS' ) && $this->version( 'iPhone', self::VERSION_TYPE_FLOAT ) >= 4.3 ||
1350 $this->is( 'iOS' ) && $this->version( 'iPod', self::VERSION_TYPE_FLOAT ) >= 4.3 ||
1351
1352 // 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)
1353 // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
1354 // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
1355 // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
1356 ( $this->version( 'Android', self::VERSION_TYPE_FLOAT ) > 2.1 && $this->is( 'Webkit' ) ) ||
1357
1358 // 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)
1359 $this->version( 'Windows Phone OS', self::VERSION_TYPE_FLOAT ) >= 7.5 ||
1360
1361 // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10)
1362 $this->is( 'BlackBerry' ) && $this->version( 'BlackBerry', self::VERSION_TYPE_FLOAT ) >= 6.0 ||
1363 // Blackberry Playbook (1.0-2.0) - Tested on PlayBook
1364 $this->match( 'Playbook.*Tablet' ) ||
1365
1366 // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0)
1367 ( $this->version( 'webOS', self::VERSION_TYPE_FLOAT ) >= 1.4 && $this->match( 'Palm|Pre|Pixi' ) ) ||
1368 // Palm WebOS 3.0 - Tested on HP TouchPad
1369 $this->match( 'hp.*TouchPad' ) ||
1370
1371 // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices
1372 ( $this->is( 'Firefox' ) && $this->version( 'Firefox', self::VERSION_TYPE_FLOAT ) >= 18 ) ||
1373
1374 // Chrome for Android - Tested on Android 4.0, 4.1 device
1375 ( $this->is( 'Chrome' ) && $this->is( 'AndroidOS' ) && $this->version( 'Android', self::VERSION_TYPE_FLOAT ) >= 4.0 ) ||
1376
1377 // Skyfire 4.1 - Tested on Android 2.3 device
1378 ( $this->is( 'Skyfire' ) && $this->version( 'Skyfire', self::VERSION_TYPE_FLOAT ) >= 4.1 && $this->is( 'AndroidOS' ) && $this->version( 'Android', self::VERSION_TYPE_FLOAT ) >= 2.3 ) ||
1379
1380 // Opera Mobile 11.5-12: Tested on Android 2.3
1381 ( $this->is( 'Opera' ) && $this->version( 'Opera Mobi', self::VERSION_TYPE_FLOAT ) >= 11.5 && $this->is( 'AndroidOS' ) ) ||
1382
1383 // Meego 1.2 - Tested on Nokia 950 and N9
1384 $this->is( 'MeeGoOS' ) ||
1385
1386 // Sailfish OS
1387 $this->is( 'SailfishOS' ) ||
1388
1389 // Tizen (pre-release) - Tested on early hardware
1390 $this->is( 'Tizen' ) ||
1391
1392 // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
1393 // @todo: more tests here!
1394 $this->is( 'Dolfin' ) && $this->version( 'Bada', self::VERSION_TYPE_FLOAT ) >= 2.0 ||
1395
1396 // UC Browser - Tested on Android 2.3 device
1397 ( ( $this->is( 'UC Browser' ) || $this->is( 'Dolfin' ) ) && $this->version( 'Android', self::VERSION_TYPE_FLOAT ) >= 2.3 ) ||
1398
1399 // Kindle 3 and Fire - Tested on the built-in WebKit browser for each
1400 ( $this->match( 'Kindle Fire' ) ||
1401 $this->is( 'Kindle' ) && $this->version( 'Kindle', self::VERSION_TYPE_FLOAT ) >= 3.0 ) ||
1402
1403 // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
1404 $this->is( 'AndroidOS' ) && $this->is( 'NookTablet' ) ||
1405
1406 // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7
1407 $this->version( 'Chrome', self::VERSION_TYPE_FLOAT ) >= 16 && ! $isMobile ||
1408
1409 // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7
1410 $this->version( 'Safari', self::VERSION_TYPE_FLOAT ) >= 5.0 && ! $isMobile ||
1411
1412 // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7
1413 $this->version( 'Firefox', self::VERSION_TYPE_FLOAT ) >= 10.0 && ! $isMobile ||
1414
1415 // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
1416 $this->version( 'IE', self::VERSION_TYPE_FLOAT ) >= 7.0 && ! $isMobile ||
1417
1418 // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
1419 $this->version( 'Opera', self::VERSION_TYPE_FLOAT ) >= 10 && ! $isMobile
1420 ) {
1421 return self::MOBILE_GRADE_A;
1422 }
1423
1424 if (
1425 $this->is( 'iOS' ) && $this->version( 'iPad', self::VERSION_TYPE_FLOAT ) < 4.3 ||
1426 $this->is( 'iOS' ) && $this->version( 'iPhone', self::VERSION_TYPE_FLOAT ) < 4.3 ||
1427 $this->is( 'iOS' ) && $this->version( 'iPod', self::VERSION_TYPE_FLOAT ) < 4.3 ||
1428
1429 // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
1430 $this->is( 'Blackberry' ) && $this->version( 'BlackBerry', self::VERSION_TYPE_FLOAT ) >= 5 && $this->version( 'BlackBerry', self::VERSION_TYPE_FLOAT ) < 6 ||
1431
1432 // Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
1433 ( $this->version( 'Opera Mini', self::VERSION_TYPE_FLOAT ) >= 5.0 && $this->version( 'Opera Mini', self::VERSION_TYPE_FLOAT ) <= 7.0 &&
1434 ( $this->version( 'Android', self::VERSION_TYPE_FLOAT ) >= 2.3 || $this->is( 'iOS' ) ) ) ||
1435
1436 // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
1437 $this->match( 'NokiaN8|NokiaC7|N97.*Series60|Symbian/3' ) ||
1438
1439 // @todo: report this (tested on Nokia N71)
1440 $this->version( 'Opera Mobi', self::VERSION_TYPE_FLOAT ) >= 11 && $this->is( 'SymbianOS' )
1441 ) {
1442 return self::MOBILE_GRADE_B;
1443 }
1444
1445 if (
1446 // Blackberry 4.x - Tested on the Curve 8330
1447 $this->version( 'BlackBerry', self::VERSION_TYPE_FLOAT ) <= 5.0 ||
1448 // Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
1449 $this->match( 'MSIEMobile|Windows CE.*Mobile' ) || $this->version( 'Windows Mobile', self::VERSION_TYPE_FLOAT ) <= 5.2 ||
1450
1451 // Tested on original iPhone (3.1), iPhone 3 (3.2)
1452 $this->is( 'iOS' ) && $this->version( 'iPad', self::VERSION_TYPE_FLOAT ) <= 3.2 ||
1453 $this->is( 'iOS' ) && $this->version( 'iPhone', self::VERSION_TYPE_FLOAT ) <= 3.2 ||
1454 $this->is( 'iOS' ) && $this->version( 'iPod', self::VERSION_TYPE_FLOAT ) <= 3.2 ||
1455
1456 // Internet Explorer 7 and older - Tested on Windows XP
1457 $this->version( 'IE', self::VERSION_TYPE_FLOAT ) <= 7.0 && ! $isMobile
1458 ) {
1459 return self::MOBILE_GRADE_C;
1460 }
1461
1462 // All older smartphone platforms and featurephones - Any device that doesn't support media queries
1463 // will receive the basic, C grade experience.
1464 return self::MOBILE_GRADE_C;
1465 }
1466 }
1467