PHP Web Services with File I/O
Building and using a PHP JSON API
Q: What is the one thing that PHP does well that JavaScript isn't well known for?
File processing
Q: From the client perspective, what is an advantage of JSON over plain text?
Easier to parse structured data, less error prone than using straight indices
Recall: What are the functions to do PHP file I/O?
file(filename)
: returns lines of a file as an array (
\n
at end of each item).
file(filename, FILE_IGNORE_NEW_LINES)
: returns lines of a file as an array
with no \n
at the end of each item.
file_get_contents(filename)
returns entire contents of a file as a single string.
file_put_contents(filename, output)
writes a string into a file, overwriting
existing content
file_put_contents(filename, output, FILE_APPEND)
writes a string into a file,
appending the content to the existing file.
Recall: What are the PHP functions that can get information from directories on the server?
function | description |
---|---|
glob | returns an array of all file names that match a given pattern (returns a file path and name, such as "foo/bar/myfile.txt") |
scandir | returns an array of all file names in a given directory (returns just the file names, such as "myfile.txt") |
Can accept a general path with the * wildcard (more powerful).
glob
Example# reverse all poems in the poetry directory
$poems = glob("poetry/poem*.dat");
foreach ($poems as $poemfile) {
$text = file_get_contents($poemfile);
file_put_contents($poemfile, strrev($text));
echo "I just reversed " . basename($poemfile) . "\n";
}
glob can match a wildcard path with the * character
glob("foo/bar/*.doc")
returns all .doc files in the foo/bar
subdirectoryglob("food*")
returns all files whose names begin with "food"The basename
function strips any leading directory from a file path
basename("foo/bar/baz.txt")
returns "baz.txt"scandir
Exampleforeach (scandir("taxes/old") as $filename) {
echo "I found a file: {$filename}\n";
}
I found a file: .
I found a file: ..
I found a file: 2007_w2.pdf
I found a file: 2006_1099.doc
scandir
includes current directory (".") and parent ("..") in the array.
Don't need basename
with scandir
; returns file names only
without directory
<?php
header("Content-Type: application/json");
$output = array();
$output["name"] = "Miranda";
$output["hobbies"] = array("pottery", "softball",
"cycling", "watching youtube");
print(json_encode($output));
?>
Produces:
{
"name":"Miranda",
"hobbies":["pottery","softball"]
}
<h1>JSON Test</h1>
<button>Get JSON data.</button>
<h2>Response</h2>
<p id="response"></p>
function loadData(data) {
let response = $("response");
response.innerText = data["name"];
let p = document.createElement("p");
p.innerText = "Hobbies";
response.appendChild(p);
let ul = document.createElement("ul");
response.appendChild(ul);
for(let i = 0; i < data["hobbies"].length; i++) {
let li = document.createElement("li");
li.innerText = data["hobbies"][i];
ul.appendChild(li);
}
}
You first need to determine how your users interact with your API. Questions you can yourself might be:
For our Points of Interest API we want three types of data:
The general format of the response could look like the following for all of our cities
{
"cities" : [
{
"name": "Seattle",
"sites": [
{
"name": "Space Needle",
"image": "....",
"review": ".... "
}
]
},
{
"name": "New York",
"sites": [
{
"name": "Ellis Island",
"image": "...."
"review": ".... "
},
{
"name": "Statue of Liberty",
"image": "...."
"review": ".... "
}
]
}
...
]
}
Think of the conditionals you need to handle your request
Remember to check if the $_GET
and $_POST
indices for those
requests are set (using isset
), and handle the error correctly if not.
You can use conditional statements to figure out which query parameter to handle.
Remember to be careful about using $_GET
vs $_POST
where
needed (for now we're using $_GET
).
Oh and don't forget to handle other error cases as well.
Put the correct headers in each part of the conditional.... then look to see if there is any refactoring you can do!
header
header("Content-type: type/subtype");
Most of the time we'll use
header("Content-type: text/plain");
or
header("Content-type: application/json");
Also remember that in error cases we want to send back the Invalid Request header
header("HTTP/1.1 400 Invalid Request");
Remember that you can not print
or echo
before a header
statement.
How will your data be stored on the server?
How will you convert the data into the right format for sending back to the caller
Talk with your neighbor: Try to list at least 5 Code Quality standards we expect to achieve for your JS in this course (e.g. as specific as "line lengths < 100 characters" or "good variable descriptive identifier names")
Those may include
These same code quality guidelines should transfer over to your PHP.
Your conditional statement that handles the request should not be in a function, but the code in the body of each condition should be fairly short. Use functions to encapsulate code.
Write your PHP with PHP specific naming conventions (like variable_names), use good indentation and curly brace style, localize variables as much as possible, ... and comment your code.