Johan Broddfelt
/* Comments on code */

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

Follow using RSS

<< Same size buttons MySQL to DB2 >>

Comment

Name
Mail (Not public)
Send mail uppdates on new comments
6 comments
Thanks for the feedback!

- 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.​
2021-01-27 21:52:33 - Johan
Sorry, meant "The header in the options array is also an array (call.​​php)". Tired :)
2021-01-27 21:09:39 - charlyarg
Excellent, thanks a lot. A couple of mistakes in the code, though. The header in the options array is also a header (call.​php). Also you repeated PHP_AUTH_USER in the evaluation (ws.​php). The htaccess fix was the real saviour. Had to put it at the bottom else it would mess up my Codeigniter redirections.​
2021-01-27 21:08:52 - charlyarg
You need to get the documentation as well. If you try the url https://ose-gw1.​efact.​pe/​api-efact-ose/​oauth/​token in the browser you can at least login. So, it should be possible from the server as well.​
2019-03-19 12:15:13 - Johan
I have a web service rest that I need to consume but I can not do it
https://ose-gw1.​efact.​pe:443/​api-efact-ose/​oauth/​token
Headers Authentication
Username: client
Pasword: secret
that data gave me
2018-06-07 00:33:01 - Paulo Romero
very good post, I would like you to help me with a similar case I want to consume a web service rest
2018-06-06 23:34:11 - Paulo Romero