<?php
// books.php
// Output book data from a text file in JSON format.
// Adapted by Morgan Doocy for INFO 343, Autumn 2012
// Originally by Marty Stepp, CSE 190 M
// File to read book data from.
$INPUT_FILE = "books.txt";
// Disallow anything other than POST requests.
if ($_SERVER["REQUEST_METHOD"] != "GET") {
http_die(400, "Invalid Request", "ERROR 400: Invalid request - This service accepts only GET requests.");
}
// Error if unknown parameters passed.
$unknown = array_diff(array_keys($_REQUEST), array('category', 'delay'));
if (count($unknown)) {
http_die(400, "Invalid Request", "ERROR 400: Invalid request - Unrecognized parameter(s) passed: " . implode(", ", $unknown));
}
// Ensure file is readable.
if (!file_exists($INPUT_FILE) || !is_readable($INPUT_FILE)) {
http_die(500, "Server Error", "ERROR 500: Server error - Unable to read input file: $INPUT_FILE");
}
// Delay specified number of seconds (optional).
if (isset($_REQUEST['delay'])) {
$delay = max(0, min(60, (int) sanitize($_REQUEST["delay"])));
sleep($delay);
}
// Load input file.
$books = array_map('line2book', file($INPUT_FILE, FILE_IGNORE_NEW_LINES));
// Output JSON data.
if (isset($_REQUEST['category'])) {
// Category specified - filter out books that aren't of the specified
// category, and output the resulting list in JSON.
$category = sanitize($_REQUEST['category']);
$count = count($books);
for ($i = 0; $i < $count; $i++) {
if ($books[$i]['category'] != $category) {
unset($books[$i]);
}
}
print_json(array_values($books));
} else {
// No category specified - get a list of the categories present in file,
// and output that list in JSON.
$categories = array();
foreach ($books as $book) {
if (!in_array($book['category'], $categories)) {
array_push($categories, $book['category']);
}
}
sort($categories);
print_json($categories);
}
// === Functions ===
// Output the given data as JSON, with an application/json header.
function print_json($data) {
header("Content-type: application/json");
print pretty_print(json_encode($data));
}
// Convert a line from the input file into an array of properties/values.
function line2book($line) {
$props = array('title', 'author', 'category', 'year', 'price');
$values = explode('|', $line);
return array_combine($props, $values);
}
// Die with the given HTTP status code and message.
function http_die($code, $status, $msg) {
header("HTTP/1.1 $code $status");
header("Content-type: text/plain");
die($msg);
}
// Removes all characters except letters/numbers from query parameters
function sanitize($str) {
return preg_replace("/[^A-Za-z0-9_]*/", "", $str);
}
// Return a human-readable version the given JSON.
// Adapted from http://www.php.net/manual/en/function.json-encode.php#80339
function pretty_print($input) {
$tab = "\t";
$nl = "\n";
$indent = 0;
$in_string = false;
$indented_array = false;
$output = "";
for ($i = 0; $i < strlen($input); $i++) {
$char = $input[$i];
$before = $after = '';
if (!$in_string) {
switch ($char) {
case '{':
case '[':
$after = $nl . str_repeat($tab, ++$indent);
break;
case '}':
case ']':
$before = $nl . str_repeat($tab, --$indent);
break;
case ',':
$after = $nl . str_repeat($tab, $indent);
break;
case ':':
$after = " ";
break;
case '"':
if ($i == 0 || $input[$i-1] != '\\') {
$in_string = true;
}
}
} else if ($char == '"' && $input[$i-1] != '\\') {
$in_string = false;
}
$output .= $before . $char . $after;
}
return $output;
}
?>