From 682b25dbb1a36f2e88fec9416f6bc07ceab61db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Sat, 10 Apr 2021 13:04:54 +0200 Subject: [PATCH 01/13] Update Mailbox.php Adding support for "original" Filename. $mailbox->setAttachmentsFilenameMode(Mailbox::ATTACH_FILE_NAMERANDOM); # filename by random (old way) $mailbox->setAttachmentsFilenameMode(Mailbox::ATTACH_FILE_NAMEORIGINAL); # filename by email --- src/PhpImap/Mailbox.php | 319 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 314 insertions(+), 5 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index a50befbf..e77d39bf 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -112,6 +112,9 @@ class Mailbox /** @var string */ protected $imapPassword; + + + /** @var int */ protected $imapSearchOption = SE_UID; @@ -155,10 +158,21 @@ class Mailbox /** @var string */ protected $mailboxFolder; + public const ATTACH_FILE_NAMERANDOM = 1; // Filename is unique (random) + public const ATTACH_FILE_NAMEORIGINAL = 2; // Filename is Attachment-Filename + /** @var int */ + protected $attachmentsFilenameMode = ATTACH_FILE_NAMERANDOM; + /** @var resource|null */ private $imapStream; /** + + + + + + * @throws InvalidParameterException */ public function __construct(string $imapPath, string $login, string $password, string $attachmentsDir = null, string $serverEncoding = 'UTF-8') @@ -183,10 +197,47 @@ public function __destruct() } /** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Sets / Changes the path delimiter character (Supported values: '.', '/'). * * @param string $delimiter Path delimiter * + + * @throws InvalidParameterException */ public function setPathDelimiter(string $delimiter): void @@ -241,6 +292,8 @@ public function getServerEncoding(): string * * @param string $serverEncoding Server encoding (eg. 'UTF-8') * + + * @throws InvalidParameterException */ public function setServerEncoding(string $serverEncoding): void @@ -273,6 +326,8 @@ public function getImapSearchOption(): int * * @psalm-param 1|2 $imapSearchOption * + + * @throws InvalidParameterException */ public function setImapSearchOption(int $imapSearchOption): void @@ -288,12 +343,37 @@ public function setImapSearchOption(int $imapSearchOption): void /** * Set $this->attachmentsIgnore param. Allow to ignore attachments when they are not required and boost performance. + + + + + + + + + */ public function setAttachmentsIgnore(bool $attachmentsIgnore): void { + + + $this->attachmentsIgnore = $attachmentsIgnore; } - + + /** + * Set $this->setAttachmentsRandomFilename param. + * + * @param int $random ATTACH_FILE_NAMERANDOM, ATTACH_FILE_NAMEORIGINAL + * + * @return Mailbox + */ + public function setAttachmentsFilenameMode(int $mode) : Mailbox + { + $this->attachmentsFilenameMode = $mode; + return $this; + } + /** * Get $this->attachmentsIgnore param. * @@ -312,6 +392,8 @@ public function getAttachmentsIgnore(): bool * * @psalm-param list<1|2|3|4> $types * + + * @throws InvalidParameterException */ public function setTimeouts(int $timeout, array $types = [IMAP_OPENTIMEOUT, IMAP_READTIMEOUT, IMAP_WRITETIMEOUT, IMAP_CLOSETIMEOUT]): void @@ -341,16 +423,23 @@ public function getLogin(): string /** * Set custom connection arguments of imap_open method. See http://php.net/imap_open. * + + * @param string[]|null $params * * @psalm-param array{DISABLE_AUTHENTICATOR?:string}|array|null $params * + + * @throws InvalidParameterException + + */ public function setConnectionArgs(int $options = 0, int $retriesNum = 0, array $params = null): void { if (0 !== $options) { if (($options & self::IMAP_OPTIONS_SUPPORTED_VALUES) !== $options) { + throw new InvalidParameterException('Please check your option for setConnectionArgs()! Unsupported option "'.$options.'". Available options: https://www.php.net/manual/de/function.imap-open.php'); } $this->imapOptions = $options; @@ -382,6 +471,8 @@ public function setConnectionArgs(int $options = 0, int $retriesNum = 0, array $ * * @param string $attachmentsDir Folder where to save attachments * + + * @throws InvalidParameterException */ public function setAttachmentsDir(string $attachmentsDir): void @@ -407,6 +498,10 @@ public function getAttachmentsDir(): ?string /** * Sets / Changes the attempts / retries to connect. + + + + */ public function setConnectionRetry(int $maxAttempts): void { @@ -415,6 +510,10 @@ public function setConnectionRetry(int $maxAttempts): void /** * Sets / Changes the delay between each attempt / retry to connect. + + + + */ public function setConnectionRetryDelay(int $milliseconds): void { @@ -441,6 +540,7 @@ public function getImapStream(bool $forceConnection = true) return $this->imapStream; } + public function hasImapStream(): bool { return \is_resource($this->imapStream) && \imap_ping($this->imapStream); @@ -449,14 +549,20 @@ public function hasImapStream(): bool /** * Returns the provided string in UTF7-IMAP encoded format. * + + * @return string $str UTF-7 encoded string */ public function encodeStringToUtf7Imap(string $str): string { + $out = \mb_convert_encoding($str, 'UTF7-IMAP', \mb_detect_encoding($str, 'UTF-8, ISO-8859-1, ISO-8859-15', true)); if (!\is_string($out)) { throw new UnexpectedValueException('mb_convert_encoding($str, \'UTF-8\', {detected}) could not convert $str'); + + + } return $out; @@ -465,10 +571,15 @@ public function encodeStringToUtf7Imap(string $str): string /** * Returns the provided string in UTF-8 encoded format. * + + * @return string $str UTF-7 encoded string or same as before, when it's no string + + */ public function decodeStringFromUtf7ImapToUtf8(string $str): string { + $out = \mb_convert_encoding($str, 'UTF-8', 'UTF7-IMAP'); if (!\is_string($out)) { @@ -490,6 +601,11 @@ public function setMailboxFolder(): void /** * Switch mailbox without opening a new connection. * + + + + + * @throws Exception */ public function switchMailbox(string $imapPath, bool $absolute = true): void @@ -507,6 +623,8 @@ public function switchMailbox(string $imapPath, bool $absolute = true): void /** * Disconnects from IMAP server / mailbox. + + */ public function disconnect(): void { @@ -517,6 +635,10 @@ public function disconnect(): void /** * Sets 'expunge on disconnect' parameter. + + + + */ public function setExpungeOnDisconnect(bool $isEnabled): void { @@ -534,6 +656,8 @@ public function setExpungeOnDisconnect(bool $isEnabled): void * Recent - number of recent mails in the mailbox * * @see imap_check + + */ public function checkMailbox(): object { @@ -545,6 +669,8 @@ public function checkMailbox(): object * * @param string $name Name of new mailbox (eg. 'PhpImap') * + + * @see imap_createmailbox() */ public function createMailbox(string $name): void @@ -556,7 +682,10 @@ public function createMailbox(string $name): void * Deletes a specific mailbox. * * @param string $name Name of mailbox, which you want to delete (eg. 'PhpImap') + * + + * @see imap_deletemailbox() */ public function deleteMailbox(string $name, bool $absolute = false): bool @@ -569,6 +698,8 @@ public function deleteMailbox(string $name, bool $absolute = false): bool * * @param string $oldName Current name of mailbox, which you want to rename (eg. 'PhpImap') * @param string $newName New name of mailbox, to which you want to rename it (eg. 'PhpImapTests') + + */ public function renameMailbox(string $oldName, string $newName): void { @@ -580,6 +711,8 @@ public function renameMailbox(string $oldName, string $newName): void * * This function returns an object containing status information. * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity. + + */ public function statusMailbox(): object { @@ -592,6 +725,8 @@ public function statusMailbox(): object * This function returns an object containing listing the folders. * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity. * + + * @return array listing the folders */ public function getListingFolders(string $pattern = '*'): array @@ -624,6 +759,10 @@ public function searchMailbox(string $criteria = 'ALL', bool $disableServerEncod /** * Search the mailbox for emails from multiple, specific senders. * + + + + * @see Mailbox::searchMailboxFromWithOrWithoutDisablingServerEncoding() * * @return int[] @@ -638,6 +777,10 @@ public function searchMailboxFrom(string $criteria, string $sender, string ...$s /** * Search the mailbox for emails from multiple, specific senders whilst not using server encoding. * + + + + * @see Mailbox::searchMailboxFromWithOrWithoutDisablingServerEncoding() * * @return int[] @@ -683,7 +826,10 @@ public function searchMailboxMergeResultsDisableServerEncoding($single_criteria, * Save a specific body section to a file. * * @param int $mailId message number + * + + * @see imap_savebody() */ public function saveMail(int $mailId, string $filename = 'email.eml'): void @@ -696,6 +842,8 @@ public function saveMail(int $mailId, string $filename = 'email.eml'): void * * @param int $mailId message number * + + * @see imap_delete() */ public function deleteMail(int $mailId): void @@ -710,6 +858,8 @@ public function deleteMail(int $mailId): void * @param string $mailBox Mailbox name * * @see imap_mail_move() + + */ public function moveMail($mailId, string $mailBox): void { @@ -723,6 +873,8 @@ public function moveMail($mailId, string $mailBox): void * @param string|int $mailId a range or message number * @param string $mailBox Mailbox name * + + * @see imap_mail_copy() */ public function copyMail($mailId, string $mailBox): void @@ -734,6 +886,8 @@ public function copyMail($mailId, string $mailBox): void /** * Deletes all the mails marked for deletion by imap_delete(), imap_mail_move(), or imap_setflag_full(). * + + * @see imap_expunge() */ public function expungeDeletedMails(): void @@ -743,6 +897,10 @@ public function expungeDeletedMails(): void /** * Add the flag \Seen to a mail. + + + + */ public function markMailAsRead(int $mailId): void { @@ -751,6 +909,10 @@ public function markMailAsRead(int $mailId): void /** * Remove the flag \Seen from a mail. + + + + */ public function markMailAsUnread(int $mailId): void { @@ -759,6 +921,10 @@ public function markMailAsUnread(int $mailId): void /** * Add the flag \Flagged to a mail. + + + + */ public function markMailAsImportant(int $mailId): void { @@ -771,6 +937,8 @@ public function markMailAsImportant(int $mailId): void * @param int[] $mailId * * @psalm-param list $mailId + + */ public function markMailsAsRead(array $mailId): void { @@ -783,6 +951,8 @@ public function markMailsAsRead(array $mailId): void * @param int[] $mailId * * @psalm-param list $mailId + + */ public function markMailsAsUnread(array $mailId): void { @@ -795,6 +965,8 @@ public function markMailsAsUnread(array $mailId): void * @param int[] $mailId * * @psalm-param list $mailId + + */ public function markMailsAsImportant(array $mailId): void { @@ -819,6 +991,8 @@ public function setFlag(array $mailsIds, string $flag): void * * @param array $mailsIds Array of mail IDs * @param string $flag Which you can delete are \Seen, \Answered, \Flagged, \Deleted, and \Draft as defined by RFC2060 + + */ public function clearFlag(array $mailsIds, string $flag): void { @@ -899,6 +1073,8 @@ public function getMailsInfo(array $mailsIds): array * returns an array of string formatted with header info, * one element per mail message. * + + * @see imap_headers() */ public function getMailboxHeaders(): array @@ -943,6 +1119,7 @@ public function getMailboxInfo(): object * @param int $criteria Sorting criteria (eg. SORTARRIVAL) * @param bool $reverse Sort reverse or not * @param string|null $searchCriteria See http://php.net/imap_search for a complete list of available criteria + * * @psalm-param value-of $criteria * @psalm-param 1|5|0|2|6|3|4 $criteria @@ -968,6 +1145,8 @@ public function sortMails( /** * Get mails count in mail box. * + + * @see imap_num_msg() */ public function countMails(): int @@ -979,6 +1158,8 @@ public function countMails(): int * Return quota limit in KB. * * @param string $quota_root Should normally be in the form of which mailbox (i.e. INBOX) + + */ public function getQuotaLimit(string $quota_root = 'INBOX'): int { @@ -1026,6 +1207,8 @@ public function getRawMail(int $msgId, bool $markAsSeen = true): string * * @param int $mailId ID of the message * + + * @throws Exception * * @todo update type checking pending resolution of https://github.com/vimeo/psalm/issues/2619 @@ -1174,6 +1357,9 @@ public function getMailHeader(int $mailId): IncomingMailHeader * * @param stdClass[] $messageParts * @param stdClass[] $flattenedParts + + + * * @psalm-param array $flattenedParts * @@ -1213,6 +1399,8 @@ public function flattenParts(array $messageParts, array $flattenedParts = [], st * * @param int $mailId ID of the mail * @param bool $markAsSeen Mark the email as seen, when set to true + + */ public function getMail(int $mailId, bool $markAsSeen = true): IncomingMail { @@ -1243,12 +1431,15 @@ public function getMail(int $mailId, bool $markAsSeen = true): IncomingMail * * @param array $params Array of params of mail * @param object $partStructure Part of mail + * @param bool $emlOrigin True, if it indicates, that the attachment comes from an EML (mail) file * * @psalm-param array $params * @psalm-param PARTSTRUCTURE $partStructure * * @return IncomingMailAttachment $attachment + + */ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object $partStructure, bool $emlOrigin = false): IncomingMailAttachment { @@ -1314,14 +1505,23 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object $attachmentsDir = $this->getAttachmentsDir(); - if (null != $attachmentsDir) { - $fileSysName = \bin2hex(\random_bytes(16)).'.bin'; + if (null !== $attachmentsDir) { + switch($this->attachmentsFilenameMode) { + case self::ATTACH_FILE_NAMEORIGINAL: + $fileSysName = $fileName; + break; + case self::ATTACH_FILE_NAMERANDOM: + default: + $fileSysName = \bin2hex(\random_bytes(16)).'.bin'; + } + $filePath = $attachmentsDir.DIRECTORY_SEPARATOR.$fileSysName; - if (\strlen($filePath) > self::MAX_LENGTH_FILEPATH) { + if (\strlen($filePath) > 255) { $ext = \pathinfo($filePath, PATHINFO_EXTENSION); - $filePath = \substr($filePath, 0, self::MAX_LENGTH_FILEPATH - 1 - \strlen($ext)).'.'.$ext; + $filePath = \substr($filePath, 0, 255 - 1 - \strlen($ext)).'.'.$ext; } + $attachment->setFilePath($filePath); $attachment->saveToDisk(); } @@ -1333,6 +1533,7 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object * Decodes a mime string. * * @param string $string MIME string to decode + * * @return string Converted string if conversion was successful, or the original string if not * @@ -1342,6 +1543,10 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object */ public function decodeMimeStr(string $string): string { + + + + $newString = ''; /** @var list|false */ $elements = \imap_mime_header_decode($string); @@ -1385,6 +1590,11 @@ public function decodeMimeStr(string $string): string } public function isUrlEncoded(string $string): bool + + + + + { $hasInvalidChars = \preg_match('#[^%a-zA-Z0-9\-_\.\+]#', $string); $hasEscapedChars = \preg_match('#%[a-zA-Z0-9]{2}#', $string); @@ -1422,7 +1632,36 @@ public function parseDateTime(string $dateHeader): string } /** + + + + + + + + + + + + + + + + + + + + + + + + + + + * Gets IMAP path. + + */ public function getImapPath(): string { @@ -1433,6 +1672,8 @@ public function getImapPath(): string * Get message in MBOX format. * * @param int $mailId message number + + */ public function getMailMboxFormat(int $mailId): string { @@ -1443,6 +1684,10 @@ public function getMailMboxFormat(int $mailId): string /** * Get folders list. + + + + */ public function getMailboxes(string $search = '*'): array { @@ -1454,6 +1699,10 @@ public function getMailboxes(string $search = '*'): array /** * Get folders list. + + + + */ public function getSubscribedMailboxes(string $search = '*'): array { @@ -1466,6 +1715,10 @@ public function getSubscribedMailboxes(string $search = '*'): array /** * Subscribe to a mailbox. * + + + + * @throws Exception */ public function subscribeMailbox(string $mailbox): void @@ -1479,6 +1732,10 @@ public function subscribeMailbox(string $mailbox): void /** * Unsubscribe from a mailbox. * + + + + * @throws Exception */ public function unsubscribeMailbox(string $mailbox): void @@ -1493,6 +1750,9 @@ public function unsubscribeMailbox(string $mailbox): void * Appends $message to $mailbox. * * @param string|array $message + + + * * @psalm-param string|array{0:COMPOSE_ENVELOPE, 1:COMPOSE_BODY} $message * @@ -1538,9 +1798,27 @@ protected function lowercase_mb_list_encodings() $encodings = \mb_list_encodings(); foreach ($encodings as $encoding) { $lowercase_encodings[] = \strtolower($encoding); + + + + + + + + + + + + + + } return $lowercase_encodings; + + + + } /** @return resource */ @@ -1564,6 +1842,8 @@ protected function initImapStreamWithRetry() * @param string $quota_root Should normally be in the form of which mailbox (i.e. INBOX) * * @see imap_get_quotaroot() + + */ protected function getQuota(string $quota_root = 'INBOX'): array { @@ -1596,10 +1876,15 @@ protected function initImapStream() } /** + * @param string|0 $partNum + + * * @psalm-param PARTSTRUCTURE $partStructure * + + * @todo refactor type checking pending resolution of https://github.com/vimeo/psalm/issues/2619 */ protected function initMailPart(IncomingMail $mail, object $partStructure, $partNum, bool $markAsSeen = true, bool $emlParse = false): void @@ -1725,9 +2010,16 @@ protected function initMailPart(IncomingMail $mail, object $partStructure, $part } } + + + + + + protected function decodeRFC2231(string $string): string { if (\preg_match("/^(.*?)'.*?'(.*?)$/", $string, $matches)) { + $data = $matches[2]; if ($this->isUrlEncoded($data)) { $string = $this->decodeMimeStr(\urldecode($data)); @@ -1768,6 +2060,10 @@ protected function getCombinedPath(string $folder, bool $absolute = false): stri } /** + + + + * @psalm-return array{0:string, 1:string|null}|null */ protected function possiblyGetEmailAndNameFromRecipient(object $recipient): ?array @@ -1807,6 +2103,8 @@ protected function possiblyGetEmailAndNameFromRecipient(object $recipient): ?arr /** * @psalm-param array $t * + + * @todo revisit implementation pending resolution of https://github.com/vimeo/psalm/issues/2619 */ protected function possiblyGetMailboxes(array $t): array @@ -1820,6 +2118,8 @@ protected function possiblyGetMailboxes(array $t): array /** @var scalar|array|object|resource|null */ $item_name = isset($item->name) ? $item->name : null; + + if (!isset($item->name, $item->attributes, $item->delimiter)) { throw new UnexpectedValueException('The object at index '.(string) $index.' of argument 1 passed to '.__METHOD__.'() was missing one or more of the required properties "name", "attributes", "delimiter"!'); } elseif (!\is_string($item_name)) { @@ -1847,6 +2147,8 @@ protected function possiblyGetMailboxes(array $t): array /** * @psalm-param HOSTNAMEANDADDRESS $t * + + * @psalm-return array{0:string|null, 1:string|null, 2:string} */ protected function possiblyGetHostNameAndAddress(array $t): array @@ -1872,6 +2174,8 @@ protected function possiblyGetHostNameAndAddress(array $t): array } /** + + * @todo revisit redundant condition issues pending fix of https://github.com/vimeo/psalm/issues/2626 */ protected function pingOrDisconnect(): void @@ -1885,6 +2189,11 @@ protected function pingOrDisconnect(): void /** * Search the mailbox for emails from multiple, specific senders. * + + + + + * This function wraps Mailbox::searchMailbox() to overcome a shortcoming in ext-imap * * @return int[] From 9f6ff93544fd3957188ce1ff0e63eecc0f5c4b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Sat, 10 Apr 2021 13:06:57 +0200 Subject: [PATCH 02/13] Update Mailbox.php --- src/PhpImap/Mailbox.php | 283 ---------------------------------------- 1 file changed, 283 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index e77d39bf..5b827717 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -112,9 +112,6 @@ class Mailbox /** @var string */ protected $imapPassword; - - - /** @var int */ protected $imapSearchOption = SE_UID; @@ -162,17 +159,10 @@ class Mailbox public const ATTACH_FILE_NAMEORIGINAL = 2; // Filename is Attachment-Filename /** @var int */ protected $attachmentsFilenameMode = ATTACH_FILE_NAMERANDOM; - /** @var resource|null */ private $imapStream; /** - - - - - - * @throws InvalidParameterException */ public function __construct(string $imapPath, string $login, string $password, string $attachmentsDir = null, string $serverEncoding = 'UTF-8') @@ -197,47 +187,10 @@ public function __destruct() } /** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Sets / Changes the path delimiter character (Supported values: '.', '/'). * * @param string $delimiter Path delimiter * - - * @throws InvalidParameterException */ public function setPathDelimiter(string $delimiter): void @@ -292,8 +245,6 @@ public function getServerEncoding(): string * * @param string $serverEncoding Server encoding (eg. 'UTF-8') * - - * @throws InvalidParameterException */ public function setServerEncoding(string $serverEncoding): void @@ -326,8 +277,6 @@ public function getImapSearchOption(): int * * @psalm-param 1|2 $imapSearchOption * - - * @throws InvalidParameterException */ public function setImapSearchOption(int $imapSearchOption): void @@ -343,21 +292,9 @@ public function setImapSearchOption(int $imapSearchOption): void /** * Set $this->attachmentsIgnore param. Allow to ignore attachments when they are not required and boost performance. - - - - - - - - - */ public function setAttachmentsIgnore(bool $attachmentsIgnore): void { - - - $this->attachmentsIgnore = $attachmentsIgnore; } @@ -392,8 +329,6 @@ public function getAttachmentsIgnore(): bool * * @psalm-param list<1|2|3|4> $types * - - * @throws InvalidParameterException */ public function setTimeouts(int $timeout, array $types = [IMAP_OPENTIMEOUT, IMAP_READTIMEOUT, IMAP_WRITETIMEOUT, IMAP_CLOSETIMEOUT]): void @@ -423,23 +358,16 @@ public function getLogin(): string /** * Set custom connection arguments of imap_open method. See http://php.net/imap_open. * - - * @param string[]|null $params * * @psalm-param array{DISABLE_AUTHENTICATOR?:string}|array|null $params * - - * @throws InvalidParameterException - - */ public function setConnectionArgs(int $options = 0, int $retriesNum = 0, array $params = null): void { if (0 !== $options) { if (($options & self::IMAP_OPTIONS_SUPPORTED_VALUES) !== $options) { - throw new InvalidParameterException('Please check your option for setConnectionArgs()! Unsupported option "'.$options.'". Available options: https://www.php.net/manual/de/function.imap-open.php'); } $this->imapOptions = $options; @@ -471,8 +399,6 @@ public function setConnectionArgs(int $options = 0, int $retriesNum = 0, array $ * * @param string $attachmentsDir Folder where to save attachments * - - * @throws InvalidParameterException */ public function setAttachmentsDir(string $attachmentsDir): void @@ -498,10 +424,6 @@ public function getAttachmentsDir(): ?string /** * Sets / Changes the attempts / retries to connect. - - - - */ public function setConnectionRetry(int $maxAttempts): void { @@ -510,10 +432,6 @@ public function setConnectionRetry(int $maxAttempts): void /** * Sets / Changes the delay between each attempt / retry to connect. - - - - */ public function setConnectionRetryDelay(int $milliseconds): void { @@ -540,7 +458,6 @@ public function getImapStream(bool $forceConnection = true) return $this->imapStream; } - public function hasImapStream(): bool { return \is_resource($this->imapStream) && \imap_ping($this->imapStream); @@ -549,20 +466,14 @@ public function hasImapStream(): bool /** * Returns the provided string in UTF7-IMAP encoded format. * - - * @return string $str UTF-7 encoded string */ public function encodeStringToUtf7Imap(string $str): string { - $out = \mb_convert_encoding($str, 'UTF7-IMAP', \mb_detect_encoding($str, 'UTF-8, ISO-8859-1, ISO-8859-15', true)); if (!\is_string($out)) { throw new UnexpectedValueException('mb_convert_encoding($str, \'UTF-8\', {detected}) could not convert $str'); - - - } return $out; @@ -571,15 +482,10 @@ public function encodeStringToUtf7Imap(string $str): string /** * Returns the provided string in UTF-8 encoded format. * - - * @return string $str UTF-7 encoded string or same as before, when it's no string - - */ public function decodeStringFromUtf7ImapToUtf8(string $str): string { - $out = \mb_convert_encoding($str, 'UTF-8', 'UTF7-IMAP'); if (!\is_string($out)) { @@ -601,11 +507,6 @@ public function setMailboxFolder(): void /** * Switch mailbox without opening a new connection. * - - - - - * @throws Exception */ public function switchMailbox(string $imapPath, bool $absolute = true): void @@ -623,8 +524,6 @@ public function switchMailbox(string $imapPath, bool $absolute = true): void /** * Disconnects from IMAP server / mailbox. - - */ public function disconnect(): void { @@ -635,10 +534,6 @@ public function disconnect(): void /** * Sets 'expunge on disconnect' parameter. - - - - */ public function setExpungeOnDisconnect(bool $isEnabled): void { @@ -656,8 +551,6 @@ public function setExpungeOnDisconnect(bool $isEnabled): void * Recent - number of recent mails in the mailbox * * @see imap_check - - */ public function checkMailbox(): object { @@ -669,8 +562,6 @@ public function checkMailbox(): object * * @param string $name Name of new mailbox (eg. 'PhpImap') * - - * @see imap_createmailbox() */ public function createMailbox(string $name): void @@ -682,10 +573,7 @@ public function createMailbox(string $name): void * Deletes a specific mailbox. * * @param string $name Name of mailbox, which you want to delete (eg. 'PhpImap') - * - - * @see imap_deletemailbox() */ public function deleteMailbox(string $name, bool $absolute = false): bool @@ -698,8 +586,6 @@ public function deleteMailbox(string $name, bool $absolute = false): bool * * @param string $oldName Current name of mailbox, which you want to rename (eg. 'PhpImap') * @param string $newName New name of mailbox, to which you want to rename it (eg. 'PhpImapTests') - - */ public function renameMailbox(string $oldName, string $newName): void { @@ -711,8 +597,6 @@ public function renameMailbox(string $oldName, string $newName): void * * This function returns an object containing status information. * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity. - - */ public function statusMailbox(): object { @@ -725,8 +609,6 @@ public function statusMailbox(): object * This function returns an object containing listing the folders. * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity. * - - * @return array listing the folders */ public function getListingFolders(string $pattern = '*'): array @@ -759,10 +641,6 @@ public function searchMailbox(string $criteria = 'ALL', bool $disableServerEncod /** * Search the mailbox for emails from multiple, specific senders. * - - - - * @see Mailbox::searchMailboxFromWithOrWithoutDisablingServerEncoding() * * @return int[] @@ -777,10 +655,6 @@ public function searchMailboxFrom(string $criteria, string $sender, string ...$s /** * Search the mailbox for emails from multiple, specific senders whilst not using server encoding. * - - - - * @see Mailbox::searchMailboxFromWithOrWithoutDisablingServerEncoding() * * @return int[] @@ -826,10 +700,7 @@ public function searchMailboxMergeResultsDisableServerEncoding($single_criteria, * Save a specific body section to a file. * * @param int $mailId message number - * - - * @see imap_savebody() */ public function saveMail(int $mailId, string $filename = 'email.eml'): void @@ -842,8 +713,6 @@ public function saveMail(int $mailId, string $filename = 'email.eml'): void * * @param int $mailId message number * - - * @see imap_delete() */ public function deleteMail(int $mailId): void @@ -858,8 +727,6 @@ public function deleteMail(int $mailId): void * @param string $mailBox Mailbox name * * @see imap_mail_move() - - */ public function moveMail($mailId, string $mailBox): void { @@ -873,8 +740,6 @@ public function moveMail($mailId, string $mailBox): void * @param string|int $mailId a range or message number * @param string $mailBox Mailbox name * - - * @see imap_mail_copy() */ public function copyMail($mailId, string $mailBox): void @@ -886,8 +751,6 @@ public function copyMail($mailId, string $mailBox): void /** * Deletes all the mails marked for deletion by imap_delete(), imap_mail_move(), or imap_setflag_full(). * - - * @see imap_expunge() */ public function expungeDeletedMails(): void @@ -897,10 +760,6 @@ public function expungeDeletedMails(): void /** * Add the flag \Seen to a mail. - - - - */ public function markMailAsRead(int $mailId): void { @@ -909,10 +768,6 @@ public function markMailAsRead(int $mailId): void /** * Remove the flag \Seen from a mail. - - - - */ public function markMailAsUnread(int $mailId): void { @@ -921,10 +776,6 @@ public function markMailAsUnread(int $mailId): void /** * Add the flag \Flagged to a mail. - - - - */ public function markMailAsImportant(int $mailId): void { @@ -937,8 +788,6 @@ public function markMailAsImportant(int $mailId): void * @param int[] $mailId * * @psalm-param list $mailId - - */ public function markMailsAsRead(array $mailId): void { @@ -951,8 +800,6 @@ public function markMailsAsRead(array $mailId): void * @param int[] $mailId * * @psalm-param list $mailId - - */ public function markMailsAsUnread(array $mailId): void { @@ -965,8 +812,6 @@ public function markMailsAsUnread(array $mailId): void * @param int[] $mailId * * @psalm-param list $mailId - - */ public function markMailsAsImportant(array $mailId): void { @@ -991,8 +836,6 @@ public function setFlag(array $mailsIds, string $flag): void * * @param array $mailsIds Array of mail IDs * @param string $flag Which you can delete are \Seen, \Answered, \Flagged, \Deleted, and \Draft as defined by RFC2060 - - */ public function clearFlag(array $mailsIds, string $flag): void { @@ -1073,8 +916,6 @@ public function getMailsInfo(array $mailsIds): array * returns an array of string formatted with header info, * one element per mail message. * - - * @see imap_headers() */ public function getMailboxHeaders(): array @@ -1119,7 +960,6 @@ public function getMailboxInfo(): object * @param int $criteria Sorting criteria (eg. SORTARRIVAL) * @param bool $reverse Sort reverse or not * @param string|null $searchCriteria See http://php.net/imap_search for a complete list of available criteria - * * @psalm-param value-of $criteria * @psalm-param 1|5|0|2|6|3|4 $criteria @@ -1145,8 +985,6 @@ public function sortMails( /** * Get mails count in mail box. * - - * @see imap_num_msg() */ public function countMails(): int @@ -1158,8 +996,6 @@ public function countMails(): int * Return quota limit in KB. * * @param string $quota_root Should normally be in the form of which mailbox (i.e. INBOX) - - */ public function getQuotaLimit(string $quota_root = 'INBOX'): int { @@ -1207,8 +1043,6 @@ public function getRawMail(int $msgId, bool $markAsSeen = true): string * * @param int $mailId ID of the message * - - * @throws Exception * * @todo update type checking pending resolution of https://github.com/vimeo/psalm/issues/2619 @@ -1357,9 +1191,6 @@ public function getMailHeader(int $mailId): IncomingMailHeader * * @param stdClass[] $messageParts * @param stdClass[] $flattenedParts - - - * * @psalm-param array $flattenedParts * @@ -1399,8 +1230,6 @@ public function flattenParts(array $messageParts, array $flattenedParts = [], st * * @param int $mailId ID of the mail * @param bool $markAsSeen Mark the email as seen, when set to true - - */ public function getMail(int $mailId, bool $markAsSeen = true): IncomingMail { @@ -1431,15 +1260,12 @@ public function getMail(int $mailId, bool $markAsSeen = true): IncomingMail * * @param array $params Array of params of mail * @param object $partStructure Part of mail - * @param bool $emlOrigin True, if it indicates, that the attachment comes from an EML (mail) file * * @psalm-param array $params * @psalm-param PARTSTRUCTURE $partStructure * * @return IncomingMailAttachment $attachment - - */ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object $partStructure, bool $emlOrigin = false): IncomingMailAttachment { @@ -1533,7 +1359,6 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object * Decodes a mime string. * * @param string $string MIME string to decode - * * @return string Converted string if conversion was successful, or the original string if not * @@ -1543,10 +1368,6 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object */ public function decodeMimeStr(string $string): string { - - - - $newString = ''; /** @var list|false */ $elements = \imap_mime_header_decode($string); @@ -1590,11 +1411,6 @@ public function decodeMimeStr(string $string): string } public function isUrlEncoded(string $string): bool - - - - - { $hasInvalidChars = \preg_match('#[^%a-zA-Z0-9\-_\.\+]#', $string); $hasEscapedChars = \preg_match('#%[a-zA-Z0-9]{2}#', $string); @@ -1632,36 +1448,7 @@ public function parseDateTime(string $dateHeader): string } /** - - - - - - - - - - - - - - - - - - - - - - - - - - - * Gets IMAP path. - - */ public function getImapPath(): string { @@ -1672,8 +1459,6 @@ public function getImapPath(): string * Get message in MBOX format. * * @param int $mailId message number - - */ public function getMailMboxFormat(int $mailId): string { @@ -1684,10 +1469,6 @@ public function getMailMboxFormat(int $mailId): string /** * Get folders list. - - - - */ public function getMailboxes(string $search = '*'): array { @@ -1699,10 +1480,6 @@ public function getMailboxes(string $search = '*'): array /** * Get folders list. - - - - */ public function getSubscribedMailboxes(string $search = '*'): array { @@ -1715,10 +1492,6 @@ public function getSubscribedMailboxes(string $search = '*'): array /** * Subscribe to a mailbox. * - - - - * @throws Exception */ public function subscribeMailbox(string $mailbox): void @@ -1732,10 +1505,6 @@ public function subscribeMailbox(string $mailbox): void /** * Unsubscribe from a mailbox. * - - - - * @throws Exception */ public function unsubscribeMailbox(string $mailbox): void @@ -1750,9 +1519,6 @@ public function unsubscribeMailbox(string $mailbox): void * Appends $message to $mailbox. * * @param string|array $message - - - * * @psalm-param string|array{0:COMPOSE_ENVELOPE, 1:COMPOSE_BODY} $message * @@ -1798,27 +1564,9 @@ protected function lowercase_mb_list_encodings() $encodings = \mb_list_encodings(); foreach ($encodings as $encoding) { $lowercase_encodings[] = \strtolower($encoding); - - - - - - - - - - - - - - } return $lowercase_encodings; - - - - } /** @return resource */ @@ -1842,8 +1590,6 @@ protected function initImapStreamWithRetry() * @param string $quota_root Should normally be in the form of which mailbox (i.e. INBOX) * * @see imap_get_quotaroot() - - */ protected function getQuota(string $quota_root = 'INBOX'): array { @@ -1876,15 +1622,10 @@ protected function initImapStream() } /** - * @param string|0 $partNum - - * * @psalm-param PARTSTRUCTURE $partStructure * - - * @todo refactor type checking pending resolution of https://github.com/vimeo/psalm/issues/2619 */ protected function initMailPart(IncomingMail $mail, object $partStructure, $partNum, bool $markAsSeen = true, bool $emlParse = false): void @@ -2010,16 +1751,9 @@ protected function initMailPart(IncomingMail $mail, object $partStructure, $part } } - - - - - - protected function decodeRFC2231(string $string): string { if (\preg_match("/^(.*?)'.*?'(.*?)$/", $string, $matches)) { - $data = $matches[2]; if ($this->isUrlEncoded($data)) { $string = $this->decodeMimeStr(\urldecode($data)); @@ -2060,10 +1794,6 @@ protected function getCombinedPath(string $folder, bool $absolute = false): stri } /** - - - - * @psalm-return array{0:string, 1:string|null}|null */ protected function possiblyGetEmailAndNameFromRecipient(object $recipient): ?array @@ -2103,8 +1833,6 @@ protected function possiblyGetEmailAndNameFromRecipient(object $recipient): ?arr /** * @psalm-param array $t * - - * @todo revisit implementation pending resolution of https://github.com/vimeo/psalm/issues/2619 */ protected function possiblyGetMailboxes(array $t): array @@ -2118,8 +1846,6 @@ protected function possiblyGetMailboxes(array $t): array /** @var scalar|array|object|resource|null */ $item_name = isset($item->name) ? $item->name : null; - - if (!isset($item->name, $item->attributes, $item->delimiter)) { throw new UnexpectedValueException('The object at index '.(string) $index.' of argument 1 passed to '.__METHOD__.'() was missing one or more of the required properties "name", "attributes", "delimiter"!'); } elseif (!\is_string($item_name)) { @@ -2147,8 +1873,6 @@ protected function possiblyGetMailboxes(array $t): array /** * @psalm-param HOSTNAMEANDADDRESS $t * - - * @psalm-return array{0:string|null, 1:string|null, 2:string} */ protected function possiblyGetHostNameAndAddress(array $t): array @@ -2174,8 +1898,6 @@ protected function possiblyGetHostNameAndAddress(array $t): array } /** - - * @todo revisit redundant condition issues pending fix of https://github.com/vimeo/psalm/issues/2626 */ protected function pingOrDisconnect(): void @@ -2189,11 +1911,6 @@ protected function pingOrDisconnect(): void /** * Search the mailbox for emails from multiple, specific senders. * - - - - - * This function wraps Mailbox::searchMailbox() to overcome a shortcoming in ext-imap * * @return int[] From 282cbca04498b37e1182a4268ec7a0f1454f1089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Sat, 10 Apr 2021 13:08:48 +0200 Subject: [PATCH 03/13] Update Mailbox.php --- src/PhpImap/Mailbox.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 5b827717..b0cfbd68 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1343,9 +1343,9 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object $filePath = $attachmentsDir.DIRECTORY_SEPARATOR.$fileSysName; - if (\strlen($filePath) > 255) { + if (\strlen($filePath) > self::MAX_LENGTH_FILEPATH) { $ext = \pathinfo($filePath, PATHINFO_EXTENSION); - $filePath = \substr($filePath, 0, 255 - 1 - \strlen($ext)).'.'.$ext; + $filePath = \substr($filePath, 0, self::MAX_LENGTH_FILEPATH - 1 - \strlen($ext)).'.'.$ext; } $attachment->setFilePath($filePath); From 08ebd5212c2e7bbcdd58c59ebb8ccb2fff8ba0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Sat, 10 Apr 2021 13:19:46 +0200 Subject: [PATCH 04/13] Update Mailbox.php --- src/PhpImap/Mailbox.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index b0cfbd68..f3c81fda 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -158,7 +158,7 @@ class Mailbox public const ATTACH_FILE_NAMERANDOM = 1; // Filename is unique (random) public const ATTACH_FILE_NAMEORIGINAL = 2; // Filename is Attachment-Filename /** @var int */ - protected $attachmentsFilenameMode = ATTACH_FILE_NAMERANDOM; + protected $attachmentsFilenameMode = self::ATTACH_FILE_NAMERANDOM; /** @var resource|null */ private $imapStream; From 2b998b941d2f911e08397364b1f4a02d6030f6b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Mon, 10 Jan 2022 12:27:21 +0100 Subject: [PATCH 05/13] Adding support for "original" Filename --- src/PhpImap/Mailbox.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 4ec7eea6..6682d912 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -158,6 +158,7 @@ class Mailbox public const ATTACH_FILE_NAMERANDOM = 1; // Filename is unique (random) public const ATTACH_FILE_NAMEORIGINAL = 2; // Filename is Attachment-Filename + public const ATTACH_FILE_NAMEITTERATED = 3; // Filename is Attachment-Filename but if allready exists it will be extend by Number (#nr) /** @var int */ protected $attachmentsFilenameMode = self::ATTACH_FILE_NAMERANDOM; /** @var resource|null */ @@ -166,7 +167,7 @@ class Mailbox /** * @throws InvalidParameterException */ - public function __construct(string $imapPath, string $login, string $password, string $attachmentsDir = null, string $serverEncoding = 'UTF-8', bool $trimImapPath = true, bool $attachmentFilenameMode = false) + public function __construct(string $imapPath, string $login, string $password, string $attachmentsDir = null, string $serverEncoding = 'UTF-8', bool $trimImapPath = true, bool $attachmentFilenameMode = self::ATTACH_FILE_NAMERANDOM) { $this->imapPath = (true == $trimImapPath) ? \trim($imapPath) : $imapPath; $this->imapLogin = \trim($login); From 46cfc29dc75542821ffe3cc128d93c3636cd161e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Tue, 11 Jan 2022 16:02:09 +0100 Subject: [PATCH 06/13] Adding support for "incremental" Filename --- src/PhpImap/Mailbox.php | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 6682d912..c8b33f6b 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -156,18 +156,18 @@ class Mailbox /** @var string */ protected $mailboxFolder; - public const ATTACH_FILE_NAMERANDOM = 1; // Filename is unique (random) - public const ATTACH_FILE_NAMEORIGINAL = 2; // Filename is Attachment-Filename - public const ATTACH_FILE_NAMEITTERATED = 3; // Filename is Attachment-Filename but if allready exists it will be extend by Number (#nr) + public const ATTACH_FILE_NAME_RANDOM = 1; // Filename is unique (random) + public const ATTACH_FILE_NAME_ORIGINAL = 2; // Filename is Attachment-Filename + public const ATTACH_FILE_NAME_ITTERATED = 3; // Filename is Attachment-Filename but if allready exists it will be extend by Number like: Filename (1).ext /** @var int */ - protected $attachmentsFilenameMode = self::ATTACH_FILE_NAMERANDOM; + protected $attachmentsFilenameMode = self::ATTACH_FILE_NAME_RANDOM; /** @var resource|null */ private $imapStream; /** * @throws InvalidParameterException */ - public function __construct(string $imapPath, string $login, string $password, string $attachmentsDir = null, string $serverEncoding = 'UTF-8', bool $trimImapPath = true, bool $attachmentFilenameMode = self::ATTACH_FILE_NAMERANDOM) + public function __construct(string $imapPath, string $login, string $password, string $attachmentsDir = null, string $serverEncoding = 'UTF-8', bool $trimImapPath = true, bool $attachmentFilenameMode = self::ATTACH_FILE_NAME_RANDOM) { $this->imapPath = (true == $trimImapPath) ? \trim($imapPath) : $imapPath; $this->imapLogin = \trim($login); @@ -332,7 +332,7 @@ public function setAttachmentsIgnore(bool $attachmentsIgnore): void /** * Set $this->setAttachmentsRandomFilename param. * - * @param int $random ATTACH_FILE_NAMERANDOM, ATTACH_FILE_NAMEORIGINAL + * @param int $random ATTACH_FILE_NAME_RANDOM, ATTACH_FILE_NAME_ORIGINAL, ATTACH_FILE_NAME_ITTERATED * * @return Mailbox */ @@ -1418,10 +1418,18 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object if (null !== $attachmentsDir) { switch($this->attachmentsFilenameMode) { - case self::ATTACH_FILE_NAMEORIGINAL: + case self::ATTACH_FILE_NAME_ORIGINAL: $fileSysName = $fileName; break; - case self::ATTACH_FILE_NAMERANDOM: + case self::ATTACH_FILE_NAME_ITTERATED: + $fileSysName = $fileName; + $i = 1; + while(file_exists($attachmentsDir.DIRECTORY_SEPARATOR.$fileSysName)) { + $frag = pathinfo($fileName); + $fileSysName = "{$frag['filename']} ({$i}){$frag['extension']}"; + } + break; + case self::ATTACH_FILE_NAME_RANDOM: default: $fileSysName = \bin2hex(\random_bytes(16)).'.bin'; } From 82547dfdf48834d1c4a554eb868839a4f32e9f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Sat, 10 Apr 2021 13:04:54 +0200 Subject: [PATCH 07/13] Adding support for "original" and "incremental" Filename Adding support for "original" Filename. $mailbox->setAttachmentsFilenameMode(Mailbox::ATTACH_FILE_NAME_RANDOM); # filename by random (old way) $mailbox->setAttachmentsFilenameMode(Mailbox::ATTACH_FILE_NAME_ORIGINAL); # filename by email --- src/PhpImap/Mailbox.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 8ed922e7..a8c21b67 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -562,7 +562,7 @@ public function disconnect(): void } /** - * Sets 'expunge on disconnect' parameter. + * Sets 'expunge on disconnect' parameter. */ public function setExpungeOnDisconnect(bool $isEnabled): void { @@ -686,7 +686,7 @@ public function searchMailboxFrom(string $criteria, string $sender, string ...$s /** * Search the mailbox for emails from multiple, specific senders whilst not using server encoding. * - * @see Mailbox::searchMailboxFromWithOrWithoutDisablingServerEncoding() + * @see Mailbox::searchMailboxFromWithOrWithoutDisablingServerEncoding() * * @return int[] * From b5fcde593b23bcdcbbbaecd9bc72d4dc8152796d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Mon, 31 Oct 2022 15:26:55 +0100 Subject: [PATCH 08/13] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9b44d8e2..6e07456f 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "php-imap/php-imap", + "name": "fglueck/php-imap", "description": "Manage mailboxes, filter/get/delete emails in PHP (supports IMAP/POP3/NNTP)", "keywords": [ "PHP", From 8f9d27adc32f88e63f17e6307133a1ec249edad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Mon, 31 Oct 2022 16:07:36 +0100 Subject: [PATCH 09/13] Update Mailbox.php --- src/PhpImap/Mailbox.php | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index a8c21b67..f483ac33 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -159,6 +159,8 @@ class Mailbox public const ATTACH_FILE_NAME_RANDOM = 1; // Filename is unique (random) public const ATTACH_FILE_NAME_ORIGINAL = 2; // Filename is Attachment-Filename public const ATTACH_FILE_NAME_ITTERATED = 3; // Filename is Attachment-Filename but if allready exists it will be extend by Number like: Filename (1).ext + public const ATTACH_FILE_NAME_TRANSFER = 3; // Filename is Attachment-Filename but if allready exists in current transfer-job it will be extend by Number like: Filename (1).ext if file exists from prior transfer it will be overwritten + static $fileNameStack = []; /** @var int */ protected $attachmentsFilenameMode = self::ATTACH_FILE_NAME_RANDOM; /** @var resource|null */ @@ -332,7 +334,7 @@ public function setAttachmentsIgnore(bool $attachmentsIgnore): void /** * Set $this->setAttachmentsRandomFilename param. * - * @param int $random ATTACH_FILE_NAME_RANDOM, ATTACH_FILE_NAME_ORIGINAL, ATTACH_FILE_NAME_ITTERATED + * @param int $random ATTACH_FILE_NAME_RANDOM, ATTACH_FILE_NAME_ORIGINAL, ATTACH_FILE_NAME_ITTERATED, ATTACH_FILE_NAME_TRANSFER * * @return Mailbox */ @@ -1421,13 +1423,10 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object $fileSysName = $fileName; break; case self::ATTACH_FILE_NAME_ITTERATED: - $fileSysName = $fileName; - $i = 1; - while(file_exists($attachmentsDir.DIRECTORY_SEPARATOR.$fileSysName)) { - $frag = pathinfo($fileName); - $fileSysName = "{$frag['filename']} ({$i}){$frag['extension']}"; - } + $fileSysName = $this->getNewFileSysName($fileName); break; + case self::ATTACH_FILE_NAME_TRANSFER: + $fileSysName = $this->getNewFileName($fileName); case self::ATTACH_FILE_NAME_RANDOM: default: $fileSysName = \bin2hex(\random_bytes(16)).'.bin'; @@ -1445,6 +1444,24 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object return $attachment; } + public function getNewFileSysName(string $fileSysName) : string { + $i = 1; + while(file_exists($attachmentsDir.DIRECTORY_SEPARATOR.$fileSysName)) { + $frag = pathinfo($fileName); + $fileSysName = "{$frag['filename']} ({$i}){$frag['extension']}"; + $i++; + } + return $fileSysName; + } + public function getNewFileName(string $fileName) : string { + $i = 1; + while(!in_array($fileName, self::$fileNameStack, true)) { + $frag = pathinfo($fileName); + $fileName = "{$frag['filename']} ({$i}){$frag['extension']}"; + $i++; + } + return $fileName; + } /** * Converts a string to UTF-8. From e866a8a129148ebe0702f5cab700985ac0fcd695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Mon, 31 Oct 2022 16:17:02 +0100 Subject: [PATCH 10/13] Update Mailbox.php --- src/PhpImap/Mailbox.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index f483ac33..d9f3386e 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -159,8 +159,9 @@ class Mailbox public const ATTACH_FILE_NAME_RANDOM = 1; // Filename is unique (random) public const ATTACH_FILE_NAME_ORIGINAL = 2; // Filename is Attachment-Filename public const ATTACH_FILE_NAME_ITTERATED = 3; // Filename is Attachment-Filename but if allready exists it will be extend by Number like: Filename (1).ext - public const ATTACH_FILE_NAME_TRANSFER = 3; // Filename is Attachment-Filename but if allready exists in current transfer-job it will be extend by Number like: Filename (1).ext if file exists from prior transfer it will be overwritten - static $fileNameStack = []; + public const ATTACH_FILE_NAME_TRANSFER = 3; // Filename is Attachment-Filename but if allready exists in current transfer-job it will be extend by Number like: Filename (1).ext if file exists from prior transfer it will be overwritten + static $fileNameStack = []; + /** @var int */ protected $attachmentsFilenameMode = self::ATTACH_FILE_NAME_RANDOM; /** @var resource|null */ @@ -1427,6 +1428,7 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object break; case self::ATTACH_FILE_NAME_TRANSFER: $fileSysName = $this->getNewFileName($fileName); + break; case self::ATTACH_FILE_NAME_RANDOM: default: $fileSysName = \bin2hex(\random_bytes(16)).'.bin'; @@ -1446,7 +1448,7 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object } public function getNewFileSysName(string $fileSysName) : string { $i = 1; - while(file_exists($attachmentsDir.DIRECTORY_SEPARATOR.$fileSysName)) { + while(file_exists($$this->getAttachmentsDir().DIRECTORY_SEPARATOR.$fileSysName)) { $frag = pathinfo($fileName); $fileSysName = "{$frag['filename']} ({$i}){$frag['extension']}"; $i++; From 02d9347963c42ca7f059b39fceb5ca21d78f8348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Mon, 31 Oct 2022 16:23:48 +0100 Subject: [PATCH 11/13] Update Mailbox.php --- src/PhpImap/Mailbox.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index d9f3386e..c07a0599 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1449,7 +1449,7 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object public function getNewFileSysName(string $fileSysName) : string { $i = 1; while(file_exists($$this->getAttachmentsDir().DIRECTORY_SEPARATOR.$fileSysName)) { - $frag = pathinfo($fileName); + $frag = pathinfo($fileSysName); $fileSysName = "{$frag['filename']} ({$i}){$frag['extension']}"; $i++; } From 37d2d03d4010159534ff38ec77505a09180e21fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Mon, 31 Oct 2022 16:26:35 +0100 Subject: [PATCH 12/13] Update Mailbox.php --- src/PhpImap/Mailbox.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index c07a0599..ac6831bf 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1446,14 +1446,14 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object return $attachment; } - public function getNewFileSysName(string $fileSysName) : string { - $i = 1; - while(file_exists($$this->getAttachmentsDir().DIRECTORY_SEPARATOR.$fileSysName)) { - $frag = pathinfo($fileSysName); - $fileSysName = "{$frag['filename']} ({$i}){$frag['extension']}"; - $i++; - } - return $fileSysName; + public function getNewFileSysName(string $fileSysName) : string { + $i = 1; + while(file_exists($$this->getAttachmentsDir().DIRECTORY_SEPARATOR.$fileSysName)) { + $frag = pathinfo($fileSysName); + $fileSysName = "{$frag['filename']} ({$i}){$frag['extension']}"; + $i++; + } + return $fileSysName; } public function getNewFileName(string $fileName) : string { $i = 1; From 44cddfb91cec6b2794eea3dbebeec50800241865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Gl=C3=BCck?= Date: Wed, 2 Nov 2022 09:51:58 +0100 Subject: [PATCH 13/13] Update Mailbox.php --- src/PhpImap/Mailbox.php | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index ac6831bf..e8de400f 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1421,13 +1421,13 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object if (null !== $attachmentsDir) { switch($this->attachmentsFilenameMode) { case self::ATTACH_FILE_NAME_ORIGINAL: - $fileSysName = $fileName; + $fileSysName = $this->sanitizeFileName($fileName); break; case self::ATTACH_FILE_NAME_ITTERATED: - $fileSysName = $this->getNewFileSysName($fileName); + $fileSysName = $this->getNewFileSysName($this->sanitizeFileName($fileName)); break; case self::ATTACH_FILE_NAME_TRANSFER: - $fileSysName = $this->getNewFileName($fileName); + $fileSysName = $this->getNewFileName($this->sanitizeFileName($fileName)); break; case self::ATTACH_FILE_NAME_RANDOM: default: @@ -1446,23 +1446,28 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object return $attachment; } - public function getNewFileSysName(string $fileSysName) : string { - $i = 1; - while(file_exists($$this->getAttachmentsDir().DIRECTORY_SEPARATOR.$fileSysName)) { - $frag = pathinfo($fileSysName); - $fileSysName = "{$frag['filename']} ({$i}){$frag['extension']}"; - $i++; - } - return $fileSysName; + public function sanitizeFileName(string $fileName) : string { + return preg_replace('/([^\p{L}\s\d\-_~,;:\[\]\(\).\'])/is', '-', $fileName); } + public function getNewFileSysName(string $fileSysName) : string { + $i = 1; + while(file_exists($this->getAttachmentsDir().DIRECTORY_SEPARATOR.$fileSysName)) { + $frag = pathinfo($fileSysName); + $ext = empty($frag['extension']) ? '' : ".{$frag['extension']}"; + $fileSysName = "{$frag['filename']} ({$i}){$ext}"; + $i++; + } + return $fileSysName; + } public function getNewFileName(string $fileName) : string { $i = 1; while(!in_array($fileName, self::$fileNameStack, true)) { $frag = pathinfo($fileName); - $fileName = "{$frag['filename']} ({$i}){$frag['extension']}"; + $ext = empty($frag['extension']) ? '' : ".{$frag['extension']}"; + $fileName = "{$frag['filename']} ({$i}){$ext}"; $i++; - } - return $fileName; + } + return $fileName; } /**