tags:

views:

65

answers:

2

I'm trying to build an email message parser for our site. What I'm eventually going to do is iterate through the messages that have attachments and save the attachment if the message comes from a particular email address.

This is just the initial test, however, I am running into problems, see comments below.

  <?php
  echo "Loading..."."<br />\n";
  $mailuser="[email protected]";

  echo "User=$mailuser"."<br />\n";;
  $mailpass="mypassword";
  echo "Pass=$mailpass"."<br />\n";
  // had to use this because we have SSL on site and regular port 110 didn't work
  $mailhost="{localhost:995/pop3/ssl/novalidate-cert}";
  echo "Host=$mailhost"."<br />\n";

  $mailbox=imap_open($mailhost,$mailuser,$mailpass) or die("<br />\nFAILLED! ".imap_last_error());
  $check = imap_check($mailbox);
  // last message parsed will be stored in the file msgcounter.dat
  $firstmsg = file_get_contents('msgcounter.dat') + 1;
  $lastmsg  = $firstmsg+$check->Recent; // should be == last msg index + count of latest messages
  echo 'First:'.$firstmsg.' - Last:'.$lastmsg."<br>";
  $result   = imap_fetch_overview($mailbox,"$firstmsg:$lastmsg");
  print_r($result);
  foreach ($result as $overview) {
    echo "#{$overview->msgno} ({$overview->date}) - From: {$overview->from}
    {$overview->subject}\n";
  }
  // the following approach didn't work either, Kept getting warnings about
  // Bad message number 
  //
  // Some messages in the sequence HAVE been deleted.
  /*
  for ($index = $firstmsg-1; $index <= ($lastmsg); $index++ ) {
    if (strlen(trim(imap_fetchheader($mailbox, $index))) > 0) { 
      echo 'in message index loop:'.$index;
    }
  }
  */
  imap_close($mailbox);
echo "completed.". "<br />\n";;
?>
A: 

IMAP is a cesspool of poor standards and worse implementations. If you don't mind a little profanity (or, er, a lot), there's an infamous IMAP rant by a Ruby library dev with some interesting insights.

You should probably consider using someone else's code to do the dirty work.

Charles
I am basing my code on some other code I found on the internet for sure...;-)
MB34
Ooooo, eeeek, NOT Zend functions!!!
MB34
That ruby rant was funny. Now if the SMTP working group would get off their asses and make relays verifiable, that would end spam!
MB34
@MB34, I've found a great deal of the Zend Framework to be well architected. That doesn't mean it's well designed, of course, but it does tend to work as designed...
Charles
A: 

Ok I have a big part of what I'm trying to do working, now. The only problem I have left is actually moving the message to another "folder". imap_mail_move is not supported on POP3 mailboxes and si I have had to come up with a different way of doing things.

The last problem I have is knowing what message FILE goes with what message that I have just opened. I know I can use the std rename() function to move the file but I found that I can lookup the msgnum in the courierimapuiddb file and the filename will be there.

Here's the code I now have working, with the exception of the moving of the file:

<?php

function showProgressMsg($msg)
{
  echo $msg."<br>";
  ob_flush();
 flush();
  usleep(2500);
}
  $mailpass="mymailpass";
  $mailhost="{localhost:995/pop3/ssl/novalidate-cert}";
  $mailuser="[email protected]";
  include "libs/database/db_mysql.php";
  $db = new Database;

  $debug=false;
  if($_GET['debug']= 'yes') {
    $debug = true;
    ini_set('output_buffering', 'Off');
    ob_start();
  }

  if($debug) {showProgressMsg('Opening Mailbox');}

  $mailbox=imap_open($mailhost,$mailuser,$mailpass) or die("<br />\nFAILLED! ".imap_last_error());

  // The IMAP.xml file contains the email address and user_id of the users that we accept 
  // their files via email 
  if($debug) {showProgressMsg('Reading IMAP.xml');}
  $xml = simplexml_load_string(file_get_contents('IMAP.xml'));
  $result = $xml->xpath('item');
  while(list( , $node) = each($result)) {
    $email   = $node->LI_email;
    $user_id = $node->LI_user_id;
    $search  = "RECENT FROM \"$email\"";

    if($debug) {showProgressMsg('Searching for '.$email);}
    $result2 = imap_search($mailbox, $search);
    if($result2) {
      $index = $result2[0];
      $structure = imap_fetchstructure($mailbox, $index);

      $attachments = array();
      if(isset($structure->parts) && count($structure->parts)) {
        if($debug) {showProgressMsg('Handling attachments');}
        for($i = 0; $i < count($structure->parts); $i++) {
          $attachments[$i] = array(
            'is_attachment' => false,
            'filename' => '',
            'name' => '',
            'attachment' => '');

          if($structure->parts[$i]->ifdparameters) {
            foreach($structure->parts[$i]->dparameters as $object) {
              if(strtolower($object->attribute) == 'filename') {
                $attachments[$i]['is_attachment'] = true;
                $attachments[$i]['filename'] = $object->value;
              }
            }
          }

          if($structure->parts[$i]->ifparameters) {
            foreach($structure->parts[$i]->parameters as $object) {
              if(strtolower($object->attribute) == 'name') {
                $attachments[$i]['is_attachment'] = true;
                $attachments[$i]['name'] = $object->value;
              }
            }
          }

          if($attachments[$i]['is_attachment']) {
            $attachments[$i]['attachment'] = imap_fetchbody($mailbox, $index, $i+1, FT_PEEK);
            if($structure->parts[$i]->encoding == 3) { // 3 = BASE64
              $attachments[$i]['attachment'] = base64_decode($attachments[$i]['attachment']);
            }
            elseif($structure->parts[$i]->encoding == 4) { // 4 = QUOTED-PRINTABLE
              $attachments[$i]['attachment'] = quoted_printable_decode($attachments[$i]['attachment']);
            }
          }             
        } // for($i = 0; $i < count($structure->parts); $i++)
      } // if(isset($structure->parts) && count($structure->parts))

      // Now add a record into the file_upload table
      for($i = 0; $i < count($attachments); $i++) {
        if (strlen(trim($attachments[$i]['filename'])) > 0) {
          $path_parts = pathinfo($attachments[$i]['filename']);
          if($debug) {showProgressMsg('Processing '.$attachments[$i]['filename']);}
          if(strtolower($path_parts['extension']) == 'zip') {
            // I am going to do something different with ziped files            
            $filename = 'file_uploads/temp/'.$user_id.'_'.$path_parts['filename'].'_'.date('m_d_Y').'.'.$path_parts['extension'];
            $fp = fopen($filename, "w");
            fwrite($fp, $attachments[$i]['attachment']);
            fclose($fp);                       
            $zip = new ZipArchive();
            if ($zip->open($filename) !== TRUE) {
              die ('Could not open archive');
            }
            $zippedfile = $zip->statIndex(0);
            $path_parts = pathinfo($zippedfile['name']);
            $newfilename = 'file_uploads/'.$user_id.'_'.$path_parts['filename'].'_'.date('m_d_Y').'.'.$path_parts['extension'];
            $zip->extractTo('file_uploads/', $zippedfile['name']);
            $zip->close();           
            unlink($filename);
            rename('file_uploads/'.$zippedfile['name'], $newfilename);
            $filestr = preg_replace('`[\r\n]+`',"\n", file_get_contents($newfilename));
            $fp = fopen($newfilename, "w+");
            fwrite($fp, $filestr);
            fclose($fp);                       
            // remove the directory from the filename
            $filename = $user_id.'_'.$path_parts['filename'].'_'.date('m_d_Y').'.'.$path_parts['extension'];
            // Now insert into file_upload table
            $insert_sql = "INSERT INTO `file_upload` VALUES(NULL,$user_id, '$filename', 0, NOW())";
            $db->query($insert_sql) or die("Can't insert record");
          } else {
            $filename = 'file_uploads/'.$user_id.'_'.$path_parts['filename'].'_'.date('m_d_Y').'.'.$path_parts['extension'];
            $fp = fopen($filename, "w");
            $attachments[$i]['attachment'] = preg_replace('`[\r\n]+`',"\n",$attachments[$i]['attachment']);
            fwrite($fp, $attachments[$i]['attachment']);
            fclose($fp);
            // remove the directory from the filename
            $filename = $user_id.'_'.$path_parts['filename'].'_'.date('m_d_Y').'.'.$path_parts['extension'];
            // Now insert into file_upload table
            $insert_sql = "INSERT INTO `file_upload` VALUES(NULL,$user_id, '$filename', 0, NOW())";
            $db->query($insert_sql) or die("Can't insert record:".mysql_error());
          }
        } // if (strlen(trim($attachments['name'])) > 0
      } // for($i = 0; $i < count($attachments); $i++)
      // Now move the message to completed uploads mailbox
      // imap_mail_move copies the message and then sets the deleted flag.
      // Found out that imap_mail_move is unsupported on POP3 accounts
      // imap_mail_move($mailbox, "$index", "INBOX/completed+uploads") or die("can't move: ".imap_last_error()); 

      // This is a stop gap to circumvent the message being processed twice
      // Found out that this also is not supported by POP3 boxes
      if($debug) {showProgressMsg('Setting \Seen flag');}
      imap_setflag_full($mailbox, "$index", "\Seen \Flagged");

      // This clears out the deleted messages
      // imap_expunge($mailbox);

      /*
        So, I'm going to have to open the courierimapuiddb file and locate the msgnum
        then get the filename and use rename() to move the file to the completed uploads 
        directory.
      */
    if($debug) {showProgressMsg(',oving message');}

    } // if($result2)
    // Now, move the message to completed uploads 
  } // while(list( , $node) = each($result))
  if($debug) {
    showProgressMsg('Closing mailbox and cleaning up');
    ob_flush();
    flush();
    ob_end_clean();
    ini_set('output_buffering', 4096);
  }
  imap_close($mailbox);  
?>
MB34