These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | defined( 'WPCOM_JSON_API__DEBUG' ) or define( 'WPCOM_JSON_API__DEBUG', false ); |
||
4 | |||
5 | require_once dirname( __FILE__ ) . '/sal/class.json-api-platform.php'; |
||
6 | |||
7 | class WPCOM_JSON_API { |
||
8 | static $self = null; |
||
9 | |||
10 | public $endpoints = array(); |
||
11 | |||
12 | public $token_details = array(); |
||
13 | |||
14 | public $method = ''; |
||
15 | public $url = ''; |
||
16 | public $path = ''; |
||
17 | public $version = null; |
||
18 | public $query = array(); |
||
19 | public $post_body = null; |
||
20 | public $files = null; |
||
21 | public $content_type = null; |
||
22 | public $accept = ''; |
||
23 | |||
24 | public $_server_https; |
||
25 | public $exit = true; |
||
26 | public $public_api_scheme = 'https'; |
||
27 | |||
28 | public $output_status_code = 200; |
||
29 | |||
30 | public $trapped_error = null; |
||
31 | public $did_output = false; |
||
32 | |||
33 | /** |
||
34 | * @return WPCOM_JSON_API instance |
||
35 | */ |
||
36 | static function init( $method = null, $url = null, $post_body = null ) { |
||
37 | if ( !self::$self ) { |
||
38 | $class = function_exists( 'get_called_class' ) ? get_called_class() : __CLASS__; |
||
39 | self::$self = new $class( $method, $url, $post_body ); |
||
40 | } |
||
41 | return self::$self; |
||
42 | } |
||
43 | |||
44 | function add( WPCOM_JSON_API_Endpoint $endpoint ) { |
||
45 | $path_versions = serialize( array ( |
||
46 | $endpoint->path, |
||
47 | $endpoint->min_version, |
||
48 | $endpoint->max_version, |
||
49 | ) ); |
||
50 | if ( !isset( $this->endpoints[$path_versions] ) ) { |
||
51 | $this->endpoints[$path_versions] = array(); |
||
52 | } |
||
53 | $this->endpoints[$path_versions][$endpoint->method] = $endpoint; |
||
54 | } |
||
55 | |||
56 | static function is_truthy( $value ) { |
||
57 | switch ( strtolower( (string) $value ) ) { |
||
58 | case '1' : |
||
59 | case 't' : |
||
60 | case 'true' : |
||
61 | return true; |
||
62 | } |
||
63 | |||
64 | return false; |
||
65 | } |
||
66 | |||
67 | static function is_falsy( $value ) { |
||
68 | switch ( strtolower( (string) $value ) ) { |
||
69 | case '0' : |
||
70 | case 'f' : |
||
71 | case 'false' : |
||
72 | return true; |
||
73 | } |
||
74 | |||
75 | return false; |
||
76 | } |
||
77 | |||
78 | function __construct() { |
||
79 | $args = func_get_args(); |
||
80 | call_user_func_array( array( $this, 'setup_inputs' ), $args ); |
||
81 | } |
||
82 | |||
83 | function setup_inputs( $method = null, $url = null, $post_body = null ) { |
||
84 | if ( is_null( $method ) ) { |
||
85 | $this->method = strtoupper( $_SERVER['REQUEST_METHOD'] ); |
||
86 | } else { |
||
87 | $this->method = strtoupper( $method ); |
||
88 | } |
||
89 | if ( is_null( $url ) ) { |
||
90 | $this->url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); |
||
91 | } else { |
||
92 | $this->url = $url; |
||
93 | } |
||
94 | |||
95 | $parsed = parse_url( $this->url ); |
||
96 | $this->path = $parsed['path']; |
||
97 | |||
98 | if ( !empty( $parsed['query'] ) ) { |
||
99 | wp_parse_str( $parsed['query'], $this->query ); |
||
100 | } |
||
101 | |||
102 | if ( isset( $_SERVER['HTTP_ACCEPT'] ) && $_SERVER['HTTP_ACCEPT'] ) { |
||
103 | $this->accept = $_SERVER['HTTP_ACCEPT']; |
||
104 | } |
||
105 | |||
106 | if ( 'POST' === $this->method ) { |
||
107 | if ( is_null( $post_body ) ) { |
||
108 | $this->post_body = file_get_contents( 'php://input' ); |
||
109 | |||
110 | if ( isset( $_SERVER['HTTP_CONTENT_TYPE'] ) && $_SERVER['HTTP_CONTENT_TYPE'] ) { |
||
111 | $this->content_type = $_SERVER['HTTP_CONTENT_TYPE']; |
||
112 | } elseif ( isset( $_SERVER['CONTENT_TYPE'] ) && $_SERVER['CONTENT_TYPE'] ) { |
||
113 | $this->content_type = $_SERVER['CONTENT_TYPE'] ; |
||
114 | } elseif ( '{' === $this->post_body[0] ) { |
||
115 | $this->content_type = 'application/json'; |
||
116 | } else { |
||
117 | $this->content_type = 'application/x-www-form-urlencoded'; |
||
118 | } |
||
119 | |||
120 | if ( 0 === strpos( strtolower( $this->content_type ), 'multipart/' ) ) { |
||
121 | $this->post_body = http_build_query( stripslashes_deep( $_POST ) ); |
||
122 | $this->files = $_FILES; |
||
123 | $this->content_type = 'multipart/form-data'; |
||
124 | } |
||
125 | } else { |
||
126 | $this->post_body = $post_body; |
||
127 | $this->content_type = '{' === isset( $this->post_body[0] ) && $this->post_body[0] ? 'application/json' : 'application/x-www-form-urlencoded'; |
||
128 | } |
||
129 | } else { |
||
130 | $this->post_body = null; |
||
131 | $this->content_type = null; |
||
132 | } |
||
133 | |||
134 | $this->_server_https = array_key_exists( 'HTTPS', $_SERVER ) ? $_SERVER['HTTPS'] : '--UNset--'; |
||
135 | } |
||
136 | |||
137 | function initialize() { |
||
138 | $this->token_details['blog_id'] = Jetpack_Options::get_option( 'id' ); |
||
139 | } |
||
140 | |||
141 | function serve( $exit = true ) { |
||
142 | ini_set( 'display_errors', false ); |
||
143 | |||
144 | $this->exit = (bool) $exit; |
||
145 | |||
146 | // This was causing problems with Jetpack, but is necessary for wpcom |
||
147 | // @see https://github.com/Automattic/jetpack/pull/2603 |
||
148 | // @see r124548-wpcom |
||
149 | if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { |
||
150 | add_filter( 'home_url', array( $this, 'ensure_http_scheme_of_home_url' ), 10, 3 ); |
||
151 | } |
||
152 | |||
153 | add_filter( 'user_can_richedit', '__return_true' ); |
||
154 | |||
155 | add_filter( 'comment_edit_pre', array( $this, 'comment_edit_pre' ) ); |
||
156 | |||
157 | $initialization = $this->initialize(); |
||
158 | if ( 'OPTIONS' == $this->method ) { |
||
159 | /** |
||
160 | * Fires before the page output. |
||
161 | * Can be used to specify custom header options. |
||
162 | * |
||
163 | * @module json-api |
||
164 | * |
||
165 | * @since 3.1.0 |
||
166 | */ |
||
167 | do_action( 'wpcom_json_api_options' ); |
||
168 | return $this->output( 200, '', 'plain/text' ); |
||
169 | } |
||
170 | |||
171 | if ( is_wp_error( $initialization ) ) { |
||
172 | $this->output_error( $initialization ); |
||
173 | return; |
||
174 | } |
||
175 | |||
176 | // Normalize path and extract API version |
||
177 | $this->path = untrailingslashit( $this->path ); |
||
178 | preg_match( '#^/rest/v(\d+(\.\d+)*)#', $this->path, $matches ); |
||
179 | $this->path = substr( $this->path, strlen( $matches[0] ) ); |
||
180 | $this->version = $matches[1]; |
||
181 | |||
182 | $allowed_methods = array( 'GET', 'POST' ); |
||
183 | $four_oh_five = false; |
||
184 | |||
185 | $is_help = preg_match( '#/help/?$#i', $this->path ); |
||
186 | $matching_endpoints = array(); |
||
187 | |||
188 | if ( $is_help ) { |
||
189 | $origin = get_http_origin(); |
||
190 | |||
191 | if ( !empty( $origin ) && 'GET' == $this->method ) { |
||
192 | header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) ); |
||
193 | } |
||
194 | |||
195 | $this->path = substr( rtrim( $this->path, '/' ), 0, -5 ); |
||
196 | // Show help for all matching endpoints regardless of method |
||
197 | $methods = $allowed_methods; |
||
198 | $find_all_matching_endpoints = true; |
||
199 | // How deep to truncate each endpoint's path to see if it matches this help request |
||
200 | $depth = substr_count( $this->path, '/' ) + 1; |
||
201 | if ( false !== stripos( $this->accept, 'javascript' ) || false !== stripos( $this->accept, 'json' ) ) { |
||
202 | $help_content_type = 'json'; |
||
203 | } else { |
||
204 | $help_content_type = 'html'; |
||
205 | } |
||
206 | } else { |
||
207 | if ( in_array( $this->method, $allowed_methods ) ) { |
||
208 | // Only serve requested method |
||
209 | $methods = array( $this->method ); |
||
210 | $find_all_matching_endpoints = false; |
||
211 | } else { |
||
212 | // We don't allow this requested method - find matching endpoints and send 405 |
||
213 | $methods = $allowed_methods; |
||
214 | $find_all_matching_endpoints = true; |
||
215 | $four_oh_five = true; |
||
216 | } |
||
217 | } |
||
218 | |||
219 | // Find which endpoint to serve |
||
220 | $found = false; |
||
221 | foreach ( $this->endpoints as $endpoint_path_versions => $endpoints_by_method ) { |
||
222 | $endpoint_path_versions = unserialize( $endpoint_path_versions ); |
||
223 | $endpoint_path = $endpoint_path_versions[0]; |
||
224 | $endpoint_min_version = $endpoint_path_versions[1]; |
||
225 | $endpoint_max_version = $endpoint_path_versions[2]; |
||
226 | |||
227 | // Make sure max_version is not less than min_version |
||
228 | if ( version_compare( $endpoint_max_version, $endpoint_min_version, '<' ) ) { |
||
229 | $endpoint_max_version = $endpoint_min_version; |
||
230 | } |
||
231 | |||
232 | foreach ( $methods as $method ) { |
||
233 | if ( !isset( $endpoints_by_method[$method] ) ) { |
||
234 | continue; |
||
235 | } |
||
236 | |||
237 | // Normalize |
||
238 | $endpoint_path = untrailingslashit( $endpoint_path ); |
||
239 | if ( $is_help ) { |
||
240 | // Truncate path at help depth |
||
241 | $endpoint_path = join( '/', array_slice( explode( '/', $endpoint_path ), 0, $depth ) ); |
||
242 | } |
||
243 | |||
244 | // Generate regular expression from sprintf() |
||
245 | $endpoint_path_regex = str_replace( array( '%s', '%d' ), array( '([^/?&]+)', '(\d+)' ), $endpoint_path ); |
||
246 | |||
247 | if ( !preg_match( "#^$endpoint_path_regex\$#", $this->path, $path_pieces ) ) { |
||
248 | // This endpoint does not match the requested path. |
||
249 | continue; |
||
250 | } |
||
251 | |||
252 | if ( version_compare( $this->version, $endpoint_min_version, '<' ) || version_compare( $this->version, $endpoint_max_version, '>' ) ) { |
||
253 | // This endpoint does not match the requested version. |
||
254 | continue; |
||
255 | } |
||
256 | |||
257 | $found = true; |
||
258 | |||
259 | if ( $find_all_matching_endpoints ) { |
||
260 | $matching_endpoints[] = array( $endpoints_by_method[$method], $path_pieces ); |
||
261 | } else { |
||
262 | // The method parameters are now in $path_pieces |
||
263 | $endpoint = $endpoints_by_method[$method]; |
||
264 | break 2; |
||
265 | } |
||
266 | } |
||
267 | } |
||
268 | |||
269 | if ( !$found ) { |
||
270 | return $this->output( 404, '', 'text/plain' ); |
||
271 | } |
||
272 | |||
273 | if ( $four_oh_five ) { |
||
274 | $allowed_methods = array(); |
||
275 | foreach ( $matching_endpoints as $matching_endpoint ) { |
||
276 | $allowed_methods[] = $matching_endpoint[0]->method; |
||
277 | } |
||
278 | |||
279 | header( 'Allow: ' . strtoupper( join( ',', array_unique( $allowed_methods ) ) ) ); |
||
280 | return $this->output( 405, array( 'error' => 'not_allowed', 'error_message' => 'Method not allowed' ) ); |
||
281 | } |
||
282 | |||
283 | if ( $is_help ) { |
||
284 | /** |
||
285 | * Fires before the API output. |
||
286 | * |
||
287 | * @since 1.9.0 |
||
288 | * |
||
289 | * @param string help. |
||
290 | */ |
||
291 | do_action( 'wpcom_json_api_output', 'help' ); |
||
292 | if ( 'json' === $help_content_type ) { |
||
293 | $docs = array(); |
||
294 | View Code Duplication | foreach ( $matching_endpoints as $matching_endpoint ) { |
|
295 | if ( $matching_endpoint[0]->is_publicly_documentable() || WPCOM_JSON_API__DEBUG ) |
||
296 | $docs[] = call_user_func( array( $matching_endpoint[0], 'generate_documentation' ) ); |
||
297 | } |
||
298 | return $this->output( 200, $docs ); |
||
299 | } else { |
||
300 | status_header( 200 ); |
||
301 | View Code Duplication | foreach ( $matching_endpoints as $matching_endpoint ) { |
|
302 | if ( $matching_endpoint[0]->is_publicly_documentable() || WPCOM_JSON_API__DEBUG ) |
||
303 | call_user_func( array( $matching_endpoint[0], 'document' ) ); |
||
304 | } |
||
305 | } |
||
306 | exit; |
||
307 | } |
||
308 | |||
309 | if ( $endpoint->in_testing && !WPCOM_JSON_API__DEBUG ) { |
||
310 | return $this->output( 404, '', 'text/plain' ); |
||
311 | } |
||
312 | |||
313 | /** This action is documented in class.json-api.php */ |
||
314 | do_action( 'wpcom_json_api_output', $endpoint->stat ); |
||
315 | |||
316 | $response = $this->process_request( $endpoint, $path_pieces ); |
||
317 | |||
318 | if ( !$response && !is_array( $response ) ) { |
||
319 | return $this->output( 500, '', 'text/plain' ); |
||
320 | } elseif ( is_wp_error( $response ) ) { |
||
321 | return $this->output_error( $response ); |
||
322 | } |
||
323 | |||
324 | $output_status_code = $this->output_status_code; |
||
325 | $this->set_output_status_code(); |
||
326 | |||
327 | return $this->output( $output_status_code, $response ); |
||
328 | } |
||
329 | |||
330 | function process_request( WPCOM_JSON_API_Endpoint $endpoint, $path_pieces ) { |
||
331 | $this->endpoint = $endpoint; |
||
332 | return call_user_func_array( array( $endpoint, 'callback' ), $path_pieces ); |
||
333 | } |
||
334 | |||
335 | function output_early( $status_code, $response = null, $content_type = 'application/json' ) { |
||
336 | $exit = $this->exit; |
||
337 | $this->exit = false; |
||
338 | if ( is_wp_error( $response ) ) |
||
339 | $this->output_error( $response ); |
||
340 | else |
||
341 | $this->output( $status_code, $response, $content_type ); |
||
342 | $this->exit = $exit; |
||
343 | if ( ! defined( 'XMLRPC_REQUEST' ) || ! XMLRPC_REQUEST ) { |
||
344 | $this->finish_request(); |
||
345 | } |
||
346 | } |
||
347 | |||
348 | function set_output_status_code( $code = 200 ) { |
||
349 | $this->output_status_code = $code; |
||
350 | } |
||
351 | |||
352 | function output( $status_code, $response = null, $content_type = 'application/json' ) { |
||
353 | // In case output() was called before the callback returned |
||
354 | if ( $this->did_output ) { |
||
355 | if ( $this->exit ) |
||
356 | exit; |
||
0 ignored issues
–
show
|
|||
357 | return $content_type; |
||
358 | } |
||
359 | $this->did_output = true; |
||
360 | |||
361 | // 400s and 404s are allowed for all origins |
||
362 | if ( 404 == $status_code || 400 == $status_code ) |
||
363 | header( 'Access-Control-Allow-Origin: *' ); |
||
364 | |||
365 | if ( is_null( $response ) ) { |
||
366 | $response = new stdClass; |
||
367 | } |
||
368 | |||
369 | if ( 'text/plain' === $content_type ) { |
||
370 | status_header( (int) $status_code ); |
||
371 | header( 'Content-Type: text/plain' ); |
||
372 | echo $response; |
||
373 | if ( $this->exit ) { |
||
374 | exit; |
||
0 ignored issues
–
show
The method
output() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
375 | } |
||
376 | |||
377 | return $content_type; |
||
378 | } |
||
379 | |||
380 | $response = $this->filter_fields( $response ); |
||
381 | |||
382 | if ( isset( $this->query['http_envelope'] ) && self::is_truthy( $this->query['http_envelope'] ) ) { |
||
383 | $response = array( |
||
384 | 'code' => (int) $status_code, |
||
385 | 'headers' => array( |
||
386 | array( |
||
387 | 'name' => 'Content-Type', |
||
388 | 'value' => $content_type, |
||
389 | ), |
||
390 | ), |
||
391 | 'body' => $response, |
||
392 | ); |
||
393 | $status_code = 200; |
||
394 | $content_type = 'application/json'; |
||
395 | } |
||
396 | |||
397 | status_header( (int) $status_code ); |
||
398 | header( "Content-Type: $content_type" ); |
||
399 | if ( isset( $this->query['callback'] ) && is_string( $this->query['callback'] ) ) { |
||
400 | $callback = preg_replace( '/[^a-z0-9_.]/i', '', $this->query['callback'] ); |
||
401 | } else { |
||
402 | $callback = false; |
||
403 | } |
||
404 | |||
405 | if ( $callback ) { |
||
406 | // Mitigate Rosetta Flash [1] by setting the Content-Type-Options: nosniff header |
||
407 | // and by prepending the JSONP response with a JS comment. |
||
408 | // [1] http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ |
||
409 | echo "/**/$callback("; |
||
410 | |||
411 | } |
||
412 | echo $this->json_encode( $response ); |
||
413 | if ( $callback ) { |
||
414 | echo ");"; |
||
415 | } |
||
416 | |||
417 | if ( $this->exit ) { |
||
418 | exit; |
||
419 | } |
||
420 | |||
421 | return $content_type; |
||
422 | } |
||
423 | |||
424 | public static function serializable_error ( $error ) { |
||
425 | |||
426 | $status_code = $error->get_error_data(); |
||
427 | |||
428 | if ( is_array( $status_code ) ) |
||
429 | $status_code = $status_code['status_code']; |
||
430 | |||
431 | if ( !$status_code ) { |
||
432 | $status_code = 400; |
||
433 | } |
||
434 | $response = array( |
||
435 | 'error' => $error->get_error_code(), |
||
436 | 'message' => $error->get_error_message(), |
||
437 | ); |
||
438 | return array( |
||
439 | 'status_code' => $status_code, |
||
440 | 'errors' => $response |
||
441 | ); |
||
442 | } |
||
443 | |||
444 | function output_error( $error ) { |
||
445 | if ( function_exists( 'bump_stats_extra' ) ) { |
||
446 | $client_id = ! empty( $this->token_details['client_id'] ) ? $this->token_details['client_id'] : 0; |
||
447 | bump_stats_extra( 'rest-api-errors', $client_id ); |
||
448 | } |
||
449 | |||
450 | $error_response = $this->serializable_error( $error ); |
||
451 | |||
452 | return $this->output( $error_response[ 'status_code'], $error_response['errors'] ); |
||
453 | } |
||
454 | |||
455 | function filter_fields( $response ) { |
||
456 | if ( empty( $this->query['fields'] ) || ( is_array( $response ) && ! empty( $response['error'] ) ) || ! empty( $this->endpoint->custom_fields_filtering ) ) |
||
457 | return $response; |
||
458 | |||
459 | $fields = array_map( 'trim', explode( ',', $this->query['fields'] ) ); |
||
460 | |||
461 | if ( is_object( $response ) ) { |
||
462 | $response = (array) $response; |
||
463 | } |
||
464 | |||
465 | $has_filtered = false; |
||
466 | if ( is_array( $response ) && empty( $response['ID'] ) ) { |
||
467 | $keys_to_filter = array( |
||
468 | 'categories', |
||
469 | 'comments', |
||
470 | 'connections', |
||
471 | 'domains', |
||
472 | 'groups', |
||
473 | 'likes', |
||
474 | 'media', |
||
475 | 'notes', |
||
476 | 'posts', |
||
477 | 'services', |
||
478 | 'sites', |
||
479 | 'suggestions', |
||
480 | 'tags', |
||
481 | 'themes', |
||
482 | 'topics', |
||
483 | 'users', |
||
484 | ); |
||
485 | |||
486 | foreach ( $keys_to_filter as $key_to_filter ) { |
||
487 | if ( ! isset( $response[ $key_to_filter ] ) || $has_filtered ) |
||
488 | continue; |
||
489 | |||
490 | foreach ( $response[ $key_to_filter ] as $key => $values ) { |
||
491 | if ( is_object( $values ) ) { |
||
492 | $response[ $key_to_filter ][ $key ] = (object) array_intersect_key( (array) $values, array_flip( $fields ) ); |
||
493 | } elseif ( is_array( $values ) ) { |
||
494 | $response[ $key_to_filter ][ $key ] = array_intersect_key( $values, array_flip( $fields ) ); |
||
495 | } |
||
496 | } |
||
497 | |||
498 | $has_filtered = true; |
||
499 | } |
||
500 | } |
||
501 | |||
502 | if ( ! $has_filtered ) { |
||
503 | if ( is_object( $response ) ) { |
||
504 | $response = (object) array_intersect_key( (array) $response, array_flip( $fields ) ); |
||
505 | } else if ( is_array( $response ) ) { |
||
506 | $response = array_intersect_key( $response, array_flip( $fields ) ); |
||
507 | } |
||
508 | } |
||
509 | |||
510 | return $response; |
||
511 | } |
||
512 | |||
513 | function ensure_http_scheme_of_home_url( $url, $path, $original_scheme ) { |
||
514 | if ( $original_scheme ) { |
||
515 | return $url; |
||
516 | } |
||
517 | |||
518 | return preg_replace( '#^https:#', 'http:', $url ); |
||
519 | } |
||
520 | |||
521 | function comment_edit_pre( $comment_content ) { |
||
522 | return htmlspecialchars_decode( $comment_content, ENT_QUOTES ); |
||
523 | } |
||
524 | |||
525 | function json_encode( $data ) { |
||
526 | return json_encode( $data ); |
||
527 | } |
||
528 | |||
529 | function ends_with( $haystack, $needle ) { |
||
530 | return $needle === substr( $haystack, -strlen( $needle ) ); |
||
531 | } |
||
532 | |||
533 | // Returns the site's blog_id in the WP.com ecosystem |
||
534 | function get_blog_id_for_output() { |
||
535 | return $this->token_details['blog_id']; |
||
536 | } |
||
537 | |||
538 | // Returns the site's local blog_id |
||
539 | function get_blog_id( $blog_id ) { |
||
540 | return $GLOBALS['blog_id']; |
||
541 | } |
||
542 | |||
543 | function switch_to_blog_and_validate_user( $blog_id = 0, $verify_token_for_blog = true ) { |
||
544 | if ( $this->is_restricted_blog( $blog_id ) ) { |
||
545 | return new WP_Error( 'unauthorized', 'User cannot access this restricted blog', 403 ); |
||
546 | } |
||
547 | |||
548 | if ( -1 == get_option( 'blog_public' ) && !current_user_can( 'read' ) ) { |
||
549 | return new WP_Error( 'unauthorized', 'User cannot access this private blog.', 403 ); |
||
550 | } |
||
551 | |||
552 | return $blog_id; |
||
553 | } |
||
554 | |||
555 | // Returns true if the specified blog ID is a restricted blog |
||
556 | function is_restricted_blog( $blog_id ) { |
||
557 | /** |
||
558 | * Filters all REST API access and return a 403 unauthorized response for all Restricted blog IDs. |
||
559 | * |
||
560 | * @module json-api |
||
561 | * |
||
562 | * @since 3.4.0 |
||
563 | * |
||
564 | * @param array $array Array of Blog IDs. |
||
565 | */ |
||
566 | $restricted_blog_ids = apply_filters( 'wpcom_json_api_restricted_blog_ids', array() ); |
||
567 | return true === in_array( $blog_id, $restricted_blog_ids ); |
||
568 | } |
||
569 | |||
570 | function post_like_count( $blog_id, $post_id ) { |
||
571 | return 0; |
||
572 | } |
||
573 | |||
574 | function is_liked( $blog_id, $post_id ) { |
||
575 | return false; |
||
576 | } |
||
577 | |||
578 | function is_reblogged( $blog_id, $post_id ) { |
||
579 | return false; |
||
580 | } |
||
581 | |||
582 | function is_following( $blog_id ) { |
||
583 | return false; |
||
584 | } |
||
585 | |||
586 | function add_global_ID( $blog_id, $post_id ) { |
||
587 | return ''; |
||
588 | } |
||
589 | |||
590 | /** |
||
591 | * Traps `wp_die()` calls and outputs a JSON response instead. |
||
592 | * The result is always output, never returned. |
||
593 | * |
||
594 | * @param string|null $error_code Call with string to start the trapping. Call with null to stop. |
||
595 | */ |
||
596 | function trap_wp_die( $error_code = null ) { |
||
597 | // Stop trapping |
||
598 | if ( is_null( $error_code ) ) { |
||
599 | $this->trapped_error = null; |
||
600 | remove_filter( 'wp_die_handler', array( $this, 'wp_die_handler_callback' ) ); |
||
601 | return; |
||
602 | } |
||
603 | |||
604 | // If API called via PHP, bail: don't do our custom wp_die(). Do the normal wp_die(). |
||
605 | if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { |
||
606 | if ( ! defined( 'REST_API_REQUEST' ) || ! REST_API_REQUEST ) { |
||
607 | return; |
||
608 | } |
||
609 | } else { |
||
610 | if ( ! defined( 'XMLRPC_REQUEST' ) || ! XMLRPC_REQUEST ) { |
||
611 | return; |
||
612 | } |
||
613 | } |
||
614 | |||
615 | // Start trapping |
||
616 | $this->trapped_error = array( |
||
617 | 'status' => 500, |
||
618 | 'code' => $error_code, |
||
619 | 'message' => '', |
||
620 | ); |
||
621 | |||
622 | add_filter( 'wp_die_handler', array( $this, 'wp_die_handler_callback' ) ); |
||
623 | } |
||
624 | |||
625 | function wp_die_handler_callback() { |
||
626 | return array( $this, 'wp_die_handler' ); |
||
627 | } |
||
628 | |||
629 | function wp_die_handler( $message, $title = '', $args = array() ) { |
||
630 | $args = wp_parse_args( $args, array( |
||
631 | 'response' => 500, |
||
632 | ) ); |
||
633 | |||
634 | if ( $title ) { |
||
635 | $message = "$title: $message"; |
||
636 | } |
||
637 | |||
638 | switch ( $this->trapped_error['code'] ) { |
||
639 | case 'comment_failure' : |
||
640 | if ( did_action( 'comment_duplicate_trigger' ) ) { |
||
641 | $this->trapped_error['code'] = 'comment_duplicate'; |
||
642 | } else if ( did_action( 'comment_flood_trigger' ) ) { |
||
643 | $this->trapped_error['code'] = 'comment_flood'; |
||
644 | } |
||
645 | break; |
||
646 | } |
||
647 | |||
648 | $this->trapped_error['status'] = $args['response']; |
||
649 | $this->trapped_error['message'] = wp_kses( $message, array() ); |
||
650 | |||
651 | // We still want to exit so that code execution stops where it should. |
||
652 | // Attach the JSON output to WordPress' shutdown handler |
||
653 | add_action( 'shutdown', array( $this, 'output_trapped_error' ), 0 ); |
||
654 | exit; |
||
655 | } |
||
656 | |||
657 | function output_trapped_error() { |
||
658 | $this->exit = false; // We're already exiting once. Don't do it twice. |
||
659 | $this->output( $this->trapped_error['status'], (object) array( |
||
660 | 'error' => $this->trapped_error['code'], |
||
661 | 'message' => $this->trapped_error['message'], |
||
662 | ) ); |
||
663 | } |
||
664 | |||
665 | function finish_request() { |
||
666 | if ( function_exists( 'fastcgi_finish_request' ) ) |
||
667 | return fastcgi_finish_request(); |
||
668 | } |
||
669 | } |
||
670 |
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exit
expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.