Skip to content

Commit 1470732

Browse files
committed
arbitrary mime-parts: added support for listing/receiving any mime part of message (can be used e.g. for parsing DSNs)
1 parent 37c93ab commit 1470732

File tree

6 files changed

+182
-13
lines changed

6 files changed

+182
-13
lines changed

MailLibrary/Drivers/ImapDriver.php

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -301,22 +301,39 @@ public function getStructure($mailId, Mailbox $mailbox)
301301
* Gets part of body
302302
*
303303
* @param int $mailId
304-
* @param array $data
304+
* @param array $data requires id and encoding keys
305305
* @return string
306+
* @throws \greeny\MailLibrary\DriverException
306307
*/
307308
public function getBody($mailId, array $data)
308309
{
309310
$body = array();
310311
foreach($data as $part) {
311-
$data = ($part['id'] == 0) ? imap_body($this->resource, $mailId, FT_UID | FT_PEEK) : imap_fetchbody($this->resource, $mailId, $part['id'], FT_UID | FT_PEEK);
312-
$encoding = $part['encoding'];
313-
if($encoding === ImapStructure::ENCODING_BASE64) {
314-
$data = base64_decode($data);
315-
} else if($encoding === ImapStructure::ENCODING_QUOTED_PRINTABLE) {
316-
$data = quoted_printable_decode($data);
312+
assert(is_array($part));
313+
$dataMessage = ($part['id'] === 0) ? @imap_body($this->resource, $mailId, FT_UID | FT_PEEK) : @imap_fetchbody($this->resource, $mailId, $part['id'], FT_UID | FT_PEEK);
314+
if($dataMessage === FALSE) {
315+
throw new DriverException("Cannot read given message part - " . error_get_last()["message"]);
316+
}
317+
318+
// when there is no encoding of mime part available
319+
if(!isset($part['encoding'])) {
320+
$decodedMessage = $dataMessage;
321+
322+
} elseif($part['encoding'] === ImapStructure::ENCODING_BASE64) {
323+
$decodedMessage = base64_decode($dataMessage);
324+
if($decodedMessage === FALSE) {
325+
throw new DriverException('Malformed mime-part: cannot decode base64 mime-part');
326+
}
327+
328+
} elseif($part['encoding'] === ImapStructure::ENCODING_QUOTED_PRINTABLE) {
329+
$decodedMessage = quoted_printable_decode($dataMessage);
330+
331+
} else {
332+
throw new DriverException("Mime-part reading error: unknown encoding ({$part['encoding']})");
333+
317334
}
318335

319-
$body[] = $data;
336+
$body[] = $decodedMessage;
320337
}
321338
return implode('\n\n', $body);
322339
}

MailLibrary/Mail.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,15 @@ public function getAttachments()
193193
return $this->structure->getAttachments();
194194
}
195195

196+
/**
197+
* @return \greeny\MailLibrary\MimePart[]
198+
*/
199+
public function getMimeParts()
200+
{
201+
$this->structure !== NULL || $this->initializeStructure();
202+
return $this->structure->getMimeParts();
203+
}
204+
196205
/**
197206
* @return array
198207
*/
@@ -257,6 +266,15 @@ protected function initializeStructure()
257266
$this->structure = $this->connection->getDriver()->getStructure($this->id, $this->mailbox);
258267
}
259268

269+
/**
270+
* @internal
271+
* @return IStructure
272+
*/
273+
public function getStructure() {
274+
$this->structure !== NULL || $this->initializeStructure();
275+
return $this->structure;
276+
}
277+
260278
protected function initializeFlags()
261279
{
262280
$this->connection->getDriver()->switchMailbox($this->mailbox->getName());

MailLibrary/MimePart.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
/**
3+
* This file is part of the imap-mail-list-extractor.
4+
* Copyright (c) 2017 Grifart spol. s r.o. (https://grifart.cz)
5+
*/
6+
7+
namespace greeny\MailLibrary;
8+
9+
use greeny\MailLibrary\Drivers\IDriver;
10+
11+
class MimePart
12+
{
13+
/** @var string */
14+
private $partId;
15+
16+
/** @var string */
17+
private $mimeType;
18+
19+
/** @var string */
20+
private $name;
21+
22+
/** @var string */
23+
private $encoding;
24+
25+
/** @var IDriver */
26+
private $driver;
27+
28+
/** @var string */
29+
private $mailId;
30+
31+
public function __construct(IDriver $driver, $mailId, $partId, $mimeType, $name, $encoding)
32+
{
33+
$this->partId = $partId;
34+
$this->mailId = $mailId;
35+
$this->mimeType = $mimeType;
36+
$this->name = $name;
37+
$this->encoding = $encoding;
38+
$this->driver = $driver;
39+
}
40+
41+
/**
42+
* @return string
43+
*/
44+
public function getPartId()
45+
{
46+
return $this->partId;
47+
}
48+
49+
/**
50+
* @return string
51+
*/
52+
public function getMimeType()
53+
{
54+
return $this->mimeType;
55+
}
56+
57+
/**
58+
* @return string
59+
*/
60+
public function getName()
61+
{
62+
return $this->name;
63+
}
64+
65+
/**
66+
* @return string
67+
*/
68+
public function getEncoding()
69+
{
70+
return $this->encoding;
71+
}
72+
73+
public function getContent()
74+
{
75+
// todo: this automatically decodes content type if supported, support for getting RAW content?
76+
return $this->driver->getBody($this->mailId, [[
77+
'id' => $this->partId,
78+
'encoding' => $this->encoding,
79+
]]);
80+
}
81+
82+
}

MailLibrary/Structures/IStructure.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace greeny\MailLibrary\Structures;
77

88
use greeny\MailLibrary\Attachment;
9+
use greeny\MailLibrary\MimePart;
910

1011
interface IStructure {
1112
/**
@@ -27,4 +28,9 @@ function getTextBody();
2728
* @return Attachment[]
2829
*/
2930
function getAttachments();
30-
}
31+
32+
/**
33+
* @return MimePart[]
34+
*/
35+
function getMimeParts();
36+
}

MailLibrary/Structures/ImapStructure.php

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use greeny\MailLibrary\Attachment;
99
use greeny\MailLibrary\Drivers\ImapDriver;
1010
use greeny\MailLibrary\Mailbox;
11+
use greeny\MailLibrary\MimePart;
1112

1213
class ImapStructure implements IStructure {
1314
const TYPE_TEXT = 0;
@@ -37,6 +38,8 @@ class ImapStructure implements IStructure {
3738
self::TYPE_OTHER => 'other',
3839
);
3940

41+
private $messageParts = [];
42+
4043
/** @var \greeny\MailLibrary\Drivers\ImapDriver */
4144
protected $driver;
4245

@@ -64,6 +67,9 @@ class ImapStructure implements IStructure {
6467
/** @var Mailbox */
6568
protected $mailbox;
6669

70+
/** @var array */
71+
private $rawStructure = [];
72+
6773
/**
6874
* @param ImapDriver $driver
6975
* @param object $structure
@@ -72,6 +78,7 @@ class ImapStructure implements IStructure {
7278
*/
7379
public function __construct(ImapDriver $driver, $structure, $mailId, Mailbox $mailbox)
7480
{
81+
$this->rawStructure = $structure;
7582
$this->driver = $driver;
7683
$this->id = $mailId;
7784
$this->mailbox = $mailbox;
@@ -84,6 +91,15 @@ public function __construct(ImapDriver $driver, $structure, $mailId, Mailbox $ma
8491
}
8592
}
8693

94+
/**
95+
* @return array
96+
* @internal use only with caution, format can change without warning
97+
*/
98+
public function getRawStructure()
99+
{
100+
return $this->rawStructure;
101+
}
102+
87103
/**
88104
* @return string
89105
*/
@@ -100,9 +116,9 @@ public function getHtmlBody()
100116
if($this->htmlBody === NULL) {
101117
$this->driver->switchMailbox($this->mailbox->getName());
102118
return $this->htmlBody = $this->driver->getBody($this->id, $this->htmlBodyIds);
103-
} else {
104-
return $this->htmlBody;
105119
}
120+
121+
return $this->htmlBody;
106122
}
107123

108124
/**
@@ -113,9 +129,9 @@ public function getTextBody()
113129
if($this->textBody === NULL) {
114130
$this->driver->switchMailbox($this->mailbox->getName());
115131
return $this->textBody = $this->driver->getBody($this->id, $this->textBodyIds);
116-
} else {
117-
return $this->textBody;
118132
}
133+
134+
return $this->textBody;
119135
}
120136

121137
/**
@@ -133,6 +149,21 @@ public function getAttachments()
133149
return $this->attachments;
134150
}
135151

152+
/**
153+
* @return MimePart[]
154+
*/
155+
public function getMimeParts()
156+
{
157+
$this->driver->switchMailbox($this->mailbox->getName());
158+
return $this->messageParts;
159+
}
160+
161+
/** @deprecated use getMimeParts() instead */
162+
public function getParts() {
163+
\trigger_error(\E_USER_DEPRECATED, 'use getMimeParts() instead');
164+
return $this->getMimeParts();
165+
}
166+
136167
protected function addStructurePart($structure, $partId)
137168
{
138169
$type = $structure->type;
@@ -151,13 +182,27 @@ protected function addStructurePart($structure, $partId)
151182
}
152183
}
153184

185+
/** @noinspection NestedTernaryOperatorInspection Yep, will fix this when we switch to PHP7 level; see ?? operator */
186+
$this->messageParts[] = new MimePart(
187+
$this->driver,
188+
$this->id,
189+
$partId,
190+
self::$typeTable[$type]. '/' . $subtype,
191+
(empty($parameters['filename']) ? $parameters['filename'] : (
192+
empty($parameters['name']) ? $parameters['name'] : ''
193+
)),
194+
$encoding
195+
);
196+
197+
154198
if(isset($parameters['filename']) || isset($parameters['name'])) {
155199
$this->attachmentsIds[] = array(
156200
'id' => $partId,
157201
'encoding' => $encoding,
158202
'name' => isset($parameters['filename']) ? $parameters['filename'] : $parameters['name'],
159203
'type' => self::$typeTable[$type]. '/' . $subtype,
160204
);
205+
161206
} else if($type === self::TYPE_TEXT) {
162207
if($subtype === 'HTML') {
163208
$this->htmlBodyIds[] = array('id' => $partId, 'encoding' => $encoding);

MailLibrary/loader.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
'greeny\maillibrary\contactlist' => 'ContactList.php',
1515
'greeny\maillibrary\contact' => 'Contact.php',
1616
'greeny\maillibrary\attachment' => 'Attachment.php',
17+
'greeny\maillibrary\mimepart' => 'MimePart.php',
1718
'greeny\maillibrary\structures\istructure' => 'Structures/IStructure.php',
1819
'greeny\maillibrary\structures\imapstructure' => 'Structures/ImapStructure.php',
1920
'greeny\maillibrary\drivers\idriver' => 'Drivers/IDriver.php',

0 commit comments

Comments
 (0)