Chapter 3
IN THIS CHAPTER
PHP and MySQL: Understanding web development’s most enduring marriage
Connecting to a MySQL database with PHP
Using PHP to access MySQL data with a SELECT query
Processing the SELECT query results
Using PHP to run INSERT, UPDATE, and DELETE queries
PHP and MySQL work together to provide powerful, flexible components that can keep up with the expanding database driven development needs of virtually any organization, large or small.
— ISAAC DUNLAP
Run a Google search on the text PHP MySQL "Match made in heaven"
and you get more than a few results. I'm not surprised one bit because it seems as though these two technologies were meant to be together; a case of love at first byte, as it were. What’s the secret of their success as a couple? First, it helps that they’re both free (not the usual prerequisite for marriage success, I know), which ensures that they’re both widely available and widely supported. Second, both PHP and MySQL reward a little bit of learning effort up front with a lot of flexibility and power right off the bat. Although both are complex, sophisticated pieces of technology, you need to learn only a few basics to take your web development skills to a whole new level. I cover the first two parts of those basics in Chapters 1 and 2 of this minibook. In this chapter, I bring everything together by showing you how to combine PHP and MySQL to create the foundation you need to build truly dynamic and powerful web applications.
Before getting to the trees of actual PHP code, I want to take a moment to look out over the forest of the server back end, so you’re comfortable and familiar with the process. Specifically, I want to look at how PHP and MySQL team up to deliver the back-end portion of a web app. Rather than getting bogged down in an abstract discussion of what happens when a user requests a page that requires some data from the server, I’ll use a concrete example. The following steps take you through the back-end process that happens when the web app I built to display this book’s sample code gets a request for a specific example:
http://mcfedries.com/webcodingfordummies/example.php?book=4&chapter=1&example=2
The PHP script file is example.php
and the request data — known to the cognoscenti as a query string — is everything after the question mark (?
): book=4&chapter=1&example=2
. This string is requesting the second example from Book 4, Chapter 1.
example.php
and sends it to the PHP processor.The PHP script parses the query string to determine which sample the user is requesting.
For the query string shown in Step 1, the script would extract the book number as 4, the chapter number as 1, and the example number as 2.
The script uses the query string data to create and run a SELECT query that returns the sample code.
The SELECT
statement looks something like this:
SELECT *
FROM code_samples
WHERE book_num=4 AND chapter_num=1 AND example_num=2
The script massages the SELECT results into a format readable by the browser.
This format is usually just HTML, but another popular format is JSON (JavaScript Object Notation), which you learn about in Book 6, Chapter 1.
The rest of this chapter expands on Steps 3 through 6.
When used as the back end of a web app, PHP's main job is to interact with MySQL to retrieve the data requested by the app and then format that data so that it’s usable by the app for display in the browser. To do all that, PHP runs through five steps:
I talk about INSERT, UPDATE, and DELETE queries later in this chapter, but the next few sections take you through the details of this five-step procedure from the point of view of a SELECT query.
Many PHP scripts don’t require any information from the web app to get the data that the app needs. For example, if the script’s job is to return every record from a table, or to return a predetermined subset of a table, then your app just needs to call the script.
However, it’s more common for a web app to decide on-the-fly (say, based on user input or some other event) what data it requires, and in such cases it needs to let the server know what to send. To get your web app to request data from the web server, you send a query string to the server. You can send a query string using two different methods:
In the GET case, the query string is a series of name-value pairs that use the following general form:
name1=value1&name2=value2&…
Here’s an example:
book=4&chapter=1&example=2
In the case of a GET request, you build the request by taking the URL of the PHP script that will handle the request, adding a question mark (?
) to designate the boundary between the script address and the query string, and then adding the query string itself. Here’s an example:
http://mcfedries.com/webcodingfordummies/example.php?book=4&chapter=1&example=2
Now your PHP script has something to work with, and you access the query string data by using PHP’s $_GET
variable, which is an associative array created from the query string's name-value pairs. Specifically, the array’s keys are the query string’s names, and the array’s values are the corresponding query string values. For example, the preceding URL creates the following $_GET
array:
$_GET['book'] => 4
$_GET['chapter'] => 1
$_GET['example'] => 2
Note, however, that it’s good programming practice to not assume that the $_GET
array is populated successfully every time. You should check each element of the array by using PHP's isset()
function, which returns true
if a variable exists and has a value other than null
. Here's some PHP code that checks that each element of the preceding $_GET
array exists and isn’t null
:
if (isset($_GET['book'])) {
$book_num = $_GET['book'];
} else {
echo 'The "book" parameter is missing!<br>';
echo 'We are done here, sorry.';
exit(0);
}
if (isset($_GET['chapter'])) {
$chapter_num = $_GET['chapter'];
} else {
echo 'The "chapter" parameter is missing!<br>';
echo 'Sorry it didn't work out.';
exit(0);
}
if (isset($_GET['example'])) {
$example_num = $_GET['example'];
} else {
echo 'The "example" parameter is missing!<br>';
echo 'You had <em>one</em> job!';
exit(0);
}
This code checks each element of the $_GET
array:
null
, the code assigns the array value to a variable.null
, the code outputs a message specifying the missing parameter and then stops the code by running the exit(0)
function (the 0
just means that you're terminating the script in the standard way).You give PHP access to MySQL through an object called MySQLi
(short for MySQL Improved). There are actually several ways to bring PHP and MySQL together, but MySQLi is both modern and straightforward, so it’s the one I cover in this book.
You connect to a MySQL database by creating an instance of the MySQLi
object. Here's the general format to use:
$var = new MySQLi(hostname, username, password, database);
$
var
: The variable that stores the new MySQLi
object.hostname
: The name of the server that's running MySQL. If the server is on the same computer as your script (which is usually the case), then you can use localhost
as the hostname
.username
: The account name of a user who has access to the MySQL database.password
: The password associated with the username
account.database
: The name of the MySQL database.Here's a script that sets up the connection parameters using four variables, and then creates the new MySQLi
object:
<?php
$host = 'localhost';
$user = 'logophil_reader';
$password = 'webcodingfordummies';
$database = 'logophil_webcodingfordummies';
$mysqli = new MySQLi($host, $user, $password, $database);
?>
However, you shouldn’t connect to a database without also checking that the connection was successful. Fortunately, the MySQLi
object makes this easy by setting two properties when an error occurs:
connect_errno
: The error numberconnect_error
: The error messageThese properties are null
by default, so your code can use an if()
test to check if either connect_error
or connect_errno
has been set:
if($mysqli->connect_error) {
echo 'Connection Failed!
Error #' . $mysqli->connect_errno
. ': ' . $mysqli->connect_error;
exit(0);
}
If an error occurs, the code displays a message like the one shown in Figure 3-1 and then runs exit(0)
to stop execution of the script.
Before moving on to querying the database, there are two quick housekeeping chores you need to add to your code. First, tell your MySQLi
object to use the UTF-8 character set:
$mysqli->set_charset('utf8');
Second, use the MySQLi
object's close()
method to close the database connection by adding the following statement at the end of your script (that is, just before the ?>
closing tag):
$mysqli->close();
To run a SELECT query on the database, you need to create a string variable to hold the SELECT
statement and then use that string to run the MySQLi
object's query()
method. Here’s an example:
$sql = 'SELECT category_name, description
FROM categories';
$result = $mysqli->query($sql);
// Check for a query error
if (!$result) {
echo 'Query Failed!
Error: ' . $mysqli->error;
exit(0);
}
The result of the query is stored in the $result
variable. You might think that this variable now holds all the data, but that's not the case. Instead, $result
is an object that contains information about the data, not the data itself. You make use of that information in the next section, but for now notice that you can use the result object to check for an error in the query. That is, if $result
is null
, the query failed, so display the error message (using the MySQLi
object's error
property) and exit the script.
$result->num_rows
The object returned by the query()
method is really just a pointer to the actual data, but you can use the object to retrieve the SELECT query's rows. There are various ways to do this, but I’ll go the associative array route, which uses the result object’s fetch_all(MYSQLI_ASSOC)
method to return all the rows as an associative array. (If you prefer to work with a numeric array, replace the MYSQLI_ASSOC
constant with MYSQLI_NUM
):
$array = $mysqli_result->fetch_all(MYSQLI_ASSOC);
$
array
: The name of the associative array you want to use to hold the query rows$
mysqli_result
: The result object returned by MySQLi's query()
methodNote that this is a two-dimensional array, which makes sense because table data is two-dimensional (that is, it consists of one or more rows and one or more columns).
I’ll make this more concrete by extending the example:
$sql = 'SELECT category_name, description
FROM categories';
$result = $mysqli->query($sql);
// Check for a query error
if (!$result) {
echo 'Query Failed!
Error: ' . $mysqli->error;
exit(0);
}
// Get the query rows as an associative array
$rows = $result->fetch_all(MYSQLI_ASSOC);
// Get the total number of rows
$total_rows = count($rows);
echo "Returned $total_rows categories:<br>";
Here, fetch_all()
stores the query result as an array named $rows
. The code then uses count()
to get the total number of rows in the array.
By storing the query results in an array, you make it easy to process the data by looping through the array using a foreach()
loop:
// Get the query rows as an associative array
$rows = $result->fetch_all(MYSQLI_ASSOC);
// Loop through the rows
foreach($rows as $row) {
echo $row['category_name'] . ': ' .
$row['description'] . '<br>';
}
Here's what’s happening in the foreach()
loop:
$rows
array is referenced using the $row
variable.$row
item is itself an associative array, where the key-value pairs are the column names and their values.$row
array are the column names, the code can refer to the values using the $row['
column
']
syntax.I talk earlier in this chapter about how you can use $_GET
to parse a URL's query string, so now I show you an example that uses a query string value in a SELECT query. First, here’s the code:
<body>
<?php
// Parse the query string
if (isset($_GET['category'])) {
$category_num = $_GET['category'];
} else {
echo 'The "category" parameter is missing!<br>';
echo 'We are done here, sorry.';
exit(0);
}
// Store the database connection parameters
$host = 'localhost';
$user = 'logophil_reader';
$password = 'webcodingfordummies';
$database = 'logophil_webcodingfordummies';
// Create a new MySQLi object with the
// database connection parameters
$mysqli = new MySQLi($host, $user, $password, $database);
// Create and run a SELECT query
// This is an INNER JOIN of the products and
// categories tables, based on the category_id
// value that was in the query string
$sql = "SELECT products.product_name,
products.unit_price,
products.units_in_stock,
categories.category_name
FROM products
INNER JOIN categories
ON products.category_id = categories.category_id
WHERE products.category_id = $category_num";
$result = $mysqli->query($sql);
// Get the query rows as an associative array
$rows = $result->fetch_all(MYSQLI_ASSOC);
// Get the category name
$category = $rows[0]['category_name'];
echo "<h2>$category</h2>";
echo '<table>';
echo '<tr>';
echo '<th>Product</th>';
echo '<th>Price</th>';
echo '<th>In Stock</th>';
echo '</tr>';
// Loop through the rows
foreach($rows as $row) {
echo '<tr>';
echo '<td>' . $row['product_name']. '</td>
<td>' . $row['unit_price'] . '</td>
<td>' . $row['units_in_stock'] . '</td>';
echo '</tr>';
}
echo '</table>>';
// That's it for now
$mysqli->close();
?>
</body>
First, note that to keep the code shorter, I removed the error checking code. There’s quite a bit going on here, so I’ll go through it piece by piece:
http://mcfedries.com/webcodingfordummies/5-3-4.php?category=1
$_GET['category']
to get the category number from the query string, and that value is stored in the $category_num
variable.SELECT
statement, which is an inner join on the products
and categories
tables. The WHERE
clause restricts the results to just those products that have the category value from the query string:
WHERE products.category_id = $category_num
query()
method runs the SELECT query and stores the result in the $result
object.fetch_all(MYSQLI_ASSOC)
method stores the returned row in an associative array named $rows
.$rows
array includes the category name in the category_name
column, so the script arbitrarily uses $rows[0]['category_name']
to get the category name and store it in the $category
variable.<h2>
heading for the category name, as well as some HTML table tags.foreach()
loop runs through the query rows. During each pass, the code outputs an HTML table row (<tr>
) and a table cell (<td>
) for each value.</table>
tag and closes the MySQLi
connection.Figure 3-2 shows the result.
Performing INSERT, UPDATE, and DELETE queries in PHP is much simpler than performing SELECT queries because once your code has checked whether the query completed successfully, you're done. Here’s an example that runs an INSERT query:
<?php
// Store the database connection parameters
$host = 'localhost';
$user = 'logophil_reader';
$password = 'webcodingfordummies';
$database = 'logophil_webcodingfordummies';
// Create a new MySQLi object with the
// database connection parameters
$mysqli = new MySQLi($host, $user, $password, $database);
// Check for a connection error
if($mysqli->connect_error) {
echo 'Connection Failed!
Error #' . $mysqli->connect_errno
. ': ' . $mysqli->connect_error;
exit(0);
}
// Create and run an INSERT query
$sql = "INSERT
INTO categories (category_name, description)
VALUES ('Breads', 'Multi-grain, rye, and other deliciousness')";
$result = $mysqli->query($sql);
// Check for a query error
if (!$result) {
echo 'Query Failed!
Error: ' . $mysqli->error;
exit(0);
}
?>
When given an INSERT
, UPDATE
, or DELETE
statement, MySQLi's query()
method returns true
if the query executed successfully, or false
if the query failed.
When you're building a web app or some other medium-to-large web project that requires a back end, you’ll soon notice that your PHP scripts that access the project’s MySQL data begin to multiply in a rabbitlike fashion. Before you know it, you’ve got 10 or 20 such scripts lying around. What do these scripts all have in common? They all include the same code for connecting to the project’s MySQL database. It’s not a big deal to just copy and paste that code into each new script, but it can be a huge deal if one day you have to change your login credentials. For example, for security reasons you might decide to change the password. That means you now have to wade through every single one of your scripts and make that change. Annoying!
A better way to go is to make use of PHP’s require
statement, which enables you to insert the contents of a specified PHP file into the current PHP file:
require php_file;
php_file
: The path and filename of the PHP file you want to insertSo what you do is take your MySQL database credentials code and paste it into a separate PHP file:
<?php
$host = 'localhost';
$user = 'logophil_reader';
$password = 'webcodingfordummies';
$database = 'logophil_webcodingfordummies';
?>
Say this file is named credentials.php
. If it resides in the same directory as your scripts, then you’d replace the credentials code in your PHP scripts with the following statement:
require 'credentials.php';
If the credentials file resides in a subdirectory, then you need to include the full path to the file:
require '/includes/credentials.php';
Note that if PHP can’t find or load this file for some reason, the script will halt with an error.
3.144.238.20