PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.11
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.11
1.1.11 1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 All 35 releases
← All changes | includes/desktop-files/favicon.php +39 -50 0.9.5 → 1.1.11 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode — Favicon resolver.
3 + * OpenStation — Favicon resolver.
4 4 *
5 5 * Resolves the favicon for an arbitrary http(s) URL, downloads the
6 6 * bytes server-side, and returns a base64 `data:` URI suitable for
7 7 * stuffing into a `placement.meta.iconUrl` so the tile renderer can
@@ -31,14 +31,13 @@
31 31 *
32 32 * Failure at any step returns `null` — the caller treats this as
33 33 * "no favicon, render the dashicons fallback". Never throws.
34 34 *
35 - * Filter the final return value through `desktop_mode_resolve_favicon`
35 + * Filter the final return value through `openstation_resolve_favicon`
36 36 * so plugins can short-circuit (return `null` to force-skip, return
37 37 * a synthetic data URI to override).
38 38 *
39 - * @package WPDesktopMode
40 - * @since 0.8.2
39 + * @package OpenStation
41 40 */
42 41
43 42 defined( 'ABSPATH' ) || exit;
44 43
@@ -47,9 +46,9 @@
47 46 * under 4 KB. The 256 KB cap exists to keep `placement.meta` blobs
48 47 * sane and to avoid base64-encoding a multi-megabyte payload that
49 48 * a malicious or sloppy host might serve at `/favicon.ico`.
50 49 */
51 -const DESKTOP_MODE_FAVICON_MAX_BYTES = 256 * 1024;
50 +const OPENSTATION_FAVICON_MAX_BYTES = 256 * 1024;
52 51
53 52 /**
54 53 * Maximum page-HTML download size, in bytes, for the step-1 page
55 54 * fetch. The `<link rel="icon">` tags live in `<head>`, so 1 MB
@@ -55,9 +54,9 @@
55 54 * fetch. The `<link rel="icon">` tags live in `<head>`, so 1 MB
56 55 * is plenty; the cap stops a malicious or sloppy host from
57 56 * streaming an unbounded body into memory before the parser runs.
58 57 */
59 -const DESKTOP_MODE_FAVICON_MAX_PAGE_BYTES = 1024 * 1024;
58 +const OPENSTATION_FAVICON_MAX_PAGE_BYTES = 1024 * 1024;
60 59
61 60 /**
62 61 * Per-request HTTP timeout, in seconds. Two fetches happen worst-
63 62 * case (page + icon) so the user-visible wait caps around 2× this
@@ -63,20 +62,18 @@
63 62 * case (page + icon) so the user-visible wait caps around 2× this
64 63 * value. Tune downward if QA finds the dialog "Create" button
65 64 * sitting too long.
66 65 */
67 -const DESKTOP_MODE_FAVICON_TIMEOUT = 4;
66 +const OPENSTATION_FAVICON_TIMEOUT = 4;
68 67
69 68 /**
70 69 * Resolve a page URL to a base64 data URI of its favicon.
71 70 *
72 - * @since 0.8.2
73 - *
74 71 * @param string $page_url HTTP(S) URL of the target page.
75 72 * @return string|null Data URI on success; `null` on any failure.
76 73 */
77 -function desktop_mode_resolve_favicon( $page_url ) {
78 - $result = desktop_mode_resolve_favicon_internal( (string) $page_url );
74 +function openstation_resolve_favicon( $page_url ) {
75 + $result = openstation_resolve_favicon_internal( (string) $page_url );
79 76
80 77 /**
81 78 * Filters the favicon data URI before it is returned to the
82 79 * caller. Plugins can override (return a synthetic data URI),
@@ -81,15 +78,13 @@
81 78 * Filters the favicon data URI before it is returned to the
82 79 * caller. Plugins can override (return a synthetic data URI),
83 80 * suppress (return `null`), or pass through.
84 81 *
85 - * @since 0.8.2
86 - *
87 82 * @param string|null $result Base64 data URI, or `null` if
88 83 * the resolver could not produce one.
89 84 * @param string $page_url The page URL that was resolved.
90 85 */
91 - $filtered = apply_filters( 'desktop_mode_resolve_favicon', $result, (string) $page_url );
86 + $filtered = apply_filters( 'openstation_resolve_favicon', $result, (string) $page_url );
92 87
93 88 if ( null === $filtered ) {
94 89 return null;
95 90 }
@@ -96,21 +91,20 @@
96 91 return is_string( $filtered ) ? $filtered : null;
97 92 }
98 93
99 94 /**
100 - * Internal resolver — see {@see desktop_mode_resolve_favicon}.
95 + * Internal resolver — see {@see openstation_resolve_favicon}.
101 96 *
102 97 * Kept separate so the public function is the only place the
103 - * `desktop_mode_resolve_favicon` filter runs (a plugin can't sneak
98 + * `openstation_resolve_favicon` filter runs (a plugin can't sneak
104 99 * its filter past the validation by hooking the internal helper).
105 100 *
106 - * @since 0.8.2
107 101 * @internal
108 102 *
109 103 * @param string $page_url Page URL.
110 104 * @return string|null
111 105 */
112 -function desktop_mode_resolve_favicon_internal( $page_url ) {
106 +function openstation_resolve_favicon_internal( $page_url ) {
113 107 $parts = wp_parse_url( $page_url );
114 108 if ( ! is_array( $parts ) || empty( $parts['host'] ) ) {
115 109 return null;
116 110 }
@@ -118,9 +112,9 @@
118 112 if ( 'http' !== $scheme && 'https' !== $scheme ) {
119 113 return null;
120 114 }
121 115
122 - $page_response = wp_safe_remote_get( $page_url, desktop_mode_favicon_request_args( DESKTOP_MODE_FAVICON_MAX_PAGE_BYTES ) );
116 + $page_response = wp_safe_remote_get( $page_url, openstation_favicon_request_args( OPENSTATION_FAVICON_MAX_PAGE_BYTES ) );
123 117 $page_body = '';
124 118 if ( ! is_wp_error( $page_response ) && 200 === (int) wp_remote_retrieve_response_code( $page_response ) ) {
125 119 $page_body = (string) wp_remote_retrieve_body( $page_response );
126 120 }
@@ -125,15 +119,15 @@
125 119 $page_body = (string) wp_remote_retrieve_body( $page_response );
126 120 }
127 121
128 122 $candidate_url = '' !== $page_body
129 - ? desktop_mode_favicon_extract_link_href( $page_body, $page_url )
123 + ? openstation_favicon_extract_link_href( $page_body, $page_url )
130 124 : '';
131 125 if ( '' === $candidate_url ) {
132 126 $candidate_url = $scheme . '://' . $parts['host'] . ( isset( $parts['port'] ) ? ':' . $parts['port'] : '' ) . '/favicon.ico';
133 127 }
134 128
135 - return desktop_mode_favicon_fetch_as_data_uri( $candidate_url );
129 + return openstation_favicon_fetch_as_data_uri( $candidate_url );
136 130 }
137 131
138 132 /**
139 133 * Common request args for both the page fetch and the icon fetch.
@@ -142,24 +136,23 @@
142 136 * an oversize (or maliciously unbounded) body is truncated during
143 137 * the download instead of being buffered whole into memory before
144 138 * the size check runs.
145 139 *
146 - * @since 0.8.2
147 140 * @internal
148 141 *
149 142 * @param int $limit_response_size Maximum response body size, in
150 143 * bytes, enforced by WP_Http while
151 144 * downloading. Default one byte over
152 - * `DESKTOP_MODE_FAVICON_MAX_BYTES`,
145 + * `OPENSTATION_FAVICON_MAX_BYTES`,
153 146 * so the post-fetch size check still
154 147 * rejects truncated over-cap bodies.
155 148 * @return array
156 149 */
157 -function desktop_mode_favicon_request_args( $limit_response_size = DESKTOP_MODE_FAVICON_MAX_BYTES + 1 ) {
150 +function openstation_favicon_request_args( $limit_response_size = OPENSTATION_FAVICON_MAX_BYTES + 1 ) {
158 151 return array(
159 - 'timeout' => DESKTOP_MODE_FAVICON_TIMEOUT,
152 + 'timeout' => OPENSTATION_FAVICON_TIMEOUT,
160 153 'redirection' => 3,
161 - 'user-agent' => 'WP Desktop Mode favicon resolver/1.0',
154 + 'user-agent' => 'WP OpenStation favicon resolver/1.0',
162 155 'limit_response_size' => (int) $limit_response_size,
163 156 'headers' => array(
164 157 'Accept' => 'text/html,application/xhtml+xml,image/*;q=0.9,*/*;q=0.5',
165 158 ),
@@ -171,9 +164,8 @@
171 164 * icon|apple-touch-icon" href="…">` and resolve `href` against
172 165 * `$base_url`. Returns the absolute icon URL, or `''` if none
173 166 * found.
174 167 *
175 - * @since 0.8.2
176 168 * @internal
177 169 *
178 170 * @param string $html Page body.
179 171 * @param string $base_url URL of the page that produced `$html`.
@@ -178,9 +170,9 @@
178 170 * @param string $html Page body.
179 171 * @param string $base_url URL of the page that produced `$html`.
180 172 * @return string
181 173 */
182 -function desktop_mode_favicon_extract_link_href( $html, $base_url ) {
174 +function openstation_favicon_extract_link_href( $html, $base_url ) {
183 175 $dom = new DOMDocument();
184 176 $prev_errors = libxml_use_internal_errors( true );
185 177 // `LIBXML_NOWARNING | LIBXML_NOERROR` suppresses libxml's stderr
186 178 // chatter on malformed HTML; we already silence libxml errors above.
@@ -199,11 +191,11 @@
199 191 // `apple-touch-icon` images are nicer for retina displays but
200 192 // usually larger than the 256 KB cap so we only fall back to
201 193 // them when nothing else exists.
202 194 $buckets = array(
203 - 'icon' => '',
204 - 'shortcut icon' => '',
205 - 'apple-touch-icon' => '',
195 + 'icon' => '',
196 + 'shortcut icon' => '',
197 + 'apple-touch-icon' => '',
206 198 );
207 199
208 200 foreach ( $links as $link ) {
209 201 if ( ! ( $link instanceof DOMElement ) ) {
@@ -230,9 +222,9 @@
230 222 foreach ( $buckets as $href ) {
231 223 if ( '' === $href ) {
232 224 continue;
233 225 }
234 - $absolute = desktop_mode_favicon_absolutize_url( $href, $base_url );
226 + $absolute = openstation_favicon_absolutize_url( $href, $base_url );
235 227 if ( '' !== $absolute ) {
236 228 return $absolute;
237 229 }
238 230 }
@@ -242,9 +234,8 @@
242 234 /**
243 235 * Resolve a possibly-relative `href` against `$base_url`. Returns
244 236 * `''` if the result isn't an http(s) URL.
245 237 *
246 - * @since 0.8.2
247 238 * @internal
248 239 *
249 240 * @param string $href Link href (absolute, scheme-relative, or path).
250 241 * @param string $base_url Page URL.
@@ -249,9 +240,9 @@
249 240 * @param string $href Link href (absolute, scheme-relative, or path).
250 241 * @param string $base_url Page URL.
251 242 * @return string
252 243 */
253 -function desktop_mode_favicon_absolutize_url( $href, $base_url ) {
244 +function openstation_favicon_absolutize_url( $href, $base_url ) {
254 245 $href = trim( $href );
255 246 if ( '' === $href ) {
256 247 return '';
257 248 }
@@ -287,19 +278,18 @@
287 278
288 279 /**
289 280 * Fetch the candidate icon URL and encode it as a data URI.
290 281 *
291 - * @since 0.8.2
292 282 * @internal
293 283 *
294 284 * @param string $icon_url Absolute http(s) URL of the icon.
295 285 * @return string|null
296 286 */
297 -function desktop_mode_favicon_fetch_as_data_uri( $icon_url ) {
287 +function openstation_favicon_fetch_as_data_uri( $icon_url ) {
298 288 if ( '' === $icon_url || ! preg_match( '#^https?://#i', $icon_url ) ) {
299 289 return null;
300 290 }
301 - $response = wp_safe_remote_get( $icon_url, desktop_mode_favicon_request_args() );
291 + $response = wp_safe_remote_get( $icon_url, openstation_favicon_request_args() );
302 292 if ( is_wp_error( $response ) ) {
303 293 return null;
304 294 }
305 295 if ( 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
@@ -311,12 +301,12 @@
311 301 if ( 0 !== strpos( $content_type, 'image/' ) ) {
312 302 return null;
313 303 }
314 304 $body = (string) wp_remote_retrieve_body( $response );
315 - if ( '' === $body || strlen( $body ) > DESKTOP_MODE_FAVICON_MAX_BYTES ) {
305 + if ( '' === $body || strlen( $body ) > OPENSTATION_FAVICON_MAX_BYTES ) {
316 306 return null;
317 307 }
318 - $subtype = desktop_mode_favicon_subtype_from_content_type( $content_type );
308 + $subtype = openstation_favicon_subtype_from_content_type( $content_type );
319 309 if ( null === $subtype ) {
320 310 return null;
321 311 }
322 312 // Catch HTML / text bodies served with a lying `Content-Type:
@@ -336,9 +326,8 @@
336 326 /**
337 327 * Map a `Content-Type` header to a known image subtype, or `null`
338 328 * if the type isn't on the allowlist.
339 329 *
340 - * @since 0.8.2
341 330 * @internal
342 331 *
343 332 * @param string $content_type Lowercased `Content-Type` value
344 333 * (no parameters).
@@ -343,18 +332,18 @@
343 332 * @param string $content_type Lowercased `Content-Type` value
344 333 * (no parameters).
345 334 * @return string|null
346 335 */
347 -function desktop_mode_favicon_subtype_from_content_type( $content_type ) {
336 +function openstation_favicon_subtype_from_content_type( $content_type ) {
348 337 $map = array(
349 - 'image/png' => 'png',
350 - 'image/jpeg' => 'jpeg',
351 - 'image/jpg' => 'jpeg',
352 - 'image/gif' => 'gif',
353 - 'image/webp' => 'webp',
354 - 'image/x-icon' => 'x-icon',
355 - 'image/vnd.microsoft.icon' => 'x-icon',
356 - 'image/ico' => 'x-icon',
357 - 'image/svg+xml' => 'svg+xml',
338 + 'image/png' => 'png',
339 + 'image/jpeg' => 'jpeg',
340 + 'image/jpg' => 'jpeg',
341 + 'image/gif' => 'gif',
342 + 'image/webp' => 'webp',
343 + 'image/x-icon' => 'x-icon',
344 + 'image/vnd.microsoft.icon' => 'x-icon',
345 + 'image/ico' => 'x-icon',
346 + 'image/svg+xml' => 'svg+xml',
358 347 );
359 348 return isset( $map[ $content_type ] ) ? $map[ $content_type ] : null;
360 349 }