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.

Turning Array into NonArray Variable and Restore It Back

Thursday, February 5, 2009

Array is useful, but it's not silver bullet. There are some conditions that we can't use array. Saving an array into a session or cookie directly, for instance. XML and MySQL can't handle native PHP array type either.

That's where the function serialize come in handy. And here's a script that shows how this function works:

<?php
$drinks = array("lemon squash",
                  "capuccino",
                  "soda");
$dinners = array(
    "salad" => "spinach",
    "main" => "tenderloine",
    "drink" => $drinks);

$dinners_s = serialize($dinners); 

echo $dinners_s; 

?>
The outputs:
PEa:3:{s:5:"salad";s:6:"spinach";s:4:"main";s:11:"tenderloine";s:5:"drink";a:3:{i:0;s:12:"lemon squash";i:1;s:9:"capuccino";i:2;s:4:"soda";}}

THe serialized variable $dinners_s can be stored in almost anywhere -database, hiddem input variable, cookies, session, and so on. And You only need a line of code to restore it back to array

$dinners = deserialize($dinners_s)

But keep in mind, serialized arrays can be read easily by people so you might need to encrypt them so that nobody can't sniff your data. Secondly, don't pass serialized arrays through GET method because URL's length have finite length. And last one, don't overuse it, when you start to get and store serialized arrays consistently, maybe it's time for you to redesign your storage mechanism or database structure.

Hope it helps.