WP Mobile Detect - Version 2.0

Version Description

  • Updated the core Mobile Detect Class 2.8.13
  • Updated shortcodes, adding [blackberry], [chrome], [safari], [opera], [ie], [firefox]
  • Updated functions, adding wpmd_is_blackberry(), wpmd_is_chrome_browser(), wpmd_is_safari_browser(), wpmd_is_opera_browser(), wpmd_is_ie_browser(), wpmd_is_firefox_browser()
  • Updated readme and some links
Download this release

Release Info

Developer professor44
Plugin Icon wp plugin WP Mobile Detect
Version 2.0
Comparing to
See all releases

Code changes from version 1.1.0 to 2.0

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