Archive for April 2009

Plugin Compatibility

For various reasons, there are some people out that who have chosen to hang onto older versions of WordPress. Personally I do not recommend this behavior, but as a plugin developer, you might not want to exclude these people from using your plugin. Does this mean you should refrain from using features that were implemented in later versions for the benefit of those who have not upgraded? Absolutely not. One thing you can do, however, is to emulate or implement the newer features your plugin relies on for older versions.

This is actually very simple to do considering you can simply take the code directly from the latest version of WordPress. In order to do this properly, you should make use of PHP’s function_exists function. For example: the function admin_url was not part of WordPress until version 2.6. Normally, if you were to use this function, users with older version of WordPress would not be able to use it. You can, however, define it yourself:

if(!function_exists('admin_url'))
{
	function admin_url($path = '') {
	$url = site_url('wp-admin/', 'admin');

	if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
		$url .= ltrim($path, '/');

	return $url;
	}
}

Notice that the function declaration is inside the if(!function_exists(‘admin_url’)) block. If you simply defined the function as you normally would users with WordPress 2.6+ would receive an error.

Another thing to notice is that the code for admin_url contains a call to a function site_url. This function also was not defined until WordPress 2.6 so you’ll have to do the same thing for this function. For some functions it will be the case that you will have to do this for many functions, and in some cases you won’t be able to do this at all due to more significant differences between older and newer versions.

Here is a file I’m using called compat.php that defines several functions and constants that do not exist in earlier versions of WordPress.

//These functions replicate Wordpress functionality
//Used in cases where a Wordpress function is not
//available (ie a version that does not have that function)
if(!function_exists('is_ssl'))
{
	function is_ssl() {
		return ( isset($_SERVER['HTTPS']) && 'on' == strtolower($_SERVER['HTTPS']) ) ? true : false;
	}
}

if(!function_exists('force_ssl_admin'))
{
	function force_ssl_admin($force = '') {
		static $forced;

		if ( '' != $force ) {
			$old_forced = $forced;
			$forced = $force;
			return $old_forced;
		}

		return $forced;
	}
}

if(!function_exists('force_ssl_login'))
{
	function force_ssl_login($force = '') {
		static $forced;

		if ( '' != $force ) {
			$old_forced = $forced;
			$forced = $force;
			return $old_forced;
		}

		return $forced;
	}
}

if(!function_exists('site_url'))
{
	function site_url($path = '', $scheme = null) {
	// should the list of allowed schemes be maintained elsewhere?
	$orig_scheme = $scheme;
	if ( !in_array($scheme, array('http', 'https')) ) {
		if ( ('login_post' == $scheme) && ( force_ssl_login() || force_ssl_admin() ) )
			$scheme = 'https';
		elseif ( ('login' == $scheme) && ( force_ssl_admin() ) )
			$scheme = 'https';
		elseif ( ('admin' == $scheme) && force_ssl_admin() )
			$scheme = 'https';
		else
			$scheme = ( is_ssl() ? 'https' : 'http' );
	}

	$url = str_replace( 'http://', "{$scheme}://", get_option('siteurl') );

	if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
		$url .= '/' . ltrim($path, '/');

	return apply_filters('site_url', $url, $path, $orig_scheme);
	}
}

if(!function_exists('admin_url'))
{
	function admin_url($path = '') {
	$url = site_url('wp-admin/', 'admin');

	if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
		$url .= ltrim($path, '/');

	return $url;
	}
}

if ( !defined('WP_CONTENT_URL') )
	define( 'WP_CONTENT_URL', get_option('siteurl') . '/wp-content'); // full url - WP_CONTENT_DIR is defined further up

if ( !defined('WP_PLUGIN_URL') )
	define( 'WP_PLUGIN_URL', WP_CONTENT_URL . '/plugins' );

if(!function_exists('plugins_url'))
{
	function plugins_url($path = '')
	{
	$scheme = ( is_ssl() ? 'https' : 'http' );
	$url = WP_PLUGIN_URL;
	if ( 0 === strpos($url, 'http') ) {
		if ( is_ssl() )
			$url = str_replace( 'http://', "{$scheme}://", $url );
	}

	if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
		$url .= '/' . ltrim($path, '/');

	return $url;
	}
}

WordPress Plugins: Using Subversion

This article is meant to supplement WordPress’ Using Subversion Guide. Whenever I mention the guide I am referring to this.

So you’ve written a WordPress plugin and its now time to upload it to the WordPress plugin repository. Your first step will be requesting that your plugin be hosted on WordPress’ Plugin Directory. Sometime later your request will be accepted (provided it doesn’t drop all of the tables in the database or something like that) and you’ll be given access to the Subversion Repository.

If this is your first time making a WordPress plugin you might have no clue what subversion is, much less how to use it. WordPress provides some good Documentation on this subject, but I think there are a few things they left out that could be useful to someone using doing this for the first time.

Reading through WordPress’ Using Subversion guide will probably give you a pretty good idea of what subversion is, but by the time they get to actually using subversion you might be a little lost. I’ll pick up at the point I think it begins to get a little fuzzy:

Task 1: Starting from scratch with your brand new plugin repository

This section begins with a short overview of what you will be doing:

  1. Check out the blank repository.
  2. Add your files to the trunk/ directory of your local copy of the repository.
  3. Check in those files back to the central repository.

Then they toss a blob of text at you.

# Create a local directory on your machine to house
# a copy of the repository.

$ mkdir my-local-dir

# Check out the repository

$ svn co http://svn.wp-plugins.org/your-plugin-name my-local-dir
> A	my-local-dir/trunk
> A	my-local-dir/branches
> A	my-local-dir/tags
> Checked out revision 11325.

# As you can see, subversion has added ( "A" for "add" )
# all of the directories from the central repository to
# your local copy.

# Copy the plugin files to the local copy.
# Put everything in the trunk/ directory for now.

$ cd my-local-dir/
my-local-dir/$ cp ~/my-plugin.php trunk/my-plugin.php
my-local-dir/$ cp ~/readme.txt trunk/readme.txt

# Let subversion know you want to add those new files
# back into the central repository.

my-local-dir/$ svn add trunk/*
> A	trunk/my-plugin.php
> A	trunk/readme.txt

# Now check in the changes back to the central repository.
# Give a message to the check in.

my-local-dir/$ svn ci -m 'Adding first version of my plugin'
> Adding	trunk/my-plugin.php
> Adding	trunk/readme.txt
> Transmitting file data .
> Committed revision 11326.

# All done!

There are a few things you should know about the commands above. To begin, these commands should be entered on a unix shell. If you are familiar with unix you already know that text following the # symbol are comments and the text following the > symbol are the shell’s response to the commands. The commands themselves are not preceded by any symbol.

Another thing you should know is that the writers assume that you already have subversion (svn) installed. If you don’t like the idea of using a command line to access and modify the repository, there are a lot of GUI programs out there. You can find a listing of third party clients on the Subversion Website From this point on, however, I (and the writers of the guide I am referring to) will assume you have access to a unix command line with subversion installed.

If you are a windows user and don’t have access to a unix shell, I suggest using cygwin. SVN is part of the cygwin package, but you must explicitly specify that it be downloaded and installed. Read the cygwin documentation for more information. To test whether or not SVN is installed, type svn help in the shell.

Now that you have access to UNIX with SVN installed you should have no trouble running the commands in the guide.

Task 2: Editing a file that is already in the repository

Once you’ve uploaded your initial version, you will almost certainly need to make changes to those files sometime in the future. The guide is pretty clear on how to do this, so I will just provide a brief summary of the commands you will use for this.

svn stat shows you a list of files that differ from those in the repository.

svn ci -m "my message" updates the files in the repository with your local copies. It does not automatically add new files or remove old files. If you have added a new file that did not exist before you will have to use the svn add command to manually add this file. Likewise you will have to remove a file manually with the svn remove command. Documentation on any command can be obtained by using the svn help [command] command, where [command] is replaced by whatever command (ie add, remove, stat) you need documentation on.

Notice that the first command issued before updating any files is cd my-local-dir. It is very important that you are in you plugin directory when using any of these commands.

Task 3: “Tagging” a new version

Tagging refers to assigning a version to your plugin. Whenever you create a new version of your plugin you will need to tag that version. As the guide mentions, you do this by using the svn cp. It is important that you use the svn cp and not the normal cp command to do this. svn cp just doesn’t copy the files, it also adds the files as you would using the add command.

It is important to note that the command svn cp trunk tags/0.1 assumes that the folder 0.1 does not exist in the tags folder. You won’t get the desired result if it already exists.

As the guide mentions, it is important that the readme.txt file in your trunk folder is updated with the proper stable tag BEFORE copying the files.

Some Important Notes

Do not add, remove, move, or copy files with the normal commands (or through a GUI). To do these things you must use the svn [command] (ie svn add, svn move).

Stick to one application for managing your repository. It is not a good idea to use one program to add and remove files and then another to attempt to update the repository.

You can use whatever editor you want to modify your files. The example in the guide is nano trunk/my-plugin.php, but you don’t have to do everything from command line. Personally I use notepad++ to make changes to my files, just refrain from doing anything other than editing from your GUI or third party app.

PHP IMAP Notes

Previously I wrote about using PHP’s IMAP functions. Now I’d like to provide a more detailed, and less wordy, overview of some of the more common IMAP functions. Enjoy!

imap_open

imap_open opens a connection to the specified mailbox. It takes up to 5 parameters:

Mailbox:
This is the address and port of the mail server you are connecting to. Typically this parameter will look like one of the following:

  • mail.domain.net:143
  • localhost
  • 127.0.0.1:110

The port number is optional, but it is much more efficient if one is provided. The default IMAP port is 143 and POP3 is 110

Username
Typically the email address you are trying to access mail from, but not necessarily.

Password
The password corresponding to the username

Options
The options, or flags, modify your connection stream. The default is /imap but I’ve found that /imap/novalidate-cert is often necessary. If you are trying to connect using POP3 you’ll have to set this to /pop3.

Retries
The number of connection retries. If your mail server limits the number of connection attempts it is important that this value be set to 0, otherwise you may lock yourself out of your account.

Don’t forget to close the connection stream using imap_close($mailbox) where mailbox is the connection stream you opened with imap_open.

imap_fetch_overview

imap_fetch_overview returns an overview of one or more emails. This function Always returns an array, even if only a single message is specified.

imap_stream
A connection stream created with imap_open

message id or sequence
imap_fetch_overview takes either a single message id, or a sequence formatted as x:y (ex. 1:5 will return message 1 through 5 inclusive).

Options
This parameter must be set to FT_UID if the sequence parameter is a sequence of UIDs rather than message ids. Using UIDs is often preferable to message ids because message ids are not guaranteed to remain the same. Some functions however, require that you use message ids.

This function returns a lot of useful information about a particular email. Read the function documentation for a full list. While this function does return to and from headers, it does not return the cc and bcc headers. You will have to use imap_headerinfo to obtain these. Note that imap_headerinfo cannot take a UID as a message parameter, you’ll have to use message ids.

imap_check

This function returns information about the specified mailbox. Most likely if you are using this function, you are using it to obtain the number of messages in the mailbox.

Setting and Unsetting Message Flags

Each message in a mailbox has a set of flags, probably the most interesting one is the SEEN flag. The seen flag indicates if the email has been opened or read. Usually this flag is set when using the imap_body function to obtain the body of a message. If you want to mark an email as seen you can use imap_setflag_full. To set the email as unread, use imap_clearflag_full to unset the SEEN flag.

Deleting Emails

The imap_delete flags an email for deletion. This function is really a shortcut for calling imap_setflag_full with the deleted flag. Likewise, imap_undelete is a shortcut for calling imap_clearflag_full with the deleted flag. Note that these functions do not actually delete the message. In order to delete the message you must either call imap_expunge or imap_close with the optional flag CL_EXPUNGE.

Searching the mailbox

The imap_search function is great for emails that meet a certain criteria. Personally I use this function mostly to find unopened emails.

Induction Mouse

The other day I began having some difficulty with my mouse. The left click was becoming less and less reliable, which is to be expected after a year of heavy use. I decided it was time to retire my old Logitech mouse and start looking for a new one.

For a long time I’ve wanted to get a wireless mouse, but I didn’t want to deal with batteries. This being the case I started looking for a wired optical mouse when I stumbled upon something I didn’t expect: A wireless mouse that did not require batteries.

You may be wondering how this is possible. The answer is a compact Tesla coil that zaps energy to your mouse (may cause shocks, fire, hair-loss, and cancer). Actually that’s a lie but I couldn’t help myself. The real answer is that it gets power from the mouse pad (through the magic of induction apparently). Once again, to my surprise, it wasn’t even too expensive under $25, which isn’t bad considering you can find mice for well over $70 (the ones that have more buttons than your keyboard and a racing stripe).

This being the case I figured I would give it a try, though I was still skeptical. After three weeks I have to say that it has been working well. It seems robust enough, I haven’t had any issues with the signal, and the electrified mouse pad hasn’t set my desk on fire. There are only two downsides I can think of: You have to use the provided mouse pad (which has been working fine for me) and you have to avoid putting your cell phone or other electronics on the mouse pad (though I accidentally left my cell phone on it and nothing bad happened).

More Info

Plugin Review: Hello World

This being my first plugin review, it seems fitting that it be a review of a plugin called Hello World. Lets start off with the basics:

Plugin: Hello World Code Generator
Author: Carl Sverre
Website: WordPress Plugin Directory, Home Page
Description: Generates a random hello world code snippet in one of many languages. Just drop the short tag [helloworldsnippet] into a post or page.
Compatibility: The plugin directory claims that it is downward compatible to WP 2.7, but I ran it on 2.5.1 without issue.

This is a plugin that really needs no description. The Hello World Code Generator, generates hello world code. This being the case I’ll get right into the four categories I’ll be judging the plugin on: Usefulness, Usability, User Interface, and Code.

Usefulness

Okay so generating hello world code for display in a post at random isn’t very useful, but this plugin does not claim to be useful. Rating this plugin on its usefulness wouldn’t be too fair when its goal is not to be useful. Considering that it does what it says it does I’m going to say that this category is not applicable.

Usability

This plugin requires no configuration and installation is a matter of dropping the files into your plugin directory. The use of the shortcode makes using this plugin exceedingly simple.

When I first saw this plugin the first thing that popped into my head was that it would be nice to drop it into my header, footer, or sidebar to display a short code snippet. This is not possible for two reasons, however. The first is that the this plugin uses short tags and they will only be parsed in posts or pages. The second is that some of these hello world code snippets consist of many lines; too many to insert into a header. In order to serve this purpose the code snippet probably shouldn’t be any more than three lines.

User Interface

Hello World has two output modes. If you use the [helloworldsnippet] tag it outputs the code without formatting. This is perfect if you intend to use it in combination with a syntax highlighter. If you use the [helloworldsnippet_pre] tag the code is wrapped in <pre> tags before outputting, which is perfect if you don’t have or don’t want to use a syntax highlighter.

Code

The code is pretty much what I would expect from a plugin this simple. Its clean and well written. One thing that I was happy to see was that this plugin cleans up after itself. On uninstallation the table it created in the database is dropped, which is exactly what you should expect when uninstalling a plugin.

To Summerize…

Hello World does exactly what it says it does more or less as well as anyone can expect. The only things I can think of to improve upon would be to use filters instead of (or in addition to) short tags and to have an output mode for only short code snippets.

PHP Error Handling

Previously I wrote about Exceptions as a way of dealing with error cases in PHP. Exceptions are a great way to anticipate errors and handle them appropriately. Unfortunately, however, it is not possible to anticipate every error and you users still might be presented with an ugly error message generated by PHP. One way to prevent users from seeing warnings or errors generated by PHP is to turn off error reporting. The down side to using this method is that you might not be aware that an error is occuring, and you’ll be even less aware of the details of that error.

A better solution would be to use a custom error handler. PHP provides you with a function that allows you to override the default error handler called set_error_handler. This function takes as input a callback, which is your custom error handling function. Once you call set_error_handler, PHP will no longer report errors as it normally would and instead pass those errors to your function. The function you define must take at least two inputs: error number, and error message, and optionally three additional parameters: error file, error line, and error context. I’ll go into more detail about this later, lets define our function:

set_error_handler('customHandler');

function customHandler($eNum, $eMsg, $eFile, $eLine, $eContext)
{
     switch(eNum)
     {
          case E_WARNING:
               echo "the following warning occured on line $eLine in $eFile: $eMsg";
               break;
          case E_NOTICE:
               echo "the following notice occured on line $eLine in $eFile: $eMsg";
               break;
          case E_ERROR:
               echo "the following error occured on line $eLine in $eFile: $eMsg";
               break;
     }
     return true;
}

In the above example we override the defualt error handler with our custom handler, customHandler. Anytime an error or warning occurs PHP will pass that error to our function. In this case, we use a switch statement to deal with each of our three error types: E_WARNING, E_NOTICE, and E_ERROR. Note that there are actually several more error types; you can find them Here.

Once the error has been passed to our function, we simply output the error message and the file and line number it occured in. This isn’t a whole lot different than the default behavior, but this code could easily be modified to create a database entry everytime an error occurs. Using this method, you could review all of the errors your users are getting as well as give them a customized error message. In the code above, I do not use the eContext parameter in my error reporting. eContext is an array containing of every variable at the time the error occured. Typically this is not something you show to a user, but can be very useful in debugging your program.

Note that the function we created returns true when it is complete. This is important. If it were to return false PHP would return control to the default error handler. If you wish to restore the default error handler you can use the restore_error_handler function.

Now that you know how to write a function that will override the default behavior when an error occurs, you might want to trigger your own errors that can be handled by this function. You can do this using the trigger_error function with an error message as the first parameter and optionally an error type as the second parameter. The defuault error type for trigger_error is E_USER_NOTICE, but it can also be set to E_USER_WARNING, or E_USER_ERROR. The method of triggering a user error and handling it with a custom error handler is similar to exception handling, though I would advice using this method only when reporting errors. If an error can be recovered from or there is an alternatice behavior that your program should use, exceptions are the way to go. If you want to present your user with custom error messages and track when errors occur, custom error handling is the way to go.

Plugin: WP SimpleMail

I have an email account that I more or less, use exclusively for this blog. As such I thought it would be nice to incorporate that email account into my blog’s Dashboard. So I wrote a plugin that allows me to access an IMAP email account from my dashboard. You can download it Here.

Currently its only been tested on my blog. That being the case I would greatly appreciate some feedback and bug reports. Feel free to install it and give it a try.

PHP Exception Handling

If you’ve ever coded in Java or C++ you probably know what exceptions are. If not, that’s okay. I’ll go over the basics.

Exceptions modify the control flow of a program. Usually, they are generated by functions when an error occurs. Throwing and catching exceptions allow the programmer to anticipate an error and handle it accordingly. For example: Say you write a function to open up a file and read its contents. When the function tries to open the file, however, it finds that the file does not exist. Generally this would just generate a nasty error and your program would terminate. If the programmer is aware that this is a possibility, however, he or she could check for that and throw an exception which would be caught and handled in a more user friendly fashion.

Enough talk lets see some code.

function open_file($fileName)
{
     if($contents = @file_get_contents($fileName))
          return $contents;
     else
          throw new Exception('Bad File Name!');
}

try
{
     $text = read_file('MyFile.txt');
}
catch(Exception $e)
{
     echo $e->getMessage();
}

In the code above, our function call, read_file, is surrounded by a try block which is followed by a catch block. The try block tells PHP that it should try to execute the code inside the block, while looking for the exception specified by the catch statement. The body of the catch statement tells PHP what to do in the event that exception is caught. In the case above if the file cannot be opened we simply echo ‘Bad File Name!’.

This example of course is trivial, but using exceptions you can better handle errors as they occur, which is bound to happen anytime user input is involved.

In the example above, a general exception is thrown. The exception itself is an object, the one above, has a constructor that takes as input a string. PHP, however, lets us define our own exceptions. Here’s how:

class CustomException extends Exception
{
     private $message;

     function __construct($message)
     {
          $this->message = $message;
     }

     function getMessage()
     {
          return $this->message;
     }
}

In the example above we define an exception called CustomException. Note that in the class declaration it states the CustomException extends Exception. In order for an exception to be thrown our custom exception class must extend Exception. A side effect of this is that if a function throws an exception within a try block, if the catch block is set to catch a general exception, it will catch ANY exception, including our CustomException. In the example, I create an exception class that is effectively identical to a general exception (though stripped down). You can however, define your exceptions in whatever way suits your needs.

It is important to remember when using exceptions, that if the exception occurs, code within the try block will stop executing. Be careful when putting code within a try block, only add code that cannot be executed if the exception occurs. For instance, if we call read_file, only code that needs the contents of that file should be inside the try block.

I Just Took a PHP Test…

So I was going through the process of signing up on a freelancers website, and the site offered various tests meant to prove proficiency in a given subject. I decided I’d give it a try so I took the PHP5 test. 30 minutes later I found out that I passed and did better than 66% of people that have taken the test. The only problem is that of the 40 questions, I can only think of one that was relevant to PHP programming. The remaining questions were completely obscure and pointless.

You might think that I’m just upset about not knowing the answers, but I actually did know the answers to most of them. That, however, doesn’t make them any less pointless. Let me give you an example. One of the questions asked what the output of the following code:

$arr = 'a';
$arr[0] = 'b';
echo $arr;
echo $arr[0];

The options were ‘ab’, ‘bb’, ‘b’, and an error. This is actually one of the better questions, but the reason why it is ridiculous is because you would never encounter code like this. What the question is attempting to determine, is your understanding of strings in PHP (strings are character arrays). The answer happens to be ‘bb’, but if you couldn’t figure that out don’t worry.

Here’s another example:

$x = 99;
$y = 9;
$z = 8;
echo $x++/$y++ + --$z;

If you can’t figure this out, that problem is not with you, but with the jackass that wrote this code. I honestly don’t know what this question is trying to show, other than your ability to stare at terrible code for 5 minutes trying to figure out what it does. I recall from my freshman year of college, taking intro to programming. Within the first week of this course, which assumed you had no knowledge of programming, everyone knew that this was bad code. In fact I recall a professor explicitly writing code similar to this on the board and telling us if we write our code like this, he won’t grade it. By the way I think the answer is 17.

Want another one? Okay, which of the following is a function that can help you determine if a function exists:

is_function ()
function_exists ()
fexists ()
None of the above

Even if I had never seen a line of PHP code in my life I could answer this by tabbing over to google. Every question on the test (with the exception of the one that I mentioned) fell into the category of completely pointless and obscure, or “Do you know how to look up what a function does using google”.

the one question that I mentioned that was actually a good question, was about outputting each value of an arbitrary list, that is a list that contain sub-lists as well as individual elements. The correct way to do this is with a recursive function and is_array().

So what’s the point of this rant you say? My point is that if you are a PHP programmer don’t waste time with these tests and definitely don’t spend money to take one. If you are looking for a PHP programmer don’t place any merit on the results of one of these tests. The only way to tell if someone is a good programmer is to see and run their code. Furthermore, the only way to become a good programmer is to write lots of code of your own, look at other people’s code, and get advice from experienced coders.

Validating User Input

Whenever you write an application that takes user input, you must assume users fall into two categories. Users who are incompetent, meaning that they are likely to provide incorrect input, and users that are attempting to exploit the system, meaning that they are trying to access, destroy, or manipulate information that they should not be able to. Obviously there is a third category: Users who neither malicious, nor incompetent and are using the system in good faith. In the context of making a secure and robust application, however, we do not care about this third group of users.

Robust Applications

An application is robust if it is not prone to crashing or misbehaving regardless of the input it is given. If an application is given improper input it should respond by informing the user of their mistake. This means that the programmer must determine the nature of a user’s input, before using it. If your program is expecting a number as input, it should not proceed if that input is a string. Furthermore, if only a certain range of numbers (ie 1 through 10) are valid, then the program should not proceed if given a number outside of that range.

Regular expressions can further aid in validating data. If you are expecting for a user to submit an email address, simply verifying that the input is a string is not sufficient. You want to ensure that the input meets certain criteria: It should consist of at least 1 character followed by the @ symbol followed by a domain name, the . symbol and finally, a TLD. A regular expression to accomplish this would be:

/^([a-zA-Z0-9])+([a-zA-Z0-9\.\\+=_-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/

Certainly there are more comprehensive ways to validate an email address, but it is important not to get carried away when validating data. The main purpose is not only to ensure that incorrect input is dealt with, but also that correct input is passed on without incident.

Secure Applications

In most cases incorrect input is harmless. It might cause the application to behave poorly or even crash, but generally restarting the programming or submitting a form over again will fix the problem. Some input, however, is intended to exploit a vulnerability in the system. An SQL injection is a common example of this type of input. Ensuring that input conforms to any applicable constraints is a first wave of defence against this type of attack. In addition to this, however, it is important to either escape or exclude certain characters from user input. Quotes for example should be be properly escaped.

Examples

So far I’ve talked about robust and secure applications in general. Now I will give examples of how to secure your application in PHP. Before I give code examples I would like to outline a few practices that will prevent SQL injections, as well as good faith mistakes:

  • Email addresses should be validated with a regular expression.
  • Number values, such as dates should be validated as integers.
  • User names should be constrained to a subset of characters (ie A-Z, a-z, 0-9 and _) and validated with a regular expression.
  • Passwords should be encrypted (i.e. sha1) before submitting to the database
  • All data should have quotes escaped

Here are a few PHP functions to validate user input:

<?php

/**
Ensures that the input is number, and if specified, lies
between the values min and max. For example, if you want to
validate that an input is a valid day of the month call
validateNumeric($input , $min = 0 , $max = 31);
**/
function validateNumeric($value , $min = 'none' , $max = 'none')
{
	if(!is_numeric($value))
		return false;

	if(is_numeric($min) && $min > $value)
		return false;

	if(is_numeric($max) && $max < $value)
		return false;

	return true;
}

/**
Ensures that the given email address is correctly
formatted
**/
function validateEmailAddress($address)
{
	if(!preg_match( "/^([a-zA-Z0-9])+([a-zA-Z0-9\.\\+=_-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/", $address))
	{
		return false;
	}
	return true;
}

/**
Ensures that the given username contains only
letters and numbers and is longer than the
give minimum length.
**/
function validateUsername($user , $minLength)
{
	if(eregi('[^A-Za-z0-9]', $u) > 0 || strlen($u) < $minLength)
	{
		return false;
	}

	return true;
}

/**
Escapes the given string. It is best to use whatever
real_escape_string method that PHP supplies for your
particular database. I use MySQL here as a default.
If no real_escape_string method exists, the addslashes
function is used.
**/
function escapeString($value)
{
	if(function_exists('mysql_real_escape_string'))
		return @mysql_real_escape_string($value);
	else
		return addslashes($value);
}

/**
Encrypts the given password using sha1 (twice).
Also supports the use of a salt, which is recommended.
**/
function encryptPassword($password , $salt = '')
{
	$hash = sha1( $salt . sha1($password) );
	return $hash;
}

?>