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
- 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.
- $r = http_parse_url($url);
- if (!$r) {
- return false;
- }
- list($proto, $scheme, $host, $portnum, $path, $query)=$r;
- if ($query) {
- $path .= '?' . $query;
- }
Decomposes the URL with the PHP function parse_url
. Returns false
if $url
is invalid.
- $hostaddr=($scheme == 'http' && $portnum == 80) ? $host : $host . ':' . $portnum;
- $user_agent='iZend';
- $content_string=$content_type=false;
- $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.
- switch ($method) {
- case 'POST':
- case 'PUT':
- if ($files) {
- $boundary = md5(microtime());
- $content_type = 'multipart/form-data; boundary='.$boundary;
- $content_string = '';
- if ($args && is_array($args)) {
- foreach ($args as $k => $v) {
- $content_string .= '--' . $boundary . $crlf;
- $content_string .= 'Content-Disposition: form-data; name="' . $k . '"' . $crlf . $crlf . $v . $crlf;
- }
- }
- if (is_array($files)) {
- foreach ($files as $k => $v ) {
- $data=false;
- if (isset($v['tmp_name'])) {
- $data = file_get_contents($v['tmp_name']);
- }
- else if (isset($v['data'])) {
- $data = $v['data'];
- }
- if (!$data) {
- break;
- }
- $content_string .= '--' . $boundary . $crlf;
- $content_string .= 'Content-Disposition: form-data; name="' . $k . '"; filename="' . $v['name'] . '"' . $crlf;
- $content_string .= 'Content-Type: ' . $v['type'] . $crlf;
- if ($base64) {
- $content_string .= 'Content-Transfer-Encoding: base64' . $crlf . $crlf;
- $content_string .= chunk_split(base64_encode($data)) . $crlf;
- }
- else {
- $content_string .= 'Content-Transfer-Encoding: binary' . $crlf . $crlf;
- $content_string .= $data . $crlf;
- }
- }
- }
- $content_string .= '--' . $boundary . '--' . $crlf;
- }
- else {
- if ($args) {
- if (is_array($args)) {
- $content_type = 'application/x-www-form-urlencoded';
- $content_string = http_build_args($args);
- }
- else {
- $content_string = $args;
- }
- }
- }
- $header_string="$method $path HTTP/1.1${crlf}Host: $hostaddr${crlf}User-Agent: $user_agent${crlf}";
- if ($content_string) {
- $content_length = strlen($content_string);
- $header_string .= "Content-Length: $content_length${crlf}";
- if ($content_type) {
- $header_string .= "Content-Type: $content_type${crlf}";
- }
- }
- 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
.
- case 'GET':
- case 'HEAD':
- case 'DELETE':
- if ($args && is_array($args)) {
- $path .= ($query ? '&' : '?') . http_build_args($args);
- }
- $header_string="$method $path HTTP/1.1${crlf}Host: $hostaddr${crlf}User-Agent: $user_agent${crlf}";
- 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.
- default:
- return false;
- }
Returns false
if $method
isn't 'POST'
, 'PUT'
'GET'
, 'HEAD'
or 'DELETE'
.
- if ($header && is_array($header)) {
- foreach ($header as $name => $value) {
- if (is_array($value)) {
- $value = implode('; ', $value);
- }
- $header_string .= "${name}: ${value}${crlf}";
- }
- }
Adds in $header_string
the lignes defined by the array $header
passed in argument.
- $header_string .= "Connection: close${crlf}${crlf}";
Ends the header of the document.
- return sendhttpraw($proto, $host, $portnum, $header_string, $content_string, $options);
- }
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
- 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.
- $url=$proto . '://' . $host . ':' . $portnum;
- $socket = $options ? @stream_socket_client($url, $errstr, $errno, 60, STREAM_CLIENT_CONNECT, stream_context_create($options)) : @stream_socket_client($url);
- if ($socket === false) {
- return false;
- }
Opens the connection with the server. Returns false
in case of error.
- if (fwrite($socket, $header_string) === false) {
- return false;
- }
- if ($content_string) {
- $content_len = strlen($content_string);
- for ($written = 0; $written < $content_len; $written += $w) {
- $w = fwrite($socket, $written == 0 ? $content_string : substr($content_string, $written));
- if ($w === false) {
- return false;
- }
- }
- }
Writes the header of the document then the body of the document in several packets if necessary.
- $response = '';
- while (!feof($socket)) {
- $response .= fread($socket, 8192);
- }
Reads the response from the server.
- fclose($socket);
Closes the connection with the server.
- if (!$response) {
- return false;
- }
Returns false
if the response is empty.
- $crlf="\r\n";
Defines $crlf
to the value of the end of line of MIME document.
- 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.
- $response_header_lines = explode($crlf, $response_headers);
- $http_response_line = array_shift($response_header_lines);
- if (preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@', $http_response_line, $r)) {
- $response_code = $r[1];
- }
- else {
- $response_code = 0;
- }
- $response_header_array = array();
- foreach ($response_header_lines as $header_line) {
- list($header, $value) = explode(': ', $header_line, 2);
- $response_header_array[ucwords($header, '-')] = $value;
- }
Saves the header of the response in an associative array.
- if (isset($response_header_array['Transfer-Encoding'])) {
- switch ($response_header_array['Transfer-Encoding']) {
- case 'chunked':
- $chunks = explode($crlf, $response_body);
- foreach ($chunks as $i => $s) {
- if ($i % 2 == 0) {
- unset($chunks[$i]);
- }
- }
- $response_body = implode('', $chunks);
- break;
- default:
- break;
- }
- }
- return array($response_code, $response_header_array, $response_body);
- }
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
- function sendget($url, $args=false, $options=false, $header=false) {
- return sendhttp('GET', $url, $args, false, false, $options, $header);
- }
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
- function sendpost($url, $args=false, $files=false, $base64=false, $options=false, $header=false) {
- return sendhttp('POST', $url, $args, $files, $base64, $options, $header);
- }
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
- function sendput($url, $args=false, $files=false, $base64=false, $options=false, $header=false) {
- return sendhttp('PUT', $url, $args, $files, $base64, $options, $header);
- }
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
- function senddelete($url, $args=false, $options=false, $header=false) {
- return sendhttp('DELETE', $url, $args, false, false, $options, $header);
- }
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
- function sendhead($url, $args=false, $options=false, $header=false) {
- return sendhttp('HEAD', $url, $args, false, false, $options, $header);
- }
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
- function http_build_args($args) {
- $args_string = '';
- foreach ($args as $name => $value) {
- $args_string .= ($args_string ? '&' : '') . urlencode($name) . '=' . urlencode($value);
- }
- return $args_string;
- }
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
- function http_parse_url($url) {
- $purl = @parse_url($url);
- if ($purl === false) {
- return false;
- }
- $scheme = isset($purl['scheme']) ? $purl['scheme'] : 'http';
- switch($scheme) {
- case 'https':
- $proto = 'ssl';
- break;
- case 'http':
- $proto = 'tcp';
- break;
- default:
- return false;
- }
- $host = isset($purl['host']) ? $purl['host'] : 'localhost';
- $portnum = isset($purl['port']) ? $purl['port'] : ($scheme == 'https' ? 443 : 80);
- $path = isset($purl['path']) ? $purl['path'] : '/';
- $query = isset($purl['query']) ? $purl['query'] : false;
- return array($proto, $scheme, $host, $portnum, $path, $query);
- }
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" />
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:
- require_once 'sendhttp.php';
- require_once 'filemimetype.php';
- function qrdecode($file) {
- $url = 'https://zxing.org/w/decode';
- $files=array('f' => array('name' => basename($file), 'tmp_name' => $file, 'type' => file_mime_type($file)));
- $response=sendpost($url, false, $files, false); // DON'T encode data in base64
- if (!$response or $response[0] != 200) {
- return false;
- }
- if (!preg_match('#<tr><td>Parsed Result</td><td><pre.*>(.*)</pre></td></tr>#', $response[2], $r)) { // extract data - adapt when response format changes
- return false;
- }
- return strip_tags($r[1]);
- }
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
Comments