Web Programming Step by Step, 2nd Edition
Lecture 12: PDO
Reading: 13.4.2–13.4.3, 13.5; 2.2.2
Except where otherwise noted, the contents of this document are
Copyright 2012 Marty Stepp, Jessica Miller, and Victoria Kirst.
All rights reserved.
Any redistribution, reproduction, transmission, or storage of part
or all of the contents in any form is prohibited without the author's
expressed written permission.
13.4: Databases and PHP
-
13.1: Database Basics
-
13.2: SQL
-
13.3: Multi-table Queries
-
13.4: Databases and PHP
-
2.2.2: HTML Tables
Including variables in a query - BAD WAY
$title = $_GET["movietitle"];
$stmt = $db->query("SELECT year FROM movies WHERE name = '$title'");
- you should not directly include variables or query parameters in a query
- they might contain illegal characters or SQL syntax to mess up the query
Including variables in a query - OKAY WAY
$title = $db->quote($_GET["movietitle"]);
$stmt = $db->query("SELECT year FROM movies WHERE name = $title");
- can use
$db->quote
to encode a value so it won't mess up a query
- drawbacks:
- easy to forget to use
$db->quote
- need to
$db->quote
each value separately (gets ugly for lots of values)
$title
now contains escaped characters, so it can only be used in a MySQL query, not other parts of your code
- this is what the textbook uses — but we'll use a different method (see next slide)
Including variables in a query - GOOD WAY
$stmt = $db->prepare('SELECT year FROM movies WHERE name = :title');
$stmt->execute(array(':title' => $_GET['movietitle']));
- called a parameterized query (using what's called a prepared statement)
- safely injects the
movietitle
value in a way that won't mess up the query
- breaks down a single query into two steps:
prepare
: parse an “unfinished” query containing temporary placeholders
execute
: safely inject the real values at placeholders, then send the final query to MySQL
- can use a single
prepare
followed by many execute
s to efficiently perform the same query over and over with different values
Parameterized queries with prepare
/execute
$db = new PDO("dbprogram:dbname=database;host=server", username, password);
$stmt = $db->prepare("parameterized SQL query with placeholder markers");
$stmt->execute(array(
marker => value,
marker => value,
...
));
foreach ($stmt as $row) {
do something with $row;
}
- safely injects values into a MySQL query
- will result in an error if your query has placeholders but you forget to give substitute values to
execute
Example: Population Search
$db = new PDO("mysql:dbname=world", "jessica", "guinness");
$stmt = $db->prepare("SELECT * FROM cities WHERE country_code = :code and population >= :pop");
$stmt->execute(array(
':code' => $_GET['c'],
':pop' => $_GET['p']
));
<h2>Cities in '<?= $_GET['c'] ?>' with ≥ <?= $_GET['p'] ?> residents:</h2>
<?php foreach ($stmt as $row) { ?>
<li> <?= $row['name'] ?>: <?= $row['population'] ?> </li>
<?php } ?>
population.php?c=USA&p=1000000
Cities in 'USA' with ≥ 1000000 residents:
- New York: 8008278
- Los Angeles: 3694820
- ...
Common bug: Quoted parameters
$stmt = $db->prepare("SELECT * FROM languages
WHERE country_code = ':code'
AND percentage > ':pctg'");
$stmt = $db->prepare("SELECT * FROM languages
WHERE country_code = :code
AND percentage > :pctg");
- don't put quotes around markers in the
prepare
statement
execute
automatically wraps quotes around the value it injects
- if there are already quotes around the marker, this results in the value having two sets of quotes around it
query
vs. prepare
/execute
- Which do I use?
- For non-parameterized queries (without values dynamically injected), you should always use
query
.
- For parameterized queries (with values dynamically injected), you should always use
prepare
/execute
.
Database/query errors
$db = new PDO("mysql:dbname=imdb_small", "jessica", "guinness");
$stmt = $db->query("SEEELECT * FROM movies WHERE year = 2000");
- database commands can often fail (invalid query; server not responding; etc.)
- normally, PDO commands fail silently by returning
false
or null
- but this makes it hard to notice and handle problems
Exceptions for errors
$db = new PDO("mysql:dbname=imdb_small", "jessica", "guinness");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $db->query("SEEELECT * FROM movies WHERE year = 2000");
- using
setAttribute
, you can tell PDO to throw (generate) a PDOException
when an error occurs
- the exceptions will appear as error messages on the page output
- you can catch the exception to gracefully handle the error
Catching an exception
try {
statement(s);
} catch (ExceptionType $name) {
code to handle the error;
}
- a
try/catch
statement attempts to run some code, but if it throws a given kind of exception, the program jumps to the catch
block and runs that code to handle the error
Example with error checking
try {
$db = new PDO("mysql:dbname=imdb_small", "jessica", "guinness");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $db->query("SEEELECT * FROM movies WHERE year = 2000");
foreach ($stmt as row) { ... }
} catch (PDOException $ex) {
?>
<p>Sorry, a database error occurred. Please try again later.</p>
<p>(Error details: <?= $ex->getMessage() ?>)</p>
<?php
}
2.2.2: HTML Tables
-
13.1: Database Basics
-
13.2: SQL
-
13.3: Multi-table Queries
-
13.4: Databases and PHP
-
2.2.2: HTML Tables
A 2D table of rows and columns of data (block element)
<table>
<tr><td>1,1</td><td>1,2 okay</td></tr>
<tr><td>2,1 real wide</td><td>2,2</td></tr>
</table>
1,1 | 1,2 okay |
2,1 real wide | 2,2 |
table
defines the overall table, tr
each row, and td
each cell's data
- tables are useful for displaying large row/column data sets
-
NOTE: tables are sometimes used by novices for web page layout, but this is not proper semantic HTML and should be avoided
Table headers, captions:
<th>
,
<caption>
<table>
<caption>My important data</caption>
<tr><th>Column 1</th><th>Column 2</th></tr>
<tr><td>1,1</td><td>1,2 okay</td></tr>
<tr><td>2,1 real wide</td><td>2,2</td></tr>
</table>
My important data
Column 1 | Column 2 |
1,1 | 1,2 okay |
2,1 real wide | 2,2 |
th
cells in a row are considered headers; by default, they appear bold
- a
caption
at the start of the table labels its meaning
Styling tables
table { border: 2px solid black; caption-side: bottom; }
tr { font-style: italic; }
td { background-color: yellow; text-align: center; width: 30%; }
My important data
Column 1 | Column 2 |
1,1 | 1,2 okay |
2,1 real wide | 2,2 |
- all standard CSS styles can be applied to a table, row, or cell
- table specific CSS properties:
table, td, th { border: 2px solid black; }
table { border-collapse: collapse; }
Without border-collapse
Column 1 | Column 2 |
1,1 | 1,2 |
2,1 | 2,2 |
With border-collapse
Column 1 | Column 2 |
1,1 | 1,2 |
2,1 | 2,2 |
- by default, the overall table has a separate border from each cell inside
- the
border-collapse
property merges these borders into one
The rowspan
and colspan
attributes
<table>
<tr><th>Column 1</th><th>Column 2</th><th>Column 3</th></tr>
<tr><td colspan="2">1,1-1,2</td>
<td rowspan="3">1,3-3,3</td></tr>
<tr><td>2,1</td><td>2,2</td></tr>
<tr><td>3,1</td><td>3,2</td></tr>
</table>
colspan
makes a cell occupy multiple columns; rowspan
multiple rows
text-align
and vertical-align
control where the text appears within a cell
<table>
<col class="urgent" />
<colgroup class="highlight" span="2"></colgroup>
<tr><th>Column 1</th><th>Column 2</th><th>Column 3</th></tr>
<tr><td>1,1</td><td>1,2</td><td>1,3</td></tr>
<tr><td>2,1</td><td>2,2</td><td>2,3</td></tr>
</table>
.urgent {
background-color: pink;
}
.highlight {
background-color: yellow;
}
col
tag can be used to define styles that apply to an entire column (self-closing)
colgroup
tag applies a style to a group of columns (NOT self-closing)
Don't use tables for layout!
- (borderless) tables appear to be an easy way to achieve grid-like page layouts
- many "newbie" web pages do this (including many UW CSE web pages...)
- but, a
table
has semantics; it should be used only to represent an actual table of data
- instead of tables, use
div
s, widths/margins, floats, etc. to perform layout
- tables should not be used for layout!
- Tables should not be used for layout!!
- TABLES SHOULD NOT BE USED FOR LAYOUT!!!
- TABLES SHOULD NOT BE USED FOR LAYOUT!!!!