12.5. Using REST in PHP

Issuing GET Requests
Modern versions of PHP make it trivial to GET web pages: any file-access function (even include!) works seamlessly with URLs, too. Thus, you can use fopen, file_get_contents, and any other file-reading function to issue GET requests. For example:

$url = "http://www.acme.com/products/3322";
$response = file_get_contents($url);
echo $response;

Any parameters passed to GET requests must be encoded (e.g., a space is %20); you can encode strings using the urlencode function.

Issuing POST Requests
In stark contrast to the ease of doing a GET, there's no simple way to do a POST in PHP. You have to open a connection to the server and manually send all HTTP headers. Here's a simple function that will do the trick, for any HTTP method:

function httpRequest($host, $port, $method, $path, $params) {
  // Params are a map from names to values
  $paramStr = "";
  foreach ($params as $name, $val) {
    $paramStr .= $name . "=";
    $paramStr .= urlencode($val);
    $paramStr .= "&";
  }

  // Assign defaults to $method and $port, if needed
  if (empty($method)) {
    $method = 'GET';
  }
  $method = strtoupper($method);
  if (empty($port)) {
    $port = 80; // Default HTTP port
  }

  // Create the connection
  $sock = fsockopen($host, $port);
  if ($method == "GET") {
    $path .= "?" . $paramStr;
  }
  fputs($sock, "$method $path HTTP/1.1\r\n");
  fputs($sock, "Host: $host\r\n");
  fputs($sock, "Content-type: " .
               "application/x-www-form-urlencoded\r\n");
  if ($method == "POST") {
    fputs($sock, "Content-length: " . 
                 strlen($paramStr) . "\r\n");
  }
  fputs($sock, "Connection: close\r\n\r\n");
  if ($method == "POST") {
    fputs($sock, $paramStr);
  }

  // Buffer the result
  $result = "";
  while (!feof($sock)) {
    $result .= fgets($sock,1024);
  }

  fclose($sock);
  return $result;
}

Issuing a POST request using this function is as simple as:

$resp = httpRequest("www.acme.com",
    80, "POST", "/userDetails",
    array("firstName" => "John", "lastName" => "Doe"));

One alternative to this approach is using PHP's CURL support; however, I'm not sure if it's really easier.

16 comments:

Christophe said...

Thanks for this tutorial, but what about methods PUT and DELETE in PHP?

Best Regards,
Christophe

Dr. M. Elkstein said...

Hi Christophe,

The method outlined here can also be used with "DELETE" or "PUT" as the HTTP method value ($method argument).

Ramanath said...

But I am getting an error like this:
unable to connect to http://localhost/REST/rest-server.php:80 (Unable to find the socket transport "http"
please help me
Thanks
Ramanath

Dr. M. Elkstein said...

Hi Ramanath,

It's probably a misconfiguration of PHP. Some things you could try: removing "http://" from the URL (it's the default, in some configurations); removing the ":80" from the URL (it shouldn't be where you've put it, anyway).

designreviews said...

Dear DR M.E.
I have tried the example above using cj rest service but i get a response:
You must specify a developer key:
even if i supplied it.

$url = "https://product-search.api.cj.com/v2/product-search?website-id=3429481&developerid=mykey&keywords=GPS&serviceable-area=US ";
$response = file_get_contents($url);
echo $response;

Please can you help me get over this?

Dr. M. Elkstein said...

Hello "designreviews",

It seems like the problem you're facing is specific to "cj", with which I'm not familiar. Try visiting their support forums, if they have any.

Warren Dowey at Blanc Lapin Software Limited said...

this example does not work with a return value of XML as the end of file is never found, it also does not work with PUT as the PUT does not have params that need converted to POST vars.

I edited the code to handle as such

[code]
function httpRequest($host, $port, $method, $path, $params) {
// Params are a map from names to values
$paramStr = "";
if ($method == "GET" || $method == "POST" ) {
foreach ($params as $name => $val) {
$paramStr .= $name . "=";
$paramStr .= urlencode($val);
$paramStr .= "&";
}
}
// Assign defaults to $method and $port, if needed
if (empty($method)) {
$method = 'GET';
}
$method = strtoupper($method);
if (empty($port)) {
$port = 80; // Default HTTP port
}

// Create the connection
$sock = fsockopen($host, $port);

if ($method == "GET") {
$path .= "?" . $data;
}

fputs($sock, "$method $path HTTP/1.1\r\n");
fputs($sock, "Host: $host\r\n");
fputs($sock, "Content-type: " .
"application/xml\r\n");
if ($method == "PUT") {
fputs($sock, "Content-length: " .
strlen($params) . "\r\n");
}elseif ($method == "POST") {
fputs($sock, "Content-length: " .
strlen($paramStr) . "\r\n");
}
fputs($sock, "Connection: close\r\n\r\n");

if ($method == "PUT") {
fputs($sock, $params);

}
elseif ($method == "POST") {
fputs($sock, $paramStr);
}

// Buffer the result
$result = "";
do {
$temp = fgets($sock,1024);
$result .= $temp;

}while($temp !="");

fclose($sock);
return $result;
}
[/code]

Tomasz said...

Hi Dr. M. Elkstein,

Thanks for the tutorial! I want to contribute by saying that a POST request could also be done via the function file_get_contents.

$url = ...;

if($_SERVER['REQUEST_METHOD'] == 'GET') {
$context = null;
} elseif ($_SERVER['REQUEST_METHOD'] == 'POST') {
$postdata = http_build_query($params);
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata
)
);
$context = stream_context_create($opts);
}

$response = file_get_contents($url, false, $context);

I hope this is helpful.

I have also one question. I could not find the answer in the rfc regarding http requests. If I want to use one of the methods PUT or DELETE to do a request and I have some parameters to send with the request, how should I encode the parameters? What are my options?

Regards,
Tomasz

dade said...

Why do this when you can easily use CURL?

Dr. M. Elkstein said...

Date -- you're right, of course; CURL can be just as easily used.

Steve Robbins said...

Is it just me or is $data undefined? Perhaps it should be $paramStr?

Dr. M. Elkstein said...

Hi Steve,

You're right, of course. Corrected.

Thanks!

Cristina H said...

"Modern versions of PHP make it trivial to GET web pages: any file-access function (even include!) works seamlessly with URLs, too."

This is true only if fopen wrappers are enabled. The PHP configuration must set allow_url_fopen to "1". This is the default, but I've seen many reports of people attempting to use fopen URL-aware fopen wrappers with it off in their configuration.

hassengh said...

hello I want to realize a small application with Rest
who can send me a source code for a simple application to understand Rest
and thank you before
My email is
hassen.gheroil @ gmail.com

Alex Henderson said...

Thanks for the information that is still useful many years later.
Now there are a number of PHP Frameworks that can take away much of the pain. I've started using Slim from slimframework dot com. It's free and open source, and handles all http verbs and variable paths too. (Note that I have no connection to the company/writers).
Alex

john son said...

Your posts is really helpful for me.Thanks for your wonderful post. I am very happy to read your post. It is really very helpful for us and I have gathered some important information from this blog.

Best JAVA Training Institute in Chennai