1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Device detection for Jetpack. |
4
|
|
|
* |
5
|
|
|
* @package automattic/jetpack-device-detection |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace Automattic\Jetpack; |
9
|
|
|
|
10
|
|
|
use Automattic\Jetpack\Device_Detection\User_Agent_Info; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Class Device_Detection |
14
|
|
|
* |
15
|
|
|
* Determine if the current User Agent matches the passed $kind. |
16
|
|
|
*/ |
17
|
|
|
class Device_Detection { |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Returns information about the current device accessing the page. |
21
|
|
|
* |
22
|
|
|
* @param string $ua (Optional) User-Agent string. |
23
|
|
|
* |
24
|
|
|
* @return array Device information. |
25
|
|
|
* |
26
|
|
|
* array( |
27
|
|
|
* 'is_phone' => (bool) Whether the current device is a mobile phone. |
28
|
|
|
* 'is_smartphone' => (bool) Whether the current device is a smartphone. |
29
|
|
|
* 'is_tablet' => (bool) Whether the current device is a tablet device. |
30
|
|
|
* 'is_handheld' => (bool) Whether the current device is a handheld device. |
31
|
|
|
* 'is_desktop' => (bool) Whether the current device is a laptop / desktop device. |
32
|
|
|
* 'platform' => (string) Detected platform. |
33
|
|
|
* 'is_phone_matched_ua' => (string) Matched UA. |
34
|
|
|
* ); |
35
|
|
|
*/ |
36
|
|
|
public static function get_info( $ua = '' ) { |
37
|
|
|
$ua_info = new User_Agent_Info( $ua ); |
38
|
|
|
|
39
|
|
|
$info = array( |
40
|
|
|
'is_phone' => self::is_mobile( 'any', false, $ua_info ), |
41
|
|
|
'is_phone_matched_ua' => self::is_mobile( 'any', true, $ua_info ), |
42
|
|
|
'is_smartphone' => self::is_mobile( 'smart', false, $ua_info ), |
43
|
|
|
'is_tablet' => $ua_info->is_tablet(), |
44
|
|
|
'platform' => $ua_info->get_platform(), |
45
|
|
|
); |
46
|
|
|
|
47
|
|
|
$info['is_handheld'] = $info['is_phone'] || $info['is_tablet']; |
48
|
|
|
$info['is_desktop'] = ! $info['is_handheld']; |
49
|
|
|
|
50
|
|
|
if ( function_exists( 'apply_filters' ) ) { |
51
|
|
|
/** |
52
|
|
|
* Filter the value of Device_Detection::get_info. |
53
|
|
|
* |
54
|
|
|
* @since 8.7.0 |
55
|
|
|
* |
56
|
|
|
* @param array $info Array of device information. |
57
|
|
|
* @param string $ua User agent string passed to Device_Detection::get_info. |
58
|
|
|
* @param User_Agent_Info $ua_info Instance of Automattic\Jetpack\Device_Detection\User_Agent_Info. |
59
|
|
|
*/ |
60
|
|
|
$info = apply_filters( 'jetpack_device_detection_get_info', $info, $ua, $ua_info ); |
|
|
|
|
61
|
|
|
} |
62
|
|
|
return $info; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Detects phone devices. |
67
|
|
|
* |
68
|
|
|
* @param string $ua User-Agent string. |
69
|
|
|
* |
70
|
|
|
* @return bool |
71
|
|
|
*/ |
72
|
|
|
public static function is_phone( $ua = '' ) { |
73
|
|
|
$device_info = self::get_info( $ua ); |
74
|
|
|
return true === $device_info['is_phone']; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Detects smartphone devices. |
79
|
|
|
* |
80
|
|
|
* @param string $ua User-Agent string. |
81
|
|
|
* |
82
|
|
|
* @return bool |
83
|
|
|
*/ |
84
|
|
|
public static function is_smartphone( $ua = '' ) { |
85
|
|
|
$device_info = self::get_info( $ua ); |
86
|
|
|
return true === $device_info['is_smartphone']; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* Detects tablet devices. |
91
|
|
|
* |
92
|
|
|
* @param string $ua User-Agent string. |
93
|
|
|
* |
94
|
|
|
* @return bool |
95
|
|
|
*/ |
96
|
|
|
public static function is_tablet( $ua = '' ) { |
97
|
|
|
$device_info = self::get_info( $ua ); |
98
|
|
|
return true === $device_info['is_tablet']; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Detects desktop devices. |
103
|
|
|
* |
104
|
|
|
* @param string $ua User-Agent string. |
105
|
|
|
* |
106
|
|
|
* @return bool |
107
|
|
|
*/ |
108
|
|
|
public static function is_desktop( $ua = '' ) { |
109
|
|
|
$device_info = self::get_info( $ua ); |
110
|
|
|
return true === $device_info['is_desktop']; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Detects handheld (i.e. phone + tablet) devices. |
115
|
|
|
* |
116
|
|
|
* @param string $ua User-Agent string. |
117
|
|
|
* |
118
|
|
|
* @return bool |
119
|
|
|
*/ |
120
|
|
|
public static function is_handheld( $ua = '' ) { |
121
|
|
|
$device_info = self::get_info( $ua ); |
122
|
|
|
return true === $device_info['is_handheld']; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Determine if the current User Agent matches the passed $kind. |
127
|
|
|
* |
128
|
|
|
* @param string $kind Category of mobile device to check for. Either: any, dumb, smart. |
129
|
|
|
* @param bool $return_matched_agent Boolean indicating if the UA should be returned. |
130
|
|
|
* @param User_Agent_Info $ua_info Boolean indicating if the UA should be returned. |
131
|
|
|
* |
132
|
|
|
* @return bool|string Boolean indicating if current UA matches $kind. If `$return_matched_agent` is true, returns the UA string. |
133
|
|
|
*/ |
134
|
|
|
private static function is_mobile( $kind = 'any', $return_matched_agent = false, $ua_info ) { |
135
|
|
|
$kinds = array( |
136
|
|
|
'smart' => false, |
137
|
|
|
'dumb' => false, |
138
|
|
|
'any' => false, |
139
|
|
|
); |
140
|
|
|
$first_run = true; |
141
|
|
|
$matched_agent = ''; |
142
|
|
|
|
143
|
|
|
// If an invalid kind is passed in, reset it to default. |
144
|
|
|
if ( ! isset( $kinds[ $kind ] ) ) { |
145
|
|
|
$kind = 'any'; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
if ( empty( $_SERVER['HTTP_USER_AGENT'] ) || strpos( strtolower( $_SERVER['HTTP_USER_AGENT'] ), 'ipad' ) ) { |
149
|
|
|
return false; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
// Remove Samsung Galaxy tablets (SCH-I800) from being mobile devices. |
153
|
|
|
if ( strpos( strtolower( $_SERVER['HTTP_USER_AGENT'] ), 'sch-i800' ) ) { |
154
|
|
|
return false; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
if ( $ua_info->is_android_tablet() && false === $ua_info->is_kindle_touch() ) { |
158
|
|
|
return false; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
if ( $ua_info->is_blackberry_tablet() ) { |
162
|
|
|
return false; |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
if ( $first_run ) { |
166
|
|
|
$first_run = false; |
|
|
|
|
167
|
|
|
|
168
|
|
|
// checks for iPhoneTier devices & RichCSS devices. |
169
|
|
|
if ( $ua_info->isTierIphone() || $ua_info->isTierRichCSS() ) { |
170
|
|
|
$kinds['smart'] = true; |
171
|
|
|
$matched_agent = $ua_info->matched_agent; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
if ( ! $kinds['smart'] ) { |
175
|
|
|
// if smart, we are not dumb so no need to check. |
176
|
|
|
$dumb_agents = $ua_info->dumb_agents; |
177
|
|
|
$agent = strtolower( $_SERVER['HTTP_USER_AGENT'] ); |
178
|
|
|
|
179
|
|
|
foreach ( $dumb_agents as $dumb_agent ) { |
180
|
|
|
if ( false !== strpos( $agent, $dumb_agent ) ) { |
181
|
|
|
$kinds['dumb'] = true; |
182
|
|
|
$matched_agent = $dumb_agent; |
183
|
|
|
|
184
|
|
|
break; |
185
|
|
|
} |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
if ( ! $kinds['dumb'] ) { |
189
|
|
|
if ( isset( $_SERVER['HTTP_X_WAP_PROFILE'] ) ) { |
190
|
|
|
$kinds['dumb'] = true; |
191
|
|
|
$matched_agent = 'http_x_wap_profile'; |
192
|
|
|
} elseif ( isset( $_SERVER['HTTP_ACCEPT'] ) && ( preg_match( '/wap\.|\.wap/i', $_SERVER['HTTP_ACCEPT'] ) || false !== strpos( strtolower( $_SERVER['HTTP_ACCEPT'] ), 'application/vnd.wap.xhtml+xml' ) ) ) { |
193
|
|
|
$kinds['dumb'] = true; |
194
|
|
|
$matched_agent = 'vnd.wap.xhtml+xml'; |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
if ( $kinds['dumb'] || $kinds['smart'] ) { |
200
|
|
|
$kinds['any'] = true; |
201
|
|
|
} |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
$value = $kinds[ $kind ]; |
205
|
|
|
|
206
|
|
|
if ( $return_matched_agent ) { |
207
|
|
|
$value = $matched_agent; |
208
|
|
|
} |
209
|
|
|
return $value; |
210
|
|
|
} |
211
|
|
|
} |
212
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.