Chapter 2 Part10
Chapter 2 Part10
Content
2.1. How to work with form data
2.2. How to code control statements
2.3. How to work with string and numbers
2.4. How to work with dates
2.5. How to work with arrays
2.6. How to work with cookie
2.7. How to work with session
2.8. How to work with functions
2.9. How to work with objects
2.10. How to work with regular expression, handle exception
C1, Slide 2
2.10. How to work with regular expression,
handle exception
Objectives
Applied
1. Create and use regular expressions.
2. Create and throw exceptions.
3. Catch and handle exceptions and errors.
C15, Slide 3
Objectives (continued)
Knowledge
1. Describe the creation of a regular expression, and the processing
that’s done by the preg_match() function.
2. Describe the use of case-insensitive, multiline, and global regular
expressions.
3. Describe the use of the preg_replace() and preg_split() functions
that work with regular expressions.
4. Describe how regular expressions can be used for data validation
such as validating a social security number.
5. Describe the way exceptions are created, thrown, and handled.
6. Describe the type of errors that PHP 7 lets you catch and how
you catch and handle them.
C15, Slide 4
A function for matching a regular expression
preg_match($pattern, $string)
C15, Slide 5
How to test for errors in a regular expression
if ($author_match === false) {
echo 'Error testing author name.';
} else if ($author_match === 0) {
echo 'Author name does not contain Harris.';
} else {
echo 'Author name contains Harris.';
}
C15, Slide 6
A case-insensitive regular expression
$pattern = '/murach/i';
C15, Slide 7
Key terms
regular expression
pattern
C15, Slide 8
Patterns for special characters
Pattern Matches
\\ Backslash character
\/ Forward slash
\t Tab
\n New line
\r Carriage return
\f Form feed
\xhh The Latin-1 character whose value is the two
hexadecimal digits
C15, Slide 9
Matching special characters
$string =
"© 2017 Mike's Music. \ All rights reserved (5/2017).";
preg_match('/\xA9/', $string)
// Matches © and returns 1
preg_match('///', $string)
// Returns FALSE and issues a warning
preg_match('/\//', $string)
// Matches / and returns 1
preg_match('/\\\\/', $string)
// Matches \ and returns 1
C15, Slide 10
Patterns for character types
Pattern Matches
. Any single character except a new line character
(use \. to match a period)
\w Any letter, number, or the underscore
\W Any character that’s not a letter, number or the
underscore
\d Any digit
\D Any character that’s not a digit
\s Any whitespace character (space, tab, new line,
carriage return, form feed, or vertical tab)
\S Any character that’s not whitespace
C15, Slide 11
Matching character types
$string = 'The product code is MBT-3461.';
preg_match('/MB./', $string)
// Matches MBT and returns 1
preg_match('/MB\d/', $string)
// Matches nothing and returns 0
preg_match('/MBT-\d/', $string)
// Matches MBT-3 and returns 1
C15, Slide 12
Using the character class
$string = 'The product code is MBT-3461.';
preg_match('/MB[TF]/', $string)
// Matches MBT and returns 1
preg_match('/[.]/', $string)
// Matches . and returns 1
preg_match('/[13579]/', $string)
// Matches 3 and returns 1
C15, Slide 13
Using metacharacters
preg_match('/MB[^TF]/', $string)
// Matches nothing and returns 0
preg_match('/MBT[^^]/', $string)
// Matches MBT- and returns 1
preg_match('/MBT-[1-5]/', $string)
// Matches MBT-3 and returns 1
preg_match('/MBT[_*-]/', $string)
// Matches MBT- and returns 1
C15, Slide 14
Using bracket expressions
preg_match('/MBT[[:punct:]]/', $string)
// Matches MBT- and returns 1
preg_match('/MBT[[:digit:]]/', $string)
// Matches nothing and returns 0
preg_match('/MB[[:upper:]]/', $string)
// Matches MBT and returns 1
C15, Slide 15
Patterns for string positions
Pattern Matches
^ The beginning of the string (use \^ to match a caret)
$ The end of the string (use \$ to match a dollar sign)
\b The beginning or end of a word (must not be inside
brackets)
\B A position other than the beginning or end of a word
C15, Slide 16
Matching string positions
$author = 'Ray Harris';
preg_match('/^Ray/', $author)
// Returns 1
preg_match('/Harris$/', $author)
// Returns 1
preg_match('/^Harris/', $author)
// Returns 0
preg_match('/Ann/', $editor)
// Returns 1
preg_match('/Ann\b/', $editor)
// Returns 0
C15, Slide 17
Matching subpatterns
$name = 'Rob Robertson';
preg_match('/^(Rob)|(Bob)\b/', $name)
// Returns 1
C15, Slide 18
Matching repeating patterns
$phone = '559-555-6627';
preg_match('/^\d{3}-\d{3}-\d{4}$/', $phone)
// Returns 1
$phone_pattern =
'/^(\d{3}-)|(\(\d{3}\) ?)\d{3}-\d{4}$/';
preg_match($phone_pattern, $phone)
// Returns 1
preg_match($phone_pattern, $fax)
// Returns 1
C15, Slide 19
Look-ahead assertions
(?=[[:digit:]])
// The next character in the pattern must be a digit
(?=.*[[:digit:]])
// The pattern must contain at least one digit
A look-ahead assertion
$pattern = '/^(?=.*[[:digit:]])[[:alnum:]]{6}$/';
preg_match($pattern, 'Harris')
// Assertion fails and returns 0
preg_match($pattern, 'Harri5')
// Matches and returns 1
C15, Slide 20
A negative look-ahead assertion
$pattern = '/^(?!3[2-9])[0-3][[:digit:]]$/';
preg_match($pattern, '32')
// Assertion fails and returns 0
preg_match($pattern, '31')
// Matches and returns 1
C15, Slide 21
A pattern to enforce password complexity
$pw_pattern =
'/^(?=.*[[:digit:]])(?=.*[[:punct:]])[[:print:]]{6,}$/';
preg_match($pw_pattern, $password1)
// Assertion fails and returns 0
preg_match($pw_pattern, $password2)
// Matches and returns 1
C15, Slide 22
How to work with a multiline regular
expression
$string = "Ray Harris\nAuthor";
$pattern1 = '/Harris$/';
preg_match($pattern1, $string);
// Does not match Harris and returns 0
$pattern2 = '/Harris$/m';
preg_match($pattern2, $string);
// Matches Harris and returns 1
C15, Slide 23
How to work with a global regular expression
$string = 'MBT-6745 MBT-5712';
$pattern = '/MBT-[[:digit:]]{4}/';
C15, Slide 24
How to use the preg_replace() function
to replace a pattern with a string
$items = 'MBT-6745 MBS-5729';
$items = preg_replace('/MB[ST]/', 'ITEM', $items);
C15, Slide 25
How to use the preg_split() function
to split a string on a pattern
$items =
'MBT-6745 MBS-5729, MBT-6824, and MBS-5214';
$pattern = '/[, ]+(and[ ]*)?/';
$items = preg_split($pattern, $items);
// $items contains:
// 'MBT-6745', 'MBS-5729', 'MBT-6824', 'MBS-5214'
C15, Slide 26
Regular expressions for testing validity
Phone numbers as: 999-999-9999
/^[[:digit:]]{3}-[[:digit:]]{3}-[[:digit:]]{4}$/
C15, Slide 27
Testing a phone number for validity
$phone = '559-555-6624';
$phone_pattern =
'/^[[:digit:]]{3}-[[:digit:]]{3}-[[:digit:]]{4}$/';
$match = preg_match($phone_pattern, $phone);
// Returns 1
C15, Slide 28
Testing a date for a valid format,
but not for a valid month, day, and year
$date = '8/10/209'; // invalid date
$date_pattern = '/^(0?[1-9]|1[0-2])\/'
. '(0?[1-9]|[12][[:digit:]]|3[01])\/'
. '[[:digit:]]{4}$/';
$match = preg_match($date_pattern, $date);
// Returns 0
C15, Slide 29
Complete email address validation
function valid_email ($email) {
$parts = explode("@", $email);
if (count($parts) != 2 ) return false;
if (strlen($parts[0]) > 64) return false;
if (strlen($parts[1]) > 255) return false;
$atom = '[[:alnum:]_!#$%&\'*+\/=?^`{|}~-]+';
$dotatom = '(\.' . $atom . ')*';
$address = '(^' . $atom . $dotatom . '$)';
$char = '([^\\\\"])';
$esc = '(\\\\[\\\\"])';
$text = '(' . $char . '|' . $esc . ')+';
$quoted = '(^"' . $text . '"$)';
$local_part = '/' . $address . '|' . $quoted . '/';
$local_match = preg_match($local_part, $parts[0]);
if ($local_match === false
|| $local_match != 1) return false;
C15, Slide 30
Complete email address validation (continued)
$hostname =
'([[:alnum:]]([-[:alnum:]]{0,62}[[:alnum:]])?)';
$hostnames = '(' . $hostname .
'(\.' . $hostname . ')*)';
$top = '\.[[:alnum:]]{2,6}';
$domain_part = '/^' . $hostnames . $top . '$/';
$domain_match = preg_match($domain_part, $parts[1]);
if ($domain_match === false
|| $domain_match != 1) return false;
return true;
}
C15, Slide 31
The syntax for creating a new Exception
object
new Exception($message [, $code])
C15, Slide 32
A function that may throw an exception
function calculate_future_value(
$investment, $interest_rate, $years) {
if ($investment <= 0 ||
$interest_rate <= 0 ||
$years <= 0 ) {
throw new Exception(
"All arguments must be greater than zero.");
}
$future_value = $investment;
for ($i = 1; $i <= $years; $i++) {
$future_value +=
$future_value * $interest_rate * .01;
}
return round($futureValue, 2);
}
C15, Slide 33
Methods of Exception objects
getMessage()
getCode()
getFile()
getLine()
getTrace()
getTraceAsString()
C15, Slide 34
The syntax for a try/catch statement
try { statements }
catch (ExceptionClass $exceptionName) { statements }
[ catch (ExceptionClass $exceptionName) { statements } ]...
C15, Slide 35
A statement that rethrows an Exception object
try {
$fv = calculate_future_value(
$investment, $annual_rate, $years);
} catch (Exception $e) {
throw $e;
}
C15, Slide 36
Code that catches all errors and exceptions
(PHP 7 and later)
try {
$fv = calc_future_value(10000, 0.06, 9);
} catch (Exception $e) {
echo 'Error: ' . $e->getMessage();
} catch (Error $e) {
echo 'Error: ' . $e->getMessage();
}
The message for the error above
Error: Call to undefined function calc_future_value()
C15, Slide 37
Code that catches a ParseError (PHP 7 and
later)
try {
require 'calculations.php';
} catch (ParseError $e) {
echo 'Required file not included: '
. $e->getMessage();
}
The message for the error above
Required file not included: syntax error, unexpected '}',
expecting ';'
C15, Slide 38
Code that catches a TypeError (PHP 7 and
later)
try {
$average = avg_of_3(5.1, 2.7, 8.2);
} catch (TypeError $e) {
echo 'Error: ' . $e->getMessage();
}
The message for the error above
Error: Argument 1 passed to avg_of_3() must be of the
type integer, float given
C15, Slide 39
The user interface for the Registration
application
C15, Slide 40
The file structure
app_root/
model/
fields.php The Field and Fields classes
validate.php The Validate class
view/
header.php The HTML and PHP for the header
register.php The HTML and PHP for the form view
success.php The HTML and PHP for the success view
footer.php The HTML and PHP for the footer
index.php The PHP for the controller
main.css The CSS for the application
C15, Slide 41
model/fields.php
<?php
class Field {
private $name;
private $message = '';
private $hasError = false;
C15, Slide 42
model/fields.php (continued)
public function setErrorMessage($message) {
$this->message = $message;
$this->hasError = true;
}
C15, Slide 43
model/fields.php (continued)
class Fields {
private $fields = array();
C15, Slide 44
model/validate.php
<?php
class Validate {
private $fields;
C15, Slide 45
model/validate.php (continued)
// Validate a generic text field
public function text($name, $value, $required = true,
$min = 1, $max = 255) {
// Get Field object
$field = $this->fields->getField($name);
C15, Slide 46
model/validate.php (continued)
// Validate a field with a generic pattern
public function pattern($name, $value, $pattern,
$message, $required = true) {
// Get Field object
$field = $this->fields->getField($name);
C15, Slide 47
model/validate.php (continued)
public function phone(
$name, $value,$required = false) {
$field = $this->fields->getField($name);
C15, Slide 48
model/validate.php
public function email($name, $value, $required = true) {
$field = $this->fields->getField($name);
C15, Slide 49
model/validate.php (continued)
// Split email address on @ sign and check parts
$parts = explode('@', $value);
if (count($parts) < 2) {
$field->setErrorMessage('At sign required.');
return;
}
if (count($parts) > 2) {
$field->setErrorMessage(
'Only one at sign allowed.');
return;
}
$local = $parts[0];
$domain = $parts[1];
C15, Slide 50
model/validate.php (continued)
// Check lengths of local and domain parts
if (strlen($local) > 64) {
$field->setErrorMessage('Username too long.');
return;
}
if (strlen($domain) > 255) {
$field->setErrorMessage(
'Domain name part too long.');
return;
}
C15, Slide 51
model/validate.php (continued)
// Patterns for address formatted local part
$atom = '[[:alnum:]_!#$%&\'*+\/=?^`{|}~-]+';
$dotatom = '(\.' . $atom . ')*';
$address = '(^' . $atom . $dotatom . '$)';
C15, Slide 52
model/validate.php (continued)
// Patterns for domain part
$hostname =
'([[:alnum:]]([-[:alnum:]]{0,62}[[:alnum:]])?)';
$hostnames =
'(' . $hostname . '(\.' . $hostname . ')*)';
$top = '\.[[:alnum:]]{2,6}';
$domainPattern = '/^' . $hostnames . $top . '$/';
C15, Slide 53
The controller (index.php)
<?php
require_once('model/fields.php');
require_once('model/validate.php');
C15, Slide 54
The controller (index.php) (continued)
switch ($action) {
case 'reset':
// Load view
include 'view/register.php';
break;
C15, Slide 55
The controller (index.php) (continued)
case 'register':
C15, Slide 56
The controller (index.php) (continued)
// Load appropriate view based on hasErrors
if ($fields->hasErrors()) {
include 'view/register.php';
} else {
include 'view/success.php';
}
break;
}
?>
C15, Slide 57
The view (view/register.php)
<?php include 'header.php'; ?>
<main>
<form action="." method="post" >
<fieldset>
<legend>User Information</legend>
<label>First Name:</label>
<input type="text" name="first_name"
value="<?php echo
htmlspecialchars($first_name);?>">
<?php echo $fields->getField('first_name')
->getHTML(); ?><br>
<label>Last Name:</label>
<input type="text" name="last_name"
value="<?php echo
htmlspecialchars($last_name);?>">
<?php echo $fields->getField('last_name')
->getHTML(); ?><br>
C15, Slide 58
The view (view/register.php) (continued)
<label>Phone:</label>
<input type="text" name="phone"
value="<?php echo
htmlspecialchars($phone);?>">
<?php echo $fields->getField('phone')
->getHTML(); ?><br>
<label>E-Mail:</label>
<input type="text" name="email"
value="<?php echo
htmlspecialchars($email);?>">
<?php echo $fields->getField('email')
->getHTML(); ?><br>
</fieldset>
C15, Slide 59
The view (view/register.php) (continued)
<fieldset>
<legend>Submit Registration</legend>
<label> </label>
<input type="submit" name="action"
value="Register">
<input type="submit" name="action"
value="Reset"><br>
</fieldset>
</form>
</main>
<?php include 'footer.php'; ?>
C15, Slide 60
A long version of the Registration application
C15, Slide 61