PHP Top Ten Tips

The majority of web applications I've worked with over the past year have used some variation of this connection class:

class DB {
    function DB() {
        $this->host = "localhost"; // your host
        $this->db = "myDatabase"; // your database
        $this->user = "root"; // your username
        $this->pass = "mysql"; // your password
        $this->link = mysql_connect($this->host, $this->user,  
$this->pass);
        mysql_select_db($this->db);
    }
}
 
// calls it to action
$db = new $DB;
 
$result = mysql_query("SELECT * FROM table ORDER BY id ASC LIMIT 0,10");

PHP “automagically” can apply slashes to your $_POST data for security purposes. It's an important measure to prevent SQL injections. However, slashes in your scripts can wreak havoc. This is an easy method for dealing with them. The way to handle the slashes is to strip them from our variables. However, what if the magic quotes directive is not enabled?

function magicQuotes($post) {
	if (get_magic_quotes_gpc()) {
		if (is_array($post) {
			return array_map('stripslashes',$post);
		} else {
			return stripslashes($post);
		}
	} else {
		return; // magic quotes are not ON so we do nothing
	}
}

The script above checks to see if magic quotes is enabled. If they are, it will determine if your $_POST data is an array (which it likely is) and then it will strip the slashes accordingly. Understand that this is not true 'validation'. Be sure to validate all your user-submitted data with regular expressions (which is the most common way to do so). More information about magic quotes: http://www.php.net/ magic_quotes/ More information about SQL injection: http://www.php.net/manual/en/security.database.sql-injection.php/ More information about regular expressions: http://www.php.net/pcre/

When you are ready to query your database you will need to escape special characters (quotes for instance) for safety's sake by adding slashes. We apply these before we insert variables into our database. Once again, we need to determine which version of PHP you are running first:

function escapeString($post) {
	if (phpversion() >= '4.3.0') {
		return array_map('mysql_real_escape_string',$post);
	} else {
		return array_map('mysql_escape_string',$post);		
	}
}

More information about SQL injection: http://php.belnet.be/manual/en/security.database.sql- injection.php

If you search the forum there are many good threads with rules about debugging. The single most important thing you can do is ask PHP to report errors and notices to you by adding this line at the beginning of your scripts:

error_reporting(E_ALL);

This will keep you in line as you learn by printing out errors to your screen. The most common error that E_ALL reports is not actually an error, but a notice for an “Undefined index”. Typically, it means that you have not properly set your variable. It's easy to fix and keeps you programming correctly. Another convenient tool while working with queries is print_r(). If your query is returning null or strange results, simply place this after your query command and it will display all the contents of the $result array.

print_r($result); exit;

The exit command stops your script from executing any further so you can specifically review your query results. More information about error_reporting: http://www.php.net/ error_reporting/ More information about print_r; http://www.php.net/print_r/

Initially I thought that tackling functions and classes would be difficult–thankfully I was wrong. Writing a function is something I urge all newbies to start doing immediately–it's really that simple. You are instantly involved in understanding how to produce more efficient code in smaller pieces. Where you might have a line of code that reads like this:

if ($rs['prefix'] == 1) {
	$prfx = 'Mrs. ';
} elseif ($rs['prefix'] == 2) {
	$prfx = 'Ms. ';
} else {
	$prfx = 'Mr. ';
}
 
echo $prfx.$rs['name'].' '.$rs['last_name'];
 
//You could rewrite it like this in a function:
 
function makePrefix($prefix='')
{
	if (!$prefix) return '';
	if ($prefix == 1) return 'Mrs. ';
	if ($prefix == 2) return 'Ms. ';
	if ($prefix == 3) return 'Mr. ';
}
 
echo makePrefix($rs['prefix']) . $rs['name'] . ' ' . $rs['last_name'];

Now that you've written this function, you can use it in many different projects! An easy way to describe classes is to think of it as a collection of functions that work together. Writing a good class requires an understanding of PHP 5's new OOP structure, but by writing functions you are well on your way to some of the greater powers of PHP. More information about writing functions: http: www.php.net/manual/en/language.functions.php More information about writing classes: http: www.php.net/manual/en/language.oop5.php Everything I've learned, more or less, came from the manual, trial and error and great help from the many fine people here at PHPBuilder.

Single and double quotes confused me for some time and it really should not have. I see this quite often in the forum as well. It's very easy to understand that double quotes allow php to parse and single quotes do not. Here are some examples:

$var = $value; // ok
$var = "$value"; // ok, but double quotes are not necessary
$var = '$value'; // will not work (single quotes will not allow parsing)

('.' the period adds/connects variables, functions, etc. together. Oftentimes programmers will leave spaces around the ' . ' to make things easier to read.)

$var = 'This is the ' . $value . ' of things.'; // ok - preferred 
technique
$var = "This is the $value of things."; // ok, but harder to read/debug
$var = 'This is the $value of things.'; // will not parse $value
$var = This is the $value of things.; // error
 
$var = $array['name']; // ok, generally the preferred technique
$var = $array["name"]; // ok, but why use double quotes if they are not 
necessary?
$var = "$array[name]"; // ok, but harder to read/debug - poor coding 
style
 
$var = 'Name: ' . $array['name']; // ok - preferred technique
$var = "Name: $array[name]"; // ok, but harder to read/debug - poor 
coding style
$var = "Name: $array["name"]"; // error
$var = "Name: $array['name']"; // error
 
exampleFunction($value); // ok
exampleFunction("$value"); // ok, but double quotes are not necessary
exampleFunction('$value'); // will not parse $value

It's a matter of style and convenience to produce your scripts in such a way that make them easy to read and debug. If you are using a programming editor that highlights your code it will be easy to identify the various parts. This may explain why you find syntax that looks rather confusing at first. Some examples:

$line = $result['name'] . ' ' . $result['last_name']; // ok - easy to read/debug
$line = $result["name"] . ' ' . $result["last_name"]; // ok, but why use double quotes if they are not necessary?
$line = "$result[name] $result[last_name]"; // ok - but much harder to read/debug - poor coding style
 
$line = $result['name'] . ' ' . doSomething($result['last_name']); //ok - preferred method (using a function)

If you are working with any kind of a team and/or plan on allowing others access to your work in the future it's etiquette to try to make it accessible and easy on the eyes.

The ternary operator is similar to an if/else statement except that it's more streamlined. This is a traditional if/else statement:

if (empty($_POST['action'])) {
	$action = 'default';
} else {
	$action = $_POST['action'];
}
 
//This example of a ternary operator will produce the same result as the above example using less space. It makes use of ? and : just like if and else.
 
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];

Working with ternary operators do take a little more practice - be sure you test your work as you work through them. More information: http://www.php.net/ operators.comparison

Safe queries are really a subject for a lengthier tutorial, but I'm going to try to make a simple presentation here. I'm using functions in this example as opposed to the more traditional class technique. A safe query will not return an error message that may reveal path information or give hackers accidental insider information. Certainly, security by obscurity is not an effective measure, but reducing error messages at the user end is desired once your site is launched. We use the connection class from the previous article and a few functions to make this happen. Our first function performs the actual query using msyql_query. If the query string is empty it will return false.

function safeQuery($query='') {  
   global $db;
   if (!$query) return false;	
   return mysql_query($query, $db->link);
}

The next two sample functions are our means for performing queries. Note that our fetchArray() function will return an array of results while the fetchRow() function will simply return a row. If either function returns no results FALSE will be returned.

// returns an array of records
function fetchArray($query='') 
{  
   if ($result = safeQuery($query)) {
     if (mysql_num_rows($result) > 0) {
	while ($arr = mysql_fetch_assoc($result)) $rows[] = $arr;
	return $rows;
     }
   }
   return false;
}
 
// returns a single record
function fetchRecord($query='')
{	
	if ($row = safeQuery($query)) {
		if (mysql_num_rows($row) > 0) {
			return mysql_fetch_assoc($row);
		}
	}
	return false;
}
 
// Now, with one simple line of code we can perform our query to return our predicted results.
 
$results = fetchArray("SELECT id,field1 FROM records");
 
// sample output results
if (!$results) {
	echo 'No results.';
} else {
	// loop the data
	foreach ($results as $result) {
		echo $result['id'] . ' ' . $result['field1'];
	}
}

With this approach you can also define your queries more specifically for INSERT, DELETE, etc. and/or for repetitive tasks. Once you have a group of functions you are comfortable with you can recycle them in other projects. If you understand how these safe query functions work then you are probably ready to explore the commonly used PEAR DB database abstraction class. This class, which is open source, will give you more flexibility, debugging features and it will work on more than just a MySQL database. A more complete tutorial regarding safe queries can be found at this site. Be sure to read the section regarding debugging your safe queries as well.

And finally, I highly recommend using a pen, paper and plain english (or your language of preference) to work out your concepts first. Chances are that if you can explain what you need to do in plain language, you will both be able to explain the problem to others and ultimately solve your problem. You will be surprised how much easier it will be to program with a plan rather than making it up as you go along.

Conclusion

For the most part, this collection of 10 things I wish I knew when I started using PHP are quite simple, but they should be considered building blocks. Additionally, some of the concepts presented are good examples of how you can build your own custom functions thus improving your speed and skill. Good luck programming!