2
149

sendhttp

sendhttp
SYNOPSIS

sendhttp($method, $url, $args, $files=false, $base64=false, $options=false, $header=false)

DESCRIPTION

sendhttp generates the HTTP document for a GET, POST, PUT, DELETE or HEAD request, transmits it to an HTTP or HTTPS server and returns the HTTP code, the header and the body of the document sent back by the server or false in case of error.

$method is set to 'GET', 'POST', 'PUT', 'DELETE' or 'HEAD' depending on the type of request expected by the server.

$url addresses the PHP code of the server which is going to analyze the document, run an action and return a regular HTTP document. $url has the format [proto://]host[:portnum]/path. Set proto to 'https' to transmit a document in a secure mode. host gives the name or the IP address of the server. If necessary, add portnum to specify a port number different from 80 or 443 for HTTP or HTTPS connections with a server listening to particular ports. path gives the path to the PHP code on the server.

$args contains a list of parameters for the called service arranged in an associative array { 'param1' => val1, ... }. $args can pass one or several fields directly in a URL for an HTTP GET, DELETE or HEAD request, the fields extracted from an HTML form or fields encoded in JSON for an HTTP POST or a PUT request.

$files contains the list of files attached to the request in the form an associative array { 'docname' => {'name' => 'filename', 'type' => 'mimetype', 'tmp_name' => 'pathname'}, ... }. This parameter is optional. Typically, it's used to pass a file transmitted by an <input type="file" name="docname"... /> tag in an HTML form. Alternatively, the field tmp_name can be replaced by a field data followed by the data in binary. To pass en empty content, set the field files to true or a field with data to '' (EMPTY STRING). If $base64 is true, the contents of the files are encoded in base64.

sendhttp sends back an array containing the HTTP return code, the header of the response and the body of the response. If an argument is invalid or if the connection has failed, sendhttp returns false.

EXAMPLE
php> $r = sendhttp('GET', 'http://www.google.com/search', array('q' => 'izend'));

Same as typing http:://www.google.com/search?q=izend in the address bar of a navigator.

php> print_r($r[0]);
200

Displays the HTTP return code.

php> print_r($r[1]);
Array
(
    [Date] => ...
    [Expires] => -1
    [Cache-Control] => private, max-age=0
    [Content-Type] => text/html; charset=ISO-8859-1
    ...
)

Displays the MIME header of the document.

php> echo $r[1]['Content-Type'];
text/html; charset=ISO-8859-1

Displays the content type of the document.

php> print_r($r[2]);
<!doctype html><head><title>izend - Google Search</title> ...

Displays the document.

CODE
  1. function sendhttp($method, $url, $args, $files=false, $base64=false, $options=false, $header=false) {

sendhttp accepts 7 arguments: a request type, a URL, a list of parameters and an optional list of files whose contents can be transmitted encoded in base64, parameters passed in the context of the connection with the remote service, additional fields placed in the header of the HTTP document.

  1.     $r = http_parse_url($url);
  2.  
  3.     if (!$r) {
  4.         return false;
  5.     }
  6.  
  7.     list($proto, $scheme, $host, $portnum, $path, $query)=$r;
  8.  
  9.     if ($query) {
  10.         $path .= '?' . $query;
  11.     }

Decomposes the URL with the PHP function parse_url. Returns false if $url is invalid.

  1.     $hostaddr=($scheme == 'http' && $portnum == 80) ? $host : $host . ':' . $portnum;
  2.  
  3.     $user_agent='iZend';
  4.  
  5.     $content_string=$content_type=false;
  6.  
  7.     $crlf="\r\n";

Initializes the values of the fields Host: and User-Agent: of the request. Prepares the header and the body of the HTTP document. Defines $crlf to the value of the end of line of MIME document. Tests the type of the request.

  1.     switch ($method) {
  2.         case 'POST':
  3.         case 'PUT':
  4.             if ($files) {
  5.                 $boundary = md5(microtime());
  6.                 $content_type = 'multipart/form-data; boundary='.$boundary;
  7.  
  8.                 $content_string = '';
  9.  
  10.                 if ($args && is_array($args)) {
  11.                     foreach ($args as $k => $v) {
  12.                         $content_string .= '--' . $boundary . $crlf;
  13.                         $content_string .= 'Content-Disposition: form-data; name="' . $k . '"' . $crlf . $crlf . $v . $crlf;
  14.                     }
  15.                 }
  16.                 if (is_array($files)) {
  17.                     foreach ($files as $k => $v ) {
  18.                         $data=false;
  19.                         if (isset($v['tmp_name'])) {
  20.                             $data = file_get_contents($v['tmp_name']);
  21.                         }
  22.                         else if (isset($v['data'])) {
  23.                             $data = $v['data'];
  24.                         }
  25.                         if (!$data) {
  26.                             break;
  27.                         }
  28.                         $content_string .= '--' . $boundary . $crlf;
  29.                         $content_string .= 'Content-Disposition: form-data; name="' . $k . '"; filename="' . $v['name'] . '"' . $crlf;
  30.                         $content_string .= 'Content-Type: ' . $v['type'] . $crlf;
  31.                         if ($base64) {
  32.                             $content_string .= 'Content-Transfer-Encoding: base64' . $crlf . $crlf;
  33.                             $content_string .= chunk_split(base64_encode($data)) . $crlf;
  34.                         }
  35.                         else {
  36.                             $content_string .= 'Content-Transfer-Encoding: binary' . $crlf . $crlf;
  37.                             $content_string .= $data . $crlf;
  38.                         }
  39.                     }
  40.                 }
  41.                 $content_string .= '--' . $boundary . '--' . $crlf;
  42.             }
  43.             else {
  44.                 if ($args) {
  45.                     if (is_array($args)) {
  46.                         $content_type = 'application/x-www-form-urlencoded';
  47.                         $content_string = http_build_args($args);
  48.                     }
  49.                     else {
  50.                         $content_string = $args;
  51.                     }
  52.                 }
  53.             }
  54.  
  55.             $header_string="$method $path HTTP/1.1${crlf}Host: $hostaddr${crlf}User-Agent: $user_agent${crlf}";
  56.  
  57.             if ($content_string) {
  58.                 $content_length = strlen($content_string);
  59.                 $header_string .= "Content-Length: $content_length${crlf}";
  60.                 if ($content_type) {
  61.                     $header_string .= "Content-Type: $content_type${crlf}";
  62.                 }
  63.             }
  64.             break;

If the request is a POST or a PUT, if the document has one or several attached files, writes a document of the type multipart/form-data, otherwise writes a document of the type application/x-www-form-urlencoded. In the first case, builds the body of the document with a first part which defines a unique separator then a series of secondary parts each containing one of the attached files encoded in base64. In the second case, builds the body of an HTTP document containing the parameters of the request, if any, properly formatted with http_build_args.

  1.         case 'GET':
  2.         case 'HEAD':
  3.         case 'DELETE':
  4.             if ($args && is_array($args)) {
  5.                 $path .= ($query ? '&' : '?') . http_build_args($args);
  6.             }
  7.             $header_string="$method $path HTTP/1.1${crlf}Host: $hostaddr${crlf}User-Agent: $user_agent${crlf}";
  8.             break;

If the request is a GET, adds the parameters, if any, properly formatted with http_build_args after the access path, then builds the header of the HTTP document. The body of the document is empty.

  1.         default:
  2.             return false;
  3.     }

Returns false if $method isn't 'POST', 'PUT''GET', 'HEAD' or 'DELETE'.

  1.     if ($header && is_array($header)) {
  2.         foreach ($header as $name => $value) {
  3.             if (is_array($value)) {
  4.                 $value = implode('; ', $value);
  5.             }
  6.             $header_string .= "${name}: ${value}${crlf}";
  7.         }
  8.     }

Adds in $header_string the lignes defined by the array $header passed in argument.

  1.     $header_string .= "Connection: close${crlf}${crlf}";

Ends the header of the document.

  1.     return sendhttpraw($proto, $host, $portnum, $header_string, $content_string, $options);
  2. }

Sends $header_string and $content_string to $host with sendhttpraw and returns an array with the HTTP code sent back by the service, the MIME header of the document in an associative array and the plain content of the response.

sendhttpraw
SYNOPSIS

sendhttpraw($proto, $host, $portnum, $header_string, $content_string=false, $options=false)

DESCRIPTION
CODE
  1. function sendhttpraw($proto, $host, $portnum, $header_string, $content_string=false, $options=false) {

sendhttpraw accepts 6 arguments: a connection type - tcp or ssl, a host name or an IP address, a port number, the header and the body of an HTTP document, a series of options passed in the context of the opening of the connection.

  1.     $url=$proto . '://' . $host . ':' . $portnum;
  2.  
  3.     $socket = $options ? @stream_socket_client($url, $errstr, $errno, 60, STREAM_CLIENT_CONNECT, stream_context_create($options)) : @stream_socket_client($url);
  4.  
  5.     if ($socket === false) {
  6.         return false;
  7.     }

Opens the connection with the server. Returns false in case of error.

  1.     if (fwrite($socket, $header_string) === false) {
  2.         return false;
  3.     }
  4.  
  5.     if ($content_string) {
  6.         $content_len = strlen($content_string);
  7.         for ($written = 0; $written < $content_len; $written += $w) {
  8.             $w = fwrite($socket, $written == 0 ? $content_string : substr($content_string, $written));
  9.             if ($w === false) {
  10.                 return false;
  11.             }
  12.         }
  13.     }

Writes the header of the document then the body of the document in several packets if necessary.

  1.     $response = '';
  2.     while (!feof($socket)) {
  3.         $response .= fread($socket, 8192);
  4.     }

Reads the response from the server.

  1.     fclose($socket);

Closes the connection with the server.

  1.     if (!$response) {
  2.         return false;
  3.     }

Returns false if the response is empty.

  1.     $crlf="\r\n";

Defines $crlf to the value of the end of line of MIME document.

  1.     list($response_headers, $response_body) = explode($crlf . $crlf, $response, 2);

Splits the header and the body of the document. Separates the header line by line. Extracts the first line of the header to get the return code.

  1.     $response_header_lines = explode($crlf, $response_headers);
  2.     $http_response_line = array_shift($response_header_lines);
  3.  
  4.     if (preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@', $http_response_line, $r)) {
  5.         $response_code = $r[1];
  6.     }
  7.     else {
  8.         $response_code = 0;
  9.     }
  10.  
  11.     $response_header_array = array();
  12.     foreach ($response_header_lines as $header_line) {
  13.         list($header, $value) = explode(': ', $header_line, 2);
  14.         $response_header_array[ucwords($header, '-')] = $value;
  15.     }

Saves the header of the response in an associative array.

  1.     if (isset($response_header_array['Transfer-Encoding'])) {
  2.         switch ($response_header_array['Transfer-Encoding']) {
  3.             case 'chunked':
  4.                 $chunks = explode($crlf, $response_body);
  5.                 foreach ($chunks as $i => $s) {
  6.                     if ($i % 2 == 0) {
  7.                         unset($chunks[$i]);
  8.                     }
  9.                 }
  10.                 $response_body = implode('', $chunks);
  11.                 break;
  12.             default:
  13.                 break;
  14.         }
  15.     }
  16.  
  17.     return array($response_code, $response_header_array, $response_body);
  18. }

Returns an array with the HTTP code sent back by the service, the MIME header of the document in an associative array and the plain content of the response.

sendget
SYNOPSIS

sendget($url, $args, $options=false, $header=false)

DESCRIPTION

sendget returns the document sent back by the HTTP service called with a GET at the address $url with the arguments $args.

sendget returns false in case of error.

CODE
  1. function sendget($url, $args=false, $options=false, $header=false) {
  2.     return sendhttp('GET', $url, $args, false, false, $options, $header);
  3. }

sendget returns the result of calling sendhttp with $method set to 'GET' and the arguments $url, $args, options and headers.

sendpost
SYNOPSIS

sendpost($url, $args, $files=false, $base64=false, $options=false, $header=false)

DESCRIPTION

sendpost returns the document sent back by the HTTP service called with a POST at the address $url with the arguments $args and the attached $files encoded in base64 if $base64 is true.

sendpost returns false in case of error.

CODE
  1. function sendpost($url, $args=false, $files=false, $base64=false, $options=false, $header=false) {
  2.     return sendhttp('POST', $url, $args, $files, $base64, $options, $header);
  3. }

sendpost returns the result of calling sendhttp with $method set to 'POST' and the arguments $url, $args, $files, $base64, options and headers.

sendput
SYNOPSIS

sendput($url, $args, $files=false, $base64=false, $options=false, $header=false)

DESCRIPTION

sendput returns the document sent back by the HTTP service called with a PUT at the address $url with the arguments $args and the attached $files encoded in base64 if $base64 is true.

sendput returns false in case of error.

CODE
  1. function sendput($url, $args=false, $files=false, $base64=false, $options=false, $header=false) {
  2.     return sendhttp('PUT', $url, $args, $files, $base64, $options, $header);
  3. }

sendput returns the result of calling sendhttp with $method set to 'PUT' and the arguments $url, $args, $files, $base64, options and headers.

senddelete
SYNOPSIS

senddelete($url, $args, $options=false, $header=false)

DESCRIPTION

senddelete returns the document sent back by the HTTP service called with a DELETE at the address $url with the arguments $args.

senddelete returns false in case of error.

CODE
  1. function senddelete($url, $args=false, $options=false, $header=false) {
  2.     return sendhttp('DELETE', $url, $args, false, false, $options, $header);
  3. }

senddelete returns the result of calling sendhttp with $method set to 'DELETE' and the arguments $url, $args, options and headers.

sendhead
SYNOPSIS

sendhead($url, $args, $options=false, $header=false)

DESCRIPTION

sendhead returns the document sent back by the HTTP service called with a HEAD at the address $url with the arguments $args.

sendhead returns false in case of error.

CODE
  1. function sendhead($url, $args=false, $options=false, $header=false) {
  2.     return sendhttp('HEAD', $url, $args, false, false, $options, $header);
  3. }

sendhead returns the result of calling sendhttp with $method set to 'HEAD' and the arguments $url, $args, options and headers.

http_build_args
SYNOPSIS

http_build_args($args)

DESCRIPTION

http_build_args returns the associative array $args in the form of a properly formatted URL string of parameters.

CODE
  1. function http_build_args($args) {
  2.     $args_string = '';
  3.  
  4.     foreach ($args as $name => $value) {
  5.         $args_string .= ($args_string ? '&' : '') . urlencode($name) . '=' . urlencode($value);
  6.     }
  7.  
  8.     return $args_string;
  9. }
http_parse_url
SYNOPSIS

http_parse_url($url)

DESCRIPTION

http_parse_url returns an array containing the protocol - tcp or ssl, the schema - http or https, the name of the host or the IP address, the port number and the path described by $url.

CODE
  1. function http_parse_url($url) {
  2.     $purl = @parse_url($url);
  3.     if ($purl === false) {
  4.         return false;
  5.     }
  6.  
  7.     $scheme = isset($purl['scheme']) ? $purl['scheme'] : 'http';
  8.     switch($scheme) {
  9.         case 'https':
  10.             $proto = 'ssl';
  11.             break;
  12.         case 'http':
  13.             $proto = 'tcp';
  14.             break;
  15.         default:
  16.             return false;
  17.     }
  18.     $host = isset($purl['host']) ? $purl['host'] : 'localhost';
  19.     $portnum = isset($purl['port']) ? $purl['port'] : ($scheme == 'https' ? 443 : 80);
  20.     $path = isset($purl['path']) ? $purl['path'] : '/';
  21.     $query = isset($purl['query']) ? $purl['query'] : false;
  22.  
  23.     return array($proto, $scheme, $host, $portnum, $path, $query);
  24. }
Application
Encoding a QR code

Google publishes an API for drawing charts and other images - Google Charts API - which can be used to obtain a PNG image of a QR code. Simply pass the proper parameters in an <img>:

<img src="http://chart.googleapis.com/chart?cht=qr&chf=bg,s,ffffff&chs=63x63&chld=M|0&chl=www.izend.org" />

qrencode

Decoding a QR code

Decoding the image of a QR code is more challenging. Suppose you haven't found a true HTTP API but just a form which lets you upload an image and returns the decoded text: ZXing Decoder Online. Try it. This form returns the decoded text or another HTML document in case of error.

Extract the source code of the form:

<form enctype="multipart/form-data" method="post" action="decode">
<input name="f" type="file"/>
<input type="submit"/>
</form>

Write a function which passes these parameters in an HTTP POST request:

  1. require_once 'sendhttp.php';
  2. require_once 'filemimetype.php';
  3.  
  4. function qrdecode($file) {
  5.     $url = 'https://zxing.org/w/decode';
  6.     $files=array('f' => array('name' => basename($file), 'tmp_name' => $file, 'type' => file_mime_type($file)));
  7.  
  8.     $response=sendpost($url, false, $files, false); // DON'T encode data in base64
  9.  
  10.     if (!$response or $response[0] != 200) {
  11.         return false;
  12.     }
  13.  
  14.     if (!preg_match('#<tr><td>Parsed Result</td><td><pre.*>(.*)</pre></td></tr>#', $response[2], $r)) { // extract data - adapt when response format changes
  15.         return false;
  16.     }
  17.  
  18.     return strip_tags($r[1]);
  19. }

qrdecode sends a POST request at the address https://zxing.org/w/decode attached with the image of a QR code and returns the text it contains. If the service returns an error, qrdecode returns false.

IMPORTANT: Be very careful when inserting data returned by another program. If possible, remove all tags with strip_tags and add your own formatting.

Test the function qrdecode with the QR of a website:

$ php -a
php > define('ROOT_DIR', dirname(__FILE__));
php > set_include_path(ROOT_DIR . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR . get_include_path());
php > require_once 'qrdecode.php';
php > echo qrdecode('logos/siteqr.png') . PHP_EOL;
http://www.izend.org
SEE ALSO

qrencode, qrdecode

Comments

Your comment:
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip help 2000

Enter a maximum of 2000 characters.
Improve the presentation of your text with the following formatting tags:
[p]paragraph[/p], [b]bold[/b], [i]italics[/i], [u]underline[/u], [s]strike[/s], [quote]citation[/quote], [pre]as is[/pre], [br]line break,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]command[/code], [code=language]source code in c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].