Preventing Basic XSS Attacks

Thursday, April 2, 2009

Unlike most attacks, XSS or Cross Site Scripting works on the client side. The most basic form of XSS is to put some JavaScript in user-submitted content to steal the data in a user's cookie. Since most sites use cookies and sessions to identify visitors, the stolen data can then be used to impersonate that user—which is deeply troublesome when it's a typical user account, and downright disastrous if it's the administrative account. If you don't use cookies or session IDs on your site, your users aren't vulnerable, but you should still be aware of how this attack works.

Unlike MySQL injection attacks, XSS attacks are difficult to prevent. Yahoo!, eBay, Apple, and Microsoft have all been affected by XSS. Although the attack doesn't involve PHP, you can use PHP to strip user data in order to prevent attacks. To stop an XSS attack, you have to restrict and filter the data a user submits to your site. It is for this precise reason that most online bulletin boards don't allow the use of HTML tags in posts and instead replace them with custom tag formats such as [b] and [linkto].

Here's a simple script that illustrates how to prevent some of these attacks.

<?php
function transform_HTML($string, $length = null) {
    // Remove dead space.
    $string = trim($string);

    // Prevent potential Unicode codec problems.
    $string = utf8_decode($string);

    // HTMLize HTML-specific characters.
    $string = htmlentities($string, ENT_NOQUOTES);
    $string = str_replace("#", "&#35;", $string);
    $string = str_replace("%", "&#37;", $string);

    $length = intval($length);
    if ($length > 0) {
        $string = substr($string, 0, $length);
    }
    return $string;
}
?>


This function transforms HTML-specific characters into HTML literals. A browser renders any HTML run through this script as text with no markup. For example, consider this HTML string:
<STRONG>Bold Text</STRONG>


Normally, this HTML would render as follows:

Bold Text

However, when run through transform_HTML(), it renders as the original input. The reason is that the tag characters are HTML entities in the processed string. The resulting string from HTML() in plaintext looks like this:
&lt;STRONG&gt;Bold Text&lt;/STRONG&gt;


The essential piece of this function is the htmlentities() function call that transforms <, >, and & into their entity equivalents of &lt;, &gt;, and &amp;. Although this takes care of the most common attacks, experienced XSS hackers have another sneaky trick up their sleeve: Encoding their malicious scripts in hexadecimal or UTF-8 instead of normal ASCII text, hoping to circumvent your filters. They can send the code along as a GET variable in the URL, saying, "Hey, this is hexadecimal code, but could you run it for me anyway?" A hexadecimal example looks something like this:
<a href="http://host/a.php?variable=%22%3e %3c%53%43%52%49%50%54%3e%44
%6f%73%6f%6d%65%74%68%69%6e%67%6d%61%6c%69%63%69%6f%75%73%3c%2f%53%43%52
%49%50%54%3e">


But when the browser renders that information, it turns out to be:
<a href="http://host/a.php?variable="> <SCRIPT>Dosomethingmalicious</SCRIPT>


To prevent this, transform_HTML() takes the additional steps of converting # and % signs into their entity, shutting down hex attacks, and converting UTF-8–encoded data.

Finally, just in case someone tries to overload a string with a very long input, hoping to crash something, you can add an optional $length parameter to trim the string to the maximum length you specify.

Hope it helps.

Validating Email Addresses

Wednesday, April 1, 2009

The following script verifies that an email address mostly follows the rules outlined in RFC 2822. This won't prevent someone from entering a false (but RFCcompliant) email address such as dontbugmeman@nonexistentdomain.com, but it will catch some typos.

<?php
function is_email($email) {
 if (! preg_match( '/^[A-Za-z0-9!#$%&\'*+-/=?^_`{|}~]+@[A-Za-z0-9-]+(\.[AZa-z0-9-]+)+[A-Za-z]$/', $email)) {
            return false;
 } 
 else {
  return true;
 }
}
?>


This script uses regular expression to check whether the given email uses proper email characters (alphabetical, dots, dashes, slashes, and so on), an @ sign in the middle, and at least one dot-something on the end.

Hope it helps.

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.

Protecting Email Addresses from Spam Collectors

Saturday, February 28, 2009

Many spammers today use harvesting software that scours websites looking for email addresses on web pages. Once found, spammers start sending spam to these addresses. It is therefore beneficial to find some way to block them from doing this. Many techniques on how to do this are described on the Webfrom basic methods such as adding the text "NOSPAM" into your email and hoping that human beings understand to remove it, to much more complex methods.

A standard tactic that we will explore here is to use JavaScript. Because most crawlers are not going to bother to execute any JavaScript on the page before trying to look for email addresses, this gives us a tool. We can print the link via JavaScript so that it isn't truly part of the page. This isn't enough though because the email address would still be visible in the JavaScript code.

The solution therefore is to convert the entire link into ASCII codes, save them in a JavaScript array, and then use JavaScript to turn it back into regular HTML. The only way that a script scanning the page would ever figure this out is if it does have a JavaScript engine in it and executes the page.

The following code is a PHP function that generates the JavaScript automatically, making it easy to use.

<?php
// A function that will protect email addreses, by generating JavaScript,
//  which will in turn generate the Email Link!
function write_protected_email($address) {
    $link = "<a href=\"mailto:{$address}\">{$address}</a>";
    $codes = array();
    for ($i = 0; $i < strlen($link); $i++) {
        $codes[] = ord($link{$i});
    }
    $outputarray = implode(',', $codes);

    echo "
<script>
var datapoints = new Array({$outputarray});
for (var i = 0; i < datapoints.length; i++)
  { document.write(String.fromCharCode(datapoints[i])); }
</script>
";
}

// Test this to see if it works:
write_protected_email('Francesca_Angelo@example.com');
?>


Hope it helps.

Submitting a POST HTTP Request with cURL

Thursday, February 26, 2009

This may happen when in the middle of a PHP script you need to send data to another server and retrieve the response. This case is often when dealing with a third-party vendor, such as a payment company, data provider, and so on. Accomplishing this is easy to do with GET strings because you can just generate the string needed by hand and call it via file_get_contents() as a URL. (Or even using http_build_query() to help you create your data request.)

However, the situation is not as simple when you need to do a POST. POST commands go to a regular URL, but the data is sent separately as part of the request headers. The regular PHP URL wrappers cannot handle this. Therefore it is easiest to use the PHP cURL extension, which allows for complex interactions with Internet protocols.

Note
It is also possible to handle POST arguments via directly connecting to the server with sockets or an fopen() command and sending the POST data manually.

The following code shows a function that handles doing a POST for you, just by passing it the URL to contact, as well as the POST data. The POST data should be in the same format that http_build_query() produces, and therefore, we will make sure to use it.

<?php
// Create a function to handle the posting of data
function http_post($url, $post) {
 $c = curl_init();
 curl_setopt($c, CURLOPT_URL, $url);

 curl_setopt($c, CURLOPT_POST, true);
 curl_setopt($c, CURLOPT_POSTFIELDS, $post);

 curl_setopt ($c, CURLOPT_RETURNTRANSFER, true);
 return curl_exec($c);
}
$fields = array('data' => 'John Doe', 'idx' => 11321);

echo http_post('http://example.com/script.php', http_build_query($fields));
?>


cURL can handle many advanced Internet protocols and is extremely powerful. This is just a small taste of what it can do. To discover more, read the documentation at http://php.net/curl.

Note
cURL support in PHP relies on the libcurl library, which must be obtained and compiled into PHP, as well as enabling the extension, which does not exist by default either. More information on how to accomplish these tasks is available in the PHP documentation at http://php.net/curl.

PHP: Basic Web Server Example

Wednesday, February 25, 2009

Now, we will create a web server in PHP, serving only GET requests and basic file types. Given that it will be written in PHP, however, we will add an easy feature: Every file served through this web server will be treated as PHP and parsed for commands. After all, why else would you write a web server in PHP except to run PHP in it?

To make this web server, we'll start by creating our service on a specific port and IP address. It will be set to the local loopback address 127.0.0.1 and port 8088 to not conflict with any other web server on the same machine. We then listen for connections. To handle more than one client connection at a time, when a connection comes in, we will launch a new process using pcntl_fork(). This creates a new process that can handle the request and return the data, leaving the parent/server process to immediately be ready to accept another connection.

This setup will not scale well; someone could easily bring down your machine by rapidly connecting to the machine, causing you to spawn thousands of processes. If this server was ever put into production, it would at the very least need to have a limiting factor built into it, keeping the number of processes to a certain maximum. Of course, after that there are many other issues with this basic web server in terms of performance, features, and so on. However, it gives a good overview of how to write an Internet server.

<?php
$port = 8088;
$host = '127.0.0.1';
$docroot = '/html';

set_time_limit(0);

if (!($server = stream_socket_server("tcp://{$host}:{$port}",
        $err_num, $err_string))) {
    exit("ERROR: Failed to Open Server - {$err_num} - {$err_string}\n");
}


for (;;) {
    $client = stream_socket_accept($server, -1);

    if ($client) {
        $pid = pcntl_fork();

        if ($pid == -1) {
            exit("ERROR: Could not create new process!");
        }
        elseif (!$pid) {
            $command = fgets($client, 2048);

            while($line = fgets($client, 2048)) {
                if (trim($line) === '') { break; }
            }

            $request = explode(' ', $command);

            if ($request[0] != 'GET') {
                @fwrite($client, 
"HTTP/0.9 501 Not Implemented Server: Bare-Basic-PHP-WebServer Content-Type: text/html
<html><head><title>501 Not Implemented</title></head>
<body><h1>501 Not Implemented</h1>
<p>This is a very basic web server that only implements GET</p>
</body></html>");
                fclose($client);
                exit();
            }
            $parts = explode('?', $request[1]);
            if ($parts[0]{strlen($parts[0])-1} == '/') {
                $parts[0] .= 'index.php';
            }
            if (!is_file($docroot . $parts[0])) {
                @fwrite($client,
"HTTP/0.9 404 Not Found
Server: Bare-Basic-PHP-WebServer
Content-Type: text/html

<html><head><title>404 Not Found</title></head>
<body><h1>404 Not Found</h1>
<p>We looked, but the file you requested was nowhere to be found!</p>
</body></html>");
                fclose($client);
                exit();
            }

            $path = pathinfo($parts[0]);
            switch ($path['extension']) {
                case 'gif':
                case 'png':
                case 'jpg':
                    $mime = "image/{$path['extension']}";
                    break;
                case 'html':
                case 'xml':
                case 'css':
                    $mime = "text/{$path['extension']}";
                    break;
                case 'js':
                    $mime = 'application/x-javascript';
                    break;
                case 'php':
                    $mime = 'text/html';
                    break;
                default:
                    $mime = 'application/octet-stream';
            }

            if (isset($parts[1])) {
                parse_str($parts[1], $_GET);
            }

            ob_start();
            include "{$docroot}{$parts[0]}";
            $output = ob_get_contents();
            ob_end_clean();

            $length = strlen($output);
            @fwrite($client,
"HTTP/0.9 200 Ok
Server: Bare-Basic-PHP-WebServer
Content-Type: {$mime}
Content-Length: {$length}

{$output}");

            fclose($client);
            exit();
        }
    }
    @fclose($client);
}
?>


Note that this program as designed will run forever and will need to be manually killed off. When calling pcntl_fork(), your process splits into two identical copies with only a slight difference. In the parent, the call to pcntl_fork() returns the process id of the child. In the child, it returns 0. This allows you to then run different code depending on whether the current process is the parent or the child of the fork.

Caution
The pcntl (process control) functions of PHP are not available on Windows, because Windows has a different process model than UNIX. Also, even on UNIX they are not compiled into the server by default and must be specifically included upon compilation. To learn more about these functions and how to enable them, visit http://php.net/pcntl.

Hope it helps.

PHP: Example Using Sockets to Connect to an Internet Server

Tuesday, February 24, 2009

When you need to talk to an Internet service such as http, ftp, SOAP, and so on, you will need to directly access this service via TCP or UDP sockets. This is a raw connection to another server, and you must know the details of the protocol you will be dealing with to properly send commands and receive data from them.

PHP provides a number of ways to talk with Internet servers, including a fsockopen() function and an entire BSD sockets extension that can be used. However, as of PHP 5, the streams extension has been greatly enhanced and is the preferred way to talk with Internet servers because it is highly configurable and powerful.

The following code is a small application that uses stream_socket_client() to connect to the free Internet Time Service provided by NIST. The time service works as follows: A TCP connection is made to port 13 on one of the NIST servers. When a connection is successfully created, the server immediately sends the response back with the current time.

<?php
if (!($tp = stream_socket_client('tcp://time.nist.gov:13', $err, $str))) {
    exit("ERROR: Failed to connect - {$err} - {$str}\n");

    exit("ERROR: Failed to connect - {$err_num} - {$err_string}\n");
}

fgets($tp);

echo trim(fgets($tp));

fclose($tp);
?>
To find out more information about the stream functions, see http://php.net/stream.

Hope it helps.

PHP: Communicating with an LDAP Server Example

Monday, February 23, 2009

LDAP(Lightweight Directory Access Protocol) is used to talk with directory services for retrieving and modifying data. It is not a relational database system. LDAP is simply a system that provides a hierarchical organization of data. LDAP's most common use currently is for corporate address and email books, allowing for all information about each employee to be stored and retrieved as needed.

PHP provides commands to communicate to an LDAP server that are easy to use. A typical set of commands would be to connect to the server, bind (authenticate), search for some data, and then handle the data. The only problem is that the structure of each LDAP server is completely different based on how the administrator set it up, just like every database system is different. Therefore, you must understand the structure of the tree hierarchy of that LDAP server to work with it.

In the following code, we connect to a fictional LDAP server that just has three levels of hierarchy with the top one being c = Country Code, then under that o = Organization, and then below that un = User Name. (Nominally, of course, there would be more information beneath that level; however, this is all we need for our example.)

<?php
if (!($lc = ldap_connect('ldap.example.com'))) {
    die("ERROR: Can't connect to the LDAP server\n");
}

//Anonymous bind (read only access)
ldap_bind($lc);

// Search for anyone in the IT department
// with a username starting with 'e'
$res = ldap_search($lc, 'o=Information Technology, c=US', 'un=e*');

// Now, let's read all results from our search:
$data = ldap_get_entries($lc, $res);

// Loop over them all, echoing the data out:
for ($i=0; $i < $data['count']; $i++) {
    echo "Full entry (distinguished name - dn): {$data[$i]['dn']}
\n"; echo "Username: {$data[$i]['un'][0]}
\n"; } ?>


Like many other extensions of the language, LDAP support must be compiled into the server (or enabled on Windows) before you can use it. Also, we have only scratched the surface of what the full LDAP extension can do. To explore more, read the documentation at http://php.net/ldap.

Hope it helps.

PHP: Automatically Creating and Updating PHP Include Files

Sunday, February 22, 2009

There are times when you have some configuration data that your script needs to access, and the easiest way to store and use that is of course to just place it in a PHP file and include it. That way it is just part of your program, and the data is immediately ready to access.

Normally, this would involve you having to update that configuration file by hand whenever anything changes. This does not need to be the case, however, because PHP provides a function called var_export() that turns any PHP variable back into valid PHP code. Therefore by applying this you could update your configuration data, saving it back to the file. You could even use this to store other forms of data as a quick and easy method as shown in following example

<?php
// Include our file:
$data = array();
@include 'config.php';

// If we were asked to make changes, then do so:
if (count($_POST)) {
    // Just update/add the value to the 'data' array
    $data[$_POST['name']] = $_POST['val'];

    // Now save it to disk, create the 'full' file wrapping it in valid PHP
    $file = "\n";
    file_put_contents('config.php', $file, LOCK_EX);
}

// Echo out the current data
echo "<pre>Current Data is:\n\n";
print_r($data);
echo "</pre>\n";
?>
<form action="<?= $_SERVER['PHP_SELF'] ?>" method="post" name="myform">
<p>Key: <input type="text" name="name" value="" /></p>
<p>Value: <input type="text" name="val" value="" /></p>
<input value="Save Data" type="submit" />
</form>


This is very simplistic and only inserts single-dimensional strings. However, you can see the basic concept. Any PHP data can be re-created/stored in this manner, allowing for PHP files that "rewrite themselves" and all the power (and danger) that comes with that.

Hope it helps.

PHP: Creating a PHP-Based FTP Client Example

Saturday, February 21, 2009

The best way to accomplish tasks like getting directory listings, making directories, deleting files, putting multiple files at once on FTP in PHP is to use the FTP extension that is built into it. (Note that the FTP extension is enabled by default in Windows builds of PHP but must be specifically compiled into other versions.)

The following script is designed to be run from the command line, using the command-line version of PHP to execute it instead of through a web server.

<?php
$stdin = fopen('php://stdin', 'r');
$server = false;
$mode = FTP_ASCII;
$commands = array('open', 'close', 'quit', 'exit', 'cd', 'ls', 'dir',
    'pwd', 'get', 'put', 'ascii', 'binary', 'bin', 'delete', 'del');

if ($argc > 1) {
    // Remove the filename from the line
    array_shift($argv);
    // Now call the open function to handle this:
    _open($argv);
}

while (true) {
    echo 'phpftp> ';

    $line = trim(fgets($stdin));

    if ($line) {
        // Split the line into an array of space separated entries:
        $opts = explode(' ', $line);
        $cmd = strtolower(array_shift($opts));

        if (!in_array($cmd, $commands)) {
            echo "! Command not supported.\n";
        }
        // If server is false, only allow 'open'
        elseif (($server xor ($cmd != 'open')) && ($cmd != 'quit') && ($cmd != 'exit')) {
            echo "! Invalid server status for this command.\n";
        } else {
            // Otherwise, execute whatever command they gave 
            $func = "_{$cmd}";
            $func($opts);
        }
    }
}


// Open a connection:
function _open($opts) {
    global $server, $stdin;

    if (!isset($opts[0])) {
        echo '? Host: ';
        $opts[0] = trim(fgets($stdin));
    }


    if (!isset($opts[1])) {
        echo '? User: ';
        $opts[1] = trim(fgets($stdin));
    }


    if (!isset($opts[2])) {
        echo '? Pass: ';
        $opts[2] = trim(fgets($stdin));
    }


    if (!($server = @ftp_connect($opts[0]))) {
        echo "! Error, cannot connect to host!\n";
        $server = false;
    } else {
        if (!(@ftp_login($server, $opts[1], $opts[2]))) {
            echo "! Error, Username/Password not accepted!\n";
            ftp_close($server);
            $server = false;
        } else {

            echo "- Connected to {$opts[0]}\n";

            if ($type = ftp_systype($server)) {
                echo "- Server type: {$type}\n";
            }

            _ascii(0);
            _pwd(0);
        }
    }
}

// Close a connection:
function _close($opts) {
    @ftp_close($GLOBALS['server']);
    $GLOBALS['server'] = false;
    echo "- Connection Closed.\n";
}

// Change directories
function _cd($opts) {
    if (!(@ftp_chdir($GLOBALS['server'], @$opts[0]))) {
        echo "! Error, Failed to change directory\n";
    }
    _pwd(0);
}

// Quit the program!
function _exit($opts) {
    if ($GLOBALS['server']) {
        _close(0);
    }
    echo "- Goodbye!\n";
    exit();
}
function _quit($opts) {
    _exit($opts);
}

// To get a directory listing:
function _ls($opts) {
    $optstring = implode(' ', $opts);
    if ($res = ftp_rawlist($GLOBALS['server'], $optstring)) {
        foreach ($res as $r) { echo "{$r}\n"; }
    } else {
        echo "! Error, could not generate directory listing\n";
    }
}
function _dir($opts) {
    _ls($opts);
}

// Figure out what directory you are in:
function _pwd($opts) {
    $cwd = ftp_pwd($GLOBALS['server']);
    echo "- Current directory: {$cwd}\n";
}

// Get a file from the remote host, and save it locally.
function _get($opts) {
    // If we don't have any options, give an error
    if (!($opts)) {
        echo "! Error, no file specified\n";
    } else {
        // If we don't have a second option, assume a desire to
        // save the file into the current directory, with the same name
        if (!isset($opts[1])) {
            $opts[1] = basename($opts[0]);
        }

        // Now, attempt to save the file.
        if (!@ftp_get($GLOBALS['server'], $opts[1], $opts[0],
                $GLOBALS['mode'])) {
            echo "! Error - Could not download file\n";
        } else {
            echo "- Data saved to file: {$opts[1]}\n";
        }
    }
}

// Put a local file to the remote host:
function _put($opts) {
    if (!($opts)) {
        echo "! Error, no file specified\n";
    } else {
        if (!isset($opts[1])) {
            $opts[1] = basename($opts[0]);
        }

        if (!@ftp_put($GLOBALS['server'], $opts[1], $opts[0],
                $GLOBALS['mode'])) {
            echo "! Error - Could not upload file\n";
        } else {
            echo "- Data uploaded to file: {$opts[1]}\n";
        }
    }
}

// To Change the transfer mode to ASCII
function _ascii($opts) {
    $GLOBALS['mode'] = FTP_ASCII;
    echo "- Transfer mode: ASCII\n";
}

// Change the transfer mode to Binary
function _binary($opts) {
    $GLOBALS['mode'] = FTP_BINARY;
    echo "- Transfer mode: Binary\n";
}
function _bin($opts) {
    _binary($opts);
}

// Allow for deleting of files
function _delete($opts) {
    if (!($opts)) {
        echo "! Error, no file specified\n";
    } else {
        if (!@ftp_delete($GLOBALS['server'], $opts[0])) {
            echo "! Error - Could not delete file\n";
        } else {
            echo "- File Deleted: {$opts[0]}\n";
        }
    }
}
function _del($opts) {
    _delete($opts);
}
?>


To accomplish the task of creating a fully functional (though basic) FTP client in PHP, start by beginning to converse with the operating system's input by opening php://stdin. This is the equivalent in other languages of reading from stdin, and is how you accept input from the user. It then enters a loop waiting for input and doing some basic sanity checks on the command it was given, and then proceeds to perform the task requested of it.

It creates a set of its own internal functions to map to the various commands and is almost a direct one-for-one mapping for the functions provided in the FTP extension. The only difference is that the client does some extra error checking to give useful responses back to the user. Of note about the code itself: The use of a variable to hold function names, as discussed in Chapter 6, "Functions," is implemented.

In the end this creates a functional FTP client that has been written completely in PHP. It is missing some more advanced features, and even some basic ones (such as the creation and removal of directories), but gives a fairly complete example of how powerful the FTP extension for PHP is.

Hope it helps.

PHP: Connecting to an FTP Server Example

Friday, February 20, 2009

There are many ways to connect to an FTP server in PHP. One is using the cURL package, which not only handles the POST submissions talked about there but can do FTP as well. Another, is with the specific FTP extension that exists in PHP. However, the easiest way to connect to an FTP server, is to use PHP's basic file commands, such as file_get_contents() and file_put_contents(), and pass them a fully qualified ftp URL, just like would be used in a web browser. The format of this is as follows:

 ftp://user:password@example.com/directory/file.ext


where, of course, you replace the user and password with the ones that you need for your situation (or leave them off for anonymous access), replace example.com with the host you are connecting do, and then similarly change the directories and filename. This makes putting or receiving a file a simple one-line operation in PHP as shown below
<?php
 file_put_contents('ftp://user:pass@example.com/mydata.txt','Hi FTP!');
 $data = file_get_contents('ftp://user:pass@example.com/storage.txt');
 echo $data;
?>


Hope it helps.

Verfying User Accounts via Email

Thursday, February 19, 2009

On sites that have multi user accounts, some people create accounts just to cause trouble. Perhaps someone will troll your bulletin board or try to mess some other part of your system. A common problem with online stores is that someone may place an order and use a fake email address because he or she doesn't want to be spammed, making it difficult for you to reach that person if you need to ask a question about the order.

One fairly effective way to verify that your users are real is to force them to validate an email address. When you first create the user account, keep it disabled until the user clicks on a verification link in an email message. Accessing the link activates the account.

This section illustrates a system that keeps track of new users who haven't yet activated their accounts. When a user tries to log in to your system, you can first check to see if the account hasn't been activated. You need the following components:

  • A MySQL database>
  • A pending_logins table with two fields: a login and a key. You can create this table with the following SQL (we're using a field called ukey because key is a reserved keyword):
    CREATE TABLE pending_logins (
        'login' varchar(32), 'ukey' varchar(32),
        PRIMARY KEY ('login'), 
        INDEX (ukey));
    
  • PHPMailer, already installed and in the phpmailer directory


There are three functions in all: a verification generator, an activator, and a verifier. All of these functions assume that you have already validated the login name as a MySQL-safe string, because they always appear inside other code. Let's first look at the verification-generator function. You need to place a call into your account-generation code to generate a key for unlocking the account and then send that key to the user's email address. The first part generates a random 32-character string of lowercase letters to serve as a key to unlock the account:

function make_verification($login, $email, $db) {
 /* Generate an account verification link and send it to the user. */
 /* Generate key. */
 $key = ""; $i = 0;
 while ($i < 32) {
     $key .= chr(rand(97, 122));
     $i++; 
 }


Next we place the key in the pending_logins table. Because the login is the primary key, and therefore multiple rows per login are not allowed, we make sure that there are no preexisting rows; then we insert the data into the table:
 /* Place the key in the table; first delete any preexisting key. */
 $query = "DELETE FROM pending_logins WHERE login = '$login'";
 mysql_query($query, $db);
 $query = "INSERT INTO pending_logins (login, ukey) VALUES ('$login', '$key')";
 mysql_query($query, $db);
 if (mysql_error($db)) {
   print "Key generation error.";
   return false; 
 }


Now we need to generate the URL that the user must visit to activate the account. Obviously, you'll need to change this to your own server name and activation script, but make sure that you send the key as a parameter somewhere:
 /* Activation URL */
 $url = "http://accounts.example.com/activate.php?k=$key";


All that's left to do is send the email to the user. You'll likely want to customize this part as well.

include_once("phpmailer/class.phpmailer.php");
 $mail = new PHPMailer;
 $mail->ClearAddresses();
 $mail->AddAddress($email, $login);
 $mail->From = 'generator@example.com';
 $mail->FromName = 'Account Generator';
 $mail->Subject = 'Account verification';
 $mail->Body = "To activate your account, please click on the account generation URL below: $url";

 if ($mail->Send()) {
     print "Verification message sent.";
 } else {
     print $mail->ErrorInfo;
     return false;
 }
 return true;
}


To use this function, call it as follows (db is a MySQL database handle that you have opened previously). It returns true if the account was placed in the pending_logins table and PHPMailer was able to send the activation message:
make_verification(login, email_address, db)


Now that we have the verification part out of the way, the next part is a function to activate an account when the user clicks on the link. The first thing to do is to sanitize the key sent to us in case the user goofed up or someone is trying to break in. Because the generator used only lowercase characters, we'll just throw out anything that doesn't fit:
function activate_account($key, $db) {
 /* Activate an account based on a key. */
 /* Clean up the key if necessary. */ 
 $key = preg_replace("/[^a-z]/", "", $key);


Now we see if the key is bogus or not. If it's not even in the pending_logins table, there's nothing to do, and we return false to indicate that we didn't do anything:
 $query = "SELECT login FROM pending_logins WHERE ukey = '$key'";
 $c = mysql_query($query, $db);
 if (mysql_num_rows($c) != 1) {
  return false;
 }


If we get this far, we know that the key exists in the table, so all we need to do is remove that row to activate the login. Notice that we don't even need to know what the login name is.
  $query = "DELETE FROM pending_logins WHERE ukey = '$key'";
  mysql_query($query, $db);
  if (mysql_error($db)) {
     return false;
  }
  return true;
}


To use this function, call it as follows:
activate_account($_REQUEST["k"], db)


The final piece is a function that you need to place inside your user login code to determine whether the account is active or not. If an account has not been activated, it has a row in the pending_logins table. Therefore, you need only look up a username in that table:
function is_active($login, $db) {
 /* See if an account has been activated. */
 $query = "SELECT count(*) AS c FROM pending_logins WHERE login ='$login'";
 $c = mysql_query($query, $db);
 if (mysql_error($db)) {
     return false;
 }
 $r = mysql_fetch_array($c);
 if (intval($r["c"]) > 0) {
     return false;
 }
 return true;
}


There are many things you may need to do to this system to make it fit in with your site. For example, you can add a timestamp field to the table so that you can cull inactive accounts that are never verified. There may be many other reasons to deactivate an account; in that case, you need to store a reason for deactivation in the table. You may even want to include the activation key in the main login table. The activation mechanism illustrated here is specifically meant to plug into foreign login systems with minimal pain.

Hope it helps.

A Short Note: MySQL Date Formats

Wednesday, February 18, 2009

Like PHP, mySQL 5 uses a form of timestamps, in its native form, and it's not compatible with the PHP timestamp. MySQL has three time/date types: DATE, TIME, and DATETIME. MySQL also has a special date field named TIMESTAMP, which works just like DATETIME but automatically updates to the current timestamp with every insert and update and has a different internal storage mechanism.

There are some ways of representing data in your queries for these types, but it's much easier to use string in it. For example, you can use 2008-09-26 as a date, 13:23:56 as time, and 2008-09-26 13:23:56 as date and time. You can use this code to convert a PHP timestamp in $timestamp into a form suitable for mySQL:

 date('Y-m-d H:i:s', $timestamp);


Although you can store PHP/Unix timestamps as INT(100, it really helps to use the native mySQL formats you wil be able to use the data independently of PHP. To get PHP timestamp from a SELET statement, use the SQL UNIX_TIMESTAMP function, like this example:
SELECT UNIX_TIMESTAMP(date_field) FROM table;


There are a lot of useful date function in mySQL5, such as DATE_FORMAT and DATE_ADD. Check their website for a complete list.

Hope it helps.

PHP HTTP Authentication

Tuesday, February 17, 2009

HTTP authentication is the same method used by server-controlled access. The HTTP protocol specifies a method for requesting access information through WWW-Authenticate header request. When browser receives WWW-Authenticate header, it will display a dialog box requesting username andd password. PHP provides some global variables in the $_SERVER superglobal array as follows:

  • PHP_AUTH_USER contains the value of username field
  • PHP_AUTH_PW contains the value of password field
  • PHP_AUTH_TYPE either Basic or Digest, contains the type of authorization being used
Here's an example of a PHP script that presents HTTP username/password dialog box and then validates the given values.
<?php
if (!isset($_SERVER['PHP_AUTH_USER']) ||
        $_SERVER['PHP_AUTH_USER'] != 'username' ||
        $_SERVER['PHP_AUTH_PW'] != 'password' ) {
    //on failed
    header('WWW-Authenticate: Basic realm="For Your Eyes Only"');
    header('HTTP/1.0 401 Unauthorized');
    echo '<h1>401 Unauthorized!</h1><strong>Forbidden</strong>';
    exit;
}

//on success
?>
<!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>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Authentication Test</title>
</head>
<body>
<h2>Hello <?= $_SERVER['PHP_AUTH_USER'] ?>:</h2>
<p>You entered <?= $_SERVER['PHP_AUTH_PW'] ?> as your password!</p>
</body></html>


Hope it helps.

Example Using PHP Mcrypt

Monday, February 16, 2009

Unlike md5 hash, mcrypt gives you option to decrypt the encrypted data. This is is useful when you need to decrypt the ecryted data at some point. Mcrypt library offers more than 30 ciphers to use in encryption and the possibility of passphrase that can decrypt data.

Let's get to the code

<?php
$data = 'your data to be encrypted';
$key = 'secret passphrase to encrypt';
$cipher = "MCRYPT_SERPENT_256";
$mode = "MCRYPT_MODE_CBC";

function m_encrypt($data, $key, $cipher, $mode){
 return (string) 
  base64_encode(
   mcrypt_encrypt(
    $cipher,
    substr(md5($key),0,mcrypt_get_key_size($cipher, $mode)),
    $data,
    $mode,
    substr(md5($key),0,mcrypt_get_block_size($cipher, $mode))
   )
  );
}

function m_decrypt($data, $key, $cipher, $mode){
 return (string)
   mcrypt_decrypt(
    $cipher,
    substr(md5($key),0,mcrypt_get_key_size($cipher, $mode)),
    base64_decode($data),
    $mode,
    substr(md5($key),0,mcrypt_get_block_size($cipher, $mode))
   );
}
?>


The mcrypt() function requires several parameter
  • The data to be encrypted
  • The passphrase to encrypt and unlock data
  • The cipher to encrypt the data, which is the specific algorithm to encrypt the data. There are many options like MCRYPT_SERPENT_256, MCRYPT_TWOFISH192, MCRYPT_RC2, MCRYPT_DES, and MCRYPT_LOKI97. You can find these options in phpinfo() page if mcrypt is available
  • The mode to encrypt the data, there are several modes like Electronic Codebook and Cipher Feedback. The script above using MCRYPT_MODE_CBC, Cipher Block Chaining
  • Initialization vector, alias IV, or a seed, and additional bit of binary data to seed the encryption algorithm, simply to make the algorithm harder to crack
  • The length of the string needed for the key and IV. Use mcrypt_get_key_size() and mcrypt_get_block_size functions to find the appropriate lengthm then trim the key value with substr() function. If the key is shorter than the required value, mcrypt will pads it with zeros
Feel free to experimenting with various encryption methods with the script to understand it better. Hope it helps.

Form Design Basic Guidelines

Saturday, February 14, 2009

Forms are the main way for users to interact with your scripts. So it's very important to make them the right way that users can easily comprehend. There are some basic usability guidelines you should follow whenn you create forms

  • Use stylesheets to lay the elements out. You can also use tables, but I don't think using tables for elements placement is not a good practice, unless your data is tabular.
  • Mark required fields with bold, or text color, or different background color on the input fields
  • If there's an error within a field, put a notice text next to it so users realize that there's a problem and know where's the problem
  • Put a size limit on text box to avoid too much text entered by user especially when your database has field length limit
  • If you split your form to pages, let the users know how far they are in the process of form submission, e.g., "Page 3 of 5." This lets users know where they stand at all times, without leaving them wondering, "Will this next button complete my registration, or are there stil more pages to come?"


Hope it helps.

Using PHP cURL and Web Services

Generally there are 3 ways to access a site's data: 1. Download the site's web content thorugh HTML 2. Send a query parameter to a website, and pick the result 3. Use XML-based web service to access data and XML parser to acces the result. There are different protocols though, such as SOAP(Simple Object Access Protocol) and REST(Representational State Transfer).

And you will eventually also need: 1. cURL 2. OpenSSL, to access secure sites 3. XML, to parse data from web services First, create a cURL connection handle to a web page
$cLink = curl_init();

Then use curl_setopt() to determine the connection setting
curl_setopt($cLink, CURLOPT_URL, 'http://www.google.com');

By default, cURL prints the accessed page instead of returning it as string. If you need to get the data to anlayze it first, use CURLOPT_RETURNTRANSFER option.
curl_setopt($cLink, CURLOPT_RETURNRANSFER, true);

Now, access the page
$page_data = curl_exec($cLink);

And don't forget to clean up the connection
curl_close($cLink)

Those steps enable you to access web data via GET method. If you want to use POST to submit form data you'll need to set more options with curl_setopt(). Now, this is an example of a function that can access pages via GET or POST method

function get_page_content($url, $posts = null){
 $query = null;
 if(!is_null($posts)){
  if(!is_array($posts)){
   die('POST parameters must in array format');
  }
  $query = http_build_query($posts);
 }



And here's the cURL connection handle. We know that it's a POST request when there's a query string, so we configure the connection according to that and use the query string as POST data
$cLink = curl_init();
if($query){
 curl_setopt($cLink, CURLOPT_POST, true);
 curl_setopt($cLink, CURLOPT_POSTFIELDS, $query);
}


Then we configure the connection, execute the query, and return the data
 curl_setopt($cLink, CURLOPT_URL, $url);
 curl_setopt($cLink, CURLOPT_HEADER, false);
 curl_setopt($cLink, CURLOPT_RETURNTRANSFER, true);
 $data = curl_exec($cLink);
 curl_close($cLink);
 return $data;
}


And here's the usage example:
echo get_page_content('http://search.yahoo.com/search", array("p" => "codeaway');

Hope it helps.

PHP Cryptography, Storing Passwords

Friday, February 13, 2009

Storing cleartext password in database is the worst idea, instead, you should store the hash of the password and use a salt for even best results.

<?php
 /*$password contains the password*/
 $salt = 'SHIFTLEFT';
 $passwordHash = md5($salt.md5($password.$salt));
 
 /* insert the $passwordHash to database */
?>


And to check whether user input the correct password, hash the provided password using the same technique, and compare them.
<?php
 $userPass = $_POST['password'];
 $salt = 'SHIFTLEFT';
 $passwordHash = md5($salt.md5($userPass).$salt);

 /*compare $passwordHash with password stored in database*/

?>


Hope it helps.

PHP Simple CAPTCHA Example

Thursday, February 12, 2009

CAPTCHA stands for Completely Automated Public Turing Test to tell Computers and Humans Apart. It is mainly used to stop computer programs from submitting form on a web page automatically, sending automated email, and other tasks. Although the term can refer to a wide variety of methods like autio bites, riddles, etc, the typical method used by many applications is interpretation of a graphic, a graphic that contains text in it that has been altered/distorted/obscured in ways that should make it difficult for OCR proframs to actually try to parse the data out of the graphic, yet, uhman can still read it.

Many different types of distortions can be done like bending the text, rotating it, putting dots, lines, and so on. Here's an example of PHP with GD library to generate CAPTCHA graphic.

<?php
$w = 300;
$h = 50;
$gfx = imagecreatetruecolor($w, $h);

imageantialias($gfx, true);

$white = imagecolorallocate($gfx, 255, 255, 255);
imagefilledrectangle($gfx, 0, 0, $w-1, $h-1, $white);

$str = '';
foreach (range(0, rand(5,7)) as $r) {
    $str .= chr(rand(65,90));
}

$pos = $w / strlen($str);

foreach(range(0, strlen($str) - 1) as $s) {
    $shade = rand(0, 100);
    $tmpgray = imagecolorallocate($gfx, $shade, $shade, $shade);
    imagettftext($gfx,     
        rand($h/3, $h/2), 
        rand(-60, 60),     
        $s*$pos+($pos*.4), 
        rand($h*.5,$h*.7), 
        $tmpgray,         
        'arial',           
        $str{$s});         
}

foreach(range(-$h, $w, 5) as $x) {
    $shade = rand(50,254);
    $tmpgray = imagecolorallocate($gfx, $shade, $shade, $shade);
    imageline($gfx, $x, 0, $x+$h+rand(0,25), $h-1, $tmpgray);
    imageline($gfx, $x, $h-1, $x+$h+rand(0,25), 0, $tmpgray);
}

session_start();
$_SESSION['captcha'] = $str;
header('Content-type: image/png');
imagepng($gfx);
?>


Save the script as captcha.php. And here's the example of how to use it on a web page
<?php
session_start();
if (count($_POST)) {
   if (isset($_SESSION['captcha'])) {
        if ($_SESSION['captcha'] === strtoupper($_POST['check'])) {
            //on success
     unset($_SESSION['captcha']);
            echo "Congratulations, you typed it in correctly!";
        } else {
            //on failed
            echo "Sorry, that wasn't it, try again!";
        }
    } else {
   //on same session
        echo "Sorry, no spamming aloud!";
    }
}
?>
<form action="<?= $_SERVER['PHP_SELF'] ?>" method="post">
Please enter the text that you see in the following graphic:<br />
<img src="captcha.php" /><br />
<input name="check" type="text"><br />
<input name="Submit" type="submit">
</form>


Remember, after you have validated a user, you MUST destroy the session variable that held the CAPTCHA key. If you don't do this, it is possible for a user to submit the same form many times through a variation on session hijacking, providing the same session id and the same text that matches the key. Because the key wasn't destroyed, this will work and will continue to work until that session expires. Therefore, always destroy the key as soon as possible.

Hope it helps.

PHP: Encrypting Session Data

Wednesday, February 11, 2009

Usually, encrypting session data is not necessary, however, if te data that you store in sessions is sensisitive, or you're questioning the security in your database, here's an example on how to do it.

The idea is simple, you'll just have to modify your functions that store and retrieve data to encrypt and decrypt the data.$sess_db is the database sesion.

<?php
 function get_sess_data($id)
    {
      global $_sess_db;

      $algorithm = MCRYPT_BLOWFISH;
      $mode = MCRYPT_MODE_CBC;

      $id = mysql_real_escape_string($id);

      $sql = "SELECT data FROM sessions
              WHERE  id = '$id'";

      if ($result = mysql_query($sql, $_sess_db))
      {
          $record = mysql_fetch_assoc($result);
          $data = base64_decode($record['data']);
          $iv_size = mcrypt_get_iv_size($algorithm, $mode);
          $ciphertext = substr($data, $iv_size);
          $iv = substr($data, 0, $iv_size);
          $crypt = new crypt();
          $crypt->iv = $iv;
          $crypt->ciphertext = $ciphertext;
          $crypt->decrypt();
          return $crypt->cleartext;
      }
      return '';
    }

    function _write($id, $data)
    {
      global $_sess_db;
      $access = time();
      $crypt = new crypt();
      $crypt->cleartext = $data;
      $crypt->generate_iv();
      $crypt->encrypt();
      $ciphertext = $crypt->ciphertext;
      $iv = $crypt->iv;
      $data = base64_encode($iv . $ciphertext);
      $id = mysql_real_escape_string($id);
      $access = mysql_real_escape_string($access);
      $data = mysql_real_escape_string($data);
      $sql = "REPLACE INTO  sessions
              VALUES ('$id', '$access', '$data')";
      return mysql_query($sql, $_sess_db);
     }
?>


Hope it helps.

Request Data from Amazon.com Using PHP and SOAP

Tuesday, February 10, 2009

Though the letter S on SOAP stands for 'Simple', SOAP is far from simple. The idea is to place all input and output detail of a web service into Web Services Description Language(WSDL) document, making it easy for programmer to generate programming interface and call a web service just like creating method or function. No more mess around wit cURL, building queries, or any of that stuff, just create your requested object, make an interface with PHP, call the method, and you get an object containing what you need. As easy as that.

PHP5 has a collection of built-in SOAP classes, including SoapClient class that will be used often. But typically, classes aren't built by default, you need to include the --enable-soap parameter whenconfiguring and building PHP5.

Here's an example based on Amazon's web service that offers to help you sell its good from your website. Just apply for an access key ID, and you can access it for free. See below

<?php
 $sClient = new SoapClient('http://webservices.amazon.com/AWSECommerceService/
AWSECommerceService.wsdl');


Now, set up an object for the request you want to send.
 $search->AWSAccessKeyId = "yourKeyId";
 $search->Request->SearchIndex = "Music";
 $search->Request->Keywords = "Van Halen";


To perform search, run itemSearch() method.
$result = $sClient->itemSearch($search);

If everything goes well, the XML results will appear ini $result. Here's how to access this object
foreach ($result->Items->Item as $item) {
    $attributes = $item->ItemAttributes;
    if (is_array($attributes->Artist)) {
        $artist = implode($attributes->Artist, ", ");
    } else {
        $artist = $attributes->Artist;
    }
    echo "artist: $artist; title: $attributes->Title
"; } ?>


Hope it helps.