PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.3-beta
16.3 16.3-beta 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 All 508 releases
← All changes | jetpack_vendor/automattic/jetpack-device-detection/src/class-device-detection.php +250 -0 16.2-beta → 16.3-beta View file →
@@ -1,0 +1,250 @@
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 +}