From 88f521011a323c554dff63cdb3d20884f280a27f Mon Sep 17 00:00:00 2001 From: westi Date: Tue, 12 Aug 2008 21:21:11 +0000 Subject: [PATCH] HTTP API improvements. Implements chunked transfer decoding. Moves plugin update checker over to api. see #4779 props santosj. git-svn-id: http://svn.automattic.com/wordpress/trunk@8630 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/includes/plugin-install.php | 2 +- wp-includes/http.php | 344 +++++++++++++++------------ wp-includes/update.php | 64 ++--- 3 files changed, 225 insertions(+), 185 deletions(-) diff --git a/wp-admin/includes/plugin-install.php b/wp-admin/includes/plugin-install.php index 767978982..526ecfc74 100644 --- a/wp-admin/includes/plugin-install.php +++ b/wp-admin/includes/plugin-install.php @@ -10,7 +10,7 @@ function plugins_api($action, $args = NULL) { $res = apply_filters('plugins_api', false, $action, $args); //NOTE: Allows a plugin to completely override the builtin WordPress.org API. if ( ! $res ) { - $request = wp_remote_post('http://api.wordpress.org/plugins/info/1.0/', array(), array(), array('action' => $action, 'request' => serialize($args)) ); + $request = wp_remote_post('http://api.wordpress.org/plugins/info/1.0/', array( 'body' => array('action' => $action, 'request' => serialize($args))) ); $res = unserialize($request['body']); if ( ! $res ) wp_die($request['body']); diff --git a/wp-includes/http.php b/wp-includes/http.php index 6241469c5..13aebb01e 100644 --- a/wp-includes/http.php +++ b/wp-includes/http.php @@ -137,6 +137,12 @@ class WP_Http { /** * Send a HTTP request to a URI. * + * The body and headers are part of the arguments. The 'body' argument is + * for the body and will accept either a string or an array. The 'headers' + * argument should be an array, but a string is acceptable. If the 'body' + * argument is an array, then it will automatically be escaped using + * http_build_query(). + * * The only URI that are supported in the HTTP Transport implementation are * the HTTP and HTTPS protocols. HTTP and HTTPS are assumed so the server * might not know how to handle the send headers. Other protocols are @@ -171,50 +177,54 @@ class WP_Http { * * @param string $url URI resource. * @param str|array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. - * @param string $body Optional. The body that should be sent. Will be automatically escaped and processed. * @return boolean */ - function request($url, $args = array(), $headers = null, $body = null) { + function request( $url, $args = array() ) { global $wp_version; $defaults = array( 'method' => 'GET', 'timeout' => apply_filters('http_request_timeout', 3), 'redirection' => 5, 'httpversion' => '1.0', 'user-agent' => apply_filters('http_headers_useragent', 'WordPress/' . $wp_version ), - 'blocking' => true + 'blocking' => true, + 'headers' => array(), 'body' => null ); $r = wp_parse_args( $args, $defaults ); - if ( is_null($headers) ) - $headers = array(); + if ( is_null( $r['headers'] ) ) + $r['headers'] = array(); - if ( ! is_array($headers) ) { - $processedHeaders = WP_Http::processHeaders($headers); - $headers = $processedHeaders['headers']; + if ( ! is_array($r['headers']) ) { + $processedHeaders = WP_Http::processHeaders($r['headers']); + $r['headers'] = $processedHeaders['headers']; } - if ( isset($headers['User-Agent']) ) { - $headers['user-agent'] = $headers['User-Agent']; - unset($headers['User-Agent']); + if ( isset($r['headers']['User-Agent']) ) { + $r['user-agent'] = $headers['User-Agent']; + unset($r['headers']['User-Agent']); } - if ( ! isset($headers['user-agent']) ) - $headers['user-agent'] = $r['user-agent']; + if ( isset($r['headers']['user-agent']) ) { + $r['user-agent'] = $r['headers']['user-agent']; + unset($r['headers']['user-agent']); + } - if ( is_null($body) ) { + if ( is_null($r['body']) ) { $transports = WP_Http::_getTransport(); } else { - if ( is_array($body) || is_object($body) ) - $body = http_build_query($body); + if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) { + $r['body'] = http_build_query($r['body']); + $r['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'); + $r['headers']['Content-Length'] = strlen($r['body']); + } $transports = WP_Http::_postTransport(); } $response = array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); foreach( (array) $transports as $transport ) { - $response = $transport->request($url, $r, $headers, $body); + $response = $transport->request($url, $r); if( !is_wp_error($response) ) return $response; @@ -233,14 +243,12 @@ class WP_Http { * * @param string $url URI resource. * @param str|array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return boolean */ - function post($url, $args = array(), $headers = null, $body = null) { + function post($url, $args = array()) { $defaults = array('method' => 'POST'); $r = wp_parse_args( $args, $defaults ); - return $this->request($url, $r, $headers, $body); + return $this->request($url, $r); } /** @@ -253,14 +261,12 @@ class WP_Http { * * @param string $url URI resource. * @param str|array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return boolean */ - function get($url, $args = array(), $headers = null, $body = null) { + function get($url, $args = array()) { $defaults = array('method' => 'GET'); $r = wp_parse_args( $args, $defaults ); - return $this->request($url, $r, $headers, $body); + return $this->request($url, $r); } /** @@ -273,14 +279,12 @@ class WP_Http { * * @param string $url URI resource. * @param str|array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return boolean */ - function head($url, $args = array(), $headers = null, $body = null) { + function head($url, $args = array()) { $defaults = array('method' => 'HEAD'); $r = wp_parse_args( $args, $defaults ); - return $this->request($url, $r, $headers, $body); + return $this->request($url, $r); } /** @@ -298,40 +302,6 @@ class WP_Http { return array('headers' => $theHeaders, 'body' => $theBody); } - /** - * Whether response code is in the 400 range. - * - * @access public - * @static - * @since 2.7 - * - * @param array $response Array with code and message keys - * @return bool True if 40x Response, false if something else. - */ - function is400Response($response) { - if ( (int) substr($response, 0, 1) == 4 ) - return true; - return false; - } - - /** - * Whether the headers returned a redirect location. - * - * Actually just checks whether the location header exists. - * - * @access public - * @static - * @since 2.7 - * - * @param array $headers Array with headers - * @return bool True if Location header is found. - */ - function isRedirect($headers) { - if ( isset($headers['location']) ) - return true; - return false; - } - /** * Transform header string into an array. * @@ -357,7 +327,6 @@ class WP_Http { if ( empty($tempheader) ) continue; - if ( false === strpos($tempheader, ':') ) { list( , $iResponseCode, $strResponseMsg) = explode(' ', $tempheader, 3); $response['code'] = $iResponseCode; @@ -373,6 +342,61 @@ class WP_Http { return array('response' => $response, 'headers' => $newheaders); } + + /** + * Decodes chunk transfer-encoding, based off the HTTP 1.1 specification. + * + * Based off the HTTP http_encoding_dechunk function. Does not support + * UTF-8. Does not support returning footer headers. Shouldn't be too + * difficult to support it though. + * + * @todo Add support for footer chunked headers. + * + * @static + * @param string $body Body content + * @return bool|string|WP_Error False if not chunked encoded. WP_Error on failure. Chunked decoded body on success. + */ + function chunkTransferDecode($body) { + $body = str_replace(array("\r\n", "\r"), "\n", $body); + // The body is not chunked encoding or is malformed. + if ( ! preg_match( '/^[0-9a-f]+(\s|\n)+/mi', trim($body) ) ) + return false; + + $hex = ''; + $dec = 0; + $parsedBody = ''; + $parsedHeaders = array(); + + $done = false; + + do { + $hasChunk = (bool) preg_match( '/^([0-9a-f]+)(\s|\n)+/mi', $body, $match ); + + if ( $hasChunk ) { + if ( empty($match[1]) ) { + return new WP_Error('http_chunked_decode', __('Does not appear to be chunked encoded or body is malformed.') ); + } + + $length = hexdec( $match[1] ); + $chunkLength = strlen( $match[0] ); + + if( $body{$length+$chunkLength} == "\n" ) + $length++; + + $strBody = substr($body, strlen( $match[0] ), $length); + $parsedBody .= $strBody; + $body = str_replace(array($match[0], $strBody), '', $body); + + if( "0" == $body ) { + $done = true; + return $parsedBody; // Ignore footer headers. + break; + } + } else { + return new WP_Error('http_chunked_decode', __('Does not appear to be chunked encoded or body is malformed.') ); + } + } while ( false === $done ); + } } /** @@ -391,25 +415,32 @@ class WP_Http_Fsockopen { * * Does not support non-blocking mode. * - * @see WP_Http::retrieve For default options descriptions. + * @see WP_Http::request For default options descriptions. * * @since 2.7 * @access public * @param string $url URI resource. * @param str|array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return array 'headers', 'body', and 'response' keys. */ - function request($url, $args = array(), $headers = null, $body = null) { + function request($url, $args = array()) { $defaults = array( 'method' => 'GET', 'timeout' => 3, 'redirection' => 5, 'httpversion' => '1.0', - 'blocking' => true + 'blocking' => true, + 'headers' => array(), 'body' => null ); $r = wp_parse_args( $args, $defaults ); + if ( isset($r['headers']['User-Agent']) ) { + $r['user-agent'] = $r['headers']['User-Agent']; + unset($r['headers']['User-Agent']); + } else if( isset($r['headers']['user-agent']) ) { + $r['user-agent'] = $r['headers']['user-agent']; + unset($r['headers']['user-agent']); + } + $iError = null; // Store error number $strError = null; // Store error string @@ -445,22 +476,21 @@ class WP_Http_Fsockopen { $strHeaders = ''; $strHeaders .= strtoupper($r['method']) . ' ' . $requestPath . ' HTTP/' . $r['httpversion'] . "\r\n"; $strHeaders .= 'Host: ' . $arrURL['host'] . "\r\n"; - if ( ! is_null($body) ) { - $strHeaders .= 'Content-Type: application/x-www-form-urlencoded; charset=' . get_option('blog_charset') . "\r\n"; - $strHeaders .= 'Content-Length: ' . strlen($body) . "\r\n"; - } - if ( is_array($headers) ) { - foreach ( (array) $headers as $header => $headerValue ) + if( isset($r['user-agent']) ) + $strHeaders .= 'User-agent: ' . $r['user-agent'] . "\r\n"; + + if ( is_array($r['headers']) ) { + foreach ( (array) $r['headers'] as $header => $headerValue ) $strHeaders .= $header . ': ' . $headerValue . "\r\n"; } else { - $strHeaders .= $headers; + $strHeaders .= $r['headers']; } $strHeaders .= "\r\n"; - if ( ! is_null($body) ) - $strHeaders .= $body; + if ( ! is_null($r['body']) ) + $strHeaders .= $r['body']; fwrite($handle, $strHeaders); @@ -481,12 +511,14 @@ class WP_Http_Fsockopen { $process = WP_Http::processResponse($strResponse); $arrHeaders = WP_Http::processHeaders($process['headers']); - if ( WP_Http::is400Response($arrHeaders['response']) ) + if ( WP_Http_Fsockopen::is400Response($arrHeaders['response']['code']) ) return new WP_Error('http_request_failed', $arrHeaders['response']['code'] . ': ' . $arrHeaders['response']['message']); + // If location is found, then assume redirect and redirect to location. if ( isset($arrHeaders['headers']['location']) ) { - if ( $r['redirection']-- > 0 ) - return $this->request($arrHeaders['headers']['location'], $r, $headers, $body); + if ( $r['redirection']-- > 0 ) { + return $this->request($arrHeaders['headers']['location'], $r); + } else return new WP_Error('http_request_failed', __('Too many redirects.')); } @@ -507,6 +539,22 @@ class WP_Http_Fsockopen { return false; } + + /** + * Whether response code is in the 400 range. + * + * @access public + * @static + * @since 2.7 + * + * @param string $response Response code. + * @return bool True if 40x Response, false if something else. + */ + function is400Response($response) { + if ( is_numeric($response) && (int) substr($response, 0, 1) == 4 ) + return true; + return false; + } } /** @@ -536,17 +584,16 @@ class WP_Http_Fopen { * * @param string $url URI resource. * @param str|array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return array 'headers', 'body', and 'response' keys. */ - function request($url, $args = array(), $headers = null, $body = null) { + function request($url, $args = array()) { global $http_response_header; $defaults = array( 'method' => 'GET', 'timeout' => 3, 'redirection' => 5, 'httpversion' => '1.0', - 'blocking' => true + 'blocking' => true, + 'headers' => array(), 'body' => null ); $r = wp_parse_args( $args, $defaults ); @@ -591,6 +638,9 @@ class WP_Http_Fopen { $processedHeaders = WP_Http::processHeaders($theHeaders); + if ( ! empty( $strResponse ) && isset( $processedHeaders['headers']['transfer-encoding'] ) && 'chunked' == $processedHeaders['headers']['transfer-encoding'] ) + $theBody = WP_Http::chunkTransferDecode($strResponse); + return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']); } @@ -629,27 +679,24 @@ class WP_Http_Streams { * * @param string $url * @param str|array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return array 'headers', 'body', and 'response' keys. */ - function request($url, $args = array(), $headers = null, $body = null) { + function request($url, $args = array()) { $defaults = array( 'method' => 'GET', 'timeout' => 3, 'redirection' => 5, 'httpversion' => '1.0', - 'blocking' => true + 'blocking' => true, + 'headers' => array(), 'body' => null ); $r = wp_parse_args( $args, $defaults ); - if ( isset($headers['User-Agent']) ) { - $r['user-agent'] = $headers['User-Agent']; - unset($headers['User-Agent']); - } else if( isset($headers['user-agent']) ) { - $r['user-agent'] = $headers['user-agent']; - unset($headers['user-agent']); - } else { - $r['user-agent'] = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version ); + if ( isset($r['headers']['User-Agent']) ) { + $r['user-agent'] = $r['headers']['User-Agent']; + unset($r['headers']['User-Agent']); + } else if( isset($r['headers']['user-agent']) ) { + $r['user-agent'] = $r['headers']['user-agent']; + unset($r['headers']['user-agent']); } $arrURL = parse_url($url); @@ -660,19 +707,27 @@ class WP_Http_Streams { if ( 'http' != $arrURL['scheme'] || 'https' != $arrURL['scheme'] ) $url = str_replace($arrURL['scheme'], 'http', $url); + // Convert Header array to string. + $strHeaders = ''; + if ( is_array( $r['headers'] ) ) + foreach( $r['headers'] as $name => $value ) + $strHeaders .= "{$name}: $value\r\n"; + else if ( is_string( $r['headers'] ) ) + $strHeaders = $r['headers']; + $arrContext = array('http' => array( 'method' => strtoupper($r['method']), 'user-agent' => $r['user-agent'], 'max_redirects' => $r['redirection'], 'protocol_version' => (float) $r['httpversion'], - 'header' => $headers, + 'header' => $strHeaders, 'timeout' => $r['timeout'] ) ); - if ( ! is_null($body) ) - $arrContext['http']['content'] = $body; + if ( ! is_null($r['body']) && ! empty($r['body'] ) ) + $arrContext['http']['content'] = $r['body']; $context = stream_context_create($arrContext); @@ -695,6 +750,9 @@ class WP_Http_Streams { $meta = stream_get_meta_data($handle); $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']); + if ( ! empty( $strResponse ) && isset( $processedHeaders['headers']['transfer-encoding'] ) && 'chunked' == $processedHeaders['headers']['transfer-encoding'] ) + $theBody = WP_Http::chunkTransferDecode($strResponse); + fclose($handle); return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']); @@ -743,29 +801,24 @@ class WP_Http_ExtHTTP { * * @param string $url * @param str|array $args Optional. Override the defaults. - * @param array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return array 'headers', 'body', and 'response' keys. */ - function request($url, $args = array(), $headers = null, $body = null) { - global $wp_version; - + function request($url, $args = array()) { $defaults = array( 'method' => 'GET', 'timeout' => 3, 'redirection' => 5, 'httpversion' => '1.0', - 'blocking' => true + 'blocking' => true, + 'headers' => array(), 'body' => null ); $r = wp_parse_args( $args, $defaults ); - if ( isset($headers['User-Agent']) ) { - $r['user-agent'] = $headers['User-Agent']; - unset($headers['User-Agent']); - } else if( isset($headers['user-agent']) ) { - $r['user-agent'] = $headers['user-agent']; - unset($headers['user-agent']); - } else { - $r['user-agent'] = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version ); + if ( isset($r['headers']['User-Agent']) ) { + $r['user-agent'] = $r['headers']['User-Agent']; + unset($r['headers']['User-Agent']); + } else if( isset($r['headers']['user-agent']) ) { + $r['user-agent'] = $r['headers']['user-agent']; + unset($r['headers']['user-agent']); } switch ( $r['method'] ) { @@ -792,10 +845,10 @@ class WP_Http_ExtHTTP { 'connecttimeout' => $r['timeout'], 'redirect' => $r['redirection'], 'useragent' => $r['user-agent'], - 'headers' => $headers, + 'headers' => $r['headers'], ); - $strResponse = http_request($r['method'], $url, $body, $options, $info); + $strResponse = http_request($r['method'], $url, $r['body'], $options, $info); if ( false === $strResponse ) return new WP_Error('http_request_failed', $info['response_code'] . ': ' . $info['error']); @@ -850,29 +903,24 @@ class WP_Http_Curl { * * @param string $url * @param str|array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return array 'headers', 'body', and 'response' keys. */ - function request($url, $args = array(), $headers = null, $body = null) { - global $wp_version; - + function request($url, $args = array()) { $defaults = array( 'method' => 'GET', 'timeout' => 3, 'redirection' => 5, 'httpversion' => '1.0', - 'blocking' => true + 'blocking' => true, + 'headers' => array(), 'body' => null ); $r = wp_parse_args( $args, $defaults ); - if ( isset($headers['User-Agent']) ) { - $r['user-agent'] = $headers['User-Agent']; - unset($headers['User-Agent']); - } else if( isset($headers['user-agent']) ) { - $r['user-agent'] = $headers['user-agent']; - unset($headers['user-agent']); - } else { - $r['user-agent'] = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version ); + if ( isset($r['headers']['User-Agent']) ) { + $r['user-agent'] = $r['headers']['User-Agent']; + unset($r['headers']['User-Agent']); + } else if( isset($r['headers']['user-agent']) ) { + $r['user-agent'] = $r['headers']['user-agent']; + unset($r['headers']['user-agent']); } $handle = curl_init(); @@ -896,8 +944,8 @@ class WP_Http_Curl { if ( !ini_get('safe_mode') && !ini_get('open_basedir') ) curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, true ); - if( ! is_null($headers) ) - curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers ); + if( ! is_null($r['headers']) ) + curl_setopt( $handle, CURLOPT_HTTPHEADER, $r['headers'] ); if ( $r['httpversion'] == '1.0' ) curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 ); @@ -915,6 +963,9 @@ class WP_Http_Curl { list($theHeaders, $theBody) = explode("\r\n\r\n", $theResponse, 2); $theHeaders = WP_Http::processHeaders($theHeaders); + if ( ! empty( $theBody ) && isset( $theHeaders['headers']['transfer-encoding'] ) && 'chunked' == $theHeaders['headers']['transfer-encoding'] ) + $theBody = WP_Http::chunkTransferDecode($theBody); + $response = array(); $response['code'] = curl_getinfo( $handle, CURLINFO_HTTP_CODE ); $response['message'] = get_status_header_desc($response['code']); @@ -986,14 +1037,11 @@ function &_wp_http_get_object() { * * @param string $url Site URL to retrieve. * @param array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return string The body of the response */ -function wp_remote_request($url, $args = array(), $headers = null, $body = null) { +function wp_remote_request($url, $args = array()) { $objFetchSite = _wp_http_get_object(); - - return $objFetchSite->request($url, $args, $headers, $body); + return $objFetchSite->request($url, $args); } /** @@ -1005,14 +1053,12 @@ function wp_remote_request($url, $args = array(), $headers = null, $body = null) * * @param string $url Site URL to retrieve. * @param array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return string The body of the response */ -function wp_remote_get($url, $args = array(), $headers = null, $body = null) { +function wp_remote_get($url, $args = array()) { $objFetchSite = _wp_http_get_object(); - return $objFetchSite->get($url, $args, $headers, $body); + return $objFetchSite->get($url, $args); } /** @@ -1024,14 +1070,11 @@ function wp_remote_get($url, $args = array(), $headers = null, $body = null) { * * @param string $url Site URL to retrieve. * @param array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return string The body of the response */ -function wp_remote_post($url, $args = array(), $headers = null, $body = null) { +function wp_remote_post($url, $args = array()) { $objFetchSite = _wp_http_get_object(); - - return $objFetchSite->post($url, $args, $headers, $body); + return $objFetchSite->post($url, $args); } /** @@ -1043,14 +1086,11 @@ function wp_remote_post($url, $args = array(), $headers = null, $body = null) { * * @param string $url Site URL to retrieve. * @param array $args Optional. Override the defaults. - * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. - * @param string $body Optional. The body that should be sent. Expected to be already processed. * @return string The body of the response */ -function wp_remote_head($url, $args = array(), $headers = null, $body = null) { +function wp_remote_head($url, $args = array()) { $objFetchSite = _wp_http_get_object(); - - return $objFetchSite->head($url, $args, $headers, $body); + return $objFetchSite->head($url, $args); } /** diff --git a/wp-includes/update.php b/wp-includes/update.php index 3b072411d..b1c162ad7 100644 --- a/wp-includes/update.php +++ b/wp-includes/update.php @@ -1,17 +1,17 @@ version_checked = $wp_version; $url = "http://api.wordpress.org/core/version-check/1.2/?version=$wp_version&php=$php_version&locale=$locale"; - $options = array('timeout' => 3); - $headers = array( + $options = array('timeout' => 3); + $options['headers'] = array( 'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'), 'User-Agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo('url') ); - $response = wp_remote_request($url, $options, $headers); + $response = wp_remote_request($url, $options); + + if ( is_wp_error( $response ) ) + return false; if ( 200 != $response['response']['code'] ) return false; - $body = $response['body']; - $body = trim( $body ); + $body = trim( $response['body'] ); $body = str_replace(array("\r\n", "\r"), "\n", $body); $returns = explode("\n", $body); @@ -73,11 +75,12 @@ function wp_version_check() { add_action( 'init', 'wp_version_check' ); /** - * wp_update_plugins() - Check plugin versions against the latest versions hosted on WordPress.org. + * Check plugin versions against the latest versions hosted on WordPress.org. * - * The WordPress version, PHP version, and Locale is sent along with a list of all plugins installed. - * Checks against the WordPress server at api.wordpress.org. - * Will only check if PHP has fsockopen enabled and WordPress isn't installing. + * The WordPress version, PHP version, and Locale is sent along with a list of + * all plugins installed. Checks against the WordPress server at + * api.wordpress.org. Will only check if PHP has fsockopen enabled and WordPress + * isn't installing. * * @package WordPress * @since 2.3 @@ -88,7 +91,7 @@ add_action( 'init', 'wp_version_check' ); function wp_update_plugins() { global $wp_version; - if ( !function_exists('fsockopen') || defined('WP_INSTALLING') ) + if ( defined('WP_INSTALLING') ) return false; // If running blog-side, bail unless we've not checked in the last 12 hours @@ -116,9 +119,11 @@ function wp_update_plugins() { $plugin_changed = true; } - foreach ( (array) $current->response as $plugin_file => $update_details ) { - if ( ! isset($plugins[ $plugin_file ]) ) { - $plugin_changed = true; + if ( isset ( $current->response ) && is_array( $current->response ) ) { + foreach ( $current->response as $plugin_file => $update_details ) { + if ( ! isset($plugins[ $plugin_file ]) ) { + $plugin_changed = true; + } } } @@ -129,27 +134,22 @@ function wp_update_plugins() { $to_send->plugins = $plugins; $to_send->active = $active; $send = serialize( $to_send ); + $body = 'plugins=' . urlencode( $send ); - $request = 'plugins=' . urlencode( $send ); - $http_request = "POST /plugins/update-check/1.0/ HTTP/1.0\r\n"; - $http_request .= "Host: api.wordpress.org\r\n"; - $http_request .= "Content-Type: application/x-www-form-urlencoded; charset=" . get_option('blog_charset') . "\r\n"; - $http_request .= "Content-Length: " . strlen($request) . "\r\n"; - $http_request .= 'User-Agent: WordPress/' . $wp_version . '; ' . get_bloginfo('url') . "\r\n"; - $http_request .= "\r\n"; - $http_request .= $request; + $options = array('method' => 'POST', 'timeout' => 3, 'body' => $body); + $options['headers'] = array( + 'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'), + 'Content-Length' => strlen($body), + 'User-Agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo('url') + ); - $response = ''; - if( false != ( $fs = @fsockopen( 'api.wordpress.org', 80, $errno, $errstr, 3) ) && is_resource($fs) ) { - fwrite($fs, $http_request); + $raw_response = wp_remote_request('http://api.wordpress.org/plugins/update-check/1.0/', $options); - while ( !feof($fs) ) - $response .= fgets($fs, 1160); // One TCP-IP packet - fclose($fs); - $response = explode("\r\n\r\n", $response, 2); + if( 200 != $raw_response['response']['code'] ) { + return false; } - $response = unserialize( $response[1] ); + $response = unserialize( $raw_response['body'] ); if ( $response ) $new_option->response = $response;