Troubleshooting
Troubleshooting (or debugging) is the process of removing errors from our code. The first line of defense in dealing with trouble is to not get in it in the first place! With this goal, always bear in mind our development ground rules:
- Start with something that works. Test, copy & modify an existing file working on a server. Don't start with files of unknown origin!
- Build and test your pages in small increments. Don't make large changes and expect things to go smoothly!
- Back up your important files. Never risk damage to a working page when making changes.
- Make extensive use of documentation, both inside the code, and on a development journal, in your case, the blog.
- NEVER PROGRAM WHEN YOU ARE TIRED. Learn to stop typing, back away from the computer, and take a break and come back later.
- Note the problem you are running into, in your documentation, so you can troubleshoot later! When you lose, don't lose the lesson.
- Programming takes time. Start Early. Remember the 80/50 rule? When you think you are 80% done with an application, you are perhaps 50% done regarding time spent. Many problems don't surface until you are near completion.
Assistance: Most important, I want you to know I'm here to help you in this regard. This class requires a great deal of time outside of class and I need to be able to help you with problems that arise before you get back to class, if possible. Email your code problems to me before you get back to class.
For me to help you, you must:
1) Indent your code properly and test. I won't sort out your curly braces. This may even fix your problem.
2) Document the details and/or background of the problem on your blog.
3) Send a link to the broken page so I can see it, along with an attached word doc with all relevant code. Also send a link to the blog, so that I know to look there.
Now, back to your regularly scheduled Troubleshooting guide:
PHP Error Handling: PHP has configuration options that allow programming errors to display via a web browser or to hide them. When PHP is set to hide all errors, we only get a blank page when we make a critical mistake. This can be good when a site is in production, but not while we are developing. Whether or not errors will display on a server running PHP start from the main PHP configuration file named php.ini.
php.ini: There is a single configuration file in PHP named php.ini. This file is used to establish environmental settings for your specific installation of PHP. It's possible to over-ride some of these settings by creating our own custom php.ini file and placing it in our web root. Not all hosts allow a custom php.ini file.
We can view many of the settings inside our current php.ini file by using a special PHP command named phpInfo()
This command displays information about the versions, settings and options set for the current installation of PHP. We view the data provided by phpInfo() to check configuration settings and for available environment variables on a given system. For example we can see if error reporting has been turned off, which would result in no data being displayed, if PHP encounters an error.
display_errors and log_errors: Two of the most important settings inside the php.ini file are display_errors and log_errors. These are the names of the main settings that allow us to see and track errors while we troubleshoot PHP. While developing our job is easier if these to are set to on or 1 (they are equivalent for the php.ini file):
display_errors = on
log_errors = on
If these settings are off or 0 (zero) in the php.ini file (as viewed by the phpInfo() command) then we will see no errors display on the page. This is frequently desirable for a production (live and in service) web server, but not while we develop applications.
We can view and sometimes alter settings such as display_errors and/or log_errors and others in the php.ini file by using a combination of the PHP functions ini_get() and ini_set(). We use ini_get() to view the current setting and use ini_set() to change it. However we would need to check to see if the settings were changed further down the page on which these commands were called. If we are able to change the behavior in this way, we would need to continue to use these command on every page. Frequently display_errors can not changed by ini_set() for security purposes.
If ini_set() can't change a setting, the alternative (besides contacting the hosting company for advice on how to troubleshoot) is to create a custom php.ini file. This file can contain a subset of settings and be named php.ini and placed in the root of your web space. Your custom php.ini file could therefore contain a single command, like the following:
display_errors = on
Example Error: If PHP has been configured to display errors, a page with a small typographical error could display something ugly like the following:
Parse error: parse error, unexpected $ in main.php on line 59
If PHP has not been configured to display errors, you could get an entirely blank page! You can determine this is the case by viewing the HTML output. If you see upper case HTML & BODY tags with no data, that is what is displayed by PHP when it has been configured to hide all errors.
Source: Code vs Output: There is a danger working with server side programming regarding the visible source code of the HTML page. I try to make the distinction between output (the HTML presented to the browser) vs code (the combination of PHP/HTML that produces the page). While in a straight HTML environment we can grab HTML output, make changes and re-upload a file. In PHP you potentially have dynamic code, not a static page, and you may overwrite all your work! To work with HTML issues, consider taking a 'snapshot' of the HTML output along with all CSS files and open the resulting 'test' page in reamweaver. Then you can isolate the HTML issues and fix it back in the PHP file.
Changing Error Reporting on a Per Page Basis: Once we know error reporting has been turned on, some hosting companies allow us to alter the error-displaying sensitivity on a page and control what types of errors should be reported by declaring the level of reporting before running significant code:
error_reporting(E_ALL); // everything
error_reporting(E_ERROR | E_PARSE); // only major problems
error_reporting(E_ALL & ~E_NOTICE); // everything but notices
As the parameters of the function, &, | and ~ are all bitwise operators to determine what kind of errors are to be reported:
- | stands for ‘OR’.
- & stands for ‘AND’.
- ~ stands for ‘NOT’.
PHP Error Types
|
Value
|
Constant
|
Description
|
Catchable
|
|
1
|
E_ERROR
|
Nonrecoverable error
|
No
|
|
2
|
E_WARNING
|
Recoverable error
|
Yes
|
|
4
|
E_PARSE
|
Parser error
|
No
|
|
8
|
E_NOTICE
|
Possible error
|
Yes
|
|
16
|
E_CORE_ERROR
|
Like E_ERROR but generated by the PHP core
|
No
|
|
32
|
E_CORE_WARNING
|
Like E_WARNING but generated by the PHP core
|
No
|
|
64
|
E_COMPILE_ERROR
|
Like E_ERROR but generated by the Zend Engine
|
No
|
|
128
|
E_COMPILE_WARNING
|
Like E_WARNING but generated by the Zend Engine
|
No
|
|
256
|
E_USER_ERROR
|
Like E_ERROR but triggered by calling trigger_error( )
|
Yes
|
|
512
|
E_USER_WARNING
|
Like E_WARNING but triggered by calling trigger_error( )
|
Yes
|
|
1024
|
E_USER_NOTICE
|
Like E_NOTICE but triggered by calling trigger_error( )
|
Yes
|
|
2047
|
E_ALL
|
Everything except E_STRICT
|
N/A
|
|
2048
|
E_STRICT
|
Runtime notices in which PHP suggests changes to improve code quality (since PHP 5)
|
N/A
|
Catching Errors: As you view the list above, you see a column named 'catchable'. Errors of the 'catchable' level can be responded to inside our code. Errors that are not catchable either show an empty HTML page, notable for placing upper case <HTML> tags (and not much else) in the source when error reporting is turned off, or display an ugly white page describing the page that created the error, the type of error as determined by PHP, and the line of code where the error occurred. This is a goldmine for hackers, so it is no surprise that in a 'production' website (one in use by customers) error reporting is so frequently turned off.
Troubleshooting Errors: While we are working, we want error reporting set in such a way that whe we have errors in the code, PHP will attempt to report them to you. The first type of error we get are called parse errors (E_PARSE). Parse errors are usually simple typos, like forgetting to add a dollar sign to a variable, or close a quote, or end a line with a semi-colon. PHP will report the type of error, and attempt to give you the line number on which it appears. Note that on this error, and others the line number is the general vicinity of the error, in practice it may be close, but not exactly the line number indicated! Here is an example error:
Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING in /home/classes/horsey01/public_html/error.php on line 2
In this case the offending code was on line 2:
prnt "blah";
Here we created a typo by leaving the letter "i" out of the print command. Note that PHP does not know exactly what has happened, and when it sees a command it doesn't recognize, it misjudges the command to be a constant, which is like a variable that doesn't vary (doesn't change) but is recognizable by not having a dollar sign. Here's another example:
Error messages will be reported one at a time, starting with the parse errors. As you fix the errors, more may be reported. This means you are making progress! Another type of error can be called the expected error. This error frequently occurs when PHP expects to see something, but doesn't get what it expects. PHP will tell you "expected }" and give the line number, for example. This is difficult to troubleshoot, as the line number is FREQUENTLY unrelated, in this case. This is because you may have a curly brace turned the wrong way, for example. PHP looks for the match to an open brace, and when it doesn't find it, it keeps going down the page, sometimes to the bottom, before reporting the error! Here's an example:
Parse error: syntax error, unexpected $end in /home/classes/horsey01/public_html/error.php on line 7
In this case the offending code was on line 4:
include "asdf
Since the command was unfinished, PHP continued down the page, and indicated the page came to an unexpected end (unexpected $end above) on line 7, the last line of code!
Error Suppression: Historically we could 'supress' error messages on a line by line basis by placing the "@" symbol in front of our potentially offending code:
@include "my_inc.php";
This appears to work less often, and on less servers. Further, it hides errors we may wish to fix.
or die() function: PHP being a determined language, uses an odd construct, and displays a functional kind of a 'do or die()' attitude in some of it's code. View the following example:
mysqli_query($iConn,$sql) or die(print mysqli_error($iConn));
Although this example is a little beyond us as it represents a connection to the database, notice the highlighted or die() section of code. If PHP encounters an error connecting to the database to retrieve data, we can optionally place code to be run if an error occurs. In this case we print the database error to the page, and stop the page from running entirely.
print and die: Sometimes you make a mistake inside the code that is not visible when the page is run. We may wish to halt page execution, and print data to the screen, so we can see what is going in our page. To do this, we do what is called print and die.
print "myVar: " . $myVar;
die();
The above example prints a variable to the page and halts execution. No code is run beyond the "die" statement. The die() works identically to the exit command. You can print the contents of any number of variables just before the die statement, to see what the current contents include. You can check your pages in various locations in this manner.
Another version of the above uses print_r() to allow us to print the value of an array, without a loop:
print_r($myArray);
die();
A more comprehensive trick is to use var_dump(), which prints information about a series of variables, arrays or objects and exposes all data and all data types contained inside:
$b = 3.1;
$c = true;
var_dump($b, $c);
Other Tips
Comment Out Problem Code: Another trick is to comment out possible offending code, to narrow down where the mistake can be. Remember to use the larger scale comment tags, /* and */ for this.
Check/Troubleshoot HTML Output: Sometimes you will need to view the output of the page, after the page is run. If you have an HTML error, like a missing quote, the HTML could submerge, or no longer be visible, but could show up in the output of your PHP page, when the source is viewed in a browser. If your problem is an HTML problem instead of a PHP problem, you can copy all pertinent HTML and work in Dreamweaver (for example) to troubleshoot the HTML problem.
Seeing No Changes?: Lastly, if you are making changes to your page, and nothing makes a difference , add a print and die line at the top of the page, and see if the message appears. If it does not, you may be uploading to the wrong directory, or the FTP client may not be updating the page, which CAN HAPPEN with Unix!
At this point you could rename your page and save it elsewhere to see if you can see your page changes. STOP MAKING CHANGES the moment you suspect nothing is working! If you continue making changes, you may be compounding the problem!
Error At The Bottom Of The Page?: If you see an error message, and the code points to the last line of a PHP block, the usual cause is a curly brace or paren turned the wrong direction. If you open another curly brace, instead of closing it, PHP looks for the match until it hits the end of the block. If no match is found, an error is reported.
Case Sensitivity: PHP is strangely inconsistent on case sensitivity. It is OVERLY case sensitive on variables you create. It also is case sensitive on SuperGlobals, such as $_POST and $_SERVER. However, on it's own functions, such as phpInfo(), it is not case sensitive. When PHP encounters something that is in the wrong case, it will not know what you wanted.
Fun With Quotes: While you can use double or single quotes in print statements, remember you must stick with one per statement. You can also get into trouble when you need to escape the type of quotes you are using. Later, single quotes will trip up MySQL.
Assignment vs Comparison: Assigning a variable uses a single equal sign, but to compare a value, we use a double equal:
if($a == $b)
{
print "they are equal!";
}
If you mix these up, you get unexpected results! Also remember your compound operators, like += can have no space between the characters! Remember the triple equal sign operator! This version returns true if the data on either side matches and even the data type must match. For example, two variables can contain the number 2, but one may be an integer and one may be a decimal:
if($a === $b)
{
print "the contents are equal, as well as the data types!";
}
Exceptions: We can use a try/catch block to determine if our program will crash, or even if we are getting data we did not expect. Exceptions are particularly useful if you are attempting to connect to an external data source. For examples, view Exceptions in PHP
Performance Warning: Only use exceptions in exceptional circumstances! And that is across all languages: Try/Catch Performance