[ Index ]

PHP Cross Reference of Wordpress 2.9.1

title

Body

[close]

/wp-includes/ -> http.php (source)

   1  <?php
   2  /**
   3   * Simple and uniform HTTP request API.
   4   *
   5   * Will eventually replace and standardize the WordPress HTTP requests made.
   6   *
   7   * @link http://trac.wordpress.org/ticket/4779 HTTP API Proposal
   8   *
   9   * @package WordPress
  10   * @subpackage HTTP
  11   * @since 2.7.0
  12   * @author Jacob Santos <wordpress@santosj.name>
  13   */
  14  
  15  /**
  16   * WordPress HTTP Class for managing HTTP Transports and making HTTP requests.
  17   *
  18   * This class is called for the functionality of making HTTP requests and should replace Snoopy
  19   * functionality, eventually. There is no available functionality to add HTTP transport
  20   * implementations, since most of the HTTP transports are added and available for use.
  21   *
  22   * The exception is that cURL is not available as a transport and lacking an implementation. It will
  23   * be added later and should be a patch on the WordPress Trac.
  24   *
  25   * There are no properties, because none are needed and for performance reasons. Some of the
  26   * functions are static and while they do have some overhead over functions in PHP4, the purpose is
  27   * maintainability. When PHP5 is finally the requirement, it will be easy to add the static keyword
  28   * to the code. It is not as easy to convert a function to a method after enough code uses the old
  29   * way.
  30   *
  31   * Debugging includes several actions, which pass different variables for debugging the HTTP API.
  32   *
  33   * <strong>http_transport_get_debug</strong> - gives working, nonblocking, and blocking transports.
  34   *
  35   * <strong>http_transport_post_debug</strong> - gives working, nonblocking, and blocking transports.
  36   *
  37   * @package WordPress
  38   * @subpackage HTTP
  39   * @since 2.7.0
  40   */
  41  class WP_Http {
  42  
  43      /**
  44       * PHP4 style Constructor - Calls PHP5 Style Constructor
  45       *
  46       * @since 2.7.0
  47       * @return WP_Http
  48       */
  49  	function WP_Http() {
  50          $this->__construct();
  51      }
  52  
  53      /**
  54       * PHP5 style Constructor - Setup available transport if not available.
  55       *
  56       * PHP4 does not have the 'self' keyword and since WordPress supports PHP4,
  57       * the class needs to be used for the static call.
  58       *
  59       * The transport are setup to save time. This should only be called once, so
  60       * the overhead should be fine.
  61       *
  62       * @since 2.7.0
  63       * @return WP_Http
  64       */
  65  	function __construct() {
  66          WP_Http::_getTransport();
  67          WP_Http::_postTransport();
  68      }
  69  
  70      /**
  71       * Tests the WordPress HTTP objects for an object to use and returns it.
  72       *
  73       * Tests all of the objects and returns the object that passes. Also caches
  74       * that object to be used later.
  75       *
  76       * The order for the GET/HEAD requests are Streams, HTTP Extension, Fopen,
  77       * and finally Fsockopen. fsockopen() is used last, because it has the most
  78       * overhead in its implementation. There isn't any real way around it, since
  79       * redirects have to be supported, much the same way the other transports
  80       * also handle redirects.
  81       *
  82       * There are currently issues with "localhost" not resolving correctly with
  83       * DNS. This may cause an error "failed to open stream: A connection attempt
  84       * failed because the connected party did not properly respond after a
  85       * period of time, or established connection failed because connected host
  86       * has failed to respond."
  87       *
  88       * @since 2.7.0
  89       * @access private
  90       *
  91       * @param array $args Request args, default us an empty array
  92       * @return object|null Null if no transports are available, HTTP transport object.
  93       */
  94      function &_getTransport( $args = array() ) {
  95          static $working_transport, $blocking_transport, $nonblocking_transport;
  96  
  97          if ( is_null($working_transport) ) {
  98              if ( true === WP_Http_ExtHttp::test($args) ) {
  99                  $working_transport['exthttp'] = new WP_Http_ExtHttp();
 100                  $blocking_transport[] = &$working_transport['exthttp'];
 101              } else if ( true === WP_Http_Curl::test($args) ) {
 102                  $working_transport['curl'] = new WP_Http_Curl();
 103                  $blocking_transport[] = &$working_transport['curl'];
 104              } else if ( true === WP_Http_Streams::test($args) ) {
 105                  $working_transport['streams'] = new WP_Http_Streams();
 106                  $blocking_transport[] = &$working_transport['streams'];
 107              } else if ( true === WP_Http_Fopen::test($args) ) {
 108                  $working_transport['fopen'] = new WP_Http_Fopen();
 109                  $blocking_transport[] = &$working_transport['fopen'];
 110              } else if ( true === WP_Http_Fsockopen::test($args) ) {
 111                  $working_transport['fsockopen'] = new WP_Http_Fsockopen();
 112                  $blocking_transport[] = &$working_transport['fsockopen'];
 113              }
 114  
 115              foreach ( array('curl', 'streams', 'fopen', 'fsockopen', 'exthttp') as $transport ) {
 116                  if ( isset($working_transport[$transport]) )
 117                      $nonblocking_transport[] = &$working_transport[$transport];
 118              }
 119          }
 120  
 121          do_action( 'http_transport_get_debug', $working_transport, $blocking_transport, $nonblocking_transport );
 122  
 123          if ( isset($args['blocking']) && !$args['blocking'] )
 124              return $nonblocking_transport;
 125          else
 126              return $blocking_transport;
 127      }
 128  
 129      /**
 130       * Tests the WordPress HTTP objects for an object to use and returns it.
 131       *
 132       * Tests all of the objects and returns the object that passes. Also caches
 133       * that object to be used later. This is for posting content to a URL and
 134       * is used when there is a body. The plain Fopen Transport can not be used
 135       * to send content, but the streams transport can. This is a limitation that
 136       * is addressed here, by just not including that transport.
 137       *
 138       * @since 2.7.0
 139       * @access private
 140       *
 141       * @param array $args Request args, default us an empty array
 142       * @return object|null Null if no transports are available, HTTP transport object.
 143       */
 144      function &_postTransport( $args = array() ) {
 145          static $working_transport, $blocking_transport, $nonblocking_transport;
 146  
 147          if ( is_null($working_transport) ) {
 148              if ( true === WP_Http_ExtHttp::test($args) ) {
 149                  $working_transport['exthttp'] = new WP_Http_ExtHttp();
 150                  $blocking_transport[] = &$working_transport['exthttp'];
 151              } else if ( true === WP_Http_Curl::test($args) ) {
 152                  $working_transport['curl'] = new WP_Http_Curl();
 153                  $blocking_transport[] = &$working_transport['curl'];
 154              } else if ( true === WP_Http_Streams::test($args) ) {
 155                  $working_transport['streams'] = new WP_Http_Streams();
 156                  $blocking_transport[] = &$working_transport['streams'];
 157              } else if ( true === WP_Http_Fsockopen::test($args) ) {
 158                  $working_transport['fsockopen'] = new WP_Http_Fsockopen();
 159                  $blocking_transport[] = &$working_transport['fsockopen'];
 160              }
 161  
 162              foreach ( array('curl', 'streams', 'fsockopen', 'exthttp') as $transport ) {
 163                  if ( isset($working_transport[$transport]) )
 164                      $nonblocking_transport[] = &$working_transport[$transport];
 165              }
 166          }
 167  
 168          do_action( 'http_transport_post_debug', $working_transport, $blocking_transport, $nonblocking_transport );
 169  
 170          if ( isset($args['blocking']) && !$args['blocking'] )
 171              return $nonblocking_transport;
 172          else
 173              return $blocking_transport;
 174      }
 175  
 176      /**
 177       * Send a HTTP request to a URI.
 178       *
 179       * The body and headers are part of the arguments. The 'body' argument is for the body and will
 180       * accept either a string or an array. The 'headers' argument should be an array, but a string
 181       * is acceptable. If the 'body' argument is an array, then it will automatically be escaped
 182       * using http_build_query().
 183       *
 184       * The only URI that are supported in the HTTP Transport implementation are the HTTP and HTTPS
 185       * protocols. HTTP and HTTPS are assumed so the server might not know how to handle the send
 186       * headers. Other protocols are unsupported and most likely will fail.
 187       *
 188       * The defaults are 'method', 'timeout', 'redirection', 'httpversion', 'blocking' and
 189       * 'user-agent'.
 190       *
 191       * Accepted 'method' values are 'GET', 'POST', and 'HEAD', some transports technically allow
 192       * others, but should not be assumed. The 'timeout' is used to sent how long the connection
 193       * should stay open before failing when no response. 'redirection' is used to track how many
 194       * redirects were taken and used to sent the amount for other transports, but not all transports
 195       * accept setting that value.
 196       *
 197       * The 'httpversion' option is used to sent the HTTP version and accepted values are '1.0', and
 198       * '1.1' and should be a string. Version 1.1 is not supported, because of chunk response. The
 199       * 'user-agent' option is the user-agent and is used to replace the default user-agent, which is
 200       * 'WordPress/WP_Version', where WP_Version is the value from $wp_version.
 201       *
 202       * 'blocking' is the default, which is used to tell the transport, whether it should halt PHP
 203       * while it performs the request or continue regardless. Actually, that isn't entirely correct.
 204       * Blocking mode really just means whether the fread should just pull what it can whenever it
 205       * gets bytes or if it should wait until it has enough in the buffer to read or finishes reading
 206       * the entire content. It doesn't actually always mean that PHP will continue going after making
 207       * the request.
 208       *
 209       * @access public
 210       * @since 2.7.0
 211       * @todo Refactor this code. The code in this method extends the scope of its original purpose
 212       *        and should be refactored to allow for cleaner abstraction and reduce duplication of the
 213       *        code. One suggestion is to create a class specifically for the arguments, however
 214       *        preliminary refactoring to this affect has affect more than just the scope of the
 215       *        arguments. Something to ponder at least.
 216       *
 217       * @param string $url URI resource.
 218       * @param str|array $args Optional. Override the defaults.
 219       * @return array containing 'headers', 'body', 'response', 'cookies'
 220       */
 221  	function request( $url, $args = array() ) {
 222          global $wp_version;
 223  
 224          $defaults = array(
 225              'method' => 'GET',
 226              'timeout' => apply_filters( 'http_request_timeout', 5),
 227              'redirection' => apply_filters( 'http_request_redirection_count', 5),
 228              'httpversion' => apply_filters( 'http_request_version', '1.0'),
 229              'user-agent' => apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' )  ),
 230              'blocking' => true,
 231              'headers' => array(),
 232              'cookies' => array(),
 233              'body' => null,
 234              'compress' => false,
 235              'decompress' => true,
 236              'sslverify' => true
 237          );
 238  
 239          $r = wp_parse_args( $args, $defaults );
 240          $r = apply_filters( 'http_request_args', $r, $url );
 241  
 242          // Allow plugins to short-circuit the request
 243          $pre = apply_filters( 'pre_http_request', false, $r, $url );
 244          if ( false !== $pre )
 245              return $pre;
 246  
 247          $arrURL = parse_url($url);
 248  
 249          if ( $this->block_request( $url ) )
 250              return new WP_Error('http_request_failed', __('User has blocked requests through HTTP.'));
 251  
 252          // Determine if this is a https call and pass that on to the transport functions
 253          // so that we can blacklist the transports that do not support ssl verification
 254          $r['ssl'] = $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl';
 255  
 256          // Determine if this request is to OUR install of WordPress
 257          $homeURL = parse_url(get_bloginfo('url'));
 258          $r['local'] = $homeURL['host'] == $arrURL['host'] || 'localhost' == $arrURL['host'];
 259          unset($homeURL);
 260  
 261          if ( is_null( $r['headers'] ) )
 262              $r['headers'] = array();
 263  
 264          if ( ! is_array($r['headers']) ) {
 265              $processedHeaders = WP_Http::processHeaders($r['headers']);
 266              $r['headers'] = $processedHeaders['headers'];
 267          }
 268  
 269          if ( isset($r['headers']['User-Agent']) ) {
 270              $r['user-agent'] = $r['headers']['User-Agent'];
 271              unset($r['headers']['User-Agent']);
 272          }
 273  
 274          if ( isset($r['headers']['user-agent']) ) {
 275              $r['user-agent'] = $r['headers']['user-agent'];
 276              unset($r['headers']['user-agent']);
 277          }
 278  
 279          // Construct Cookie: header if any cookies are set
 280          WP_Http::buildCookieHeader( $r );
 281  
 282          if ( WP_Http_Encoding::is_available() )
 283              $r['headers']['Accept-Encoding'] = WP_Http_Encoding::accept_encoding();
 284  
 285          if ( empty($r['body']) ) {
 286              // Some servers fail when sending content without the content-length header being set.
 287              // Also, to fix another bug, we only send when doing POST and PUT and the content-length
 288              // header isn't already set.
 289              if( ($r['method'] == 'POST' || $r['method'] == 'PUT') && ! isset($r['headers']['Content-Length']) )
 290                  $r['headers']['Content-Length'] = 0;
 291  
 292              // The method is ambiguous, because we aren't talking about HTTP methods, the "get" in
 293              // this case is simply that we aren't sending any bodies and to get the transports that
 294              // don't support sending bodies along with those which do.
 295              $transports = WP_Http::_getTransport($r);
 296          } else {
 297              if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) {
 298                  if ( ! version_compare(phpversion(), '5.1.2', '>=') )
 299                      $r['body'] = _http_build_query($r['body'], null, '&');
 300                  else
 301                      $r['body'] = http_build_query($r['body'], null, '&');
 302                  $r['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset');
 303                  $r['headers']['Content-Length'] = strlen($r['body']);
 304              }
 305  
 306              if ( ! isset( $r['headers']['Content-Length'] ) && ! isset( $r['headers']['content-length'] ) )
 307                  $r['headers']['Content-Length'] = strlen($r['body']);
 308  
 309              // The method is ambiguous, because we aren't talking about HTTP methods, the "post" in
 310              // this case is simply that we are sending HTTP body and to get the transports that do
 311              // support sending the body. Not all do, depending on the limitations of the PHP core
 312              // limitations.
 313              $transports = WP_Http::_postTransport($r);
 314          }
 315  
 316          do_action( 'http_api_debug', $transports, 'transports_list' );
 317  
 318          $response = array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
 319          foreach ( (array) $transports as $transport ) {
 320              $response = $transport->request($url, $r);
 321  
 322              do_action( 'http_api_debug', $response, 'response', get_class($transport) );
 323  
 324              if ( ! is_wp_error($response) )
 325                  return apply_filters( 'http_response', $response, $r, $url );
 326          }
 327  
 328          return $response;
 329      }
 330  
 331      /**
 332       * Uses the POST HTTP method.
 333       *
 334       * Used for sending data that is expected to be in the body.
 335       *
 336       * @access public
 337       * @since 2.7.0
 338       *
 339       * @param string $url URI resource.
 340       * @param str|array $args Optional. Override the defaults.
 341       * @return boolean
 342       */
 343  	function post($url, $args = array()) {
 344          $defaults = array('method' => 'POST');
 345          $r = wp_parse_args( $args, $defaults );
 346          return $this->request($url, $r);
 347      }
 348  
 349      /**
 350       * Uses the GET HTTP method.
 351       *
 352       * Used for sending data that is expected to be in the body.
 353       *
 354       * @access public
 355       * @since 2.7.0
 356       *
 357       * @param string $url URI resource.
 358       * @param str|array $args Optional. Override the defaults.
 359       * @return boolean
 360       */
 361  	function get($url, $args = array()) {
 362          $defaults = array('method' => 'GET');
 363          $r = wp_parse_args( $args, $defaults );
 364          return $this->request($url, $r);
 365      }
 366  
 367      /**
 368       * Uses the HEAD HTTP method.
 369       *
 370       * Used for sending data that is expected to be in the body.
 371       *
 372       * @access public
 373       * @since 2.7.0
 374       *
 375       * @param string $url URI resource.
 376       * @param str|array $args Optional. Override the defaults.
 377       * @return boolean
 378       */
 379  	function head($url, $args = array()) {
 380          $defaults = array('method' => 'HEAD');
 381          $r = wp_parse_args( $args, $defaults );
 382          return $this->request($url, $r);
 383      }
 384  
 385      /**
 386       * Parses the responses and splits the parts into headers and body.
 387       *
 388       * @access public
 389       * @static
 390       * @since 2.7.0
 391       *
 392       * @param string $strResponse The full response string
 393       * @return array Array with 'headers' and 'body' keys.
 394       */
 395  	function processResponse($strResponse) {
 396          list($theHeaders, $theBody) = explode("\r\n\r\n", $strResponse, 2);
 397          return array('headers' => $theHeaders, 'body' => $theBody);
 398      }
 399  
 400      /**
 401       * Transform header string into an array.
 402       *
 403       * If an array is given then it is assumed to be raw header data with numeric keys with the
 404       * headers as the values. No headers must be passed that were already processed.
 405       *
 406       * @access public
 407       * @static
 408       * @since 2.7.0
 409       *
 410       * @param string|array $headers
 411       * @return array Processed string headers. If duplicate headers are encountered,
 412       *                     Then a numbered array is returned as the value of that header-key.
 413       */
 414  	function processHeaders($headers) {
 415          // split headers, one per array element
 416          if ( is_string($headers) ) {
 417              // tolerate line terminator: CRLF = LF (RFC 2616 19.3)
 418              $headers = str_replace("\r\n", "\n", $headers);
 419              // unfold folded header fields. LWS = [CRLF] 1*( SP | HT ) <US-ASCII SP, space (32)>, <US-ASCII HT, horizontal-tab (9)> (RFC 2616 2.2)
 420              $headers = preg_replace('/\n[ \t]/', ' ', $headers);
 421              // create the headers array
 422              $headers = explode("\n", $headers);
 423          }
 424  
 425          $response = array('code' => 0, 'message' => '');
 426  
 427          $cookies = array();
 428          $newheaders = array();
 429          foreach ( $headers as $tempheader ) {
 430              if ( empty($tempheader) )
 431                  continue;
 432  
 433              if ( false === strpos($tempheader, ':') ) {
 434                  list( , $iResponseCode, $strResponseMsg) = explode(' ', $tempheader, 3);
 435                  $response['code'] = $iResponseCode;
 436                  $response['message'] = $strResponseMsg;
 437                  continue;
 438              }
 439  
 440              list($key, $value) = explode(':', $tempheader, 2);
 441  
 442              if ( !empty( $value ) ) {
 443                  $key = strtolower( $key );
 444                  if ( isset( $newheaders[$key] ) ) {
 445                      $newheaders[$key] = array( $newheaders[$key], trim( $value ) );
 446                  } else {
 447                      $newheaders[$key] = trim( $value );
 448                  }
 449                  if ( 'set-cookie' == strtolower( $key ) )
 450                      $cookies[] = new WP_Http_Cookie( $value );
 451              }
 452          }
 453  
 454          return array('response' => $response, 'headers' => $newheaders, 'cookies' => $cookies);
 455      }
 456  
 457      /**
 458       * Takes the arguments for a ::request() and checks for the cookie array.
 459       *
 460       * If it's found, then it's assumed to contain WP_Http_Cookie objects, which are each parsed
 461       * into strings and added to the Cookie: header (within the arguments array). Edits the array by
 462       * reference.
 463       *
 464       * @access public
 465       * @version 2.8.0
 466       * @static
 467       *
 468       * @param array $r Full array of args passed into ::request()
 469       */
 470  	function buildCookieHeader( &$r ) {
 471          if ( ! empty($r['cookies']) ) {
 472              $cookies_header = '';
 473              foreach ( (array) $r['cookies'] as $cookie ) {
 474                  $cookies_header .= $cookie->getHeaderValue() . '; ';
 475              }
 476              $cookies_header = substr( $cookies_header, 0, -2 );
 477              $r['headers']['cookie'] = $cookies_header;
 478          }
 479      }
 480  
 481      /**
 482       * Decodes chunk transfer-encoding, based off the HTTP 1.1 specification.
 483       *
 484       * Based off the HTTP http_encoding_dechunk function. Does not support UTF-8. Does not support
 485       * returning footer headers. Shouldn't be too difficult to support it though.
 486       *
 487       * @todo Add support for footer chunked headers.
 488       * @access public
 489       * @since 2.7.0
 490       * @static
 491       *
 492       * @param string $body Body content
 493       * @return string Chunked decoded body on success or raw body on failure.
 494       */
 495  	function chunkTransferDecode($body) {
 496          $body = str_replace(array("\r\n", "\r"), "\n", $body);
 497          // The body is not chunked encoding or is malformed.
 498          if ( ! preg_match( '/^[0-9a-f]+(\s|\n)+/mi', trim($body) ) )
 499              return $body;
 500  
 501          $parsedBody = '';
 502          //$parsedHeaders = array(); Unsupported
 503  
 504          while ( true ) {
 505              $hasChunk = (bool) preg_match( '/^([0-9a-f]+)(\s|\n)+/mi', $body, $match );
 506  
 507              if ( $hasChunk ) {
 508                  if ( empty( $match[1] ) )
 509                      return $body;
 510  
 511                  $length = hexdec( $match[1] );
 512                  $chunkLength = strlen( $match[0] );
 513  
 514                  $strBody = substr($body, $chunkLength, $length);
 515                  $parsedBody .= $strBody;
 516  
 517                  $body = ltrim(str_replace(array($match[0], $strBody), '', $body), "\n");
 518  
 519                  if ( "0" == trim($body) )
 520                      return $parsedBody; // Ignore footer headers.
 521              } else {
 522                  return $body;
 523              }
 524          }
 525      }
 526  
 527      /**
 528       * Block requests through the proxy.
 529       *
 530       * Those who are behind a proxy and want to prevent access to certain hosts may do so. This will
 531       * prevent plugins from working and core functionality, if you don't include api.wordpress.org.
 532       *
 533       * You block external URL requests by defining WP_HTTP_BLOCK_EXTERNAL in your wp-config.php file
 534       * and this will only allow localhost and your blog to make requests. The constant
 535       * WP_ACCESSIBLE_HOSTS will allow additional hosts to go through for requests. The format of the
 536       * WP_ACCESSIBLE_HOSTS constant is a comma separated list of hostnames to allow.
 537       *
 538       * @since 2.8.0
 539       * @link http://core.trac.wordpress.org/ticket/8927 Allow preventing external requests.
 540       *
 541       * @param string $uri URI of url.
 542       * @return bool True to block, false to allow.
 543       */
 544  	function block_request($uri) {
 545          // We don't need to block requests, because nothing is blocked.
 546          if ( ! defined('WP_HTTP_BLOCK_EXTERNAL') || ( defined('WP_HTTP_BLOCK_EXTERNAL') && WP_HTTP_BLOCK_EXTERNAL == false ) )
 547              return false;
 548  
 549          // parse_url() only handles http, https type URLs, and will emit E_WARNING on failure.
 550          // This will be displayed on blogs, which is not reasonable.
 551          $check = @parse_url($uri);
 552  
 553          /* Malformed URL, can not process, but this could mean ssl, so let through anyway.
 554           *
 555           * This isn't very security sound. There are instances where a hacker might attempt
 556           * to bypass the proxy and this check. However, the reason for this behavior is that
 557           * WordPress does not do any checking currently for non-proxy requests, so it is keeps with
 558           * the default unsecure nature of the HTTP request.
 559           */
 560          if ( $check === false )
 561              return false;
 562  
 563          $home = parse_url( get_option('siteurl') );
 564  
 565          // Don't block requests back to ourselves by default
 566          if ( $check['host'] == 'localhost' || $check['host'] == $home['host'] )
 567              return apply_filters('block_local_requests', false);
 568  
 569          if ( !defined('WP_ACCESSIBLE_HOSTS') )
 570              return true;
 571  
 572          static $accessible_hosts;
 573          if ( null == $accessible_hosts )
 574              $accessible_hosts = preg_split('|,\s*|', WP_ACCESSIBLE_HOSTS);
 575  
 576          return !in_array( $check['host'], $accessible_hosts ); //Inverse logic, If its in the array, then we can't access it.
 577      }
 578  }
 579  
 580  /**
 581   * HTTP request method uses fsockopen function to retrieve the url.
 582   *
 583   * This would be the preferred method, but the fsockopen implementation has the most overhead of all
 584   * the HTTP transport implementations.
 585   *
 586   * @package WordPress
 587   * @subpackage HTTP
 588   * @since 2.7.0
 589   */
 590  class WP_Http_Fsockopen {
 591      /**
 592       * Send a HTTP request to a URI using fsockopen().
 593       *
 594       * Does not support non-blocking mode.
 595       *
 596       * @see WP_Http::request For default options descriptions.
 597       *
 598       * @since 2.7
 599       * @access public
 600       * @param string $url URI resource.
 601       * @param str|array $args Optional. Override the defaults.
 602       * @return array 'headers', 'body', 'cookies' and 'response' keys.
 603       */
 604  	function request($url, $args = array()) {
 605          $defaults = array(
 606              'method' => 'GET', 'timeout' => 5,
 607              'redirection' => 5, 'httpversion' => '1.0',
 608              'blocking' => true,
 609              'headers' => array(), 'body' => null, 'cookies' => array()
 610          );
 611  
 612          $r = wp_parse_args( $args, $defaults );
 613  
 614          if ( isset($r['headers']['User-Agent']) ) {
 615              $r['user-agent'] = $r['headers']['User-Agent'];
 616              unset($r['headers']['User-Agent']);
 617          } else if( isset($r['headers']['user-agent']) ) {
 618              $r['user-agent'] = $r['headers']['user-agent'];
 619              unset($r['headers']['user-agent']);
 620          }
 621  
 622          // Construct Cookie: header if any cookies are set
 623          WP_Http::buildCookieHeader( $r );
 624  
 625          $iError = null; // Store error number
 626          $strError = null; // Store error string
 627  
 628          $arrURL = parse_url($url);
 629  
 630          $fsockopen_host = $arrURL['host'];
 631  
 632          $secure_transport = false;
 633  
 634          if ( ! isset( $arrURL['port'] ) ) {
 635              if ( ( $arrURL['scheme'] == 'ssl' || $arrURL['scheme'] == 'https' ) && extension_loaded('openssl') ) {
 636                  $fsockopen_host = "ssl://$fsockopen_host";
 637                  $arrURL['port'] = 443;
 638                  $secure_transport = true;
 639              } else {
 640                  $arrURL['port'] = 80;
 641              }
 642          }
 643  
 644          //fsockopen has issues with 'localhost' with IPv6 with certain versions of PHP, It attempts to connect to ::1,
 645          // which fails when the server is not setup for it. For compatibility, always connect to the IPv4 address.
 646          if ( 'localhost' == strtolower($fsockopen_host) )
 647              $fsockopen_host = '127.0.0.1';
 648  
 649          // There are issues with the HTTPS and SSL protocols that cause errors that can be safely
 650          // ignored and should be ignored.
 651          if ( true === $secure_transport )
 652              $error_reporting = error_reporting(0);
 653  
 654          $startDelay = time();
 655  
 656          $proxy = new WP_HTTP_Proxy();
 657  
 658          if ( !WP_DEBUG ) {
 659              if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) )
 660                  $handle = @fsockopen( $proxy->host(), $proxy->port(), $iError, $strError, $r['timeout'] );
 661              else
 662                  $handle = @fsockopen( $fsockopen_host, $arrURL['port'], $iError, $strError, $r['timeout'] );
 663          } else {
 664              if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) )
 665                  $handle = fsockopen( $proxy->host(), $proxy->port(), $iError, $strError, $r['timeout'] );
 666              else
 667                  $handle = fsockopen( $fsockopen_host, $arrURL['port'], $iError, $strError, $r['timeout'] );
 668          }
 669  
 670          $endDelay = time();
 671  
 672          // If the delay is greater than the timeout then fsockopen should't be used, because it will
 673          // cause a long delay.
 674          $elapseDelay = ($endDelay-$startDelay) > $r['timeout'];
 675          if ( true === $elapseDelay )
 676              add_option( 'disable_fsockopen', $endDelay, null, true );
 677  
 678          if ( false === $handle )
 679              return new WP_Error('http_request_failed', $iError . ': ' . $strError);
 680  
 681          $timeout = (int) floor( $r['timeout'] );
 682          $utimeout = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000;
 683          stream_set_timeout( $handle, $timeout, $utimeout );
 684  
 685          if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) //Some proxies require full URL in this field.
 686              $requestPath = $url;
 687          else
 688              $requestPath = $arrURL['path'] . ( isset($arrURL['query']) ? '?' . $arrURL['query'] : '' );
 689  
 690          if ( empty($requestPath) )
 691              $requestPath .= '/';
 692  
 693          $strHeaders = strtoupper($r['method']) . ' ' . $requestPath . ' HTTP/' . $r['httpversion'] . "\r\n";
 694  
 695          if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) )
 696              $strHeaders .= 'Host: ' . $arrURL['host'] . ':' . $arrURL['port'] . "\r\n";
 697          else
 698              $strHeaders .= 'Host: ' . $arrURL['host'] . "\r\n";
 699  
 700          if ( isset($r['user-agent']) )
 701              $strHeaders .= 'User-agent: ' . $r['user-agent'] . "\r\n";
 702  
 703          if ( is_array($r['headers']) ) {
 704              foreach ( (array) $r['headers'] as $header => $headerValue )
 705                  $strHeaders .= $header . ': ' . $headerValue . "\r\n";
 706          } else {
 707              $strHeaders .= $r['headers'];
 708          }
 709  
 710          if ( $proxy->use_authentication() )
 711              $strHeaders .= $proxy->authentication_header() . "\r\n";
 712  
 713          $strHeaders .= "\r\n";
 714  
 715          if ( ! is_null($r['body']) )
 716              $strHeaders .= $r['body'];
 717  
 718          fwrite($handle, $strHeaders);
 719  
 720          if ( ! $r['blocking'] ) {
 721              fclose($handle);
 722              return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
 723          }
 724  
 725          $strResponse = '';
 726          while ( ! feof($handle) )
 727              $strResponse .= fread($handle, 4096);
 728  
 729          fclose($handle);
 730  
 731          if ( true === $secure_transport )
 732              error_reporting($error_reporting);
 733  
 734          $process = WP_Http::processResponse($strResponse);
 735          $arrHeaders = WP_Http::processHeaders($process['headers']);
 736  
 737          // Is the response code within the 400 range?
 738          if ( (int) $arrHeaders['response']['code'] >= 400 && (int) $arrHeaders['response']['code'] < 500 )
 739              return new WP_Error('http_request_failed', $arrHeaders['response']['code'] . ': ' . $arrHeaders['response']['message']);
 740  
 741          // If location is found, then assume redirect and redirect to location.
 742          if ( isset($arrHeaders['headers']['location']) ) {
 743              if ( $r['redirection']-- > 0 ) {
 744                  return $this->request($arrHeaders['headers']['location'], $r);
 745              } else {
 746                  return new WP_Error('http_request_failed', __('Too many redirects.'));
 747              }
 748          }
 749  
 750          // If the body was chunk encoded, then decode it.
 751          if ( ! empty( $process['body'] ) && isset( $arrHeaders['headers']['transfer-encoding'] ) && 'chunked' == $arrHeaders['headers']['transfer-encoding'] )
 752              $process['body'] = WP_Http::chunkTransferDecode($process['body']);
 753  
 754          if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($arrHeaders['headers']) )
 755              $process['body'] = WP_Http_Encoding::decompress( $process['body'] );
 756  
 757          return array('headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies']);
 758      }
 759  
 760      /**
 761       * Whether this class can be used for retrieving an URL.
 762       *
 763       * @since 2.7.0
 764       * @static
 765       * @return boolean False means this class can not be used, true means it can.
 766       */
 767  	function test( $args = array() ) {
 768          if ( false !== ($option = get_option( 'disable_fsockopen' )) && time()-$option < 43200 ) // 12 hours
 769              return false;
 770  
 771          $is_ssl = isset($args['ssl']) && $args['ssl'];
 772  
 773          if ( ! $is_ssl && function_exists( 'fsockopen' ) )
 774              $use = true;
 775          elseif ( $is_ssl && extension_loaded('openssl') && function_exists( 'fsockopen' ) )
 776              $use = true;
 777          else
 778              $use = false;
 779  
 780          return apply_filters('use_fsockopen_transport', $use, $args);
 781      }
 782  }
 783  
 784  /**
 785   * HTTP request method uses fopen function to retrieve the url.
 786   *
 787   * Requires PHP version greater than 4.3.0 for stream support. Does not allow for $context support,
 788   * but should still be okay, to write the headers, before getting the response. Also requires that
 789   * 'allow_url_fopen' to be enabled.
 790   *
 791   * @package WordPress
 792   * @subpackage HTTP
 793   * @since 2.7.0
 794   */
 795  class WP_Http_Fopen {
 796      /**
 797       * Send a HTTP request to a URI using fopen().
 798       *
 799       * This transport does not support sending of headers and body, therefore should not be used in
 800       * the instances, where there is a body and headers.
 801       *
 802       * Notes: Does not support non-blocking mode. Ignores 'redirection' option.
 803       *
 804       * @see WP_Http::retrieve For default options descriptions.
 805       *
 806       * @access public
 807       * @since 2.7.0
 808       *
 809       * @param string $url URI resource.
 810       * @param str|array $args Optional. Override the defaults.
 811       * @return array 'headers', 'body', 'cookies' and 'response' keys.
 812       */
 813  	function request($url, $args = array()) {
 814          $defaults = array(
 815              'method' => 'GET', 'timeout' => 5,
 816              'redirection' => 5, 'httpversion' => '1.0',
 817              'blocking' => true,
 818              'headers' => array(), 'body' => null, 'cookies' => array()
 819          );
 820  
 821          $r = wp_parse_args( $args, $defaults );
 822  
 823          $arrURL = parse_url($url);
 824  
 825          if ( false === $arrURL )
 826              return new WP_Error('http_request_failed', sprintf(__('Malformed URL: %s'), $url));
 827  
 828          if ( 'http' != $arrURL['scheme'] && 'https' != $arrURL['scheme'] )
 829              $url = str_replace($arrURL['scheme'], 'http', $url);
 830  
 831          if ( !WP_DEBUG )
 832              $handle = @fopen($url, 'r');
 833          else
 834              $handle = fopen($url, 'r');
 835  
 836          if (! $handle)
 837              return new WP_Error('http_request_failed', sprintf(__('Could not open handle for fopen() to %s'), $url));
 838  
 839          $timeout = (int) floor( $r['timeout'] );
 840          $utimeout = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000;
 841          stream_set_timeout( $handle, $timeout, $utimeout );
 842  
 843          if ( ! $r['blocking'] ) {
 844              fclose($handle);
 845              return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
 846          }
 847  
 848          $strResponse = '';
 849          while ( ! feof($handle) )
 850              $strResponse .= fread($handle, 4096);
 851  
 852          if ( function_exists('stream_get_meta_data') ) {
 853              $meta = stream_get_meta_data($handle);
 854              $theHeaders = $meta['wrapper_data'];
 855              if ( isset( $meta['wrapper_data']['headers'] ) )
 856                  $theHeaders = $meta['wrapper_data']['headers'];
 857          } else {
 858              //$http_response_header is a PHP reserved variable which is set in the current-scope when using the HTTP Wrapper
 859              //see http://php.oregonstate.edu/manual/en/reserved.variables.httpresponseheader.php
 860              $theHeaders = $http_response_header;
 861          }
 862  
 863          fclose($handle);
 864  
 865          $processedHeaders = WP_Http::processHeaders($theHeaders);
 866  
 867          if ( ! empty( $strResponse ) && isset( $processedHeaders['headers']['transfer-encoding'] ) && 'chunked' == $processedHeaders['headers']['transfer-encoding'] )
 868              $strResponse = WP_Http::chunkTransferDecode($strResponse);
 869  
 870          if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($processedHeaders['headers']) )
 871              $strResponse = WP_Http_Encoding::decompress( $strResponse );
 872  
 873          return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies']);
 874      }
 875  
 876      /**
 877       * Whether this class can be used for retrieving an URL.
 878       *
 879       * @since 2.7.0
 880       * @static
 881       * @return boolean False means this class can not be used, true means it can.
 882       */
 883  	function test($args = array()) {
 884          if ( ! function_exists('fopen') || (function_exists('ini_get') && true != ini_get('allow_url_fopen')) )
 885              return false;
 886  
 887          $use = true;
 888  
 889          //PHP does not verify SSL certs, We can only make a request via this transports if SSL Verification is turned off.
 890          $is_ssl = isset($args['ssl']) && $args['ssl'];
 891          if ( $is_ssl ) {
 892              $is_local = isset($args['local']) && $args['local'];
 893              $ssl_verify = isset($args['sslverify']) && $args['sslverify'];
 894              if ( $is_local && true != apply_filters('https_local_ssl_verify', true) )
 895                  $use = true;
 896              elseif ( !$is_local && true != apply_filters('https_ssl_verify', true) )
 897                  $use = true;
 898              elseif ( !$ssl_verify )
 899                  $use = true;
 900              else
 901                  $use = false;
 902          }
 903  
 904          return apply_filters('use_fopen_transport', $use, $args);
 905      }
 906  }
 907  
 908  /**
 909   * HTTP request method uses Streams to retrieve the url.
 910   *
 911   * Requires PHP 5.0+ and uses fopen with stream context. Requires that 'allow_url_fopen' PHP setting
 912   * to be enabled.
 913   *
 914   * Second preferred method for getting the URL, for PHP 5.
 915   *
 916   * @package WordPress
 917   * @subpackage HTTP
 918   * @since 2.7.0
 919   */
 920  class WP_Http_Streams {
 921      /**
 922       * Send a HTTP request to a URI using streams with fopen().
 923       *
 924       * @access public
 925       * @since 2.7.0
 926       *
 927       * @param string $url
 928       * @param str|array $args Optional. Override the defaults.
 929       * @return array 'headers', 'body', 'cookies' and 'response' keys.
 930       */
 931  	function request($url, $args = array()) {
 932          $defaults = array(
 933              'method' => 'GET', 'timeout' => 5,
 934              'redirection' => 5, 'httpversion' => '1.0',
 935              'blocking' => true,
 936              'headers' => array(), 'body' => null, 'cookies' => array()
 937          );
 938  
 939          $r = wp_parse_args( $args, $defaults );
 940  
 941          if ( isset($r['headers']['User-Agent']) ) {
 942              $r['user-agent'] = $r['headers']['User-Agent'];
 943              unset($r['headers']['User-Agent']);
 944          } else if( isset($r['headers']['user-agent']) ) {
 945              $r['user-agent'] = $r['headers']['user-agent'];
 946              unset($r['headers']['user-agent']);
 947          }
 948  
 949          // Construct Cookie: header if any cookies are set
 950          WP_Http::buildCookieHeader( $r );
 951  
 952          $arrURL = parse_url($url);
 953  
 954          if ( false === $arrURL )
 955              return new WP_Error('http_request_failed', sprintf(__('Malformed URL: %s'), $url));
 956  
 957          if ( 'http' != $arrURL['scheme'] && 'https' != $arrURL['scheme'] )
 958              $url = preg_replace('|^' . preg_quote($arrURL['scheme'], '|') . '|', 'http', $url);
 959  
 960          // Convert Header array to string.
 961          $strHeaders = '';
 962          if ( is_array( $r['headers'] ) )
 963              foreach ( $r['headers'] as $name => $value )
 964                  $strHeaders .= "{$name}: $value\r\n";
 965          else if ( is_string( $r['headers'] ) )
 966              $strHeaders = $r['headers'];
 967  
 968          $is_local = isset($args['local']) && $args['local'];
 969          $ssl_verify = isset($args['sslverify']) && $args['sslverify'];
 970          if ( $is_local )
 971              $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify);
 972          elseif ( ! $is_local )
 973              $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify);
 974  
 975          $arrContext = array('http' =>
 976              array(
 977                  'method' => strtoupper($r['method']),
 978                  'user_agent' => $r['user-agent'],
 979                  'max_redirects' => $r['redirection'],
 980                  'protocol_version' => (float) $r['httpversion'],
 981                  'header' => $strHeaders,
 982                  'timeout' => $r['timeout'],
 983                  'ssl' => array(
 984                          'verify_peer' => $ssl_verify,
 985                          'verify_host' => $ssl_verify
 986                  )
 987              )
 988          );
 989  
 990          $proxy = new WP_HTTP_Proxy();
 991  
 992          if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
 993              $arrContext['http']['proxy'] = 'tcp://' . $proxy->host() . ':' . $proxy->port();
 994              $arrContext['http']['request_fulluri'] = true;
 995  
 996              // We only support Basic authentication so this will only work if that is what your proxy supports.
 997              if ( $proxy->use_authentication() )
 998                  $arrContext['http']['header'] .= $proxy->authentication_header() . "\r\n";
 999          }
1000  
1001          if ( ! is_null($r['body']) && ! empty($r['body'] ) )
1002              $arrContext['http']['content'] = $r['body'];
1003  
1004          $context = stream_context_create($arrContext);
1005  
1006          if ( !WP_DEBUG )
1007              $handle = @fopen($url, 'r', false, $context);
1008          else
1009              $handle = fopen($url, 'r', false, $context);
1010  
1011          if ( ! $handle)
1012              return new WP_Error('http_request_failed', sprintf(__('Could not open handle for fopen() to %s'), $url));
1013  
1014          $timeout = (int) floor( $r['timeout'] );
1015          $utimeout = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000;
1016          stream_set_timeout( $handle, $timeout, $utimeout );
1017  
1018          if ( ! $r['blocking'] ) {
1019              stream_set_blocking($handle, 0);
1020              fclose($handle);
1021              return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
1022          }
1023  
1024          $strResponse = stream_get_contents($handle);
1025          $meta = stream_get_meta_data($handle);
1026  
1027          fclose($handle);
1028  
1029          $processedHeaders = array();
1030          if ( isset( $meta['wrapper_data']['headers'] ) )
1031              $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']['headers']);
1032          else
1033              $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']);
1034  
1035          if ( ! empty( $strResponse ) && isset( $processedHeaders['headers']['transfer-encoding'] ) && 'chunked' == $processedHeaders['headers']['transfer-encoding'] )
1036              $strResponse = WP_Http::chunkTransferDecode($strResponse);
1037  
1038          if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($processedHeaders['headers']) )
1039              $strResponse = WP_Http_Encoding::decompress( $strResponse );
1040  
1041          return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies']);
1042      }
1043  
1044      /**
1045       * Whether this class can be used for retrieving an URL.
1046       *
1047       * @static
1048       * @access public
1049       * @since 2.7.0
1050       *
1051       * @return boolean False means this class can not be used, true means it can.
1052       */
1053  	function test($args = array()) {
1054          if ( ! function_exists('fopen') || (function_exists('ini_get') && true != ini_get('allow_url_fopen')) )
1055              return false;
1056  
1057          if ( version_compare(PHP_VERSION, '5.0', '<') )
1058              return false;
1059  
1060          //HTTPS via Proxy was added in 5.1.0
1061          $is_ssl = isset($args['ssl']) && $args['ssl'];
1062          if ( $is_ssl && version_compare(PHP_VERSION, '5.1.0', '<') ) {
1063              $proxy = new WP_HTTP_Proxy();
1064              /**
1065               * No URL check, as its not currently passed to the ::test() function
1066               * In the case where a Proxy is in use, Just bypass this transport for HTTPS.
1067               */
1068              if ( $proxy->is_enabled() )
1069                  return false;
1070          }
1071  
1072          return apply_filters('use_streams_transport', true, $args);
1073      }
1074  }
1075  
1076  /**
1077   * HTTP request method uses HTTP extension to retrieve the url.
1078   *
1079   * Requires the HTTP extension to be installed. This would be the preferred transport since it can
1080   * handle a lot of the problems that forces the others to use the HTTP version 1.0. Even if PHP 5.2+
1081   * is being used, it doesn't mean that the HTTP extension will be enabled.
1082   *
1083   * @package WordPress
1084   * @subpackage HTTP
1085   * @since 2.7.0
1086   */
1087  class WP_Http_ExtHTTP {
1088      /**
1089       * Send a HTTP request to a URI using HTTP extension.
1090       *
1091       * Does not support non-blocking.
1092       *
1093       * @access public
1094       * @since 2.7
1095       *
1096       * @param string $url
1097       * @param str|array $args Optional. Override the defaults.
1098       * @return array 'headers', 'body', 'cookies' and 'response' keys.
1099       */
1100  	function request($url, $args = array()) {
1101          $defaults = array(
1102              'method' => 'GET', 'timeout' => 5,
1103              'redirection' => 5, 'httpversion' => '1.0',
1104              'blocking' => true,
1105              'headers' => array(), 'body' => null, 'cookies' => array()
1106          );
1107  
1108          $r = wp_parse_args( $args, $defaults );
1109  
1110          if ( isset($r['headers']['User-Agent']) ) {
1111              $r['user-agent'] = $r['headers']['User-Agent'];
1112              unset($r['headers']['User-Agent']);
1113          } else if( isset($r['headers']['user-agent']) ) {
1114              $r['user-agent'] = $r['headers']['user-agent'];
1115              unset($r['headers']['user-agent']);
1116          }
1117  
1118          // Construct Cookie: header if any cookies are set
1119          WP_Http::buildCookieHeader( $r );
1120  
1121          switch ( $r['method'] ) {
1122              case 'POST':
1123                  $r['method'] = HTTP_METH_POST;
1124                  break;
1125              case 'HEAD':
1126                  $r['method'] = HTTP_METH_HEAD;
1127                  break;
1128              case 'PUT':
1129                  $r['method'] =  HTTP_METH_PUT;
1130                  break;
1131              case 'GET':
1132              default:
1133                  $r['method'] = HTTP_METH_GET;
1134          }
1135  
1136          $arrURL = parse_url($url);
1137  
1138          if ( 'http' != $arrURL['scheme'] || 'https' != $arrURL['scheme'] )
1139              $url = preg_replace('|^' . preg_quote($arrURL['scheme'], '|') . '|', 'http', $url);
1140  
1141          $is_local = isset($args['local']) && $args['local'];
1142          $ssl_verify = isset($args['sslverify']) && $args['sslverify'];
1143          if ( $is_local )
1144              $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify);
1145          elseif ( ! $is_local )
1146              $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify);
1147  
1148          $r['timeout'] = (int) ceil( $r['timeout'] );
1149  
1150          $options = array(
1151              'timeout' => $r['timeout'],
1152              'connecttimeout' => $r['timeout'],
1153              'redirect' => $r['redirection'],
1154              'useragent' => $r['user-agent'],
1155              'headers' => $r['headers'],
1156              'ssl' => array(
1157                  'verifypeer' => $ssl_verify,
1158                  'verifyhost' => $ssl_verify
1159              )
1160          );
1161  
1162          // The HTTP extensions offers really easy proxy support.
1163          $proxy = new WP_HTTP_Proxy();
1164  
1165          if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1166              $options['proxyhost'] = $proxy->host();
1167              $options['proxyport'] = $proxy->port();
1168              $options['proxytype'] = HTTP_PROXY_HTTP;
1169  
1170              if ( $proxy->use_authentication() ) {
1171                  $options['proxyauth'] = $proxy->authentication();
1172                  $options['proxyauthtype'] = HTTP_AUTH_BASIC;
1173              }
1174          }
1175  
1176          if ( !WP_DEBUG ) //Emits warning level notices for max redirects and timeouts
1177              $strResponse = @http_request($r['method'], $url, $r['body'], $options, $info);
1178          else
1179              $strResponse = http_request($r['method'], $url, $r['body'], $options, $info); //Emits warning level notices for max redirects and timeouts
1180  
1181          // Error may still be set, Response may return headers or partial document, and error
1182          // contains a reason the request was aborted, eg, timeout expired or max-redirects reached.
1183          if ( false === $strResponse || ! empty($info['error']) )
1184              return new WP_Error('http_request_failed', $info['response_code'] . ': ' . $info['error']);
1185  
1186          if ( ! $r['blocking'] )
1187              return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
1188  
1189          list($theHeaders, $theBody) = explode("\r\n\r\n", $strResponse, 2);
1190          $theHeaders = WP_Http::processHeaders($theHeaders);
1191  
1192          if ( ! empty( $theBody ) && isset( $theHeaders['headers']['transfer-encoding'] ) && 'chunked' == $theHeaders['headers']['transfer-encoding'] ) {
1193              if ( !WP_DEBUG )
1194                  $theBody = @http_chunked_decode($theBody);
1195              else
1196                  $theBody = http_chunked_decode($theBody);
1197          }
1198  
1199          if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($theHeaders['headers']) )
1200              $theBody = http_inflate( $theBody );
1201  
1202          $theResponse = array();
1203          $theResponse['code'] = $info['response_code'];
1204          $theResponse['message'] = get_status_header_desc($info['response_code']);
1205  
1206          return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $theResponse, 'cookies' => $theHeaders['cookies']);
1207      }
1208  
1209      /**
1210       * Whether this class can be used for retrieving an URL.
1211       *
1212       * @static
1213       * @since 2.7.0
1214       *
1215       * @return boolean False means this class can not be used, true means it can.
1216       */
1217  	function test($args = array()) {
1218          return apply_filters('use_http_extension_transport', function_exists('http_request'), $args );
1219      }
1220  }
1221  
1222  /**
1223   * HTTP request method uses Curl extension to retrieve the url.
1224   *
1225   * Requires the Curl extension to be installed.
1226   *
1227   * @package WordPress
1228   * @subpackage HTTP
1229   * @since 2.7
1230   */
1231  class WP_Http_Curl {
1232  
1233      /**
1234       * Send a HTTP request to a URI using cURL extension.
1235       *
1236       * @access public
1237       * @since 2.7.0
1238       *
1239       * @param string $url
1240       * @param str|array $args Optional. Override the defaults.
1241       * @return array 'headers', 'body', 'cookies' and 'response' keys.
1242       */
1243  	function request($url, $args = array()) {
1244          $defaults = array(
1245              'method' => 'GET', 'timeout' => 5,
1246              'redirection' => 5, 'httpversion' => '1.0',
1247              'blocking' => true,
1248              'headers' => array(), 'body' => null, 'cookies' => array()
1249          );
1250  
1251          $r = wp_parse_args( $args, $defaults );
1252  
1253          if ( isset($r['headers']['User-Agent']) ) {
1254              $r['user-agent'] = $r['headers']['User-Agent'];
1255              unset($r['headers']['User-Agent']);
1256          } else if( isset($r['headers']['user-agent']) ) {
1257              $r['user-agent'] = $r['headers']['user-agent'];
1258              unset($r['headers']['user-agent']);
1259          }
1260  
1261          // Construct Cookie: header if any cookies are set.
1262          WP_Http::buildCookieHeader( $r );
1263  
1264          $handle = curl_init();
1265  
1266          // cURL offers really easy proxy support.
1267          $proxy = new WP_HTTP_Proxy();
1268  
1269          if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1270  
1271              $isPHP5 = version_compare(PHP_VERSION, '5.0.0', '>=');
1272  
1273              if ( $isPHP5 ) {
1274                  curl_setopt( $handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
1275                  curl_setopt( $handle, CURLOPT_PROXY, $proxy->host() );
1276                  curl_setopt( $handle, CURLOPT_PROXYPORT, $proxy->port() );
1277              } else {
1278                  curl_setopt( $handle, CURLOPT_PROXY, $proxy->host() .':'. $proxy->port() );
1279              }
1280  
1281              if ( $proxy->use_authentication() ) {
1282                  if ( $isPHP5 )
1283                      curl_setopt( $handle, CURLOPT_PROXYAUTH, CURLAUTH_BASIC );
1284  
1285                  curl_setopt( $handle, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
1286              }
1287          }
1288  
1289          $is_local = isset($args['local']) && $args['local'];
1290          $ssl_verify = isset($args['sslverify']) && $args['sslverify'];
1291          if ( $is_local )
1292              $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify);
1293          elseif ( ! $is_local )
1294              $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify);
1295  
1296  
1297          // CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT expect integers.  Have to use ceil since
1298          // a value of 0 will allow an ulimited timeout.
1299          $timeout = (int) ceil( $r['timeout'] );
1300          curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, $timeout );
1301          curl_setopt( $handle, CURLOPT_TIMEOUT, $timeout );
1302  
1303          curl_setopt( $handle, CURLOPT_URL, $url);
1304          curl_setopt( $handle, CURLOPT_RETURNTRANSFER, true );
1305          curl_setopt( $handle, CURLOPT_SSL_VERIFYHOST, $ssl_verify );
1306          curl_setopt( $handle, CURLOPT_SSL_VERIFYPEER, $ssl_verify );
1307          curl_setopt( $handle, CURLOPT_USERAGENT, $r['user-agent'] );
1308          curl_setopt( $handle, CURLOPT_MAXREDIRS, $r['redirection'] );
1309  
1310          switch ( $r['method'] ) {
1311              case 'HEAD':
1312                  curl_setopt( $handle, CURLOPT_NOBODY, true );
1313                  break;
1314              case 'POST':
1315                  curl_setopt( $handle, CURLOPT_POST, true );
1316                  curl_setopt( $handle, CURLOPT_POSTFIELDS, $r['body'] );
1317                  break;
1318              case 'PUT':
1319                  curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, 'PUT' );
1320                  curl_setopt( $handle, CURLOPT_POSTFIELDS, $r['body'] );
1321                  break;
1322          }
1323  
1324          if ( true === $r['blocking'] )
1325              curl_setopt( $handle, CURLOPT_HEADER, true );
1326          else
1327              curl_setopt( $handle, CURLOPT_HEADER, false );
1328  
1329          // The option doesn't work with safe mode or when open_basedir is set.
1330          if ( !ini_get('safe_mode') && !ini_get('open_basedir') )
1331              curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, true );
1332  
1333          if ( !empty( $r['headers'] ) ) {
1334              // cURL expects full header strings in each element
1335              $headers = array();
1336              foreach ( $r['headers'] as $name => $value ) {
1337                  $headers[] = "{$name}: $value";
1338              }
1339              curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers );
1340          }
1341  
1342          if ( $r['httpversion'] == '1.0' )
1343              curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );
1344          else
1345              curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 );
1346  
1347          // Cookies are not handled by the HTTP API currently. Allow for plugin authors to handle it
1348          // themselves... Although, it is somewhat pointless without some reference.
1349          do_action_ref_array( 'http_api_curl', array(&$handle) );
1350  
1351          // We don't need to return the body, so don't. Just execute request and return.
1352          if ( ! $r['blocking'] ) {
1353              curl_exec( $handle );
1354              curl_close( $handle );
1355              return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
1356          }
1357  
1358          $theResponse = curl_exec( $handle );
1359  
1360          if ( !empty($theResponse) ) {
1361              $headerLength = curl_getinfo($handle, CURLINFO_HEADER_SIZE);
1362              $theHeaders = trim( substr($theResponse, 0, $headerLength) );
1363              $theBody = substr( $theResponse, $headerLength );
1364              if ( false !== strrpos($theHeaders, "\r\n\r\n") ) {
1365                  $headerParts = explode("\r\n\r\n", $theHeaders);
1366                  $theHeaders = $headerParts[ count($headerParts) -1 ];
1367              }
1368              $theHeaders = WP_Http::processHeaders($theHeaders);
1369          } else {
1370              if ( $curl_error = curl_error($handle) )
1371                  return new WP_Error('http_request_failed', $curl_error);
1372              if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array(301, 302) ) )
1373                  return new WP_Error('http_request_failed', __('Too many redirects.'));
1374  
1375              $theHeaders = array( 'headers' => array(), 'cookies' => array() );
1376              $theBody = '';
1377          }
1378  
1379          $response = array();
1380          $response['code'] = curl_getinfo( $handle, CURLINFO_HTTP_CODE );
1381          $response['message'] = get_status_header_desc($response['code']);
1382  
1383          curl_close( $handle );
1384  
1385          if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($theHeaders['headers']) )
1386              $theBody = WP_Http_Encoding::decompress( $theBody );
1387  
1388          return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies']);
1389      }
1390  
1391      /**
1392       * Whether this class can be used for retrieving an URL.
1393       *
1394       * @static
1395       * @since 2.7.0
1396       *
1397       * @return boolean False means this class can not be used, true means it can.
1398       */
1399  	function test($args = array()) {
1400          if ( function_exists('curl_init') && function_exists('curl_exec') )
1401              return apply_filters('use_curl_transport', true, $args);
1402  
1403          return false;
1404      }
1405  }
1406  
1407  /**
1408   * Adds Proxy support to the WordPress HTTP API.
1409   *
1410   * There are caveats to proxy support. It requires that defines be made in the wp-config.php file to
1411   * enable proxy support. There are also a few filters that plugins can hook into for some of the
1412   * constants.
1413   *
1414   * The constants are as follows:
1415   * <ol>
1416   * <li>WP_PROXY_HOST - Enable proxy support and host for connecting.</li>
1417   * <li>WP_PROXY_PORT - Proxy port for connection. No default, must be defined.</li>
1418   * <li>WP_PROXY_USERNAME - Proxy username, if it requires authentication.</li>
1419   * <li>WP_PROXY_PASSWORD - Proxy password, if it requires authentication.</li>
1420   * <li>WP_PROXY_BYPASS_HOSTS - Will prevent the hosts in this list from going through the proxy.
1421   * You do not need to have localhost and the blog host in this list, because they will not be passed
1422   * through the proxy. The list should be presented in a comma separated list</li>
1423   * </ol>
1424   *
1425   * An example can be as seen below.
1426   * <code>
1427   * define('WP_PROXY_HOST', '192.168.84.101');
1428   * define('WP_PROXY_PORT', '8080');
1429   * define('WP_PROXY_BYPASS_HOSTS', 'localhost, www.example.com');
1430   * </code>
1431   *
1432   * @link http://core.trac.wordpress.org/ticket/4011 Proxy support ticket in WordPress.
1433   * @since 2.8
1434   */
1435  class WP_HTTP_Proxy {
1436  
1437      /**
1438       * Whether proxy connection should be used.
1439       *
1440       * @since 2.8
1441       * @use WP_PROXY_HOST
1442       * @use WP_PROXY_PORT
1443       *
1444       * @return bool
1445       */
1446  	function is_enabled() {
1447          return defined('WP_PROXY_HOST') && defined('WP_PROXY_PORT');
1448      }
1449  
1450      /**
1451       * Whether authentication should be used.
1452       *
1453       * @since 2.8
1454       * @use WP_PROXY_USERNAME
1455       * @use WP_PROXY_PASSWORD
1456       *
1457       * @return bool
1458       */
1459  	function use_authentication() {
1460          return defined('WP_PROXY_USERNAME') && defined('WP_PROXY_PASSWORD');
1461      }
1462  
1463      /**
1464       * Retrieve the host for the proxy server.
1465       *
1466       * @since 2.8
1467       *
1468       * @return string
1469       */
1470  	function host() {
1471          if ( defined('WP_PROXY_HOST') )
1472              return WP_PROXY_HOST;
1473  
1474          return '';
1475      }
1476  
1477      /**
1478       * Retrieve the port for the proxy server.
1479       *
1480       * @since 2.8
1481       *
1482       * @return string
1483       */
1484  	function port() {
1485          if ( defined('WP_PROXY_PORT') )
1486              return WP_PROXY_PORT;
1487  
1488          return '';
1489      }
1490  
1491      /**
1492       * Retrieve the username for proxy authentication.
1493       *
1494       * @since 2.8
1495       *
1496       * @return string
1497       */
1498  	function username() {
1499          if ( defined('WP_PROXY_USERNAME') )
1500              return WP_PROXY_USERNAME;
1501  
1502          return '';
1503      }
1504  
1505      /**
1506       * Retrieve the password for proxy authentication.
1507       *
1508       * @since 2.8
1509       *
1510       * @return string
1511       */
1512  	function password() {
1513          if ( defined('WP_PROXY_PASSWORD') )
1514              return WP_PROXY_PASSWORD;
1515  
1516          return '';
1517      }
1518  
1519      /**
1520       * Retrieve authentication string for proxy authentication.
1521       *
1522       * @since 2.8
1523       *
1524       * @return string
1525       */
1526  	function authentication() {
1527          return $this->username() . ':' . $this->password();
1528      }
1529  
1530      /**
1531       * Retrieve header string for proxy authentication.
1532       *
1533       * @since 2.8
1534       *
1535       * @return string
1536       */
1537  	function authentication_header() {
1538          return 'Proxy-Authentication: Basic ' . base64_encode( $this->authentication() );
1539      }
1540  
1541      /**
1542       * Whether URL should be sent through the proxy server.
1543       *
1544       * We want to keep localhost and the blog URL from being sent through the proxy server, because
1545       * some proxies can not handle this. We also have the constant available for defining other
1546       * hosts that won't be sent through the proxy.
1547       *
1548       * @uses WP_PROXY_BYPASS_HOSTS
1549       * @since unknown
1550       *
1551       * @param string $uri URI to check.
1552       * @return bool True, to send through the proxy and false if, the proxy should not be used.
1553       */
1554  	function send_through_proxy( $uri ) {
1555          // parse_url() only handles http, https type URLs, and will emit E_WARNING on failure.
1556          // This will be displayed on blogs, which is not reasonable.
1557          $check = @parse_url($uri);
1558  
1559          // Malformed URL, can not process, but this could mean ssl, so let through anyway.
1560          if ( $check === false )
1561              return true;
1562  
1563          $home = parse_url( get_option('siteurl') );
1564  
1565          if ( $check['host'] == 'localhost' || $check['host'] == $home['host'] )
1566              return false;
1567  
1568          if ( !defined('WP_PROXY_BYPASS_HOSTS') )
1569              return true;
1570  
1571          static $bypass_hosts;
1572          if ( null == $bypass_hosts )
1573              $bypass_hosts = preg_split('|,\s*|', WP_PROXY_BYPASS_HOSTS);
1574  
1575          return !in_array( $check['host'], $bypass_hosts );
1576      }
1577  }
1578  /**
1579   * Internal representation of a single cookie.
1580   *
1581   * Returned cookies are represented using this class, and when cookies are set, if they are not
1582   * already a WP_Http_Cookie() object, then they are turned into one.
1583   *
1584   * @todo The WordPress convention is to use underscores instead of camelCase for function and method
1585   * names. Need to switch to use underscores instead for the methods.
1586   *
1587   * @package WordPress
1588   * @subpackage HTTP
1589   * @since 2.8.0
1590   * @author Beau Lebens
1591   */
1592  class WP_Http_Cookie {
1593  
1594      /**
1595       * Cookie name.
1596       *
1597       * @since 2.8.0
1598       * @var string
1599       */
1600      var $name;
1601  
1602      /**
1603       * Cookie value.
1604       *
1605       * @since 2.8.0
1606       * @var string
1607       */
1608      var $value;
1609  
1610      /**
1611       * When the cookie expires.
1612       *
1613       * @since 2.8.0
1614       * @var string
1615       */
1616      var $expires;
1617  
1618      /**
1619       * Cookie URL path.
1620       *
1621       * @since 2.8.0
1622       * @var string
1623       */
1624      var $path;
1625  
1626      /**
1627       * Cookie Domain.
1628       *
1629       * @since 2.8.0
1630       * @var string
1631       */
1632      var $domain;
1633  
1634      /**
1635       * PHP4 style Constructor - Calls PHP5 Style Constructor.
1636       *
1637       * @access public
1638       * @since 2.8.0
1639       * @param string|array $data Raw cookie data.
1640       */
1641  	function WP_Http_Cookie( $data ) {
1642          $this->__construct( $data );
1643      }
1644  
1645      /**
1646       * Sets up this cookie object.
1647       *
1648       * The parameter $data should be either an associative array containing the indices names below
1649       * or a header string detailing it.
1650       *
1651       * If it's an array, it should include the following elements:
1652       * <ol>
1653       * <li>Name</li>
1654       * <li>Value - should NOT be urlencoded already.</li>
1655       * <li>Expires - (optional) String or int (UNIX timestamp).</li>
1656       * <li>Path (optional)</li>
1657       * <li>Domain (optional)</li>
1658       * </ol>
1659       *
1660       * @access public
1661       * @since 2.8.0
1662       *
1663       * @param string|array $data Raw cookie data.
1664       */
1665  	function __construct( $data ) {
1666          if ( is_string( $data ) ) {
1667              // Assume it's a header string direct from a previous request
1668              $pairs = explode( ';', $data );
1669  
1670              // Special handling for first pair; name=value. Also be careful of "=" in value
1671              $name  = trim( substr( $pairs[0], 0, strpos( $pairs[0], '=' ) ) );
1672              $value = substr( $pairs[0], strpos( $pairs[0], '=' ) + 1 );
1673              $this->name  = $name;
1674              $this->value = urldecode( $value );
1675              array_shift( $pairs ); //Removes name=value from items.
1676  
1677              // Set everything else as a property
1678              foreach ( $pairs as $pair ) {
1679                  if ( empty($pair) ) //Handles the cookie ending in ; which results in a empty final pair
1680                      continue;
1681  
1682                  list( $key, $val ) = explode( '=', $pair );
1683                  $key = strtolower( trim( $key ) );
1684                  if ( 'expires' == $key )
1685                      $val = strtotime( $val );
1686                  $this->$key = $val;
1687              }
1688          } else {
1689              if ( !isset( $data['name'] ) )
1690                  return false;
1691  
1692              // Set properties based directly on parameters
1693              $this->name   = $data['name'];
1694              $this->value  = isset( $data['value'] ) ? $data['value'] : '';
1695              $this->path   = isset( $data['path'] ) ? $data['path'] : '';
1696              $this->domain = isset( $data['domain'] ) ? $data['domain'] : '';
1697  
1698              if ( isset( $data['expires'] ) )
1699                  $this->expires = is_int( $data['expires'] ) ? $data['expires'] : strtotime( $data['expires'] );
1700              else
1701                  $this->expires = null;
1702          }
1703      }
1704  
1705      /**
1706       * Confirms that it's OK to send this cookie to the URL checked against.
1707       *
1708       * Decision is based on RFC 2109/2965, so look there for details on validity.
1709       *
1710       * @access public
1711       * @since 2.8.0
1712       *
1713       * @param string $url URL you intend to send this cookie to
1714       * @return boolean TRUE if allowed, FALSE otherwise.
1715       */
1716  	function test( $url ) {
1717          // Expires - if expired then nothing else matters
1718          if ( time() > $this->expires )
1719              return false;
1720  
1721          // Get details on the URL we're thinking about sending to
1722          $url = parse_url( $url );
1723          $url['port'] = isset( $url['port'] ) ? $url['port'] : 80;
1724          $url['path'] = isset( $url['path'] ) ? $url['path'] : '/';
1725  
1726          // Values to use for comparison against the URL
1727          $path   = isset( $this->path )   ? $this->path   : '/';
1728          $port   = isset( $this->port )   ? $this->port   : 80;
1729          $domain = isset( $this->domain ) ? strtolower( $this->domain ) : strtolower( $url['host'] );
1730          if ( false === stripos( $domain, '.' ) )
1731              $domain .= '.local';
1732  
1733          // Host - very basic check that the request URL ends with the domain restriction (minus leading dot)
1734          $domain = substr( $domain, 0, 1 ) == '.' ? substr( $domain, 1 ) : $domain;
1735          if ( substr( $url['host'], -strlen( $domain ) ) != $domain )
1736              return false;
1737  
1738          // Port - supports "port-lists" in the format: "80,8000,8080"
1739          if ( !in_array( $url['port'], explode( ',', $port) ) )
1740              return false;
1741  
1742          // Path - request path must start with path restriction
1743          if ( substr( $url['path'], 0, strlen( $path ) ) != $path )
1744              return false;
1745  
1746          return true;
1747      }
1748  
1749      /**
1750       * Convert cookie name and value back to header string.
1751       *
1752       * @access public
1753       * @since 2.8.0
1754       *
1755       * @return string Header encoded cookie name and value.
1756       */
1757  	function getHeaderValue() {
1758          if ( empty( $this->name ) || empty( $this->value ) )
1759              return '';
1760  
1761          return $this->name . '=' . urlencode( $this->value );
1762      }
1763  
1764      /**
1765       * Retrieve cookie header for usage in the rest of the WordPress HTTP API.
1766       *
1767       * @access public
1768       * @since 2.8.0
1769       *
1770       * @return string
1771       */
1772  	function getFullHeader() {
1773          return 'Cookie: ' . $this->getHeaderValue();
1774      }
1775  }
1776  
1777  /**
1778   * Implementation for deflate and gzip transfer encodings.
1779   *
1780   * Includes RFC 1950, RFC 1951, and RFC 1952.
1781   *
1782   * @since 2.8
1783   * @package WordPress
1784   * @subpackage HTTP
1785   */
1786  class WP_Http_Encoding {
1787  
1788      /**
1789       * Compress raw string using the deflate format.
1790       *
1791       * Supports the RFC 1951 standard.
1792       *
1793       * @since 2.8
1794       *
1795       * @param string $raw String to compress.
1796       * @param int $level Optional, default is 9. Compression level, 9 is highest.
1797       * @param string $supports Optional, not used. When implemented it will choose the right compression based on what the server supports.
1798       * @return string|bool False on failure.
1799       */
1800  	function compress( $raw, $level = 9, $supports = null ) {
1801          return gzdeflate( $raw, $level );
1802      }
1803  
1804      /**
1805       * Decompression of deflated string.
1806       *
1807       * Will attempt to decompress using the RFC 1950 standard, and if that fails
1808       * then the RFC 1951 standard deflate will be attempted. Finally, the RFC
1809       * 1952 standard gzip decode will be attempted. If all fail, then the
1810       * original compressed string will be returned.
1811       *
1812       * @since 2.8
1813       *
1814       * @param string $compressed String to decompress.
1815       * @param int $length The optional length of the compressed data.
1816       * @return string|bool False on failure.
1817       */
1818  	function decompress( $compressed, $length = null ) {
1819          $decompressed = WP_Http_Encoding::compatible_gzinflate( $compressed );
1820  
1821          if ( false !== $decompressed )
1822              return $decompressed;
1823  
1824          $decompressed = gzuncompress( $compressed );
1825  
1826          if ( false !== $decompressed )
1827              return $decompressed;
1828  
1829          if ( function_exists('gzdecode') ) {
1830              $decompressed = gzdecode( $compressed );
1831  
1832              if ( false !== $decompressed )
1833                  return $decompressed;
1834          }
1835  
1836          return $compressed;
1837      }
1838  
1839      /**
1840       * Decompression of deflated string while staying compatible with the majority of servers.
1841       *
1842       * Certain Servers will return deflated data with headers which PHP's gziniflate()
1843       * function cannot handle out of the box. The following function lifted from
1844       * http://au2.php.net/manual/en/function.gzinflate.php#77336 will attempt to deflate
1845       * the various return forms used.
1846       *
1847       * @since 2.8.1
1848       * @link http://au2.php.net/manual/en/function.gzinflate.php#77336
1849       *
1850       * @param string $gzData String to decompress.
1851       * @return string|bool False on failure.
1852       */
1853  	function compatible_gzinflate($gzData) {
1854          if ( substr($gzData, 0, 3) == "\x1f\x8b\x08" ) {
1855              $i = 10;
1856              $flg = ord( substr($gzData, 3, 1) );
1857              if ( $flg > 0 ) {
1858                  if ( $flg & 4 ) {
1859                      list($xlen) = unpack('v', substr($gzData, $i, 2) );
1860                      $i = $i + 2 + $xlen;
1861                  }
1862                  if ( $flg & 8 )
1863                      $i = strpos($gzData, "\0", $i) + 1;
1864                  if ( $flg & 16 )
1865                      $i = strpos($gzData, "\0", $i) + 1;
1866                  if ( $flg & 2 )
1867                      $i = $i + 2;
1868              }
1869              return gzinflate( substr($gzData, $i, -8) );
1870          } else {
1871              return false;
1872          }
1873      }
1874  
1875      /**
1876       * What encoding types to accept and their priority values.
1877       *
1878       * @since 2.8
1879       *
1880       * @return string Types of encoding to accept.
1881       */
1882  	function accept_encoding() {
1883          $type = array();
1884          if ( function_exists( 'gzinflate' ) )
1885              $type[] = 'deflate;q=1.0';
1886  
1887          if ( function_exists( 'gzuncompress' ) )
1888              $type[] = 'compress;q=0.5';
1889  
1890          if ( function_exists( 'gzdecode' ) )
1891              $type[] = 'gzip;q=0.5';
1892  
1893          return implode(', ', $type);
1894      }
1895  
1896      /**
1897       * What enconding the content used when it was compressed to send in the headers.
1898       *
1899       * @since 2.8
1900       *
1901       * @return string Content-Encoding string to send in the header.
1902       */
1903  	function content_encoding() {
1904          return 'deflate';
1905      }
1906  
1907      /**
1908       * Whether the content be decoded based on the headers.
1909       *
1910       * @since 2.8
1911       *
1912       * @param array|string $headers All of the available headers.
1913       * @return bool
1914       */
1915  	function should_decode($headers) {
1916          if ( is_array( $headers ) ) {
1917              if ( array_key_exists('content-encoding', $headers) && ! empty( $headers['content-encoding'] ) )
1918                  return true;
1919          } else if( is_string( $headers ) ) {
1920              return ( stripos($headers, 'content-encoding:') !== false );
1921          }
1922  
1923          return false;
1924      }
1925  
1926      /**
1927       * Whether decompression and compression are supported by the PHP version.
1928       *
1929       * Each function is tested instead of checking for the zlib extension, to
1930       * ensure that the functions all exist in the PHP version and aren't
1931       * disabled.
1932       *
1933       * @since 2.8
1934       *
1935       * @return bool
1936       */
1937  	function is_available() {
1938          return ( function_exists('gzuncompress') || function_exists('gzdeflate') || function_exists('gzinflate') );
1939      }
1940  }
1941  
1942  /**
1943   * Returns the initialized WP_Http Object
1944   *
1945   * @since 2.7.0
1946   * @access private
1947   *
1948   * @return WP_Http HTTP Transport object.
1949   */
1950  function &_wp_http_get_object() {
1951      static $http;
1952  
1953      if ( is_null($http) )
1954          $http = new WP_Http();
1955  
1956      return $http;
1957  }
1958  
1959  /**
1960   * Retrieve the raw response from the HTTP request.
1961   *
1962   * The array structure is a little complex.
1963   *
1964   * <code>
1965   * $res = array( 'headers' => array(), 'response' => array('code' => int, 'message' => string) );
1966   * </code>
1967   *
1968   * All of the headers in $res['headers'] are with the name as the key and the
1969   * value as the value. So to get the User-Agent, you would do the following.
1970   *
1971   * <code>
1972   * $user_agent = $res['headers']['user-agent'];
1973   * </code>
1974   *
1975   * The body is the raw response content and can be retrieved from $res['body'].
1976   *
1977   * This function is called first to make the request and there are other API
1978   * functions to abstract out the above convoluted setup.
1979   *
1980   * @since 2.7.0
1981   *
1982   * @param string $url Site URL to retrieve.
1983   * @param array $args Optional. Override the defaults.
1984   * @return WP_Error|array The response or WP_Error on failure.
1985   */
1986  function wp_remote_request($url, $args = array()) {
1987      $objFetchSite = _wp_http_get_object();
1988      return $objFetchSite->request($url, $args);
1989  }
1990  
1991  /**
1992   * Retrieve the raw response from the HTTP request using the GET method.
1993   *
1994   * @see wp_remote_request() For more information on the response array format.
1995   *
1996   * @since 2.7.0
1997   *
1998   * @param string $url Site URL to retrieve.
1999   * @param array $args Optional. Override the defaults.
2000   * @return WP_Error|array The response or WP_Error on failure.
2001   */
2002  function wp_remote_get($url, $args = array()) {
2003      $objFetchSite = _wp_http_get_object();
2004      return $objFetchSite->get($url, $args);
2005  }
2006  
2007  /**
2008   * Retrieve the raw response from the HTTP request using the POST method.
2009   *
2010   * @see wp_remote_request() For more information on the response array format.
2011   *
2012   * @since 2.7.0
2013   *
2014   * @param string $url Site URL to retrieve.
2015   * @param array $args Optional. Override the defaults.
2016   * @return WP_Error|array The response or WP_Error on failure.
2017   */
2018  function wp_remote_post($url, $args = array()) {
2019      $objFetchSite = _wp_http_get_object();
2020      return $objFetchSite->post($url, $args);
2021  }
2022  
2023  /**
2024   * Retrieve the raw response from the HTTP request using the HEAD method.
2025   *
2026   * @see wp_remote_request() For more information on the response array format.
2027   *
2028   * @since 2.7.0
2029   *
2030   * @param string $url Site URL to retrieve.
2031   * @param array $args Optional. Override the defaults.
2032   * @return WP_Error|array The response or WP_Error on failure.
2033   */
2034  function wp_remote_head($url, $args = array()) {
2035      $objFetchSite = _wp_http_get_object();
2036      return $objFetchSite->head($url, $args);
2037  }
2038  
2039  /**
2040   * Retrieve only the headers from the raw response.
2041   *
2042   * @since 2.7.0
2043   *
2044   * @param array $response HTTP response.
2045   * @return array The headers of the response. Empty array if incorrect parameter given.
2046   */
2047  function wp_remote_retrieve_headers(&$response) {
2048      if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
2049          return array();
2050  
2051      return $response['headers'];
2052  }
2053  
2054  /**
2055   * Retrieve a single header by name from the raw response.
2056   *
2057   * @since 2.7.0
2058   *
2059   * @param array $response
2060   * @param string $header Header name to retrieve value from.
2061   * @return string The header value. Empty string on if incorrect parameter given, or if the header doesnt exist.
2062   */
2063  function wp_remote_retrieve_header(&$response, $header) {
2064      if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
2065          return '';
2066  
2067      if ( array_key_exists($header, $response['headers']) )
2068          return $response['headers'][$header];
2069  
2070      return '';
2071  }
2072  
2073  /**
2074   * Retrieve only the response code from the raw response.
2075   *
2076   * Will return an empty array if incorrect parameter value is given.
2077   *
2078   * @since 2.7.0
2079   *
2080   * @param array $response HTTP response.
2081   * @return string the response code. Empty string on incorrect parameter given.
2082   */
2083  function wp_remote_retrieve_response_code(&$response) {
2084      if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
2085          return '';
2086  
2087      return $response['response']['code'];
2088  }
2089  
2090  /**
2091   * Retrieve only the response message from the raw response.
2092   *
2093   * Will return an empty array if incorrect parameter value is given.
2094   *
2095   * @since 2.7.0
2096   *
2097   * @param array $response HTTP response.
2098   * @return string The response message. Empty string on incorrect parameter given.
2099   */
2100  function wp_remote_retrieve_response_message(&$response) {
2101      if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
2102          return '';
2103  
2104      return $response['response']['message'];
2105  }
2106  
2107  /**
2108   * Retrieve only the body from the raw response.
2109   *
2110   * @since 2.7.0
2111   *
2112   * @param array $response HTTP response.
2113   * @return string The body of the response. Empty string if no body or incorrect parameter given.
2114   */
2115  function wp_remote_retrieve_body(&$response) {
2116      if ( is_wp_error($response) || ! isset($response['body']) )
2117          return '';
2118  
2119      return $response['body'];
2120  }
2121  
2122  ?>


Generated: Fri Jan 8 00:19:48 2010 Cross-referenced by PHPXref 0.7