HTTP Fetching in PHP Without cURL

HTTP Fetching in PHP Without cURL

On some shared hosting accounts, cURL, fopen or file_get_contents functions may be disabled ‘for security reasons’, yet you can still achieve HTTP fetching using socket functions.

This simple class of code will allow you to do a wide range of HTTP fetching. It should be easy enough to customise should you feel the need to. Check out the 3 examples provided at the foot of the code to try it out. You should be able to use this code with plain old PHP, with no extra functionality.

class streams {

    

    public $timeout = 5; // Time out of requests in seconds

    public $defaults = array( // Default request headers

        ‘User-Agent’=>‘Mozilla/6.0 (Windows; Windows NT 4.0; en-US;)’,

        ‘Accept’=>‘*/*’,

        ‘Connection’=>‘Close’

    ); 

    public $request = array(); // Variable that holds the formed request 

    

    public $headers = array(); // HTTP headers of resposne

    public $body = ”; // HTTP body of response

    public $error = ”; // Holds a descriptive error string should something go wrong with the request

    

    // Prepares some variables and HTTP headers for the fetch

    public function request($method,$uri,$headers = array(),$post = ”) {

        

        // Find the (mandatory) domain in the URI

        $_p = parse_url($uri);

        if(!isset($_p[‘scheme’])) {

            $this->error = ‘URI lacks a scheme’;

            return false;

        }

        if(!isset($_p[‘host’])) {

            $this->error = ‘URI lacks a hostname’;

            return false;

        }

        

        // Add the ? to any query string… that PHP likes to remove after parse_url

        if(isset($_p[‘query’]))

            $_p[‘query’] = ‘?’.$_p[‘query’];

        else

            $_p[‘query’] = ”;

            

        if(!isset($_p[‘path’]))

            $_p[‘path’] = ‘/’;

    

         // [Request Method] [URL] [HTTP Version] in 1st line of request

        array_unshift($this->request,$method.‘ ‘.$_p[‘path’].$_p[‘query’].” HTTP/1.1″);

        // Host header

        $this->request[‘Host’] = ‘Host: ‘.$_p[‘host’];

 

        // Add default headers

        foreach($this->defaults as $headername => $headervalue)

            $this->request[$headername] = $headername.‘: ‘.$headervalue;

            

        // Add user-defined headers

        foreach($headers as $headername => $headervalue)

            $this->request[$headername] = $headername.‘: ‘.$headervalue;

        

         // If performing a POST, add some headers and the POST data

        if($method == ‘POST’ && strlen($post)) {

            $this->request[‘Content-Length’] = ‘Content-Length: ‘.strlen($post);

            $this->request[‘Content-Type’] = ‘Content-Type: application/x-www-form-urlencoded’;

            array_push($this->request,“\r\n”.$post);

        }

        else

            array_push($this->request,“\r\n”);

            

        // Assume port 80|443 if there is not a user defined port in the URI

        if(!isset($_p[‘port’])) 

            $_p[‘port’] = (strtolower($_p[‘scheme’]) == ‘https’ ? 443 : 80);

            

        // … ready to perform the connection …

 

        // Connect to server

        $fp = fsockopen(($_p[‘port’] == 443 ? ‘ssl://’ : ”).$_p[‘host’],$_p[‘port’],$errno,$this->error,$this->timeout);

        if(!$fp) 

            return false;

        

        // For separating the HEAD and BODY of HTTP responses

        $head = true;

        $body = ”;

        

        // Send request headers

        

        fputs($fp,implode(“\r\n”,$this->request));

                

        // Read the response back, separate HTTP headers and body

        while(!feof($fp)) {

            if($head) {

                if(!trim($line = fgets($fp))) {

                    $head = false;

                    if(!isset($this->headers[‘transfer-encoding’]) && !isset($this->headers[‘content-encoding’]))

                        $body = &$this->body;

                }

                else {

                    $line = preg_split(“‘:s*’”,rtrim($line),2);

                    @$this->headers[strtolower($line[0])] = $line[1];

                }

            }

            else

                $body .= fread($fp,65536);

        }

 

        // Decode the response if required to, deals with chunked transfer-encoding and gzipped content-encoding

        if(isset($this->headers[‘transfer-encoding’]) || isset($this->headers[‘content-encoding’],$body)) 

            $this->decode_body($body);

        

    }

 

    // Separated for clarity and extensibility

    

    private function decode_body($body,$eol = “rn”) {

        $add = strlen($eol);

        

        if(isset($this->headers[‘transfer-encoding’]) && $this->headers[‘transfer-encoding’] == ‘chunked’) {

            do {

                $body = ltrim($body);

                $pos = strpos($body,$eol);

                $len = hexdec(substr($body,0,$pos ));

                if(isset($this->headers[‘content-encoding’] ) )

                    $this->body .= gzinflate(substr($body,($pos + $add + 10 ),$len ));

                else

                    $this->body .= substr($body,($pos + $add ),$len);

                $body = substr($body,($len + $pos + $add ));

                $check = trim($body);

            } while(!empty($check));

        }

        elseif(isset($this->headers[‘content-encoding’]))

            $this->body = gzinflate(substr($body,10));

    }

}

You may find httpbin.org useful in testing your network requests.

See also  Install Redis daemon and Redis PHP extension in cPanel

Here are some simple examples to get started with…

Example 1 – HTTP Fetching (GET)

$_str = new streams;

$_str->request(‘GET’,‘http://httpbin.org/get’);

print_r($_str->headers);

print_r($_str->body);

echo $_str->error;

Example 2 – HTTP Fetching (POST)

$_str = new streams;

$_str->request(‘POST’,‘http://httpbin.org/post’,array(),‘zebedee=123&mytest=yes’);

print_r($_str->headers);

print_r($_str->body);

echo $_str->error;

Example 3 – Adding custom headers

$xtra = array(

	‘User-Agent’=>‘My custom user agent’,

	‘Cookie’=>‘SESS=1357913’

);

$_str = new streams;

$_str->request(‘GET’,‘http://httpbin.org/get’,$xtra);

print_r($_str->headers);

print_r($_str->body);

echo $_str->error;
whoami
Stefan Pejcic
Join the discussion

I enjoy constructive responses and professional comments to my posts, and invite anyone to comment or link to my site.