Changeset 8520
- Timestamp:
- 08/01/2008 06:44:40 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/wp-includes/http.php
r8519 r8520 1 1 <?php 2 2 /** 3 * Simple HTTP request fallback system 3 * Simple and uniform HTTP request API. 4 * 5 * Will eventually replace and standardize the WordPress HTTP requests made. 4 6 * 5 7 * @package WordPress … … 10 12 11 13 /** 12 * Abstract class for all of the fallback implementation 13 * classes. The implementation classes will extend this class 14 * to keep common API methods universal between different 15 * functionality. 14 * WordPress HTTP Class for managing HTTP Transports and making HTTP requests. 15 * 16 * This class is called for the functionality of making HTTP requests and should 17 * replace Snoopy functionality, eventually. There is no available functionality 18 * to add HTTP transport implementations, since most of the HTTP transports are 19 * added and available for use. 20 * 21 * The exception is that cURL is not available as a transport and lacking an 22 * implementation. It will be added later and should be a patch on the WordPress 23 * Trac. 24 * 25 * There are no properties, because none are needed and for performance reasons. 26 * Some of the functions are static and while they do have some overhead over 27 * functions in PHP4, the purpose is maintainability. When PHP5 is finally the 28 * requirement, it will be easy to add the static keyword to the code. It is not 29 * as easy to convert a function to a method after enough code uses the old way. 16 30 * 17 31 * @package WordPress … … 34 48 * PHP5 style Constructor - Setup available transport if not available. 35 49 * 50 * PHP4 does not have the 'self' keyword and since WordPress supports PHP4, 51 * the class needs to be used for the static call. 52 * 53 * The transport are setup to save time. This should only be called once, so 54 * the overhead should be fine. 55 * 36 56 * @since 2.7 37 57 * @return WP_Http … … 39 59 function __construct() { 40 60 WP_Http::_getTransport(); 61 WP_Http::_postTransport(); 41 62 } 42 63 … … 46 67 * Tests all of the objects and returns the object that passes. Also caches 47 68 * that object to be used later. 69 * 70 * The order for the GET/HEAD requests are Streams, HTTP Extension, Fopen, 71 * and finally Fsockopen. fsockopen() is used last, because it has the most 72 * overhead in its implementation. There isn't any real way around it, since 73 * redirects have to be supported, much the same way the other transports 74 * also handle redirects. 75 * 76 * There are currently issues with "localhost" not resolving correctly with 77 * DNS. This may cause an error "failed to open stream: A connection attempt 78 * failed because the connected party did not properly respond after a 79 * period of time, or established connection failed because connected host 80 * has failed to respond." 48 81 * 49 82 * @since 2.7 … … 76 109 * is used when there is a body. The plain Fopen Transport can not be used 77 110 * to send content, but the streams transport can. This is a limitation that 78 * is addressed here .111 * is addressed here, by just not including that transport. 79 112 * 80 113 * @since 2.7 … … 99 132 100 133 /** 101 * Retrieve the location and set the class properties after the site has been retrieved. 102 * 103 * @access public 104 * @since 2.7 105 * 106 * @param string $url 134 * Send a HTTP request to a URI. 135 * 136 * The only URI that are supported in the HTTP Transport implementation are 137 * the HTTP and HTTPS protocols. HTTP and HTTPS are assumed so the server 138 * might not know how to handle the send headers. Other protocols are 139 * unsupported and most likely will fail. 140 * 141 * The defaults are 'method', 'timeout', 'redirection', 'httpversion', 142 * 'blocking' and 'user-agent'. 143 * 144 * Accepted 'method' values are 'GET', 'POST', and 'HEAD', some transports 145 * technically allow others, but should not be assumed. The 'timeout' is 146 * used to sent how long the connection should stay open before failing when 147 * no response. 'redirection' is used to track how many redirects were taken 148 * and used to sent the amount for other transports, but not all transports 149 * accept setting that value. 150 * 151 * The 'httpversion' option is used to sent the HTTP version and accepted 152 * values are '1.0', and '1.1' and should be a string. Version 1.1 is not 153 * supported, because of chunk response. The 'user-agent' option is the 154 * user-agent and is used to replace the default user-agent, which is 155 * 'WordPress/WP_Version', where WP_Version is the value from $wp_version. 156 * 157 * 'blocking' is the default, which is used to tell the transport, whether 158 * it should halt PHP while it performs the request or continue regardless. 159 * Actually, that isn't entirely correct. Blocking mode really just means 160 * whether the fread should just pull what it can whenever it gets bytes or 161 * if it should wait until it has enough in the buffer to read or finishes 162 * reading the entire content. It doesn't actually always mean that PHP will 163 * continue going after making the request. 164 * 165 * @access public 166 * @since 2.7 167 * 168 * @param string $url URI resource. 169 * @param str|array $args Optional. Override the defaults. 107 170 * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. 108 171 * @param string $body Optional. The body that should be sent. Expected to be already processed. 109 * @param str|array $type Optional. Should be an already processed array with HTTP arguments.110 172 * @return boolean 111 173 */ … … 115 177 $defaults = array( 116 178 'method' => 'GET', 'timeout' => 3, 117 'redirection' => 5, 'redirected' => false, 118 'httpversion' => '1.0', 'blocking' => true 179 'redirection' => 5, 'httpversion' => '1.0', 180 'user-agent' => apply_filters('http_headers_useragent', 'WordPress/' . $wp_version ), 181 'blocking' => true 119 182 ); 120 183 … … 129 192 130 193 if ( ! isset($headers['user-agent']) || ! isset($headers['User-Agent']) ) 131 $headers['user-agent'] = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version );132 133 if ( is_null($body) )194 $headers['user-agent'] = $r['user-agent']; 195 196 if ( is_null($body) || count($headers) > 1 ) 134 197 $transport = WP_Http::_getTransport(); 135 198 else … … 147 210 * @since 2.7 148 211 * 149 * @param string $url The location of the site and page to retrieve. 212 * @param string $url URI resource. 213 * @param str|array $args Optional. Override the defaults. 150 214 * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. 151 215 * @param string $body Optional. The body that should be sent. Expected to be already processed. … … 166 230 * @since 2.7 167 231 * 232 * @param string $url URI resource. 233 * @param str|array $args Optional. Override the defaults. 168 234 * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. 169 235 * @param string $body Optional. The body that should be sent. Expected to be already processed. … … 184 250 * @since 2.7 185 251 * 252 * @param string $url URI resource. 253 * @param str|array $args Optional. Override the defaults. 186 254 * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. 187 255 * @param string $body Optional. The body that should be sent. Expected to be already processed. … … 228 296 * Whether the headers returned a redirect location. 229 297 * 298 * Actually just checks whether the location header exists. 299 * 230 300 * @access public 231 301 * @static … … 244 314 * Transform header string into an array. 245 315 * 246 * Will overwrite the last header value, if it is not empty. 316 * If an array is given, then it will be immediately passed through with no 317 * changes. This is to prevent overhead in processing headers that don't 318 * need to be processed. That and it is unknown what kind of effect 319 * processing the array will have since there is no checking done on whether 320 * ':' does not exist within the array string. 321 * 322 * Checking could be added, but it is easier and faster to just passed the 323 * array through and assume that it has already been processed. 247 324 * 248 325 * @access public … … 251 328 * 252 329 * @param string|array $headers 253 * @return array 330 * @return array Processed string headers 254 331 */ 255 332 function processHeaders($headers) { … … 257 334 return $headers; 258 335 259 $headers = explode("\n", str_replace(array("\r "), '', $headers) );336 $headers = explode("\n", str_replace(array("\r\n", "\r"), "\n", $headers) ); 260 337 261 338 $response = array('code' => 0, 'message' => ''); … … 286 363 * HTTP request method uses fsockopen function to retrieve the url. 287 364 * 288 * Preferred method since it works with all WordPress supported PHP versions. 365 * This would be the preferred method, but the fsockopen implementation has the 366 * most overhead of all the HTTP transport implementations. 289 367 * 290 368 * @package WordPress … … 294 372 class WP_Http_Fsockopen { 295 373 /** 296 * Retrieve the location and set the class properties after the site has been retrieved. 297 * 298 * @since 2.7 299 * @access public 300 * @param string $url 374 * Send a HTTP request to a URI using fsockopen(). 375 * 376 * Does not support non-blocking mode. 377 * 378 * @see WP_Http::retrieve For default options descriptions. 379 * 380 * @since 2.7 381 * @access public 382 * @param string $url URI resource. 383 * @param str|array $args Optional. Override the defaults. 301 384 * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. 302 385 * @param string $body Optional. The body that should be sent. Expected to be already processed. 303 * @param str|array $type Optional. Should be an already processed array with HTTP arguments. 304 * @return boolean 386 * @return array 'headers', 'body', and 'response' keys. 305 387 */ 306 388 function request($url, $args = array(), $headers = null, $body = null) { … … 323 405 if ( ($arrURL['scheme'] == 'ssl' || $arrURL['scheme'] == 'https') && extension_loaded('openssl') ) { 324 406 $arrURL['host'] = 'ssl://' . $arrURL['host']; 325 $arrURL['port'] = apply_filters('http_request_ default_port', 443);407 $arrURL['port'] = apply_filters('http_request_port', 443); 326 408 $secure_transport = true; 327 409 } else { … … 332 414 } 333 415 416 // There are issues with the HTTPS and SSL protocols that cause errors 417 // that can be safely ignored and should be ignored. 334 418 if ( true === $secure_transport ) 335 419 $error_reporting = error_reporting(0); … … 361 445 fwrite($handle, $strHeaders); 362 446 363 if ( ! $r['blocking'] ) 364 return array( 'headers' => array(), 'body' => '', 'response' => array() ); 447 if ( ! $r['blocking'] ) { 448 fclose($handle); 449 return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 450 } 365 451 366 452 $strResponse = ''; … … 411 497 * getting the response. Also requires that 'allow_url_fopen' to be enabled. 412 498 * 413 * Second preferred method for handling the retrieving the url for PHP 4.3+.414 *415 499 * @package WordPress 416 500 * @subpackage HTTP … … 419 503 class WP_Http_Fopen { 420 504 /** 421 * Retrieve the location and set the class properties after the site has been retrieved. 422 * 423 * @access public 424 * @since 2.7 425 * 426 * @param string $url 505 * Send a HTTP request to a URI using fopen(). 506 * 507 * This transport does not support sending of headers and body, therefore 508 * should not be used in the instances, where there is a body and headers. 509 * 510 * Notes: Does not support non-blocking mode. Ignores 'redirection' option. 511 * 512 * @see WP_Http::retrieve For default options descriptions. 513 * 514 * @access public 515 * @since 2.7 516 * 517 * @param string $url URI resource. 518 * @param str|array $args Optional. Override the defaults. 427 519 * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. 428 520 * @param string $body Optional. The body that should be sent. Expected to be already processed. 429 * @param str|array $type Optional. Should be an already processed array with HTTP arguments. 430 * @return boolean 521 * @return array 'headers', 'body', and 'response' keys. 431 522 */ 432 523 function request($url, $args = array(), $headers = null, $body = null) { … … 454 545 stream_set_timeout($handle, apply_filters('http_request_timeout', $r['timeout']) ); 455 546 456 if ( ! $r['blocking'] ) 457 return array( 'headers' => array(), 'body' => '', 'response' => array() ); 547 if ( ! $r['blocking'] ) { 548 fclose($handle); 549 return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 550 } 458 551 459 552 $strResponse = ''; 460 553 while ( ! feof($handle) ) 461 554 $strResponse .= fread($handle, 4096); 555 556 fclose($handle); 462 557 463 558 $theHeaders = ''; … … 468 563 $theHeaders = $http_response_header; 469 564 } 470 fclose($handle);471 472 565 $processedHeaders = WP_Http::processHeaders($theHeaders); 566 473 567 return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']); 474 568 } … … 502 596 class WP_Http_Streams { 503 597 /** 504 * Retrieve the location and set the class properties after the site has been retrieved.598 * Send a HTTP request to a URI using streams with fopen(). 505 599 * 506 600 * @access public … … 511 605 * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. 512 606 * @param string $body Optional. The body that should be sent. Expected to be already processed. 513 * @return boolean607 * @return array 'headers', 'body', and 'response' keys. 514 608 */ 515 609 function request($url, $args = array(), $headers = null, $body = null) { … … 549 643 return new WP_Error('http_request_failed', sprintf(__('Could not open handle for fopen() to %s'), $url)); 550 644 551 if ( ! $r['blocking'] ) 552 return array( 'headers' => array(), 'body' => '', 'response' => array() ); 645 if ( ! $r['blocking'] ) { 646 fclose($handle); 647 return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 648 } 553 649 554 650 $strResponse = stream_get_contents($handle); 555 651 $meta = stream_get_meta_data($handle); 652 $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']); 556 653 557 654 fclose($handle); 558 655 559 $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']);560 656 return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']); 561 657 } … … 584 680 * HTTP request method uses HTTP extension to retrieve the url. 585 681 * 586 * Requires the HTTP extension to be installed. 587 * 588 * Last ditch effort to retrieve the URL before complete failure.589 * Does not support non-blocking requests.682 * Requires the HTTP extension to be installed. This would be the preferred 683 * transport since it can handle a lot of the problems that forces the others to 684 * use the HTTP version 1.0. Even if PHP 5.2+ is being used, it doesn't mean 685 * that the HTTP extension will be enabled. 590 686 * 591 687 * @package WordPress … … 595 691 class WP_Http_ExtHTTP { 596 692 /** 597 * Retrieve the location and set the class properties after the site has been retrieved. 693 * Send a HTTP request to a URI using HTTP extension. 694 * 695 * Does not support non-blocking. 598 696 * 599 697 * @access public … … 604 702 * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. 605 703 * @param string $body Optional. The body that should be sent. Expected to be already processed. 606 * @return boolean704 * @return array 'headers', 'body', and 'response' keys. 607 705 */ 608 706 function request($url, $args = array(), $headers = null, $body = null) { … … 612 710 'method' => 'GET', 'timeout' => 3, 613 711 'redirection' => 5, 'httpversion' => '1.0', 614 'blocking' => true , 'user_agent' => apply_filters('http_headers_useragent', 'WordPress/' . $wp_version)712 'blocking' => true 615 713 ); 616 714 617 715 $r = wp_parse_args( $args, $defaults ); 618 716 619 if ( isset($headers['User-Agent']) ) 717 if ( isset($headers['User-Agent']) ) { 718 $r['user-agent'] = $headers['User-Agent']; 620 719 unset($headers['User-Agent']); 720 } else if( isset($headers['user-agent']) ) { 721 $r['user-agent'] = $headers['user-agent']; 722 unset($headers['user-agent']); 723 } else { 724 $r['user-agent'] = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version ); 725 } 621 726 622 727 switch ( $r['method'] ) { … … 640 745 641 746 $options = array( 642 'timeout' => $ this->timeout,643 'connecttimeout' => apply_filters('http_request_stream_timeout', $this->timeout),644 'redirect' => apply_filters('http_request_redirect', 3),747 'timeout' => $r['timeout'], 748 'connecttimeout' => $r['timeout'], 749 'redirect' => $r['redirection'], 645 750 'useragent' => $r['user_agent'], 646 751 'headers' => $headers, … … 652 757 return new WP_Error('http_request_failed', $info['response_code'] . ': ' . $info['error']); 653 758 759 if ( ! $r['blocking'] ) 760 return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 761 654 762 list($theHeaders, $theBody) = explode("\r\n\r\n", $strResponse, 2); 655 763 $theHeaders = WP_Http::processHeaders($theHeaders); … … 672 780 function test() { 673 781 if ( function_exists('http_request') ) 782 return true; 783 784 return false; 785 } 786 } 787 788 /** 789 * HTTP request method uses Curl extension to retrieve the url. 790 * 791 * Requires the Curl extension to be installed. 792 * 793 * @package WordPress 794 * @subpackage HTTP 795 * @since 2.7 796 */ 797 class WP_Http_Curl { 798 /** 799 * Send a HTTP request to a URI using cURL extension. 800 * 801 * @access public 802 * @since 2.7 803 * 804 * @param string $url 805 * @param str|array $args Optional. Override the defaults. 806 * @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized. 807 * @param string $body Optional. The body that should be sent. Expected to be already processed. 808 * @return array 'headers', 'body', and 'response' keys. 809 */ 810 function request($url, $args = array(), $headers = null, $body = null) { 811 global $wp_version; 812 813 $defaults = array( 814 'method' => 'GET', 'timeout' => 3, 815 'redirection' => 5, 'httpversion' => '1.0', 816 'blocking' => true 817 ); 818 819 $r = wp_parse_args( $args, $defaults ); 820 821 if ( isset($headers['User-Agent']) ) { 822 $r['user-agent'] = $headers['User-Agent']; 823 unset($headers['User-Agent']); 824 } else if( isset($headers['user-agent']) ) { 825 $r['user-agent'] = $headers['user-agent']; 826 unset($headers['user-agent']); 827 } else { 828 $r['user-agent'] = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version ); 829 } 830 831 $handle = curl_init(); 832 curl_setopt( $handle, CURLOPT_URL, $url); 833 834 if ( true === $r['blocking'] ) { 835 curl_setopt( $handle, CURLOPT_HEADER, true ); 836 } else { 837 curl_setopt( $handle, CURLOPT_HEADER, false ); 838 curl_setopt( $handle, CURLOPT_NOBODY, true ); 839 } 840 841 curl_setopt( $handle, CURLOPT_RETURNTRANSFER, 1 ); 842 curl_setopt( $handle, CURLOPT_USERAGENT, $r['user-agent'] ); 843 curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, 1 ); 844 curl_setopt( $handle, CURLOPT_TIMEOUT, $r['timeout'] ); 845 curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, true ); 846 curl_setopt( $handle, CURLOPT_MAXREDIRS, $r['redirection'] ); 847 848 if( ! is_null($headers) ) 849 curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers ); 850 851 if ( $r['httpversion'] == '1.0' ) 852 curl_setopt( $headle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 ); 853 else 854 curl_setopt( $headle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 ); 855 856 if ( ! $r['blocking'] ) { 857 curl_close( $handle ); 858 return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 859 } 860 861 $theResponse = curl_exec( $handle ); 862 863 list($theHeaders, $theBody) = explode("\r\n\r\n", $strResponse, 2); 864 $theHeaders = WP_Http::processHeaders($theHeaders); 865 866 $response = array(); 867 $response['code'] = curl_getinfo( $handle, CURLINFO_HTTP_CODE ); 868 $response['message'] = get_status_header_desc($response['code']); 869 870 curl_close( $handle ); 871 872 return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response); 873 } 874 875 /** 876 * Whether this class can be used for retrieving an URL. 877 * 878 * @static 879 * @since 2.7 880 * 881 * @return boolean False means this class can not be used, true means it can. 882 */ 883 function test() { 884 if ( function_exists('curl_init') ) 674 885 return true; 675 886
Note: See TracChangeset
for help on using the changeset viewer.