PHP
  Home arrow PHP arrow Page 4 - Building A PHP-Based Mail Client (part...
Administration  
AJAX  
Apache  
BrainDump  
DHTML  
Flash  
Java  
JavaScript  
Multimedia  
MySQL  
Oracle  
Perl  
PHP  
Practices  
Python  
Reviews  
Security  
Style-Sheets  
Web Services  
XML  
Zend  
Zope  
Forums Sitemap 
IBM® developerWorks 
Sun Developer Network 
E-Commerce Hosting 
Linux Web Hosting 
Managed Hosting 
Small Business Hosting 
Mobile Linux 
App Generation ROI 
VPS Hosting 
Weekly Newsletter

 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
PHP

Building A PHP-Based Mail Client (part 2)
By: icarus, (c) Melonfire
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 5 stars5 stars5 stars5 stars5 stars / 12
    2002-01-11

    Table of Contents:
  • Building A PHP-Based Mail Client (part 2)
  • A Picture Is Worth A Thousand Words
  • The Way Things Work
  • Structure And Syntax
  • Room With A View
  • Getting Down
  • Miles To Go

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    Building A PHP-Based Mail Client (part 2) - Structure And Syntax


    (Page 4 of 7 )

    Using this process flow as reference, let's now begin implementing the code for the mail client.

    A quick look at the PHP manual reveals that PHP provides a number of useful functions to assist in this process:

    1. imap_fetchstructure() - read and return information on message structure

    2. imap_header() - return an object containing header elements

    3. imap_body() - retrieve the complete message body

    4. imap_fetchbody() - retrieve a specific section of the body

    Of these, you've already seen the imap_fetchstructure() function in action - using a mailbox handle and message number as arguments, this function reads the message body and returns an object containing information on the message size, message body and MIME parts within it.

    This object exposes a "parts" property, which is itself an array; the elements of this array are objects representing the various sections of the message. Therefore, it's possible to identify whether or not a message contains multiple parts, and obtain information on those parts, simply by iterating through this array.

    Each of the objects in the "parts" array provides information on the corresponding message section - the encoding, the size, the type and subtype, the filename and so on. A complete list of the properties exposed by each of these objects is available in the PHP manual at http://www.php.net/manual/en/function.imap-fetchstructure.php - you should look at it before proceeding further.

    Using this information, it's possible to write a couple of simple functions that build on imap_fetchstructure() to deliver customized information about message sections:

    <? // define some constants // message types $type = array("text", "multipart", "message", "application", "audio", "image", "video", "other"); // message encodings $encoding = array("7bit", "8bit", "binary", "base64", "quoted-printable", "other"); // parse message body function parse($structure) { global $type; global $encoding; // create an array to hold message sections $ret = array(); // split structure into parts $parts = $structure->parts; for($x=0; $x<sizeof($parts); $x++) { $ret[$x]["pid"] = ($x+1); $this = $parts[$x]; // default to text if ($this->type == "") { $this->type = 0; } $ret[$x]["type"] = $type[$this->type] . "/" . strtolower($this->subtype); // default to 7bit if ($this->encoding == "") { $this->encoding = 0; } $ret[$x]["encoding"] = $encoding[$this->encoding]; $ret[$x]["size"] = strtolower($this->bytes); $ret[$x]["disposition"] = strtolower($this->disposition); if (strtolower($this->disposition) == "attachment") { $params = $this->dparameters; foreach ($params as $p) { if($p->attribute == "FILENAME") { $ret[$x]["name"] = $p->value; break; } } } } return $ret; } ?>
    The parse() function accepts an object, as returned by imap_fetchstructure(), and parses it to produce an array holding some very specific information on each message part.

    First, parse() creates an empty array named $ret, which will ultimately contain as many elements as there are message parts.

    <? // create an array to hold message sections $ret = array(); ?>
    Every element of $ret will itself be an associative array, with keys representing the part number, part type, encoding, disposition, size and filename.

    Next, parse() creates an array named $parts, to hold the object array returned by the "parts" property of the imap_fetchstructure() object.

    <? // split structure into parts $parts = $structure->parts; ?>
    parse() then iterates through $parts, adding each element to $ret and creating keys to represent the characteristics of each part found.

    <? for($x=0; $x<sizeof($parts); $x++) { $ret[$x]["pid"] = ($x+1); $ret[$x]["type"] = $type[$this->type] . "/" . strtolower($this->subtype); $ret[$x]["encoding"] = $encoding[$this->encoding]; $ret[$x]["size"] = strtolower($this->bytes); $ret[$x]["disposition"] = strtolower($this->disposition); // some parts snipped for brevity } ?>
    The IMAP specification (available at http://www.faqs.org/rfcs/rfc2060.html) defines a number, or part ID, for every part of a multipart message, starting from 1 (which is usually the message text itself); my array defines this part ID via the "pid" key, and I'm recording it at this stage itself because I'm sure to need it when handling messages containing more than one attachment.

    The type and encoding of each part are stored as integers by imap_fetchstructure(); these correspond to elements of the $type and $encoding arrays respectively. If you look at the complete function definition above, you'll see that these arrays are defined outside the function, and imported into it with the "global" keyword.

    Here's an example of the array returned by parse():

    Array ( [0] => Array ( [pid] => 1 [type] => text/plain [encoding] => 7bit [size] => 41 [disposition] => ) [1] => Array ( [pid] => 2 [type] => application/zip [encoding] => base64 [size] => 50634 [disposition] => attachment [name] => photos1.zip ) [2] => Array ( [pid] => 3 [type] => application/zip [encoding] => base64 [size] => 44882 [disposition] => attachment [name] => photos2.zip ) )
    As you can see, this is a fairly clear representation of the various sections that make up a MIME message.{mospagebreak title=Getting Attached} I've also written another function to extract the attachments only from the array returned by parse() - take a look at the get_attachments() function:

    <? // iterate through object returned by parse() // create a new array holding information only on message attachments function get_attachments($arr) { for($x=0; $x<sizeof($arr); $x++) { if($arr[$x]["disposition"] == "attachment") { $ret[] = $arr[$x]; } } return $ret; } ?>
    Let's now backtrack a little and add this code to the message listing, "list.php", where it will be used to identify which messages have attachments (so that an attachment icon can be displayed next to those messages).

    Here's the revised version of that script:

    <?php // list.php - display message list // includes include("functions.php"); // session check session_start(); if (!session_is_registered("SESSION")) { header("Location: error.php?ec=2"); exit; } // open mailbox $inbox = @imap_open ("{". $SESSION_MAIL_HOST . "/pop3:110}", $SESSION_USER_NAME, $SESSION_USER_PASS) or header("Location: error.php?ec=3"); // get number of messages $total = imap_num_msg($inbox); ?> <html> <head> </head> <body bgcolor="White"> <? // page header ?> <table width="100%" border="0" cellspacing="3" cellpadding="5"> <!-- command buttons - snipped --> </table> <? if ($total > 0) { ?> <table width="100%" border="0" cellspacing="0" cellpadding="5"> <form action="delete.php" method="post"> <!-- message info columns --> <tr> <td width="5%"><font size="-1">&nbsp;</font></td> <td width="5%"><font size="-1">&nbsp;</font></td> <td width="15%"><font face="Verdana" size="-1"><b>Date</b></font></td> <td width="20%"><font face="Verdana" size="-1"><b>From</b></font></td> <td width="45%"><font face="Verdana" size="-1"><b>Subject</b></font></td> <td width="10%"><font face="Verdana" size="-1"><b>Size</b></font></td> </tr> <?php // iterate through messages for($x=$total; $x>0; $x--) { // get header and structure $headers = imap_header($inbox, $x); $structure = imap_fetchstructure($inbox, $x); ?> <tr bgcolor="<?php echo $bgcolor; ?>"> <td align="right" valign="top"> <input type="Checkbox" name="dmsg[]" value="<? echo $x; ?>"> </td> <td valign="top"> <? // attachment handling code goes here // parse structure to see if attachments exist // display icon if so $sections = parse($structure); $attachments = get_attachments($sections); if(is_array($attachments)) { echo "<img alt=\"Message has attachment\" src=images/list.gif width=30 height=30 border=0>"; } else { echo "&nbsp;"; } ?> </td> <td valign="top"> <font face="Verdana" size="-1"><? echo substr($headers->Date, 0, 22); ?></font> </td> <td valign="top"> <font face="Verdana" size="-1"><? echo htmlspecialchars($headers->fromaddress); ?></font> </td> <td valign="top"> <font face="Verdana" size="-1"> <a href="view.php?id=<? echo $x; ?>"> <? // correction for empty subject if ($headers->Subject == "") { echo "No subject"; } else { echo $headers->Subject; } ?> </a> </font> </td> <td valign="top"> <font face="Verdana" size="-1"> <? // display message size echo ceil(($structure->bytes/1024)), " KB"; ?> </font> </td> </tr> <? } // clean up imap_close($inbox); ?> </form> </table> <? } else { echo "<font face=Verdana size=-1>You have no mail at this time</font>"; } ?> </body> </html>
    And here's what the listing looks like, after making the addition:

    More PHP Articles
    More By icarus, (c) Melonfire


     

       

    PHP ARTICLES

    - Authentication Scripts for a User Management...
    - Utilizing the Use Keyword for Namespaces in ...
    - Building a User Management Application
    - Working With Different Namespaces in PHP 5
    - User Management Explained: Overview
    - Using Namespaces in PHP 5
    - Database Security: Guarding Against SQL Inje...
    - Building a Modular Exception Class in PHP 5
    - Database and Password Security for Web Appli...
    - Handling MySQL Data Set Failures in PHP 5
    - Building Site Registration for Web Applicati...
    - Intercepting Customized Exceptions in PHP 5
    - Securing Your Web Application Against Attacks
    - Sub Classing Exceptions in PHP 5
    - Authentication for Web Application Security





    © 2003-2008 by Developer Shed. All rights reserved. DS Cluster 1 hosted by Hostway
    Stay green...Green IT