PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Libraries/Imap2/Message.php +546 -0 10.2.0 → 11.1.0 View file →
@@ -1,0 +1,546 @@
1 +<?php
2 +
3 +/*
4 + * This file is part of the PHP IMAP2 package.
5 + *
6 + * (c) Francesco Bianco <[email protected]>
7 + *
8 + * For the full copyright and license information, please view the LICENSE
9 + * file that was distributed with this source code.
10 + */
11 +
12 +namespace AcyMailing\Libraries\Imap2;
13 +
14 +class Message
15 +{
16 + /**
17 + * Returns an array of messages matching the given search criteria.
18 + *
19 + * @param $imap
20 + * @param $criteria
21 + * @param $flags
22 + * @param $charset
23 + *
24 + * @return array|false|mixed
25 + */
26 + public static function search($imap, $criteria, $flags = SE_FREE, $charset = "")
27 + {
28 + if (!is_a($imap, Connection::class)) {
29 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
30 + }
31 +
32 + $client = $imap->getClient();
33 + #$client->setDebug(true);
34 +
35 + $result = $client->search($imap->getMailboxName(), $criteria, $flags & SE_UID);
36 +
37 + if (empty($result->count())) {
38 + return false;
39 + }
40 +
41 + $messages = $result->get();
42 + foreach ($messages as &$message) {
43 + $message = is_numeric($message) ? intval($message) : $message;
44 + }
45 +
46 + return $messages;
47 + }
48 +
49 + public static function sort($imap, $criteria, $reverse, $flags = 0, $searchCriteria = null, $charset = null)
50 + {
51 + if (is_a($imap, Connection::class)) {
52 + $client = $imap->getClient();
53 + #$client->setDebug(true);
54 +
55 + $result = $client->search($imap->getMailboxName(), $criteria, $flags & SE_UID);
56 +
57 + if (empty($result->count())) {
58 + return false;
59 + }
60 +
61 + $messages = $result->get();
62 + foreach ($messages as &$message) {
63 + $message = is_numeric($message) ? intval($message) : $message;
64 + }
65 +
66 + return $messages;
67 + }
68 +
69 + return imap_sort($imap, $criteria, $reverse, $flags, $searchCriteria, $charset);
70 + }
71 +
72 + public static function headerInfo($imap, $messageNum, $fromLength = 0, $subjectLength = 0, $defaultHost = null)
73 + {
74 + if (!is_a($imap, Connection::class)) {
75 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
76 + }
77 +
78 + $client = $imap->getClient();
79 + #$client->setDebug(true);
80 +
81 + $messages = $client->fetch($imap->getMailboxName(), $messageNum, false, [
82 + 'BODY.PEEK[HEADER.FIELDS (SUBJECT FROM TO CC REPLY-TO DATE SIZE REFERENCES)]',
83 + 'ENVELOPE',
84 + 'INTERNALDATE',
85 + 'UID',
86 + 'FLAGS',
87 + 'RFC822.SIZE',
88 + 'RFC822.HEADER',
89 + ]);
90 +
91 + if (empty($messages)) {
92 + return false;
93 + }
94 +
95 + foreach ($messages as $message) {
96 + return HeaderInfo::fromMessage($message, $defaultHost);
97 + }
98 + }
99 +
100 + public static function headers($imap)
101 + {
102 + if (!is_a($imap, Connection::class)) {
103 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
104 + }
105 +
106 + $client = $imap->getClient();
107 + #$client->setDebug(true);
108 +
109 + $status = $client->status($imap->getMailboxName(), ['MESSAGES']);
110 + if (empty($status['MESSAGES'])) {
111 + return [];
112 + }
113 +
114 + $sequence = '1:'.intval($status['MESSAGES']);
115 + $messages = $client->fetch($imap->getMailboxName(), $sequence, false, [
116 + 'BODY.PEEK[HEADER.FIELDS (SUBJECT FROM TO CC REPLYTO MESSAGEID DATE SIZE REFERENCES)]',
117 + #'UID',
118 + 'FLAGS',
119 + 'INTERNALDATE',
120 + 'RFC822.SIZE',
121 + #'ENVELOPE',
122 + 'RFC822.HEADER',
123 + ]);
124 +
125 + if (empty($messages)) {
126 + return [];
127 + }
128 +
129 + $headers = [];
130 + foreach ($messages as $message) {
131 + $from = ' ';
132 + if ($message->from != 'no_host') {
133 + $from = imap_rfc822_parse_adrlist($message->from, 'no_host');
134 + $from = isset($from[0]->personal) ? $from[0]->personal : $message->from;
135 + }
136 +
137 + $date = explode(' ', $message->internaldate);
138 + $subject = empty($message->subject) ? ' ' : $message->subject;
139 + $unseen = empty($message->flags['SEEN']) ? 'U' : ' ';
140 + $flagged = empty($message->flags['FLAGGED']) ? ' ' : 'F';
141 + $answered = empty($message->flags['ANSWERED']) ? ' ' : 'A';
142 + $draft = empty($message->flags['DRAFT']) ? ' ' : 'D';
143 + $deleted = empty($message->flags['DELETED']) ? ' ' : 'X';
144 +
145 + $header = ' '.$unseen.$flagged.$answered.$draft.$deleted.' '
146 + .str_pad($message->id, 3, ' ', STR_PAD_LEFT).')'.$date[0].' '.str_pad($from, 20, ' ').' '
147 + .substr($subject, 0, 25).' ('.$message->size.' chars)';
148 +
149 + $headers[] = $header;
150 + }
151 +
152 + return $headers;
153 + }
154 +
155 + /**
156 + * Picks the requested message in a fetch result.
157 + * The result is keyed by sequence number, and it may also contain unsolicited FETCH responses
158 + * the server sent for other messages (flag updates for instance), so we can't simply take the first one.
159 + *
160 + * @return object|null
161 + */
162 + private static function findMessage($messages, $messageNum, bool $isUid)
163 + {
164 + if (empty($messages) || !is_array($messages)) {
165 + return null;
166 + }
167 +
168 + if (!$isUid) {
169 + return $messages[$messageNum] ?? null;
170 + }
171 +
172 + // On a UID FETCH the server has to include the UID in its response, that's the only reliable way to identify the message
173 + foreach ($messages as $message) {
174 + if (isset($message->uid) && intval($message->uid) === intval($messageNum)) {
175 + return $message;
176 + }
177 + }
178 +
179 + return null;
180 + }
181 +
182 + public static function body($imap, $messageNum, $flags = 0)
183 + {
184 + if (!is_a($imap, Connection::class)) {
185 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
186 + }
187 +
188 + $client = $imap->getClient();
189 + #$client->setDebug(true);
190 +
191 + $isUid = boolval($flags & FT_UID);
192 +
193 + $messages = $client->fetch($imap->getMailboxName(), $messageNum, $isUid, ['BODY[TEXT]']);
194 +
195 + $message = self::findMessage($messages, $messageNum, $isUid);
196 +
197 + if ($message === null) {
198 + return false;
199 + }
200 +
201 + return $message->bodypart['TEXT'] ?? false;
202 + }
203 +
204 + public static function fetchBody($imap, $messageNum, $section, $flags = 0)
205 + {
206 + if (!is_a($imap, Connection::class)) {
207 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
208 + }
209 +
210 + $client = $imap->getClient();
211 + #$client->setDebug(true);
212 +
213 + if ($messageNum <= 0 || !is_int($messageNum)) {
214 + trigger_error(Errors::badMessageNumber(debug_backtrace(), 1), E_USER_WARNING);
215 +
216 + return false;
217 + }
218 +
219 + $isUid = boolval($flags & FT_UID);
220 + $messages = $client->fetch($imap->getMailboxName(), $messageNum, $isUid, ['BODY['.$section.']']);
221 +
222 + $message = self::findMessage($messages, $messageNum, $isUid);
223 +
224 + // The message may have been expunged, the section may not exist, or the connection may have dropped
225 + if ($message === null) {
226 + return false;
227 + }
228 +
229 + if ($section) {
230 + return $message->bodypart[$section] ?? false;
231 + }
232 +
233 + return $message->body ?? false;
234 + }
235 +
236 + public static function fetchMime($imap, $messageNum, $section, $flags = 0)
237 + {
238 + if (!is_a($imap, Connection::class)) {
239 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
240 + }
241 +
242 + if ($messageNum <= 0 || !is_int($messageNum)) {
243 + trigger_error(Errors::badMessageNumber(debug_backtrace(), 1), E_USER_WARNING);
244 +
245 + return false;
246 + }
247 +
248 + $client = $imap->getClient();
249 + #$client->setDebug(true);
250 +
251 + $isUid = boolval($flags & FT_UID);
252 +
253 + $sectionKey = $section.'.MIME';
254 + $messages = $client->fetch($imap->getMailboxName(), $messageNum, $isUid, ['BODY['.$sectionKey.']']);
255 +
256 + $message = self::findMessage($messages, $messageNum, $isUid);
257 +
258 + if ($message === null) {
259 + return '';
260 + }
261 +
262 + if ($section && isset($message->bodypart[$sectionKey])) {
263 + return $message->bodypart[$sectionKey];
264 + }
265 +
266 + return $message->body ?? '';
267 + }
268 +
269 + public static function saveBody($imap, $file, $messageNum, $section = "", $flags = 0)
270 + {
271 + if (is_a($imap, Connection::class)) {
272 + $client = $imap->getClient();
273 + #$client->setDebug(true);
274 +
275 + $messages = $client->fetch($imap->getMailboxName(), $messageNum, false, ['BODY['.$section.']']);
276 +
277 + $message = self::findMessage($messages, $messageNum, false);
278 +
279 + if ($message === null) {
280 + return false;
281 + }
282 +
283 + $body = $section ? ($message->bodypart[$section] ?? '') : ($message->body ?? '');
284 +
285 + return file_put_contents($file, $body);
286 + }
287 +
288 + return imap_savebody($imap, $file, $messageNum, $section, $flags);
289 + }
290 +
291 + public static function fetchStructure($imap, $messageNum, $flags = 0)
292 + {
293 + if (!is_a($imap, Connection::class)) {
294 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
295 + }
296 +
297 + $client = $imap->getClient();
298 + #$client->setDebug(true);
299 +
300 + $isUid = boolval($flags & FT_UID);
301 +
302 + $messages = $client->fetch($imap->getMailboxName(), $messageNum, $isUid, ['BODYSTRUCTURE']);
303 +
304 + if (empty($messages)) {
305 + return false;
306 + }
307 +
308 + foreach ($messages as $message) {
309 + return BodyStructure::fromMessage($message);
310 + }
311 + }
312 +
313 + public static function fetchHeader($imap, $messageNum, $flags = 0)
314 + {
315 + if (!is_a($imap, Connection::class)) {
316 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
317 + }
318 +
319 + /*
320 + * FT_UID - The message_num argument is a UID
321 + FT_INTERNAL - The return string is in "internal" format, without any attempt to canonicalize to CRLF newlines
322 + FT_PREFETCHTEXT
323 + * */
324 +
325 + $client = $imap->getClient();
326 + #$client->setDebug(true);
327 +
328 + $isUid = boolval($flags & FT_UID);
329 +
330 + $messages = $client->fetch($imap->getMailboxName(), $messageNum, $isUid, ['BODY[HEADER]']);
331 +
332 + if (empty($messages)) {
333 + return false;
334 + }
335 +
336 + foreach ($messages as $message) {
337 + return $message->bodypart['HEADER'] ?? false;
338 + }
339 + }
340 +
341 + public static function fetchOverview($imap, $sequence, $flags = 0)
342 + {
343 + if (!is_a($imap, Connection::class)) {
344 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
345 + }
346 +
347 + $client = $imap->getClient();
348 + #$client->setDebug(true);
349 +
350 + $messages = $client->fetch($imap->getMailboxName(), $sequence, false, [
351 + 'BODY[HEADER.FIELDS (SUBJECT FROM TO CC REPLYTO MESSAGEID DATE SIZE REFERENCES)]',
352 + 'UID',
353 + 'FLAGS',
354 + 'INTERNALDATE',
355 + 'RFC822.SIZE',
356 + 'ENVELOPE',
357 + 'RFC822.HEADER',
358 + ]);
359 +
360 + if ($sequence != '*' && count($messages) < Functions::expectedNumberOfMessages($sequence)) {
361 + return [];
362 + }
363 +
364 + $overview = [];
365 + foreach ($messages as $message) {
366 + #var_dump($message);
367 + #die();
368 + $messageEntry = (object)[
369 + 'subject' => $message->envelope[1],
370 + 'from' => Functions::writeAddressFromEnvelope($message->envelope[2]),
371 + 'to' => $message->get('to'),
372 + 'date' => $message->envelope[0],
373 + 'message_id' => $message->envelope[9],
374 + 'references' => $message->references,
375 + 'in_reply_to' => $message->envelope[8],
376 + 'size' => $message->size,
377 + 'uid' => $message->uid,
378 + 'msgno' => $message->id,
379 + 'recent' => intval($message->flags['RECENT'] ?? 0),
380 + 'flagged' => intval($message->flags['FLAGGED'] ?? 0),
381 + 'answered' => intval($message->flags['ANSWERED'] ?? 0),
382 + 'deleted' => intval($message->flags['DELETED'] ?? 0),
383 + 'seen' => intval($message->flags['SEEN'] ?? 0),
384 + 'draft' => intval($message->flags['DRAFT'] ?? 0),
385 + 'udate' => strtotime($message->internaldate),
386 + ];
387 +
388 + if (empty($messageEntry->subject)) {
389 + unset($messageEntry->subject);
390 + }
391 +
392 + if (empty($messageEntry->references)) {
393 + unset($messageEntry->references);
394 + }
395 +
396 + if (empty($messageEntry->in_reply_to)) {
397 + unset($messageEntry->in_reply_to);
398 + }
399 +
400 + if (empty($messageEntry->to)) {
401 + unset($messageEntry->to);
402 + }
403 +
404 + $overview[] = $messageEntry;
405 + }
406 +
407 + return $overview;
408 + }
409 +
410 + public static function delete($imap, $messageNums, $flags = 0)
411 + {
412 + if (!is_a($imap, Connection::class)) {
413 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
414 + }
415 +
416 + $mailboxName = $imap->getMailboxName();
417 +
418 + if ($mailboxName === Connection::DEFAULT_MAILBOX_GMAIL) {
419 + Mail::move($imap, $messageNums, Connection::GMAIL_TRASH_MAILBOX, $flags);
420 + } else {
421 + $client = $imap->getClient();
422 + $uids = ImapHelpers::idToUid($imap, $messageNums);
423 + $client->flag($mailboxName, $uids, $client->flags['DELETED']);
424 + }
425 +
426 + return true;
427 + }
428 +
429 + public static function undelete($imap, $messageNums, $flags = 0)
430 + {
431 + if (is_a($imap, Connection::class)) {
432 + $client = $imap->getClient();
433 + #$client->setDebug(true);
434 +
435 + $messages = $client->fetch($imap->getMailboxName(), $messageNums, false, ['UID']);
436 + foreach ($messages as $message) {
437 + $client->unflag($imap->getMailboxName(), $message->uid, $client->flags['DELETED']);
438 + }
439 +
440 + return true;
441 + }
442 +
443 + return imap_undelete($imap, $messageNums, $flags);
444 + }
445 +
446 + public static function expunge($imap)
447 + {
448 + if (is_a($imap, Connection::class)) {
449 + $client = $imap->getClient();
450 +
451 + return $client->expunge($imap->getMailboxName());
452 + }
453 +
454 + return imap_expunge($imap);
455 + }
456 +
457 + /**
458 + * Sets flags on messages.
459 + *
460 + * @param $imap
461 + * @param $sequence
462 + * @param $flag
463 + * @param $options
464 + *
465 + * @return bool
466 + */
467 + public static function setFlagFull($imap, $sequence, $flag, $options = 0)
468 + {
469 + if (!is_a($imap, Connection::class)) {
470 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
471 + }
472 +
473 + $client = $imap->getClient();
474 +
475 + if (!($options & ST_UID)) {
476 + $messages = $client->fetch($imap->getMailboxName(), $sequence, false, ['UID']);
477 +
478 + $uid = [];
479 + foreach ($messages as $message) {
480 + $uid[] = $message->uid;
481 + }
482 +
483 + $sequence = implode(',', $uid);
484 + }
485 +
486 + return $client->flag($imap->getMailboxName(), $sequence, strtoupper(substr($flag, 1)));
487 + }
488 +
489 + /**
490 + * Clears flags on messages.
491 + *
492 + * @param $imap
493 + * @param $sequence
494 + * @param $flag
495 + * @param $options
496 + *
497 + * @return false|string
498 + */
499 + public static function clearFlagFull($imap, $sequence, $flag, $options = 0)
500 + {
501 + if (!is_a($imap, Connection::class)) {
502 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
503 + }
504 +
505 + $client = $imap->getClient();
506 +
507 + if (!($options & ST_UID)) {
508 + $messages = $client->fetch($imap->getMailboxName(), $sequence, false, ['UID']);
509 +
510 + $uid = [];
511 + foreach ($messages as $message) {
512 + $uid[] = $message->uid;
513 + }
514 +
515 + $sequence = implode(',', $uid);
516 + }
517 +
518 + $client->unflag($imap->getMailboxName(), $sequence, strtoupper(substr($flag, 1)));
519 +
520 + return false;
521 + }
522 +
523 + public static function msgno($imap, $messageUid)
524 + {
525 + if (!is_a($imap, Connection::class)) {
526 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
527 + }
528 +
529 + $client = $imap->getClient();
530 +
531 + $msgNo = ImapHelpers::uidToId($imap, $messageUid);
532 +
533 + return is_numeric($msgNo) ? intval($msgNo) : $msgNo;
534 + }
535 +
536 + public static function uid($imap, $messageNum)
537 + {
538 + if (!is_a($imap, Connection::class)) {
539 + return Errors::invalidImapConnection(debug_backtrace(), 1, false);
540 + }
541 +
542 + $uid = ImapHelpers::idToUid($imap, $messageNum);
543 +
544 + return is_numeric($uid) ? intval($uid) : $uid;
545 + }
546 +}