PageRenderTime 35ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-includes/http.php

https://gitlab.com/Gashler/dp
PHP | 519 lines | 185 code | 54 blank | 280 comment | 63 complexity | dfc5c8781b9e109125f0dca520de0a46 MD5 | raw file
  1. <?php
  2. /**
  3. * Simple and uniform HTTP request API.
  4. *
  5. * Will eventually replace and standardize the WordPress HTTP requests made.
  6. *
  7. * @link http://trac.wordpress.org/ticket/4779 HTTP API Proposal
  8. *
  9. * @package WordPress
  10. * @subpackage HTTP
  11. * @since 2.7.0
  12. */
  13. /**
  14. * Returns the initialized WP_Http Object
  15. *
  16. * @since 2.7.0
  17. * @access private
  18. *
  19. * @return WP_Http HTTP Transport object.
  20. */
  21. function _wp_http_get_object() {
  22. static $http;
  23. if ( is_null($http) )
  24. $http = new WP_Http();
  25. return $http;
  26. }
  27. /**
  28. * Retrieve the raw response from a safe HTTP request.
  29. *
  30. * This function is ideal when the HTTP request is being made to an arbitrary
  31. * URL. The URL is validated to avoid redirection and request forgery attacks.
  32. *
  33. * @see wp_remote_request() For more information on the response array format
  34. * and default arguments.
  35. *
  36. * @since 3.6.0
  37. *
  38. * @param string $url Site URL to retrieve.
  39. * @param array $args Optional. Override the defaults.
  40. * @return WP_Error|array The response or WP_Error on failure.
  41. */
  42. function wp_safe_remote_request( $url, $args = array() ) {
  43. $args['reject_unsafe_urls'] = true;
  44. $http = _wp_http_get_object();
  45. return $http->request( $url, $args );
  46. }
  47. /**
  48. * Retrieve the raw response from a safe HTTP request using the GET method.
  49. *
  50. * This function is ideal when the HTTP request is being made to an arbitrary
  51. * URL. The URL is validated to avoid redirection and request forgery attacks.
  52. *
  53. * @see wp_remote_request() For more information on the response array format
  54. * and default arguments.
  55. *
  56. * @since 3.6.0
  57. *
  58. * @param string $url Site URL to retrieve.
  59. * @param array $args Optional. Override the defaults.
  60. * @return WP_Error|array The response or WP_Error on failure.
  61. */
  62. function wp_safe_remote_get( $url, $args = array() ) {
  63. $args['reject_unsafe_urls'] = true;
  64. $http = _wp_http_get_object();
  65. return $http->get( $url, $args );
  66. }
  67. /**
  68. * Retrieve the raw response from a safe HTTP request using the POST method.
  69. *
  70. * This function is ideal when the HTTP request is being made to an arbitrary
  71. * URL. The URL is validated to avoid redirection and request forgery attacks.
  72. *
  73. * @see wp_remote_request() For more information on the response array format
  74. * and default arguments.
  75. *
  76. * @since 3.6.0
  77. *
  78. * @param string $url Site URL to retrieve.
  79. * @param array $args Optional. Override the defaults.
  80. * @return WP_Error|array The response or WP_Error on failure.
  81. */
  82. function wp_safe_remote_post( $url, $args = array() ) {
  83. $args['reject_unsafe_urls'] = true;
  84. $http = _wp_http_get_object();
  85. return $http->post( $url, $args );
  86. }
  87. /**
  88. * Retrieve the raw response from a safe HTTP request using the HEAD method.
  89. *
  90. * This function is ideal when the HTTP request is being made to an arbitrary
  91. * URL. The URL is validated to avoid redirection and request forgery attacks.
  92. *
  93. * @see wp_remote_request() For more information on the response array format
  94. * and default arguments.
  95. *
  96. * @since 3.6.0
  97. *
  98. * @param string $url Site URL to retrieve.
  99. * @param array $args Optional. Override the defaults.
  100. * @return WP_Error|array The response or WP_Error on failure.
  101. */
  102. function wp_safe_remote_head( $url, $args = array() ) {
  103. $args['reject_unsafe_urls'] = true;
  104. $http = _wp_http_get_object();
  105. return $http->head( $url, $args );
  106. }
  107. /**
  108. * Retrieve the raw response from the HTTP request.
  109. *
  110. * The array structure is a little complex.
  111. *
  112. * <code>
  113. * $res = array( 'headers' => array(), 'response' => array('code' => int, 'message' => string) );
  114. * </code>
  115. *
  116. * All of the headers in $res['headers'] are with the name as the key and the
  117. * value as the value. So to get the User-Agent, you would do the following.
  118. *
  119. * <code>
  120. * $user_agent = $res['headers']['user-agent'];
  121. * </code>
  122. *
  123. * The body is the raw response content and can be retrieved from $res['body'].
  124. *
  125. * This function is called first to make the request and there are other API
  126. * functions to abstract out the above convoluted setup.
  127. *
  128. * List of default arguments:
  129. * 'method' => 'GET'
  130. * - Default 'GET' for wp_remote_get()
  131. * - Default 'POST' for wp_remote_post()
  132. * - Default 'HEAD' for wp_remote_head()
  133. * 'timeout' => 5
  134. * 'redirection' => 5
  135. * 'httpversion' => '1.0'
  136. * 'user-agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' )
  137. * 'blocking' => true
  138. * 'headers' => array()
  139. * 'cookies' => array()
  140. * 'body' => null
  141. * 'compress' => false,
  142. * 'decompress' => true,
  143. * 'sslverify' => true,
  144. * 'stream' => false,
  145. * 'filename' => null
  146. *
  147. * @since 2.7.0
  148. *
  149. * @param string $url Site URL to retrieve.
  150. * @param array $args Optional. Override the defaults.
  151. * @return WP_Error|array The response or WP_Error on failure.
  152. */
  153. function wp_remote_request($url, $args = array()) {
  154. $objFetchSite = _wp_http_get_object();
  155. return $objFetchSite->request($url, $args);
  156. }
  157. /**
  158. * Retrieve the raw response from the HTTP request using the GET method.
  159. *
  160. * @see wp_remote_request() For more information on the response array format and default arguments.
  161. *
  162. * @since 2.7.0
  163. *
  164. * @param string $url Site URL to retrieve.
  165. * @param array $args Optional. Override the defaults.
  166. * @return WP_Error|array The response or WP_Error on failure.
  167. */
  168. function wp_remote_get($url, $args = array()) {
  169. $objFetchSite = _wp_http_get_object();
  170. return $objFetchSite->get($url, $args);
  171. }
  172. /**
  173. * Retrieve the raw response from the HTTP request using the POST method.
  174. *
  175. * @see wp_remote_request() For more information on the response array format and default arguments.
  176. *
  177. * @since 2.7.0
  178. *
  179. * @param string $url Site URL to retrieve.
  180. * @param array $args Optional. Override the defaults.
  181. * @return WP_Error|array The response or WP_Error on failure.
  182. */
  183. function wp_remote_post($url, $args = array()) {
  184. $objFetchSite = _wp_http_get_object();
  185. return $objFetchSite->post($url, $args);
  186. }
  187. /**
  188. * Retrieve the raw response from the HTTP request using the HEAD method.
  189. *
  190. * @see wp_remote_request() For more information on the response array format and default arguments.
  191. *
  192. * @since 2.7.0
  193. *
  194. * @param string $url Site URL to retrieve.
  195. * @param array $args Optional. Override the defaults.
  196. * @return WP_Error|array The response or WP_Error on failure.
  197. */
  198. function wp_remote_head($url, $args = array()) {
  199. $objFetchSite = _wp_http_get_object();
  200. return $objFetchSite->head($url, $args);
  201. }
  202. /**
  203. * Retrieve only the headers from the raw response.
  204. *
  205. * @since 2.7.0
  206. *
  207. * @param array $response HTTP response.
  208. * @return array The headers of the response. Empty array if incorrect parameter given.
  209. */
  210. function wp_remote_retrieve_headers(&$response) {
  211. if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
  212. return array();
  213. return $response['headers'];
  214. }
  215. /**
  216. * Retrieve a single header by name from the raw response.
  217. *
  218. * @since 2.7.0
  219. *
  220. * @param array $response
  221. * @param string $header Header name to retrieve value from.
  222. * @return string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist.
  223. */
  224. function wp_remote_retrieve_header(&$response, $header) {
  225. if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
  226. return '';
  227. if ( array_key_exists($header, $response['headers']) )
  228. return $response['headers'][$header];
  229. return '';
  230. }
  231. /**
  232. * Retrieve only the response code from the raw response.
  233. *
  234. * Will return an empty array if incorrect parameter value is given.
  235. *
  236. * @since 2.7.0
  237. *
  238. * @param array $response HTTP response.
  239. * @return string the response code. Empty string on incorrect parameter given.
  240. */
  241. function wp_remote_retrieve_response_code(&$response) {
  242. if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
  243. return '';
  244. return $response['response']['code'];
  245. }
  246. /**
  247. * Retrieve only the response message from the raw response.
  248. *
  249. * Will return an empty array if incorrect parameter value is given.
  250. *
  251. * @since 2.7.0
  252. *
  253. * @param array $response HTTP response.
  254. * @return string The response message. Empty string on incorrect parameter given.
  255. */
  256. function wp_remote_retrieve_response_message(&$response) {
  257. if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
  258. return '';
  259. return $response['response']['message'];
  260. }
  261. /**
  262. * Retrieve only the body from the raw response.
  263. *
  264. * @since 2.7.0
  265. *
  266. * @param array $response HTTP response.
  267. * @return string The body of the response. Empty string if no body or incorrect parameter given.
  268. */
  269. function wp_remote_retrieve_body(&$response) {
  270. if ( is_wp_error($response) || ! isset($response['body']) )
  271. return '';
  272. return $response['body'];
  273. }
  274. /**
  275. * Determines if there is an HTTP Transport that can process this request.
  276. *
  277. * @since 3.2.0
  278. *
  279. * @param array $capabilities Array of capabilities to test or a wp_remote_request() $args array.
  280. * @param string $url Optional. If given, will check if the URL requires SSL and adds that requirement to the capabilities array.
  281. *
  282. * @return bool
  283. */
  284. function wp_http_supports( $capabilities = array(), $url = null ) {
  285. $objFetchSite = _wp_http_get_object();
  286. $capabilities = wp_parse_args( $capabilities );
  287. $count = count( $capabilities );
  288. // If we have a numeric $capabilities array, spoof a wp_remote_request() associative $args array
  289. if ( $count && count( array_filter( array_keys( $capabilities ), 'is_numeric' ) ) == $count ) {
  290. $capabilities = array_combine( array_values( $capabilities ), array_fill( 0, $count, true ) );
  291. }
  292. if ( $url && !isset( $capabilities['ssl'] ) ) {
  293. $scheme = parse_url( $url, PHP_URL_SCHEME );
  294. if ( 'https' == $scheme || 'ssl' == $scheme ) {
  295. $capabilities['ssl'] = true;
  296. }
  297. }
  298. return (bool) $objFetchSite->_get_first_available_transport( $capabilities );
  299. }
  300. /**
  301. * Get the HTTP Origin of the current request.
  302. *
  303. * @since 3.4.0
  304. *
  305. * @return string URL of the origin. Empty string if no origin.
  306. */
  307. function get_http_origin() {
  308. $origin = '';
  309. if ( ! empty ( $_SERVER[ 'HTTP_ORIGIN' ] ) )
  310. $origin = $_SERVER[ 'HTTP_ORIGIN' ];
  311. return apply_filters( 'http_origin', $origin );
  312. }
  313. /**
  314. * Retrieve list of allowed http origins.
  315. *
  316. * @since 3.4.0
  317. *
  318. * @return array Array of origin URLs.
  319. */
  320. function get_allowed_http_origins() {
  321. $admin_origin = parse_url( admin_url() );
  322. $home_origin = parse_url( home_url() );
  323. // @todo preserve port?
  324. $allowed_origins = array_unique( array(
  325. 'http://' . $admin_origin[ 'host' ],
  326. 'https://' . $admin_origin[ 'host' ],
  327. 'http://' . $home_origin[ 'host' ],
  328. 'https://' . $home_origin[ 'host' ],
  329. ) );
  330. return apply_filters( 'allowed_http_origins' , $allowed_origins );
  331. }
  332. /**
  333. * Determines if the http origin is an authorized one.
  334. *
  335. * @since 3.4.0
  336. *
  337. * @param string Origin URL. If not provided, the value of get_http_origin() is used.
  338. * @return bool True if the origin is allowed. False otherwise.
  339. */
  340. function is_allowed_http_origin( $origin = null ) {
  341. $origin_arg = $origin;
  342. if ( null === $origin )
  343. $origin = get_http_origin();
  344. if ( $origin && ! in_array( $origin, get_allowed_http_origins() ) )
  345. $origin = '';
  346. return apply_filters( 'allowed_http_origin', $origin, $origin_arg );
  347. }
  348. /**
  349. * Send Access-Control-Allow-Origin and related headers if the current request
  350. * is from an allowed origin.
  351. *
  352. * If the request is an OPTIONS request, the script exits with either access
  353. * control headers sent, or a 403 response if the origin is not allowed. For
  354. * other request methods, you will receive a return value.
  355. *
  356. * @since 3.4.0
  357. *
  358. * @return bool|string Returns the origin URL if headers are sent. Returns false
  359. * if headers are not sent.
  360. */
  361. function send_origin_headers() {
  362. $origin = get_http_origin();
  363. if ( is_allowed_http_origin( $origin ) ) {
  364. @header( 'Access-Control-Allow-Origin: ' . $origin );
  365. @header( 'Access-Control-Allow-Credentials: true' );
  366. if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] )
  367. exit;
  368. return $origin;
  369. }
  370. if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
  371. status_header( 403 );
  372. exit;
  373. }
  374. return false;
  375. }
  376. /**
  377. * Validate a URL for safe use in the HTTP API.
  378. *
  379. * @since 3.5.2
  380. *
  381. * @return mixed URL or false on failure.
  382. */
  383. function wp_http_validate_url( $url ) {
  384. $url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
  385. if ( ! $url )
  386. return false;
  387. $parsed_url = @parse_url( $url );
  388. if ( ! $parsed_url || empty( $parsed_url['host'] ) )
  389. return false;
  390. if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) )
  391. return false;
  392. if ( false !== strpos( $parsed_url['host'], ':' ) )
  393. return false;
  394. $parsed_home = @parse_url( get_option( 'home' ) );
  395. $same_host = strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );
  396. if ( ! $same_host ) {
  397. $host = trim( $parsed_url['host'], '.' );
  398. if ( preg_match( '#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host ) ) {
  399. $ip = $host;
  400. } else {
  401. $ip = gethostbyname( $host );
  402. if ( $ip === $host ) // Error condition for gethostbyname()
  403. $ip = false;
  404. }
  405. if ( $ip ) {
  406. $parts = array_map( 'intval', explode( '.', $ip ) );
  407. if ( '127.0.0.1' === $ip
  408. || ( 10 === $parts[0] )
  409. || ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
  410. || ( 192 === $parts[0] && 168 === $parts[1] )
  411. ) {
  412. // If host appears local, reject unless specifically allowed.
  413. if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) )
  414. return false;
  415. }
  416. }
  417. }
  418. if ( empty( $parsed_url['port'] ) )
  419. return $url;
  420. $port = $parsed_url['port'];
  421. if ( 80 === $port || 443 === $port || 8080 === $port )
  422. return $url;
  423. if ( $parsed_home && $same_host && $parsed_home['port'] === $port )
  424. return $url;
  425. return false;
  426. }
  427. /**
  428. * Whitelists allowed redirect hosts for safe HTTP requests as well.
  429. *
  430. * Attached to the http_request_host_is_external filter.
  431. *
  432. * @since 3.6.0
  433. *
  434. * @param bool $is_external
  435. * @param string $host
  436. * @return bool
  437. */
  438. function allowed_http_request_hosts( $is_external, $host ) {
  439. if ( ! $is_external && wp_validate_redirect( 'http://' . $host ) )
  440. $is_external = true;
  441. return $is_external;
  442. }
  443. /**
  444. * Whitelists any domain in a multisite installation for safe HTTP requests.
  445. *
  446. * Attached to the http_request_host_is_external filter.
  447. *
  448. * @since 3.6.0
  449. *
  450. * @param bool $is_external
  451. * @param string $host
  452. * @return bool
  453. */
  454. function ms_allowed_http_request_hosts( $is_external, $host ) {
  455. global $wpdb, $current_site;
  456. static $queried = array();
  457. if ( $is_external )
  458. return $is_external;
  459. if ( $host === $current_site->domain )
  460. return true;
  461. if ( isset( $queried[ $host ] ) )
  462. return $queried[ $host ];
  463. $queried[ $host ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $host ) );
  464. return $queried[ $host ];
  465. }