【问题标题】:imap - get attached fileimap - 获取附件
【发布时间】:2012-07-02 09:08:21
【问题描述】:

如何从这封电子邮件中获取附件?

这封邮件是从苹果电脑发出的,邮件结构和其他的都不一样(惊喜)..这里的处置部分比其他部分更深一维..

该脚本适用于包含文件的部分位于第一维中的所有其他电子邮件,但不适用于这个

$part->dparameters[0]->value返回文件名,但strlen($data)返回0

imap 流

$structure = imap_fetchstructure($this->stream, $this->msgno);

if(isset($structure->parts)){
    print_r($structure->parts);
    $this->parse_parts($structure->parts);
}

function parse_parts($parts){
    foreach($parts as $section => $part){
        if(isset($part->parts)){

            // some mails have one extra dimension
            $this->parse_parts($part->parts);

        }
        elseif(isset($part->disposition)){
            if(in_array(strtolower($part->disposition), array('attachment','inline'))){
                $data = imap_fetchbody($this->stream, $this->msgno, $section+1);
                echo $part->dparameters[0]->value.' '.strlen($data)."\n";
            }
        }
    }
}

print_r

Array
(
    [0] => stdClass Object
        (
            [type] => 0
            [encoding] => 0
            [ifsubtype] => 1
            [subtype] => PLAIN
            [ifdescription] => 0
            [ifid] => 0
            [lines] => 15
            [bytes] => 173
            [ifdisposition] => 0
            [ifdparameters] => 0
            [ifparameters] => 1
            [parameters] => Array
                (
                    [0] => stdClass Object
                        (
                            [attribute] => CHARSET
                            [value] => us-ascii
                        )

                )

        )

    [1] => stdClass Object
        (
            [type] => 1
            [encoding] => 0
            [ifsubtype] => 1
            [subtype] => MIXED
            [ifdescription] => 0
            [ifid] => 0
            [bytes] => 23420
            [ifdisposition] => 0
            [ifdparameters] => 0
            [ifparameters] => 1
            [parameters] => Array
                (
                    [0] => stdClass Object
                        (
                            [attribute] => BOUNDARY
                            [value] => Apple-Mail=_800896E0-A9C9-456E-B063-79CED9DD4FD7
                        )

                )

            [parts] => Array
                (
                    [0] => stdClass Object
                        (
                            [type] => 0
                            [encoding] => 0
                            [ifsubtype] => 1
                            [subtype] => HTML
                            [ifdescription] => 0
                            [ifid] => 0
                            [bytes] => 136
                            [ifdisposition] => 0
                            [ifdparameters] => 0
                            [ifparameters] => 1
                            [parameters] => Array
                                (
                                    [0] => stdClass Object
                                        (
                                            [attribute] => CHARSET
                                            [value] => us-ascii
                                        )

                                )

                        )

                    [1] => stdClass Object
                        (
                            [type] => 3
                            [encoding] => 3
                            [ifsubtype] => 1
                            [subtype] => PDF
                            [ifdescription] => 0
                            [ifid] => 0
                            [bytes] => 17780
                            [ifdisposition] => 1
                            [disposition] => INLINE
                            [ifdparameters] => 1
                            [dparameters] => Array
                                (
                                    [0] => stdClass Object
                                        (
                                            [attribute] => FILENAME
                                            [value] => 057 - LPJ - Stik og labels.pdf
                                        )

                                )

                            [ifparameters] => 1
                            [parameters] => Array
                                (
                                    [0] => stdClass Object
                                        (
                                            [attribute] => NAME
                                            [value] => 057 - LPJ - Stik og labels.pdf
                                        )

                                )

                        )

                    [2] => stdClass Object
                        (
                            [type] => 0
                            [encoding] => 4
                            [ifsubtype] => 1
                            [subtype] => HTML
                            [ifdescription] => 0
                            [ifid] => 0
                            [lines] => 75
                            [bytes] => 4931
                            [ifdisposition] => 0
                            [ifdparameters] => 0
                            [ifparameters] => 1
                            [parameters] => Array
                                (
                                    [0] => stdClass Object
                                        (
                                            [attribute] => CHARSET
                                            [value] => us-ascii
                                        )

                                )

                        )

                )

        )

)

【问题讨论】:

  • 我不明白FROM Mac 发送的电子邮件与其他任何电子邮件有何不同。您是否将电子邮件标题与从其他类型帐户发送的电子邮件进行了比较,以了解它们的确切差异?除非“发件人”是指它存储在 Mac 上的电子邮件服务器上。
  • 主体结构与其他结构不同..带有文件的部分在结构中比其他部分更深一维
  • 我说的是邮件标题。查看电子邮件的源代码并比较它们,看看有什么不同。比较他们每个人发送附件的方式,这可能会让您了解发生了什么。
  • 我将 $part->dparameters[0]->value 更改为 foreach 循环,因为有时 Content-Disposition 不仅包含文件名,还包含其他参数(例如,创建日期)可以在数组中排在第一位。要获取文件名,您应该搜索它: foreach($part->dparameters as $dp) { if (strcasecmp($dp->attribute, 'filename')==0) $filename=$dp->value; }
  • @Mike 问题不在于它是从 Mac 发送的,而在于它是通过“mac mailer”发送的。如果你在 Mac 上使用 Thunderbird,没问题。

标签: php imap apple-mail


【解决方案1】:

我从这里的其他用户那里获取了代码,并为自己制作了这个函数,它可以让我完美地了解电子邮件的结构。该函数的结果如下所示:

array (
    0 =>
        array (
            'section_num' => '1.1',
            'type' => 0,
            'subtype' => 'PLAIN',
            'size_bytes' => 128,
        ),
    1 =>
        array (
            'section_num' => '1.2.1',
            'type' => 0,
            'subtype' => 'HTML',
            'size_bytes' => 527,
        ),
    2 =>
        array (
            'section_num' => '1.2.2',
            'type' => 5,
            'subtype' => 'GIF',
            'disposition' => 'inline',
            'size_bytes' => 3304,
            'file_name' => 'logo_email.gif',
        ),
    3 =>
        array (
            'section_num' => '2',
            'type' => 3,
            'subtype' => 'VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.SHEET',
            'disposition' => 'attachment',
            'size_bytes' => 14742,
            'file_name' => 'my_excel_table.xlsx',
        ),
)

现在很容易遍历它并获取电子邮件的任何部分。 例如,如果我想要那个 excel 文件,我在这里获取节号“2”:

$excelData = imap_fetchbody($imapConnection, $msgNumber, '2')

最后是我的函数,它为我提供了很好的概述以及如何使用它的示例:

$imapConnection = imap_open(..........);
$msgs = imap_search($imapConnection, ........);
$msgStructure = imap_fetchstructure($imapConnection, $msgNumber);

$resultOverview = []; // here the result will be stored
analyzeParts($msgStructure->parts, $resultOverview);

function analyzeParts($parts, &$structOverview, $parent = ''){
    foreach ($parts as $sectionNum => $part) {
        $sectionName = $parent . ($sectionNum+1);
        if (isset($part->parts)){
            analyzeParts($part->parts, $structOverview, $sectionName.'.');
        } else {
            $partInfo = [
                'section_num' => $sectionName,
                'type' => $part->type,
                'subtype' => $part->subtype,
            ];
            if (isset($part->bytes)) $partInfo['size_bytes'] = $part->bytes;
            if (isset($part->disposition)) {
                $partInfo['disposition'] = $part->disposition;
                if (in_array($part->disposition, ['attachment', 'inline'])){
                    foreach ($part->parameters as $parameter) {
                        if ($parameter->attribute === 'name')
                            $partInfo['file_name'] = $parameter->value;
                    }
                }
            }
            $structOverview[] = $partInfo;
        }
    }
}

【讨论】:

    【解决方案2】:

    下一个代码显示收件箱中的目录和电子邮件

        $mailbox = imap_open ("{correo.servidor.com:993/imap/ssl/novalidate-cert}INBOX", "correo@usuario.com", "PASSWORD");
    
        if (!$mailbox){
            die('murio');
        }
    
        echo "<h1>Buzones</h1>\n";
        $carpetas = imap_listmailbox($mailbox, "{correo.patronato.unam.mx:993}", "*");
    
        if ($carpetas == false) {
            echo "Llamada fallida<br />\n";
        } else {
            foreach ($carpetas as $val) {
                echo $val . "<br />\n";
            }
        }
    
        echo "<h1>Cabeceras en INBOX</h1>\n";
        $cabeceras = imap_headers($mailbox);
    
        if ($cabeceras == false) {
            echo "Llamada fallida<br />\n";
        } else {
            foreach ($cabeceras as $val) {
                echo $val . "<br />\n";
            }
        }
    
    
    
        $numMessages = imap_num_msg($mailbox);
        for ($i = $numMessages; $i > 0; $i--) {
            $header = imap_header($mailbox, $i);
    
            $fromInfo = $header->from[0];
            $replyInfo = $header->reply_to[0];
    
            // print_r($header);
    
            $details = array(
                "fromAddr" => (isset($fromInfo->mailbox) && isset($fromInfo->host))
                    ? $fromInfo->mailbox . "@" . $fromInfo->host : "",
                "fromName" => (isset($fromInfo->personal))
                    ? $fromInfo->personal : "",
                "replyAddr" => (isset($replyInfo->mailbox) && isset($replyInfo->host))
                    ? $replyInfo->mailbox . "@" . $replyInfo->host : "",
                "replyName" => (isset($replyTo->personal))
                    ? $replyto->personal : "",
                "subject" => (isset($header->subject))
                    ? $header->subject : "",
                "udate" => (isset($header->udate))
                    ? $header->udate : "",
                "Unseen" => (isset($header->Unseen))
                    ? $header->Unseen  : "-"
            );
            $uid = imap_uid($mailbox, $i);
    
            echo "<ul>";
            echo "<li><strong>From:</strong>" . $details["fromName"];
            echo " " . $details["fromAddr"] . "</li>";
            echo "<li><strong>Subject:</strong> " . $details["subject"] . "</li>";
            echo "<li><strong>Estatus:</strong> " . $details["Unseen"] . "</li>";
            echo '<li><a href="test_imap_attachment.php?folder=' . $folder . '&uid=' . $i . '">Read</a></li>';
            echo "</ul>";
        }
    
    
        imap_close($mailbox);
    

    显示附件文件的 test_imap_attachment.php 代码

    function getAttachments($imap, $mailNum, $part, $partNum) {
        $attachments = array();
    
        if (isset($part->parts)) {
            foreach ($part->parts as $key => $subpart) {
                if($partNum != "") {
                    $newPartNum = $partNum . "." . ($key + 1);
                }
                else {
                    $newPartNum = ($key+1);
                }
                $result = getAttachments($imap, $mailNum, $subpart,
                    $newPartNum);
                if (count($result) != 0) {
                     array_push($attachments, $result);
                 }
            }
        }
        else if (isset($part->disposition)) {
            // print_r($part);
            if (strtoupper($part->disposition) == "ATTACHMENT") {
                $partStruct = imap_bodystruct($imap, $mailNum, $partNum);
                $attachmentDetails = array(
                    "name"    => $part->dparameters[0]->value,
                    "subtype" => $partStruct->subtype,
                    "partNum" => $partNum,
                    "enc"     => $partStruct->encoding
                );
                return $attachmentDetails;
            }
        }
    
        return $attachments;
    }
    
    $mailbox = imap_open ("{correo.servidor.com:993/imap/ssl/novalidate-cert}INBOX", "correo@usuario.com", "PASSWORD");
    
    $uid = $_GET['uid'];
    
    $mailStruct = imap_fetchstructure($mailbox, $uid);
    
    $attachments = getAttachments($mailbox, $uid, $mailStruct, "");
    
    echo "Attachments: ";
    echo "<ul>";
    foreach ($attachments as $attachment) {  
        echo '<li><a href="test_imap_download.php?func=' . $func . '&folder=' . $folder . '&uid=' . $uid .
            '&part=' . $attachment["partNum"] . '&enc=' . $attachment["enc"] . '">' .
            $attachment["name"] . "</a></li>";
    }
    echo "</ul>";
    

    下一段代码将文件保存在同一台服务器上:test_imap_download.php

    function downloadAttachment($imap, $uid) {
        $structure = imap_fetchstructure($imap, $uid);
        $attachments = '';
        if(isset($structure->parts) && count($structure->parts)) {
            for($i=0; $i<count($structure->parts); $i++) {
                if(strtoupper($structure->parts[$i]->disposition) == 'ATTACHMENT') {
    
                    $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($imap, $uid, $i+1);
                        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']);
                        }
                    }
    
                    file_put_contents('directorio/'.$attachments[$i]['filename'], $attachments[$i]['attachment']);
    
                }
            } 
        }
    }   
    
    $mailbox = imap_open ("{correo.servidor.com:993/imap/ssl/novalidate-cert}INBOX", "correo@usuario.com", "PASSWORD");
    
    
    $uid        = $_GET["uid"];
    $partNum    = $_GET["partNum"];
    
    downloadAttachment($mailbox, $uid);
    

    我使用了此页面中的代码:

    http://www.sitepoint.com/exploring-phps-imap-library-2/

    Downloading attachments to directory with IMAP in PHP, randomly works

    【讨论】:

      【解决方案3】:

      您没有为嵌套附件提供正确的部分编号。您需要在递归步骤中传入节号。

      function parse_parts($parts, $parentsection = ""){
          foreach($parts as $subsection => $part){
              $section = $parentsection . ($subsection + 1);
              if(isset($part->parts)){
      
                  // some mails have one extra dimension
                  $this->parse_parts($part->parts, $section . "." );
      
              }
              elseif(isset($part->disposition)){
                  if(in_array(strtolower($part->disposition), array('attachment','inline'))){
                      $data = imap_fetchbody($this->stream, $this->msgno, $section );
                      echo 'Getting section ' . $section;
                      echo $part->dparameters[0]->value.' '.strlen($data)."\n";
                  }
              }
          }
      }
      

      (未经测试,但应该做正确的事情......)

      【讨论】:

        【解决方案4】:

        我不具体了解 Mac 电子邮件,但这里有一些代码可以检查每个部分以查看它是否是“附件”并将文件保存在某个位置以便我以后调用它。

        $body = imap_fetchstructure($box, $i);
        $attachments = '';
        $att = count($body->parts);
        if($att >=2) {
        for($a=0;$a<$att;$a++) {
        if($body->parts[$a]->disposition == 'ATTACHMENT') {
        $file = imap_base64(imap_fetchbody($box, $i, $a+1));
        $string = genRandomString();
            if(!file_exists('/var/www/email_store/'.$_SESSION['site_user_id'])) {
                mkdir('/var/www/email_store/'.$_SESSION['site_user_id'].'/');   
            }
            $attachments .= $body->parts[$a]->dparameters[0]->value.'[#]'.$string.',';
            file_put_contents('/var/www/email_store/'.$_SESSION['site_user_id'].'/'.$string,$file);
            }
        }       
        

        【讨论】:

        • 这假定邮件存储在本地。如果它存储在远程 IMAP 服务器上怎么办?
        • 确实如此,但获取附件仍然有效,您可以跳过将其保存在本地并将其放在其他地方。
        • @Mike:它不假定邮件存储在本地 - 它联系 IMAP 服务器,获取附加邮件,然后将其保存在本地。
        猜你喜欢
        • 2012-12-31
        • 2012-01-24
        • 1970-01-01
        • 2019-02-21
        • 2013-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多