[ Index ]

PHP Cross Reference of BackPress

title

Body

[close]

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

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


Generated: Thu Dec 26 01:01:01 2024 Cross-referenced by PHPXref 0.7.1