plain); unset($this->header); unset($this->body); unset($this->content_type); unset($this->content_subtype); unset($this->content_param); unset($this->content_encoding); unset($this->content_disposition); unset($this->content_sub_disposition); unset($this->to); unset($this->from); unset($this->msgid); unset($this->datetime); unset($this->subject); $this->plain = $plain; } function analyze($plain) { // // Header 及び body の分離 // if($plain!='') { $this->plain = $plain; } $ex = explode( "\r\n\r\n" , $this->plain , 2 ); $header_temp = $ex[0]; $body_temp = $ex[1]; // // マルチラインヘッダーの正規化 // $header_array = explode( "\n" , $header_temp ); $this->header = ''; foreach( $header_array as $hl ) { $matches = array(); if( preg_match("/^((?:\s|\t)+)(.*)/",$hl,$matches )==True ) { $this->header .= trim($matches[2]); } else { $this->header .= "\n".trim($hl); } } $this->header .= "\n"; $this->body = $body_temp; // // Content-Type: のチェック // if( preg_match("/[\^\n]content-type: (\S+)\/(\S+)\s*;\s*(.*)/i",$this->header,$match)==True ) { $this->content_type = $match[1]; $this->content_subtype = $match[2]; $this->content_param = $match[3]; } // // Content-Transfer-Encoding: のチェック // if( preg_match("/[\^\n]content-transfer-encoding: (\S+)/i",$this->header,$match)==True ) { $this->content_encoding = $match[1]; //echo $this->content_encoding."/ "; } // Content-Disposition: のチェック if( preg_match("/[\^\n]content-disposition: (\w+)\s*;\s*(.+)/i",$this->header,$match)==True ) { $this->content_disposition = $match[1]; $this->content_sub_disposition = $match[2]; } // // To: のチェック // if( preg_match("/[\^\n]to:\s+<([\w\.\-]+@[\w\.\-]+)>/i",$this->header,$match)==True ) { $this->to = $match[1]; } else if( preg_match("/[\^\n]to:\s+([\w\.\-]+@[\w\.\-]+)/i",$this->header,$match)==True ) { $this->to = $match[1]; } // // From: のチェック // if( preg_match("/[\^\n]from:\s+.*<([\w\.\-]+@[\w\.\-]+)>/i",$this->header,$match)==True ) { $this->from = $match[1]; } else if( preg_match("/[\^\n]from:\s+([\w\.\-]+@[\w\.\-]+)/i",$this->header,$match)==True ) { $this->from = $match[1]; } // // Message-Id: のチェック // if( preg_match("/[\^\n]message-id:[ \t]*([^\r\n]+)/i",$this->header,$match)==True ) { $this->msgid = $match[1]; } // 日付の抽出 $this->datetime = -1; if( preg_match("/[\^\n]date:[ \t]*([^\r\n]+)/i",$this->header,$match)==True ) { $this->datetime = strtotime($match[1]); } if ($this->datetime == -1) { $this->datetime = time(); } // サブジェクトの抽出 if (eregi("\nSubject:[ \t]*([^\r\n]+)", $this->header, $subreg)) { // =?iso-2022-jp〜 をデコードする $this->subject = $this->text_decode($subreg[1]); } // // Multipartチェック(RFC2046) // (再帰呼び出し) // $content = strtolower($this->content_type) . "/" . strtolower($this->content_subtype); //echo $content . "/ \n"; if( $content=="multipart/mixed" || $content=="multipart/alternative" || $content=="multipart/parallel" || $content=="multipart/digest" ) { if( preg_match('/boundary="([^"]+)"/i' , $this->content_param , $match ) ) { $boundary = '--'.$match[1]; } else { return FALSE; } // echo "(!) Boundary => (" . $boundary . ")\n"; $bounding_array = explode( $boundary , $this->body ); $result = array(); foreach( $bounding_array as $id => $bounding_body ) { if( $id==0 ) continue; if( preg_match('/^--/',$bounding_body) ) { break; } $bbody = new popmail_parse($bounding_body); $r = $bbody->analyze(); if($r!=FALSE) { foreach( $r as $key => $data ) { $result[] = $data; } } } return $result; } // // BASE64 / uuencode // if( $this->content_encoding=="base64" ) { $data = base64_decode($this->body); } else if( $this->content_encoding=="quoted-printable" ) { $data = quoted_printable_decode($this->body); } else { $data = $this->body; } if($content=="text/plain") { if(function_exists('mb_convert_encoding')) { // テキストを変換する $data = mb_convert_encoding($data, SOURCE_ENCODING, "auto"); } } $filename = ''; if( preg_match("/name\=\"(.+)\"/i",$this->content_param,$match)==True ) { // Content-Type: にname指定あり $filename = $match[1]; } if( isset($this->content_sub_disposition) && preg_match("/filename\=\"(.+)\"/i",$this->content_sub_disposition,$match)==True ) { // こちらがContent-Typeの指定より優先される // Content-Disposition: にfilename指定あり $filename = $match[1]; } // ファイル名を変換する $filename = $this->text_decode($filename); $result[] = array("Content-Type" => $content , "Body" => $data , "Filename" => $filename); return $result; } function to() { return $this->to; } function from() { return $this->from; } function msgid() { return $this->msgid; } function datetime() { return strftime("%Y/%m/%d %H:%M:%S",$this->datetime); } function date() { return strftime("%Y-%m-%d",$this->datetime); } function body() { return $this->body; } function header() { return $this->header; } function subject() { return $this->subject; } function content_type() { return $this->content_type."/".$this->content_subtype; } function text_decode($str) { //MIME Bデコ−ド while (eregi("(.*)=\?iso-2022-jp\?B\?([^\?]+)\?=(.*)",$str,$regs)) { $str = $regs[1].base64_decode($regs[2]).$regs[3]; } //MIME Qデコ−ド while (eregi("(.*)=\?iso-2022-jp\?Q\?([^\?]+)\?=(.*)",$str,$regs)) { $str = $regs[1].quoted_printable_decode($regs[2]).$regs[3]; } if(function_exists('mb_convert_encoding')) { $str = mb_convert_encoding($str, SOURCE_ENCODING, "auto"); } return htmlspecialchars($str); } } ///////////////////////////////////////////////// // POPメール受信処理 class popmail_pop3_protocol { var $sock; var $mailnum, $totalsize; var $uid, $break_flg; function popmail_pop3_protocol() { unset($this->sock); unset($this->mailnum); unset($this->totalsize); } ////////////////////////////////////////////////////////// // POP3接続を開始して受信メール件数とサイズを得る function connect($server,$pop_port,$timeout,$user,$pass,$apop) { // POP3接続開始 $this->sock = fsockopen($server, $pop_port, $err, $errno, $timeout); if($this->sock!=FALSE) { $buf = fgets($this->sock, 512); if(substr($buf, 0, 3) != '+OK') { die($buf); // サーバ接続エラー } if($apop==0) { // クリアテキスト認証 $buf = $this->_sendcmd($this->sock,"USER $user"); $buf = $this->_sendcmd($this->sock,"PASS $pass"); } else { // APOPを使用する if( preg_match("/^\+OK\s+.*(<+.*>)/",$buf,$match)==True ) { $apop = md5($match[1].$pass); $buf = $this->_sendcmd($this->sock,"APOP $user $apop"); } } // 受信済みメールの件数とサイズを得る $buf = $this->_sendcmd($this->sock,"STAT"); sscanf($buf, '+OK %d %d',$this->mailnum,$this->totalsize); } return $this->sock; } ////////////////////////////////////////////////////////// // POP3接続を終了する function disconnect() { $buf = $this->_sendcmd($this->sock,"QUIT"); fclose($this->sock); } ////////////////////////////////////////////////////////// // 指定番号のメールを受信する function get_mail($num,$maxsize,$rcvline) { //UIDL n -n番目のUID取得 $buf = $this->_sendcmd($this->sock,"UIDL $num"); sscanf($buf, '+OK %d %s',$dummy,$this->uid); //LIST n -n番目のサイズ取得(ヘッダ含) $buf = $this->_sendcmd($this->sock,"LIST $num"); sscanf($buf, '+OK %d %ld',$dummy,$size); if($maxsize>0 && $size>$maxsize) { // 受信サイズ制限にかかった $buf = $this->_sendcmd($this->sock,"TOP $num ".$rcvline); } else { //RETR n -n番目のメッセージ取得(ヘッダ含) $buf = $this->_sendcmd($this->sock,"RETR $num"); } $data = ''; while (!ereg("^\.\r\n",$buf)) { //EOFの.まで読む $buf = fgets($this->sock,512); $data.= $buf; } // 取得したメールデータの検証 $mail_len = strlen($data) - 3; // LISTで取得したサイズと実際の受信データのサイズを比較 $this->break_flg = 0; if($mail_len != $size) { // TOPコマンド受信で全て受信できていない $this->break_flg = 1; } return $data; } ////////////////////////////////////////////////////////// // 指定番号のメールを消去する function delete_mail($num) { //DELE n n番目のメッセージ削除 $buf = $this->_sendcmd($this->sock,"DELE $num"); } ////////////////////////////////////////////////////////// // 最後に取得したメールのUIDを得る function get_uid() { return $this->uid; } ////////////////////////////////////////////////////////// // 受信件数を返す function get_mailnum() { return $this->mailnum; } ////////////////////////////////////////////////////////// // 全受信メールのサイズを返す function get_totalsize() { return $this->totalsize; } ////////////////////////////////////////////////////////// // 新着メールの確認(0..新着メールなし) function check_newmail($last_uid) { $num = $this->mailnum; // 受信しているメール数 $newnum = 1; while($num>0) { //UIDL n -n番目のUID取得 $buf = $this->_sendcmd($this->sock,"UIDL $num"); sscanf($buf, '+OK %d %s',$dummy,$check); if(strcmp($check,$last_uid)==0) { // 最後に受信したメールを見つけた if($num==$this->mailnum) { // 新着メールなし $newnum = 0; } else { $newnum = $num + 1; } break; } $num--; } // 一致しなければ、全てが新着メール return $newnum; } ////////////////////////////////////////////////////////// // 最後に受信したメールのUIDを得る function get_lastuid($file) { if(file_exists($file)) { $fp = fopen($file, 'r') or die('popmail.lib.php : cannot open '.$file); $last_uid = rtrim(fgets($fp,256)); // ファイルを閉じる fclose($fp); } else { $last_uid = ''; } return $last_uid; } ////////////////////////////////////////////////////////// // 最後に受信したメールのUIDを保存する function set_lastuid($file) { $fp = fopen($file, 'w') or die('popmail.lib.php : cannot write '.$file); set_file_buffer($fp, 0); flock($fp,LOCK_EX); rewind($fp); ftruncate($fp,0); fputs($fp,$this->uid); flock($fp,LOCK_UN); fclose($fp); } ////////////////////////////////////////////////////////// // 最後に受信したメールが破損しているかどうか function is_broken() { return $this->break_flg; } ////////////////////////////////////////////////////////// // (内部関数) // POP3コマンド送信 function _sendcmd($sock,$cmd) { fputs($sock, $cmd."\r\n"); $buf = fgets($sock, 512); if(substr($buf, 0, 3) == '+OK') { return $buf; } else { die($cmd." >> ".$buf); } } } ?>