CSE 154

Lecture 18: PHP Web Services with File I/O

Agenda

Important Course Details

Associative Arrays

PHP File I/O

PHP Web Services with File I/O

Important course details

  • The resources page is a really repository helpful!
  • Exploration session tomorrow on Websockets 5:00-6:20
  • WPL Location change today (see Piazza)
  • "Picking up" exams (on Gradescope)
  • CP4 out
  • IMPORTANT info about turning in HW 3
    • If you accepted HW 3 Milestone 1 and turned that in before you accepted HW 3 Completed your pokedex.js will be copied to your new repository when you accept HW 3 Completed
    • If you accepted both HW 3 M1 and HW 3 Completed at the same time, you *MUST* copy your pokedex.js to your new (second) repository before you turn in.

More Useful PHP

Keep these in mind as we work through these slides

NULL

$name = "Pascal";
$name = NULL;
if (isset($name)) {
  echo "This line isn't going to be printed";
}

PHP

A variable is NULL if

  • It has not been set to any value (undefined)
  • It has been assigned the constant NULL
  • It has been deleted using the unset function

Can test if a variable is NULL using the isset function

NULL prints as an empty string (no output)

Variable scope: global

$school = "UW";               # global
  ...

function downgrade() {
  global $school;
  $suffix = "(Wisconsin)";    # local

  $school = "$school $suffix";
  echo "$school\n";
}

PHP

Variables declared in a function are local to that function; others are global

If a function wants to use a global variable, it must have a global statement

  • globals should be considered more of a "last resort"
  • remember to localize as much as possible
  • remember you should mostly use parameters to pass information between functions

Default Parameter Values

function name(parameterName=value, ..., parameterName=value) {
  statements;
}

PHP (template)

function print_separated($str, $separator=", ") {
  if (strlen($str) < 0) {
    echo $str[0];
    for ($i = 1; $i < strlen($str); $i++) {
      echo $separator . $str[$i];
    }
  }
}
print_separated("hello");      # h, e, l, l, o
print_separated("hello", "-"); # h-e-l-l-o

PHP (example)

If no value is passed, the default will be used (defaults must come last)

Associative Arrays

Associative Arrays

Associative arrays are arrays that have keys with assigned values (similar to Maps in Java, dictionaries in Python, or JSON objects in JS)

$tas = array("AA" => "Connie Wang", "AB" => "Jack Venberg",
             "AC" => "William Kim", "AD" => "Kelley Chen",
             "AE" => "Sweekruthi Raghunathan", "AF" => "Jeffrey Worley",
             "AI" => "Sven Hansen", "AJ" => "Anupam Gupta",
             "AK" => "Conner Ardman", "AL" => "Andrew Wolfram");
$tas["ZZ"] = "Jeremy Zhang";

PHP

$ages = array(); # empty array (length 0)
$ages["Whitney"] = 17; # stores 17 at the location where "Whitney" is stored

PHP

These will be very useful when writing JSON-based web services in PHP!

The foreach loop for arrays

A convenient way to loop over each element of an array without indices

            foreach ($array as $variableName) {
  ...
}

PHP (template)

$pups = array("Mowgli", "Abby", "Archie", "Pascal");
foreach ($pups as $pup) {
  echo "Mowgli boops $pup\n"; # even himself
}

PHP (example)

Mowgli boops Mowgli
Mowgli boops Abby
Mowgli boops Archie
Mowgli boops Bailey

Output

The foreach loop for associative arrays arrays

foreach ($array_name as $key => $value)  {
  ...
}

PHP (template)

$tas = array("AA" => "Connie Wang", ...);
foreach ($tas as $section => $ta)  {
  echo "$ta leads section $section.\n";
}

PHP (example)

Connie Wang leads section AA.
Jack Venberg leads section AB.
William Kim leads section AC.
Kelley Chen leads section AD.
...

Output

array_key_exists

Note: in_array tests whether a value is in an array

array_key_exists tests whether a key is in an array

$tas = array("AA" => "Connie Wang", ...);
in_array("AA", $tas);      # false
array_key_exists("AA", $tas);   # true

PHP (example)

Web Services

Review: Web Services

Web service: software functionality that can be invoked through the internet using common protocols

Like a remote function(s) you can call by contacting a program on a web server

  • Many web services accept parameters and produce results

Can be written in PHP and contacted by the browser in HTML and/or AJAX code

Service's output might be HTML but could be text, XML, JSON, or other content

Review: GET and POST

There are two common ways to make AJAX requests to a server.

  • GET requests
    • are the default, most of what we've seen have been GET requests
    • retrieve or get information from the server
  • POST requests
    • send information to the server
    • often change information on the server

Query Parameters in PHP

  • PHP includes built-in associative arrays to hold GET and POST parameters called $_GET and $_POST
  • You can access these parameters by putting the parameter name as a string index for the GET/POST array.
  • For example, to access a GET parameter name, reference it in PHP as $_GET["name"]
  • If it were instead passed as a POST parameter (e.g. through FormData with fetch) you would access it in PHP with $_POST["name"]
  • Most of the web services you will write in this class will accept GET parameters, but when we start using PHP to update files/databases, we will use POST requests to modify this data on the server.

Example of GET in PHP

For a GET url with parameters passed, like:
hello.php?name=mowgli&age=2

<?php
  $name = $_GET["name"];
  $age = (int) $_GET["age"];
  $dog_age = $age * 7;
  echo "Hi {$name}! You are {$age} years old! " .
       "That's {$dog_age} in dog years!";
?>

PHP

Example of POST in PHP

For a POST to url with parameters passed, like:

let url = ..... // put url string here
let data =  new FormData();
data.append("username", "Kyle");
data.append("password", "cse!54webz");
data.append("word", "duck");
data.append("definition", "a debugger friend");

fetch(url, {method: "POST", body: data})
...

JS

PHP Code:

$username = $_POST["username"];
$password = $_POST["password"];
$users_pw_hash = db_lookup_hashed_pw($username);

if (password_hash($password) == $users_pw_hash) {
  print("Successfully logged in!");
  // code to update word/definition to a file on the server
}

PHP

Checking before using

Good practice #1: It is good practice to check if a variable is set before using it

<?php
header("Content-type: text/html");
if (isset($_GET["name"]) && issset($_GET["age"])) {
  $name = $_GET["name"];
  $age = (int) $_GET["age"];
  $dog_age = $age * 7;
  echo "Hi {$name}! You are {$age} years old! " .
  "That's {$dog_age} in dog years!";
}
else {
  echo "You need to pass in the name and age parameters!";
}
?>

Recall: Content ("MIME") Types

When we first talked about the internet, we introduced "Content Types"

MIME type file extension
text/html .html
text/plain .txt
image/gif .gif
image/jpeg .jpg
video/quicktime .mov
application/octet-stream .exe

Lists of MIME types: by type, by extension

Now let's build a web service

Setting Content Type with header

header("Content-type: type/subtype");

PHP (template)

header("Content-type: type/plain");
echo "This output will appear as plain text now!\n";

PHP (example)

By default, a PHP file's output is assumed to be HTML (text/html)

However, in this course we aren't using PHP to generate HTML, so we use the header function to specify non-HTML output

  • The header must appear before any other output generated by the script
  • (doesn't have to be the first line of code, though)

Example: Points of Interest Web Service

Write a web service that accepts a city and outputs an attraction that you should visit in that city

http://example.com/pointsofinterest.php?city=Seattle

GET request

The best place to visit in Seattle is Space Needle.

Output

Solution

<?php
  header("Content-type: text/plain");
  $attractions = array("Seattle" => "Space Needle",
                        "New York" => "Ellis Island",
                        ... );
  $city = $_GET["city"];       # What should be done here to prevent errors?
  echo "The best place to visit in " . $city .  " is " .
        $attractions[$city] . ".\n";
?>

PHP

Example: Points of Interest Web Service

What if we want to return all of the cities/points of interest?

http://example.com/pointsofinterest.php?city=all

GET request

{
  "Seattle":"Space Needle",
  "New York":"Ellis Island",
  ...
  "San Franciso":"Fisherman's Warf"
}

JSON Output

Solution

<?php
  $attractions = array("Seattle" => "Space Needle",
                        "New York" => "Ellis Island",
                        ... );
  $city = $_GET["city"];
  if (strcmp($city, "all") == 0) {
    header("Content-type: application/json");
    print_r(json_encode($attractions));
  }
?>

PHP

Returning JSON from PHP

We use the PHP function json_encode(array) to output JSON

json_encode takes PHP arrays (including nested arrays) and generates JSON strings that can be printed

NOTE: we can also use json_decode to convert json strings into PHP arrays.

PHP File I/O

PHP I/O Functions

function name(s) category
file, file_get_contents, file_put_contents reading/writing entire files
basename, file_exists, filesize, fileperms, filemtime, is_dir, is_readable, is_writable, disk_free_space asking for information
copy, rename, unlink, chmod, chgrp, chown, mkdir, rmdir manipulating files and directories
glob, scandir reading directories

Reading/Writing Files

contents of foo.txt file("foo.txt") file_get_contents("foo.txt")
Hello
      how r u?

      I'm fine

                    
array("Hello\n", #0
      "how r u?\n",    #1
      "\n",            #2
      "I'm fine\n"     #3
      )
                    
"Hello\n
      how r u\n    # a single
      \n           # string
      I'm fine\n"
                    

The file function returns lines of a file as an array (\n at end of each).

file_get_contents returns entire contents of a file as a single string.

file_put_contents writes a string into a file.

The file Function

file returns the lines of a file as an array of strings.

But each ends with \n; to strip it, use an optional second parameter:

$cities = file("cities.txt");
foreach ($cities as $city) { # for ($i = 0; $i < count($cities); $i++)
  echo $city;               # no newline needed here!
}

PHP

$lines = file("cities.txt", FILE_IGNORE_NEW_LINES);

PHP

Common idiom: foreach or for loop over lines of file

Reading/Writing an Entire File

# reverse a file
    $text = file_get_contents("poem.txt");
    $text = strrev($text);
    file_put_contents("poem.txt", $text);

PHP

file_get_contents returns entire contents of a file as a string

  • if the file doesn't exist, you will get a warning and an empty return string

file_put_contents writes a string into a file, replacing its old contents

  • if the file doesn't exist, it will be created

Appending to a File

# add a new line to a file
    $new_text = "P.S. ILY, GTG TTYL!~";
    file_put_contents("poem.txt", $new_text, FILE_APPEND);

PHP

old contents new contents
Roses are red
Violets are blue
All my base
Are belong to you.
Roses are red
Violets are blue
All my base
Are belong to you.
P.S. ILY, GTG TTYL!~

file_put_contents can be called with an optional third parameter to append (add to end) rather than overwrite.

Splitting/Joining Strings

$array = explode(delimiter, string);
$string = implode(delimiter, array);

PHP (template)

$s = "CSE 154 A";
$a = explode(" ", $s);     # ("CSE", "154", "A")
$s2 = implode("...", $a);  # "CSE...154...A"  

PHP (example)

explode and implode convert between strings and arrays.

For more complex strings, you can use regular expressions.

Example with explode

Seattle, Space Needle
Seattle, Space Needle
New York, Ellis Island
Boston, Boston Harbor
Philadelphia, Valley Forge

contents of cities.txt

foreach (file("cities.txt", FILE_IGNORE_NEW_LINES) as $city) {
  $tokens = explode(",", $city);
  echo "The best place to visit in " . $tokens[0] .
         " is " . $tokens[1] . ".\n";
}

PHP

The best place to visit in Seattle is Space Needle.
The best place to visit in New York is Ellis Island.
The best place to visit in Boston is Boston Harbor.
The best place to visit in Philadelphia is Valley Forge.

output

Unpacking an array: list

The list function "unpacks" an array into a set of variables.

When you now a file or line's exact length/format, use file and list to unpack it

list($var1, ..., $varN) = array;

PHP (template)

Kyle Thayer
(206) 154 2017
17-154-0123

contents of personal.txt

list($name, $phone, $ssn) = file("personal.txt");
...
list($area_code, $prefix, $suffix) = explode(" ", $phone);  

PHP

Reading Directories

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";
}

PHP

glob can match a wildcard path with the * character

  • glob("foo/bar/*.doc") returns all .doc files in the foo/bar subdirectory
  • glob("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 Example

foreach (scandir("taxes/old") as $filename) {
  echo "I found a file: {$filename}\n";
}

PHP

I found a file: .

I found a file: ..

I found a file: 2007_w2.pdf

I found a file: 2006_1099.doc

output

scandir includes current directory (".") and parent ("..") in the array.

Don't need basename with scandir; returns file names only without directory

Code Quality in a Web Service

Code Quality in JS

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

  • Using proper naming conventions (camelCase and ALL_CAPS) for JS
  • Good indentation and curly brace style (either stacked or K&R)
  • Using descriptive JSdoc to comment functions
  • Use the module pattern and "use strict;"
  • Localizing variables, not overusing globals
  • Using functions to capture functionality
  • Refactoring common code and sub-operations into function
  • Do not mix HTML/CSS/JS

Code Quality in PHP

These same code quality guidelines should transfer over to your PHP.

Demo