如何使用PHPExcel读取XLSX邮件附件文件?

时间:2017-09-05 23:22:23

标签: php phpexcel php-imap

我通过IMAP连接从邮箱获取XLSX附件,以便我可以使用PHPExcel将这些电子表格转换为PHP数组数据,但是当我加载文件并将其转换为数组时,数组为空。

这是从符合条件的邮件中获取附件的功能:

public function getEmailAttachments($criteria){
  $emails = imap_search($this->inbox, $criteria);
  $email_attachments = [];
  if($emails) {
    rsort($emails);
    foreach ($emails as $email_number) {
      $attachments = [];
      //get Email structure
      $structure = imap_fetchstructure($this->inbox, $email_number);
      /* if any attachments found... */
      if(isset($structure->parts) && count($structure->parts))
      {
          for($i = 0; $i < count($structure->parts); $i++)
          {
              $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($this->inbox, $email_number, $i+1);
                  /* 3 = BASE64 encoding */
                  if($structure->parts[$i]->encoding == 3)
                  {
                      $attachments[$i]['attachment'] = base64_decode($attachments[$i]['attachment']);
                  }
                  /* 4 = QUOTED-PRINTABLE encoding */
                  elseif($structure->parts[$i]->encoding == 4)
                  {
                      $attachments[$i]['attachment'] = quoted_printable_decode($attachments[$i]['attachment']);
                  }
              }
          }
      }
      $email_attachments = array_merge($email_attachments, array_filter($attachments, function($attachment){return $attachment['is_attachment'] == 1;}));
    }
  }
  imap_close($this->inbox);
  return $email_attachments;
}

然后,这是将XLSX文件写入服务器并使用PHPExcel加载它们以将它们转换为数据数据的函数:

public function getEmailReports(){
  $this->loadPhpExcel();
  $attachments = parent::getEmailAttachments('FROM "example@example.com"');
   //iterate through each attachment and save it
  foreach($attachments as $attachment){
    $filename = $attachment['name'];
    if(empty($filename)) $filename = $attachment['filename'];
    $folder = "data/excel";
    $file_path = "./". $folder ."/". time() . "-" . $filename;
    $fp = fopen($file_path, "w");
    fwrite($fp, $attachment['attachment']);
    $excelReader = PHPExcel_IOFactory::createReaderForFile($file_path);
    $excelObj = $excelReader->load($file_path);
    foreach ($excelObj->getWorksheetIterator() as $worksheet) {
      $worksheets[$worksheet->getTitle()] = $worksheet->toArray();
    }
    fclose($fp);
    print_r($worksheets); //ARRAY IS EMPTY HERE
    //unlink($file_path);
  }
}

1 个答案:

答案 0 :(得分:1)

我用WinRAR打开了XLSX文件,发现xl / worbooks.xml文件有一个&#34; S&#34;命名空间:

<?xml version="1.0"?>
<s:workbook 
xmlns:s="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<s:workbookPr/>
<s:bookViews>
 <s:workbookView activeTab="0"/>
</s:bookViews>
<s:sheets>
 <s:sheet r:id="rId1" sheetId="1" name="Sheet1"/>
 <s:sheet r:id="rId2" sheetId="2" name="Sheet2"/>
 <s:sheet r:id="rId3" sheetId="3" name="Sheet3"/>
 <s:sheet r:id="rId4" sheetId="4" name="Sheet4"/>
</s:sheets>
<s:definedNames/>
<s:calcPr fullCalcOnLoad="1" calcId="124519"/>
</s:workbook>

然后我在PHPExcel GitHub repo https://github.com/PHPOffice/PHPExcel/issues/571

上发现了这个问题

所以我所做的就是创建一个从PHPExcel_Reader_Excel2007扩展的类来删除&#34; s&#34;命名空间

<?php
class PHPExcel_Reader_Excel2007_XNamespace extends 
PHPExcel_Reader_Excel2007
{

 public function securityScan($xml)
 {
     $xml = parent::securityScan($xml);
     return str_replace(['<s:', '</s:'], ['<', '</'], $xml);
 }

}

最后取代了这个:

$excelReader = PHPExcel_IOFactory::createReaderForFile($file_path);

为此:

$excelReader = new PHPExcel_Reader_Excel2007_XNamespace();