WS with Basic Auth and REST
This post is going to contain a lot of acronyms. If you want to know more about them I advice you to look them up in a search engine. When you try to work with web services, the first suggestion you get is to use cURL. Because it has all the functionality you could ever wish for when creating a web service. But I had some issues on my local machine when trying to connect to an external web service. And cURL was not even installed on the production server. So I tried to install it, both using the regular apt-get install curl libcurl3 php5-curl and by downloading a binary, compiling and installing that. But I ended up in a dead end. So I started looking at file_get_contents() which is the second choice if you ask Internet, and it could do the things I wanted it to do. So, after some minor tweaking and testing I managed to get it to work. Have a look at the code below.
The first file contains the web service. It expects a JSON string containing a name, location and a list of cars. This information is then turned into a small string and returned.
// ws.php
<?php
// Make sure you get a login prompt if you try to access the service
if (!isset($_SERVER['PHP_AUTH_USER']) or $_SERVER['PHP_AUTH_USER'] != '') {
header('WWW-Authenticate: Basic realm="LOGIN REQUIRED"');
header('HTTP/1.0 401 Unauthorized');
$status = array('error' => 1, 'message' => 'Access denied 401!');
echo json_encode($status);
exit;
}
// Check if you could login. This is of course a very simple check. You probably have a login function to check the user
$accessOk = false;
if ($_SERVER['PHP_AUTH_USER'] == 'John' and $_SERVER['PHP_AUTH_PW'] == 'Doe') {
$accessOk = true;
}
// If the login fail we prompt the login box again
if (!$accessOk) {
header('WWW-Authenticate: Basic realm="WRONG PASSWORD"');
header('HTTP/1.0 401 Unauthorized');
$status = array('error' => 2, 'message' => 'Wrong username or password!');
echo json_encode($status);
exit;
}
// If we manage to get in we read the content from the POST and turn it into a php object
$jContent = file_get_contents('php://input');
$jObj = json_decode($jContent); //convert JSON into array
#echo '<br>' . $jContent . '<br>'; // This is just to check that you recieve the correct data
#print_r($jObj); // This is to check that the data is converted to an object
#echo '<br>';
$carsCnt = count($jObj->cars);
// Then we compose a string and add it to our return array and print it to screen as a reply
$status = array('error' => 0, 'message' => 'Hi ' . $jObj->name . '. You live in ' . $jObj->location->city . ' and have ' . $carsCnt . ' cars. Have a nice day!');
echo json_encode($status);
Next we take a look at the script that calls the web service. In the web service I added some prints that shows what we send, what we receive and what the object we get back looks like.
// call.php
<?php
// Here is the url to our web service
$url = "http://www.johanbroddfelt.se/samples/48_ws_auth/ws.php";
// The username and password used to access the service
$username = 'John';
$password = 'Doe';
// Her we create a quite large object for such a simple sample, but I wanted to show you how a larger
// structure could look like if you might need some of the structures in your code
$jObj = new stdClass();
$jObj->name = 'John Doe';
$jObj->age = 44;
// Here we create an object inside our main object
$location = new stdClass();
$location->address = "Homestreet 7";
$location->zip = "1234";
$location->city = "Hometown";
$jObj->location = $location;
// Here is an array, just to show some different kinds of data
$pObj1 = new stdClass();
$pObj1->brand = "Viper";
$pObj1->year = 1997;
$carArr[] = $pObj1;
$pObj2 = new stdClass();
$pObj2->brand = "Volvo";
$pObj2->year = 2013;
$carArr[] = $pObj2;
$jObj->cars = $carArr;
// Here we encode the object to a JSON string so that we can send it
$content = json_encode($jObj);
echo 'Sending: ' . $content . '<br>';
$options = array('http' =>
array(
'method' => 'POST',
'header' => "Content-type: application/json" . PHP_EOL
. "Accept: application/json" . PHP_EOL
. "Authorization: Basic " . base64_encode("$username:$password"),
'content' => $content
)
);
$context = stream_context_create($options);
$json_response = file_get_contents($url, false, $context);
echo 'JSON response: ' . $json_response . '<br>';
$response = json_decode($json_response, true);
echo 'Object: ';
var_dump($response);
This should work fine, but there might be one more thing that you need to do. I did at least. For some reason if your server is configured to use CGI then you also need to add the following lines to your .htaccess file.
RewriteEngine on
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
And that finally got my sample to work as you can see here: Sample Web Service
- php, webservice, rest, basic authentication, json, software
Comment
https://ose-gw1.efact.pe:443/api-efact-ose/oauth/token
Headers Authentication
Username: client
Pasword: secret
that data gave me
- If you look in the definition (https://www.php.net/manual/en/context.http.php) it can be either an array or a string. In my case the editor had removed the new line characters. I have now updated with the PHP_EOL instead of n r with backslashes that my editor removed.
- About the PHP_AUTH_USER I believe the intention for the second one was to check if it was not empty. I have updated the code.