Skip to content

Instantly share code, notes, and snippets.

@Mwamitovi
Last active January 29, 2025 06:44
Show Gist options
  • Save Mwamitovi/e444dc06c6b13c6ca9369dccbd3c7bb4 to your computer and use it in GitHub Desktop.
Save Mwamitovi/e444dc06c6b13c6ca9369dccbd3c7bb4 to your computer and use it in GitHub Desktop.
learningPHP: Chapters
<?php
// Chapter - 2: Exercises
// Question-1
// 1. Find the errors in this PHP program:
// 1. The opening PHP tag should be just <?php with no space between the <? and php.
// 2. Because the string I'm fine contains a ',
// it should be surrounded by double quotes ("I'm fine") or the ' should be escaped ('I\'m fine').
// 3. The closing PHP tag should be \?\>, not ?\?\>.
// Or, if this code were the last thing in its file, the closing PHP tag could be omitted.
// Question-2
// 2. Write a PHP program that computes the total cost of this restaurant meal: two
// hamburgers at $4.95 each, one chocolate milkshake at $1.95, and one cola at 85
// cents. The sales tax rate is 7.5%, and you left a pre-tax tip of 16%.
// Answer-2
$hamburger = 4.95;
$shake = 1.95;
$cola = 0.85;
$tip_rate = 0.16;
$tax_rate = 0.075;
$food = (2 * $hamburger) + $shake + $cola;
$tip = $food * $tip_rate;
$tax = $food * $tax_rate;
$total = $food + $tip + $tax;
print 'The total cost of the meal is $' . $total;
// Question-3
// 3. Modify your solution to the previous exercise to print out a formatted bill. For
// each item in the meal, print the price, quantity, and total cost. Print the pre-tax
// food and drink total, the post-tax total, and the total with tax and tip. Make sure
// that prices in your output are vertically aligned.
// Answer-3
$hamburger = 4.95;
$shake = 1.95;
$cola = 0.85;
$tip_rate = 0.16;
$tax_rate = 0.075;
$food = (2 * $hamburger) + $shake + $cola;
$tip = $food * $tip_rate;
$tax = $food * $tax_rate;
$total = $food + $tip + $tax;
printf("%d %-9s at \$%.2f each: \$%5.2f\n", 2, 'Hamburger', $hamburger, 2 * $hamburger);
printf("%d %-9s at \$%.2f each: \$%5.2f\n", 1, 'Shake', $shake, $hamburger);
printf("%d %-9s at \$%.2f each: \$%5.2f\n", 1, 'Cola', $cola, $cola);
printf("%25s: \$%5.2f\n", 'Food Total', $food);
printf("%25s: \$%5.2f\n", 'Food and Tax Total', $food + $tax);
printf("%25s: \$%5.2f\n", 'Food, Tax, and Tip Total', $total);
// Question-4
// 4. Write a PHP program that sets the variable $first_name to your first name and
// $last_name to your last name. Print out a string containing your first and last
// name separated by a space. Also print out the length of that string.
// Answer-4
$first_name = 'Srinivasa';
$last_name = 'Ramanujan';
$name = "$first_name $last_name";
print $name;
print strlen($name);
// Question-5
// 5. Write a PHP program that uses the increment operator (++) and the combined
// multiplication operator (*=) to print out the numbers from 1 to 5 and powers of
// 2 from 2 (21) to 32 (25).
// Answer-5
$n = 1;
$p = 2;
print "$n, $p\n";
$n++;
$p *= 2;
print "$n, $p\n";
$n++;
$p *= 2;
print "$n, $p\n";
$n++;
$p *= 2;
print "$n, $p\n";
$n++;
$p *= 2;
print "$n, $p\n";
// Question-6
// 6. Add comments to the PHP programs you’ve written for the other exercises. Try
// both single and multiline comments. After you’ve added the comments, run the
// programs to make sure they work properly and your comment syntax is correct.
<?php
// Chapter - 3: Exercises
// Question-1
// 1. Without using a PHP program to evaluate them, determine whether each of
// these expressions is true or false:
// a. 100.00 - 100
// b. "zero"
// c. "false"
// d. 0 + "true"
// e. 0.000
// f. "0.0"
// g. strcmp("false","False")
// h. 0 <=> "0"
// Answer-1
// 1. false
// 2. true
// 3. true
// 4. false
// 5. false
// 6. true
// 7. true
// 8. false
// Question-2
// 2. Without running it through the PHP engine, figure out what this program prints:
// $age = 12;
// $shoe_size = 13;
// if ($age > $shoe_size) {
// print "Message 1.";
// } elseif (($shoe_size++) && ($age > 20)) {
// print "Message 2.";
// } else {
// print "Message 3.";
// }
// print "Age: $age. Shoe Size: $shoe_size";
// Answer-2
// Message 3.Age: 12. Shoe Size: 14
// Question-3
// 3. Use while() to print a table of Fahrenheit and Celsius temperature equivalents
// from –50 degrees F to 50 degrees F in 5-degree increments. On the Fahrenheit
// temperature scale, water freezes at 32 degrees and boils at 212 degrees. On the
// Celsius scale, water freezes at 0 degrees and boils at 100 degrees. So, to convert
// from Fahrenheit to Celsius, you subtract 32 from the temperature, multiply by 5,
// and divide by 9. To convert from Celsius to Fahrenheit, you multiply by 9, divide
// by 5, and then add 32.
// Answer-3
$f = -50;
while ($f <= 50) {
$c = ($f - 32) * (5 / 9);
printf("%d degrees F = %d degrees C\n", $f, $c);
$f += 5;
}
// 4. Modify your answer to Exercise 3 to use for() instead of while().
// Answer-4
for ($f = -50; $f <= 50; $f += 5) {
$c = ($f - 32) * (5 / 9);
printf("%d degrees F = %d degrees C\n", $f, $c);
}
<?php
// Chapter-4: Exercises
// Question-1
// 1. According to the US Census Bureau, the 10 largest American cities (by population) in 2010 were as follows:
// • New York, NY (8,175,133 people)
// • Los Angeles, CA (3,792,621)
// • Chicago, IL (2,695,598)
// • Houston, TX (2,100,263)
// • Philadelphia, PA (1,526,006)
// • Phoenix, AZ (1,445,632)
// • San Antonio, TX (1,327,407)
// • San Diego, CA (1,307,402)
// • Dallas, TX (1,197,816)
// • San Jose, CA (945,942)
//
// Define an array (or arrays) that holds this information about locations and populations.
// Print a table of locations and population information that includes the total population in all 10 cities.
// Answer-1 ?>
<table>
<tr>
<th>City</th>
<th>Population</th>
</tr>
<?php
$census = [
'New York, NY' => 8175133,
'Los Angeles, CA' => 3792621,
'Chicago, IL' => 2695598,
'Houston, TX' => 2100263,
'Philadelphia, PA' => 1526006,
'Phoenix, AZ' => 1445632,
'San Antonio, TX' => 1327407,
'San Diego, CA' => 1307402,
'Dallas, TX' => 1197816,
'San Jose, CA' => 945942
];
$total = 0;
foreach ($census as $city => $population) {
$total += $population;
print "<tr><td>$city</td><td>$population</td></tr>\n";
}
print "<tr><td>Total</td><td>$total</td></tr>\n";
print "</table>";
?>
<?php
// Question-2
// 2. Modify your solution to the previous exercise so that the rows in the result table are ordered by population.
// Then modify your solution so that the rows are ordered by city name.
// Answer-2
$census = [
'New York, NY' => 8175133,
'Los Angeles, CA' => 3792621,
'Chicago, IL' => 2695598,
'Houston, TX' => 2100263,
'Philadelphia, PA' => 1526006,
'Phoenix, AZ' => 1445632,
'San Antonio, TX' => 1327407,
'San Diego, CA' => 1307402,
'Dallas, TX' => 1197816,
'San Jose, CA' => 945942
];
// Sort the associative array by value
asort($census);
print "<table>\n";
print "<tr><th>City</th><th>Population</th></tr>\n";
$total = 0;
foreach ($census as $city => $population) {
$total += $population;
print "<tr><td>$city</td><td>$population</td></tr>\n";
}
print "<tr><td>Total</td><td>$total</td></tr>\n";
print "</table>";
// Sort the associative array by key
ksort($census);
print "<table>\n";
print "<tr><th>City</th><th>Population</th></tr>\n";
$total = 0;
foreach ($census as $city => $population) {
$total += $population;
print "<tr><td>$city</td><td>$population</td></tr>\n";
}
print "<tr><td>Total</td><td>$total</td></tr>\n";
print "</table>";
// Question-3
// 3. Modify your solution to the first exercise so that the table also contains rows that hold state population totals for each state represented in the list of cities.
// Answer-3 ?>
<table>
<tr>
<th>City</th>
<th>Population</th>
</tr><?php
// Each element in $census is a three-element array containing city name, state, and population
$census = [
['New York', 'NY', 8175133],
['Los Angeles', 'CA', 3792621],
['Chicago', 'IL', 2695598],
['Houston', 'TX', 2100263],
['Philadelphia', 'PA', 1526006],
['Phoenix', 'AZ', 1445632],
['San Antonio', 'TX', 1327407],
['San Diego', 'CA', 1307402],
['Dallas', 'TX', 1197816],
['San Jose', 'CA', 945942]
];
$total = 0;
$state_totals = array();
foreach ($census as $city_info) {
// Update the total population
$total += $city_info[2];
// If we haven't seen this state yet, initialize its population total to 0
if (!array_key_exists($city_info[1], $state_totals)) {
$state_totals[$city_info[1]] = 0;
}
// Update the per-state population
$state_totals[$city_info[1]] += $city_info[2];
print "<tr><td>$city_info[0], $city_info[1]</td><td>$city_info[2]</td></tr>\n";
}
print "<tr><td>Total</td><td>$total</td></tr>\n";
// Print the per-state totals
foreach ($state_totals as $state => $population) {
print "<tr><td>$state</td><td>$population</td></tr>\n";
}
print "</table>";
// Question-4
// 4. For each of the following kinds of information,
// state how you would store it in an array and then give sample code that creates such an array with a few elements.
// For example, for the first item, you might say, “An associative array whose key is the student’s name
// and whose value is an associative array of grade and ID number,” as in the following:
$students = [
'James D. McCawley' => ['grade' => 'A+', 'id' => 271231],
'Buwei Yang Chao' => ['grade' => 'A', 'id' => 818211]
];
// Answer-4
// a. The grades and ID numbers of students in a class
/* The grades and ID numbers of students in a class:
An associative array whose key is the student's name and whose value is an associative array of grade and ID number
*/
$students = [
'James D. McCawley' => [ 'grade' => 'A+','id' => 271231 ],
'Buwei Yang Chao' => [ 'grade' => 'A', 'id' => 818211]
];
// b. How many of each item in a store inventory are in stock
/* How many of each item in a store inventory are in stock:
An associative array whose key is the item name and whose value is the number in stock
*/
$inventory = [ 'Wok' => 5, 'Steamer' => 3, 'Heavy Cleaver' => 3, 'Light Cleaver' => 0 ];
// c. School lunches for a week: the different parts of each meal (entrée, side dish, drink, etc.) and the cost for each day
/* School lunches for a week — the different parts of each meal (entree, side dish, drink, etc.) and the cost for each day:
An associative array whose key is the day and whose value is an associative array describing the meal.
This associative array has a key/value pair for cost and a key/value pair for each part of the meal.
*/
$lunches = [
'Monday' => [
'cost' => 1.50,
'entree' => 'Beef Shu-Mai',
'side' => 'Salty Fried Cake',
'drink' => 'Black Tea'
],
'Tuesday' => [
'cost' => 2.50,
'entree' => 'Clear-steamed Fish',
'side' => 'Turnip Cake',
'drink' => 'Bubble Tea'
],
'Wednesday' => [
'cost' => 2.00,
'entree' => 'Braised Sea Cucumber',
'side' => 'Turnip Cake',
'drink' => 'Green Tea'
],
'Thursday' => [
'cost' => 1.35,
'entree' => 'Stir-fried Two Winters',
'side' => 'Egg Puff',
'drink' => 'Black Tea'
],
'Friday' => [
'cost' => 3.25,
'entree' => 'Stewed Pork with Taro',
'side' => 'Duck Feet',
'drink' => 'Jasmine Tea'
]
];
// d. The names of people in your family
/* The names of people in your family:
A numeric array whose indices are implicit and whose values are the names of family members
*/
$family = [ 'Bart', 'Lisa', 'Homer', 'Marge', 'Maggie' ];
// e. The names, ages, and relationship to you of people in your family
/* The names, ages, and relationship to you of people in your family:
An associative array whose keys are the names of family members and whose
values are associative arrays with age and relationship key/value pairs
*/
$family = [
'Bart' => [
'age' => 10,
'relation' => 'brother'
],
'Lisa' => [
'age' => 7,
'relation' => 'sister'
],
'Homer' => [
'age' => 36,
'relation' => 'father'
],
'Marge' => [
'age' => 34,
'relation' => 'mother'
],
'Maggie' => [
'age' => 1,
'relation' => 'self'
]
];
<?php
// Chapter-5
// Question-1
// 1. Write a function to return an HTML <img /> tag.
// The function should accept a mandatory argument of the image URL and optional arguments for alt text, height, and width.
// Answer-1
function html_img($url, $alt = null, $height = null, $width = null)
{
$html = '<img src="' . $url . '"';
if (isset($alt)) {
$html .= ' alt="' . $alt . '"';
}
if (isset($height)) {
$html .= ' height="' . $height . '"';
}
if (isset($width)) {
$html .= ' width="' . $width . '"';
}
$html .= '/>';
return $html;
}
// Question-2
// 2. Modify the function in the previous exercise so that only the filename is passed to the function in the URL argument.
// Inside the function, prepend a global variable to the filename to make the full URL.
// For example, if you pass photo.png to the function, and the global variable contains /images/,
// then the src attribute of the returned <img> tag would be /images/photo.png.
// A function like this is an easy way to keep your image tags correct, even if the images move to a new path or server.
// Just change the global variable—for example, from /images/ to http://images.example.com/.
// Answer-2
function html_img2($file, $alt = null, $height = null, $width = null)
{
if (isset($GLOBALS['image_path'])) {
$file = $GLOBALS['image_path'] . $file;
}
$html = '<img src="' . $file . '"';
if (isset($alt)) {
$html .= ' alt="' . $alt . '"';
}
if (isset($height)) {
$html .= ' height="' . $height . '"';
}
if (isset($width)) {
$html .= ' width="' . $width . '"';
}
$html .= '/>';
return $html;
}
// Question-3
// 3. Put your function from the previous exercise in one file.
// Then make another file that loads the first file and uses it to print out some <img /> tags.
// Answer-3
// The html_img2() function from the previous exercise is saved in this file
include "html-img2.php";
$image_path = '/images/';
print html_img2('puppy.png');
print html_img2('kitten.png', 'fuzzy');
print html_img2('dragon.png', null, 640, 480);
// Question-4
// 4. What does the following code print out? ?>
<?php
function restaurant_check($meal, $tax, $tip)
{
$tax_amount = $meal * ($tax / 100);
$tip_amount = $meal * ($tip / 100);
return $meal + $tax_amount + $tip_amount;
}
$cash_on_hand = 31;
$meal = 25;
$tax = 10;
$tip = 10;
while (($cost = restaurant_check($meal, $tax, $tip)) < $cash_on_hand) {
$tip++;
print "I can afford a tip of $tip% ($cost)\n";
}
?><?php
// Answer-4
// I can afford a tip of 11% (30)
// I can afford a tip of 12% (30.25)
// I can afford a tip of 13% (30.5)
// I can afford a tip of 14% (30.75)
// Question-5
// 5. Web colors such as #ffffff and #cc3399 are made by concatenating the hexadecimal color values for red, green, and blue.
// Write a function that accepts decimal red, green, and blue arguments and returns a string containing
// the appropriate color for use in a web page. For example, if the arguments are 255, 0, and 255,
// then the returned string should be #ff00ff. You may find it helpful to use the built-in function dechex(),
// which is documented at http://www.php.net/dechex.
// Answer-5
/* Using dechex(): */
function web_color1($red, $green, $blue)
{
$hex = [dechex($red), dechex($green), dechex($blue)];
// Prepend a leading 0 if necessary to 1-digit hex values
foreach ($hex as $i => $val) {
if (strlen($i) == 1) {
$hex[$i] = "0$val";
}
}
return '#' . implode(
''
,
$hex
);
}
/* You can also rely on sprintf()'s %x format character to do hex-to-decimal conversion: */
function web_color2($red, $green, $blue)
{
return sprintf('#%02x%02x%02x', $red, $green, $blue);
}
// The PricedEntree class referencing that namespace:
class PricedEntree extends Entree {
public function __construct($name, $ingredients) {
parent::__construct($name, $ingredients);
foreach ($this->ingredients as $ingredient) {
if (! $ingredient instanceof \Meals\Ingredient) {
throw new Exception('Elements of $ingredients must be Ingredient objects');
}
}
}
public function getCost() {
$cost = 0;
foreach ($this->ingredients as $ingredient) {
$cost += $ingredient->getCost();
}
return $cost;
<?php
// Chapter-7: Exercises
// Question-1
// 1. What does $_POST look like when the following form is submitted with the third option in the Braised Noodles menu selected,
// the first and last options in the Sweet menu selected, and 4 entered into the text box? ?>
<form method="POST" action="order.php">
Braised Noodles with: <select name="noodle">
<option>crab meat</option>
Chapter Summary | 153
<option>mushroom</option>
<option>barbecued pork</option>
<option>shredded ginger and green onion</option>
</select>
<br />
Sweet: <select name="sweet[]" multiple>
<option value="puff"> Sesame Seed Puff
<option value="square"> Coconut Milk Gelatin Square
<option value="cake"> Brown Sugar Cake
<option value="ricemeat"> Sweet Rice and Meat
</select>
<br />
Sweet Quantity: <input type="text" name="sweet_q">
<br />
<input type="submit" name="submit" value="Order">
</form><?php
// Answer-1
$_POST['noodle'] = 'barbecued pork';
$_POST['sweet'] = ['puff', 'ricemeat'];
$_POST['sweet_q'] = '4';
$_POST['submit'] = 'Order';
// Question-2
// 2. Write a process_form() function that prints out all submitted form parameters and their values.
// You can assume that form parameters have only scalar values.
// Answer-2
// Since this is operating on form data, it looks directly at $_POST instead of a validated $input array
function process_form()
{
print '<ul>';
foreach ($_POST as $k => $v) {
print '<li>' . htmlentities($k) . '=' . htmlentities($v) . '</li>';
}
print '</ul>';
}
// Question-3
// 3. Write a program that does basic arithmetic.
// Display a form with text box inputs for two operands and a <select> menu to choose an operation: addition, subtraction, multiplication, or division.
// Validate the inputs to make sure that they are numeric and appropriate for the chosen operation.
// The processing function should display the operands, the operator, and the result.
// For example, if the operands are 4 and 2 and the operation is multiplication,
// the processing function should display something like 4 * 2 = 8.
// Answer-3
// This assumes FormHelper.php is in the same directory as this file.
require 'FormHelper.php';
// Set up the arrays of choices in the select menu.
// This is needed in display_form(), validate_form(), and process_form(), so it is declared in the global scope.
$ops = array('+', '-', '*', '/');
// The main page logic:
// - If the form is submitted, validate and then process or redisplay
// - If it's not submitted, display
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// If validate_form() returns errors, pass them to show_form()
list($errors, $input) = validate_form();
if ($errors) {
show_form($errors);
} else {
// The submitted data is valid, so process it
process_form($input);
// And then show the form again to do another calculation
show_form();
}
} else {
// The form wasn't submitted, so display
show_form();
}
function show_form($errors = array())
{
$defaults = array(
'num1' => 2,
'op' => 2, // the index of '*' in $ops
'num2' => 8
);
// Set up the $form object with proper defaults
$form = new FormHelper($defaults);
// All the HTML and form display is in a separate file for clarity
include 'math-form.php';
}
function validate_form()
{
$input = array();
$errors = array();
// op is required
$input['op'] = $GLOBALS['ops'][$_POST['op']] ?? '';
if (!in_array($input['op'], $GLOBALS['ops'])) {
$errors[] = 'Please select a valid operation.';
}
// num1 and num2 must be numbers
$input['num1'] = filter_input(INPUT_POST, 'num1', FILTER_VALIDATE_FLOAT);
if (is_null($input['num1']) || ($input['num1'] === false)) {
$errors[] = 'Please enter a valid first number.';
}
$input['num2'] = filter_input(INPUT_POST, 'num2', FILTER_VALIDATE_FLOAT);
if (is_null($input['num2']) || ($input['num2'] === false)) {
$errors[] = 'Please enter a valid second number.';
}
// Can't divide by zero
if (($input['op'] == '/') && ($input['num2'] == 0)) {
$errors[] = 'Division by zero is not allowed.';
}
return array($errors, $input);
}
function process_form2($input)
{
$result = 0;
if ($input['op'] == '+') {
$result = $input['num1'] + $input['num2'];
} else if ($input['op'] == '-') {
$result = $input['num1'] - $input['num2'];
} else if ($input['op'] == '*') {
$result = $input['num1'] * $input['num2'];
} else if ($input['op'] == '/') {
$result = $input['num1'] / $input['num2'];
}
$message =
"{$input['num1']} {$input['op']} {$input['num2']} = $result";
print "<h3>$message</h3>";
}
// The code relies on the FormHelper.php file discussed in Chapter 7.
// The mathform.php file referenced, which displays the form HTML, contains: ?>
<form method="POST" action="<?= $form->encode($_SERVER['PHP_SELF']) ?>">
<table>
<?php if ($errors) { ?>
<tr>
<td>You need to correct the following errors:</td>
<td>
<ul>
<?php foreach ($errors as $error) { ?>
<li><?= $form->encode($error) ?></li>
<?php } ?>
</ul>
</td>
<?php } ?>
<tr>
<td>First Number:</td>
<td><?= $form->input('text', ['name' => 'num1']) ?></td>
</tr>
<tr>
<td>Operation:</td>
<td><?= $form->select($GLOBALS['ops'], ['name' => 'op']) ?></td>
</tr>
<tr>
<td>Second Number:</td>
<td><?= $form->input('text', ['name' => 'num2']) ?></td>
</tr>
<tr>
<td colspan="2" align="center"><?= $form->input(
'submit',
['value' => 'Calculate']
) ?>
</td>
</tr>
</table><?php
// Question-4
// 4. Write a program that displays, validates, and processes a form for entering information about a package to be shipped.
// The form should contain inputs for the from and to addresses for the package, dimensions of the package, and weight of the package.
// The validation should check (at least) that the package weighs no more than 150 pounds and that no dimension of the package is more than 36 inches.
// You can assume that the addresses entered on the form are both US addresses,
// but you should check that a valid state and a zip code with valid syntax are entered.
// The processing function in your program should print out the information about the package in an organized, formatted report.
// Answer-4
// This assumes FormHelper.php is in the same directory as this file.
require 'FormHelper.php';
// Set up the array of choices in the select menu.
// This is needed in display_form(), validate_form(),
// and process_form(), so it is declared in the global scope.
$states = [ 'AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'GA',
'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN',
'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK',
'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI',
'WY' ];
// The main page logic:
// - If the form is submitted, validate and then process or redisplay
// - If it's not submitted, display
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// If validate_form() returns errors, pass them to show_form()
list($errors, $input) = validate_form();
if ($errors) {
show_form($errors);
} else {
// The submitted data is valid, so process it
process_form2($input);
}
} else {
// The form wasn't submitted, so display
show_form();
}
function show_form2($errors = array())
{
// Set up the $form object with proper defaults
$form = new FormHelper();
// All the HTML and form display is in a separate file for clarity
include 'shipping-form.php';
}
function validate_form2()
{
$input = array();
$errors = array();
foreach (['from', 'to'] as $addr) {
// Check required fields
foreach (['Name' => 'name', 'Address 1' => 'address1', 'City' => 'city', 'State' => 'state'] as $label => $field) {
$input[$addr . '_' . $field] = $_POST[$addr . '_' . $field] ?? '';
if (strlen($input[$addr . '_' . $field]) == 0) {
$errors[] = "Please enter a value for $addr $label.";
}
}
// Check state
$input[$addr . '_state'] =
$GLOBALS['states'][$input[$addr . '_state']] ?? '';
if (!in_array($input[$addr . '_state'], $GLOBALS['states'])) {
$errors[] = "Please select a valid $addr state.";
}
// Check zip code
$input[$addr . '_zip'] = filter_input(
INPUT_POST,
$addr . '_zip',
FILTER_VALIDATE_INT,
[
'options' => [
'min_range' => 10000,
'max_range' => 99999
]
]
);
if (is_null($input[$addr . '_zip']) || ($input[$addr . '_zip'] === false)) {
$errors[] = "Please enter a valid $addr ZIP";
}
// Don't forget about address2!
$input[$addr . '_address2'] = $_POST[$addr . '_address2'] ?? '';
}
// height, width, depth, weight must all be numbers > 0
foreach (['height', 'width', 'depth', 'weight'] as $field) {
$input[$field] = filter_input(INPUT_POST, $field, FILTER_VALIDATE_FLOAT);
// Since 0 is not valid, we can just test for truth rather than
// null or exactly false
if (!($input[$field] && ($input[$field] > 0))) {
$errors[] = "Please enter a valid $field.";
}
}
// Check weight
if ($input['weight'] > 150) {
$errors[] = "The package must weigh no more than 150 lbs.";
}
// Check dimensions
foreach (['height', 'width', 'depth'] as $dim) {
if ($input[$dim] > 36) {
$errors[] = "The package $dim must be no more than 36 inches.";
}
}
return array($errors, $input);
}
function process_form3($input)
{
// Make a template for the report
$tpl = <<<HTML
<p>Your package is {height}" x {width}" x {depth}" and weighs {weight} lbs.</p>
<p>It is coming from:</p>
<pre>
{from_name}
{from_address}
{from_city}, {from_state} {from_zip}
</pre>
<p>It is going to:</p>
<pre>
{to_name}
{to_address}
{to_city}, {to_state} {to_zip}
</pre>
HTML;
// Adjust addresses in $input for easier output
foreach (['from', 'to'] as $addr) {
$input[$addr . '_address'] = $input[$addr . '_address1'];
if (strlen($input[$addr . '_address2'])) {
$input[$addr . '_address'] .= "\n" . $input[$addr . '_address2'];
}
}
// Replace each template variable with the corresponding value
// in $input
$html = $tpl;
foreach ($input as $k => $v) {
$html = str_replace('{' . $k . '}', $v, $html);
}
// Print the report
print $html;
}
// The code relies on the FormHelper.php file discussed in Chapter 7.
// The shipping-form.php file referenced, which displays the form HTML, contains: ?>
<form method="POST" action="<?= $form->encode($_SERVER['PHP_SELF']) ?>">
<table>
<?php if ($errors) { ?>
<tr>
<td>You need to correct the following errors:</td>
<td>
<ul>
<?php foreach ($errors as $error) { ?>
<li><?= $form->encode($error) ?></li>
<?php } ?>
</ul>
</td>
<?php } ?>
<tr>
<th>From:</th>
<td></td>
</tr>
<tr>
<td>Name:</td>
<td><?= $form->input('text', ['name' => 'from_name']) ?></td>
</tr>
<tr>
<td>Address 1:</td>
<td><?= $form->input('text', ['name' => 'from_address1']) ?></td>
</tr>
<tr>
<td>Address 2:</td>
<td><?= $form->input('text', ['name' => 'from_address2']) ?></td>
</tr>
<tr>
<td>City:</td>
<td><?= $form->input('text', ['name' => 'from_city']) ?></td>
</tr>
<tr>
<td>State:</td>
<td><?= $form->select($GLOBALS['states'], ['name' => 'from_state']) ?>
</td>
</tr>
<tr>
<td>ZIP:</td>
<td><?= $form->input('text', ['name' => 'from_zip', 'size' => 5]) ?>
</td>
</tr>
<tr>
<th>To:</th>
<td></td>
</tr>
<tr>
<td>Name:</td>
<td><?= $form->input('text', ['name' => 'to_name']) ?></td>
</tr>
<tr>
<td>Address 1:</td>
<td><?= $form->input('text', ['name' => 'to_address1']) ?></td>
</tr>
<tr>
<td>Address 2:</td>
<td><?= $form->input('text', ['name' => 'to_address2']) ?></td>
</tr>
<tr>
<td>City:</td>
<td><?= $form->input('text', ['name' => 'to_city']) ?></td>
</tr>
<tr>
<td>State:</td>
<td><?= $form->select($GLOBALS['states'], ['name' => 'to_state']) ?>
</td>
</tr>
<tr>
<td>ZIP:</td>
<td><?= $form->input('text', ['name' => 'to_zip', 'size' => 5]) ?>
</td>
</tr>
<tr>
<th>Package:</th>
<td></td>
</tr>
<tr>
<td>Weight:</td>
<td><?= $form->input('text', ['name' => 'weight']) ?></td>
</tr>
<tr>
<td>Height:</td>
<td><?= $form->input('text', ['name' => 'height']) ?></td>
</tr>
<tr>
<td>Width:</td>
<td><?= $form->input('text', ['name' => 'width']) ?></td>
</tr>
<tr>
<td>Depth:</td>
<td><?= $form->input('text', ['name' => 'depth']) ?></td>
</tr>
<tr>
<td colspan="2" align="center">
<?= $form->input('submit', ['value' => 'Ship!']) ?>
</td>
</tr>
</table>
</form><?php
// Question-5
// 5. (Optional) Modify your process_form() function that enumerates all submitted form parameters
// and their values so that it correctly handles submitted form parameters that have array values.
// Remember, those array values could themselves contain arrays.
// Answer-5
function print_array($ar)
{
print '<ul>';
foreach ($ar as $k => $v) {
if (is_array($v)) {
print '<li>' . htmlentities($k) . ':</li>';
print_array($v);
} else {
print '<li>' . htmlentities($k) . '=' . htmlentities($v) . '</li>';
}
}
print '</ul>';
}
/* Since this is operating on form data, it looks directly at $_POST
instead of a validated $input array */
function process_form4()
{
print_array($_POST);
}
<?php
// Chapter-8: Exercises
// The following exercises use a database table called dishes with the following structure:
// -- CREATE TABLE dishes (
// -- dish_id INT,
// -- dish_name VARCHAR(255),
// -- price DECIMAL(4,2),
// -- is_spicy INT
// -- )
// Here is some sample data to put into the dishes table:
// -- INSERT INTO dishes VALUES (1,'Walnut Bun',1.00,0)
// -- INSERT INTO dishes VALUES (2,'Cashew Nuts and White Mushrooms',4.95,0)
// -- INSERT INTO dishes VALUES (3,'Dried Mulberries',3.00,0)
// -- INSERT INTO dishes VALUES (4,'Eggplant with Chili Sauce',6.50,1)
// -- INSERT INTO dishes VALUES (5,'Red Bean Bun',1.00,0)
// -- INSERT INTO dishes VALUES (6,'General Tso''s Chicken',5.50,1)
// Question-1
// 1. Write a program that lists all of the dishes in the table, sorted by price.
// Answer-1
try {
// Connect
$db = new PDO('sqlite:/tmp/restaurant.db');
// Set up exceptions on DB errors
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $db->query('SELECT * FROM dishes ORDER BY price');
$dishes = $stmt->fetchAll();
if (count($dishes) == 0) {
$html = '<p>No dishes to display</p>';
} else {
$html = "<table>\n";
$html .= "<tr><th>Dish Name</th><th>Price</th><th>Spicy?</th></tr>\n";
foreach ($dishes as $dish) {
$html .= '<tr><td>' .
htmlentities($dish['dish_name']) . '</td><td>$' .
sprintf('%.02f', $dish['price']) . '</td><td>' .
($dish['is_spicy'] ? 'Yes' : 'No') . "</td></tr>\n";
}
$html .= "</table>";
}
} catch (PDOException $e) {
$html = "Can't show dishes: " . $e->getMessage();
}
print $html;
// Question-2
// 2. Write a program that displays a form asking for a price. When the form is submitted,
// the program should print out the names and prices of the dishes whose price is at least the submitted price.
// Don’t retrieve from the database any rows or columns that aren’t printed in the table.
// Answer-2
// Load the form helper class
require 'FormHelper.php';
// Connect to the database
try {
$db = new PDO('sqlite:/tmp/restaurant.db');
} catch (PDOException $e) {
print "Can't connect: " . $e->getMessage();
exit();
}
// Set up exceptions on DB errors
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Set up fetch mode: rows as objects
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
// The main page logic:
// - If the form is submitted, validate and then process or redisplay
// - If it's not submitted, display
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// If validate_form() returns errors, pass them to show_form()
list($errors, $input) = validate_form();
if ($errors) {
show_form($errors);
} else {
// The submitted data is valid, so process it
process_form($input);
}
} else {
// The form wasn't submitted, so display
show_form();
}
function show_form($errors = array())
{
// Set up the $form object with proper defaults
$form = new FormHelper();
// All the HTML and form display is in a separate file for clarity
include 'price-form.php';
}
function validate_form()
{
$input = array();
$errors = array();
// Minimum price must be a valid floating-point number
$input['min_price'] = filter_input(
INPUT_POST,
'min_price',
FILTER_VALIDATE_FLOAT
);
if ($input['min_price'] === null || $input['min_price'] === false) {
$errors[] = 'Please enter a valid minimum price.';
}
return array($errors, $input);
}
function process_form($input)
{
// Access the global variable $db inside this function
global $db;
// Build up the query
$sql = 'SELECT dish_name, price, is_spicy FROM dishes WHERE
price >= ?';
// Send the query to the database program and get all the rows back
$stmt = $db->prepare($sql);
$stmt->execute(array($input['min_price']));
$dishes = $stmt->fetchAll();
if (count($dishes) == 0) {
print 'No dishes matched.';
} else {
print '<table>';
print '<tr><th>Dish Name</th><th>Price</th><th>Spicy?</th></tr>';
foreach ($dishes as $dish) {
if ($dish->is_spicy == 1) {
$spicy = 'Yes';
} else {
$spicy = 'No';
}
}
printf(
'<tr><td>%s</td><td>$%.02f</td><td>%s</td></tr>',
htmlentities($dish->dish_name),
$dish->price,
$spicy
);
print '</table>';
}
}
// The code relies on the FormHelper.php file discussed in Chapter 7.
// The price-form.php file referenced, which displays the form HTML, contains: ?>
<form method="POST" action="<?= $form->encode($_SERVER['PHP_SELF']) ?>">
<table>
<?php if ($errors) { ?>
<tr>
<td>You need to correct the following errors:</td>
<td>
<ul>
<?php foreach ($errors as $error) { ?>
<li><?= $form->encode($error) ?></li>
<?php } ?>
</ul>
</td>
<?php } ?>
<tr>
<td>Minimum Price:</td>
<td><?= $form->input('text', ['name' => 'min_price']) ?></td>
</tr>
<tr>
<td colspan="2" align="center">
<?= $form->input('submit', [
'name' => 'search',
'value' => 'Search'
]) ?>
</td>
</tr>
</table>
</form><?php
// Question-3
// 3. Write a program that displays a form with a <select> menu of dish names.
// Create the dish names to display by retrieving them from the database.
// When the form is submitted, the program should print out all of the information in the table (ID, name, price, and spiciness) for the selected dish.
// Answer-3
// Load the form helper class
require 'FormHelper.php';
// Connect to the database
try {
$db = new PDO('sqlite:/tmp/restaurant.db');
} catch (PDOException $e) {
print "Can't connect: " . $e->getMessage();
exit();
}
// Set up exceptions on DB errors
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Set up fetch mode: rows as objects
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
// The main page logic:
// - If the form is submitted, validate and then process or redisplay
// - If it's not submitted, display
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// If validate_form() returns errors, pass them to show_form()
list($errors, $input) = validate_form();
if ($errors) {
show_form($errors);
} else {
// The submitted data is valid, so process it
process_form($input);
}
} else {
// The form wasn't submitted, so display
show_form();
}
function show_form2($errors = array())
{
global $db;
// Set up the $form object with proper defaults
$form = new FormHelper();
// Retrieve the list of dish names to use from the database
$sql = 'SELECT dish_id, dish_name FROM dishes ORDER BY dish_name';
$stmt = $db->query($sql);
$dishes = array();
while ($row = $stmt->fetch()) {
$dishes[$row->dish_id] = $row->dish_name;
}
// All the HTML and form display is in a separate file for clarity
include 'dish-form.php';
}
function validate_form2()
{
$input = array();
$errors = array();
// As long as some dish_id value is submitted, we'll consider it OK.
// If it doesn't match any dishes in the database, process_form()
// can report that.
if (isset($_POST['dish_id'])) {
$input['dish_id'] = $_POST['dish_id'];
} else {
$errors[] = 'Please select a dish.';
}
return array($errors, $input);
}
function process_form2($input)
{
// Access the global variable $db inside this function
global $db;
// Build up the query
$sql = 'SELECT dish_id, dish_name, price, is_spicy FROM dishes WHERE
dish_id = ?';
// Send the query to the database program and get all the rows back
$stmt = $db->prepare($sql);
$stmt->execute(array($input['dish_id']));
$dish = $stmt->fetch();
if (count($dish) == 0) {
print 'No dishes matched.';
} else {
print '<table>';
print '<tr><th>ID</th><th>Dish Name</th><th>Price</th>';
print '<th>Spicy?</th></tr>';
if ($dish->is_spicy == 1) {
$spicy = 'Yes';
} else {
$spicy = 'No';
}
printf(
'<tr><td>%d</td><td>%s</td><td>$%.02f</td><td>%s</td></tr>',
$dish->dish_id,
htmlentities($dish->dish_name),
$dish->price,
$spicy
);
print '</table>';
}
}
// The code relies on the FormHelper.php file discussed in Chapter 7.
// The dish-form.php file referenced, which displays the form HTML, contains: ?>
<form method="POST" action="<?= $form->encode($_SERVER['PHP_SELF']) ?>">
<table>
<?php if ($errors) { ?>
<tr>
<td>You need to correct the following errors:</td>
<td>
<ul>
<?php foreach ($errors as $error) { ?>
<li><?= $form->encode($error) ?></li>
<?php } ?>
</ul>
</td>
<?php } ?>
<tr>
<td>Dish:</td>
<td><?= $form->select($dishes, ['name' => 'dish_id']) ?></td>
</tr>
<tr>
<td colspan="2" align="center">
<?= $form->input('submit', [
'name' => 'info',
'value' => 'Get Dish Info'
]) ?>
</td>
</tr>
</table>
<?php
// Question-4
// 4. Create a new table that holds information about restaurant customers.
// The table should store the following information about each customer: customer ID, name, phone number,
// and the ID of the customer’s favorite dish. Write a program that displays a form for putting a new customer into the table.
// The part of the form for entering the customer’s favorite dish should be a <select> menu of dish names.
// The customer’s ID should be generated by your program, not entered in the form.
// Answer-4
// Load the form helper class
require 'FormHelper.php';
// Connect to the database
try {
$db = new PDO('sqlite:/tmp/restaurant.db');
} catch (PDOException $e) {
print "Can't connect: " . $e->getMessage();
exit();
}
// Set up exceptions on DB errors
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Set up fetch mode: rows as objects
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
// Put the list of dish IDs and names in a global array because
// we'll need it in show_form() and validate_form()
$dishes = array();
$sql = 'SELECT dish_id, dish_name FROM dishes ORDER BY dish_name';
$stmt = $db->query($sql);
while ($row = $stmt->fetch()) {
$dishes[$row->dish_id] = $row->dish_name;
}
// The main page logic:
// - If the form is submitted, validate and then process or redisplay
// - If it's not submitted, display
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// If validate_form() returns errors, pass them to show_form()
list($errors, $input) = validate_form();
if ($errors) {
show_form($errors);
} else {
// The submitted data is valid, so process it
process_form($input);
}
} else {
// The form wasn't submitted, so display
show_form();
}
function show_form3($errors = array())
{
global $db, $dishes;
// Set up the $form object with proper defaults
$form = new FormHelper();
// All the HTML and form display is in a separate file for clarity
include 'customer-form.php';
}
function validate_form3()
{
global $dishes;
$input = array();
$errors = array();
// Make sure a dish_id valid is submitted and in $dishes.
// As long as some dish_id value is submitted, we'll consider it OK.
// If it doesn't match any dishes in the database, process_form()
// can report that.
$input['dish_id'] = $_POST['dish_id'] ?? '';
if (!array_key_exists($input['dish_id'], $dishes)) {
$errors[] = 'Please select a valid dish.';
}
// Name is required
$input['name'] = trim($_POST['name'] ?? '');
if (0 == strlen($input['name'])) {
$errors[] = 'Please enter a name.';
}
// Phone number is required
$input['phone'] = trim($_POST['phone'] ?? '');
if (0 == strlen($input['phone'])) {
$errors[] = 'Please enter a phone number.';
} else {
// Be US-centric and ensure that the phone number contains
// at least 10 digits. Using ctype_digit() on each
// character is not the most efficient way to do this,
// but is logically straightforward and avoids
// regular expressions.
$digits = 0;
for ($i = 0; $i < strlen($input['phone']); $i++) {
if (ctype_digit($input['phone'][$i])) {
$digits++;
}
}
if ($digits < 10) {
$errors[] = 'Phone number needs at least ten digits.';
}
}
return array($errors, $input);
}
function process_form4($input)
{
// Access the global variable $db inside this function
global $db;
// Build up the query. No need to specify customer_id because
// the database will automatically assign a unique one.
$sql = 'INSERT INTO customers (name,phone,favorite_dish_id) ' .
'VALUES (?,?,?)';
// Send the query to the database program and get all the rows back
try {
$stmt = $db->prepare($sql);
$stmt->execute(array($input['name'], $input['phone'], $input['dish_id']));
print '<p>Inserted new customer.</p>';
} catch (Exception $e) {
print "<p>Couldn't insert customer: {$e->getMessage()}.</p>";
}
}
// The code relies on the FormHelper.php file discussed in Chapter 7.
// The customer-form.php file referenced, which displays the form HTML, contains: ?>
<form method="POST" action="<?= $form->encode($_SERVER['PHP_SELF']) ?>">
<table>
<?php if ($errors) { ?>
<tr>
<td>You need to correct the following errors:</td>
<td>
<ul>
<?php foreach ($errors as $error) { ?>
<li><?= $form->encode($error) ?></li>
<?php } ?>
</ul>
</td>
<?php } ?>
<tr>
<tr>
<td>Name:</td>
<td><?= $form->input('text', ['name' => 'name']) ?>
</td>
</tr>
<tr>
<td>Phone Number:</td>
<td><?= $form->input('text', ['name' => 'phone']) ?></td>
</tr>
<tr>
<td>Favorite Dish:</td>
<td><?= $form->select($dishes, ['name' => 'dish_id']) ?></td>
</tr>
<tr>
<td colspan="2" align="center">
<?= $form->input('submit', ['name' => 'add', 'value' => 'Add Customer']) ?>
</td>
</tr>
</table>
</form>
<?php
// Chapter-10: Exercises
// Question-1
// 1. Make a web page that uses a cookie to keep track of how many times a user has viewed the page.
// The first time a particular user looks at the page, it should print something like “Number of views: 1.”
// The second time the user looks at the page, it should print “Number of views: 2,” and so on.
// Answer-1
$view_count = 1 + ($_COOKIE['view_count'] ?? 0);
setcookie('view_count', $view_count);
print "<p>Hi! Number of times you've viewed this page: $view_count.</p>";
// Question-2
// 2. Modify the web page from the first exercise so that it prints out a special message on the 5th, 10th,
// and 15th times the user looks at the page. Also modify it so that on the 20th time the user looks at the page,
// it deletes the cookie and the page count starts over.
// Answer-2
$view_count = 1 + ($_COOKIE['view_count'] ?? 0);
if ($view_count == 20) {
// An empty value for setcookie() removes the cookie
setcookie(
'view_count',
''
);
$msg = "<p>Time to start over.</p>";
} else {
setcookie('view_count', $view_count);
$msg = "<p>Hi! Number of times you've viewed this page: $view_count.</p>";
if ($view_count == 5) {
$msg .= "<p>This is your fifth visit.</p>";
} elseif ($view_count == 10) {
$msg .= "<p>This is your tenth visit. You must like this page.</p>";
} elseif ($view_count == 15) {
$msg .= "<p>This is your fifteenth visit. " .
"Don't you have anything else to do?</p>";
}
}
print $msg;
// Question-3
// 3. Write a PHP program that displays a form for a user to pick his favorite color from a list of colors.
// Make another page whose background color is set to the color that the user picks in the form.
// Store the color value in $_SESSION so that both pages can access it.
// Answer-3
// The color-picking page:
// Start sessions first thing so we can use $_SESSION freely later
session_start();
// Load the form helper class
require 'FormHelper.php';
$colors = array(
'ff0000' => 'Red',
'ffa500' => 'Orange',
'ffffff' => 'Yellow',
'008000' => 'Green',
'0000ff' => 'Blue',
'4b0082' => 'Indigo',
'663399' => 'Rebecca Purple'
);
// The main page logic:
// - If the form is submitted, validate and then process or redisplay
// - If it's not submitted, display
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// If validate_form() returns errors, pass them to show_form()
list($errors, $input) = validate_form();
if ($errors) {
show_form($errors);
} else {
// The submitted data is valid, so process it
process_form($input);
}
} else {
// The form wasn't submitted, so display
show_form();
}
function show_form($errors = array())
{
global $colors;
// Set up the $form object with proper defaults
$form = new FormHelper();
// All the HTML and form display is in a separate file for clarity
include 'color-form.php';
}
function validate_form()
{
$input = array();
$errors = array();
// color must be a valid color
$input['color'] = $_POST['color'] ?? '';
if (!array_key_exists($input['color'], $GLOBALS['colors'])) {
$errors[] = 'Please select a valid color.';
}
return array($errors, $input);
}
function process_form($input)
{
global $colors;
$_SESSION['background_color'] = $input['color'];
print '<p>Your color has been set.</p>';
}
// The code relies on the FormHelper.php file discussed in Chapter 7.
// The color-form.php file referenced, which displays the form HTML, contains: ?>
<form method="POST" action="<?= $form->encode($_SERVER['PHP_SELF']) ?>">
<table>
<?php if ($errors) { ?>
<tr>
<td>You need to correct the following errors:</td>
<td>
<ul>
<?php foreach ($errors as $error) { ?>
<li><?= $form->encode($error) ?></li>
<?php } ?>
</ul>
</td>
<?php } ?>
<tr>
<td>Favorite Color:</td>
<td><?= $form->select($colors, ['name' => 'color']) ?></td>
</tr>
<tr>
<td colspan="2" align="center">
<?= $form->input('submit', [
'name' => 'set',
'value' => 'Set Color'
]) ?>
</td>
</tr>
</table>
<?php
// The page with background color set:
// Start sessions first thing so we can use $_SESSION freely later
session_start();
?>
<html>
<head>
<title>Background Color Example</title>
<body style="background-color:<?= $_SESSION['background_color'] ?>">
<p>What color did you pick?</p>
</body>
</html><?php
// Question-4
// 4. Write a PHP program that displays an order form. The order form should list six products.
// Next to each product name there should be a text box into which a user can enter how many of
// that product she wants to order.
// When the form is submitted, the submitted form data should be saved into the session.
// Make another page that displays the contents of the saved order, a link back to the order form page,
// and a Check Out button. If the link back to the order form page is clicked, the order form page should be
// displayed with the saved order quantities from the session in the text boxes.
// When the Check Out button is clicked, the order should be cleared from the session.
// Answer-4
// The ordering page:
session_start();
// This assumes FormHelper.php is in the same directory as this file.
require 'FormHelper.php';
// Set up the array of choices in the select menu.
// This is needed in display_form(), validate_form(),
// and process_form(), so it is declared in the global scope.
$products = [
'cuke' => 'Braised Sea Cucumber',
'stomach' => "Sauteed Pig's Stomach",
'tripe' => 'Sauteed Tripe with Wine Sauce',
'taro' => 'Stewed Pork with Taro',
'giblets' => 'Baked Giblets with Salt',
'abalone' => 'Abalone with Marrow and Duck Feet'
];
// The main page logic:
// - If the form is submitted, validate and then process or redisplay
// - If it's not submitted, display
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// If validate_form() returns errors, pass them to show_form()
list($errors, $input) = validate_form2();
if ($errors) {
show_form($errors);
} else {
// The submitted data is valid, so process it
process_form2($input);
}
} else {
// The form wasn't submitted, so display
show_form2();
}
function show_form2($errors = array())
{
global $products;
$defaults = array();
// Start out with 0 as a default
foreach ($products as $code => $label) {
$defaults["quantity_$code"] = 0;
}
// If quantities are in the session, use those
if (isset($_SESSION['quantities'])) {
foreach ($_SESSION['quantities'] as $field => $quantity) {
$defaults[$field] = $quantity;
}
}
$form = new FormHelper($defaults);
// All the HTML and form display is in a separate file for clarity
include 'order-form.php';
}
function validate_form2()
{
global $products;
$input = array();
$errors = array();
// For each quantity box, make sure the value is
// a valid integer >= 0
foreach ($products as $code => $name) {
$field = "quantity_$code";
$input[$field] = filter_input(
INPUT_POST,
$field,
FILTER_VALIDATE_INT,
['options' => ['min_range' => 0]]
);
if (is_null($input[$field]) || ($input[$field] === false)) {
$errors[] = "Please enter a valid quantity for $name.";
}
}
return array($errors, $input);
}
function process_form2($input)
{
$_SESSION['quantities'] = $input;
print "Thank you for your order.";
}
// The code relies on the FormHelper.php file discussed in Chapter 7.
// The order-form.php file referenced, which displays the form HTML, contains: ?>
<form method="POST" action="<?= $form->encode($_SERVER['PHP_SELF']) ?>">
<table>
<?php if ($errors) { ?>
<tr>
<td>You need to correct the following errors:</td>
<td>
<ul>
<?php foreach ($errors as $error) { ?>
<li><?= $form->encode($error) ?></li>
<?php } ?>
</ul>
</td>
<?php } ?>
<tr>
<th>Product</th>
<td>Quantity</td>
</tr>
<?php foreach ($products as $code => $name) { ?>
<tr>
<td><?= htmlentities($name) ?>:</td>
<td><?= $form->input('text', ['name' => "quantity_$code"]) ?></td>
</tr>
<?php } ?>
<tr>
<td colspan="2" align="center"><?= $form->input('submit', ['value' => 'Order']) ?>
</td>
</tr>
</table>
</form><?php
// The checkout page:
session_start();
// The same products from the order page
$products = [
'cuke' => 'Braised Sea Cucumber',
'stomach' => "Sauteed Pig's Stomach",
'tripe' => 'Sauteed Tripe with Wine Sauce',
'taro' => 'Stewed Pork with Taro',
'giblets' => 'Baked Giblets with Salt',
'abalone' => 'Abalone with Marrow and Duck Feet'
];
// Simplified main page logic without form validation
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
process_form3();
} else {
// The form wasn't submitted, so display
show_form3();
}
function show_form3()
{
global $products;
// The "form" is just a single submit button, so we won't use
// FormHelper and just inline all the HTML here
if (isset($_SESSION['quantities']) && (count($_SESSION['quantities']) > 0)) {
print "<p>Your order:</p><ul>";
foreach ($_SESSION['quantities'] as $field => $amount) {
list($junk, $code) = explode('_', $field);
$product = $products[$code];
print "<li>$amount $product</li>";
}
print "</ul>";
print '<form method="POST" action=' .
htmlentities($_SERVER['PHP_SELF']) . '>';
print '<input type="submit" value="Check Out" />';
print '</form>';
} else {
print "<p>You don't have a saved order.</p>";
}
// This assumes the order form page is saved as "order.php"
print '<a href="order.php">Return to Order page</a>';
}
function process_form3()
{
// This removes the data from the session
unset($_SESSION['quantities']);
print "<p>Thanks for your order.</p>";
}
<?php
// Chapter-12: Exercises
// Question-1
// 1. This program has a syntax error in it:
$name = 'Umberto';
function say_hello() {
print 'Hello, ';
// print global $name;
}
say_hello();
// Without running the program through the PHP engine,
// figure out what the parse error that gets printed when the engine tries to run the program looks like.
// What change must you make to the program to get it to run properly and print Hello, Umberto?
// Answer-1
// The keyword global should not be in line 5, so the parse error should report that unexpected keyword.
// The actual parse error is:
// PHP Parse error: syntax error, unexpected 'global' (T_GLOBAL) in debugging-12.php on line 5
// To make the program run properly, change the line print global $name; to print
// $GLOBALS['name'];. Or, you can add global name; as the first line of the function and then change print global $name; to print $name;.
// Question-2
// 2. Modify the validate_form() function in your answer to Exercise 3 in Chapter 7 (see “Exercise 3” on page 345)
// so that it prints in the web server error log the names and values of all of the submitted form parameters.
// Answer-2
function validate_form()
{
$input = array();
$errors = array();
// turn on output buffering
ob_start();
// dump all the submitted data
var_dump($_POST);
// capture the generated "output"
$output = ob_get_contents();
// turn off output buffering
ob_end_clean();
// send the variable dump to the error log
error_log($output);
// op is required
$input['op'] = $GLOBALS['ops'][$_POST['op']] ?? '';
if (!in_array($input['op'], $GLOBALS['ops'])) {
$errors[] = 'Please select a valid operation.';
}
// num1 and num2 must be numbers
$input['num1'] = filter_input(INPUT_POST, 'num1', FILTER_VALIDATE_FLOAT);
if (is_null($input['num1']) || ($input['num1'] === false)) {
$errors[] = 'Please enter a valid first number.';
}
$input['num2'] = filter_input(INPUT_POST, 'num2', FILTER_VALIDATE_FLOAT);
if (is_null($input['num2']) || ($input['num2'] === false)) {
$errors[] = 'Please enter a valid second number.';
}
// can't divide by zero
if (($input['op'] == '/') && ($input['num2'] == 0)) {
$errors[] = 'Division by zero is not allowed.';
}
return array($errors, $input);
}
// Question-3
// 3. Modify your answer to Exercise 4 in Chapter 8 (see “Exercise 4” on page 357) to use a custom database
// error-handling function that prints out different messages in the web browser and in the web server error log.
// The error-handling function should make the program exit after it prints the error messages.
// Answer-3
// At the top of the program, this code defines an exception handler and sets it up to be called on unhandled exceptions:
function exceptionHandler($ex)
{
// Log the specifics to the error log
error_log("ERROR: " . $ex->getMessage());
// Print something less specific for users to see
// and exit
die("<p>Sorry, something went wrong.</p>");
}
set_exception_handler('exceptionHandler');
// Question-4
// Then the try/catch blocks can be removed from the two places they are used (once around creating the PDO object and once in process_form())
// because the exceptions will be handled by the exception handler.
// 4. The following program is supposed to print out an alphabetical list of all the customers in the table from
// Exercise 4 in Chapter 8 (see “Exercise 4” on page 357). Find and fix the errors in it.
// Connect to the database
try {
} catch ($e) {
$db = new PDO('sqlite::/tmp/restaurant.db');
die("Can't connect: " . $e->getMessage());
}
// Set up exception error handling
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Set up fetch mode: rows as arrays
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
// Get the array of dish names from the database
$dish_names = array();
$res = $db->query('SELECT dish_id,dish_name FROM dishes');
foreach ($res->fetchAll() as $row) {
$dish_names[ $row['dish_id']]] = $row['dish_name'];
}
$res = $db->query('SELECT ** FROM customers ORDER BY phone DESC');
$customers = $res->fetchAll();
if (count($customers) = 0) {
print "No customers.";
} else {
print '<table>';
print '<tr><th>ID</th><th>Name</th><th>Phone</th>
<th>Favorite Dish</th></tr>';
foreach ($customers as $customer) {
printf("<tr><td>%d</td><td>%s</td><td>%f</td><td>%s</td></tr>\n"
$customer['customer_id'],
htmlentities($customer['customer_name']),
$customer['phone'],
$customer['favorite_dish_id']);
}
print '</table>';
// Answer-4
// • Line 4: Change :: to : in the DSN.
// • Line 5: Change catch ($e) to catch (Exception $e).
// • Line 16: Change $row['dish_id']] to $row['dish_id'] as the key to look up in the $dish_names array.
// • Line 18: Change ** to * in the SQL query.
// • Line 20: Change = to ==.
// • Line 26: Change the third format specifier from %f to %s—$customer['phone'] is a string.
// • Line 30: Change $customer['favorite_dish_id'] to $dish_names [$customer['favorite_dish_id']] so that
// the dish ID is translated into the name of the corresponding dish.
// • Line 33: Insert a } to match the opening { in line 22.
// The complete corrected program is:
// Connect to the database
try {
$db = new PDO('sqlite:/tmp/restaurant.db');
} catch (Exception $e) {
die("Can't connect: " . $e->getMessage());
}
// Set up exception error handling
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Set up fetch mode: rows as arrays
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
// Get the array of dish names from the database
$dish_names = array();
$res = $db->query('SELECT dish_id,dish_name FROM dishes');
foreach ($res->fetchAll() as $row) {
$dish_names[$row['dish_id']] = $row['dish_name'];
}
$res = $db->query('SELECT * FROM customers ORDER BY phone DESC');
$customers = $res->fetchAll();
if (count($customers) == 0) {
print "No customers.";
} else {
print '<table>';
print '<tr><th>ID</th><th>Name</th>
<th>Phone</th><th>Favorite Dish</th></tr>';
foreach ($customers as $customer) {
printf(
"<tr><td>%d</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
$customer['customer_id'],
htmlentities($customer['customer_name']),
$customer['phone'],
$dish_names[$customer['favorite_dish_id']]
);
}
print '</table>';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment