PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-device-detection / src / class-device-detection.php

class-device-detection.php in Jetpack – WP Security, Backup, Speed, & Growth 16.2, at jetpack_vendor/automattic/jetpack-device-detection/src/class-device-detection.php

251 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Device detection for Jetpack.
4 *
5 * @package automattic/jetpack-device-detection
6 */
7
8 namespace Automattic\Jetpack;
9
10 require_once __DIR__ . '/functions.php';
11 require_once __DIR__ . '/class-user-agent-info.php';
12
13 use Automattic\Jetpack\Device_Detection\User_Agent_Info;
14 use function Automattic\Jetpack\Device_Detection\wp_unslash;
15
16 /**
17 * Class Device_Detection
18 *
19 * Determine if the current User Agent matches the passed $kind.
20 *
21 * Note: str_contains() and other PHP8+ functions that have a polyfill in core are not used here,
22 * as wp-includes/compat.php may not be loaded yet.
23 */
24 class Device_Detection {
25
26 /**
27 * Memoization cache for get_info() results.
28 *
29 * @var array
30 */
31 private static $get_info_memo = array();
32
33 /**
34 * Maximum size of the memoization cache.
35 *
36 * @var int
37 */
38 private static $max_memo_size = 100;
39
40 /**
41 * Returns information about the current device accessing the page.
42 *
43 * @param string $ua (Optional) User-Agent string.
44 *
45 * @return array Device information.
46 *
47 * array(
48 * 'is_phone' => (bool) Whether the current device is a mobile phone.
49 * 'is_smartphone' => (bool) Whether the current device is a smartphone.
50 * 'is_tablet' => (bool) Whether the current device is a tablet device.
51 * 'is_handheld' => (bool) Whether the current device is a handheld device.
52 * 'is_desktop' => (bool) Whether the current device is a laptop / desktop device.
53 * 'platform' => (string) Detected platform.
54 * 'is_phone_matched_ua' => (string) Matched UA.
55 * );
56 */
57 public static function get_info( $ua = '' ) {
58 // Return memoized result if available.
59 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
60 $memo_key = ! empty( $ua ) ? $ua : ( $_SERVER['HTTP_USER_AGENT'] ?? '' );
61 // Note: UA string used raw for compatibility reasons.
62 // No sanitization is needed as the value is never output or persisted, and is only used for memoization.
63 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
64 if ( isset( self::$get_info_memo[ $memo_key ] ) ) {
65 return self::$get_info_memo[ $memo_key ];
66 }
67
68 $ua_info = new User_Agent_Info( $ua );
69
70 $info = array(
71 'is_phone' => self::is_mobile( 'any', false, $ua_info ),
72 'is_phone_matched_ua' => self::is_mobile( 'any', true, $ua_info ),
73 'is_smartphone' => self::is_mobile( 'smart', false, $ua_info ),
74 'is_tablet' => $ua_info->is_tablet(),
75 'platform' => $ua_info->get_platform(),
76 'desktop_platform' => $ua_info->get_desktop_platform(),
77 'browser' => $ua_info->get_browser(),
78 );
79
80 $info['is_handheld'] = $info['is_phone'] || $info['is_tablet'];
81 $info['is_desktop'] = ! $info['is_handheld'];
82
83 if ( function_exists( 'apply_filters' ) ) {
84 /**
85 * Filter the value of Device_Detection::get_info.
86 *
87 * @since 1.0.0
88 *
89 * @param array $info Array of device information.
90 * @param string $ua User agent string passed to Device_Detection::get_info.
91 * @param User_Agent_Info $ua_info Instance of Automattic\Jetpack\Device_Detection\User_Agent_Info.
92 */
93 $info = apply_filters( 'jetpack_device_detection_get_info', $info, $ua, $ua_info );
94 }
95
96 // Memoize the result.
97 self::$get_info_memo[ $memo_key ] = $info;
98 if ( count( self::$get_info_memo ) > self::$max_memo_size ) {
99 array_shift( self::$get_info_memo );
100 }
101
102 return $info;
103 }
104
105 /**
106 * Detects phone devices.
107 *
108 * @param string $ua User-Agent string.
109 *
110 * @return bool
111 */
112 public static function is_phone( $ua = '' ) {
113 $device_info = self::get_info( $ua );
114 return true === $device_info['is_phone'];
115 }
116
117 /**
118 * Detects smartphone devices.
119 *
120 * @param string $ua User-Agent string.
121 *
122 * @return bool
123 */
124 public static function is_smartphone( $ua = '' ) {
125 $device_info = self::get_info( $ua );
126 return true === $device_info['is_smartphone'];
127 }
128
129 /**
130 * Detects tablet devices.
131 *
132 * @param string $ua User-Agent string.
133 *
134 * @return bool
135 */
136 public static function is_tablet( $ua = '' ) {
137 $device_info = self::get_info( $ua );
138 return true === $device_info['is_tablet'];
139 }
140
141 /**
142 * Detects desktop devices.
143 *
144 * @param string $ua User-Agent string.
145 *
146 * @return bool
147 */
148 public static function is_desktop( $ua = '' ) {
149 $device_info = self::get_info( $ua );
150 return true === $device_info['is_desktop'];
151 }
152
153 /**
154 * Detects handheld (i.e. phone + tablet) devices.
155 *
156 * @param string $ua User-Agent string.
157 *
158 * @return bool
159 */
160 public static function is_handheld( $ua = '' ) {
161 $device_info = self::get_info( $ua );
162 return true === $device_info['is_handheld'];
163 }
164
165 /**
166 * Determine if the current User Agent matches the passed $kind.
167 *
168 * @param string $kind Category of mobile device to check for. Either: any, dumb, smart.
169 * @param bool $return_matched_agent Boolean indicating if the UA should be returned.
170 * @param User_Agent_Info $ua_info Boolean indicating if the UA should be returned.
171 *
172 * @return bool|string Boolean indicating if current UA matches $kind. If `$return_matched_agent` is true, returns the UA string.
173 */
174 private static function is_mobile( $kind, $return_matched_agent, $ua_info ) {
175 $kinds = array(
176 'smart' => false,
177 'dumb' => false,
178 'any' => false,
179 );
180 $matched_agent = '';
181
182 // If an invalid kind is passed in, reset it to default.
183 if ( ! isset( $kinds[ $kind ] ) ) {
184 $kind = 'any';
185 }
186
187 if ( empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
188 return false;
189 }
190
191 $agent = strtolower( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- This is validating.
192 if ( strpos( $agent, 'ipad' ) !== false ) {
193 return false;
194 }
195
196 // Remove Samsung Galaxy tablets (SCH-I800) from being mobile devices.
197 if ( strpos( $agent, 'sch-i800' ) !== false ) {
198 return false;
199 }
200
201 if ( $ua_info->is_android_tablet() && false === $ua_info->is_kindle_touch() ) {
202 return false;
203 }
204
205 if ( $ua_info->is_blackberry_tablet() ) {
206 return false;
207 }
208
209 // checks for iPhoneTier devices & RichCSS devices.
210 if ( $ua_info->isTierIphone() || $ua_info->isTierRichCSS() ) {
211 $kinds['smart'] = true;
212 $matched_agent = $ua_info->matched_agent;
213 }
214
215 if ( ! $kinds['smart'] ) {
216 // if smart, we are not dumb so no need to check.
217 $dumb_agents = $ua_info->dumb_agents;
218
219 foreach ( $dumb_agents as $dumb_agent ) {
220 if ( false !== strpos( $agent, $dumb_agent ) ) {
221 $kinds['dumb'] = true;
222 $matched_agent = $dumb_agent;
223
224 break;
225 }
226 }
227
228 if ( ! $kinds['dumb'] ) {
229 if ( isset( $_SERVER['HTTP_X_WAP_PROFILE'] ) ) {
230 $kinds['dumb'] = true;
231 $matched_agent = 'http_x_wap_profile';
232 } elseif ( isset( $_SERVER['HTTP_ACCEPT'] ) && ( preg_match( '/wap\.|\.wap/i', $_SERVER['HTTP_ACCEPT'] ) || false !== strpos( strtolower( $_SERVER['HTTP_ACCEPT'] ), 'application/vnd.wap.xhtml+xml' ) ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is doing the validating.
233 $kinds['dumb'] = true;
234 $matched_agent = 'vnd.wap.xhtml+xml';
235 }
236 }
237 }
238
239 if ( $kinds['dumb'] || $kinds['smart'] ) {
240 $kinds['any'] = true;
241 }
242
243 $value = $kinds[ $kind ];
244
245 if ( $return_matched_agent ) {
246 $value = $matched_agent;
247 }
248 return $value;
249 }
250 }
251