Validating American Phone Numbers with PHP

Tuesday, March 31, 2009

It's sad, but there's no way to make sure a telephone number is valid outside of making a real telephone call. However, you can validate the number of digits and put it into standard format. The following function returns a pure 10-digit phone number if the number given is 10 digits or 11 digits starting with 1. If the number does not conform, the return value is false.

<?php
function is_phone($phone) {
    $phone = preg_replace('/[^\d]+/', '', $phone);
    $num_digits = strlen($phone);
    if ($num_digits == 11 && $phone[0] == "1") {
        return substr($phone, 1);
    } else if ($num_digits == 10) {
        return $phone;
    } else {
        return false;
    }
}
?>


This script shows the power of regular expressions combined with standard string functions. The key is to first throw out any character that's not a digit—a perfect task for the preg_replace() function. Once you know that you have nothing but digits in a string, you can simply examine the string length to determine the number of digits, and the rest practically writes itself.

Hope it helps.

Removing Excess Whitespace Inside a String

Monday, March 30, 2009

One of constant problems when working with form data is excess whitespace. The trim() function is usually the first tool a programmer turns to, because it removes any excess spaces from the beginning or end of a string. For example, " codeaway php " becomes "codeaway php". It's so handy that you may find yourself using it on almost every available piece of user-inputted, non-array data:

$user_input = trim($user_input);


But sometimes you have excessive whitespace inside a string—when someone may be cutting and copying information from an email, for instance. In that case, you can replace multiple spaces and other whitespace with a single space by using the preg_replace() function.
<?php
function remove_whitespace($string) {
    $string = preg_replace('/\s+/', ' ', $string);
    $string = trim($string);
    return $string;
}
?>


You'll find many uses for this script outside of form verification. It's great for cleaning up data that comes from other external sources.

Hope it helps.

Accepting and Displaying User Data Giving Warnings for Links

Saturday, March 28, 2009

There is one final manipulation of user submitted data that is regularly done. If the script allows users to include URLs in their data, the user could make the link say something completely different from where the URL actually goes. This ends up being a blemish on your website. The common solution is to display beside the actual link, the host name that the link refers to. This gives the browser a visual indication whether the link is going where they think it is.

This can be done whether you are allowing HTML to be entered or BBCode. If BBCode, just call the function defined in the following code after it has been converted into HTML. This technique can be useful for other purposes as well, such as scanning HTML data and placing "offsite" links for any external link versus ones to your own website.

<?php
// A function to create warnings on any links:
function warn_links($string) {
    // First, find all the links in the string:
    preg_match_all('|<a\s+href\s*=\s*([\'"])(.*?)\1>|i',
        $string, $results, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);

    // Now, loop over all results, BACKWARDS, to make replacements
    // Backwards so that our offsets don't start changing on us:
    foreach (array_reverse($results) as $r) {
        // [0][1] contains the offset position of the link & [2][0]
        //  contains the URL - So parse the URL to get it's host:
        $parsed = parse_url($r[2][0]);

        // Check the host - if it doesn't exist use this server's hostname:
        $host = isset($parsed['host']) ? $parsed['host'] :
            $_SERVER['HTTP_HOST'];

        // Now insert the 'host' warning:
        $string = substr_replace($string, " [{$host}] ", $r[0][1], 0);
    }

    return $string;
}

// If we had a POST, then output the data for reference:
if (count($_POST)) {
    echo "<p>The data, with link warnings:</p>\n";
    echo warn_links($_POST['data']);
}
?>
<form action="<?= $_SERVER['PHP_SELF'] ?>" method="post" name="f1">
<p>Enter some data:</p>
<p><textarea name="data" cols="80"
    rows="10"><?= @$_POST['data'] ?></textarea></p>
<p><input type="submit" /></p>
</form>


Hope it helps.

Forcing a User to Use SSL-Encrypted Pages

Friday, March 27, 2009

Here is a simple function to see if a user is connecting via SSL or not:

<?php
function is_SSL() {
    /* Checks to see whether the page is in secure mode */
    if ($_SERVER['SERVER_PORT'] == "443") { 
        return true;
    } else {
        return false;
    }
}
?>


This function works by checking the port through which the client connected to the server (SSL is port 443). If the access is not secure and it should be, you can use $_SERVER['PHP_SELF'] and the header() function to redirect to a secure version of the page.

Detailed Backtracing for Error Reporting in PHP

Thursday, March 26, 2009

It can be useful to have detailed error messages when you are trying to debug code. This can be used to display detailed messages to the screen when in your development environment.

Here's the code

<?php
// Define a custom error handler for more details
function detailed_err($errno, $errstr, $errfile, $errline, $errcontext) {
    // First of all, begin by noting that a fatal error occurred, and basic
    // details just like a normal error report:
    echo "<p>FATAL ERROR - {$errstr}</p>\n";

    // Now use debug_print_backtrace to give the function call list in
    // a compressed format easy for quick scanning:
    echo "<pre>\nFunction Call Tree:\n";
    debug_print_backtrace();

    // To finish off our 'extreme' debugging mode here, let's also give
    // a full backtrace dump, which will contain all variables that existed
    // and much much more.
    echo "\nFull Backtrace:\n";
    var_dump(debug_backtrace());

    // Close off that pre tag
    echo "</pre>\n";

    // That's it, time to make sure the script dies:
    die();
}

// Now go ahead and register this as the error handler:
set_error_handler('detailed_err', E_ERROR | E_USER_ERROR);
?>


This example makes full use of debug_bracktrace(), which gives you a full list (as an array) of all currently open function calls, variables, line numbers, and more. It also uses debug_print_backtrace(), which gives a smaller, simpler output to the backtrace to make it easier to just see the heart of the problem. Combined, this makes for as much detail as you could really care to have.

Of course, you would certainly want to make sure that this is enabled only on your development environment. You would not want this level of detail about your system to be displayed to the end user. However, you could modify this on your production server so that instead of outputting all this to the screen, it could send it as an email to you instead. That way if a fatal error happens on the website, you will be instantly notified and have all the information possible to go and debug it.

Hop it helps.

PHP Tips and Trick on Drawing

Tuesday, March 24, 2009

PHP has numerous basic functions provided for drawing that are easy enough to use and understand: Draw a rectangle, draw a circle, draw a line, and so on. Often you may need to do slight variations on these methods. That can be a little tricky to achieve the effect that you are going for.

The following code includes examples of some of the fancier tricks you may want to use, such as making rectangles with rounded corners or adding drop shadows. After studying these techniques you should be able to extrapolate many different features that you want to create.

Drop-Shadows, Outline, and Rounded-Corner Rectangles

<?php
// First of all, create a function that will automatically make a
// dropshadowed box. give it the coordinates of the primary box
// and the offset that you want the drop to be.  It assumes lower right.
function i_filledrectangledropshadow($g,
        $x1, $y1, $x2, $y2,
        $drop, $color, $shcolor) {
    // First draw the shadow box offset appropriately
    imagefilledrectangle($g, $x1 + $drop, $y1 + $drop,
        $x2 + $drop, $y2 + $drop, $shcolor);

    // Now the main box:
    imagefilledrectangle($g, $x1, $y1, $x2, $y2, $color);
}

// Create a function similar to above, but that creates an outline rectangle
//  with the drop shadow.  A more normal looking drop shadow box.
function i_rectangledropshadow($g,
        $x1, $y1, $x2, $y2,
        $drop, $color, $shcolor, $border) {
    // Time to cheat a bit.  First call our previous function:
    i_filledrectangledropshadow($g, $x1, $y1, $x2, $y2,
        $drop, $color, $shcolor);

    // Now draw a regular rectangle on top of it:
    imagerectangle($g, $x1, $y1, $x2, $y2, $border);
}

// A function to draw a filled rectangle with rounded corners:
// Just like drawing a rectangle, but also specify a radius for the corners.
function i_filledroundedrectangle($g, $x1, $y1, $x2, $y2, $color, $radius) {
    // We need to know the diameter too:
    $diam = $radius * 2;

    // Going to cheat slightly to accomplish this.  First draw four circles
    //  at the corners of this box:
    imagefilledellipse($g, $x1 + $radius, $y1 + $radius, $d, $d, $color);
    imagefilledellipse($g, $x2 - $radius, $y1 + $radius, $d, $d, $color);
    imagefilledellipse($g, $x1 + $radius, $y2 - $radius, $d, $d, $color);
    imagefilledellipse($g, $x2 - $radius, $y2 - $radius, $d, $d, $color);

    // Now fill in the middle, two well placed rectangles will do it.
    imagefilledrectangle($g, $x1+$radius, $y1, $x2-$radius, $y2, $color);
    imagefilledrectangle($g, $x1, $y1+$radius, $x2, $y2-$radius, $color);
}

// Now a version that will just draw an outline of a rounded rectangle
function i_roundedrectangle($g,
        $x1, $y1, $x2, $y2,
        $color, $border, $radius) {
    // This could be implemented by doing calls of imagearc and imageline
    //  similar to the previous function.  But since we have that function
    //  we can cheat:
    // Just call it twice with the inner color, and the border.
    i_filledroundedrectangle($g, $x1, $y1, $x2, $y2, $border, $radius);
    i_filledroundedrectangle($g, $x1 + 1, $y1 + 1, $x2 - 1, $y2 - 1,
        $color, $radius);
}

// We are going to call each of these to test them.
// Create a blank image to do this on.
$gfx = imagecreatetruecolor(200, 200);

// Declare a few colors we will use:
$black = imagecolorallocate($gfx, 0, 0, 0);
$gray = imagecolorallocate($gfx, 120, 120, 120);
$white = imagecolorallocate($gfx, 255, 255, 255);
$blue = imagecolorallocate($gfx, 0, 0, 255);

// Make almost entire background white.
imagefilledrectangle($gfx, 1, 1, 198, 198, $white);

// Turn on antialiasing so that curvy things look better.
imageantialias($gfx, true);

// Ok, try to make a blue box with a gray drop shadow:
i_filledrectangledropshadow($gfx, 5, 5, 50, 40, 5, $blue, $gray);

// How about a basic white box, with black outline, with a drop shadow
i_rectangledropshadow($gfx, 5, 60, 50, 100, 5, $white, $gray, $black);

// Insert a filled rounded rectangle, blue sounds good
i_filledroundedrectangle($gfx, 70, 5, 150, 50, $blue, 15);

// Now how about a rectangle with rounded corners, not filled in:
i_roundedrectangle($gfx, 70, 65, 160, 100, $white, $black, 15);

// Output our sample as a PNG
header('Content-type: image/png');
imagepng($gfx);
?>


Hope it helps.

PHP: Automatically Creating a Photo Gallery from Digital Camera Files (Exif Data)

Monday, March 23, 2009

Digital cameras actually store a Pandora's box of additional information in any JPEG or TIFF that they create. Information about the camera itself and the specifications of the image (such as ISO speed used) will be saved. Also, most cameras actually save a small thumbnail version of the image as wellthat's how they implement the preview function on the camera itself.

PHP has a library, the Exif library that can read this data. (The data is in a standard format known as the Exif specification.) This library, like many others, is actually included in the PHP distribution but is not compiled in by default. You will need to specify that you want to compile or include it into your version of PHP. For more information on this, visit the PHP documentation: http://php.net/exif.

This information can be great to use when building photo albums of your pictures. Listing 18.5.1 is a quick example that scans a provided directory for any .JPG images and, for each one, reads the thumbnail and other Exif data, displaying it to the user with a link to the full image.

<style>
div {
    text-align: center;
    border: 2px solid black;
    padding: 5px;
    margin: 10px;
}
ul {
    font-size: 9px;
    text-align: left;
}
</style>
<?php
// Define a path - We are assuming that this will be a relative path working
//  both in the filesystem, and through the web for links:
$path = "photos/";

// Open the directory
$do = dir($path);

// Loop through it, looking for any/all JPG files:
while (($file = $do->read()) !== false) {
    // Parse this for the extension
    $info = pathinfo($path . $file);

    // Continue only if this is a Jpeg
    if (strtolower($info['extension']) == 'jpg') {
        // We found one!  Start a DIV to display & link to this:
        echo "<div><a href=\"{$path}{$file}\">";

        // Let's try to grab the graphic, and if so, display it.
           if ($thumb = exif_thumbnail($path . $file, $width,
                   $height, $type)) {
            // We got one.  Therefore first figure out the mime type of it
            $mime = image_type_to_mime_type($type);

            // Now we are going to use an HTML trick, and embed the graphic
            // directly into the webpage as base64 encoded data
            $encoded = base64_encode($thumb);
            echo "<img src=\"data:{$mime};base64,{$encoded}\" /><br />";
        }

        // In either case, place the name of the file as part of the link:
        echo $file, "</a>\n";

        // Now let's read in all the Exif data:
        if ($exif = exif_read_data($path . $file)) {
            // We got it.  So start an unordered list to display it all
            echo "<ul>\n";

            // We need to loop through each 'section' of this data
            foreach ($exif as $section => $sectiondata) {
                // If sectiondata is an array, start a new list:
                if (is_array($sectiondata)) {
                    // Output the section name, and start a new list
                    echo "<li>{$section}<ul>\n";

                    // Loop through this section now
                    foreach ($sectiondata as $name => $data) {
                        // Output this line of data
                        echo "<li>{$name} = ", htmlspecialchars($data),
                            "</li>\n";
                    }

                    // Close our section off
                    echo "</ul></li>\n";
                } else {
                    // It's not really a section, its got data.  Echo it
                    echo "<li>{$section} = ",
                        htmlspecialchars($sectiondata), "</li>\n";
                }
            }

            // Close the entire list off
            echo "</ul>\n";
        }

        // Close the div tag
        echo "</div>\n";
    }
}
?>


As written, this ends up generating some potentially ugly pages (as well as large). The biggest problem is that what Exif data exists depends completely on the manufacturer, and even the model of the camera. Some may only include a few fields; however, most include far more than you would expect. If you were going to truly be writing some form of photo gallery software based on this code, you would certainly need to pick a subset of the fields that you would want to display.

Hope it helps.

Making RSS Display Example

Sunday, March 22, 2009

RSS feeds are often used in nontraditional ways. Web browsers have various ways of displaying RSS feeds, separate RSS software exists to read them, and even email clients are starting to display the output of the RSS.

With all this, though, one thing is often overlooked: simply reading in the RSS feed from another website and displaying it on your own website. The followong code creates a basic function that reads in a remote RSS feed, specified by a URL, and generates an HTML definition list from it, making the title a link and including the description. It also includes the title of the feed as a paragraph first.

If you want to use this in a live web page, you can wrap it inside a <div> tag to control/apply additional formatting.

<?php
// Create a function that will turn an RSS feed, into a definition list:
function rss_dl($url) {
    // Begin by loading the RSS feed into SimpleXML:
    $rss = simplexml_load_file($url);

    // Ok, output the title of the feed just as a paragraph block.  People
    // can use stylesheets later to make it look as they wish:
    echo <<<EOSNIPPET
<p>
  <a href="{$rss->channel->link}">{$rss->channel->title}</a>
</p>
EOSNIPPET;

    // Now begin our definition list:
    echo "<dl>\n";

    // Loop through all items to make definition entries from them
    foreach ($rss->channel->item as $i) {
        // The title with link:
        echo "<dt><a href=\"{$i->link}\">{$i->title}</a></dt>\n";

        // The description as the dd
        echo "<dd>{$i->description}</dd>\n";
    }

    // End our list now, we are done
    echo "</dl>\n";
}

// Test this out:
rss_dl('http://acorn.atlantia.sca.org/calendar.xml');

// And try it again:
echo "<br /><br /><br />\n";
rss_dl('http://rss.cnn.com/rss/cnn_topstories.rss');
?>


Hope it helps.

Creating an RSS File With PHP

Saturday, March 21, 2009

RSS is a specific XML format that has been created for the sole purpose of syndicating "news" type information. It considers your information to be a channel and for that channel to have multiple items. Each item in turn caan have certain information included, such as a title, URL, and description. RSS is used regularly now by news websites, blogs, and podcasts.

For full specification, you can visit http://www.rssboard.org/, which hosts the current keepers of the standard. As an example, the code below generates a small RSS feed from an array of news items.

<?php
// Create our array of news stories.
// These might have come from a database originally:
$news = array(
  array('Man hates politics', 'http://example.com/23423.php',
    'A man has been found that hates politics.  Politicians are surprised.'),
  array('Cat eats mouse', 'http://example.com/83482.php',
    'A cat was found eating a mouse.  The mouse was very surprised.'),
  array('Programmer gets hired', 'http://example.com/03912.php',
    'A programmer has received a telecommuting agreement, and is happy.'),
    );

// Now, first to create our RSS feed, start with the appropriate header:
header('Content-type: text/xml');

// Echo out the opening of the RSS document.  These are parts that just
//  describe your website, and what the RSS feed is about:
echo '<?xml version="1.0" ?>';
echo <<<EORSS

<rss version="2.0">
  <channel>
    <title>Not So Nifty News Stories (NSNNS)</title>
    <link>http://example.com/nsnns.php</link>
    <description>The best news stories we can legally find!</description>
    <language>en-us</language>
    <copyright>Copyright 2006 - NSNNS</copyright>
    <webMaster>webmaster@example.com</webMaster>
    <generator>A Custom PHP Script</generator>
EORSS;

// Now that we've taken care of that, we can echo out each news item
// So just start looping through them!
foreach ($news as $item) {
    // Well, not much fancyness needed, just echo them out:
    echo <<<EOITEM

    <item>
      <title>{$item[0]}</title>
      <link>{$item[1]}</link>
      <description>{$item[2]}</description>
    </item>
EOITEM;
}

// Almost done.  Just need to print a few closing tags now and that's it:
echo <<<EOCLOSE

  </channel>
</rss>
EOCLOSE;
?>


As can be seen from examining the code, this script starts off with some data. In this case an array of data refers to various news stories including a title, a URL, and a description of the story. Using this data, it generates an RSS feed that describes all of this news. The data more likely would have come from a database in a real example.

Hope it helps.

Searches Through XML with XPath

Friday, March 20, 2009

Directly accessing and traversing through an XML document, is handy when you know the exact format and ordering of the document in question. Often you may be presented with a document that has varying specifications. The data that you want to access might exist under multiple tags. Or you simply may have a large XML document and know that you want only one small piece of data from it.

In these cases, traversing the document tree may not be the best use of your time. Instead, you want to search through the document for the exact item (or items) that you need. This capability is available also through the SimpleXML extension. Within it, you can perform XPath searches. XPath is a standard for performing these kinds of searches through XML.

You perform a search via xpath('searchstring'). The basic format of an XPath search is of the form: "/x/y/z", where x, y, and z are nested XML tags, such as of the form: <x><y><z/></y></x>. Starting the XPath with a "/" as we did means that "x" had to be at the top level. Had that been left off, such as in "x/y/z", it would match that combination of elements at any depth in the XML structure.

Some common XPath queries are explained in the following list; these different queries can be combined in infinite combinations to generate powerful searches:

x Matches any tag named x

x/y Matches any tag named y, directly contained in a tag named x

x/y/.. Similar to the preceding item but actually matches and returns tag x, instead of tag y

x//y Matches any tag named y that is a descendant of a tag named x (any number of levels deep)

x[5] Matches the fifth tag named x

x[last()] Matches the last tag named x

x[@att] Matches any tag named x, with an attribute named att

x[@att="val"] Matches any tag named x, with an attribute named att that has the value "val"

Many more options exist; these are just the most common. To discover more about XPath and all its various options, read the W3C's specification for XPath, found at http://www.w3.org/TR/xpath.

Example Searches of an XML Document

<?php
// Using SimpleXML, read the file into memory:
$xml = simplexml_load_file('contacts.xml');

// Xpath search to find all 'meta' tags no matter what the depth:
$meta = $xml->xpath('//meta');

// Loop over them and output their IDs
foreach ($meta as $m) {
    echo "Meta - {$m['id']}<br />\n";
}

// Find all email tags within a contact tag from the root of the XML document:
$email = $xml->xpath('/contacts/contact/email');

// Loop over them and output the email addreses:
foreach ($email as $e) {
    echo "Email - {$e}<br />\n";
}

// Finally, find any contact who has a cellphone number
$cell = $xml->xpath('contact/phone[@type="cell"]/..');

// Loop over them and output their names:
foreach ($cell as $c) {
    echo "Cell Contact - {$c->name}<br />\n";
}
?>


Hope it helps.

Parsing an XML File to Retrieve Data

Thursday, March 19, 2009

PHP actually provides a number of different ways to access the data from an XML document. The XML, XMLReader, and DOM XML extensions all offer different unique ways in which to navigate through an XML document. Each has its own benefits and drawbacks, and is worth investigating. However, PHP 5 adds another extension, known as SimpleXML. This extension, as it sounds, makes it simple to access XML data and therefore will be the manner this book uses.

SimpleXML at its heart is one of two functions: simplexml_load_string(), which operates on an XML document already saved into a PHP variable, and simplexml_load_file(), which does the same from a file. Upon calling one of these functions SimpleXML returns an object that replicates the XML document. Each XML tag becomes a property of the object, nested accordingly. Perhaps the best way to illustrate this is via an example.

Reading XML Files with SimpleXML

<?php
// Using SimpleXML, read the file into memory:
$xml = simplexml_load_file('contacts.xml');

// Let's print out a formatted version of some of this contact data:
// Start with an ordered list:
echo "<ol>\n";

// Loop over each contact:
foreach ($xml->contact as $c) {
    // Print their name:
    echo '<li>' . $c->name;

    // Now start an Unordered list for their phone numbers:
    echo '<ul>';

    // Loop over every phone number for this person:
    foreach ($c->phone as $p) {
        // Echo out a line including the type of number:
        // The attribute will be accesible as if it were an assoc array
        // entry.  Using the entry itself, will echo it's value.
        echo '<li>', ucfirst($p['type']), ': ', $p, '</li>';
    }

    // Close off the phone list:
    echo "</ul></li>\n";
}
?>


Hope it helps.

PHP: Automatically Including Files from the Parent Tree

Wednesday, March 18, 2009

A common templating technique is to have identically named files with variables and functions in them that vary for each subdirectory that they are in. This way you can customize various data for each subdirectory. However, it can become an administrative problem to constantly make sure that each of your PHP files include all appropriate header/library files at all times.

Fortunately, it is possible to script this, making it an automatic process for you. The snippet below automatically includes any file named header.php from the current directory, or any directory higher than it but still within the web server's document root. As coded, this includes all header.php files, allowing for an inheritance scheme of sorts, because each subdirectory will have not only its header.php file included but also those from all its parent directories.

It is a small modification to this script to make it instead stop at the first one it finds, or perhaps to work backward, starting at the document root and including them from top to bottom.

Here's the code:

<?php
$curdir = str_replace('\\', '/', __FILE__);
// Store a copy of document root, ensuring forward slashes:
$root = str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']);

while ($root !== $curdir) {
    // Remove one directory level from the current directory
    $curdir = dirname($curdir);

    // Try to include the file, hide any error:
    @include("{$curdir}/header.php");
}
?>


The manipulation of the various directories to ensure forward slashes is just so that we know that our comparison between the root and current directory returns true. This is because on some operating systems, such as Windows, it is common for the __FILE__ constant and $_SERVER['DOCUMENT_ROOT'] to have different types of slashes in them. If you know the server that you are working on has consistent slashes, you can remove that portion of code.

Hope it helps.

PHP: Timing the Script Execution

Sunday, March 15, 2009

When debugging your scripts, and during the maintenance phase of any project, you often need to determine how long it takes for a PHP script to run. More importantly, you often know that a certain script takes a long time to run but don't know exactly what section of code is causing the slowdown. It is useful, therefore, to have an easy way to add time tracking to a script.

The first snippet below is a small include file that defines two functions useful in tracking down execution time issues. The first is used to mark different time stamps in your script. The final one generates a report based on these for you. This primarily uses the function microtime(), which when passed a parameter of true returns a UNIX epoch like time(), except that this epoch is a float with accuracy down to microseconds.

The second function defined in the first snippet, and intended to make the listing more interesting and useful, is the debug_backtrace() function, which determines the context of where the timing call was made. Filename: timer.php

<?php
$_timer_results = array();

function _timer() {
    global $_timer_results;
    $curtime = microtime(true);
    $trace = debug_backtrace();

    $_timer_results[] = array(
        'line' => $trace[0]['line'],
        'file' => $trace[0]['file'],
        'func' => isset($trace[1]['function']) ? $trace[1]['function'] : '',
        'time' => $curtime
        );
}

_timer();

function _timer_text() {
    global $_timer_results;
    $result = 'Timing Results';

    $clock = @$_timer_results[0]['time'];

    foreach ($_timer_results as $tr) {
        $thistime = $tr['time'] - $clock;
        $clock = $tr['time'];
        $fn = basename($tr['file']);

        $pretty = number_format($thistime, 5);

        $result .= "\n{$pretty} secs - File: {$fn} - Line: {$tr['line']}";

        if ($tr['func']) {
            $result .= " - Calling Function: {$tr['func']}";
        }
    }
    return $result;
}
?>


Now that we have created this script, let's use it. The following script does just that by including the script, doing some various operations while showing all the different ways in which timing can be used.

Using the timer.php
<?php
require 'timer.php';

foreach(range(1,100000) as $r) {
    rand();
}

_timer();

sha1($r);

_timer();

function do_it() {
    _timer();
    sleep(3);
}

do_it();
_timer();

$output = _timer_text();
echo "<pre>{$output}</pre>\n";
?>


Hope it helps.

PHP: Recursive Handling of Multidimensional Arrays

Saturday, March 14, 2009

There will be times when you find yourself with a multidimensional array and needing to perform some task across all values in it. It would be cumbersome (and in some cases impossible) to actually perform the task manually on all the elements. This is where recursion can help you. By using a recursive function, you can craft a simple function that performs the final task for you. Find the Maximum Value in a Multidimensional Array

<?php
function recursive_array_max($a) {
    foreach ($a as $value) {
        if (is_array($value)) {
            $value = recursive_array_max($value);
        }
        if (!(isset($max))) {
            $max = $value;
        } else {
            $max = $value > $max ? $value : $max;
        }
    }
    return $max;
}

$dimensional = array(
    57,
    array(3, 35),
    array(235, 534, 73, array(3, 4, 956), 6),
    14,
    2,
    array(5, 74, 73)
    );

$max = recursive_array_max($dimensional);

echo "The maximum value was: {$max}";
?>


In this case a function is created that finds the maximum value within the array. Like the built-in function max(), however, this recursive function dives deep into the array. Note the use of is_array() to detect whether each entry happens to be an array itself. If so, the function is called recursively on that array to find its maximum value. Eventually every element has been individually compared, or each array has been collapsed to its single highest value. Then the final answer is known.

Hope it helps.

PHP: How to Prevent Multiple Form Submissions

Friday, March 13, 2009

There are many reasons why you may need to prevent a form from being submitted multiple times. If you don't, you can end up with duplicate records. This can be caused by a careless user who submits a form once but then clicks reload, causing the data to be submitted a second time. Worse is the case of a spammer attacking your website by rapidly submitting the same form again and again. This not only creates an ugly cleanup problem to solve but also eats precious site resources.

Just redirecting the user to another web page after the form submission is complete can solve the accidental case; however, there is a solution that fulfills both needs. This solution uses sessions. The method is fairly simple. When the user accesses the form page, a session is started in which a variable indicates that the form submission will be valid from this browser. Then on the submission page, the script checks this variable, and if it exists, the submission is allowed and the variable is cleared. If the page is loaded again, an error will be generated, because the variable stating that it was valid is not there. Here's a basic form to prevent multiple form submissions

<?php
session_start();
if (!isset($_SESSION['validsubmit'])) {
    $_SESSION['validsubmit'] = true;
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Data Entry Form</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<form action="submit.php" method="post" name="u1">
Please enter your name: <input name="name" type="text" /><br />
<input type="submit" />
</form>
</body>
</html>


And here's the file submit.php
<?php
session_start();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Data Processing Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<p>
<?php
if (!isset($_SESSION['validsubmit']) || !$_SESSION['validsubmit']) {
    echo "ERROR:  Invalid form submission, or form already submitted!";
} else {
    $_SESSION['validsubmit'] = false;
    echo "Your name is {$_POST['name']}?  That's a nice name.";
}
?>
</p>
</body>
</html>


This method can still be circumvented by a user willing to click back, reload the page, re-enter data, and submit again. It can also fall prey to a script that is smart enough to load the form page first, receive the session cookie, and then return that session cookie upon the form submission. It does, however, stop the simple and common forms of abuse. Taking it one step further would be to check against the IP address and only allow so many submissions, per IP address, per a time period. This can backfire, however, because many ISPs place all their users behind dynamic IP systems that make thousands of users look like one IP address.

This concept can be extended to attempt to only allow one submission per user by also storing a cookie on the user's machine that shows that the user already submitted that page. However, because users can edit or delete their cookies, that is not reliable. The only reliable way to make only one submission, per user, ever, is to have users sign up for accounts and restrict posting to one per account.

Hope it helps.

PHP: Using GET and POST Form Data Together

Thursday, March 12, 2009

You can use GET and POST both at the same time because they are both passed in separately, even having the same variable names in both cases. The most common practice of this is to pass some configuration variables to your script via GET, while allowing user input to come as a POST.

This can be especially useful in some situations because GET parameters are saved in bookmarks, and POST parameters are not. Therefore you can place a few items in the GET string that will affect whether someone makes a bookmark, giving you the information you need to display the page properly. The following script demonstrate how we can use the GET string to indicate that the page has been posted but send the user's data via a POST. This way if someone bookmarks the "posted" page, the user will be presented a custom error if he returns to the page.

<?php
if (isset($_GET['state']) && ($_GET['state'] == 'save')) {
    if (count($_POST) == 0) {
        die("ERROR:  This page has been improperly accessed.");
    }
    echo "You claim to live in state: {$_POST['state']}\n";
    echo "The script in is the '{$_GET['state']}' state.\n";
}
?>
<form action="<?= $_SERVER['PHP_SELF'] ?>?state=save" method="post" name="f1">
In what state do you live? <input name="state" type="text" />
<input type="submit" />
</form>


Hope it helps.

PHP: Compressing and Uncompressing Files

Wednesday, March 11, 2009

Compressing data is usually a good thing, especially when file space and network bandwidth are always at premium. PHP provides a set of functions that allow you to deal with compressed files and make them yourself. Note that these functions are immediately available under Windows and some other binary distributions, although you may need to specifically compile PHP with Zlib support to access these functions on other machines.

Before we go further, it should also be noted that there is rarely a need to bother to compress the output of your PHP script to send it to the browser. The reason is that PHP has this capability automatically built in, and you can enable it for all your pages if you want by changing the value of the zlib.output_compression setting in your php.ini file. To read more about this, see http://php.net/zlib.

One good use of this is to store various data files that you may want to access in compressed format to save space but to read them into memory when needed. Here's a demo:

<?php
$data = gzfile('compressed-data.gz');
?>


Another common use is to store raw files that will be served to the public in gzipped format but use PHP to serve them back up in the end. The following shows a script that takes a filename passed in and returns the contents of said file uncompressed. Use it, for example, by calling it in an image source tag like this:
<img src="decompress.php?file=image.jpg" alt="A Photo" width="100" height="150" />


Uncompress Files for Serving
<?php
$file = $_GET['file'];
if (($file{0} == '/') || (strstr($file, '..') !== false)) {
    exit("ERROR: Attempt to navigate directory tree detected!");
}

$parts = pathinfo($file);
switch (strtolower($parts['extension'])) {
    case 'gif':
        header('Content-type: image/gif');
        break;
    case 'jpg':
    case 'jpeg':
        header('Content-type: image/jpeg');
        break;
    case 'png':
        header('Content-type: image/png');
        break;
    case 'html':
        header('Content-type: text/html');
        break;
    default:
        exit("ERROR: Unsupported filetype accessed!");
}
readgzfile("{$file}.gz");
?>


Finally you may want to take data that is passed into your script and compress it for storage into a file. This way you can allow for uploaded files on a system but mitigate the amount of disk space used by this feature. Using gzencode() prepares data to be written to a gzip file as shown here. (Also of note are gzdeflate() and gzinflate(), which can be used to compress and restore data for storage in a binary field of a database.)

Compressing User Input
<?php
$ized = serialize($_REQUEST);
$compressed = gzencode($ized, 9);
$filename = tempnam('.', 'GZ-');
file_put_contents($filename, $compressed);
?>


Hope it helps.

PHP: Displaying Full Directory Listing

Friday, March 6, 2009

Most web servers display a list of all files in a directory, allowing users to select any one of their choosing. However, this is usually turned off for security reasons. You don't want users stumbling around your web server and finding access to files that they shouldn't.

Nevertheless, there are times when you want to give users access to a particular directory. Via custom PHP, you can easily choose which files to display and which to remain hidden. Also you can format the data in whatever style you want, making it have a completely custom look that matches your website. The following script explains how.

Custom index.php File

<?php
$files = array();
$d = dir('.');

while (false !== ($file = $d->read())) {
    if ( ($file{0} != '.') &&
         ($file{0} != '~') &&
         (substr($file, -3) != 'LCK') &&
         ($file != basename($_SERVER['PHP_SELF']))    ) {
        $files[$file] = stat($file);
    }
}

$d->close();

echo '<style>td { padding-right: 10px; }</style>';
echo '<table><caption>The contents of this directory:</caption>';

ksort($files);

date_default_timezone_set('America/New_York');

foreach ($files as $name => $stats) {
    echo "<tr><td><a href=\"{$name}\">{$name}</a></td>\n";
    echo "<td align='right'>{$stats['size']}</td>\n";
    echo '<td>', date('m-d-Y h:ia', $stats['mtime']), "</td></tr>\n";
}
echo '</table>';
?>


The script uses a call to stat() to retrieve vital statistics about the file. This function returns many attributes of the file, including its current access restrictions, owner, size, various timestamps, and more. It is a powerful function, and it is recommended that you read the full documentation at http://php.net/stat.

Hope it helps.

Example Recursive Function in PHP

Thursday, March 5, 2009

A recursive function is defined simply as a function that calls itself. (Also falling under the definition would be any group of functions that loop among themselves, such as function A calling function B, which in turn calls A.) PHP supports recursive functions, and they are often an elegant solution instead of a lengthy, deep, set of static instructions. Let's look at a simple comparison of two functions that do the same thing, one written recursively, and the other not.

Recursive function example

<?php
function sum_up_to($number) {
    $result = 0;
    for ($i = 1; $i <= $number; $i++) {
        $result += $i;
    }
    return $result;
}

// The same function, written as a recursive function
function sum_up_recursive($number) {
    return ($number) ? ($number + sum_up_recursive($number - 1)) : 0;
}

// Try this in both cases, with the number 42, which should return: 903
echo 'Regular version = ', sum_up_to(42), "\n";
echo 'Recursive version = ', sum_up_recursive(42), "\n";
?>


Notice how even in this simple example of adding numbers, the code for the recursive version is much shorter and simpler. The only extra effort that must always go into recursive functions is ensuring that they exit. It is easy to write a function that will run forever. In this case, we are using the recursive function to count down, so we need to detect when we are at zero and return zero, ending the recursion.

When writing recursive functions, keep in mind two issues. The first issue is execution time.By default, PHP restricts the execution time of any script. This helps ensure that a script does not lock up a web server. Hence, you should make sure that any recursion will complete within the allotted time or modify the limit using set_time_limit().

The second issue is resources. With each call to a function, memory is allocated for all arguments passed by value and for all local variables created in a function. This memory is released on exit of that function call. Normally, this is not an issue because a function is called, does its job, and then exits. However, when a function is called recursively, this normal pattern is interrupted. When a function is called recursively, each call consumes whatever memory is needed until the recursion finally ends, when each recursive call starts returning. Normally this is not an issue. However, it is good practice to ensure that recursive functions do not create large arrays or use other "consumable" resources, such as opening files.

Finding how to end your recursion properly is the most important skill to learn in this regard. Hope it helps.

PHP: Generating Random Passwords Example

Sunday, March 1, 2009

Sometimes security dictates that users may not be allowed to choose their own passwords. In these cases you need some way to quickly generate them. Even if you do not have a requirement for random passwords, you will still often need to generate initial passwords for users, or use them when someone has lost his password and needs a new temporary one.

The following code gives an example of a function that lets you specify an arbitrary length of characters, and it generates a random password for you containing only lowercase letters, uppercase letters, and numbers.

<?php
// A function that accepts a parameter to specify a length, and then returns
// a random password with characters and letters
function random_password($length = 8) {
    // Declare a blank string to start from
    $pass = '';

    // Now loop for as many times as the length
    for ($i = 0; $i < $length; $i++) {
        // For this character, first give an equal chance of upper,lower,num
        switch (rand(0,2)) {
            case 0:
                // Generate a Number from 0 to 9
                $pass .= rand(0,9);
                break;
            case 1:
                // Generate a letter from A to Z via ascii values 65 to 90
                $pass .= chr(rand(65,90));
                break;
            default:
                // Instead use a letter from a to z, via ascii 97 to 122
                $pass .= chr(rand(97,122));
        }
    }

    // Return that password!
    return $pass;
}

// Test this, echo out a batch of 10 passwords, from 1 to 10 characters long
echo "<ol>\n";
foreach (range(1,10) as $l) {
    $tmp = random_password($l);
    echo "<li>{$tmp}</li>\n";
}
echo "</ol>\n";
?>


At the heart of this code is a switch statement that gives a random one-in-three chance of each character being lowercase, uppercase, or a number. It then randomly picks the appropriate type of character via generating ASCII values and converting them with chr(). By first randomly choosing which of the three types is used, we evenly distribute them throughout. Otherwise, because there are more letters than digits, digits would rarely appear.

Hope it helps.