Location: PHPKode > scripts > POP3 Message Handler for PHP > pop3.class.php
<?

set_time_limit(500000);

/*
  POP3.CLASS:
	Finally it's here, the shit that's been asked of me for ages, finally I got my head around
	an algorithm to properly decode POP3 mailboxes without tons if type checking.

	Came down to that nasty recursive code your mother told you to avoid being needed.

	This is an extensible "base" API which includes:
		Get Message List
		Get Headers
		Get Message
		Split Message
		Age In Days of message
*/

define("pop3NoProblem",	"+OK");				// Standard OK message from a POP3 server
define("pop3FinalBoundary",	"----POP3_Class_Final_Boundary_". mktime());

class pop3 {

  var $pop_server = "";
  var $pop_port = "";
  var $pop_uid = "";
  var $pop_pass = "";
  var $fhandle = "";
  var $LoggedOn = false;

  function DateDiff($startdate, $enddate) {

    // This code snippet courtessy of "stew" from PHPBuilder.COM

    ## difference between the two in seconds
    $time_period = ( $enddate - $startdate );

    $days = 0;
    $hours = 0;
    $minutes = 0;
    $seconds = 0;

    $time_increments = array('Days' => 86400, 'Hours' => 3600, 'Minutes' => 60, 'Seconds' => 1);

    ## will hold our values for ( day, minute, hour, seconds )

    $time_span = array();

    ## cycle through time_increments

    while (list( $key, $value ) = each( $time_increments )) {
      $this_value = (int) ( $time_period / $value );
      $time_period = ( $time_period % $value );
      $time_span[$key] = $this_value;
    }

    ## Also the difference in minutes between the two - JB
    $time_span["min_diff"] = ($time_span["Days"] * 1440) + ($time_span["Hours"] * 60) + $time_span["Minutes"];

    return $time_span;
  }


  function pop3($pop_server, $pop_port, $pop_uid, $pop_pass) {

    $this->pop_server = 	$pop_server;
    $this->pop_port = 		$pop_port;
    $this->pop_uid = 		$pop_uid;
    $this->pop_pass = 		$pop_pass;

    // return 1 on sucessful connect.

    if ($this->Connect()) { return 1; } else { return 0; }

  }

  function Connect() {
    $this->fhandle = "";
    $fp = fsockopen($this->pop_server, $this->pop_port, $errno, $errstr, 10);
    if (!$fp) {
      echo "Error: POP3/Connect: (Err # $errno) $errstr\n";
      return 0;
    } else {
      $this->fhandle = $fp;
      list($status, $msg) = $this->GetString();
      if ($status == pop3NoProblem) {
        return 1;
      } else {
        $this->fhandle = "";
        echo "Error: POP3/Connect: Established port but did not receive standard opening response from server.\n";
        echo "Status: $status, Msg: $msg\n";
        return 0;
      }
      return 1;
    }
  } // END Connect()

  function Disconnect() {
    if ($this->fhandle) {
      if ($this->LoggedOn) {
        $this->Logoff();
      }
      fclose($this->fhandle);
    }
  } // END Disconnect()

  function SendString($message) {
    if ($this->fhandle) {
      fwrite($this->fhandle, $message);
    }
  } // END SendString()

  function GetString() {
    if ($this->fhandle) {
      $retval = fgets($this->fhandle, 65535);
      $retArr = split("\ ", $retval, 2);
    }
    return $retArr;
  } // END GetString()

  function GetDataBlock() {
    $retval = "";
    if ($this->fhandle) {
      $quitflag = false;
      while (!$quitflag) {
        $tmpstr = fgets($this->fhandle, 65535);
        $tmpstr = eregi_replace("\n|\r\n", "", $tmpstr);
        if ($tmpstr == ".") {
          $quitflag = true;
        } else {
          $retval .= "$tmpstr\n";
        }
      }
    }
    return $retval;
  }

  function Logon() {
    if ($this->fhandle) {
      if ($this->LoggedOn) { 
        return 1;				// if we're already logged on, just return
      }
      $this->SendString("user ". $this->pop_uid ."\r\n");
      list($status, $msg) = $this->GetString();
      if ($status == pop3NoProblem) {
        $this->SendString("pass ". $this->pop_pass ."\r\n");
        list($status, $msg) = $this->GetString();
        if ($status == pop3NoProblem) {
          $this->LoggedOn = true;
          return 1;
        } else {
          echo "Error: POP3/Logon: $status, $msg\n";
          return 0;
        }
      } else {
        echo "Error: POP3/Logon: $status, $msg\n";
        return 0;
      }  
    }
  } // END Logon()

  function Logoff() {
    if ($this->LoggedOn) {
      $this->SendString("quit\r\n");
      list($status, $msg) = $this->GetString();
      if ($status == pop3NoProblem) {
        $this->LoggedOn = false;
        return 1;
      } else {
        echo "Error: POP3/Logoff: $status, $msg\n";
        return 0;
      }
    }
  } // END Logoff()

  function GetNumberOfMessages() {
    $tmpArr = Array();
    if ($this->Logon()) {
      $this->SendString("stat\r\n");
      list($status, $msg) = $this->GetString();
      if ($status == pop3NoProblem) {
        $retArr = split("\ ", $msg);
        $tmpArr["messages"] = $retArr[0];
        $tmpArr["mailbox_size"] = $retArr[1];
        return $tmpArr;
      } else {
        echo "Error: POP3/GetNumberOfMessages(): $status, $msg\n";
        return 0;
      }
    } else {
      return 0;
    }
  }  

  function GetHeaders($msgnum) {
    $headArr = Array();
    if ($this->Logon()) {
      $this->SendString("list $msgnum\r\n");
      $val = $this->GetString();
      $sizeArr = split("\ ", $val[1]);
      $headArr["size_of_message"] = trim($sizeArr[1]);
      $this->SendString("top $msgnum 0\r\n");
      $textblock = $this->GetDataBlock();
      $lineArr = split("\n", $textblock);
      for ($t=0; $t<count($lineArr); $t++) {
        if (eregi("^([0-9A-Za-z_]{1,})\:", $lineArr[$t])) {
          $tmpArr = split("\:", $lineArr[$t], 2);
          $tmpArr[0] = strtolower(trim($tmpArr[0]));
          $tmpArr[1] = trim($tmpArr[1]);
          $headArr[$tmpArr[0]] = $tmpArr[1];
        } elseif (eregi("^\ *([0-9A-Za-z_]{1,})", $lineArr[$t])) {
        }
      }
    }
    return $headArr;
  } // END GetHeaders()

  function GetMessageList() {
    $tmpArr = Array();
    if ($this->Logon()) {
      $msgCountArr = $this->GetNumberOfMessages();
      for ($t=0; $t<$msgCountArr["messages"]; $t++) {
        $msgnum = $t+1;
        $headArr = $this->GetHeaders($msgnum);
        $tmpArr[] = $headArr;
      }
    }
    return $tmpArr;
  } // END GetMessageList()

  function ReadMessage($msgnum) {
    if ($this->Logon()) {
      $this->SendString("retr $msgnum\r\n");
      $textblock = $this->GetDataBlock();
      return $textblock;
    }
  }

  function DeleteMessage($msgnum) {
    if ($this->Logon()) {
      $this->SendString("dele $msgnum\r\n");
      $respArr = $this->GetString();
    }
  }

  function FindLine($start_at, $regex, $msgblock) {
    $linepos = -1;
    $posfound = false;
    $curpos = $start_at;
    while (!$posfound) {
      $line = $msgblock[$curpos];
      if ($regex != "") {
        if (eregi($regex, $line)) {
          $linepos = $curpos;
          $posfound = true;
        }
      } else {
        if ($line == "") {
          $linepos = $curpos;
          $posfound = true;
        }
      }
      $curpos++;
      if ($curpos >= count($msgblock)) {
        $posfound = true;
      }
    }
    return $linepos;
  } // END FindLine

  function GetStringBlock($start_line, $end_line, $msgArr) {
    $tmpArr = Array();
    for ($x=$start_line; $x<$end_line; $x++) {
      $tmpArr[] = trim($msgArr[$x]);
    }
    return $tmpArr;
  } // END GetStringBlock

  function AssembleTypeArray($start_line, $end_line, $msgArr, $boundarySTR = "") {
    $typeArr = Array();
    $tmpArr = $this->GetStringBlock($start_line, $end_line, $msgArr);
    for ($x=0; $x<count($tmpArr); $x++) {
      $line = $tmpArr[$x];
      $htArr = split(";", $line);
      for ($jj=0; $jj<count($htArr); $jj++) {
        $item = $htArr[$jj];
        if (eregi("[:=](\ *)", $item)) {
          $tmpArr2 = split("[:=](\ *)", $item, 2);
          $typeArr[strtolower(trim($tmpArr2[0]))] = trim($tmpArr2[1]);
        } elseif (eregi("=\"", $item)) {
          $tmpArr2 = split("=\"", $item, 2);
          $tmpArr2[1] = eregi_replace("\"$", "", $tmpArr2[1]);
          $typeArr[strtolower(trim($tmpArr2[0]))] = trim($tmpArr2[1]);
        }
      }
    }
    if ($typeArr["name"]) {
      $typeArr["name"] = eregi_replace("^\"|\"$", "", $typeArr["name"]);
    }
    if ($typeArr["filename"]) {
      $typeArr["filename"] = eregi_replace("^\"|\"$", "", $typeArr["filename"]);
    }
    if ($typeArr["boundary"]) {
      $typeArr["boundary"] = eregi_replace("\"","",$typeArr["boundary"]);
    } else {
      $typeArr["boundary"] = $boundarySTR;
    }
    if (!$typeArr["boundary"]) {
      $typeArr["boundary"] = pop3FinalBoundary;
    }
    if (!$typeArr["content-type"]) {
      $typeArr["content-type"] = "text/plain";
    }
    return $typeArr;
  } // END AssembleTypeArray

  function GetChunksFromBody($parts, $boundary, $level = 1, $headArr = "") {
    $end_chunk = count($parts);
    $chunkArr = Array();
//    echo "GetChunksFromBody[$level]: Entering: $end_chunk segments, Boundary = $boundary\n";
    for ($i=0; $i<$end_chunk; $i++) {
      $parts[$i] = eregi_replace("^(\n|\r\n*)", "", $parts[$i]);
      $mArr = split("\n", $parts[$i]);
      if (count($mArr) > 0 & $mArr[0] != "--") {
//        echo "GetChunksFromBody[$level]: First Line oF Segment $i: $mArr[0]\n";
        if (eregi("content-type", $mArr[0])) {
//          echo "GetChunksFromBody[$level]: Segment Found\n";
          $head_end = $this->FindLine(0, "", $mArr);
          $headArr = $this->AssembleTypeArray(0, $head_end, $mArr, $boundary);
          $bodyArr = $this->GetStringBlock($head_end + 1, count($mArr), $mArr);
//          echo "GetChunksFromBody[$level]: Content-Type: ". $headArr["content-type"] ."\n";
          if ($headArr["boundary"] != $boundary) { // we've got an embedded segment to explode
//            echo "GetChunksFromBody[$level]: Recursing, new boundary = ". $headArr["boundary"] . "\n";
            $moreparts = explode("--". $headArr["boundary"], join("\n", $bodyArr));
            $extras = $this->GetChunksFromBody($moreparts, $headArr["boundary"], $level+1);
            for ($z=0; $z<count($extras); $z++) {
              $chunkArr[] = $extras[$z];
            }          
          } else {
            $t["headers"] = $headArr;
            $t["body"] = join("\n", $bodyArr);
            $chunkArr[] = $t;
          }
        } else {
          if (!$headArr) { $headArr = $this->AssembleTypeArray(0, 1, $mArr, $boundary); }
          $bodyArr = $this->GetStringBlock(0, count($mArr), $mArr);
          $t["headers"] = $headArr;
          $t["body"] = join("\n", $bodyArr);
          $chunkArr[] = $t;
        }
      } else {
//        echo "GetChunksFromBody[$level]: No data in segment $i\n";
      }
    }
//    echo "GetChunksFromBody[$level]: Leaving\n";
    return $chunkArr;
  }

  function SplitMessage($msgblock) {
    $chunks = Array();
    $msgArr = split("\n", $msgblock);
    $msgArr[] = "--". pop3FinalBoundary."--";

    $first_head_end = $this->FindLine(1, "", $msgArr);
    $hArr = $this->AssembleTypeArray(0, $first_head_end, $msgArr);
    $body = join("\n", $this->GetStringBlock($first_head_end + 1, count($msgArr) -1, $msgArr));

    $parts = explode("--". $hArr["boundary"], $body);

    $chunks = $this->GetChunksFromBody($parts, $hArr["boundary"], 1, $hArr);
    
    return $chunks;
  }

  function AgeInDays($date_received) {
    $dStamp = strtotime($date_received);
    $cStamp = mktime();
    $diff = $this->DateDiff($dStamp, $cStamp);
    return $diff["Days"];
  }

  function SplitSender($sender) {
    $senderParts["name"] = $sender;

    if (($pos = strrpos($sender, "<")) && substr($sender, -1) == ">") {
      $senderParts["name"] = substr($sender, 0, $pos - 1);
      $senderParts["email"] = substr($sender, $pos);
    }

    $senderParts["name"] = eregi_replace("\<|\>", "", $senderParts["name"]);

    $firstChar = substr($senderParts["name"], 0, 1);
    $lastChar = substr($senderParts["name"], -1);
    if ($firstChar == "\"" || $firstChar == "'") $senderParts["name"] = substr($senderParts["name"], 1);
    if ($lastChar == "\"" || $lastChar == "'") $senderParts["name"] = substr($senderParts["name"], 0, -1);

    return $senderParts;
  }

  function HTMLFormatSender($sender) {
    $sender = eregi_replace("\"", "", $sender);
    $sender = eregi_replace("\<", "&lt;", $sender);
    $sender = eregi_replace("\>", "&gt;", $sender);
    return $sender;
  }

} // END pop3
Return current item: POP3 Message Handler for PHP