X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/6c8f14c09105d0afa4c1574215c59b5021040e76..a349837896628462bf8c9bdc27d1477a10fe03eb:/wp-includes/class-wp-xmlrpc-server.php diff --git a/wp-includes/class-wp-xmlrpc-server.php b/wp-includes/class-wp-xmlrpc-server.php index ac758e4c..255a29c4 100644 --- a/wp-includes/class-wp-xmlrpc-server.php +++ b/wp-includes/class-wp-xmlrpc-server.php @@ -12,8 +12,8 @@ * pingback. Additional WordPress API for managing comments, pages, posts, * options, etc. * - * Since WordPress 2.6.0, WordPress XMLRPC server can be disabled in the - * administration panels. + * As of WordPress 3.5.0, XML-RPC is enabled by default. It can be disabled + * via the xmlrpc_enabled filter found in wp_xmlrpc_server::login(). * * @package WordPress * @subpackage Publishing @@ -211,28 +211,22 @@ class wp_xmlrpc_server extends IXR_Server { } /** - * Sanitize string or array of strings for database. + * Escape string or array of strings for database. * * @since 1.5.2 * - * @param string|array $array Sanitize single string or array of strings. - * @return string|array Type matches $array and sanitized for the database. + * @param string|array $data Escape single string or array of strings. + * @return string|array Type matches $data and sanitized for the database. */ - function escape(&$array) { - global $wpdb; - - if (!is_array($array)) { - return($wpdb->escape($array)); - } else { - foreach ( (array) $array as $k => $v ) { - if ( is_array($v) ) { - $this->escape($array[$k]); - } else if ( is_object($v) ) { - //skip - } else { - $array[$k] = $wpdb->escape($v); - } - } + function escape( &$data ) { + if ( ! is_array( $data ) ) + return wp_slash( $data ); + + foreach ( $data as &$v ) { + if ( is_array( $v ) ) + $this->escape( $v ); + elseif ( ! is_object( $v ) ) + $v = wp_slash( $v ); } } @@ -280,16 +274,16 @@ class wp_xmlrpc_server extends IXR_Server { $meta['id'] = (int) $meta['id']; $pmeta = get_metadata_by_mid( 'post', $meta['id'] ); if ( isset($meta['key']) ) { - $meta['key'] = stripslashes( $meta['key'] ); - if ( $meta['key'] != $pmeta->meta_key ) + $meta['key'] = wp_unslash( $meta['key'] ); + if ( $meta['key'] !== $pmeta->meta_key ) continue; - $meta['value'] = stripslashes_deep( $meta['value'] ); + $meta['value'] = wp_unslash( $meta['value'] ); if ( current_user_can( 'edit_post_meta', $post_id, $meta['key'] ) ) update_metadata_by_mid( 'post', $meta['id'], $meta['value'] ); } elseif ( current_user_can( 'delete_post_meta', $post_id, $pmeta->meta_key ) ) { delete_metadata_by_mid( 'post', $meta['id'] ); } - } elseif ( current_user_can( 'add_post_meta', $post_id, stripslashes( $meta['key'] ) ) ) { + } elseif ( current_user_can( 'add_post_meta', $post_id, wp_unslash( $meta['key'] ) ) ) { add_post_meta( $post_id, $meta['key'], $meta['value'] ); } } @@ -318,15 +312,25 @@ class wp_xmlrpc_server extends IXR_Server { 'value' => $wp_version ), 'blog_url' => array( - 'desc' => __( 'Site URL' ), + 'desc' => __( 'WordPress Address (URL)' ), 'readonly' => true, 'option' => 'siteurl' ), 'home_url' => array( - 'desc' => __( 'Home URL' ), + 'desc' => __( 'Site Address (URL)' ), 'readonly' => true, 'option' => 'home' ), + 'login_url' => array( + 'desc' => __( 'Login Address (URL)' ), + 'readonly' => true, + 'value' => wp_login_url( ) + ), + 'admin_url' => array( + 'desc' => __( 'The URL to the admin area' ), + 'readonly' => true, + 'value' => get_admin_url( ) + ), 'image_default_link_type' => array( 'desc' => __( 'Image default link type' ), 'readonly' => true, @@ -455,7 +459,6 @@ class wp_xmlrpc_server extends IXR_Server { * - 'xmlrpc' - url of xmlrpc endpoint */ function wp_getUsersBlogs( $args ) { - global $current_site; // If this isn't on WPMU then just use blogger_getUsersBlogs if ( !is_multisite() ) { array_unshift( $args, 1 ); @@ -477,7 +480,7 @@ class wp_xmlrpc_server extends IXR_Server { foreach ( $blogs as $blog ) { // Don't include blogs that aren't hosted at this site - if ( $blog->site_id != $current_site->id ) + if ( $blog->site_id != get_current_site()->id ) continue; $blog_id = $blog->userblog_id; @@ -543,6 +546,9 @@ class wp_xmlrpc_server extends IXR_Server { if ( in_array( 'cap', $fields ) ) $_taxonomy['cap'] = (array) $taxonomy->cap; + if ( in_array( 'menu', $fields ) ) + $_taxonomy['show_in_menu'] = (bool) $_taxonomy->show_in_menu; + if ( in_array( 'object_type', $fields ) ) $_taxonomy['object_type'] = array_unique( (array) $taxonomy->object_type ); @@ -562,13 +568,13 @@ class wp_xmlrpc_server extends IXR_Server { if ( ! is_array( $_term) ) $_term = get_object_vars( $_term ); - // For Intergers which may be largeer than XMLRPC supports ensure we return strings. + // For integers which may be larger than XML-RPC supports ensure we return strings. $_term['term_id'] = strval( $_term['term_id'] ); $_term['term_group'] = strval( $_term['term_group'] ); $_term['term_taxonomy_id'] = strval( $_term['term_taxonomy_id'] ); $_term['parent'] = strval( $_term['parent'] ); - // Count we are happy to return as an Integer because people really shouldn't use Terms that much. + // Count we are happy to return as an integer because people really shouldn't use terms that much. $_term['count'] = intval( $_term['count'] ); return apply_filters( 'xmlrpc_prepare_term', $_term, $term ); @@ -1007,7 +1013,7 @@ class wp_xmlrpc_server extends IXR_Server { if ( $update ) { if ( ! get_post( $post_data['ID'] ) ) return new IXR_Error( 401, __( 'Invalid post ID.' ) ); - if ( ! current_user_can( $post_type->cap->edit_post, $post_data['ID'] ) ) + if ( ! current_user_can( 'edit_post', $post_data['ID'] ) ) return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post.' ) ); if ( $post_data['post_type'] != get_post_type( $post_data['ID'] ) ) return new IXR_Error( 401, __( 'The post type may not be changed.' ) ); @@ -1317,8 +1323,7 @@ class wp_xmlrpc_server extends IXR_Server { if ( empty( $post['ID'] ) ) return new IXR_Error( 404, __( 'Invalid post ID.' ) ); - $post_type = get_post_type_object( $post['post_type'] ); - if ( ! current_user_can( $post_type->cap->delete_post, $post_id ) ) + if ( ! current_user_can( 'delete_post', $post_id ) ) return new IXR_Error( 401, __( 'Sorry, you are not allowed to delete this post.' ) ); $result = wp_delete_post( $post_id ); @@ -1399,8 +1404,7 @@ class wp_xmlrpc_server extends IXR_Server { if ( empty( $post['ID'] ) ) return new IXR_Error( 404, __( 'Invalid post ID.' ) ); - $post_type = get_post_type_object( $post['post_type'] ); - if ( ! current_user_can( $post_type->cap->edit_post, $post_id ) ) + if ( ! current_user_can( 'edit_post', $post_id ) ) return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); return $this->_prepare_post( $post, $fields ); @@ -1495,8 +1499,7 @@ class wp_xmlrpc_server extends IXR_Server { $struct = array(); foreach ( $posts_list as $post ) { - $post_type = get_post_type_object( $post['post_type'] ); - if ( ! current_user_can( $post_type->cap->edit_post, $post['ID'] ) ) + if ( ! current_user_can( 'edit_post', $post['ID'] ) ) continue; $struct[] = $this->_prepare_post( $post, $fields ); @@ -2978,9 +2981,9 @@ class wp_xmlrpc_server extends IXR_Server { $comment['comment_post_ID'] = $post_id; if ( $logged_in ) { - $comment['comment_author'] = $wpdb->escape( $user->display_name ); - $comment['comment_author_email'] = $wpdb->escape( $user->user_email ); - $comment['comment_author_url'] = $wpdb->escape( $user->user_url ); + $comment['comment_author'] = $this->escape( $user->display_name ); + $comment['comment_author_email'] = $this->escape( $user->user_email ); + $comment['comment_author_url'] = $this->escape( $user->user_url ); $comment['user_ID'] = $user->ID; } else { $comment['comment_author'] = ''; @@ -3192,6 +3195,7 @@ class wp_xmlrpc_server extends IXR_Server { */ function _getOptions($options) { $data = array(); + $can_manage = current_user_can( 'manage_options' ); foreach ( $options as $option ) { if ( array_key_exists( $option, $this->blog_options ) ) { $data[$option] = $this->blog_options[$option]; @@ -3200,6 +3204,9 @@ class wp_xmlrpc_server extends IXR_Server { $data[$option]['value'] = get_option( $data[$option]['option'] ); unset($data[$option]['option']); } + + if ( ! $can_manage ) + $data[$option]['readonly'] = true; } } @@ -3535,7 +3542,7 @@ class wp_xmlrpc_server extends IXR_Server { return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit posts.' ) ); // Check if revisions are enabled. - if ( ! WP_POST_REVISIONS || ! post_type_supports( $post->post_type, 'revisions' ) ) + if ( ! wp_revisions_enabled( $post ) ) return new IXR_Error( 401, __( 'Sorry, revisions are disabled.' ) ); $revisions = wp_get_post_revisions( $post_id ); @@ -3602,7 +3609,7 @@ class wp_xmlrpc_server extends IXR_Server { return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); // Check if revisions are disabled. - if ( ! WP_POST_REVISIONS || ! post_type_supports( $post->post_type, 'revisions' ) ) + if ( ! wp_revisions_enabled( $post ) ) return new IXR_Error( 401, __( 'Sorry, revisions are disabled.' ) ); $post = wp_restore_post_revision( $revision_id ); @@ -3746,9 +3753,9 @@ class wp_xmlrpc_server extends IXR_Server { $categories = implode(',', wp_get_post_categories($post_ID)); - $content = ''.stripslashes($post_data['post_title']).''; + $content = ''.wp_unslash($post_data['post_title']).''; $content .= ''.$categories.''; - $content .= stripslashes($post_data['post_content']); + $content .= wp_unslash($post_data['post_content']); $struct = array( 'userid' => $post_data['post_author'], @@ -3784,6 +3791,9 @@ class wp_xmlrpc_server extends IXR_Server { if ( !$user = $this->login($username, $password) ) return $this->error; + if ( ! current_user_can( 'edit_posts' ) ) + return new IXR_Error( 401, __( 'Sorry, you cannot edit posts on this site.' ) ); + do_action('xmlrpc_call', 'blogger.getRecentPosts'); $posts_list = wp_get_recent_posts( $query ); @@ -3800,9 +3810,9 @@ class wp_xmlrpc_server extends IXR_Server { $post_date = $this->_convert_date( $entry['post_date'] ); $categories = implode(',', wp_get_post_categories($entry['ID'])); - $content = ''.stripslashes($entry['post_title']).''; + $content = ''.wp_unslash($entry['post_title']).''; $content .= ''.$categories.''; - $content .= stripslashes($entry['post_content']); + $content .= wp_unslash($entry['post_content']); $struct[] = array( 'userid' => $entry['post_author'], @@ -4300,22 +4310,20 @@ class wp_xmlrpc_server extends IXR_Server { return strval($post_ID); } - function add_enclosure_if_new($post_ID, $enclosure) { + function add_enclosure_if_new( $post_ID, $enclosure ) { if ( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) { - - $encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type']; + $encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'] . "\n"; $found = false; - foreach ( (array) get_post_custom($post_ID) as $key => $val) { - if ($key == 'enclosure') { - foreach ( (array) $val as $enc ) { - if ($enc == $encstring) { - $found = true; - break 2; - } + if ( $enclosures = get_post_meta( $post_ID, 'enclosure' ) ) { + foreach ( $enclosures as $enc ) { + // This method used to omit the trailing new line. #23219 + if ( rtrim( $enc, "\n" ) == rtrim( $encstring, "\n" ) ) { + $found = true; + break; } } } - if (!$found) + if ( ! $found ) add_post_meta( $post_ID, 'enclosure', $encstring ); } } @@ -4335,7 +4343,7 @@ class wp_xmlrpc_server extends IXR_Server { $attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '0' AND post_type = 'attachment'" ); if ( is_array( $attachments ) ) { foreach ( $attachments as $file ) { - if ( strpos( $post_content, $file->guid ) !== false ) + if ( ! empty( $file->guid ) && strpos( $post_content, $file->guid ) !== false ) $wpdb->update($wpdb->posts, array('post_parent' => $post_ID), array('ID' => $file->ID) ); } } @@ -4757,6 +4765,9 @@ class wp_xmlrpc_server extends IXR_Server { if ( !$user = $this->login($username, $password) ) return $this->error; + if ( ! current_user_can( 'edit_posts' ) ) + return new IXR_Error( 401, __( 'Sorry, you cannot edit posts on this site.' ) ); + do_action('xmlrpc_call', 'metaWeblog.getRecentPosts'); $posts_list = wp_get_recent_posts( $query ); @@ -4908,8 +4919,8 @@ class wp_xmlrpc_server extends IXR_Server { global $wpdb; $blog_ID = (int) $args[0]; - $username = $wpdb->escape($args[1]); - $password = $wpdb->escape($args[2]); + $username = $this->escape($args[1]); + $password = $this->escape($args[2]); $data = $args[3]; $name = sanitize_file_name( $data['name'] ); @@ -5309,10 +5320,14 @@ class wp_xmlrpc_server extends IXR_Server { $pagelinkedto = str_replace('&', '&', $pagelinkedto); $pagelinkedto = str_replace('&', '&', $pagelinkedto); + $pagelinkedfrom = apply_filters( 'pingback_ping_source_uri', $pagelinkedfrom, $pagelinkedto ); + if ( ! $pagelinkedfrom ) + return $this->pingback_error( 0, __( 'A valid URL was not provided.' ) ); + // Check if the page linked to is in our site $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home'))); if ( !$pos1 ) - return new IXR_Error(0, __('Is there no link to us?')); + return $this->pingback_error( 0, __( 'Is there no link to us?' ) ); // let's find which post is linked to // FIXME: does url_to_postid() cover all these cases already? @@ -5346,51 +5361,64 @@ class wp_xmlrpc_server extends IXR_Server { $sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", like_escape( $title ) ); if (! ($post_ID = $wpdb->get_var($sql)) ) { // returning unknown error '0' is better than die()ing - return new IXR_Error(0, ''); + return $this->pingback_error( 0, '' ); } $way = 'from the fragment (title)'; } } else { // TODO: Attempt to extract a post ID from the given URL - return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.')); + return $this->pingback_error( 33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) ); } $post_ID = (int) $post_ID; $post = get_post($post_ID); if ( !$post ) // Post_ID not found - return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.')); + return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) ); if ( $post_ID == url_to_postid($pagelinkedfrom) ) - return new IXR_Error(0, __('The source URL and the target URL cannot both point to the same resource.')); + return $this->pingback_error( 0, __( 'The source URL and the target URL cannot both point to the same resource.' ) ); // Check if pings are on if ( !pings_open($post) ) - return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.')); + return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) ); // Let's check that the remote site didn't already pingback this entry if ( $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ) ) - return new IXR_Error( 48, __( 'The pingback has already been registered.' ) ); + return $this->pingback_error( 48, __( 'The pingback has already been registered.' ) ); // very stupid, but gives time to the 'from' server to publish ! sleep(1); + $remote_ip = preg_replace( '/[^0-9a-fA-F:., ]/', '', $_SERVER['REMOTE_ADDR'] ); + $user_agent = apply_filters( 'http_headers_useragent', 'WordPress/' . $GLOBALS['wp_version'] . '; ' . get_bloginfo( 'url' ) ); + // Let's check the remote site - $linea = wp_remote_fopen( $pagelinkedfrom ); + $http_api_args = array( + 'timeout' => 10, + 'redirection' => 0, + 'limit_response_size' => 153600, // 150 KB + 'user-agent' => "$user_agent; verifying pingback from $remote_ip", + 'headers' => array( + 'X-Pingback-Forwarded-For' => $remote_ip, + ), + ); + $linea = wp_remote_retrieve_body( wp_safe_remote_get( $pagelinkedfrom, $http_api_args ) ); + if ( !$linea ) - return new IXR_Error(16, __('The source URL does not exist.')); + return $this->pingback_error( 16, __( 'The source URL does not exist.' ) ); $linea = apply_filters('pre_remote_source', $linea, $pagelinkedto); // Work around bug in strip_tags(): $linea = str_replace(']*>/", "\n\n", $linea ); preg_match('|([^<]*?)|is', $linea, $matchtitle); $title = $matchtitle[1]; if ( empty( $title ) ) - return new IXR_Error(32, __('We cannot find a title on that page.')); + return $this->pingback_error( 32, __('We cannot find a title on that page.' ) ); $linea = strip_tags( $linea, '' ); // just keep the tag we need @@ -5412,7 +5440,7 @@ class wp_xmlrpc_server extends IXR_Server { // prevent really long link text if ( strlen($context[1]) > 100 ) - $context[1] = substr($context[1], 0, 100) . '...'; + $context[1] = substr($context[1], 0, 100) . '…'; $marker = ''.$context[1].''; // set up our marker $excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker @@ -5426,12 +5454,12 @@ class wp_xmlrpc_server extends IXR_Server { } if ( empty($context) ) // Link to target not found - return new IXR_Error(17, __('The source URL does not contain a link to the target URL, and so cannot be used as a source.')); + return $this->pingback_error( 17, __( 'The source URL does not contain a link to the target URL, and so cannot be used as a source.' ) ); $pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom); - $context = '[...] ' . esc_html( $excerpt ) . ' [...]'; - $pagelinkedfrom = $wpdb->escape( $pagelinkedfrom ); + $context = '[…] ' . esc_html( $excerpt ) . ' […]'; + $pagelinkedfrom = $this->escape( $pagelinkedfrom ); $comment_post_ID = (int) $post_ID; $comment_author = $title; @@ -5473,14 +5501,14 @@ class wp_xmlrpc_server extends IXR_Server { $post_ID = url_to_postid($url); if ( !$post_ID ) { // We aren't sure that the resource is available and/or pingback enabled - return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.')); + return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) ); } $actual_post = get_post($post_ID, ARRAY_A); if ( !$actual_post ) { // No such post = resource not found - return new IXR_Error(32, __('The specified target URL does not exist.')); + return $this->pingback_error( 32, __('The specified target URL does not exist.' ) ); } $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = %d", $post_ID) ); @@ -5496,4 +5524,8 @@ class wp_xmlrpc_server extends IXR_Server { return $pingbacks; } + + protected function pingback_error( $code, $message ) { + return apply_filters( 'xmlrpc_pingback_error', new IXR_Error( $code, $message ) ); + } }