Created
February 10, 2016 19:37
-
-
Save MidnightLightning/7fb6282fd2dd74784843 to your computer and use it in GitHub Desktop.
HTTP Transfer class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * HTTP transfer class | |
| * @author Brooks Boyd | |
| * @version 1.0 | |
| * @package simpleHTTP | |
| */ | |
| /** | |
| * Interface used for fetching http data | |
| */ | |
| interface http { | |
| /** | |
| * Send data via HTTP POST | |
| * | |
| * @return array A class extending this interface is expected to return an array of two elements, the first element being an array of all the header lines of the response, and the second being the body of the response | |
| * @param string $url | |
| * @param string|array $data Child classes can take an associative array and turn it into a query string, or take a query string already formed | |
| * @param string|array $extra_headers Child classes can take an array of lines, an associative array of name/value pairs, or an already-constructed string | |
| * @param bool $debug | |
| */ | |
| public function post_send($url, $data = "", $extra_headers = "", $debug = false); | |
| /** | |
| * Send data via HTTP GET | |
| * | |
| * @return array A class extending this interface is expected to return an array of two elements, the first element being an array of all the header lines of the response, and the second being the body of the response | |
| * @param string $url | |
| * @param string|array $data Child classes can take an associative array and turn it into a query string, or take a query string already formed | |
| * @param string|array $extra_headers Child classes can take an array of lines, an associative array of name/value pairs, or an already-constructed string | |
| * @param bool $debug | |
| */ | |
| public function get_send($url, $data = "", $extra_headers = "", $debug = false); | |
| } | |
| /** | |
| * Basic HTTP class using PHP Socket functions | |
| */ | |
| class http_socket implements http { | |
| /** | |
| * Send data via HTTP POST | |
| * | |
| * Required for the interface; passes off to a global method | |
| * @return array | |
| */ | |
| public function post_send($url, $data = "", $extra_headers = "", $debug = false) { | |
| return $this->http_send($url, 'POST', '', $data, $extra_headers, $debug); | |
| } | |
| /** | |
| * Send data via HTTP GET | |
| * | |
| * Required for the interface; passes off to a global method | |
| * @return array | |
| */ | |
| public function get_send($url, $data = "", $extra_headers = "", $debug = false) { | |
| return $this->http_send($url, 'GET', $data, '', $extra_headers, $debug); | |
| } | |
| /** | |
| * Send data via HTTP DELETE | |
| * | |
| * Technically the same as a POST request; the data bundle is handled the same way. | |
| * @return array | |
| */ | |
| public function delete_send($url, $data = "", $extra_headers = "", $debug = false) { | |
| return $this->http_send($url, 'DELETE', '', $data, $extra_headers, $debug); | |
| } | |
| /** | |
| * Prepare data to send via HTTP | |
| * | |
| * Master function that handles all the transactions | |
| * @return array | |
| */ | |
| private function http_send($url, $verb = "GET", $query = "", $data = "", $headers = "", $debug = false) { | |
| $verb = strtoupper($verb); // Ensure upper-case | |
| $url = parse_url($url); // Get URL info | |
| if ($url['scheme'] != 'http' && $url['scheme'] != 'https') trigger_error("Scheme '{$url['scheme']}' is not supported; only HTTP/S requests supported!\n", E_USER_ERROR); | |
| // Generate data string | |
| $query_string = ""; | |
| if (is_array($query)) { | |
| foreach($query as $key => $value) { | |
| $query_string .= rawurlencode($key)."=".rawurlencode($value)."&"; | |
| } | |
| $query_string = substr($query_string, 0, -1); // Trim trailing ampersand | |
| } else { | |
| // Data is already a string | |
| $query_string = $query; | |
| } | |
| $url_final = ($query_string != "")? $url['path']."?".$query_string : $url['path']; | |
| $header_string = ""; | |
| if (is_array($headers)) { | |
| $keys = array_keys($headers); | |
| if ($keys[0] == 0) { | |
| // non-associative array | |
| $header_string = implode("\r\n", $headers)."\r\n"; | |
| } else { | |
| // associative array | |
| foreach($headers as $key => $value) { | |
| $header_string .= $key.": ".$value."\r\n"; | |
| } | |
| } | |
| } else { | |
| // string sent | |
| $header_string = $headers; | |
| } | |
| $request = "{$verb} {$url_final} HTTP/1.1\r\n". | |
| "Host: {$url['host']}\r\n". | |
| "Connection: close\r\n"; | |
| if ($data != "") { | |
| $request .= "Content-length: " . strlen($data) . "\r\n"; | |
| } | |
| if ($header_string != "") $request .= $header_string; | |
| if (substr($request, -2) != "\r\n") $request .= "\r\n"; // Ensure extra headers had trailing \r\n | |
| $request .= "\r\n".$data; | |
| if ($debug) echo $request."\n\n"; | |
| return $this->send_query($url['host'], $request, $url['scheme'], $debug); | |
| } | |
| /** | |
| * Send prepared data | |
| * | |
| * Sends the request, check for errors, unchunks result and returns final result | |
| * @return array | |
| */ | |
| private function send_query($host, $request, $scheme = 'http', $debug = FALSE) { | |
| switch($scheme) { | |
| case "https": | |
| $host = "ssl://".$host; | |
| $port = 443; | |
| break; | |
| default: | |
| $port = 80; | |
| break; | |
| } | |
| if ($debug) echo "Port: $port\n"; | |
| $fp = fsockopen($host, $port, $errno, $errstr, 30); | |
| if (!$fp) trigger_error("Socket Error: $errstr ($errno)", E_USER_ERROR); | |
| fputs($fp, $request); | |
| // Get response | |
| $buf = ""; | |
| while (!feof($fp)) | |
| $buf .= fgets($fp,128); | |
| fclose($fp); | |
| // split the result header from the content | |
| $pos = strpos($buf, "\r\n\r\n"); | |
| $result = array(); | |
| $result[0] = substr($buf,0,$pos); | |
| $result[1] = substr($buf,$pos+4); | |
| while(strtolower($result[0]) == "http/1.1 100 continue") { array_shift($result); } | |
| $headers = isset($result[0]) ? explode("\r\n", $result[0]) : array(); | |
| $content = isset($result[1]) ? $result[1] : ''; | |
| // Unchunk data | |
| foreach($headers as $header) { | |
| if (strtolower($header) == "transfer-encoding: chunked") { | |
| // Data is chunked | |
| if ($debug) echo "Unchunking data...\n"; | |
| $content = $this->unchunk($content); // Replace with un-chunked | |
| break; // Jump out of foreach | |
| } | |
| } | |
| // return as array: | |
| return array($headers, $content); | |
| } | |
| /** | |
| * Unchunk HTTP data | |
| */ | |
| private function unchunk($data) { | |
| $final = ""; | |
| $i = 0; | |
| while ($i < strlen($data)) { | |
| $rawnum = substr($data, $i, strpos(substr($data, $i), "\r\n") + 2); // Grab line size | |
| $num = hexdec(trim($rawnum)); // Convert to decimal | |
| $i += strlen($rawnum); // move pointer to after line size demarker | |
| $chunk = substr($data, $i, $num); // Grab chunk | |
| $final .= $chunk; // Add to final | |
| $i += strlen($chunk); // Move to after chunk | |
| } | |
| return $final; | |
| } | |
| } | |
| /** | |
| * Basic HTTP class using PHP CURL binding functions | |
| */ | |
| class http_curl implements http { | |
| private $ch; | |
| private $uid; | |
| /** | |
| * Initialize CURL object | |
| */ | |
| function __construct() { | |
| $this->ch = curl_init(); | |
| $this->uid = dechex(rand(0,99999999)); | |
| curl_setopt($this->ch,CURLOPT_MAXCONNECTS,100); | |
| curl_setopt($this->ch,CURLOPT_CLOSEPOLICY,CURLCLOSEPOLICY_LEAST_RECENTLY_USED); | |
| curl_setopt($this->ch,CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MtGox PHP client; PHP/'.phpversion().')'); | |
| } | |
| /** | |
| * Set proxy information | |
| * | |
| * Optional method to define a proxy for CURL requests | |
| */ | |
| public function set_proxy($url, $port) { | |
| curl_setopt($this->ch,CURLOPT_PROXY, $url); | |
| curl_setopt($this->ch,CURLOPT_PROXYPORT, $port); | |
| } | |
| /** | |
| * Send data via HTTP POST | |
| * | |
| * Required for the interface | |
| * @return array | |
| */ | |
| public function post_send($url, $data = "", $headers = "", $debug = false) { | |
| $header_array = array(); | |
| if (is_array($headers)) { | |
| $keys = array_keys($headers); | |
| if ($keys[0] == 0) { | |
| // non-associative array | |
| $header_array = $headers; | |
| } else { | |
| // associative array | |
| foreach($headers as $key => $value) { | |
| $header_array[] = $key.": ".$value; | |
| } | |
| } | |
| } else { | |
| // string sent | |
| $header_array = explode("\r\n", $headers); | |
| } | |
| curl_setopt($this->ch,CURLOPT_URL,$url); | |
| curl_setopt($this->ch,CURLOPT_FOLLOWLOCATION,1); | |
| curl_setopt($this->ch,CURLOPT_MAXREDIRS,10); | |
| curl_setopt($this->ch,CURLOPT_HEADER,1); | |
| curl_setopt($this->ch,CURLOPT_RETURNTRANSFER,1); | |
| curl_setopt($this->ch,CURLOPT_TIMEOUT,30); | |
| curl_setopt($this->ch,CURLOPT_CONNECTTIMEOUT,10); | |
| curl_setopt($this->ch,CURLOPT_POST,1); | |
| curl_setopt($this->ch,CURLOPT_POSTFIELDS, $data); // Handles both string and array already | |
| curl_setopt($this->ch,CURLOPT_HTTPHEADER, $header_array); | |
| return $this->send_query(); | |
| } | |
| /** | |
| * Send data via HTTP GET | |
| * | |
| * Required for the interface | |
| * @return array | |
| */ | |
| public function get_send($url, $data = "", $headers = "", $debug = false) { | |
| $header_array = array(); | |
| if (is_array($headers)) { | |
| $keys = array_keys($headers); | |
| if ($keys[0] == 0) { | |
| // non-associative array | |
| $header_array = $headers; | |
| } else { | |
| // associative array | |
| foreach($headers as $key => $value) { | |
| $header_array[] = $key.": ".$value; | |
| } | |
| } | |
| } else { | |
| // string sent | |
| $header_array = explode("\r\n", $headers); | |
| } | |
| // Generate query string | |
| $query_string = ""; | |
| if (is_array($data)) { | |
| $query_string = ""; | |
| foreach($data as $key => $value) { | |
| $query_string .= rawurlencode($key)."=".rawurlencode($value)."&"; | |
| } | |
| $query_string = substr($query_string, 0, -1); // Trim trailing ampersand | |
| } else { | |
| // Assume data is already a string | |
| $query_string = $data; | |
| } | |
| curl_setopt($this->ch,CURLOPT_URL,$url."?".$query_string); | |
| curl_setopt($this->ch,CURLOPT_FOLLOWLOCATION,1); | |
| curl_setopt($this->ch,CURLOPT_MAXREDIRS,10); | |
| curl_setopt($this->ch,CURLOPT_HEADER,1); | |
| curl_setopt($this->ch,CURLOPT_RETURNTRANSFER,1); | |
| curl_setopt($this->ch,CURLOPT_TIMEOUT,30); | |
| curl_setopt($this->ch,CURLOPT_CONNECTTIMEOUT,10); | |
| curl_setopt($this->ch,CURLOPT_HTTPGET,1); | |
| curl_setopt($this->ch,CURLOPT_HTTPHEADER, $header_array); | |
| return $this->send_query(); | |
| } | |
| /** | |
| * Send prepared data | |
| * | |
| * Sends the request, check for errors, and returns final result | |
| * @return array | |
| */ | |
| private function send_query() { | |
| $buf = curl_exec($this->ch); | |
| if ($buf === FALSE) trigger_error("CURL error: ".curl_error($this->ch)."\n", E_USER_ERROR); | |
| // split the result header from the content | |
| $result = explode("\r\n\r\n", $buf); | |
| while(strtolower($result[0]) == "http/1.1 100 continue") { array_shift($result); } | |
| $headers = isset($result[0]) ? explode("\r\n", $result[0]) : array(); | |
| $content = isset($result[1]) ? $result[1] : ''; | |
| // return as array: | |
| return array($headers, $content); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment