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; |
||
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; |
||
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 ) { |
||
0 ignored issues
–
show
|
|||
540 | return $GLOBALS['blog_id']; |
||
541 | } |
||
542 | |||
543 | function switch_to_blog_and_validate_user( $blog_id = 0, $verify_token_for_blog = true ) { |
||
0 ignored issues
–
show
|
|||
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 ) { |
||
0 ignored issues
–
show
|
|||
571 | return 0; |
||
572 | } |
||
573 | |||
574 | function is_liked( $blog_id, $post_id ) { |
||
0 ignored issues
–
show
|
|||
575 | return false; |
||
576 | } |
||
577 | |||
578 | function is_reblogged( $blog_id, $post_id ) { |
||
0 ignored issues
–
show
|
|||
579 | return false; |
||
580 | } |
||
581 | |||
582 | function is_following( $blog_id ) { |
||
0 ignored issues
–
show
|
|||
583 | return false; |
||
584 | } |
||
585 | |||
586 | function add_global_ID( $blog_id, $post_id ) { |
||
0 ignored issues
–
show
|
|||
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 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.