Skip to content

Commit c241f8e

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 c241f8e

File tree

6 files changed

+183
-13
lines changed

6 files changed

+183
-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: 50 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,9 @@ class ImapStructure implements IStructure {
3738
self::TYPE_OTHER => 'other',
3839
);
3940

41+
/** @var MimePart[] */
42+
private $mimeParts = [];
43+
4044
/** @var \greeny\MailLibrary\Drivers\ImapDriver */
4145
protected $driver;
4246

@@ -64,6 +68,9 @@ class ImapStructure implements IStructure {
6468
/** @var Mailbox */
6569
protected $mailbox;
6670

71+
/** @var array */
72+
private $rawStructure = [];
73+
6774
/**
6875
* @param ImapDriver $driver
6976
* @param object $structure
@@ -72,6 +79,7 @@ class ImapStructure implements IStructure {
7279
*/
7380
public function __construct(ImapDriver $driver, $structure, $mailId, Mailbox $mailbox)
7481
{
82+
$this->rawStructure = $structure;
7583
$this->driver = $driver;
7684
$this->id = $mailId;
7785
$this->mailbox = $mailbox;
@@ -84,6 +92,15 @@ public function __construct(ImapDriver $driver, $structure, $mailId, Mailbox $ma
8492
}
8593
}
8694

95+
/**
96+
* @return array
97+
* @internal use only with caution, format can change without warning
98+
*/
99+
public function getRawStructure()
100+
{
101+
return $this->rawStructure;
102+
}
103+
87104
/**
88105
* @return string
89106
*/
@@ -100,9 +117,9 @@ public function getHtmlBody()
100117
if($this->htmlBody === NULL) {
101118
$this->driver->switchMailbox($this->mailbox->getName());
102119
return $this->htmlBody = $this->driver->getBody($this->id, $this->htmlBodyIds);
103-
} else {
104-
return $this->htmlBody;
105120
}
121+
122+
return $this->htmlBody;
106123
}
107124

108125
/**
@@ -113,9 +130,9 @@ public function getTextBody()
113130
if($this->textBody === NULL) {
114131
$this->driver->switchMailbox($this->mailbox->getName());
115132
return $this->textBody = $this->driver->getBody($this->id, $this->textBodyIds);
116-
} else {
117-
return $this->textBody;
118133
}
134+
135+
return $this->textBody;
119136
}
120137

121138
/**
@@ -133,6 +150,21 @@ public function getAttachments()
133150
return $this->attachments;
134151
}
135152

153+
/**
154+
* @return MimePart[]
155+
*/
156+
public function getMimeParts()
157+
{
158+
$this->driver->switchMailbox($this->mailbox->getName());
159+
return $this->mimeParts;
160+
}
161+
162+
/** @deprecated use getMimeParts() instead */
163+
public function getParts() {
164+
\trigger_error(\E_USER_DEPRECATED, 'use getMimeParts() instead');
165+
return $this->getMimeParts();
166+
}
167+
136168
protected function addStructurePart($structure, $partId)
137169
{
138170
$type = $structure->type;
@@ -151,13 +183,27 @@ protected function addStructurePart($structure, $partId)
151183
}
152184
}
153185

186+
/** @noinspection NestedTernaryOperatorInspection Yep, will fix this when we switch to PHP7 level; see ?? operator */
187+
$this->mimeParts[] = new MimePart(
188+
$this->driver, // for lazy loading
189+
$this->id,
190+
$partId,
191+
self::$typeTable[$type]. '/' . $subtype,
192+
(empty($parameters['filename']) ? $parameters['filename'] : (
193+
empty($parameters['name']) ? $parameters['name'] : ''
194+
)),
195+
$encoding
196+
);
197+
198+
154199
if(isset($parameters['filename']) || isset($parameters['name'])) {
155200
$this->attachmentsIds[] = array(
156201
'id' => $partId,
157202
'encoding' => $encoding,
158203
'name' => isset($parameters['filename']) ? $parameters['filename'] : $parameters['name'],
159204
'type' => self::$typeTable[$type]. '/' . $subtype,
160205
);
206+
161207
} else if($type === self::TYPE_TEXT) {
162208
if($subtype === 'HTML') {
163209
$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)