Archive for the ‘PHP’ Category.

Accessing Email through IMAP using PHP

For a concise overview of some of the more common functions and a few tips read PHP IMAP Notes.

Previously I wrote about Intercepting Email with PHP and so far, that has been the most popular post on this blog. That being the case, I decided to write about how you can use PHP’s IMAP functions to access email.

The main difference between the two method is that when accessing email through IMAP you are accessing a mailbox that already exists. If you use piping to intercept an email you bypass the mailbox altogether. One advantage of using PHP’s IMAP functions to access Email is that you can avoid working with raw data, which would be the case with piping. With the functions provided by PHP, there would be nothing to stop you from building a webmail application with just as many capabilities as any of the major applications out there.

Before you can retrieve your email you must establish a connection to the mailbox. In order to do this you will need the IP and port of the mail server, along with a valid username and password. To connect to a mailbox on your local host use this code:

$host = 'localhost:143';
$user = 'user@domain.com';
$password = 'drowssap';
$mailbox = "{$host}INBOX";

$mbx = imap_open($mailbox , $user , $password);

Note that port 143 is the default, but is not always the correct port. If you don’t know the port you can use just the IP (or localhost) by itself, though it is recommended that you find the correct port. Also note that you can use this code to open a POP stream, as well as many other protocols. I’ll show you how to open a POP stream here, but for other protocols (IMAP over SSL, NNTP, etc.) you’ll have to read the documentation for imap_open.

$pophost = 'localhost:110/pop3';
$user = 'user@domain.com';
$password = 'drowssap';
$mailbox = "{$host}INBOX";

$mbx = imap_open($mailbox , $user , $password);

In this case as well, port 110 is the default but might not be the case for you.

Now that we’ve opened our IMAP (or other) stream we can start using PHP’s various IMAP functions to work with our mailbox. Note that if you’re stream is not an IMAP stream, not all of these functions will work as intended. Here I will show you to retrieve all of the emails in your inbox and how to view one of those emails, but I will only be using a small portion of the functions available to you, so you may want to take a look at the functions.

<?php
$mbx = imap_open($mailbox , $user , $password);

/*imap_check returns information about the mailbox
including mailbox name and number of messages*/
$check = imap_check($mbx);

/*imap_fetch_overview returns an overview for a message.
An overview contains information such as message subject,
sender, date, and if it has been seen. Note that it does
not contain the body of the message. Setting the second
parameter to "1:n" will cause it to return a sequence of messages*/
$overviews = imap_fetch_overview($mbox,"1:{$check->Nmsgs}");
?>
<table>
     <tr>
          <td>From</td>
          <td>Date</td>
          <td>Subject</td>
     </tr>

<?php
foreach($overviews as $overview)
{
     ?>
     <tr>
          <td><?php echo $overview->from; ?></td>
          <td><?php echo $overview->date; ?></td>
          <td><a href="open.php?id=<?php echo $overview->uid; ?>"><?php echo $overview->subject; ?></a></td>
     </tr>
     <?php
}
?>
</table>

The code above will generate a list of emails in your inbox, similar to what you would see if you logged into your email account. Each subject line is a link to open.php which is an arbitrary script that will open the message with the corresponding uid. The code below is an example of what open.php might look like:

<?php
$uid = $_GET['id']; //I won't validate this input, but you should

$mbx = imap_open($mailbox , $user , $password);
$overview = imap_fetch_overview($mbx, $uid, FT_UID);
$body = imap_body($mbx, $uid, FT_UID);
?>
<table>
     <tr>
          <td>From:</td>
          <td><?php echo $overview->from; ?></td>
     </tr>
     <tr>
          <td>Date:</td>
          <td><?php echo $overview->date; ?></td>
     </tr>
     <tr>
          <td>Subject:</td>
          <td><?php echo $overview->subject; ?></td>
     </tr>
     <tr>
          <td colspan="2"><?php echo $body; ?></td>
     </tr>
</table>

Notice that I set the FT_UID parameter in order to use a UID rather than a message_id. A UID will always remain the same, while a message_id may change as the content of the mailbox changes. The script would most likely work with message ids, but UIDs are guaranteed to work. If you are using a POP stream, you might find that in some cases you have to use message_ids in place of UIDs due to compatibility issues.

The imap_body function returns the body of the message with the corresponding id, but it also sets the message to “seen”. If you do not want to mark the message as seen, pass it the FT_PEEK option.

There is a great deal that you can do with these functions; far too much for me to detail all of it here. If there is anything in particular you would like to see, feel free to post a comment detailing your question.

PDO… Use It

The majority of PHP code I see, whether it be posted by a beginner on a forum, or built into a large application, seems to suggest that the current standard when accessing a database is to make use of whatever database specific commands PHP provides for your particular database (ie mysql_query, mssql_query, etc). Often times, calls to these function are coupled with various attempts to prevent sql injections (such as calls to mysql_real_escape_string). Altogether, however, to me it seems clumsy and insecure.

PHP5 provies a built in (partial) database abstraction layer that can not only simplify the process of querying your database not only protecting against sql injections, but optimize your queries and make your application more portable: PDO (PHP Data Objects). A typical database transaction with PHP might look something like this:

mysql_connect('localhost', 'user', 'password');
mysql_select_db('myDB');

$data = mysql_real_escape_string($_POST['data']);
$query = 'SELECT column FROM table WHERE data = \'' . $data . '\'';

$result = mysql_query($query);
while($row = mysql_fetch_array($result, FETCH_NUM))
{
     echo $row[0];
}

Now with PDO

$dsn = 'mysql:dbname=myDB;host=127.0.0.1';
try {
     $db = new PDO($dsn , 'user' , 'password');
}
catch(PDOException $e) {
     echo $e->getMessage();
}

$query = 'SELECT column FROM table WHERE data = ?';
$statement = $db->prepare($query);
$statement->bindParam(1 , $_POST['data']);
$statement->execute();

$rows = $statement->fetchAll(PDO::FETCH_NUM);

foreach($rows as $row)
{
     echo $row[0];
}

Outwardly, the second example might not seem like an improvement on the first. What is important, however, is what is going on underneath. From PHP.net:

Calling PDO::prepare() and PDOStatement::execute() for statements that will be issued multiple times with different parameter values optimizes the performance of your application by allowing the driver to negotiate client and/or server side caching of the query plan and meta information, and helps to prevent SQL injection attacks by eliminating the need to manually quote the parameters.

In addition to this, it simplifies the process of making your application compatible with another database. If you were to use database specific function throughout your application, you would need to change each to allow it to work with another database.

PDO, however, is not a complete database abstraction layer. While it does aid you in making your application portable, it will not emulate features of a particular database. If your queries are incompatible with your database PDO will not help you. Rarely, however, will it be the case that your queries are not compatible with most sql databases.

There are actually a few cases where where PDO will not be able to execute your queries (example: http://dev.mysql.com/doc/refman/5.0/en/c-api-prepared-statement-problems.html) but these cases are few and far between. Really it is rarely the case that you should NOT be using PDO.

Using PDO does not guarantee that user data is safe. You should always validate and sanitize user input, but PDO provides a decent extra line of defense.

http://us.php.net/pdo

Consolidating Error Pages with .htaccess

Before I get into the topic of how to consolidate all of your error pages, let me first explain how to use .htaccess to create custom error pages. If you already know how to do this feel free to skip to the next section.

Creating Custom Error Pages

.htaccess, among other things, allows you to specify custom error pages for your site. Say a user requests a file that does not exist, typically that person will get an error page that looks somewhat like this:

—————————————————-
Not Found

The requested URL /somepage.html was not found on this server.

Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.
—————————————————-

Not only is this message not helpful, but it is unappealing. Most likely you worked tirelessly making your site look presentable, so it would be a shame for a user attempting to access a page on your site to be given an ugly error message.

.htaccess allows you to specify the page you would like to use as an error page for a particular error (404, 301, 500 etc.). To do this, if it does not already exist, create a file called .htaccess in the root ( / ) directory of your site, or whatever directory you want to use custom error pages for. Note that these custom error pages will be used not only for the directory that the .htaccess file is located in, but all of the ones below it, unless you specifically override it.

Once you have created your .htaccess file, for each error you would like a custom page for add the following line:
ErrorDocument
So for example, if you would like to use a custom error page for a 404 (file not found) do the following:
ErrorDocument 404 /404.html
Where 404.html is your custom error page. Note that not every code is an error code. If you tried to set up an error page for code 200 you would end up creating an infinite loop.

Consolidating Your Error Pages

So you’ve setup your custom error pages. Mostly likely you haven’t taken the time to create a custom page for every error, and its most likely the case you don’t need to. I can honestly say I’ve never gone to a site and have it come up with a 414 Request URI Too Long error. Still, you might have taken the time to create several pages for the more common errors. You may even have a whole directory dedicated to error pages. Instead, you may want to consider using a single error page for all errors. If you’re experienced with .htaccess, you may already know how to accomplish this, if not I’ll show you.

In your .htaccess file you’ll still need to add a line for each error code you want to use a custom page for. Make sure to use the same scheme when naming all of your error pages, for example fourohfour.html, and 5hundred.php would be a bad choice. For this example I’ll use error.php (ie error404.php). These pages don’t actually need to (and should not) exist. Now we just need to create a RewriteRule for our error pages:
RewriteEngine On
ErrorDocument 404 /error404.php
ErrorDocument 500 /error500.php
RewriteRule ^error([0-9]+) error.php?code=$1 [NC]


You could eleminate the need for the rewrite rule by redirecting all of your errors to the same page like so:
RewriteEngine On
ErrorDocument 404 /error.php?code=404
ErrorDocument 500 /error.php?code=500


This, however, reveals the underlying system. This might not be a problem for most people, but some people prefer the look of urls that don’t contain parameters (?code=xxx). Also, if you decide you want to track what errors your users are getting (like what pages they are linking to that don’t exist) you can store this information in a database, in which case you wouldn’t want users to be aware of the underlying system.

Now whenever a user gets a 404 or a 500 error they will be redirected to error.php and the error code will be passed to that script. In error.php you can now set up custom messages for each error code. Here is a simple script as an example:

$code = $_GET['code']; //the error code
$code .= ''; //avoid integer indexing of the array

$errors = array( '300' => 'Multiple Choices',
                 '301' => 'Moved Permanently',
                 '302' => 'Moved Temporarily',
                 '303' => 'See Other',
                 '304' => 'Not Modified',
                 '305' => 'Use Proxy',
                 '400' => 'Bad Request',
                 '401' => 'Authorization Required',
                 '402' => 'Payment Required',
                 '403' => 'Forbidden',
                 '404' => 'Not Found',
                 '405' => 'Method Not Allowed',
                 '406' => 'Not Acceptable',
                 '407' => 'Proxy Authentication Required',
                 '408' => 'Request Timed Out',
                 '409' => 'Conflicting Request',
                 '410' => 'Gone',
                 '411' => 'Content Length Required',
                 '412' => 'Precondition Failed',
                 '413' => 'Request Entity Too Long',
                 '414' => 'Request URI Too Long',
                 '415' => 'Unsupported Media Type',
                 '500' => 'Internal Server Error',
                 '501' => 'Not Implemented',
                 '502' => 'Bad Gateway',
                 '503' => 'Service Unavailable',
                 '504' => 'Gateway Timeout',
                 '505' => 'HTTP Version Not Supported'
                      );

echo $code . ' ' . $errors[$code];

Clearly the error page generated by the script above would be no better than the default ones, but it is just an example. You could easily embed it into your site in order to maintain consistency for your users.

Intercepting Email with PHP

Here I will show you how to intercept an incoming email through piping. I have also written a guide on How to Access Email in a Mailbox through IMAP

One of the most frequent questions I’m asked, or I see asked on forums is “how do I send out an email using PHP?” The answer to that is fairly simple and well documented. It more or less involves the use of a single function mail().

Something a bit more complicated and, I think, more interesting is how you can intercept an incoming email with a pretty small chunk of PHP code. The answer to how to do this, though not so difficult to find out, is a far less trivial thing.

The Scenario (optional if you don’t feel like reading)

Say we are building a contact form for a web application. This pretty basic contact form takes whatever input  the user gives, to keep things simple we’ll just say its the users email address and a message. This message is then sent to a database where it can be read from an administrative control panel of some sort. This is pretty simple and for the most part effective. Personally I have a problem with this type of setup. If users are not logged in when using the form there is no guaranteed way to respond. The email address they provide may or may not be valid, or they could just be spamming some nonsense because they are anonymous in the Internet and no one can stop them. A simple solution: Force users to log in. But Wait! what if users are having trouble creating an account or logging in and this is the reason why thy need to contact you? OK, to solve this problem we’ll just set up an email address that users can contact us with in addition to the form. This solves the problem of reliable contact information and minimizes the spam problem (the email address can still be spammed but a lot of it can be filtered). So once this is all setup will have a contact form that sends info that can be read by all of our admins in our admin panel… and the occasional email to some email account that all of our admins will need the password to to check regularly.

This may be acceptable to some… but not to us! We know of a better way to consolidate all of our communications with our users while at the same time having our desired setup. OK maybe you don’t or else why would you read this. Here’s how we do it:

The Code(this is where you should start reading if you like to get to the point)

Some of you may be thinking that PHP is so magical that there is a simple function that is going to go out and fetch the email we want from where ever it is on the server. Well you’re wrong (not about the magical part). What we need to do is setup a script that can capture the email when the server recieves it. This is actually pretty simple, all we need to do is extract the email data from standard input (php://stdin).

$file = fopen('php://stdin', 'r');

Once we establish a file pointer to our input stream the rest is the same as reading in any other file. Here’s the complete code:

< ?php
$data = '';
$file = fopen('php://stdin', 'r');
while(!feof($file))
{
     $data .= fgets($file, 4096);
}
fclose($file);
?>

$data now stores the raw content of the email, headers and body. At this point we just need to decide what to do with the email, I’ll leave that for you to decide. So other than that our script is complete correct? False. We have not yet addressed one crucial step. The server needs to be told how to execute this script. You may be wondering, why would we have to tell the server what to do with a .php file… its .php! The main difference between a user requesting a .php file via the internet and what we are doing here is what is handling the request. When a user goes to index.php on your website, apache knows what to do with the file because that is how it has been configured. The server on the otherhand will not necissarily assume that the file should be parsed by php. So how do we tell it to you say? Hashbang. A hashbang tells the server how to handle a file, in our case we will use the following hashbang #!/usr/bin/php -q. Note that this may or may not work for you depending on the path to php on your server. The one I’m using is the default, so if you’re not sure use that one, otherwise contact your hosting provider. Ok so here is our completed, hashbanged code:

#!/usr/bin/php -q
< ?php
$data = '';
$file = fopen('php://stdin', 'r');
while(!feof($file))
{
     $data .= fgets($file, 4096);
}
fclose($file);
?>

Note that the hashbang is outside of the php tags. This is absolutely necissary for the script to work. Save this code and take note of the path to it.

The Setup

Now that we’ve written our script we need to tell the server what to do with incoming email. This setup is going to vary depending on your server configuration, I’ll tell you how to do it on a linux server with sendmail and cpanel but for anything else you’re on your own (or you can post back explaining how and I’ll add it to the tutorial). What we need to do is setup a forwarder. If you have cPanel this is fairly straightforward. In your mail section find the forwarders option and click it. From there click add new forwarder. At this point you’ll have a few different options: you can forward to another address, discard and send an error message, do nothing, or pipe to a program. We want to pipe to a program. Just type in the address that you want piped, select the pipe option and then set the path to the path to the file you just saved. If you have access to your home directory, you can forego using cpanel and use a .forward file. All you have to do is create a file called .forward and add the following line:

email@address.com,”|/path/to/script.php”

Of course replace the email address with the address you want forwarded and /path/to/script.php with the actual path to the script. You can also omit the email address portion to have all mail forwarded to the script. I believe this process is the same using Exim or Qmail.

Well that’s it for the most part. Feel free to post back with any problems you have or additions you’d like to make. I’ll write about taking a raw email and converting it to a more friendly format, in this case an associative array, in the near future.

Configuring WP for Code Examples and Execution

Since launching this blog a few days ago I have yet to post and code examples or tutorials. In preperation for this, and having decided that plain text code examples just wouldn’t cut it, I went searching for a plugin to format and highlight my code. Not too long afterward I came across the SyntaxHighlighter plugin. After a simple installation I was able to do things like this:

<?php
//this is php code
echo 'hello world';
?>

How is the feat accomplished you say?The plugin allows you to post your code by surrounding it with the tags [/sourcecode], where lang is equal to one of these supported languages:
<ul>
<li>C++ — <code>cpp</code>, <code>c</code>, <code>c++</code></li>
<li>C# — <code>c#</code>, <code>c-sharp</code>, <code>csharp</code></li>
<li>CSS — <code>css</code></li>
<li>Delphi — <code>delphi</code>, <code>pascal</code></li>
<li>Java — <code>java</code></li>
<li>JavaScript — <code>js</code>, <code>jscript</code>, <code>javascript</code></li>
<li>PHP — <code>php</code></li>
<li>Python — <code>py</code>, <code>python</code></li>
<li>Ruby — <code>rb</code>, <code>ruby</code>, <code>rails</code>, <code>ror</code></li>
<li>SQL — <code>sql</code></li>
<li>VB — <code>vb</code>, <code>vb.net</code></li>
<li>XML/HTML — <code>xml</code>, <code>html</code>, <code>xhtml</code>, <code>xslt</code></li>
</ul>
The words following the — are valid arguments for language corresponding to that particular language, meaning that for python code you can set language equal to ‘py’ or ‘python’. Pretty cool right?

But Wait!

There was one catch in my case when it came to getting this plugin up and running. I had previously installed a plugin called <a href="http://bluesome.net/post/2005/08/18/50/" target="_blank">Exec-PHP</a> that allowed me to insert php code into posts that would be executed rather than displayed (this only works for me and it only works in posts so don’t get any ideas). So now all of my code examples would simply be executed, resulting in whatever the output of that example would be (worse potentially, the execution of that code everytime someone loads that page).

I came up with two possible solutions to this problem. The first being just to not use php tags in any of the code I post (NEVER!!!). The second being that I throw away about an hour of my life, dive into the exec-php plugin code, and set things right. Clearly I chose the second of these options.

So far I’ve only found 1 bug with this modification. I can’t display the code I used to impliment it. Any php code containing the strings [sourcecode language='p h p'] or will most likely break the plugin. Here is the link to download the plugin with the modification, feel free to comment back with error reports or improvements:

Download