Regular Expressions and Numeric Comparisons

So let’s say you’re parsing through order numbers (as strings):

OD1004A
OD1004B
OD1108A
OE1108B
OE1108C
OE1109A
OE1148A
OE1149A
OE1151A

…and so on. And you want to find orders where the numeric portion is between 1100 and 1150, regardless of what the rest is.

Tempting as it is, this isn’t actually a regular expression problem, but requires a bit of numeric processing too.

We would need to parse the digits and then perform numeric comparison, e.g.:

$input = whatever(); # gets something like "OE1105A"

…then match with the following pattern:

preg_match("/w+(d+)w/", $input, $match);

…to store the digits in memory, and then:

if($match[1] >= 1100 and $match[1] <= 1150){...

to check to see if the number is in range.

Advertisement

PHP: require and include

Another simple feature that’s good to pick up on!

When you want to run the same functions from several pages, but don’t want to copy/paste (because that’s BAD), you do this.

Usually, you’d use require or include to include the code from one PHP script in another.

If you hadn’t done this before, or designed it in, you’ll probably need to extract the functions from your script(s), place them in a central file, and include that in all scripts that need it (including, of course, the one they were originally in!). Remember that includeing a file in another causes its embedded HTML to be included too, so you’ll typically include PHP files that have functions only, to achieve the desired result.

Then you just call the function, as if it were written in the script in the first place 🙂

Representing Hierarchical data in PHP

I’ve come across a lot of people having a problem when representing data from their databases; hierarchical data provides us with a particular problem when displaying the relationships and containers required.

An example of hierarchical data

As an example, let’s say you have forums within categories. The category “Web Programming” may have forums like “PHP”, “JavaScript” and so on, so we want to list each forum under each category. The problem here is that you’ll have:

  • a table for categories
  • one for forums (with a foreign key for categories)
  • one for posts, with a foreign key for forums
  • and probably one for comments.

This fits quite neatly into a hierarchy: each comment belongs to a post, which belongs to a forum, which belongs to a category.

Using multiple resultsets

If you want to display the Categories with Forums under them in your page, one way to do this is by setting up multiple resultsets, each focusing on one level of the hierarchy. To achieve this, you’d need to get a resultset for the categories first, and then iterate over this list with another loop for your forum list.

The following code is an example of iterating using nested queries:

$cat_rs = mysql_query("select id, name from categories");
while($cat_row = mysql_fetch_array($cat_rs)){
     // print category name from $cat_row[1]
     $forum_rs = mysql_query("select name... "
                          . "from forums "
                          . "where cat_id = '" . $cat_row[0] ."'");
     while($forum_row = mysql_fetch_array($forum_rs)){
        //print forum stuff
     }
}

Although this matches the hierarchical nature of the data, and is pretty straightforward and intuitive to understand, it is somewhat inefficient; it issues a select statement for each category, plus one to list the categories in the first place. If there are many categories, the page might take some time to load as all queries are issued and processed.

Using a SQL JOIN: a single resultset

Another way to solve the problem would be to retrieve all relevant data in a single resultset, and use PHP to iterate over the rows, deciding on when to print each individual section.

A join will give you a single recordset with the category in one column, and the forum in another, giving you many rows for a single category.

$join_rs = mysql_query("select c.id, c.name, f.name,... "
                        . "from categories c inner join forums f "
                        . "on c.id = f.cat_id "
                        . "order by c.id"); // this line is crucial
$current_category = "";
while($join_row = mysql_fetch_array($join_rs)){
	if($join_row[0] != $current_category){
                //set up new category headings here
                $current_category = $join_row[0];
        }
        //print the forum stuff in the current category
}

The PHP is a bit more complex, because you have to close divs or tables correctly, within the loop. The order by line in the above example is vital, because without it, the categories may be dotted throughout the resultset. As we want all forum data related to a single category to appear together, we want rows belonging to that category to be adjacent in the resultset. The order by clause achieves this.

Despite the complexity, there are still benefits to this approach. The earlier example was simple and intuitive, using nested queries for each parent element. On the other hand, in this example we’ve only issued one select statement, so the page is likely to load more quickly, given that the number of round trips to MySQL will be substantially fewer.

PHP: Handling Parameter Arrays from Forms

Sometimes, when processing a form, you need to retrieve a number of values for a single variable. This is often a cause for confusion when beginning PHP. The particular problem faced: how do we process multiple values coming from a form to a databse, when using PHP?

Imagine we had a drop-down box containing a number of elements, and we want the user to select one or more. We’d use the select element in HTML.


Note the square brackets: for parameter arrays — parameters that allow multiple values — PHP requires that you name a GET or POST variable accordingly, so the select above needs to be named taglist[] in order to tell PHP that it will contain an array rather than a single value.

In order to process this, we then have to iterate over that array.

To iterate over the array in PHP code, we use something like this:

foreach($_POST["taglist[]"] as $s) {
    mysql_query("INSERT INTO articlestagged (article_id, tag) " .
       "VALUES ('$id','$s')")
        or die("Insert Error: ".mysql_error());
}

Obviously this example relates to adding new entries to a database, but the same would apply if we were querying a database, displaying multiple images, or indeed anywhere else we needed to operate on multiple concurrent values.