mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-10-29 12:43:25 +00:00
[Web] Update composer libraries
This commit is contained in:
1297 files changed
+71585
-24460
No files matched your search
+3
-3
@@ -17,7 +17,7 @@ return (new PhpCsFixer\Config())
|
||||
'binary_operator_spaces' => ['default' => 'align_single_space'],
|
||||
'blank_line_before_statement' => true,
|
||||
'class_definition' => ['single_item_single_line' => true],
|
||||
'compact_nullable_typehint' => true,
|
||||
'compact_nullable_type_declaration' => true,
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'echo_tag_syntax' => ['format' => 'long'],
|
||||
'error_suppression' => false,
|
||||
@@ -39,7 +39,7 @@ return (new PhpCsFixer\Config())
|
||||
'no_null_property_initialization' => true,
|
||||
'no_php4_constructor' => true,
|
||||
'no_superfluous_elseif' => true,
|
||||
'no_unneeded_curly_braces' => true,
|
||||
'no_unneeded_braces' => true,
|
||||
'no_unneeded_final_method' => true,
|
||||
'no_unreachable_default_argument_value' => true,
|
||||
'no_useless_else' => true,
|
||||
@@ -49,7 +49,7 @@ return (new PhpCsFixer\Config())
|
||||
'php_unit_set_up_tear_down_visibility' => true,
|
||||
'php_unit_strict' => true,
|
||||
'php_unit_test_annotation' => true,
|
||||
'php_unit_test_case_static_method_calls' => true,
|
||||
'php_unit_test_case_static_method_calls' => false,
|
||||
'php_unit_test_class_requires_covers' => false,
|
||||
'phpdoc_add_missing_param_annotation' => true,
|
||||
'phpdoc_order' => true,
|
||||
|
||||
+20
-22
@@ -2,12 +2,12 @@
|
||||
|
||||
[](https://packagist.org/packages/ddeboer/imap)
|
||||
[](https://packagist.org/packages/ddeboer/imap)
|
||||
[](https://github.com/ddeboer/imap/actions)
|
||||
[](https://github.com/ddeboer/imap/actions)
|
||||
[](https://codecov.io/gh/ddeboer/imap?branch=master)
|
||||
|
||||
A PHP IMAP library to read and process e-mails over IMAP protocol, built with robust Object-Oriented architecture.
|
||||
|
||||
This library requires PHP >= 7.4 with [IMAP](https://www.php.net/manual/en/book.imap.php),
|
||||
This library requires PHP >= 8.2 with [IMAP](https://www.php.net/manual/en/book.imap.php),
|
||||
[iconv](https://www.php.net/manual/en/book.iconv.php) and
|
||||
[Multibyte String](https://www.php.net/manual/en/book.mbstring.php) extensions installed.
|
||||
|
||||
@@ -157,7 +157,7 @@ By the way most of the common search criteria are available and functioning, bro
|
||||
References:
|
||||
|
||||
1. https://stackoverflow.com/questions/36356715/imap-search-unknown-search-criterion-or
|
||||
1. imap-2007f.tar.gz: `./src/c-client/mail.c` and `./docs/internal.txt`
|
||||
2. imap-2007f.tar.gz: `./src/c-client/mail.c` and `./docs/internal.txt`
|
||||
|
||||
#### Message Properties and Operations
|
||||
|
||||
@@ -182,19 +182,29 @@ $message->isDraft();
|
||||
$message->isSeen();
|
||||
```
|
||||
|
||||
Get message headers as a [\Ddeboer\Imap\Message\Headers](/src/Ddeboer/Imap/Message/Headers.php) object:
|
||||
Get message headers as a [\Ddeboer\Imap\Message\Headers](/src/Message/Headers.php) object:
|
||||
|
||||
```php
|
||||
$message->getHeaders();
|
||||
```
|
||||
|
||||
Get message body as HTML or plain text:
|
||||
Get message body as HTML or plain text (only first part):
|
||||
|
||||
```php
|
||||
$message->getBodyHtml(); // Content of text/html part, if present
|
||||
$message->getBodyText(); // Content of text/plain part, if present
|
||||
```
|
||||
|
||||
|
||||
Get complete body (all parts):
|
||||
|
||||
```php
|
||||
$body = $message->getCompleteBodyHtml(); // Content of text/html part, if present
|
||||
if ($body === null) { // If body is null, there are no HTML parts, so let's try getting the text body
|
||||
$body = $message->getCompleteBodyText(); // Content of text/plain part, if present
|
||||
}
|
||||
```
|
||||
|
||||
Reading the message body keeps the message as unseen.
|
||||
If you want to mark the message as seen:
|
||||
|
||||
@@ -284,24 +294,12 @@ Mockability is granted by interfaces present for each API.
|
||||
Dig into [MockabilityTest](tests/MockabilityTest.php) for an example of a
|
||||
mocked workflow.
|
||||
|
||||
## Running the Tests
|
||||
## Contributing: run the build locally
|
||||
|
||||
This library is functionally tested on [Travis CI](https://travis-ci.org/ddeboer/imap)
|
||||
against a local Dovecot server.
|
||||
Docker is needed to run the build on your computer.
|
||||
|
||||
If you have your own IMAP (test) account, you can run the tests locally by
|
||||
providing your IMAP credentials:
|
||||
First command you need to run is `make start-imap-server`, which starts an IMAP server locally.
|
||||
|
||||
```bash
|
||||
$ composer install
|
||||
$ IMAP_SERVER_NAME="my.imap.server.com" IMAP_SERVER_PORT="60993" IMAP_USERNAME="johndoe" IMAP_PASSWORD="p4ssword" vendor/bin/phpunit
|
||||
```
|
||||
Then the local build can be triggered with a bare `make`.
|
||||
|
||||
You can also copy `phpunit.xml.dist` file to a custom `phpunit.xml` and put
|
||||
these environment variables in it.
|
||||
|
||||
**WARNING** Tests create new mailboxes without removing them.
|
||||
|
||||
```
|
||||
$ docker-compose run tests
|
||||
```
|
||||
When you finish the development, stop the local IMAP server with `make stop-imap-server`.
|
||||
+9
-13
@@ -22,19 +22,20 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.0.1",
|
||||
"php": "~8.2.0 || ~8.3.0",
|
||||
"ext-dom": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-imap": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^v3.4.0",
|
||||
"laminas/laminas-mail": "^2.15.1",
|
||||
"malukenho/mcbumpface": "^1.1.5",
|
||||
"phpstan/phpstan": "^1.3.3",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.1.0",
|
||||
"phpunit/phpunit": "^9.5.11"
|
||||
"friendsofphp/php-cs-fixer": "^3.38.2",
|
||||
"laminas/laminas-mail": "^2.25.1",
|
||||
"phpstan/phpstan": "^1.10.43",
|
||||
"phpstan/phpstan-phpunit": "^1.3.15",
|
||||
"phpstan/phpstan-strict-rules": "^1.5.2",
|
||||
"phpunit/phpunit": "^10.4.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -45,10 +46,5 @@
|
||||
"psr-4": {
|
||||
"Ddeboer\\Imap\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"malukenho/mcbumpface": true
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -50,9 +50,11 @@ final class Connection implements ConnectionInterface
|
||||
|
||||
public function close(int $flag = 0): bool
|
||||
{
|
||||
$stream = $this->resource->getStream();
|
||||
|
||||
$this->resource->clearLastMailboxUsedCache();
|
||||
|
||||
return \imap_close($this->resource->getStream(), $flag);
|
||||
return \imap_close($stream, $flag);
|
||||
}
|
||||
|
||||
public function getQuota(string $root = 'INBOX'): array
|
||||
@@ -61,7 +63,7 @@ final class Connection implements ConnectionInterface
|
||||
$errorNumber = 0;
|
||||
\set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
|
||||
$errorMessage = $message;
|
||||
$errorNumber = $nr;
|
||||
$errorNumber = $nr;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace Ddeboer\Imap;
|
||||
|
||||
use Ddeboer\Imap\Exception\CreateMailboxException;
|
||||
use Ddeboer\Imap\Exception\DeleteMailboxException;
|
||||
use Ddeboer\Imap\Exception\InvalidResourceException;
|
||||
use Ddeboer\Imap\Exception\MailboxDoesNotExistException;
|
||||
|
||||
/**
|
||||
@@ -31,8 +30,6 @@ interface ConnectionInterface extends \Countable
|
||||
|
||||
/**
|
||||
* Check if the connection is still active.
|
||||
*
|
||||
* @throws InvalidResourceException If connection was closed
|
||||
*/
|
||||
public function ping(): bool;
|
||||
|
||||
|
||||
Vendored
Regular → Executable
+1
-1
@@ -4,6 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ddeboer\Imap\Exception;
|
||||
|
||||
final class InvalidResourceException extends AbstractException
|
||||
final class RenameMailboxException extends AbstractException
|
||||
{
|
||||
}
|
||||
+5
-20
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ddeboer\Imap;
|
||||
|
||||
use Ddeboer\Imap\Exception\InvalidResourceException;
|
||||
use Ddeboer\Imap\Exception\ReopenMailboxException;
|
||||
use IMAP\Connection;
|
||||
|
||||
@@ -13,33 +12,21 @@ use IMAP\Connection;
|
||||
*/
|
||||
final class ImapResource implements ImapResourceInterface
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $resource;
|
||||
private ?MailboxInterface $mailbox = null;
|
||||
private Connection $resource;
|
||||
private ?MailboxInterface $mailbox;
|
||||
private static ?string $lastMailboxUsedCache = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Connection|resource $resource
|
||||
*/
|
||||
public function __construct($resource, MailboxInterface $mailbox = null)
|
||||
public function __construct(Connection $resource, MailboxInterface $mailbox = null)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
$this->mailbox = $mailbox;
|
||||
}
|
||||
|
||||
public function getStream()
|
||||
public function getStream(): Connection
|
||||
{
|
||||
if (
|
||||
!$this->resource instanceof Connection
|
||||
&& (false === \is_resource($this->resource) || 'imap' !== \get_resource_type($this->resource))
|
||||
) {
|
||||
throw new InvalidResourceException('Supplied resource is not a valid imap resource');
|
||||
}
|
||||
|
||||
$this->initMailbox();
|
||||
|
||||
return $this->resource;
|
||||
@@ -76,10 +63,8 @@ final class ImapResource implements ImapResourceInterface
|
||||
|
||||
/**
|
||||
* Check whether the current mailbox is open.
|
||||
*
|
||||
* @param resource $resource
|
||||
*/
|
||||
private static function isMailboxOpen(MailboxInterface $mailbox, $resource): bool
|
||||
private static function isMailboxOpen(MailboxInterface $mailbox, Connection $resource): bool
|
||||
{
|
||||
$currentMailboxName = $mailbox->getFullEncodedName();
|
||||
if ($currentMailboxName === self::$lastMailboxUsedCache) {
|
||||
|
||||
@@ -4,18 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ddeboer\Imap;
|
||||
|
||||
use Ddeboer\Imap\Exception\InvalidResourceException;
|
||||
use IMAP\Connection;
|
||||
|
||||
interface ImapResourceInterface
|
||||
{
|
||||
/**
|
||||
* Get IMAP resource stream.
|
||||
*
|
||||
* @throws InvalidResourceException
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
public function getStream();
|
||||
public function getStream(): Connection;
|
||||
|
||||
/**
|
||||
* Clear last mailbox used cache.
|
||||
|
||||
+19
-6
@@ -4,12 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ddeboer\Imap;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Ddeboer\Imap\Exception\ImapNumMsgException;
|
||||
use Ddeboer\Imap\Exception\ImapStatusException;
|
||||
use Ddeboer\Imap\Exception\InvalidSearchCriteriaException;
|
||||
use Ddeboer\Imap\Exception\MessageCopyException;
|
||||
use Ddeboer\Imap\Exception\MessageMoveException;
|
||||
use Ddeboer\Imap\Exception\RenameMailboxException;
|
||||
use Ddeboer\Imap\Search\ConditionInterface;
|
||||
use Ddeboer\Imap\Search\LogicalOperator\All;
|
||||
|
||||
@@ -41,6 +41,23 @@ final class Mailbox implements MailboxInterface
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function renameTo(string $name): bool
|
||||
{
|
||||
$encodedName = \mb_convert_encoding($name, 'UTF7-IMAP', 'UTF-8');
|
||||
$oldFullName = $this->getFullEncodedName();
|
||||
$newFullName = \preg_replace('/' . \preg_quote(\mb_convert_encoding($this->name, 'UTF7-IMAP', 'UTF-8')) . '$/', $encodedName, $oldFullName);
|
||||
\assert(null !== $newFullName);
|
||||
|
||||
$return = \imap_renamemailbox($this->resource->getStream(), $oldFullName, $newFullName);
|
||||
if (false === $return) {
|
||||
throw new RenameMailboxException('Could not rename mailbox');
|
||||
}
|
||||
$this->name = $name;
|
||||
$this->info->name = $newFullName;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getEncodedName(): string
|
||||
{
|
||||
/** @var string $name */
|
||||
@@ -104,10 +121,6 @@ final class Mailbox implements MailboxInterface
|
||||
}
|
||||
$query = $search->toString();
|
||||
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$descending = (int) $descending;
|
||||
}
|
||||
|
||||
// We need to clear the stack to know whether imap_last_error()
|
||||
// is related to this imap_search
|
||||
\imap_errors();
|
||||
@@ -178,7 +191,7 @@ final class Mailbox implements MailboxInterface
|
||||
return $this->getMessages();
|
||||
}
|
||||
|
||||
public function addMessage(string $message, string $options = null, DateTimeInterface $internalDate = null): bool
|
||||
public function addMessage(string $message, string $options = null, \DateTimeInterface $internalDate = null): bool
|
||||
{
|
||||
$arguments = [
|
||||
$this->resource->getStream(),
|
||||
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ddeboer\Imap;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Ddeboer\Imap\Message\PartInterface;
|
||||
use Ddeboer\Imap\Search\ConditionInterface;
|
||||
|
||||
@@ -20,6 +19,11 @@ interface MailboxInterface extends \Countable, \IteratorAggregate
|
||||
*/
|
||||
public function getName(): string;
|
||||
|
||||
/**
|
||||
* Set new mailbox name.
|
||||
*/
|
||||
public function renameTo(string $name): bool;
|
||||
|
||||
/**
|
||||
* Get mailbox encoded path.
|
||||
*/
|
||||
@@ -92,7 +96,7 @@ interface MailboxInterface extends \Countable, \IteratorAggregate
|
||||
/**
|
||||
* Add a message to the mailbox.
|
||||
*/
|
||||
public function addMessage(string $message, string $options = null, DateTimeInterface $internalDate = null): bool;
|
||||
public function addMessage(string $message, string $options = null, \DateTimeInterface $internalDate = null): bool;
|
||||
|
||||
/**
|
||||
* Returns a tree of threaded message for the current Mailbox.
|
||||
|
||||
+10
-5
@@ -49,7 +49,7 @@ final class Message extends Message\AbstractMessage implements MessageInterface
|
||||
$errorNumber = 0;
|
||||
\set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
|
||||
$errorMessage = $message;
|
||||
$errorNumber = $nr;
|
||||
$errorNumber = $nr;
|
||||
|
||||
return true;
|
||||
});
|
||||
@@ -80,7 +80,6 @@ final class Message extends Message\AbstractMessage implements MessageInterface
|
||||
}
|
||||
$this->messageNumberVerified = true;
|
||||
|
||||
$msgno = null;
|
||||
\set_error_handler(static function (): bool {
|
||||
return true;
|
||||
});
|
||||
@@ -89,7 +88,7 @@ final class Message extends Message\AbstractMessage implements MessageInterface
|
||||
|
||||
\restore_error_handler();
|
||||
|
||||
if (\is_numeric($msgno) && $msgno > 0) {
|
||||
if ($msgno > 0) {
|
||||
$this->imapMsgNo = $msgno;
|
||||
|
||||
return;
|
||||
@@ -133,6 +132,14 @@ final class Message extends Message\AbstractMessage implements MessageInterface
|
||||
return $this->rawMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource|string $file the path to the saved file as a string, or a valid file descriptor
|
||||
*/
|
||||
public function saveRawMessage($file): void
|
||||
{
|
||||
$this->doSaveContent($file, '');
|
||||
}
|
||||
|
||||
public function getHeaders(): Message\Headers
|
||||
{
|
||||
if (null === $this->headers) {
|
||||
@@ -198,8 +205,6 @@ final class Message extends Message\AbstractMessage implements MessageInterface
|
||||
|
||||
public function maskAsSeen(): bool
|
||||
{
|
||||
\trigger_error(\sprintf('%s is deprecated and will be removed in 2.0. Use %s::markAsSeen instead.', __METHOD__, __CLASS__), \E_USER_DEPRECATED);
|
||||
|
||||
return $this->markAsSeen();
|
||||
}
|
||||
|
||||
|
||||
@@ -203,23 +203,86 @@ abstract class AbstractMessage extends AbstractPart
|
||||
}
|
||||
|
||||
/**
|
||||
* Get body HTML.
|
||||
* Get first body HTML part.
|
||||
*/
|
||||
final public function getBodyHtml(): ?string
|
||||
{
|
||||
$iterator = new \RecursiveIteratorIterator($this, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$htmlParts = $this->getAllContentsBySubtype(self::SUBTYPE_HTML);
|
||||
|
||||
return $htmlParts[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all contents parts of specific subtype (self::SUBTYPE_HTML or self::SUBTYPE_PLAIN).
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
final public function getAllContentsBySubtype(string $subtype): array
|
||||
{
|
||||
$iterator = new \RecursiveIteratorIterator($this, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$parts = [];
|
||||
/** @var PartInterface $part */
|
||||
foreach ($iterator as $part) {
|
||||
if (self::SUBTYPE_HTML === $part->getSubtype()) {
|
||||
return $part->getDecodedContent();
|
||||
if ($subtype === $part->getSubtype()) {
|
||||
$parts[] = $part->getDecodedContent();
|
||||
}
|
||||
}
|
||||
if (\count($parts) > 0) {
|
||||
return $parts;
|
||||
}
|
||||
|
||||
// If message has no parts and is of right type, return content of message.
|
||||
if ($subtype === $this->getSubtype()) {
|
||||
return [$this->getDecodedContent()];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get body HTML parts.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
final public function getBodyHtmlParts(): array
|
||||
{
|
||||
return $this->getAllContentsBySubtype(self::SUBTYPE_HTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all body HTML parts merged into 1 html.
|
||||
*/
|
||||
final public function getCompleteBodyHtml(): ?string
|
||||
{
|
||||
$htmlParts = $this->getAllContentsBySubtype(self::SUBTYPE_HTML);
|
||||
|
||||
if (1 === \count($htmlParts)) {
|
||||
return $htmlParts[0];
|
||||
}
|
||||
if (0 === \count($htmlParts)) {
|
||||
return null;
|
||||
}
|
||||
\libxml_use_internal_errors(true); // Suppress parse errors, get errors with libxml_get_errors();
|
||||
|
||||
$newDom = new \DOMDocument();
|
||||
|
||||
$newBody = '';
|
||||
$newDom->loadHTML(\implode('', $htmlParts));
|
||||
|
||||
$bodyTags = $newDom->getElementsByTagName('body');
|
||||
|
||||
foreach ($bodyTags as $body) {
|
||||
foreach ($body->childNodes as $node) {
|
||||
$newBody .= $newDom->saveHTML($node);
|
||||
}
|
||||
}
|
||||
|
||||
// If message has no parts and is HTML, return content of message itself.
|
||||
if (self::SUBTYPE_HTML === $this->getSubtype()) {
|
||||
return $this->getDecodedContent();
|
||||
}
|
||||
$newDom = new \DOMDocument();
|
||||
$newDom->loadHTML($newBody);
|
||||
|
||||
return null;
|
||||
$completeHtml = $newDom->saveHTML();
|
||||
|
||||
return false === $completeHtml ? null : $completeHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,19 +290,28 @@ abstract class AbstractMessage extends AbstractPart
|
||||
*/
|
||||
final public function getBodyText(): ?string
|
||||
{
|
||||
$iterator = new \RecursiveIteratorIterator($this, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
foreach ($iterator as $part) {
|
||||
if (self::SUBTYPE_PLAIN === $part->getSubtype()) {
|
||||
return $part->getDecodedContent();
|
||||
}
|
||||
$plainParts = $this->getAllContentsBySubtype(self::SUBTYPE_PLAIN);
|
||||
|
||||
return $plainParts[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all body PLAIN parts merged into 1 string.
|
||||
*
|
||||
* @return null|string Null if message has no PLAIN message parts
|
||||
*/
|
||||
final public function getCompleteBodyText(): ?string
|
||||
{
|
||||
$plainParts = $this->getAllContentsBySubtype(self::SUBTYPE_PLAIN);
|
||||
|
||||
if (1 === \count($plainParts)) {
|
||||
return $plainParts[0];
|
||||
}
|
||||
if (0 === \count($plainParts)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If message has no parts, return content of message itself.
|
||||
if (self::SUBTYPE_PLAIN === $this->getSubtype()) {
|
||||
return $this->getDecodedContent();
|
||||
}
|
||||
|
||||
return null;
|
||||
return \implode("\n", $plainParts);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +341,7 @@ abstract class AbstractMessage extends AbstractPart
|
||||
$attachments[] = $childPart;
|
||||
}
|
||||
if ($childPart->hasChildren()) {
|
||||
$attachments = \array_merge($attachments, self::gatherAttachments($childPart));
|
||||
$attachments = [...$attachments, ...self::gatherAttachments($childPart)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,8 +56,7 @@ abstract class AbstractPart implements PartInterface
|
||||
private ?string $encoding = null;
|
||||
private ?string $disposition = null;
|
||||
private ?string $description = null;
|
||||
/** @var null|int|string */
|
||||
private $bytes;
|
||||
private string|int|null $bytes;
|
||||
private ?string $lines = null;
|
||||
private ?string $content = null;
|
||||
private ?string $decodedContent = null;
|
||||
@@ -256,6 +255,26 @@ abstract class AbstractPart implements PartInterface
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save raw message content to file.
|
||||
*
|
||||
* @param resource|string $file the path to the saved file as a string, or a valid file descriptor
|
||||
*/
|
||||
final protected function doSaveContent($file, string $partNumber): void
|
||||
{
|
||||
$return = \imap_savebody(
|
||||
$this->resource->getStream(),
|
||||
$file,
|
||||
$this->getNumber(),
|
||||
$partNumber,
|
||||
\FT_UID | \FT_PEEK
|
||||
);
|
||||
|
||||
if (false === $return) {
|
||||
throw new ImapFetchbodyException('imap_savebody failed');
|
||||
}
|
||||
}
|
||||
|
||||
final public function getParts(): array
|
||||
{
|
||||
$this->lazyParseStructure();
|
||||
@@ -265,8 +284,6 @@ abstract class AbstractPart implements PartInterface
|
||||
|
||||
/**
|
||||
* Get current child part.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
final public function current()
|
||||
@@ -360,7 +377,7 @@ abstract class AbstractPart implements PartInterface
|
||||
|
||||
// When the message is not multipart and the body is the attachment content
|
||||
// Prevents infinite recursion
|
||||
if (self::isAttachment($this->structure) && !$this instanceof Attachment) {
|
||||
if (!$this instanceof Attachment && self::isAttachment($this->structure)) {
|
||||
$this->parts[] = new Attachment($this->resource, $this->getNumber(), '1', $this->structure);
|
||||
}
|
||||
|
||||
@@ -372,12 +389,11 @@ abstract class AbstractPart implements PartInterface
|
||||
}
|
||||
foreach ($parts as $key => $partStructure) {
|
||||
$partNumber = (!$this instanceof Message) ? $this->partNumber . '.' : '';
|
||||
$partNumber .= (string) ($key + 1);
|
||||
$partNumber .= $key + 1;
|
||||
|
||||
$newPartClass = self::isAttachment($partStructure)
|
||||
? Attachment::class
|
||||
: SimplePart::class
|
||||
;
|
||||
: SimplePart::class;
|
||||
|
||||
$this->parts[] = new $newPartClass($this->resource, $this->getNumber(), $partNumber, $partStructure);
|
||||
}
|
||||
@@ -400,9 +416,9 @@ abstract class AbstractPart implements PartInterface
|
||||
}
|
||||
|
||||
if (
|
||||
'inline' === \strtolower($part->disposition)
|
||||
'inline' === \strtolower($part->disposition)
|
||||
&& self::SUBTYPE_PLAIN !== \strtoupper($part->subtype)
|
||||
&& self::SUBTYPE_HTML !== \strtoupper($part->subtype)
|
||||
&& self::SUBTYPE_HTML !== \strtoupper($part->subtype)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -427,10 +443,6 @@ abstract class AbstractPart implements PartInterface
|
||||
}
|
||||
*/
|
||||
|
||||
if (self::SUBTYPE_RFC822 === \strtoupper($part->subtype)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return self::SUBTYPE_RFC822 === \strtoupper($part->subtype);
|
||||
}
|
||||
}
|
||||
+36
-1
@@ -18,6 +18,13 @@ interface BasicMessageInterface extends PartInterface
|
||||
*/
|
||||
public function getRawMessage(): string;
|
||||
|
||||
/**
|
||||
* Save the raw message, including all headers, parts, etc. unencoded and unparsed to file.
|
||||
*
|
||||
* @param resource|string $file the path to the saved file as a string, or a valid file descriptor
|
||||
*/
|
||||
public function saveRawMessage($file): void;
|
||||
|
||||
/**
|
||||
* Get message headers.
|
||||
*/
|
||||
@@ -109,17 +116,45 @@ interface BasicMessageInterface extends PartInterface
|
||||
public function getReferences(): array;
|
||||
|
||||
/**
|
||||
* Get body HTML.
|
||||
* Get message parts by type.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAllContentsBySubtype(string $subtype): array;
|
||||
|
||||
/**
|
||||
* Get first body HTML part.
|
||||
*
|
||||
* @return null|string Null if message has no HTML message part
|
||||
*/
|
||||
public function getBodyHtml(): ?string;
|
||||
|
||||
/**
|
||||
* Get all body HTML parts as array.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getBodyHtmlParts(): array;
|
||||
|
||||
/**
|
||||
* Get all body HTML parts merged into 1 html.
|
||||
*
|
||||
* @return null|string Null if message has no HTML message parts
|
||||
*/
|
||||
public function getCompleteBodyHtml(): ?string;
|
||||
|
||||
/**
|
||||
* Get body text.
|
||||
*/
|
||||
public function getBodyText(): ?string;
|
||||
|
||||
/**
|
||||
* Get all body PLAIN parts merged into 1 string.
|
||||
*
|
||||
* @return null|string Null if message has no PLAIN message parts
|
||||
*/
|
||||
public function getCompleteBodyText(): ?string;
|
||||
|
||||
/**
|
||||
* Get attachments (if any) linked to this e-mail.
|
||||
*
|
||||
|
||||
@@ -38,6 +38,14 @@ final class EmbeddedMessage extends AbstractMessage implements EmbeddedMessageIn
|
||||
return $this->rawMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource|string $file the path to the saved file as a string, or a valid file descriptor
|
||||
*/
|
||||
public function saveRawMessage($file): void
|
||||
{
|
||||
$this->doSaveContent($file, $this->getPartNumber());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content part number.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ddeboer\Imap\Message;
|
||||
|
||||
use Ddeboer\Imap\Exception\UnsupportedCharsetException;
|
||||
|
||||
final class Headers extends Parameters
|
||||
{
|
||||
public function __construct(\stdClass $headers)
|
||||
@@ -14,7 +16,11 @@ final class Headers extends Parameters
|
||||
$headers = \array_change_key_case((array) $headers);
|
||||
|
||||
foreach ($headers as $key => $value) {
|
||||
$this[$key] = $this->parseHeader($key, $value);
|
||||
try {
|
||||
$this[$key] = $this->parseHeader($key, $value);
|
||||
} catch (UnsupportedCharsetException) {
|
||||
// safely skip header with unsupported charset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +56,6 @@ final class Headers extends Parameters
|
||||
case 'sender':
|
||||
case 'return_path':
|
||||
\assert(\is_array($value));
|
||||
/** @var \stdClass $address */
|
||||
foreach ($value as $address) {
|
||||
if (isset($address->mailbox)) {
|
||||
$address->host = $address->host ?? null;
|
||||
|
||||
@@ -304,7 +304,7 @@ final class Transcoder
|
||||
$errorNumber = 0;
|
||||
\set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
|
||||
$errorMessage = $message;
|
||||
$errorNumber = $nr;
|
||||
$errorNumber = $nr;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -39,8 +39,8 @@ final class MessageIterator extends \ArrayIterator implements MessageIteratorInt
|
||||
'The current value "%s" isn\'t an integer and doesn\'t represent a message;'
|
||||
. ' try to cycle this "%s" with a native php function like foreach or with the method getArrayCopy(),'
|
||||
. ' or check it by calling the methods valid().',
|
||||
\is_object($current) ? \get_class($current) : \gettype($current),
|
||||
static::class
|
||||
\get_debug_type($current),
|
||||
self::class
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ddeboer\Imap\Search;
|
||||
|
||||
use DateTimeInterface;
|
||||
|
||||
/**
|
||||
* Represents a date condition.
|
||||
*/
|
||||
@@ -19,14 +17,14 @@ abstract class AbstractDate implements ConditionInterface
|
||||
/**
|
||||
* The date to be used for the condition.
|
||||
*/
|
||||
private DateTimeInterface $date;
|
||||
private \DateTimeInterface $date;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param DateTimeInterface $date optional date for the condition
|
||||
* @param \DateTimeInterface $date optional date for the condition
|
||||
*/
|
||||
public function __construct(DateTimeInterface $date, string $dateFormat = 'j-M-Y')
|
||||
public function __construct(\DateTimeInterface $date, string $dateFormat = 'j-M-Y')
|
||||
{
|
||||
$this->date = $date;
|
||||
$this->dateFormat = $dateFormat;
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ final class Server implements ServerInterface
|
||||
$errorNumber = 0;
|
||||
\set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
|
||||
$errorMessage = $message;
|
||||
$errorNumber = $nr;
|
||||
$errorNumber = $nr;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user