One of the most useful skills that you can acquire in HTML development and PHP programming is called "debugging" . A "bug" is something that goes wrong with a Web page or the server or some other aspect of the Internet that you are dealing with. "Debugging" means the process of finding out what is going wrong, and (hopefully) fixing it.
There are three main parts of the Internet that you will be dealing with as you develop PHP pages:
The following sections will give you some ideas regarding how to deal with some of the most common errors that you may encounter from these parts of the Internet.
The messages listed here are just a tiny sampling of the messages that you might see. I can add to this list as we encounter other messages....
Some PHP servers are set up to suppress most of the error messages that could otherwise display in the Web page.
If a PHP page on one of these servers has a syntax error, the PHP processor will probably quit before it can display the error message. The Web page becomes, quite literally, a totally empty "white screen of death".
The "Runtime Configuration" reference page at php.net has some clues about how to fix this "white screen of death" situation. The instructions are a bit cryptic, so here are the instructions in more or less plain English:
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1); // this can also be ini_set("display_errors", "on");
?>
This magic solution basically boils down to this: You need a special testing page of some kind.
Here is a sample of a special testing page. This example assumes that the page that you are trying to debug and find errors in, is errorTest.php. This magic test page is testBed.php:
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
include("errorTest.php");
?>
You can see the test page which includes an error here. Note the white screen of death! (But in the Chrome brower you may see an error message which says "Server Error 500". It is the same situation as the "white screen of death".)
Now here is the same page, as included by testBed.php, which has the three lines of code shown above in it. Now you can actually see the syntax error message in errorTest.php!
Here is the fixed page, errorTestFixed.php,.
Here is the full code for page errorTest.php: Do you see the syntax error?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="../myStyles.css">
<title>Error Test</title>
</head>
<body>
<div id="mainDiv">
<h1>PHP Error Test</h1>
<?php
ini_set('display_errors', 'On');
ini_set('error_reporting', E_ALL);
echo "<p>Test</p>";
echo "<p>Another test</p>"
echo "<p>How are we doing?</p>";
?>
</div>
</body>
</html>
A slightly more complicated test-bed arrangement is shown below. It is much more flexible in that it lists all of the PHP pages in the directory in a select list, and then the form's action page displays the selected page as a "testBed" include file like we looked at just a few minutes ago. You don't need to worry about how the select list is created in this page yet; we will look at similar code in another e-handout later in the semester.
Here is the page-selection form page, testBedInputForm.php:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>TestBed Input Form</title>
<link rel="stylesheet" href="myStyles.css">
</head>
<body>
<div id="mainDiv">
<h3>Test Bed Input Form</h3>
<?php
function fileTypePHP($filename) {
// returns whether the file is of type *.php
$hasPHP = stripos($filename, ".php");
if ($hasPHP === false) {
return false;
} else {
return true;
}
}
$dir = '.';
$files1 = scandir($dir);
$files1_PHP = array_filter($files1, "fileTypePHP");
$files_compact = array_merge($files1_PHP);
?>
<form method="post" action="runTestBed.php">
Select the page to run as a testBed include:<br><br>
<select name="fileToInclude">
<?php
for ($i = 0; $i < count($files_compact); $i++) {
echo "<option value='{$files_compact[$i]}'>{$files_compact[$i]}</option>\n";
}
?>
</select>
<br><br>
<input type="submit" value="Run the Test Bed Include">
</form>
</div>
</body>
</html>
And now here is the form's action page, runTestBed.php:
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
include("{$_POST['fileToInclude']}");
?>
You can see this more flexible test-bed page running here. (The user is Get and the password is TestBedList)
Just in case you do want to understand some of the details in this set of more flexible test-bed pages, here are some items to note:
When you ask your browser to display a PHP page, the page is loaded by the PHP server (on the Web server) and then the PHP server parses and syntax-checks the page. (The term "parse" means that the PHP server figures out what commands, text, tags, etc. are in the page.) After the PHP page has been parsed and checked for syntax errors, it still needs to be executed/run by the PHP server. If anything goes wrong with this execution of the page, an error situation (technically called an "exception") can be created by the PHP server.
When PHP discovers an error and creates an exception, we say that PHP "throws" the exception. (Your code can also explicity "throw" an exception if you discover something wrong with the page's running. More on that later.)
If an exception is "thrown" (either by the PHP server or by your code), it needs to be "caught". If a "thrown" exception is not "caught", a default error message is displayed, and this default display of the error message is ugly. But you have the option to handle errors in a more graceful and pleasing way than the ugly default handling that PHP uses.
Here is how you can control the handling and communication of error situations (and make the information a bit less ugly than how the PHP server handles the information by default):
Here is some sample code that shows how an error looks without try and catch, and how the same error looks when you handle it with try and catch. (This page has the database's table name misspelled on purpose, to create the error.)
The first page, without try and catch, is database4a.php:
<?php
error_reporting (E_ALL);
require "config.php";
$mysqli = new mysqli(DBSERVER, DBUSER, DBPWD, DBNAME);
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PHP Database Access</title>
</head>
<body>
<!-- Create a database error which is NOT caught -->
<?php
error_reporting (E_ALL);
$result = $mysqli->query ( "SELECT * FROM Transactionz ORDER BY TransDate DESC, Description" );
$row = $result->fetch_assoc();
echo "<table>\n";
echo "<tr><th>Name</th><th>City</th><th>State</th></tr>\n";
while ($row !== null)
{
$rowId = $row["ID"];
$transDate = $row["TransDate"];
$amount = $row["Amount"];
$descr = $row["Description"];
printf('<tr>
<td class="numeric">%s</td>
<td class="numeric">$%01.2f</td>
<td>%s</td>
<td>
<form action="edittrans.php" method="post">
<input type="hidden" name="rowID" value="%d" />
<input type="submit" value="Edit" />
</form>
</td>
<td>
<form action="deletetrans.php" method="post">
<input type="hidden" name="rowID" value="%d" />
<input type="submit" value="Delete" />
</form>
</td>
</tr>',
date("m/d/Y", strtotime($transDate)),
$amount,
$descr,
$rowId,
$rowId);
$row = $result->fetch_assoc();
} //end while()
echo "</td></tr>\n";
echo "</table>\n";
?>
</body>
</html>
Here is the second page, which is very similar to the first, but which uses try and catch. (This page also has the database's table name misspelled on purpose, to create the error.) This is page database4b.php:
<?php
error_reporting (E_ALL);
require "config.php";
$mysqli = new mysqli(DBSERVER, DBUSER, DBPWD, DBNAME);
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PHP Database Access</title>
<link rel="stylesheet" href="myStyles.css">
</head>
<body>
<div id="mainDiv">
<!-- Create a database error which is CAUGHT -->
<?php
error_reporting(0);
try
{
$result = $mysqli->query ( "SELECT * FROM Transactionz ORDER BY TransDate DESC, Description" );
if ($result === false)
{
throw new Exception($mysqli->error);
}
$row = $result->fetch_assoc();
echo "<table>\n";
echo "<tr><th>Name</th><th>City</th><th>State</th></tr>\n";
while ($row !== null)
{
$rowId = $row["ID"];
$transDate = $row["TransDate"];
$amount = $row["Amount"];
$descr = $row["Description"];
printf('<tr>
<td class="numeric">%s</td>
<td class="numeric">$%01.2f</td>
<td>%s</td>
<td>
<form action="edittrans.php" method="post">
<input type="hidden" name="rowID" value="%d" />
<input type="submit" value="Edit" />
</form>
</td>
<td>
<form action="deletetrans.php" method="post">
<input type="hidden" name="rowID" value="%d" />
<input type="submit" value="Delete" />
</form>
</td>
</tr>',
date("m/d/Y", strtotime($transDate)),
$amount,
$descr,
$rowId,
$rowId);
$row = $result->fetch_assoc();
} //end while()
echo "</td></tr>\n";
echo "</table>\n";
}
catch (Exception $e)
{
echo "The site has experienced a serious error.<br /><br />";
echo "Please call the site administrator at <strong>1-800-333-3333</strong>,<br />";
echo "or send e-mail to <strong>support@mysite.edu</strong>, and give them this information:<br /><br />";
echo $e->getMessage(), "<br />";
}
?>
</div>
</body>
</html>
Please note these points about the above code:
error_reporting (E_ALL)
error_reporting(0);
@echo "This line will not ever generate an error message.";you need to be aware that the "@" sign is the "Error Control Operator". It tells PHP not to generate errors for this statement. If you use this operator you are potentially creating a debugging nightmare for yourself.
There are three very handy PHP functions that you can use for debugging. They are print_r(), var_dump(), and var_export().
Shown below is some code that shows how these functions can display complex data in your debugging efforts.
Here is a simple HTML form page, which sends its data to a PHP processing page. This is file testFormData.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="myStyles.css">
<title>Display Form Data</title>
<script type="text/javascript">
function validate()
{
var retValue = true;
var phone = document.getElementById("theNumber").value;
var phoneRE = /^\(?\d{3}\)?(\s|\.|-)?\d{3}(\s|-|\.)?\d{4}$/;
retValue = phoneRE.test(phone);
if (!retValue)
{
alert("Please enter a valid phone number.");
}
return retValue;
}
</script>
</head>
<body>
<div id="mainDiv">
<form name="theForm" action="displayFormInfo.php"
method="post" onsubmit="return validate();">
Please enter your name:
<input type="text" name="theName" id="theName">
<br>
<br>
Please enter your phone number:
<input type="text" name="theNumber" id="theNumber">
<br>
<br>
<input type="submit" value="Send the form information">
</form>
</div>
</body>
</html>
Here is the form's action page, displayFormInfo.php:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="myStyles.css">
<title>Display Form Info</title>
</head>
<body>
<div id="mainDiv">
<h3>This is the form data that was sent:</h3>
<?php
echo("<b>print_r(\$_POST):</b> <br /><br />");
echo("<pre>");
print_r($_POST);
echo("</pre>");
echo("<b>var_dump(\$_POST):</b> <br /><br />");
echo("<pre>");
var_dump($_POST);
echo("</pre>");
echo("<b>var_export(\$_POST):</b> <br /><br />");
echo("<pre>");
var_export($_POST);
echo("</pre>");
?>
</div>
</body>
</html>
Please note these points about the above code:
In the real world of PHP, you will often run into a situation where an error is occurring and you just can't see the data (variables) that are involved in the situation.
A very handy function that you can use for displaying the data (variables) in such a difficult situation is the disp() custom function.
You can create your own disp() function, but fortunately you don't need to. I am giving it to you right here! I did not originate the idea for disp(), but when a co-worker created it, I pretty quickly made my own version on my personal PHP site!
Please note that the disp() function is in an include file. It does not need to be in its own directory, although it is. But you do need to include this file in the page that you are debugging, if you want to use disp() for debugging.
Here is the file that disp() is in. This is the "include" file helperStuff.php:
<?php
/*
*
* Function disp()
* Displays the data/variable that is sent in via the First parameter, $data.
* Second parameter: $runAndDie. Defaults to dying. If you want the test page to keep running, send in false.
* Third parameter: $useVardump. Defaults to false. disp() uses print_r() by default. To use var_dump(), send in true.
*
*/
function disp($data = null, $runAndDie = false, $useVardump = false)
{
if ((!empty($data)) && ($data !== null))
{
echo "<pre>\n";
if ($useVardump === true)
{
var_dump($data);
}
else
{
print_r($data);
}
echo "</pre>\n";
if ($runAndDie === true)
{
die("done");
}
}
else
{
echo "<p>No arguments given for disp()</p>\n";
}
}
?>
Now here is a test page which shows how to include the file helperStuff.php and how to use the disp() function. This is page TestDisp.php:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test the disp() function</title>
<link rel="stylesheet" href="myStyles.css">
</head>
<body>
<div id="mainDiv">
<h3>Test the disp() debugging function</h3>
<?php
include "includes/helperStuff.php";
$testVar = new stdClass();
$testVar->State = "Texas";
$testVar->Features = array("Description"=>"The Lone Star State", "Philosophy"=>"I wasn't born here but I got here as fast as I could!");
echo "<h4>Using var_dump() and continuing to run:</h4>\n";
disp($testVar, false, true);
echo "<h4>Using no arguments</h4>\n";
disp();
echo "<h4>Using only the first argument</h4>\n";
disp($testVar);
echo "<h4>Using print_r() and dying:</h4>\n";
disp($testVar, true, false);
?>
</div>
</body>
</html>
You can see the above page running here.
Now, please note these points about the above pages:
Macromedia's Dreamweaver has some features that can help you do your PHP coding. Here are some ideas and hints. Please note that these instructions only work on server www.multimedia.richlandcollege.edu at Richland. The main Multimedia Learning Center server, www.mmlab2.rlc.dcccd.edu, requires FTPES as its FTP type, which Dreamweaver does not support.
http://www.multimedia.richlandcollege.edu/imed2351n01/web5401/(using your folder name, of course, in place of "web5401") and click the "Test URL" button.
http://www.multimedia.richlandcollege.edu/imed2351n01/web5401/(using your folder name, of course, in place of "web5401").
The Chrome and Firefox browsers have some very nice built-in debugging aids called "Developer Tools".
You can open the Developer Tools from the Settings menu under "Tools", "Developer tools"; or you can press the <Ctrl> + <Shift> + I keys (that's an uppercase "i" as the third key) simultaneously to open up the same screen, or you can press the F12 key.
For PHP debugging purposes, the "Network" and "Console" tabs in the Developer Tools are probably the most useful.
The "Network" tab shows you what pages and files were loaded or failed to load.
The "Console" tab shows you scripting errors from JavaScript. Most PHP pages also include some JavaScript code, so even though JavaScript does not directly affect the PHP code, sometimes a JavaScript error will prevent the Web server from completing its processing of the page.