2013-09-30 15 views
12

私はPOP3メールボックスから電子メールを取得し、そのデータをMySQLデータベースに挿入するためにPHPのimap関数を使用しています。ここでphp imap - 本文を取得してプレーンテキストを作成

は、PHPのコードです:

$inbox = imap_open($hostname,$username,$password) or die('Cannot connect: ' . imap_last_error()); 

$emails = imap_search($inbox,'ALL'); 


if($emails) 
{ 
    $output = ''; 

    rsort($emails); 

    foreach($emails as $email_number) 
    { 
     $header=imap_headerinfo($inbox,$email_number); 

     $from = $header->from[0]->mailbox . "@" . $header->from[0]->host; 
     $toaddress=$header->toaddress; 
     $replyto=$header->reply_to[0]->mailbox."@".$header->reply_to[0]->host; 
     $datetime=date("Y-m-d H:i:s",$header->udate); 
     $subject=$header->subject; 

     //remove the " from the $toaddress 
     $toaddress = str_replace('"','',$toaddress); 

     echo '<strong>To:</strong> '.$toaddress.'<br>'; 
     echo '<strong>From:</strong> '.$from.'<br>'; 
     echo '<strong>Subject:</strong> '.$subject.'<br>'; 

     //get message body 
     $message = (imap_fetchbody($inbox,$email_number,1.1)); 
     if($message == '') 
     { 
      $message = (imap_fetchbody($inbox,$email_number,1)); 
     } 
} 

それは私が単語、または単語の間で=20間で=を取得しかし、体内のいくつかのメールに、正常に動作します。また、送信時に空白ではなくても、電子メールは空白になります。

これは特定のメールから来た場合にのみ発生します。

どうすればいいですか?メールを完全に平文にするにはどうすればよいですか?

+0

オプションを 'FT_INTERNAL'に設定しようとしましたか? http://php.net/manual/en/function.imap-fetchbody.php –

答えて

23

これは、電子メールが通常Quoted-printableにエンコードされているために発生します。 =はソフトな改行で、=20は空白です。私は、メッセージにquoted_printable_decode()を使って正しく表示できると思います。空白の電子メールについてはわかりませんが、詳細が必要です。

基本的に

//get message body 
$message = quoted_printable_decode(imap_fetchbody($inbox,$email_number,1.1)); 
+2

この関数は、 'boundary = 1asa8238asd'が同じフォーマットをしているので、以前はMIME境界ヘッダーを混乱させていたので注意してください(' = 1a')を引用符で囲んだ印字可能な符号化文字とする。 –

3

空白の電子メールについては、メールのエンコーディングを確認してください。

バイナリでエンコードされたメールの場合、それらをmysqlテキストフィールドに挿入しようとすると空白のメールが表示されます。

(、)、)、 "UTF-8"、$のmail_contentを真(mb_detect_encodingの$ mail_content、mb_detect_order()UTF-8にすべてのメールをシフトしてみた後、

のiconvを、それを挿入します。

4
$data = imap_fetchbody($this->imapStream, $Part->uid, $Part->path, FT_UID | FT_PEEK); 
if ($Part->format === 'quoted-printable' && $data) { 
    $data = quoted_printable_decode($data); 
} 

これは

コンテンツ転送エンコードでメールに必要とされる:8ビット

:quoted-printableの

しかし

コンテンツ転送エンコーディングとのメールの

単純にimap_fetchbodyで十分です。

上記のコードは、IMAPからメールボックスからメールを取得するために作成されたcake-phpコンポーネントから取得されたものです。

5

私は数年前にクラス全体を作りましたが、私は電子メールからコンテンツを取得する必要があるときにまだ使用しています。読み込み可能な形式ですべての電子メール本文(HTMLやプレーンテキストを持つことがあります)を取得し、添付ファイルをすべて取得し、どこかに保存するか、Webサイトユーザーに送信するだけです。

これは本当に最適化されていないので、大きなメールボックスでは問題が発生する可能性があります。このクラスの目的は、ウェブサイトのウィジェットにそれらを置くために読める形式で電子メールにアクセスすることでした。以下のサンプルを試してみましょう。

ImapReader.class.phpここにソースコードがあります。

<?php 

class ImapReader 
{ 

    private $host; 
    private $port; 
    private $user; 
    private $pass; 
    private $box; 
    private $box_list; 
    private $errors; 
    private $connected; 
    private $list; 
    private $deleted; 

    const FROM = 0; 
    const TO = 1; 
    const REPLY_TO = 2; 
    const SUBJECT = 3; 
    const CONTENT = 4; 
    const ATTACHMENT = 5; 

    public function __construct($host = null, $port = '143', $user = null, $pass = null) 
    { 
     $this->host = $host; 
     $this->port = $port; 
     $this->user = $user; 
     $this->pass = $pass; 
     $this->box = null; 
     $this->box_list = null; 
     $this->errors = array(); 
     $this->connected = false; 
     $this->list = null; 
     $this->deleted = false; 
    } 

    public function __destruct() 
    { 
     if ($this->isConnected()) 
     { 
      $this->disconnect(); 
     } 
    } 

    public function changeServer($host = null, $port = '143', $user = null, $pass = null) 
    { 
     if ($this->isConnected()) 
     { 
      $this->disconnect(); 
     } 
     $this->host = $host; 
     $this->port = $port; 
     $this->user = $user; 
     $this->pass = $pass; 
     $this->box_list = null; 
     $this->errors = array(); 
     $this->list = null; 
     return $this; 
    } 

    public function canConnect() 
    { 
     return (($this->connected == false) && (is_string($this->host)) && (!empty($this->host)) 
      && (is_numeric($this->port)) && ($this->port >= 1) && ($this->port <= 65535) 
      && (is_string($this->user)) && (!empty($this->user)) && (is_string($this->pass)) && (!empty($this->pass))); 
    } 

    public function connect() 
    { 
     if ($this->canConnect()) 
     { 
      $this->box = @imap_open("{{$this->host}:{$this->port}/imap/ssl/novalidate-cert}INBOX", $this->user, 
        $this->pass); 
      if ($this->box !== false) 
      { 
       $this->_connected(); 
      } 
      else 
      { 
       $this->errors = array_merge($this->errors, imap_errors()); 
      } 
     } 
     return $this; 
    } 

    public function boxList() 
    { 
     if (is_null($this->box_list)) 
     { 
      $list = imap_getsubscribed($this->box, "{{$this->host}:{$this->port}}", "*"); 
      $this->box_list = array(); 
      foreach ($list as $box) 
      { 
       $this->box_list[] = $box->name; 
      } 
     } 
     return $this->box_list; 
    } 

    public function fetchAllHeaders($mbox) 
    { 
     if ($this->isConnected()) 
     { 
      $test = imap_reopen($this->box, "{$mbox}"); 
      if (!$test) 
      { 
       return false; 
      } 
      $num_msgs = imap_num_msg($this->box); 
      $this->list = array(); 
      for ($id = 1; ($id <= $num_msgs); $id++) 
      { 
       $this->list[] = $this->_fetchHeader($mbox, $id); 
      } 
      return true; 
     } 
     return false; 
    } 

    public function fetchSearchHeaders($mbox, $criteria) 
    { 
     if ($this->isConnected()) 
     { 
      $test = imap_reopen($this->box, "{$mbox}"); 
      if (!$test) 
      { 
       return false; 
      } 
      $msgs = imap_search($this->box, $criteria); 
      if ($msgs) 
      { 
       foreach ($msgs as $id) 
       { 
        $this->list[] = $this->_fetchHeader($mbox, $id); 
       } 
      } 
      return true; 
     } 
     return false; 
    } 

    public function isConnected() 
    { 
     return $this->connected; 
    } 

    public function disconnect() 
    { 
     if ($this->connected) 
     { 
      if ($this->deleted) 
      { 
       imap_expunge($this->box); 
       $this->deleted = false; 
      } 
      imap_close($this->box); 
      $this->connected = false; 
      $this->box = null; 
     } 
     return $this; 
    } 

    /** 
    * Took from khigashi dot oang at gmail dot com at php.net 
    * with replacement of ereg family functions by preg's ones. 
    * 
    * @param string $str 
    * @return string 
    */ 
    private function _fix($str) 
    { 
     if (preg_match("/=\?.{0,}\?[Bb]\?/", $str)) 
     { 
      $str = preg_split("/=\?.{0,}\?[Bb]\?/", $str); 
      while (list($key, $value) = each($str)) 
      { 
       if (preg_match("/\?=/", $value)) 
       { 
        $arrTemp = preg_split("/\?=/", $value); 
        $arrTemp[0] = base64_decode($arrTemp[0]); 
        $str[$key] = join("", $arrTemp); 
       } 
      } 
      $str = join("", $str); 
     } 

     if (preg_match("/=\?.{0,}\?Q\?/", $str)) 
     { 
      $str = quoted_printable_decode($str); 
      $str = preg_replace("/=\?.{0,}\?[Qq]\?/", "", $str); 
      $str = preg_replace("/\?=/", "", $str); 
     } 
     return trim($str); 
    } 

    private function _connected() 
    { 
     $this->connected = true; 
     return $this; 
    } 

    public function getErrors() 
    { 
     $errors = $this->errors; 
     $this->errors = array(); 
     return $errors; 
    } 

    public function count() 
    { 
     if (is_null($this->list)) 
     { 
      return 0; 
     } 
     return count($this->list); 
    } 

    public function get($nbr = null) 
    { 
     if (is_null($nbr)) 
     { 
      return $this->list; 
     } 
     if ((is_array($this->list)) && (isset($this->list[$nbr]))) 
     { 
      return $this->list[$nbr]; 
     } 
     return null; 
    } 

    public function fetch($nbr = null) 
    { 
     return $this->_callById('_fetch', $nbr); 
    } 

    private function _fetchHeader($mbox, $id) 
    { 
     $header = imap_header($this->box, $id); 
     if (!is_object($header)) 
     { 
      continue; 
     } 
     $mail = new stdClass(); 
     $mail->id = $id; 
     $mail->mbox = $mbox; 
     $mail->timestamp = (isset($header->udate)) ? ($header->udate) : (''); 
     $mail->date = date("d/m/Y H:i:s", (isset($header->udate)) ? ($header->udate) : ('')); 
     $mail->from = $this->_fix(isset($header->fromaddress) ? ($header->fromaddress) : ('')); 
     $mail->to = $this->_fix(isset($header->toaddress) ? ($header->toaddress) : ('')); 
     $mail->reply_to = $this->_fix(isset($header->reply_toaddress) ? ($header->reply_toaddress) : ('')); 
     $mail->subject = $this->_fix(isset($header->subject) ? ($header->subject) : ('')); 
     $mail->content = array(); 
     $mail->attachments = array(); 
     $mail->deleted = false; 
     return $mail; 
    } 

    private function _fetch($mail) 
    { 
     $test = imap_reopen($this->box, "{$mail->mbox}"); 
     if (!$test) 
     { 
      return $mail; 
     } 
     $structure = imap_fetchstructure($this->box, $mail->id); 
     if ((!isset($structure->parts)) || (!is_array($structure->parts))) 
     { 
      $body = imap_body($this->box, $mail->id); 
      $content = new stdClass(); 
      $content->type = 'content'; 
      $content->mime = $this->_fetchType($structure); 
      $content->charset = $this->_fetchParameter($structure->parameters, 'charset'); 
      $content->data = $this->_decode($body, $structure->type); 
      $content->size = strlen($content->data); 
      $mail->content[] = $content; 
      return $mail; 
     } 
     else 
     { 
      $parts = $this->_fetchPartsStructureRoot($mail, $structure); 
      foreach ($parts as $part) 
      { 
       $content = new stdClass(); 
       $content->type = null; 
       $content->data = null; 
       $content->mime = $this->_fetchType($part->data); 
       if ((isset($part->data->disposition)) 
        && ((strcmp('attachment', $part->data->disposition) == 0) 
        || (strcmp('inline', $part->data->disposition) == 0))) 
       { 
        $content->type = $part->data->disposition; 
        $content->name = null; 
        if (isset($part->data->dparameters)) 
        { 
         $content->name = $this->_fetchParameter($part->data->dparameters, 'filename'); 
        } 
        if (is_null($content->name)) 
        { 
         if (isset($part->data->parameters)) 
         { 
          $content->name = $this->_fetchParameter($part->data->parameters, 'name'); 
         } 
        } 
        $mail->attachments[] = $content; 
       } 
       else if ($part->data->type == 0) 
       { 
        $content->type = 'content'; 
        $content->charset = null; 
        if (isset($part->data->parameters)) 
        { 
         $content->charset = $this->_fetchParameter($part->data->parameters, 'charset'); 
        } 
        $mail->content[] = $content; 
       } 
       $body = imap_fetchbody($this->box, $mail->id, $part->no); 
       if (isset($part->data->encoding)) 
       { 
        $content->data = $this->_decode($body, $part->data->encoding); 
       } 
       else 
       { 
        $content->data = $body; 
       } 
       $content->size = strlen($content->data); 
      } 
     } 
     return $mail; 
    } 

    private function _fetchPartsStructureRoot($mail, $structure) 
    { 
     $parts = array(); 
     if ((isset($structure->parts)) && (is_array($structure->parts)) && (count($structure->parts) > 0)) 
     { 
      foreach ($structure->parts as $key => $data) 
      { 
       $this->_fetchPartsStructure($mail, $data, ($key + 1), $parts); 
      } 
     } 
     return $parts; 
    } 

    private function _fetchPartsStructure($mail, $structure, $prefix, &$parts) 
    { 
     if ((isset($structure->parts)) && (is_array($structure->parts)) && (count($structure->parts) > 0)) 
     { 
      foreach ($structure->parts as $key => $data) 
      { 
       $this->_fetchPartsStructure($mail, $data, $prefix . "." . ($key + 1), $parts); 
      } 
     } 

     $part = new stdClass; 
     $part->no = $prefix; 
     $part->data = $structure; 

     $parts[] = $part; 
    } 

    private function _fetchParameter($parameters, $key) 
    { 
     foreach ($parameters as $parameter) 
     { 
      if (strcmp($key, $parameter->attribute) == 0) 
      { 
       return $parameter->value; 
      } 
     } 
     return null; 
    } 

    private function _fetchType($structure) 
    { 
     $primary_mime_type = array ("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "OTHER"); 
     if ((isset($structure->subtype)) && ($structure->subtype) && (isset($structure->type))) 
     { 
      return $primary_mime_type[(int) $structure->type] . '/' . $structure->subtype; 
     } 
     return "TEXT/PLAIN"; 
    } 

    private function _decode($message, $coding) 
    { 
     switch ($coding) 
     { 
      case 2: 
       $message = imap_binary($message); 
       break; 
      case 3: 
       $message = imap_base64($message); 
       break; 
      case 4: 
       $message = imap_qprint($message); 
       break; 
      case 5: 
       break; 
      default: 
       break; 
     } 
     return $message; 
    } 

    private function _callById($method, $data) 
    { 
     $callback = array ($this, $method); 

     // data is null 
     if (is_null($data)) 
     { 
      $result = array(); 
      foreach ($this->list as $mail) 
      { 
       $result[] = $this->_callById($method, $mail); 
      } 
      return $result; 
     } 

     // data is an array 
     if (is_array($data)) 
     { 
      $result = array(); 
      foreach ($data as $elem) 
      { 
       $result[] = $this->_callById($method, $elem); 
      } 
      return $result; 
     } 

     // data is an object 
     if ((is_object($data)) && ($data instanceof stdClass) && (isset($data->id))) 
     { 
      return call_user_func($callback, $data); 
     } 

     // data is numeric 
     if (($this->isConnected()) && (is_array($this->list)) && (is_numeric($data))) 
     { 
      foreach ($this->list as $mail) 
      { 
       if ($mail->id == $data) 
       { 
        return call_user_func($callback, $mail); 
       } 
      } 
     } 

     return null; 
    } 

    public function delete($nbr) 
    { 
     $this->_callById('_delete', $nbr); 
     return; 
    } 

    private function _delete($mail) 
    { 
     if ($mail->deleted == false) 
     { 
      $test = imap_reopen($this->box, "{$mail->mbox}"); 
      if ($test) 
      { 
       $this->deleted = true; 
       imap_delete($this->box, $mail->id); 
       $mail->deleted = true; 
      } 
     } 
    } 

    public function searchBy($pattern, $type) 
    { 
     $result = array(); 
     if (is_array($this->list)) 
     { 
      foreach ($this->list as $mail) 
      { 
       $match = false; 
       switch ($type) 
       { 
        case self::FROM: 
         $match = $this->_match($mail->from, $pattern); 
         break; 
        case self::TO: 
         $match = $this->_match($mail->to, $pattern); 
         break; 
        case self::REPLY_TO: 
         $match = $this->_match($mail->reply_to, $pattern); 
         break; 
        case self::SUBJECT: 
         $match = $this->_match($mail->subject, $pattern); 
         break; 
        case self::CONTENT: 
         foreach ($mail->content as $content) 
         { 
          $match = $this->_match($content->data, $pattern); 
          if ($match) 
          { 
           break; 
          } 
         } 
         break; 
        case self::ATTACHMENT: 
         foreach ($mail->attachments as $attachment) 
         { 
          $match = $this->_match($attachment->name, $pattern); 
          if ($match) 
          { 
           break; 
          } 
         } 
         break; 
       } 
       if ($match) 
       { 
        $result[] = $mail; 
       } 
      } 
     } 
     return $result; 
    } 

    private function _nmatch($string, $pattern, $a, $b) 
    { 
     if ((!isset($string[$a])) && (!isset($pattern[$b]))) 
     { 
      return 1; 
     } 

     if ((isset($pattern[$b])) && ($pattern[$b] == '*')) 
     { 
      if (isset($string[$a])) 
      { 
       return ($this->_nmatch($string, $pattern, ($a + 1), $b) + $this->_nmatch($string, $pattern, $a, ($b + 1))); 
      } 
      else 
      { 
       return ($this->_nmatch($string, $pattern, $a, ($b + 1))); 
      } 
     } 

     if ((isset($string[$a])) && (isset($pattern[$b])) && ($pattern[$b] == '?')) 
     { 
      return ($this->_nmatch($string, $pattern, ($a + 1), ($b + 1))); 
     } 

     if ((isset($string[$a])) && (isset($pattern[$b])) && ($pattern[$b] == '\\')) 
     { 
      if ((isset($pattern[($b + 1)])) && ($string[$a] == $pattern[($b + 1)])) 
      { 
       return ($this->_nmatch($string, $pattern, ($a + 1), ($b + 2))); 
      } 
     } 

     if ((isset($string[$a])) && (isset($pattern[$b])) && ($string[$a] == $pattern[$b])) 
     { 
      return ($this->_nmatch($string, $pattern, ($a + 1), ($b + 1))); 
     } 

     return 0; 
    } 

    private function _match($string, $pattern) 
    { 
     return $this->_nmatch($string, $pattern, 0, 0); 
    } 

} 

ImapReader.demo.phpは、ここでの使用サンプル

<?php 

require_once("ImapReader.class.php"); 

$box = new ImapReader('example.com', '143', '[email protected]', 'xxxxxxxxxxxx'); 
$box 
    ->connect() 
    ->fetchAllHeaders() 
; 

echo $box->count() . " emails in mailbox\n"; 
for ($i = 0; ($i < $box->count()); $i++) 
{ 
    $msg = $box->get($i); 
    echo "Reception date : {$msg->date}\n"; 
    echo "From : {$msg->from}\n"; 
    echo "To : {$msg->to}\n"; 
    echo "Reply to : {$msg->from}\n"; 
    echo "Subject : {$msg->subject}\n"; 
    $msg = $box->fetch($msg); 
    echo "Number of readable contents : " . count($msg->content) . "\n"; 
    foreach ($msg->content as $key => $content) 
    { 
     echo "\tContent " . ($key + 1) . " :\n"; 
     echo "\t\tContent type : {$content->mime}\n"; 
     echo "\t\tContent charset : {$content->charset}\n"; 
     echo "\t\tContent size : {$content->size}\n"; 
    } 
    echo "Number of attachments : " . count($msg->attachments) . "\n"; 
    foreach ($msg->attachments as $key => $attachment) 
    { 
     echo "\tAttachment " . ($key + 1) . " :\n"; 
     echo "\t\tAttachment type : {$attachment->type}\n"; 
     echo "\t\tContent type : {$attachment->mime}\n"; 
     echo "\t\tFile name : {$attachment->name}\n"; 
     echo "\t\tFile size : {$attachment->size}\n"; 
    } 
    echo "\n"; 
} 

echo "Searching '*Bob*' ...\n"; 
$results = $box->searchBy('*Bob*', ImapReader::FROM); 
foreach ($results as $result) 
{ 
    echo "\tMatched: {$result->from} - {$result->date} - {$result->subject}\n"; 
} 

私はこのすべての答えを試みた

+0

私はあなたのコードを変更したくないのですが、将来誰かを助ける場合には、 '_fix'関数にいくつかの問題がありました。末尾に'? 'を残し、スペースをアンダースコアに置き換えました。代わりに 'imap_mime_header_decode'を使用しました(ここでは(http://stackoverflow.com/a/17187116/1714)) – Hobo

+0

あなたの貢献に感謝します。私のコードは古く、古いプロセスでも動作しますが、最近テストしませんでした。まもなくそれをチェックします。 –

0

お楽しみですが、どちらもが私のために働きました。それから私はこのPHPページに最初のユーザー貢献したノートを打つ:

http://php.net/manual/en/function.imap-fetchstructure.php

、これはすべての私の例のために動作します。かなり古い答えbtw。

関連する問題