Completed
Push — fix/comments-photon ( fff68e...a2496c )
by
unknown
52:12 queued 43:46
created

functions.photon.php ➔ jetpack_photon_allow_facebook_graph_domain()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Generates a Photon URL.
5
 *
6
 * @see http://developer.wordpress.com/docs/photon/
7
 *
8
 * @param string $image_url URL to the publicly accessible image you want to manipulate
9
 * @param array|string $args An array of arguments, i.e. array( 'w' => '300', 'resize' => array( 123, 456 ) ), or in string form (w=123&h=456)
10
 * @return string The raw final URL. You should run this through esc_url() before displaying it.
11
 */
12
function jetpack_photon_url( $image_url, $args = array(), $scheme = null ) {
13
	$image_url = trim( $image_url );
14
15
	if ( class_exists( 'Jetpack') ) {
16
		/**
17
		 * Disables Photon URL processing for local development
18
	 	 *
19
	 	 * @module photon
20
	 	 *
21
	 	 * @since 4.1.0
22
	 	 *
23
	 	 * @param bool false Result of Jetpack::is_development_mode.
24
	 	 */
25
		if ( true === apply_filters( 'jetpack_photon_development_mode', Jetpack::is_development_mode() ) ) {
26
			return $image_url;
27
		}
28
	}
29
30
	/**
31
	 * Allow specific image URls to avoid going through Photon.
32
	 *
33
	 * @module photon
34
	 *
35
	 * @since 3.2.0
36
	 *
37
	 * @param bool false Should the image be returned as is, without going through Photon. Default to false.
38
	 * @param string $image_url Image URL.
39
	 * @param array|string $args Array of Photon arguments.
40
	 * @param string|null $scheme Image scheme. Default to null.
41
	 */
42
	if ( false !== apply_filters( 'jetpack_photon_skip_for_url', false, $image_url, $args, $scheme ) ) {
43
		return $image_url;
44
	}
45
46
	/**
47
	 * Filter the original image URL before it goes through Photon.
48
	 *
49
	 * @module photon
50
	 *
51
	 * @since 1.9.0
52
	 *
53
	 * @param string $image_url Image URL.
54
	 * @param array|string $args Array of Photon arguments.
55
	 * @param string|null $scheme Image scheme. Default to null.
56
	 */
57
	$image_url = apply_filters( 'jetpack_photon_pre_image_url', $image_url, $args, $scheme );
58
	/**
59
	 * Filter the original Photon image parameters before Photon is applied to an image.
60
	 *
61
	 * @module photon
62
	 *
63
	 * @since 1.9.0
64
	 *
65
	 * @param array|string $args Array of Photon arguments.
66
	 * @param string $image_url Image URL.
67
	 * @param string|null $scheme Image scheme. Default to null.
68
	 */
69
	$args = apply_filters( 'jetpack_photon_pre_args', $args, $image_url, $scheme );
70
71
	if ( empty( $image_url ) )
72
		return $image_url;
73
74
	$image_url_parts = @jetpack_photon_parse_url( $image_url );
75
76
	// Unable to parse
77
	if ( ! is_array( $image_url_parts ) || empty( $image_url_parts['host'] ) || empty( $image_url_parts['path'] ) )
78
		return $image_url;
79
80
	if ( is_array( $args ) ){
81
		// Convert values that are arrays into strings
82
		foreach ( $args as $arg => $value ) {
83
			if ( is_array( $value ) ) {
84
				$args[$arg] = implode( ',', $value );
85
			}
86
		}
87
88
		// Encode values
89
		// See http://core.trac.wordpress.org/ticket/17923
90
		$args = rawurlencode_deep( $args );
91
	}
92
93
	/* Don't photon-ize WPCOM hosted images with only the following url args:
94
	 *  `w`, `h`, `fit`, `crop`, `zoom`, `strip`, `resize`, `quality`
95
	 * These args can just be added to the wpcom-version of the image, and save on latency.
96
	 */
97
	$is_wpcom_image_with_safe_args = false;
98
	$allowed_wpcom_keys = array(
99
		'w'       => true,
100
		'h'       => true,
101
		'fit'     => true,
102
		'crop'    => true,
103
		'zoom'    => true,
104
		'strip'   => true,
105
		'resize'  => true,
106
		'quality' => true,
107
	);
108
	if ( wp_endswith( strtolower( $image_url_parts['host'] ), '.files.wordpress.com' ) && ! array_diff_key( $args, $allowed_wpcom_keys ) ) {
109
		$is_wpcom_image_with_safe_args = true;
110
	}
111
112
	/** This filter is documented below. */
113
	$custom_photon_url = apply_filters( 'jetpack_photon_domain', '', $image_url );
114
	$custom_photon_url = esc_url( $custom_photon_url );
115
116
	// You can't run a Photon URL through Photon again because query strings are stripped.
117
	// So if the image is already a Photon URL, append the new arguments to the existing URL.
118
	// Alternately, if it's a *.files.wordpress.com url, and the arguments are supported, keep the domain.
119
	if (
120
		in_array( $image_url_parts['host'], array( 'i0.wp.com', 'i1.wp.com', 'i2.wp.com' ) )
121
		|| $image_url_parts['host'] === jetpack_photon_parse_url( $custom_photon_url, PHP_URL_HOST )
122
		|| $is_wpcom_image_with_safe_args
123
	) {
124
		$photon_url = add_query_arg( $args, $image_url );
125
		return jetpack_photon_url_scheme( $photon_url, $scheme );
126
	}
127
128
	/**
129
	 * Allow Photon to use query strings as well.
130
	 * By default, Photon doesn't support query strings so we ignore them and look only at the path.
131
	 * This setting is Photon Server dependent.
132
	 *
133
	 * @module photon
134
	 *
135
	 * @since 1.9.0
136
	 *
137
	 * @param bool false Should images using query strings go through Photon. Default is false.
138
	 * @param string $image_url_parts['host'] Image URL's host.
139
	 */
140
	if ( ! apply_filters( 'jetpack_photon_any_extension_for_domain', false, $image_url_parts['host'] ) ) {
141
		// Photon doesn't support query strings so we ignore them and look only at the path.
142
		// However some source images are served via PHP so check the no-query-string extension.
143
		// For future proofing, this is a blacklist of common issues rather than a whitelist.
144
		$extension = pathinfo( $image_url_parts['path'], PATHINFO_EXTENSION );
145
		if ( empty( $extension ) || in_array( $extension, array( 'php', 'ashx' ) ) )
146
			return $image_url;
147
	}
148
149
	$image_host_path = $image_url_parts['host'] . $image_url_parts['path'];
150
151
	// Figure out which CDN subdomain to use
152
	srand( crc32( $image_host_path ) );
153
	$subdomain = rand( 0, 2 );
154
	srand();
155
156
	/**
157
	 * Filters the domain used by the Photon module.
158
	 *
159
	 * @module photon
160
	 *
161
	 * @since 3.4.2
162
	 *
163
	 * @param string https://i{$subdomain}.wp.com Domain used by Photon. $subdomain is a random number between 0 and 2.
164
	 * @param string $image_url URL of the image to be photonized.
165
	 */
166
	$photon_domain = apply_filters( 'jetpack_photon_domain', "https://i{$subdomain}.wp.com", $image_url );
167
	$photon_domain = trailingslashit( esc_url( $photon_domain ) );
168
	$photon_url  = $photon_domain . $image_host_path;
169
170
	/**
171
	 * Add query strings to Photon URL.
172
	 * By default, Photon doesn't support query strings so we ignore them.
173
	 * This setting is Photon Server dependent.
174
	 *
175
	 * @module photon
176
	 *
177
	 * @since 1.9.0
178
	 *
179
	 * @param bool false Should query strings be added to the image URL. Default is false.
180
	 * @param string $image_url_parts['host'] Image URL's host.
181
	 */
182
	if ( isset( $image_url_parts['query'] ) && apply_filters( 'jetpack_photon_add_query_string_to_domain', false, $image_url_parts['host'] ) ) {
183
		$photon_url .= '?q=' . rawurlencode( $image_url_parts['query'] );
184
	}
185
186
	if ( $args ) {
187
		if ( is_array( $args ) ) {
188
			$photon_url = add_query_arg( $args, $photon_url );
189
		} else {
190
			// You can pass a query string for complicated requests but where you still want CDN subdomain help, etc.
191
			$photon_url .= '?' . $args;
192
		}
193
	}
194
195
	if ( isset( $image_url_parts['scheme'] ) && 'https' == $image_url_parts['scheme'] ) {
196
		$photon_url = add_query_arg( array( 'ssl' => 1 ), $photon_url );
197
	}
198
199
	return jetpack_photon_url_scheme( $photon_url, $scheme );
200
}
201
add_filter( 'jetpack_photon_url', 'jetpack_photon_url', 10, 3 );
202
203
/**
204
 * WordPress.com
205
 *
206
 * If a cropped WP.com-hosted image is the source image, have Photon replicate the crop.
207
 */
208
add_filter( 'jetpack_photon_pre_args', 'jetpack_photon_parse_wpcom_query_args', 10, 2 );
209
210
function jetpack_photon_parse_wpcom_query_args( $args, $image_url ) {
211
	$parsed_url = @parse_url( $image_url );
212
213
	if ( ! $parsed_url )
214
		return $args;
215
216
	$image_url_parts = wp_parse_args( $parsed_url, array(
217
		'host'  => '',
218
		'query' => ''
219
	) );
220
221
	if ( '.files.wordpress.com' != substr( $image_url_parts['host'], -20 ) )
222
		return $args;
223
224
	if ( empty( $image_url_parts['query'] ) )
225
		return $args;
226
227
	$wpcom_args = wp_parse_args( $image_url_parts['query'] );
228
229
	if ( empty( $wpcom_args['w'] ) || empty( $wpcom_args['h'] ) )
230
		return $args;
231
232
	// Keep the crop by using "resize"
233
	if ( ! empty( $wpcom_args['crop'] ) ) {
234 View Code Duplication
		if ( is_array( $args ) ) {
235
			$args = array_merge( array( 'resize' => array( $wpcom_args['w'], $wpcom_args['h'] ) ), $args );
236
		} else {
237
			$args = 'resize=' . rawurlencode( absint( $wpcom_args['w'] ) . ',' . absint( $wpcom_args['h'] ) ) . '&' . $args;
238
		}
239 View Code Duplication
	} else {
240
		if ( is_array( $args ) ) {
241
			$args = array_merge( array( 'fit' => array( $wpcom_args['w'], $wpcom_args['h'] ) ), $args );
242
		} else {
243
			$args = 'fit=' . rawurlencode( absint( $wpcom_args['w'] ) . ',' . absint( $wpcom_args['h'] ) ) . '&' . $args;
244
		}
245
	}
246
247
	return $args;
248
}
249
250
function jetpack_photon_url_scheme( $url, $scheme ) {
251
	if ( ! in_array( $scheme, array( 'http', 'https', 'network_path' ) ) ) {
252
		if ( preg_match( '#^(https?:)?//#', $url ) ) {
253
			return $url;
254
		}
255
256
		$scheme = 'http';
257
	}
258
259
	if ( 'network_path' == $scheme ) {
260
		$scheme_slashes = '//';
261
	} else {
262
		$scheme_slashes = "$scheme://";
263
	}
264
265
	return preg_replace( '#^([a-z:]+)?//#i', $scheme_slashes, $url );
266
}
267
268
/**
269
 * A wrapper for PHP's parse_url, prepending assumed scheme for network path
270
 * URLs. PHP versions 5.4.6 and earlier do not correctly parse without scheme.
271
 *
272
 * @see http://php.net/manual/en/function.parse-url.php#refsect1-function.parse-url-changelog
273
 *
274
 * @param string $url The URL to parse
275
 * @param integer $component Retrieve specific URL component
276
 * @return mixed Result of parse_url
277
 */
278
function jetpack_photon_parse_url( $url, $component = -1 ) {
279
	if ( 0 === strpos( $url, '//' ) ) {
280
		$url = ( is_ssl() ? 'https:' : 'http:' ) . $url;
281
	}
282
283
	return parse_url( $url, $component );
284
}
285
286
add_filter( 'jetpack_photon_skip_for_url', 'jetpack_photon_banned_domains', 9, 4 );
287
function jetpack_photon_banned_domains( $skip, $image_url, $args, $scheme ) {
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $scheme is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
288
	$banned_domains = array(
289
		'http://chart.googleapis.com/',
290
		'https://chart.googleapis.com/',
291
		'http://chart.apis.google.com/',
292
		'http://graph.facebook.com/',
293
		'https://graph.facebook.com/',
294
	);
295
296
	foreach ( $banned_domains as $banned_domain ) {
297
		if ( wp_startswith( $image_url, $banned_domain ) )
298
			return true;
299
	}
300
301
	return $skip;
302
}
303
304
305
/**
306
 * Jetpack Photon - Support Text Widgets.
307
 *
308
 * @access public
309
 * @param string $content Content from text widget.
310
 * @return string
311
 */
312
function jetpack_photon_support_text_widgets( $content ) {
313
	if ( class_exists( 'Jetpack_Photon' ) && Jetpack::is_module_active( 'photon' ) ) {
314
		return Jetpack_Photon::filter_the_content( $content );
315
	}
316
	return $content;
317
}
318
add_filter( 'widget_text', 'jetpack_photon_support_text_widgets' );
319