Handles any HTTP request correctly. This is a flexible and powerful HTTP client implementation of GET, POST, PUT or any other HTTP requests. The reason I built this was due to use of url arguments without any attributes in a specific feed url. Both curl and get_file_contents methods failed.
Source code viewer
/** * Request function that works with requests as well as a web browser. * * @param string $url * A string containing a fully qualified URI. * @param array $options * (optional) An array that can have one or more of the following elements: * headers: An array containing request headers to send as name/value pairs. * method: A string containing the request method. Defaults to 'GET'. * data: A string containing the request body, formatted as * 'param=value&param=value&...'; to generate this, * use http_build_query(). * Defaults to NULL. * max_redirects: An integer representing how many times a redirect * may be followed. Defaults to 3. * timeout: A float representing the maximum number of seconds the function * call may take. The default is 30 seconds. If a timeout occurs, * the error code is set to -1. * context: A context resource created with stream_context_create(). * * @return object * An object that can have one or more of the following components: * request: A string containing the request body that was sent. * code: An integer containing the response status code, or the error code * if an error occurred. * protocol: The response protocol (e.g. HTTP/1.1 or HTTP/1.0). * status_message: The status message from the response, if a response was * received. * redirect_code: If redirected, an integer containing the initial response * status code. * redirect_url: If redirected, a string containing the URL of the redirect * target. * error: If an error occurred, the error message. Otherwise not set.< * headers: An array containing the response headers as name/value pairs. * HTTP header names are case-insensitive (RFC 2616, section 4.2), so for * easy access the array keys are returned in lower case. * data: A string containing the response body that was received. * * @see https://api.drupal.org/api/drupal/includes%21common.inc/function/drupal_http_request/7.x * @licence GNU General Public Licence see http://www.gnu.org/licenses/gpl.html */ $result = new stdClass(); // Parse the URL and make sure we can handle the schema. if ($uri == FALSE) { $result->error = 'unable to parse URL'; $result->code = -1001; return $result; } $result->error = 'missing schema'; $result->code = -1002; return $result; } // Merge the default options. 'method' => 'GET', 'data' => NULL, 'max_redirects' => 3, 'timeout' => 30.0, 'context' => NULL, ); // Merge the default headers. 'User-Agent' => 'Drupal (+http://drupal.org/)', ); // stream_socket_client() requires timeout to be a float. $options['timeout'] = (double) $options['timeout']; switch ($uri['scheme']) { case 'http': $socket = 'tcp://' . $uri['host'] . ':' . $port; // RFC 2616: "non-standard ports MUST, default ports MAY be included". // We don't add the standard port to prevent from breaking rewrite rules // checking the host that do not take into account the port number. $options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : ''); } break; case 'https': // Note: Only works when PHP is compiled with OpenSSL support. $socket = 'ssl://' . $uri['host'] . ':' . $port; $options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : ''); } break; default: $result->error = 'invalid schema ' . $uri['scheme']; $result->code = -1003; return $result; } } else { // Create a stream with context. Allows verification of a SSL certificate. $fp = @stream_socket_client($socket, $errno, $errstr, $options['timeout'], STREAM_CLIENT_CONNECT, $options['context']); } // Make sure the socket opened properly. if (!$fp) { // When a network error occurs, we use a negative number so it does not // clash with the HTTP status codes. $result->code = -$errno; return $result; } // Construct the path to act on. $path .= '?' . $uri['query']; } // Only add Content-Length if we actually have any content or if it is a POST // or PUT request. Some non-standard servers get confused by Content-Length in // at least HEAD/GET requests, and Squid always requires Content-Length in // POST/PUT requests. if ($content_length > 0 || $options['method'] == 'POST' || $options['method'] == 'PUT') { $options['headers']['Content-Length'] = $content_length; } // If the server URL has a user then attempt to use basic authentication. $options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ':')); } $request = $options['method'] . ' ' . $path . " HTTP/1.0\r\n"; foreach ($options['headers'] as $name => $value) { } $request .= "\r\n" . $options['data']; $result->request = $request; // Calculate how much time is left of the original timeout value. $diff += $timer['time']; } $timeout = $options['timeout'] - $diff / 1000; if ($timeout > 0) { } // Fetch response. Due to PHP bugs like http://bugs.php.net/bug.php?id=43782 // and http://bugs.php.net/bug.php?id=46049 we can't rely on feof(), but // instead must invoke stream_get_meta_data() each iteration. $alive = !$info['eof'] && !$info['timed_out']; $response = ''; while ($alive) { // Calculate how much time is left of the original timeout value. $diff += $timer['time']; } $timeout = $options['timeout'] - $diff / 1000; if ($timeout <= 0) { $info['timed_out'] = TRUE; break; } $response .= $chunk; $alive = !$info['eof'] && !$info['timed_out'] && $chunk; } if ($info['timed_out']) { $result->code = -1; $result->error = 'request timed out'; return $result; } // Parse response headers from the response body. // Be tolerant of malformed HTTP responses that separate header and body with // \n\n or \r\r instead of \r\n\r\n. // Parse the response status line. // Set up empty values. 'reason_phrase' => '', ); $response_status_array['http_version'] = $response_array[0]; $response_status_array['response_code'] = $response_array[1]; $response_status_array['reason_phrase'] = $response_array[2]; } $result->protocol = $response_status_array['http_version']; $result->status_message = $response_status_array['reason_phrase']; $code = $response_status_array['response_code']; // Parse the response headers. // RFC 2109: the Set-Cookie response header comprises the token Set- // Cookie:, followed by a comma-separated list of one or more cookies. } else { } } 100 => 'Continue', 101 => 'Switching Protocols', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported', ); // RFC 2616 states that all unknown HTTP codes must be treated the same as the // base code in their class. } $result->code = $code; switch ($code) { // The request was successfully received, understood and accepted. case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 304: break; // Further action needs to be taken in order to complete the request. case 301: case 302: case 307: $location = $result->headers['location']; $diff += $timer['time']; } $options['timeout'] -= $diff / 1000; if ($options['timeout'] <= 0) { $result->code = -1; $result->error = 'request timed out'; } elseif ($options['max_redirects']) { // Redirect to the new location. $options['max_redirects']--; $result = request($location, $options); $result->redirect_code = $code; } if (!property_exists($result, 'redirect_url')) { $result->redirect_url = $location; } break; default: $result->error = $result->status_message; } return $result; }Programming Language: PHP