| | 1448 | if( ! function_exists('remote_http') ){ |
| | 1449 | /** |
| | 1450 | * remote_http() - performs an HTTP/1.0 request. |
| | 1451 | * |
| | 1452 | * Makes a remote HTTP request and returns a object represnting the request. |
| | 1453 | * |
| | 1454 | * Things to note about this function: |
| | 1455 | * * This function does not support Proxies |
| | 1456 | * * This function is not cached |
| | 1457 | * * $data may either be an array of values to be sent, Or it may be a string of raw data. |
| | 1458 | * * The headers sent by this function can be modified/added to by the 'remote_http_headers' filter. |
| | 1459 | * * All headers returned by this function are normalised to lowercase names. |
| | 1460 | * * Be default, This function will follow 5 redirections, The final return object will have a property 'redirectionpath' which contains the object representing each redirection attempt. |
| | 1461 | * * Defaults can be overridden via the 2nd argument $args, See code for values to be overridden. |
| | 1462 | * |
| | 1463 | * Example Use: |
| | 1464 | * |
| | 1465 | * $request = remote_http('http://my-site/api/', 'method=post&timeout=30', array('PostField' => 'PostDataValue'), array('User-Agent' => 'My Super Plugin')); |
| | 1466 | * HTTP Request: |
| | 1467 | * |
| | 1468 | * POST /api/ HTTP/1.0 |
| | 1469 | * Host: my-site |
| | 1470 | * User-Agent: My Super Plugin |
| | 1471 | * Content-Length: 23 |
| | 1472 | * Content-Type: application/x-www-form-urlencoded; charset=UTF-8 |
| | 1473 | * |
| | 1474 | * PostField=PostDataValue |
| | 1475 | * |
| | 1476 | * Return Object: |
| | 1477 | * object(stdClass)[69] |
| | 1478 | * public 'status' => string '200' (length=3) |
| | 1479 | * public 'statusvalue' => string 'OK' (length=2) |
| | 1480 | * public 'headers' => |
| | 1481 | * array |
| | 1482 | * 'date' => string 'Sun, 25 May 2008 06:36:40 GMT' (length=29) |
| | 1483 | * 'server' => string 'Apache' (length=6) |
| | 1484 | * 'connection' => string 'close' (length=5) |
| | 1485 | * 'content-type' => string 'text/html' (length=9) |
| | 1486 | * public 'content' => string 'Return Value from API Service here' (length=34) |
| | 1487 | * |
| | 1488 | * Example use with a String as the $data param: |
| | 1489 | * |
| | 1490 | * $request = remote_http('http://my-site/api/', array('method' => 'post'), serialize( array(time()) )); |
| | 1491 | * HTTP Request: |
| | 1492 | * POST /api/ HTTP/1.0 |
| | 1493 | * Host: my-site |
| | 1494 | * User-Agent: WordPress/2.6; http://your-site/ |
| | 1495 | * Content-Length: 23 |
| | 1496 | * Content-Type: application/x-www-form-urlencoded; charset=UTF-8 |
| | 1497 | * |
| | 1498 | * a:1:{i:0;i:1211698656;} |
| | 1499 | * |
| | 1500 | * @since 2.6 |
| | 1501 | * |
| | 1502 | * @param string $url the URL to open |
| | 1503 | * @param string|array $args |
| | 1504 | * @param string|array $data (optional) an Associative array containing data keys to be sent, or a pre-made HTTP query string |
| | 1505 | * @param array $headers (optional) Extra headers to send with the connection. eg. array('Referer' => 'http://localhost/'); |
| | 1506 | * @return bool|object Returns false on failure, Else an object with 4 properties: "status", "statusname", "headers" and "content", If a redirection has taken place, an extra 5th property "redirectionpath" will contain objects of the other HTTP Requests which were made. |
| | 1507 | */ |
| | 1508 | function remote_http($url, $args = array(), $data='', $headers = array()){ |
| | 1509 | global $wp_version; |
| | 1510 | |
| | 1511 | $defaults = array( |
| | 1512 | 'method' => 'GET', 'timeout' => 3, |
| | 1513 | 'allowed_methods' => array('GET', 'POST', 'HEAD'), |
| | 1514 | 'redirection' => 5, 'redirected' => false, |
| | 1515 | 'httpversion' => '1.0' |
| | 1516 | ); |
| | 1517 | |
| | 1518 | $r = wp_parse_args( $args, $defaults ); |
| | 1519 | extract( $r );//Allow it to overwrite $data/$headers if user has specified them in this array, However, this is an unsupported use of the function. |
| | 1520 | |
| | 1521 | if( ! function_exists('fsockopen') ) |
| | 1522 | return false; |
| | 1523 | |
| | 1524 | if( is_array($data) ) |
| | 1525 | $data = http_build_query($data); |
| | 1526 | |
| | 1527 | $headers = wp_parse_args($headers); |
| | 1528 | |
| | 1529 | $method = strtoupper($method); |
| | 1530 | if( ! in_array($method, $allowed_methods) ) |
| | 1531 | $method = 'GET'; |
| | 1532 | |
| | 1533 | $port = 80; |
| | 1534 | $schema = 'http'; |
| | 1535 | $path = $host = $query = ''; |
| | 1536 | $parts = parse_url($url); |
| | 1537 | extract($parts); |
| | 1538 | |
| | 1539 | if( ! empty($query) ) |
| | 1540 | $query = "?$query"; |
| | 1541 | |
| | 1542 | $http_request = "$method $path$query HTTP/$httpversion\r\n"; |
| | 1543 | $http_request .= "Host: $host\r\n"; |
| | 1544 | |
| | 1545 | if( ! isset($headers['User-Agent']) ) |
| | 1546 | $headers['User-Agent'] = 'WordPress/' . $wp_version . '; ' . get_bloginfo('url'); |
| | 1547 | |
| | 1548 | if( ! empty($data) ) { |
| | 1549 | $headers['Content-Length'] = strlen($data); |
| | 1550 | |
| | 1551 | if( ! isset($headers['Content-Type']) ) |
| | 1552 | $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'); |
| | 1553 | } |
| | 1554 | |
| | 1555 | $headers = apply_filters('remote_http_headers', $headers); |
| | 1556 | |
| | 1557 | if( ! empty($headers) ) |
| | 1558 | foreach($headers as $header => $value) |
| | 1559 | $http_request .= "$header: $value\r\n"; |
| | 1560 | |
| | 1561 | $http_request .= "\r\n"; |
| | 1562 | if( ! empty($data) ) |
| | 1563 | $http_request .= $data; |
| | 1564 | |
| | 1565 | $response = ''; |
| | 1566 | if( false == ( $fs = @fsockopen( $host, $port, $errno, $errstr, $timeout) ) || ! is_resource($fs) ) |
| | 1567 | return false; |
| | 1568 | |
| | 1569 | fwrite($fs, $http_request); |
| | 1570 | |
| | 1571 | while ( !feof($fs) ) |
| | 1572 | $response .= fgets($fs, 1160); // One TCP-IP packet |
| | 1573 | fclose($fs); |
| | 1574 | $response = explode("\r\n\r\n", $response, 2); |
| | 1575 | |
| | 1576 | $ret = (object)array('status' => 0, 'statusvalue' => '', 'headers' => array(), 'content'=> $response[1]); |
| | 1577 | |
| | 1578 | foreach( explode("\n", $response[0]) as $rheader) { |
| | 1579 | if( strpos($rheader, ':') ) { //Proper header |
| | 1580 | list($header, $value) = explode(':', $rheader, 2); |
| | 1581 | if( !empty($header) && ! empty($value) ) |
| | 1582 | $ret->headers[ strtolower(trim($header)) ] = trim($value); |
| | 1583 | } else if( strpos($rheader, 'HTTP') > -1) { //A Status header. |
| | 1584 | list(,$status, $status_value) = preg_split('|\s+|', $rheader,3); |
| | 1585 | $ret->status = trim($status); |
| | 1586 | $ret->statusvalue = trim($status_value); |
| | 1587 | } |
| | 1588 | } |
| | 1589 | |
| | 1590 | //Handle Redirections: |
| | 1591 | if ( isset($ret->headers['location']) && $redirection ) { |
| | 1592 | $ret->headers['x-location'] = $ret->headers['location']; //Record the location the redirection has taken us to. |
| | 1593 | |
| | 1594 | $r['redirection']--; |
| | 1595 | $r['redirected'] = true; |
| | 1596 | |
| | 1597 | $redirected = remote_http($ret->headers['location'], $r, $data, $headers); |
| | 1598 | $redirected->redirectionpath[] = $ret; |
| | 1599 | $ret = $redirected; |
| | 1600 | } |
| | 1601 | |
| | 1602 | return $ret; |
| | 1603 | } |
| | 1604 | } |