Serving API Requests in PHP

Your PHP program can serve API requests to clients as well. Instead of generating a plain HTML page, you generate whatever data is appropriate to the API call. Addi­tionally, you may need to manipulate the HTTP response code and response headers you send.

To send an HTTP header along with your response, use the header() function. Example 11-15 is a tiny clock API in PHP. It serves up the current time in JSON format.

Example 11-15. Serving a JSON response

$response_data = array(‘now’ => time());

header(‘Content-Type: apptication/json’);

print json_encode($response_data);

The call to header() in Example 11-15 adds a header line to the HTTP response that the PHP engine generates. The header line is whatever you pass to the function. The code uses the json_encode() function to generate the JSON that makes up the response. This function is the opposite of json_decode(). You give it a PHP data type (string, number, object, array, etc.) and it returns a string containing the JSON repre­sentation of what was passed in. Example 11-15 generates an HTTP response that looks like this:

HTTP/1.1 200 OK

Host: www.exampte.com

Connection: close

Content-Type: apptication/json

{“now”:1962258300}

The first four lines are the response headers. A few get added automatically by your web server. The Content-Type: apptication/json line is from the call to header(). After the blank line comes the request body. This is the stuff you see in your web browser (or, if it’s HTML, you see the results of your web browser rendering the HTML). In this case, the request body is a JSON object with one property, now, whose value is a timestamp corresponding to the current time. The value you get when you run this code will almost certainly be different because you are almost certainly run­ning this code at a different time than the timestamp printed here. For more details on time handling in PHP, see Chapter 15.

The first line of the response headers contains the response code, which in this case is 200—which is HTTP-speak for “everything was fine.” To send a different response code, use the http_response_code() function. Example 11-16 is like Example 11-15 except it sends back a 403 status code (“Forbidden”) and an error response body unless a query string parameter named key is supplied with a value of pineapple.

Example 11-16. Changing the response code

if (! (isset($_GET[‘key’]) && ($_GET[‘key’] == ‘pineapple’))) {

http_response_code(403);

$response_data = array(‘error’ => ‘bad key’);

}

else {

$response_data = array(‘now’ => time());

}

header(‘Content-Type: application/json’);

print json_encode($response_data);

Without the proper query string parameter supplied, Example 11-16’s response looks like this:

HTTP/1.1 403 Forbidden Host: www.example.com Connection: close Content-Type: application/json

{“error”:”bad key”}

Example 11-4 used a Content-Type header to tell the NDB API to send back a response as JSON. To access incoming request headers from your PHP program, look in the $_SERVER array. Each incoming header is there. A header’s array key is HTTP_ followed by the header’s name in all uppercase and with any dashes (-) converted to underscores (_). For example, the value of an incoming Content-Type header would be in $_SERVER[‘HTTP_CONTENT_TYPE’]. Example 11-17 examines the value of an incoming Accept header to determine how to format the output data.

Example 11-17. Examining a request header

<?php

// Formats we want to support

$formats = array(‘application/json’,’text/html’,’text/plain’);

// Response format if not specified

$default_format = ‘application/json’;

// Was a response format supplied?

if (isset($_SERVER[‘HTTP_ACCEPT’])) {

// If a supported format is supplied, use it

if (in_array($_SERVER[‘HTTP_ACCEPT’], $formats)) {

$format = $_SERVER[‘HTTP_ACCEPT’];

}

// An unsupported format was supplied, so return an error

else {

// 406 means “You want a response in a format I can’t generate”

http_response_code( 406 );

// Exiting now means no response body, which is OK

exit();

}

} else {

$format = $default_format;

}

// Figure out what time it is

$response_data = array(‘now’ => time());

// Tell the client what kind of content we’re sending

header(“Content-Type: $format”);

// Print the time in a format-appropriate way

if ($format == ‘application/json’) {

print json_encode($response_data);

}

else if ($format == ‘text/html’) { ?>

<!doctype html>

<html>

<head><title>Clock</title></head>

<body><time><?= date(‘c’, $response_data[‘now’]) ?></time></body>

</html>

<?php

} else if ($format == ‘text/plain’) {

print $response_data[‘now’];

}

If the incoming Accept header is application/json, text/html, or text/plain, then $format is set to the proper format to use. This value gets put in the Content-Type header of the response and is used to generate a format-appropriate output. If no Accept header is supplied, a default of application/json is used. If any other value is supplied in the Accept header, then the program returns an empty body with a 406 error code. This tells the client that an invalid format was asked for.

The $_SERVER array is also where you look to determine if the current request is a secure request; that is, if it was made with HTTPS. If the current request is secure, then $_SERVER[‘HTTPS’] is set to on. Example 11-18 checks if the current request was made over HTTPS and redirects to an HTTPS version of the current request’s URL if not.

Example 11-18. Checking for HTTPS

$is_https = (isset($_SERVER[‘HTTPS’]) && ($_SERVER[‘HTTPS’] == ‘on’));

if (! $is_https) {

$newUrl = ‘https://’ . $_SERVER[‘HTTP_HOST’] . $_SERVER[‘REQUEST_URI’];

header(“Location: $newUrl“);

exit();

}

print “You accessed this page over HTTPS. Yay!“;

In Example 11-18, the first line determines whether the current request was over HTTPS by ensuring two things: first, that there is a value set for $_SERVER[‘HTTPS’] and second, that the value is on. If both of those things are not true, then an HTTPS version of the current URL is built by combining the right protocol (https://) with the current request’s hostname (the value of $_SERVER[‘HTTP_HOST’]) and the cur­rent request’s path (the value of $_SERVER[‘REQUEST_URI’]). If the request included any query string parameters, those are included in $_SERVER[‘REQUEST_URI’] as well. The Location header, sent by the header() function, redirects a web client to a new URL.

Source: Sklar David (2016), Learning PHP: A Gentle Introduction to the Web’s Most Popular Language, O’Reilly Media; 1st edition.

Leave a Reply

Your email address will not be published. Required fields are marked *