/bp-forums/bbpress/bb-includes/backpress/class.wp-http.php

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