Hier kommt mal wieder ein Artikel der etwas länger, aber vielleicht auch etwas informativer, als die letzten wird.
Dieses mal geht es um eine Möglichkeit via fsockopen in PHP ein IMAP-Postfach auszulesen. Normaler weise gibt es dafür in PHP schon eine Extension, jedoch ist diese nicht überall aktiviert, daher kann man diese Technik nicht sehr gut nutzen, wenn man ein Programm/Skript, schreiben möchte, welches auf möglichst vielen Server läuft.
fsockopen ist zwar auch bei vielen Free Webhostern ausgeschaltet, da mit dieser Funktion viel “Schaden” angerichtet werden kann, jedoch hat man bei Pytal.de zum Beispiel die Möglichkeit, durch eine Bestätigte Mitgliedschaft fsockopen nutzen zu können.
Naja lange genug um den heißen Brei geredet, was habe ich also gemacht?
Ganz einfach, ich habe es mir einige Stunden vorm PC gemütlich gemacht, während sich @Pfirsichwolke immer mehr langweilte.
Nach ziemlich viel gegoogle, ausprobieren und fragen im Pytalchat, habe ich jetzt endlich eine naja zugegeben schlechte, aber trotzdem Funktionierenden IMAP-Klasse geschrieben.
Der Code dazu kommt hier:
// +———————————————————————-+
// | Copyright (c) 2010 DasLampe |
// | Encoding: UTF-8 |
// +———————————————————————-+
class IMAP
{
var $sock;
var $host;
var $port;
var $sid;
var $tag;
var $_lastTag;
var $currentMailbox;
function __construct()
{
$this->sock = null;
$this->host = “localhost”;
$this->port = “143″;
$this->sid = “”;
$this->tag = 0;
$this->_lastTag = $this->tag;
$this->currentMailbox = “”;
}
function __destruct()
{
fwrite($this->sock, “A000″.$this->getTag().” LOGOUT\r\n”);
}
function connect($host=”", $port=”", $ssl=false)
{
$this->host = $host;
$this->port = $port;
if($ssl == true)
{
$this->host = “ssl://”.$host;
}
$this->sock = fsockopen($this->host, $this->port, $errno, $errstr);
if(!$this->_assumedNextLine(‘* OK’))
{
echo ‘FAIL CONNECT’;
}
}
function getTag()
{
$this->tag = $this->tag +1;
$this->_lastTag = “A000″.$this->tag;
return $this->tag;
}
function login($username, $pass)
{
fwrite($this->sock, “A000″.$this->getTag().” LOGIN “.$username.” “.$pass.”\r\n”);
if(!$this->_assumedNextLine($this->_lastTag))
{
}
}
function selectMailBox($mailbox)
{
fwrite($this->sock, “A000″.$this->getTag().” SELECT “.$mailbox.”\r\n”);
$this->currentMailbox = $mailbox;
$this->readResponse($this->_lastTag);
}
function countMessages()
{
fwrite($this->sock, “A000″.$this->getTag().” SEARCH ALL\r\n”);
$response = $this->readResponse($this->_lastTag);
foreach($response as $id)
{
if($id[0] == “S”)
{
$count = count_chars($id, 1);
}
}
return $count[32];
}
public function getSubject($msgId)
{
if(empty($msgId))
{
return false;
}
$this->fetch($msgId.” BODY[HEADER.FIELDS (subject)]“);
$array = array();
while(!$this->readLine($tokens, $this->_lastTag))
{
if(!empty($tokens) && preg_match(“/FETCH/”, $tokens))
{
$msgId = preg_split(“/ /”, $tokens, 2);
$msgId = $msgId[0];
}
if(!empty($tokens) && !preg_match(“/FETCH/”, $tokens))
{
$array[] = array(“id” => $msgId,
“subject” => $tokens);
}
}
return mb_decode_mimeheader($array[0]['subject']);
}
public function getMsgText($msgId=”")
{
if(empty($msgId))
{
return false;
}
$this->fetch($msgId.” BODY[TEXT]“);
$array = array();
$array[] = “=?ISO-8859-1?Q?”;
while(!$this->readLine($tokens, $this->_lastTag, $tag))
{
$array[] .= $tag.’ ‘.$tokens;
}
//Löschen der 1. und letzten Response
unset($array[1]); //FETCH
unset($array[count($array)]); //Klammer
$array = array_values($array);
//Array2String
$array = implode(”, $array);
//Decodieren und Zeilenumbrüche setzten
return nl2br(mb_decode_mimeheader($array));
}
public function getFromOrTo($msgId=”", $fromOrTo=”")
{
if(empty($msgId) || empty($fromOrTo))
{
return false;
}
$this->fetch($msgId.” BODY[HEADER.FIElDS (".$fromOrTo.")]“);
while(!$this->readLine($tokens, $this->_lastTag))
{
if(!isset($return) && !preg_match(‘/FETCH/’, $tokens))
{
$return = htmlspecialchars($tokens);
}
}
return mb_decode_mimeheader($return);
}
private function fetch($command, $param=false)
{
if(!$param)
{
fwrite($this->sock, “A000″.$this->getTag().” FETCH “.$command.”\r\n”);
}
else
{
fwrite($this->sock, “A000″.$this->getTag().” FETCH “.$command.” “.$param.”\r\n”);
}
}
function _nextLine()
{
$line = @fgets($this->sock);
if ($line === false)
{
echo ‘FAIL!!’;
return false;
}
return $line;
}
protected function _assumedNextLine($start)
{
$line = $this->_nextLine();
return strpos($line, $start) === 0;
}
public function readLine(&$tokens = array(), $wantedTag = ‘*’, &$tag=”")
{
$line = $this->_nextTaggedLine($tag);
$tokens = $line;
$tag = $tag;
if(($tag == “A000″.$this->tag) || ($tag == $wantedTag))
{
return $tag;
}
}
public function readResponse($tag=”*”)
{
if($tag == “lastTag”)
{
$tag = $this->_lastTag;
}
$lines = array();
while (!$this->readLine($tokens, $tag)) {
$lines[] = $tokens;
}
return $lines;
}
protected function _nextTaggedLine(&$tag)
{
$line = $this->_nextLine();
// seperate tag from line
@list($tag, $line) = explode(‘ ‘, $line, 2);
return $line;
}
}
Vielleicht kann diese Klasse ja jemanden Helfen, der ein ähnliches Problem hat, ich würde mich dann auf jeden Fall über ein Kommentar freuen.
Ich muss dazu sagen, das ich bei meiner Suche natürlich auch auf andere Klassen gestoßen bin, welche bei mir jedoch alle nicht Problemlos liefen. Dazu kommt, das ich natürlich gerne weiß, was mein Programm macht und ich in den Ferien auch Zeit dafür habe, so etwas selbst zu schreiben.
Kleiner Tipp noch am Rande, wer plant auch einige eigene Klasse zu schreiben, dem kann Wireshark echt gut helfen!
Ich hatte zum Beispiel das Problem, das schon die 2. Anfrage gesendet wurde, bevor die 1. Anfrage zurück kam, trotz eines sleep(2), solche Fehler kann man eher schlecht aus einer Protokolldokumentation entnehmen.
Achja, hier noch die Klassen, die ich so ausprobiert habe und von welchen Einflüsse in meinem Code sind:
Zend Mail aus dem Zend Framework + diese Anleitung von PHP Gangsta
Net_IMAP aus der PEAR Bibliothek.