1: <?php
2: /**
3: * Wei Framework
4: *
5: * @copyright Copyright (c) 2008-2013 Twin Huang
6: * @license http://opensource.org/licenses/mit-license.php MIT License
7: */
8:
9: namespace Wei;
10:
11: /**
12: * A service to detect user OS, browser and device name and version
13: *
14: * @author Twin Huang <twinhuang@qq.com>
15: *
16: * @method bool isIE() Check if the user is browsing in Internet Explorer browser
17: * @method bool isChrome() Check if the user is browsing in Chrome browser
18: * @method bool isFirefox() Check if the user is browsing in Firefox browser
19: *
20: * @method bool isIOS() Check if the device is running on Apple's iOS platform
21: * @method bool isAndroid() Check if the device is running on Google's Android platform
22: * @method bool isWindowsPhone() Check if the device is running on Windows Phone platform
23: *
24: * @method bool isIPhone() Check if the user is browsing by iPhone/iPod
25: * @method bool isIPad() Check if the user is browsing by iPad
26: *
27: * @method bool isWeChat() Check if the user is browsing in WeChat App
28: */
29: class Ua extends Base
30: {
31: protected $patterns = array(
32: // Browser
33: 'ie' => 'MSIE ([\w.]+)',
34: 'chrome' => 'Chrome\/([\w.]+)',
35: 'firefox' => 'Firefox\/([\w.]+)',
36:
37: // OS
38: 'ios' => 'iP(?:hone|ad).*OS ([\d_]+)', // Contains iPod
39: 'android' => 'Android ([\w.]+)',
40: 'windowsphone' => 'Windows Phone (?:OS )?([\w.]+)',
41:
42: // Device (Mobile & Tablet)
43: 'iphone' => 'iPhone OS ([\d_]+)',
44: 'ipad' => 'iPad.*OS ([\d_]+)',
45:
46: // App
47: 'wechat' => 'MicroMessenger',
48: );
49:
50: /**
51: * The versions of detected os
52: *
53: * @var string
54: */
55: protected $versions = array();
56:
57: /**
58: * The user agent string from request header
59: *
60: * @var string
61: */
62: protected $userAgent;
63:
64: /**
65: * The server and execution environment parameters, equals to $_SERVER on default
66: *
67: * @var array
68: */
69: protected $server;
70:
71: /**
72: * Constructor
73: *
74: * @param array $options
75: */
76: public function __construct(array $options = array())
77: {
78: parent::__construct($options);
79:
80: if (!$this->server) {
81: $this->server = &$_SERVER;
82: }
83:
84: if (!$this->userAgent) {
85: $this->userAgent = isset($this->server['HTTP_USER_AGENT']) ? $this->server['HTTP_USER_AGENT'] : null;
86: }
87: }
88:
89: /**
90: * Check if in the specified browser, OS or device
91: *
92: * @param string $name The name of browser, OS or device
93: * @return bool
94: */
95: public function __invoke($name)
96: {
97: return $this->is($name);
98: }
99:
100: /**
101: * Check if in the specified browser, OS or device
102: *
103: * @param string $name The name of browser, OS or device
104: * @throws \InvalidArgumentException When name is not defined in patterns array
105: * @return bool
106: */
107: public function is($name)
108: {
109: $name = strtolower($name);
110:
111: if (!array_key_exists($name, $this->patterns)) {
112: throw new \InvalidArgumentException(sprintf('Unrecognized browser, OS, mobile or tablet name "%s"', $name));
113: }
114:
115: if (preg_match('/' . $this->patterns[$name] . '/i', $this->userAgent, $matches)) {
116: $this->versions[$name] = isset($matches[1]) ? $matches[1] : false;
117: return true;
118: } else {
119: $this->versions[$name] = false;
120: return false;
121: }
122: }
123:
124: /**
125: * Returns the version of specified browser, OS or device
126: *
127: * @param string $name
128: * @return string
129: */
130: public function getVersion($name)
131: {
132: $name = strtolower($name);
133: if (!isset($this->versions[$name])) {
134: $this->is($name);
135: }
136: return $this->versions[$name];
137: }
138:
139: /**
140: * Magic call for method isXXX
141: *
142: * @param string $name
143: * @param array $args
144: * @return bool
145: */
146: public function __call($name, $args)
147: {
148: if('is' == substr($name, 0, 2)) {
149: return $this->is(substr($name, 2));
150: }
151: return parent::__call($name, $args);
152: }
153:
154: /**
155: * Check if the device is mobile
156: *
157: * @link https://github.com/serbanghita/Mobile-Detect
158: * @license MIT License https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt
159: * @return bool
160: */
161: public function isMobile()
162: {
163: $s = $this->server;
164: if (
165: isset($s['HTTP_ACCEPT']) &&
166: (strpos($s['HTTP_ACCEPT'], 'application/x-obml2d') !== false || // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
167: strpos($s['HTTP_ACCEPT'], 'application/vnd.rim.html') !== false || // BlackBerry devices.
168: strpos($s['HTTP_ACCEPT'], 'text/vnd.wap.wml') !== false ||
169: strpos($s['HTTP_ACCEPT'], 'application/vnd.wap.xhtml+xml') !== false) ||
170: isset($s['HTTP_X_WAP_PROFILE']) ||
171: isset($s['HTTP_X_WAP_CLIENTID']) ||
172: isset($s['HTTP_WAP_CONNECTION']) ||
173: isset($s['HTTP_PROFILE']) ||
174: isset($s['HTTP_X_OPERAMINI_PHONE_UA']) || // Reported by Nokia devices (eg. C3)
175: isset($s['HTTP_X_NOKIA_IPADDRESS']) ||
176: isset($s['HTTP_X_NOKIA_GATEWAY_ID']) ||
177: isset($s['HTTP_X_ORANGE_ID']) ||
178: isset($s['HTTP_X_VODAFONE_3GPDPCONTEXT']) ||
179: isset($s['HTTP_X_HUAWEI_USERID']) ||
180: isset($s['HTTP_UA_OS']) || // Reported by Windows Smartphones.
181: isset($s['HTTP_X_MOBILE_GATEWAY']) || // Reported by Verizon, Vodafone proxy system.
182: isset($s['HTTP_X_ATT_DEVICEID']) || // Seend this on HTC Sensation. @ref: SensationXE_Beats_Z715e
183: //HTTP_X_NETWORK_TYPE = WIFI
184: ( isset($s['HTTP_UA_CPU']) &&
185: $s['HTTP_UA_CPU'] == 'ARM' // Seen this on a HTC.
186: )
187: ) {
188: return true;
189: }
190: return false;
191: }
192: }
193: