PHP – Error Handling

Certify and Increase Opportunity.
Be
Govt. Certified PHP-Developer

Error Handling

When creating scripts and web applications, error handling is an important part. If your code lacks error checking code, your program may look very unprofessional and you may be open to security risks.

This tutorial contains some of the most common error checking methods in PHP.

We will show different error handling methods:

  • Simple “die()” statements
  • Custom errors and error triggers
  • Error reporting

Basic Error Handling: Using the die() function

The first example shows a simple script that opens a text file:

<?php
$file=fopen(“welcome.txt”,”r”);
?>

If the file does not exist you might get an error like this:

Warning: fopen(welcome.txt) [function.fopen]: failed to open stream:
No such file or directory in C:\webfolder\test.php on line 2

To avoid that the user gets an error message like the one above, we test if the file exist before we try to access it:

<?php
if(!file_exists(“welcome.txt”))
{
die(“File not found”);
}
else
{
$file=fopen(“welcome.txt”,”r”);
}
?>

Now if the file does not exist you get an error like this:

File not found

The code above is more efficient than the earlier code, because it uses a simple error handling mechanism to stop the script after the error.

However, simply stopping the script is not always the right way to go. Let’s take a look at alternative PHP functions for handling errors.


Creating a Custom Error Handler

Creating a custom error handler is quite simple. We simply create a special function that can be called when an error occurs in PHP.

This function must be able to handle a minimum of two parameters (error level and error message) but can accept up to five parameters (optionally: file, line-number, and the error context):

Syntax

error_function(error_level,error_message,
error_file,error_line,error_context)

 

ParameterDescription
error_levelRequired. Specifies the error report level for the user-defined error. Must be a value number. See table below for possible error report levels
error_messageRequired. Specifies the error message for the user-defined error
error_fileOptional. Specifies the filename in which the error occurred
error_lineOptional. Specifies the line number in which the error occurred
error_contextOptional. Specifies an array containing every variable, and their values, in use when the error occurred

Error Report levels

These error report levels are the different types of error the user-defined error handler can be used for:

ValueConstantDescription
2E_WARNINGNon-fatal run-time errors. Execution of the script is not halted
8E_NOTICERun-time notices. The script found something that might be an error, but could also happen when running a script normally
256E_USER_ERRORFatal user-generated error. This is like an E_ERROR set by the programmer using the PHP function trigger_error()
512E_USER_WARNINGNon-fatal user-generated warning. This is like an E_WARNING set by the programmer using the PHP function trigger_error()
1024E_USER_NOTICEUser-generated notice. This is like an E_NOTICE set by the programmer using the PHP function trigger_error()
4096E_RECOVERABLE_ERRORCatchable fatal error. This is like an E_ERROR but can be caught by a user defined handle (see also set_error_handler())
8191E_ALLAll errors and warnings (E_STRICT became a part of E_ALL in PHP 5.4)

Now lets create a function to handle errors:

function customError($errno, $errstr)
{
echo “<b>Error:</b> [$errno] $errstr<br>”;
echo “Ending Script”;
die();
}

The code above is a simple error handling function. When it is triggered, it gets the error level and an error message. It then outputs the error level and message and terminates the script.

Now that we have created an error handling function we need to decide when it should be triggered.

PHP – Installation

Certify and Increase Opportunity.
Be
Govt. Certified PHP-Developer

PHP – Installation

Steps to Setting Up PHP 5

  1. Download PHP 5

    Before you begin, get a copy of PHP 5 from the PHP download page. In particular, download the VC6 thread-safe zip package from the “Windows Binaries” section — that is, don’t get the installer. For example, select the package labelled “PHP 5.2.5 zip package” if 5.2.5 is the current version.

    [Update: note that I have not tested the procedure below with any of the PHP 5.3 versions, only with 5.2.5, which was the latest version at the time I originally wrote this. In theory, the procedure should work with later 5.2 versions as well. I’m not sure about 5.3 though. A version jump from 5.2 to 5.3 usually means bigger changes than simple bug fixes. If you want to be sure the procedure below will work, just get the latest of the 5.2 series.]
  2. Install PHP 5

    Create a folder on your hard disk for PHP. I suggest “c:\php” although you can use other names if you wish. Personally though, I prefer to avoid names with spaces in it, like “c:\Program Files\php” to avoid potential problems with programs that cannot handle such things. I will assume that you used c:\php in this tutorial.

    Extract all the files from the zip package into that folder. To do that simply double-click the zip file to open it, and drag all the files and folders to c:\php.

  3. Upgraders: Remove the Old PHP.INI File from Your Windows Directory

    If you are upgrading to PHP 5 from an older version, go to your windows directory, typically c:\windows, and delete any php.ini file that you have previously placed there.

  4. Configuring PHP

    Go to the c:\php folder and make a copy of the file “php.ini-recommended”. Name the new file “php.ini”. That is, you should now have a file “c:\php\php.ini”, identical in content with “c:\php\php.ini-recommended”.

    Note: if you are using Apache 1, you should either move the php.ini file to your windows directory, “C:\Windows” on most systems, or configure your PATH environment variable to include “c:\php”. If you don’t know how to do the latter, just move the php.ini file to the “c:\windows” folder. You do not have to do this if you are using Apache 2, since we will include a directive later in the Apache 2 configuration file to specify the location of the php.ini file.

    Use an ASCII text editor (such as Notepad, which can be found in the Accessories folder of your Start menu) to open “php.ini”. You may need to make the following changes to the file, depending on your requirements:

    1. Enable Short Open Tags

      Search for the line that reads:

      short_open_tag = Off

      If short_open_tag is set to “off”, tags like “<?” will not be recognised as the start tag for a PHP script. In such a case, to begin a PHP script, you will need to code your script with an opening tag like “<?php”. Since many third party PHP scripts use “<?”, setting this to “Off” will give you more problems than it’s worth, particularly since most, if not all, commercial web hosts that support PHP have no issues with your scripts using “<?” as the open tag. To fix this, change it to the following:

      short_open_tag = On
    2. Magic Quotes

      By default, input data is not escaped with backslashes. That is, if your visitors enter an inverted comma (single quote) into your web form, the script will receive that unadorned inverted comma (single quote). This is for the most part desirable unless you have special requirements. If you want your input data to have the backslash (“\”) prefix, such as, for example, to mimic your web host’s settings, search for the following:

      magic_quotes_gpc = Off

      and replace it with:

      magic_quotes_gpc = On

      Do not do this unless your web host has this setting as well. Even with the setting of “Off”, you can still use the addslashes() function in PHP to add the slashes for the specific pieces of data that need them.

    3. Register Globals

      A number of older scripts assume that all data sent by a form will automatically have a PHP variable of the same name. For example, if your form has an input field with a name of “something”, older PHP scripts assume that the PHP processor will automatically create a variable called $something that contains the value set in that field.

      If you are running such scripts, you will need to look for the following field:

      register_globals = Off

      and change it to the following:

      register_globals = On

      WARNING: Do NOT do this unless you have third party scripts that need it. When writing new scripts, it’s best to always code with the assumption that the register_globals item is set to “Off”.

    4. Display Errors

      On a “live” website, you typically want errors in your script to be silently logged to a PHP error file. On your own local machine, however, while you are testing and debugging a PHP script, it is probably more convenient to have error messages sent to the browser window when they appear. This way, you won’t miss errors if you forget to check the error log file.

      If you want PHP to display error messages in your browser window, look for the following:

      display_errors = Off

      And change it to:

      display_errors = On

      This value should always be set to “Off” for a “live” website.

    5. Session Path

      If your script uses sessions, look for the following line:

      ;session.save_path = “/tmp”

      The session.save_pathsets the folder where PHP saves its session files. Since “/tmp” does not exist on Windows, you will need to set it to a directory that does. One way is to create a folder called (say) “c:\tmp” (the way you created c:\php earlier), and point this setting to that folder. If you do that, change the line to the following:

      session.save_path = “c:\tmp”

      Notice that in addition to changing the path, I also removed the semi-colon (“;”) prefix from the line.

      Alternatively, you can find out the current TEMP folder on your computer and use that. Or create a “tmp” folder in your PHP directory, like “c:\php\tmp” and set the configuration file accordingly. The possibilities are endless. If you can’t decide, just create “c:\tmp” and do as I said above.

    6. SMTP Server

      If your script uses the mail() function, and you want the function to successfully send mail on your local machine, look for the following section:

      [mail function] ; For Win32 only.
      SMTP = localhost
      smtp_port = 25; For Win32 only.
      ;sendmail_from = me@example.com

      Change it to point to your SMTP server and email account. For example, if your SMTP server is “mail.example.com” and your email address is “youremail@example.com”, change the code to:

      [mail function] SMTP = mail.example.com
      smtp_port = 25
      sendmail_from = youremail@example.com

      Note that after you do this, when your script tries to use the mail() function, you will need to be connected to your ISP for the function to succeed. If you do not modify the above lines and attempt to use mail() in your script, the function will return a fail code, and display (or log) the error (depending on how you configure php.ini to handle errors).

      (Note that in Apache 1.x, the smtp_port line may not be present. If so, don’t include it.)

How to Configure Apache for PHP 5

There are two ways to set up Apache to use PHP: the first is to configure it to load the PHP interpreter as an Apache module. The second is to configure it to run the interpreter as a CGI binary. I will supply information for how you can accomplish both, but you should only implement one of these methods. Choose the module method if your web host also installed PHP as an Apache module, and use the CGI method if they have implemented it to run as a CGI binary.

  1. Running PHP 5 as an Apache Module

    To configure Apache to load PHP as a module to parse your PHP scripts, use an ASCII text editor to open the Apache configuration file, “httpd.conf”. If you use Apache 1.x, the file is found in “c:\Program Files\Apache Group\Apache\conf\”. Apache 2.0.x users can find it in “C:\Program Files\Apache Group\Apache2\conf\” while Apache 2.2.x users can find it in “C:\Program Files\Apache Software Foundation\Apache2.2\conf\”. Basically, it’s in the “conf” folder of wherever you installed Apache.

    Search for the section of the file that has a series of “LoadModule” statements. Statements prefixed by the hash “#” sign are regarded as having been commented out.

    If you are using Apache 1.x, add the following line after all the LoadModule statements:

    LoadModule php5_module “c:/php/php5apache.dll”

    If you are using Apache 2.0.x, add the following line after all the LoadModule statements:

    LoadModule php5_module “c:/php/php5apache2.dll”

    If you are using Apache 2.2.x, add the following line instead:

    LoadModule php5_module “c:/php/php5apache2_2.dll”

    Note carefully the use of the forward slash character (“/”) instead of the traditional Windows backslash (“\”). This is not a typographical error.

    If you are using Apache 1.x, search for the series of “AddModule” statements, and add the following line after all of them. You do not have to do this in any of the Apache 2 series of web servers.

    AddModule mod_php5.c

    Next, search for “AddType” in the file, and add the following line after the last “AddType” statement. Do this no matter which version of Apache you are using. For Apache 2.2.x, you can find the “AddType” lines in the <IfModule mime_module> section. Add the line just before the closing </IfModule> for that section.

    AddType application/x-httpd-php .php

    If you need to support other file types, like “.phtml”, simply add them to the list, like this:

    AddType application/x-httpd-php .phtml

    Finally, for those using one of the Apache 2 versions, you will need to indicate the location of your PHP ini file. Add the following line to the end of your httpd.conf file.

    PHPIniDir “c:/php”

    Of course if you used a different directory for your PHP installation, you will need to change “c:/php” to that path. Remember to use the forward slash (“/”) here again.

    If you are using Apache 1, you will have already placed your php.ini file in either the Windows directory or somewhere in your PATH, so PHP should be able to find it by itself. You can of course do the same if you are using Apache 2, but I find modifying the Apache configuration file a better solution than cluttering your c:\windows directory or your PATH variable.

  2. Running PHP 5 as a CGI Binary

    If you have configured PHP 5 to run as an Apache module, skip forward to the next section. This section is for those who want to configure PHP to run as a CGI binary.

    The procedure is the same whether you are using the Apache 1.x series or one of the 2.x series.

    Search for the portion of your Apache configuration file which has the ScriptAlias section. Add the line from the box below immediately after the ScriptAlias line for “cgi-bin”. If you use Apache 2.2.x, make sure that the line goes before the closing </IfModule> for that <IfModule alias_module> section.

    Note that if you installed PHP elsewhere, such as “c:\Program Files\php\”, you should substitute the appropriate path in place of “c:/php/” (for example, “c:/Program Files/php/”). Observe carefully that I used forward slashes (“/”) instead of the usual Windows backslashes (“\”) below. You will need to do the same.

    ScriptAlias /php/ “c:/php/”

    Apache needs to be configured for the PHP MIME type. Search for the “AddType” comment block explaining its use, and add the AddType line in the box below after it. For Apache 2.2.x, you can find the AddType lines in the <IfModule mime_module> section. Add the following line just before the closing </IfModule> for that section.

    AddType application/x-httpd-php .php

    As in the case of running PHP as an Apache module, you can add whatever extensions you want Apache to recognise as PHP scripts, such as:

    AddType application/x-httpd-php .phtml

    Next, you will need to tell the server to execute the PHP executable each time it encounters a PHP script. Add the following somewhere in the file, such as after the comment block explaining “Action”. If you use Apache 2.2.x, you can simply add it immediately after your “AddType” statement above; there’s no “Action” comment block in Apache 2.2.x.

    Action application/x-httpd-php “/php/php-cgi.exe”

    Note: the “/php/” portion will be recognised as a ScriptAlias, a sort of macro which will be expanded to “c:/php/” (or “c:/Program Files/php/” if you installed PHP there) by Apache. In other words, don’t put “c:/php/php.exe” or “c:/Program Files/php/php.exe” in that directive, put “/php/php-cgi.exe”.

    If you are using Apache 2.2.x, look for the following section in the httpd.conf file:

    <Directory “C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin”>
    AllowOverride None
    Options None
    Order allow,deny
    Allow from all
    </Directory>

    Add the following lines immediately after the section you just found.

    <Directory “C:/php”>
    AllowOverride None
    Options None
    Order allow,deny
    Allow from all
    </Directory>
  3. Configuring the Default Index Page

    This section applies to all users, whether you are using PHP as a module or as a CGI binary.

    If you create a file index.php, and want Apache to load it as the directory index page for your website, you will have to add another line to the “httpd.conf” file. To do this, look for the line in the file that begins with “DirectoryIndex” and add “index.php” to the list of files on that line. For example, if the line used to be:

    DirectoryIndex index.html

    change it to:

    DirectoryIndex index.php index.html

    The next time you access your web server with just a directory name, like “localhost” or “localhost/directory/”, Apache will send whatever your index.php script outputs, or if index.php is not available, the contents of index.html.

Restart the Apache Web Server

Restart your Apache server. This is needed because Apache needs to read the new configuration directives for PHP that you have placed into the httpd.conf file. The Apache 2.2 server can be restarted by doubleclicking the Apache Service Monitor system tray icon, and when the window appears, clicking the “Restart” button.

PHP – Optimization

Certify and Increase Opportunity.
Be
Govt. Certified PHP-Developer
PHP – Optimization

Some optimization tips –

  • echo is faster than print.
  • Wrap your string in single quotes (‘) instead of double quotes (“) is faster because PHP searches for variables inside “…” and not in ‘…’, use this when you’re not using variables you need evaluating in your string.
  • Use sprintf instead of variables contained in double quotes, it’s about 10x faster.
  • Use echo‘s multiple parameters (or stacked) instead of string concatenation.
  • Use pre-calculations, set the maximum value for your for-loops before and not in the loop. ie: for ($x=0; $x < count($array); $x), this calls the count() function each time, use $max=count($array) instead before the for-loop starts.
  • Unset or null your variables to free memory, especially large arrays.
  • Avoid magic like __get, __set, __autoload.
  • Use require() instead of require_once() where possible.
  • Use full paths in includes and requires, less time spent on resolving the OS paths.
  • require() and include() are identical in every way except require halts if the file is missing. Performance wise there is very little difference.
  • Since PHP5, the time of when the script started executing can be found in $_SERVER[’REQUEST_TIME’], use this instead of time() or microtime().
  • PCRE regex is quicker than EREG, but always see if you can use quicker native functions such as strncasecmp, strpbrk and stripos instead.
  • When parsing with XML in PHP try xml2array, which makes use of the PHP XML functions, for HTML you can try PHP’s DOM document or DOM XML in PHP4.
  • str_replace is faster than preg_replace, str_replace is best overall, however strtr is sometimes quicker with larger strings. Using array() inside str_replace is usually quicker than multiple str_replace.
  • “else if” statements are faster than select statements aka case/switch.
  • Error suppression with @ is very slow.
  • To reduce bandwidth usage turn on mod_deflate in Apache v2  or for Apache v1 try mod_gzip.
  • Close your database connections when you’re done with them.
  • $row[’id’] is 7 times faster than $row[id], because if you don’t supply quotes it has to guess which index you meant, assuming you didn’t mean a constant.
  • Use <?php … ?> tags when declaring PHP as all other styles are depreciated, including short tags.
  • Use strict code, avoid suppressing errors, notices and warnings thus resulting in cleaner code and less overheads. Consider having error_reporting(E_ALL) always on.
  • PHP scripts are be served at 2-10 times slower by Apache httpd than a static page. Try to use static pages instead of server side scripts.
  • PHP scripts (unless cached) are compiled on the fly every time you call them. Install a PHP caching product (such as memcached or eAccelerator or Turck MMCache) to typically increase performance by 25-100% by removing compile times. You can even setup eAccelerator on cPanel using EasyApache3.
  • An alternative caching technique when you have pages that don’t change too frequently is to cache the HTML output of your PHP pages. Try Smarty or Cache Lite.
  • Use isset where possible in replace of strlen. (ie: if (strlen($foo) < 5) { echo “Foo is too short”; } vs. if (!isset($foo{5})) { echo “Foo is too short”; } ).
  • ++$i is faster than $ i++, so use pre-increment where possible.
  • Make use of the countless predefined functions of PHP, don’t attempt to build your own as the native ones will be far quicker; if you have very time and resource consuming functions, consider writing them as C extensions or modules.
  • Profile your code. A profiler shows you, which parts of your code consumes how many time. The Xdebug debugger already contains a profiler. Profiling shows you the bottlenecks in overview.
  • Document your code.
  • Learn the difference between good and bad code.
  • Stick to coding standards, it will make it easier for you to understand other people’s code and other people will be able to understand yours.
  • Separate code, content and presentation: keep your PHP code separate from your HTML.
  • Don’t bother using complex template systems such as Smarty, use the one that’s included in PHP already, see ob_get_contents and extract, and simply pull the data from your database.
  • Never trust variables coming from user land (such as from $_POST) use mysql_real_escape_string when using mysql, and htmlspecialchars when outputting as HTML.
  • For security reasons never have anything that could expose information about paths, extensions and configuration, such as display_errors or phpinfo() in your webroot.
  • Turn off register_globals (it’s disabled by default for a reason!). No script at production level should need this enabled as it is a security risk. Fix any scripts that require it on, and fix any scripts that require it off using unregister_globals(). Do this now, as it’s set to be removed in PHP6.
  • Avoid using plain text when storing and evaluating passwords to avoid exposure, instead use a hash, such as an md5 hash.
  • Use ip2long() and long2ip() to store IP addresses as integers instead of strings.
  • You can avoid reinventing the wheel by using the PEAR project, giving you existing code of a high standard.
  • When using header(‘Location: ‘.$url); remember to follow it with a die(); as the script continues to run even though the location has changed or avoid using it all together where possible.
  • In OOP, if a method can be a static method, declare it static. Speed improvement is by a factor of 4. .
  • Incrementing a local variable in an OOP method is the fastest. Nearly the same as calling a local variable in a function and incrementing a global variable is 2 times slow than a local variable.
  • Incrementing an object property (eg. $this->prop++) is 3 times slower than a local variable.
  • Incrementing an undefined local variable is 9-10 times slower than a pre-initialized one.
  • Just declaring a global variable without using it in a function slows things down (by about the same amount as incrementing a local var). PHP probably does a check to see if the global exists.
  • Method invocation appears to be independent of the number of methods defined in the class because I added 10 more methods to the test class (before and after the test method) with no change in performance.
  • Methods in derived classes run faster than ones defined in the base class.
  • A function call with one parameter and an empty function body takes about the same time as doing 7-8 $localvar++ operations. A similar method call is of course about 15 $localvar++ operations.
  • Not everything has to be OOP, often it is just overhead, each method and object call consumes a lot of memory.
  • Never trust user data, escape your strings that you use in SQL queries using mysql_real_escape_string, instead of mysql_escape_string or addslashes. Also note that if magic_quotes_gpc is enabled you should use stripslashes first.
  • Avoid the PHP mail() function header injection issue.
  • Unset your database variables (the password at a minimum), you shouldn’t need it after you make the database connection.

Security

Certify and Increase Opportunity.
Be
Govt. Certified PHP-Developer
PHP Security

To identify or avoid security holes in applications written using PHP, follow these measures –

Avoid Using Variables When Accessing Files

The user could set the or variables and include files such as or remote files such as with malicious code. This malicious code could potentially delete files, corrupt databases, or change the values of variables used to track authentication status.

What to Look For

Search code for the following functions:

  • readfile
  • fopen
  • file
  • include
  • require

Possible Fixes or Improvements

  • Avoid using variables as file names. The $lib_dirvariable above could be replaced with a value defined by the PHPdefinefunction.
  • Check the file name against a list of valid file names. For example,
    $valid_pages = array(
    	"apage.php"   => "",
    	"another.php" => "",
    	"more.php"    => "");
    
    if (!isset($valid_pages[$page])) {
    	// Abort the script
    	// You should probably write a log message here too
    	die("Invalid request");
    }
  • If you must really use a variable from the browser, check the variable’s value using code like the following:
    if (!(eregi("^[a-z_./]*$", $page) && !eregi("\\.\\.", $page))) {
    	// Abort the script
    	// You should probably write a log message here too
    	die("Invalid request");
    }
  • See Do Not Trust Global Variables for further steps on ensuring variables cannot be maliciously set.
  • Use the allow_url_fopenand open_basedirconfiguration variables to limit the locations where files can be opened from.

Escape characters in SQL statements

A common mistake is to use a variable value supplied by the user or the URL in an SQL query without escaping special characters. Consider the following fragment of code from a script designed to authenticate a username and password entered in a HTML form:

$query = "SELECT * FROM users WHERE username='" . $username . "' 
          AND password='" . $password . "'";

// the record exists function is defined elsewhere
if (record_exists($query)) {
	echo "Access granted";
} else {
	echo "Access denied";
}

his code would work when accessed using check.php?username=admin&password=x. However, if the code were accessed usingcheck.php?username=admin&password=a%27+OR+1%3Di%271(and if magic_quotes_gpcwere disabled) then the password condition becomes Password='a' or 1='1'so that the admin user record would always be returned regardless of the password it contained.

This problem is partly avoided when the magic_quotes_gpcvariable is on in the php.inifile, meaning that PHP will escape quotes in GET, POST, and cookie data using the \character. However, magic_quotes_gpcis frequently disabled because it could make other code behave strangely. Given a line containing echo $usernamein the above code fragment, any occurrences of 'would be replaced by \'). Furthermore the magic_quotes_gpcvariable does not protect against variable values obtained from sources such as database records or files which a malicious user may have already modified during normal program operation.

What to Look For

Search for the query functions for your database. For example, if you are using MySQL, search for usage of themysql_db_queryfunction.

Possible Fixes or Improvements

  • Use the built-in addslashesfunction or a similar function to escape quotes and backslashes in SQL statements with backslashes.
  • Enabling magic_quotes_gpcmay help, but don’t rely upon it. (Enabling this setting and using addslasheswill produce errors).
  • If you are using variables which you expect to contain numbers in your SQL statement, ensure that they really do contain numbers. You can use various built-in PHP functions including sprintferegand is_long, to perform this check.

Do Not Trust Global Variables

If the register_globalsoption is enabled, PHP will create global variables for each GET, POST, and cookie variable included in the HTTP request. This means that a malicious user may be able to set variables unexpectedly. Consider the following code aimed to allow anonymous access to a single article and require authentication for all other articles:

// Assume $article_id is set by the URL
if ($article_id == 0) {
	$guest_ok = true;
}

if (!$guest_ok) {
	// Check user is authenticated using a function defined elsewhere
	check_auth();
}

This code may appear to work, because the $guest_okvariable will generally be initialized to false. However, if a malicious user includes guest_ok=1in the URL, he will be granted access to any article in the system.

A similar problem can arise when you perform security checks when showing links to pages but do not perform security checks on the linked pages themselves. In a system where users are granted access to a select list of articles, you should perform security checks when producing the list of available articles and when displaying an article selected from the list. Without this checking, a malicious user could type URLs for articles to which he should not have access and view the article successfully. Another common variation of this problem is to implement a “Remember My Login” feature by storing a user identifier in a cookie, allowing users to change their cookie value to login as whomever they want.

What to Look For

This problem can appear almost anywhere in your code. Pay careful attention to the following areas:

  • Authentication and permission checking code
  • Use of variables before they are initialized. (You can set the error_reportingconfiguration variable to give a warning whenever uninitialized variables are used.)
  • Use of variables designed to be set by GET or POST requests.

Possible Fixes or Improvements

  • Disable register_globalsin your php.inifile. After making this change, you will need to use the $HTTP_GET_VARSand$HTTP_POST_VARSassociative arrays to access GET and POST inputs instead of using global variables. This can be tedious, but also far more secure.
  • If a “Remember My Login” function is required, include a password or a hard to guess random identifier in the cookie. (A “Remember My Login” function can still produce other holes such as malicious user who shares a machine with a legitimate user to gain access.)
  • Write code to initialize all global variables. The previous code fragment could be improved by initializing $guest_okto false at the start of the script.
  • Ensure session variables really do come from the session and not from a malicious user.
  • Write code to check that a global variable is not in the $HTTP_POSTor $HTTP_GETassociative arrays.

Avoid False Uploads

File uploads can suffer from a severe case of the untrusted global variables problem that is worth considering as an additional problem. When a file is uploaded, a PHP script is given a variable that provides the name of the temporary file where PHP saves the uploaded file. However, the user could construct a URL that sets this variable to a malicious value such as /etc/passwdand not upload a file. The responding script may then copy that file to an accessible location or display the file’s contents to the user.

What to Look For

Examine all scripts that respond to file uploads. Searching for type="file"may help identify these scripts.

Possible Fixes or Improvements

  • Recent versions of PHP have the is_uploaded_fileand move_uploaded_filefunctions that allows the programmer to ensure that they are working with uploaded files.
  • If you are not sure that your code will be running on a recent version of PHP, set the upload_tmp_dirconfiguration setting and then perform input checking to ensure that the file you are working with is in this directory.

Escape HTML Characters in Text

What happens if somebody puts a <blink>tag in a posting to a discussion board? If you don’t escape HTML characters in text either before you save or display it, all subsequent text on the page could be blinking. More severe versions of this attack are also possible; for example an attacker could write JavaScript that takes the browser to a competitor’s site.

What to Look For

Identify pages which display text entered by untrusted users.

Possible Fixes or Improvements

  • Escape HTML appropriately either before you save it or before you display it. You can use PHP’s built-in functionshtmlspecialcharsor htmlentitiesfor this purpose.
  • If you want untrusted users to use HTML for formatting, you should perform validation to restrict the available HTML tags to a basic tags set, like <b>and <i>.

Image Submission

Certify and Increase Opportunity.
Be
Govt. Certified PHP-Developer
PHP – Image Submission

When submitting a form, it is possible to use an image instead of the standard submit button with a tag like:

<input type=”image” src=”image.gif” name=”sub” />

When the user clicks somewhere on the image, the accompanying form will be transmitted to the server with two additional variables, sub_x and sub_y. These contain the coordinates of the user click within the image. The experienced may note that the actual variable names sent by the browser contains a period rather than an underscore, but PHP converts the period to an underscore automatically.

PHP – Variables From External Sources

Certify and Increase Opportunity.
Be
Govt. Certified PHP-Developer
PHP – Variables From External Sources

HTML Forms (GET and POST)

When a form is submitted to a PHP script, the information from that form is automatically made available to the script. There are many ways to access this information, for example:

Example #1 A simple HTML form

<form action=”foo.php” method=”post”>
Name:  <input type=”text” name=”username” /><br />
Email: <input type=”text” name=”email” /><br />
<input type=”submit” name=”submit” value=”Submit me!” />
</form>

Depending on your particular setup and personal preferences, there are many ways to access data from your HTML forms. Some examples are:

Example #2 Accessing data from a simple POST HTML form
<?php
// Available since PHP 4.1.0

echo $_POST[‘username’];
echo $_REQUEST[‘username’];

import_request_variables(‘p’, ‘p_’);
echo $p_username;

// As of PHP 5.0.0, these long predefined variables can be
// disabled with the register_long_arrays directive.

echo $HTTP_POST_VARS[‘username’];

// Available if the PHP directive register_globals = on. As of
// PHP 4.2.0 the default value of register_globals = off.
// Using/relying on this method is not preferred.

echo $username;
?>

Using a GET form is similar except you’ll use the appropriate GET predefined variable instead. GET also applies to the QUERY_STRING (the information after the ‘?’ in a URL). So, for example, http://www.example.com/test.php?id=3  contains GET data which is accessible with $_GET[‘id’]. See also $_REQUEST and import_request_variables().

Receiving Form Data

Certify and Increase Opportunity.
Be
Govt. Certified PHP-Developer

PHP – Receiving Form Data

Form submission method

The

method

 

attribute of the

FORM

element specifies the HTTP method used to send the form to the processing agent. This attribute may take two values:

 

  • get: With the HTTP “get” method, the form data set is appended to the URI specified by the action attribute (with a question-mark (“?”) as separator) and this new URI is sent to the processing agent.
  • post: With the HTTP “post” method, the form data set is included in the body of the form and sent to the processing agent.

The “get” method should be used when the form is idempotent (i.e., causes no side-effects). Many database searches have no visible side-effects and make ideal applications for the “get” method.

If the service associated with the processing of a form causes side effects (for example, if the form modifies a database or subscription to a service), the “post” method should be used.

In HTML, one can specify two different submission methods for a form. The method is specified inside a FORMelement, using theMETHODattribute. The difference between

METHOD="GET"(the default) and METHOD="POST"is primarily defined in terms of form data encoding. The official recommendations say that "GET"should be used if and only if the form processing is idempotent, which typically means a pure query form. Generally it is advisable to do so. There are, however, problems related to long URLs and non-ASCII character repertoires which can make it necessary to use "POST"even for idempotent processing.

In HTML, one can specify two different submission methods for a form. The method is specified inside a FORMelement, using theMETHODattribute. The difference between METHOD="GET"(the default) and METHOD="POST"is primarily defined in terms of form data encoding. The official recommendations say that "GET"should be used if and only if the form processing is idempotent, which typically means a pure query form. Generally it is advisable to do so. There are, however, problems related to long URLs and non-ASCII character repertoires which can make it necessary to use "POST"even for idempotent processing.

Content:

The fundamental differences between "GET"and "POST"

The HTML specifications technically define the difference between "GET"and "POST"so that former means that form data is to be encoded (by a browser) into a URL while the latter means that the form data is to appear within a message body. But the specifications also give the usage recommendation that the "GET"method should be used when the form processing is “idempotent”, and in those cases only. As a simplification, we might say that "GET"is basically for just getting (retrieving) datawhereas "POST"may involve anything, like storing or updating data, or ordering a product, or sending E-mail.

The HTML 2.0 specification says, in section Form Submission (and the HTML 4.0 specification repeats this with minor stylistic changes):

If the processing of a form is idempotent (i.e. it has no lasting observable effect on the state of the world), then the form method should be GET. Many database searches have no visible side-effects and make ideal applications of query forms.

– –

If the service associated with the processing of a form has side effects (for example, modification of a database or subscription to a service), the method should be POST.

In the HTTP specifications (specifically RFC 2616) the word idempotent is defined as follows:

Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

The word idempotent, as used in this context in the specifications, is (pseudo)mathematical jargon (see definition of “idempotent” in FOLDOC) and should not be taken too seriously or literally here. The phrase “no lasting observable effect on the state of the world” isn’t of course very exact either, and isn’t really the same thing. Idempotent processing, as defined above, does not exclude fundamental changes, only that processing the same data twice has the same effect as processing it once. But here, in fact, idempotent processing means that a form submission causes no changes anywhere except on the user’s screen (or, more generally speaking, in the user agent’s state). Thus, it is basically for retrieving data. If such a form is resubmitted, it might get different data (if the data had been changed meanwhile), but the submission would not cause any update of data or other events. The concept of changes should not be taken too pedantically; for instance, it can hardly be regarded as a change that a form submission is logged into the server’s log file. On the other hand, sending E-mail should normally be regarded as “an effect on the state of the world”.

The HTTP specifications aren’t crystal clear on this, and section Safe Methods in the HTTP/1.1 specification describes the principles in yet another way. It opens a different perspective by says that users “cannot be held accountable” for side effects, which presumably means any effect than mere retrieval:

In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered “safe”. This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested.

Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them.

The concept and its background is explained in section Allowing input in Tim Berners-Lee‘s Style Guide for online hypertext. It refers, for more information, to User agent watch points, which emphatically says that GETshould be used if and only if there are no side effects. But this line of thought, however logical, is not always practical at present, as we shall see.

See also answer to question “What is the difference between GET and POST?” in CGI Programming FAQ by Nick Kew.

Why the distinction matters

In the same context where the pragmatic difference is stated, the HTML 2.0 specification describes the corresponding submission methods technically. However, it does not explain why those methods are recommended for idempotent vs. non-idempotent submissions. Neither does it explain what practical difference there might be between the methods.

Alan Flavell has explained, in an article in a thread titled Limit on URL length in the newsgroupcomp.infosystems.www.authoring.html, that “the distinction [between GETand POST] is a real one, and has been observed by some browser makers, which can result in undesirable consequences if the inappropriate one is used”. He gives the following reason for conforming to the advice:

When users revisit a page that resulted from a form submission, they might be presented with the page from their history stack (which they had probably intended), or they might be told that the page has now expired. Typical user response to the latter is to hit

Reload.

This is harmless if the request is idempotent, which the form author signals to the browser by specifying theGETmethod.

Browsers typically will (indeed “should”) caution their users if they are about to resubmit a POSTrequest, in the belief that this is going to cause a further “permanent change in the state of the universe”, e.g. ordering another Mercedes-Benz against their credit card or whatever. If users get so accustomed to this happening when they try to reload a harmless idempotent request, then sooner or later it’s going to bite them when they casually

[OK]the request and do, indeed, order a second pizza, or invalidate their previous competition entry by apparently trying to enter twice, or whatever.

Thus, some browsers can act more cleverly if the author uses "GET"or "POST"consistently, i.e. using "GET"for pure queries and"POST"for other form submissions. It needs to be noted, though, that using "GET"gives no protection against causing changes. A script which processes a form submission sent with the "GET"could cause a pizza ordering. It’s just that authors are expected to take care that such things don’t happen.

Moreover, the use of "POST"cannot guarantee that the user does not inadvertantly submit the same form data twice; the browser might not give a warning, or the user might fail to understand the warning. Users are known to become impatient when it seems that “nothing happens” when they click on a button, so they might click on it again and again. Thus, robust processing of forms should take precautions against unintended duplicate actions. (As a simple example, a submission might be processed first by a script which sends back a page containing a confirmation request, echoing back the data submitted and asking the user to verify it and then submit the confirmation.)

"GET"request is often cacheable, whereas a "POST"request can hardly be. For query systems this may have a considerable efficiency impact, especially if the query strings are simple, since caches might serve the most frequent queries. For information about caches, see Caching Tutorial for Web Authors and Webmasters, especially section Writing Cache-Aware Scripts.

Differences in form submission

For both METHOD="GET"and METHOD="POST", the processing of a user’s submit request (such as clicking on a submit button) in a browser begins with a construction of the form data set, which is then encoded in a manner which depends on the ENCTYPEattribute. That attribute has two possible values mentioned in the specifications, but multipart/form-datais for "POST"submissions only, whereas application/x-www-form-urlencoded(the default) can be used both for "POST"and for "GET".

Then the form data set is transmitted as follows (quotation from the HTML 4.0 specification):

  • If the method is "get"– -, the user agent takes the value of action, appends a ?to it, then appends the form data set, encoded using the application/x-www-form-urlencodedcontent type. The user agent then traverses the link to this URI. In this scenario, form data are restricted to ASCII codes.
  • If the method is "post"–, the user agent conducts an HTTP posttransaction using the value of the action attribute and a message created according to the content type specified by the enctype attribute.

Thus, for METHOD="GET"the form data is encoded into a URL (or, speaking more generally, into a URI). This means that an equivalent to a form submission can be achieved by following a normal link referring to a suitable URL; see the document Choices in HTML forms for details and examples. On a typical browser, the user sees the URL of a document somewhere (e.g. on

Locationline), and if he is viewing the results of a query sent using METHOD="GET", he will see what the actual query was (i.e. the part of the URL that follows the ?sign). The user could then bookmark it or cut&paste it for later use (e.g. to be E-mailed or put into one’s own HTML document after some editing).

Although the HTML specifications don’t say it very explicitly, the fundamental difference between the methods is really that they correspond to different HTTP requests, as defined in the HTTP specifications. See especially Method Definitions in RFC 2616. For form submission with METHOD="GET", the browser constructs a URL as described above, then processes it as if following a link (or as if the user had typed the URL directly). The browser divides the URL into parts and recognizes a host, then sends to that host a GETrequest with the rest of the URL as argument. The server takes it from there. Submission of a form withMETHOD="POST"causes a POSTrequest to be sent.

Differences in server-side processing

In principle, processing of a submitted form data depends on whether it is sent with METHOD="GET"or METHOD="POST". Since the data is encoded in different ways, different decoding mechanisms are needed. Thus, generally speaking, changing the METHODmay necessitate a change in the script which processes the submission. For example, when using the CGI interface, the script receives the data in an environment variable when METHOD="GET"is used but in the standard input stream (stdin) when METHOD="POST"is used.

It is, however, possible to construct libraries of subroutines (e.g. Perl functions) which allow one to write scripts in a manner which works both for METHOD="GET"and METHOD="POST". This would be based on distinguishing between the cases within the subroutine code and returning the data to the caller in a uniform manner.

Possible reasons to use "POST"for idempotent queries

For reasons explained above, one should normally use METHOD="POST"if and only if the form submission may cause changes. There are some exceptional situations where one may consider using METHOD="POST"even for pure queries, too:

  • If the form data would contain non-ASCII characters, then METHOD="GET"is inapplicable in principle, although it may work in practice (mainly for ISO Latin 1 characters). Thus, for a query where the keywords might contain e.g. accented letters, you have to select among two evils: using METHOD="GET"against the rules which restrict the character reportoire to ASCII within it, or using METHOD="POST"against the rules which says that it should not be used when the processing is idempotent. The latter alternative is probably less dangerous.
  • If the form data set is large – say, hundreds of characters – then METHOD="GET"may cause practical problems with implementations which cannot handle that long URLs. Such usage is mentioned in the the HTML 2.0 specification in an informative note as follows:
    Note – The URL encoding may result in very long URIs, which cause some historical HTTP server implementations to exhibit defective behavior. As a result, some HTML forms are written using METHOD=POSTeven though the form submission has no side-effects.
    The limitations are not only historical. There is an official statement by Microsoft, originally published 2000-02-23: INFO: Maximum URL Length Is 2,083 Characters in Internet Explorer (Q208427).
  • You might wish to avoid METHOD="GET"in order to make it less visible to users how the form works, especially in order to make “hidden” fields (INPUT TYPE="HIDDEN") more hidden. Using POSTimplies that users won’t see the form data in the URL shown by the user; but note that this is not a very effective method of hiding, since the user can of course view the source code of yourFORMelement!

 

 

POST data is submitted by a form and “posted” to the web server as form data. POST data is encoded the same way as GET data, but isn’t typically visible to the user in standard browsers.

Most forms use the post method because it “hides” the form data away from the user and doesn’t clutter up the URL in the address bar.

Note that GET and POST methods are equally (in)secure.

As easily as a user can monkey with GET data in a URL, the same thing can be done with POST data. You should always assume that the user can submit whatever form and form data that they want to, and process the data accordingly. Don’t trust user input, whether it’s from GET or from POST!

Post data is accessed with the $_POST array in PHP.

<?php
  echo("First name: " $_POST['firstname'] . "<br />\n");
  echo("Last name: " $_POST['lastname'] . "<br />\n");
?>
<form action="myform5.php" method="post">
  <p>First name: <input type="text" name="firstname" /></p>
  <p>Last name: <input type="text" name="firstname" /></p>
  <input type="submit" name="submit" value="Submit" />
</form>

Using “isset”

You can use the “isset” function on any variable to determine if it has been set or not. You can use this function on the $_POST array to determine if the variable was posted or not. This is often applied to the submit button value, but can be applied to any variable.

For example:

<?php
  if(isset($_POST['submit'])
  {
  echo("First name: " $_POST['firstname'] . "<br />\n");
  echo("Last name: " $_POST['lastname'] . "<br />\n");
  }
?>
<form action="myform5.php" method="post">
  <p>First name: <input type="text" name="firstname" /></p>
  <p>Last name: <input type="text" name="firstname" /></p>
  <input type="submit" name="submit" value="Submit" />
</form>

The above code will only display the submitted values if the submit button was clicked.

Can I use both GET and POST in the same page?

GET and POST occupy different spaces in the server’s memory, so both can be accessed on the same page if you want. One use might be to display different messages on a form depending on what’s in the query string.

http://mysite/myform5.php?lang=english

<?php
  if(isset($_POST['submit']) {
  if($_GET['lang'] == "english") {
  echo("First name: " $_POST['firstname'] . "<br />\n");
  echo("Last name: " $_POST['lastname'] . "<br />\n");
  else if($_GET['lang'] == "spanish") {
  echo("Nombre: " $_POST['firstname'] . "<br />\n");
  echo("Apellido: " $_POST['lastname'] . "<br />\n");
  }
?>
<form method="post">
  <p>First name: <input type="text" name="firstname" /></p>
  <p>Last name: <input type="text" name="firstname" /></p>
  <input type="submit" name="submit" value="Submit" />
</form>

Instead of using GET and POST arrays, you can also use the $_REQUESTarray, which will contain the combined contents of the data. If GET and POST variables have the same name, POST will take priority. It’s recommended not to do this unless you really have to, because it can be confusing, and it’s best to be clear about where an input is coming from.

One more thing to notice: the “action” on the form is now missing. Technically, this is not valid HTML. However, by not putting in an action, browsers will assume that the form is submitting to itself. This is important because it will also preserve the querystring when the form is submitted (the ?lang=english part). You can use server variables like $_SERVER['PHP_SELF']and$_SERVER['QUERY_STRING']to build an action value.

Create Basic Form

Certify and Increase Opportunity.
Be
Govt. Certified PHP-Developer

Create Basic Form

HTML forms are used to pass data to a server.
An HTML form can contain input elements like text fields, checkboxes, radio-buttons, submit buttons and more. A form can also contain select lists, textarea, fieldset, legend, and label elements.

The <form> tag is used to create an HTML form:
<form>
.
input elements
.
</form>

The Input Element
The most important form element is the <input> element.

The <input> element is used to select user information.

An <input> element can vary in many ways, depending on the type attribute. An <input> element can be of type text field, checkbox, password, radio button, submit button, and more.

 

Here is an example HTML form:

Example #1 A simple HTML form
<form action=”action.php” method=”post”>
<p>Your name: <input type=”text” name=”name” /></p>
<p>Your age: <input type=”text” name=”age” /></p>
<p><input type=”submit” /></p>
</form>

There is nothing special about this form. It is a straight HTML form with no special tags of any kind.

Forms Basics

Certify and Increase Opportunity.
Be
Govt. Certified PHP-Developer

Forms Basics

One of the most powerful features of PHP is the way it handles HTML forms. The basic concept that is important to understand is that any form element will automatically be available to your PHP scripts.

Here is an example HTML form:

Example #1 A simple HTML form
<form action=”action.php” method=”post”>
<p>Your name: <input type=”text” name=”name” /></p>
<p>Your age: <input type=”text” name=”age” /></p>
<p><input type=”submit” /></p>
</form>

There is nothing special about this form. It is a straight HTML form with no special tags of any kind. When the user fills in this form and hits the submit button, the action.php page is called. In this file you would write something like this:

Example #2 Printing data from our form
Hi <?php echo htmlspecialchars($_POST[‘name’]); ?>.
You are <?php echo (int)$_POST[‘age’]; ?> years old.

A sample output of this script may be:

Hi Joe. You are 22 years old.

Apart from the htmlspecialchars() and (int) parts, it should be obvious what this does. htmlspecialchars() makes sure any characters that are special in html are properly encoded so people can’t inject HTML tags or Javascript into your page. For the age field, since we know it is a number, we can just convert it to an integer which will automatically get rid of any stray characters. You can also have PHP do this for you automatically by using the filter extension. The $_POST[‘name’] and $_POST[‘age’] variables are automatically set for you by PHP. Earlier we used the $_SERVER superglobal; above we just introduced the $_POST superglobal which contains all POST data. Notice how the method of our form is POST. If we used the method GET then our form information would live in the $_GET superglobal instead. You may also use the $_REQUEST superglobal, if you do not care about the source of your request data. It contains the merged information of GET, POST and COOKIE data. Also see the import_request_variables() function.