From 85a6999cea0641eab4dd2e2da9f18f930f4ca019 Mon Sep 17 00:00:00 2001 From: Marv Date: Wed, 6 May 2020 10:55:35 +0100 Subject: [PATCH 01/73] update baseline --- psalm.baseline.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/psalm.baseline.xml b/psalm.baseline.xml index 36fc39b2..1bbed09f 100644 --- a/psalm.baseline.xml +++ b/psalm.baseline.xml @@ -34,13 +34,6 @@ $element->charset $element->text - - array - - - $lowercase_encodings - $lowercase_encodings - setConnectionRetry setConnectionRetryDelay From 114463c799a6b0fb26724ef0de773cdc150a47c7 Mon Sep 17 00:00:00 2001 From: Marv Date: Wed, 6 May 2020 10:59:39 +0100 Subject: [PATCH 02/73] attempts to fix barbushin/php-imap#496 psalm did not identify the second argument to preg_match_all as `string|null`, typecasting a locally typehinted variable will work around this issue. --- src/PhpImap/IncomingMail.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PhpImap/IncomingMail.php b/src/PhpImap/IncomingMail.php index c253e830..b722636f 100644 --- a/src/PhpImap/IncomingMail.php +++ b/src/PhpImap/IncomingMail.php @@ -199,7 +199,10 @@ public function replaceInternalLinks(string $baseUri): string */ public function embedImageAttachments(): void { - \preg_match_all("/\bcid:[^'\"\s]{1,256}/mi", $this->textHtml, $matches); + /** @var string|null */ + $fetchedHtml = $this->textHtml; + + \preg_match_all("/\bcid:[^'\"\s]{1,256}/mi", $fetchedHtml ?? '', $matches); /** @psalm-var list> */ $matches = $matches; From bd7dfcef52f3020a9aaafaff520c1df66cc36a60 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 10 May 2020 15:33:46 +0100 Subject: [PATCH 03/73] adding tests that require manual setup i.e. to verify encoding issues are not caused by this library --- .travis.yml | 2 +- tests/unit/AbstractLiveMailboxTest.php | 89 +++++++++++++++++++ tests/unit/LiveMailboxTest.php | 66 +------------- tests/unit/LiveMailboxWithManualSetupTest.php | 69 ++++++++++++++ tests/unit/MailboxTest.php | 1 + 5 files changed, 161 insertions(+), 66 deletions(-) create mode 100644 tests/unit/AbstractLiveMailboxTest.php create mode 100644 tests/unit/LiveMailboxWithManualSetupTest.php diff --git a/.travis.yml b/.travis.yml index 5cbe1d88..599d88d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ php: - 7.3 env: - - phpunitflags="--stop-on-failure --exclude-group=live" + - phpunitflags="--stop-on-failure --exclude-group=live,live-manual" matrix: fast_finish: true diff --git a/tests/unit/AbstractLiveMailboxTest.php b/tests/unit/AbstractLiveMailboxTest.php new file mode 100644 index 00000000..1e0bf1d4 --- /dev/null +++ b/tests/unit/AbstractLiveMailboxTest.php @@ -0,0 +1,89 @@ +getString(), $login->getString(), $password->getString(), $attachmentsDir, $serverEncoding); + + $random = 'test-box-'.\date('c').\bin2hex(\random_bytes(4)); + + $mailbox->createMailbox($random); + + $mailbox->switchMailbox($random, false); + + return [$mailbox, $random, $imapPath]; + } + + /** + * @psalm-param MAILBOX_ARGS $mailbox_args + * + * @return mixed[] + * + * @psalm-return array{0:Mailbox, 1:string, 2:HiddenString} + */ + protected function getMailboxFromArgs(array $mailbox_args): array + { + list($path, $username, $password, $attachments_dir) = $mailbox_args; + + return $this->getMailbox( + $path, + $username, + $password, + $attachments_dir, + isset($mailbox_args[4]) ? $mailbox_args[4] : 'UTF-8' + ); + } +} diff --git a/tests/unit/LiveMailboxTest.php b/tests/unit/LiveMailboxTest.php index 61e9e31d..04dea8fd 100644 --- a/tests/unit/LiveMailboxTest.php +++ b/tests/unit/LiveMailboxTest.php @@ -14,7 +14,6 @@ use Exception; use Generator; use ParagonIE\HiddenString\HiddenString; -use PHPUnit\Framework\TestCase; use const TYPETEXT; /** @@ -39,7 +38,7 @@ * * @todo see @todo of Imap::mail_compose() */ -class LiveMailboxTest extends TestCase +class LiveMailboxTest extends AbstractLiveMailboxTest { const RANDOM_MAILBOX_SAMPLE_SIZE = 3; @@ -48,26 +47,6 @@ class LiveMailboxTest extends TestCase 391 => 2, ]; - /** - * Provides constructor arguments for a live mailbox. - * - * @psalm-return MAILBOX_ARGS[] - */ - public function MailBoxProvider(): array - { - $sets = []; - - $imapPath = \getenv('PHPIMAP_IMAP_PATH'); - $login = \getenv('PHPIMAP_LOGIN'); - $password = \getenv('PHPIMAP_PASSWORD'); - - if (\is_string($imapPath) && \is_string($login) && \is_string($password)) { - $sets['CI ENV'] = [new HiddenString($imapPath), new HiddenString($login), new HiddenString($password, true, true), \sys_get_temp_dir()]; - } - - return $sets; - } - /** * @dataProvider MailBoxProvider * @@ -767,49 +746,6 @@ public function testAppendRetrievalMatchesExpected( ); } - /** - * Get instance of Mailbox, pre-set to a random mailbox. - * - * @param string $attachmentsDir - * @param string $serverEncoding - * - * @return mixed[] - * - * @psalm-return array{0:Mailbox, 1:string, 2:HiddenString} - */ - protected function getMailbox(HiddenString $imapPath, HiddenString $login, HiddenString $password, $attachmentsDir, $serverEncoding = 'UTF-8') - { - $mailbox = new Mailbox($imapPath->getString(), $login->getString(), $password->getString(), $attachmentsDir, $serverEncoding); - - $random = 'test-box-'.\date('c').\bin2hex(\random_bytes(4)); - - $mailbox->createMailbox($random); - - $mailbox->switchMailbox($random, false); - - return [$mailbox, $random, $imapPath]; - } - - /** - * @psalm-param MAILBOX_ARGS $mailbox_args - * - * @return mixed[] - * - * @psalm-return array{0:Mailbox, 1:string, 2:HiddenString} - */ - protected function getMailboxFromArgs(array $mailbox_args): array - { - list($path, $username, $password, $attachments_dir) = $mailbox_args; - - return $this->getMailbox( - $path, - $username, - $password, - $attachments_dir, - isset($mailbox_args[4]) ? $mailbox_args[4] : 'UTF-8' - ); - } - protected function MaybeSkipAppendTest(array $envelope): bool { if (!isset($envelope['subject'])) { diff --git a/tests/unit/LiveMailboxWithManualSetupTest.php b/tests/unit/LiveMailboxWithManualSetupTest.php new file mode 100644 index 00000000..9d06b282 --- /dev/null +++ b/tests/unit/LiveMailboxWithManualSetupTest.php @@ -0,0 +1,69 @@ + + */ + public function RelativeToRootPathProvider(): Generator + { + yield [ + '.issue-499.Éléments envoyés', + ]; + } + + /** + * @return Generator + */ + public function statusProviderAbsolutePath(): Generator + { + foreach ($this->RelativeToRootPathProvider() as $path_args) { + foreach ($this->MailBoxProvider() as $args) { + $args[0] = new HiddenString($args[0]->getString().$path_args[0]); + + yield [$args]; + } + } + } + + /** + * Tests the status of an absolute mailbox path set from the Mailbox constructor. + * + * @dataProvider statusProviderAbsolutePath + * + * @group live-manual + * + * @psalm-param MAILBOX_ARGS $mailbox_args + */ + public function testAbsolutePathStatusFromConstruction( + array $mailbox_args + ): void { + list($mailbox) = $this->getMailboxFromArgs($mailbox_args); + + $mailbox->statusMailbox(); + + $this->assertTrue(true); + } +} diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index 3e97a31a..ffab7aa7 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -387,6 +387,7 @@ public function encodingTestStringsProvider(): array 'Deutsch' => ['Deutsch'], // German 'U.S. English' => ['U.S. English'], // U.S. English 'français' => ['français'], // French + 'Éléments envoyés' => ['Éléments envoyés'], // issue 499 'føroyskt' => ['føroyskt'], // Faroese 'Kĩmĩrũ' => ['Kĩmĩrũ'], // Kimîîru 'Kɨlaangi' => ['Kɨlaangi'], // Langi From 7b40d147f96ab5881bc424b556ac3b27860ff870 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 10 May 2020 15:34:53 +0100 Subject: [PATCH 04/73] adding testdox to travis for easier reading --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 599d88d1..0bd3626a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ php: - 7.3 env: - - phpunitflags="--stop-on-failure --exclude-group=live,live-manual" + - phpunitflags="--stop-on-failure --testdox --exclude-group=live,live-manual" matrix: fast_finish: true @@ -30,7 +30,7 @@ matrix: env: - lint=no - coverage=yes - - phpunitflags="--stop-on-failure --coverage-clover=clover.xml" + - phpunitflags="--stop-on-failure --testdox --coverage-clover=clover.xml" cache: directories: From ef4a5ab6233162bbfcba8add1eb9491440db09b7 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 10 May 2020 15:44:06 +0100 Subject: [PATCH 05/73] apply patch suggested in barbushin/php-imap#499 --- src/PhpImap/Imap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpImap/Imap.php b/src/PhpImap/Imap.php index 14373b7a..c767616d 100644 --- a/src/PhpImap/Imap.php +++ b/src/PhpImap/Imap.php @@ -691,7 +691,7 @@ public static function open( $mailbox_name = $matches[1]; if (!\mb_detect_encoding($mailbox_name, 'ASCII', true)) { - $mailbox = static::encodeStringToUtf7Imap($mailbox_name); + $mailbox = static::encodeStringToUtf7Imap($mailbox); } } From 7c33e1549a408f6dd03e9ab7d2d085c255ea9d0b Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 12:06:50 +0100 Subject: [PATCH 06/73] moving method for reuse --- tests/unit/AbstractLiveMailboxTest.php | 20 ++++++++++++++++++++ tests/unit/LiveMailboxTest.php | 20 -------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/unit/AbstractLiveMailboxTest.php b/tests/unit/AbstractLiveMailboxTest.php index 1e0bf1d4..ff21ea5f 100644 --- a/tests/unit/AbstractLiveMailboxTest.php +++ b/tests/unit/AbstractLiveMailboxTest.php @@ -86,4 +86,24 @@ protected function getMailboxFromArgs(array $mailbox_args): array isset($mailbox_args[4]) ? $mailbox_args[4] : 'UTF-8' ); } + + /** + * Get subject search criteria and subject. + * + * @psalm-param array{subject?:mixed} $envelope + * + * @psalm-return array{0:string, 1:string} + */ + protected function SubjectSearchCriteriaAndSubject(array $envelope): array + { + /** @var string|null */ + $subject = isset($envelope['subject']) ? $envelope['subject'] : null; + + $this->assertIsString($subject); + + $search_criteria = \sprintf('SUBJECT "%s"', (string) $subject); + + /** @psalm-var array{0:string, 1:string} */ + return [$search_criteria, (string) $subject]; + } } diff --git a/tests/unit/LiveMailboxTest.php b/tests/unit/LiveMailboxTest.php index 04dea8fd..20f9d72e 100644 --- a/tests/unit/LiveMailboxTest.php +++ b/tests/unit/LiveMailboxTest.php @@ -759,26 +759,6 @@ protected function MaybeSkipAppendTest(array $envelope): bool return false; } - /** - * Get subject search criteria and subject. - * - * @psalm-param array{subject?:mixed} $envelope - * - * @psalm-return array{0:string, 1:string} - */ - protected function SubjectSearchCriteriaAndSubject(array $envelope): array - { - /** @var string|null */ - $subject = isset($envelope['subject']) ? $envelope['subject'] : null; - - $this->assertIsString($subject); - - $search_criteria = \sprintf('SUBJECT "%s"', (string) $subject); - - /** @psalm-var array{0:string, 1:string} */ - return [$search_criteria, (string) $subject]; - } - /** * @param string $expected_result * @param string $actual_result From 60b7f013e1e14c2e8d348b2a889503cd33c980e0 Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 12:09:28 +0100 Subject: [PATCH 07/73] implement test for barbushin/php-imap#501 --- tests/unit/LiveMailboxIssue501Test.php | 108 +++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 tests/unit/LiveMailboxIssue501Test.php diff --git a/tests/unit/LiveMailboxIssue501Test.php b/tests/unit/LiveMailboxIssue501Test.php new file mode 100644 index 00000000..029a963b --- /dev/null +++ b/tests/unit/LiveMailboxIssue501Test.php @@ -0,0 +1,108 @@ +getMailbox( + $imapPath, + $login, + $password, + $attachmentsDir, + $serverEncoding + ); + + $exception = null; + + try { + $envelope = [ + 'subject' => 'barbushin/php-imap#501: '.\bin2hex(\random_bytes(16)), + ]; + + list($search_criteria) = $this->SubjectSearchCriteriaAndSubject( + $envelope + ); + + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 0, + $search, + ( + 'If a subject was found,'. + ' then the message is insufficiently unique to assert that'. + ' a newly-appended message was actually created.' + ) + ); + + $mailbox->appendMessageToMailbox(Imap::mail_compose( + $envelope, + [ + [ + 'type' => TYPETEXT, + 'contents.data' => '', + ], + ] + )); + + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 1, + $search, + ( + 'If a subject was not found, '. + ' then Mailbox::appendMessageToMailbox() failed'. + ' despite not throwing an exception.' + ) + ); + + $mail = $mailbox->getMail($search[0], false); + + $this->assertSame('', $mail->textPlain); + } catch (Exception $ex) { + $exception = $ex; + } finally { + $mailbox->switchMailbox($imapPath->getString()); + $mailbox->deleteMailbox($remove_mailbox); + $mailbox->disconnect(); + } + + if (null !== $exception) { + throw $exception; + } + } +} From e944206ddc4c7e0f2f0b3c34bb904dbf048a0b83 Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 12:15:29 +0100 Subject: [PATCH 08/73] assign test to live group --- tests/unit/LiveMailboxIssue501Test.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/LiveMailboxIssue501Test.php b/tests/unit/LiveMailboxIssue501Test.php index 029a963b..a988934a 100644 --- a/tests/unit/LiveMailboxIssue501Test.php +++ b/tests/unit/LiveMailboxIssue501Test.php @@ -28,6 +28,7 @@ class LiveMailboxIssue501Test extends AbstractLiveMailboxTest /** * @dataProvider MailBoxProvider * + * @group live * @group live-issue-501 */ public function testGetEmptyBody( From 06a04798c93266a0b3f034faf2aa26a1f759a1e4 Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 12:22:00 +0100 Subject: [PATCH 09/73] add additional test for empty string decoding --- tests/unit/LiveMailboxIssue501Test.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/unit/LiveMailboxIssue501Test.php b/tests/unit/LiveMailboxIssue501Test.php index a988934a..d0643da2 100644 --- a/tests/unit/LiveMailboxIssue501Test.php +++ b/tests/unit/LiveMailboxIssue501Test.php @@ -25,6 +25,27 @@ */ class LiveMailboxIssue501Test extends AbstractLiveMailboxTest { + /** + * @group offline + * @group offline-issue-501 + */ + public function testDecodeMimeStrEmpty(): void + { + $this->assertSame([], \imap_mime_header_decode('')); + + // example credentials nabbed from MailboxTest::testConstructorTrimsPossibleVariables() + $imapPath = ' {imap.example.com:993/imap/ssl}INBOX '; + $login = ' php-imap@example.com'; + $password = ' v3rY!53cEt&P4sSWöRd$'; + // directory names can contain spaces before AND after on Linux/Unix systems. Windows trims these spaces automatically. + $attachmentsDir = '.'; + $serverEncoding = 'UTF-8 '; + + $mailbox = new Mailbox($imapPath, $login, $password, $attachmentsDir, $serverEncoding); + + $this->assertSame('', $mailbox->decodeMimeStr('')); + } + /** * @dataProvider MailBoxProvider * From 9fd2857c3ba10a2f5ed92a5a758ef07b113dba1f Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 12:22:59 +0100 Subject: [PATCH 10/73] add test to multiple groups to rollback multiple groups in phpunitflags --- .travis.yml | 2 +- tests/unit/LiveMailboxWithManualSetupTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0bd3626a..f7a2f01d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ php: - 7.3 env: - - phpunitflags="--stop-on-failure --testdox --exclude-group=live,live-manual" + - phpunitflags="--stop-on-failure --testdox --exclude-group=live" matrix: fast_finish: true diff --git a/tests/unit/LiveMailboxWithManualSetupTest.php b/tests/unit/LiveMailboxWithManualSetupTest.php index 9d06b282..5624b0c0 100644 --- a/tests/unit/LiveMailboxWithManualSetupTest.php +++ b/tests/unit/LiveMailboxWithManualSetupTest.php @@ -53,6 +53,7 @@ public function statusProviderAbsolutePath(): Generator * * @dataProvider statusProviderAbsolutePath * + * @group live * @group live-manual * * @psalm-param MAILBOX_ARGS $mailbox_args From 457590081aa33c9da25172655ec60e848da889e7 Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 12:23:26 +0100 Subject: [PATCH 11/73] drop overly paranoid type check that breaks empty message bodies --- src/PhpImap/Mailbox.php | 4 ---- tests/unit/MailboxTest.php | 7 +------ 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 07121c04..d99f93b1 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1241,10 +1241,6 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object */ public function decodeMimeStr(string $string): string { - if (empty(\trim($string))) { - throw new Exception('decodeMimeStr() Can not decode an empty string!'); - } - $newString = ''; /** @var list|false */ $elements = \imap_mime_header_decode($string); diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index ffab7aa7..3e53d84a 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -523,7 +523,7 @@ public function mimeEncodingProvider(): array ['=?iso-8859-1?Q?Sebastian_Kr=E4tzig?=', 'Sebastian Krätzig'], ['sebastian.kraetzig', 'sebastian.kraetzig'], ['=?US-ASCII?Q?Keith_Moore?= ', 'Keith Moore '], - [' ', ''], + [' ', ' '], ['=?ISO-8859-1?Q?Max_J=F8rn_Simsen?= ', 'Max Jørn Simsen '], ['=?ISO-8859-1?Q?Andr=E9?= Muster ', 'André Muster '], ['=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=', 'If you can read this you understand the example.'], @@ -539,12 +539,7 @@ public function testMimeEncoding(string $str, string $expected): void { $mailbox = $this->getMailbox(); - if (empty($expected)) { - $this->expectException(Exception::class); - $mailbox->decodeMimeStr($str); - } else { $this->assertEquals($mailbox->decodeMimeStr($str), $expected); - } } /** From a725da2002767e4bfe2bd032e07678375ae5c398 Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 12:35:41 +0100 Subject: [PATCH 12/73] add additional test case for barbushin/php-imap#501 --- tests/unit/MailboxTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index 3e53d84a..a63f93da 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -527,6 +527,7 @@ public function mimeEncodingProvider(): array ['=?ISO-8859-1?Q?Max_J=F8rn_Simsen?= ', 'Max Jørn Simsen '], ['=?ISO-8859-1?Q?Andr=E9?= Muster ', 'André Muster '], ['=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=', 'If you can read this you understand the example.'], + ['', ''], // barbushin/php-imap#501 ]; } From dec69a88f8183d3f1a8fc94367ec087347aae6b7 Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 12:35:49 +0100 Subject: [PATCH 13/73] adjusting indentation --- tests/unit/MailboxTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index a63f93da..9caf9b2b 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -540,7 +540,7 @@ public function testMimeEncoding(string $str, string $expected): void { $mailbox = $this->getMailbox(); - $this->assertEquals($mailbox->decodeMimeStr($str), $expected); + $this->assertEquals($mailbox->decodeMimeStr($str), $expected); } /** From d65aed0edce44a1889b13082f0e4fdda13945d49 Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 12:41:00 +0100 Subject: [PATCH 14/73] drop unused import --- tests/unit/MailboxTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index 9caf9b2b..b28f27c4 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -9,7 +9,6 @@ namespace PhpImap; use DateTime; -use Exception; use PhpImap\Exceptions\InvalidParameterException; use PHPUnit\Framework\TestCase; From f54808e437909788b351356e18c4d4beeee7f2cf Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 16:37:03 +0100 Subject: [PATCH 15/73] implementing tests for barbushin/php-imap#490 --- tests/unit/LiveMailboxIssue490Test.php | 140 +++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 tests/unit/LiveMailboxIssue490Test.php diff --git a/tests/unit/LiveMailboxIssue490Test.php b/tests/unit/LiveMailboxIssue490Test.php new file mode 100644 index 00000000..fbc1e0e1 --- /dev/null +++ b/tests/unit/LiveMailboxIssue490Test.php @@ -0,0 +1,140 @@ +getMailbox( + $imapPath, + $login, + $password, + $attachmentsDir, + $serverEncoding + ); + + $exception = null; + + try { + $envelope = [ + 'subject' => 'barbushin/php-imap#501: '.\bin2hex(\random_bytes(16)), + ]; + + list($search_criteria) = $this->SubjectSearchCriteriaAndSubject( + $envelope + ); + + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 0, + $search, + ( + 'If a subject was found,'. + ' then the message is insufficiently unique to assert that'. + ' a newly-appended message was actually created.' + ) + ); + + $message = Imap::mail_compose( + $envelope, + [ + [ + 'type' => TYPEMULTIPART, + ], + [ + 'type' => TYPETEXT, + 'contents.data' => 'foo', + ], + [ + 'type' => TYPEMULTIPART, + 'subtype' => 'plain', + 'description' => 'bar.txt', + 'disposition.type' => 'attachment', + 'disposition' => ['filename' => 'bar.txt'], + 'type.parameters' => ['name' => 'bar.txt'], + 'contents.data' => 'bar', + ], + [ + 'type' => TYPEMULTIPART, + 'subtype' => 'plain', + 'description' => 'baz.txt', + 'disposition.type' => 'attachment', + 'disposition' => ['filename' => 'baz.txt'], + 'type.parameters' => ['name' => 'baz.txt'], + 'contents.data' => 'baz', + ], + ] + ); + + $mailbox->appendMessageToMailbox($message); + + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 1, + $search, + ( + 'If a subject was not found, '. + ' then Mailbox::appendMessageToMailbox() failed'. + ' despite not throwing an exception.' + ) + ); + + $mail = $mailbox->getMail($search[0], false); + + $this->assertSame('foo', $mail->textPlain); + + $attachments = $mail->getAttachments(); + $keys = \array_keys($attachments); + + $this->assertCount(2, $attachments); + + $this->assertSame('bar', $attachments[$keys[0]]->getContents()); + $this->assertSame('baz', $attachments[$keys[1]]->getContents()); + } catch (Exception $ex) { + $exception = $ex; + } finally { + $mailbox->switchMailbox($imapPath->getString()); + $mailbox->deleteMailbox($remove_mailbox); + $mailbox->disconnect(); + } + + if (null !== $exception) { + throw $exception; + } + } +} From bd79ccf92964136053a37c6c630ea016546fd3ce Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 16:37:56 +0100 Subject: [PATCH 16/73] adding separate command for running static analysis --- composer.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a57ff16d..85dd039e 100644 --- a/composer.json +++ b/composer.json @@ -42,14 +42,17 @@ "vimeo/psalm": "^3.11" }, "scripts": { - "tests": [ + "static-analysis": [ "parallel-lint .php_cs.dist src tests examples", "phpcpd src tests", - "phpunit --testdox", "composer-require-checker check ./composer.json", "phpmnd ./ --exclude=./.github/ --exclude=./examples/ --exclude=./vendor/ --non-zero-exit-on-violation --hint", "php-cs-fixer fix --allow-risky=yes --no-interaction --dry-run --diff-format=udiff -v", "psalm --show-info=false" + ], + "tests": [ + "@static-analysis", + "phpunit --testdox" ] }, "suggest": { From 2ff6116e0026405f3e211df6425209b196049cc7 Mon Sep 17 00:00:00 2001 From: Marv Date: Thu, 14 May 2020 16:42:33 +0100 Subject: [PATCH 17/73] fixes barbushin/php-imap#490 --- src/PhpImap/Mailbox.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index d99f93b1..1ba00f0c 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1532,8 +1532,18 @@ protected function initMailPart(IncomingMail $mail, object $partStructure, $part $isAttachment = isset($params['filename']) || isset($params['name']); + $dispositionAttachment = ( + isset($partStructure->disposition) && + \is_string($partStructure->disposition) && + 'attachment' === \mb_strtolower($partStructure->disposition) + ); + // ignore contentId on body when mail isn't multipart (https://github.com/barbushin/php-imap/issues/71) - if (!$partNum && TYPETEXT === $partStructure->type) { + if ( + !$partNum && + TYPETEXT === $partStructure->type && + !$dispositionAttachment + ) { $isAttachment = false; } @@ -1590,12 +1600,16 @@ protected function initMailPart(IncomingMail $mail, object $partStructure, $part } else { if (TYPETEXT === $partStructure->type) { if ('plain' === \mb_strtolower($partStructure->subtype)) { + if ($dispositionAttachment) { + return; + } + $mail->addDataPartInfo($dataInfo, DataPartInfo::TEXT_PLAIN); } elseif (!$partStructure->ifdisposition) { $mail->addDataPartInfo($dataInfo, DataPartInfo::TEXT_HTML); } elseif (!\is_string($partStructure->disposition)) { throw new InvalidArgumentException('disposition property of object passed as argument 2 to '.__METHOD__.'() was present but not a string!'); - } elseif ('attachment' !== \mb_strtolower($partStructure->disposition)) { + } elseif (!$dispositionAttachment) { $mail->addDataPartInfo($dataInfo, DataPartInfo::TEXT_HTML); } } elseif (TYPEMESSAGE === $partStructure->type) { From 35f76efc0e75b56aeedc6a1f50286811a2f2becd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=A4tzig?= Date: Sun, 17 May 2020 21:42:05 +0200 Subject: [PATCH 18/73] #495: Added more headers as properties --- src/PhpImap/IncomingMailAttachment.php | 15 +++++++++++++++ src/PhpImap/IncomingMailHeader.php | 21 +++++++++++++++++++++ src/PhpImap/Mailbox.php | 14 +++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 9943c69c..72984b64 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -22,9 +22,24 @@ class IncomingMailAttachment /** @var string|null */ public $contentId; + /** @var integer|null */ + public $type; + + /** @var integer|null */ + public $encoding; + + /** @var string|null */ + public $subtype; + + /** @var string|null */ + public $description; + /** @var string|null */ public $name; + /** @var integer|null */ + public $sizeInBytes; + /** @var string|null */ public $disposition; diff --git a/src/PhpImap/IncomingMailHeader.php b/src/PhpImap/IncomingMailHeader.php index fc0abbd2..69e55cf4 100644 --- a/src/PhpImap/IncomingMailHeader.php +++ b/src/PhpImap/IncomingMailHeader.php @@ -26,6 +26,27 @@ class IncomingMailHeader /** @var object|null */ public $headers; + /** @var string|null */ + public $mimeVersion; + + /** @var string|null */ + public $xVirusScanned; + + /** @var string|null */ + public $organization; + + /** @var string|null */ + public $contentType; + + /** @var string|null */ + public $xMailer; + + /** @var string|null */ + public $contentLanguage; + + /** @var string|null */ + public $xSenderIp; + /** @var string|null */ public $priority; diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index d99f93b1..8b601184 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1022,6 +1022,13 @@ public function getMailHeader(int $mailId): IncomingMailHeader $header->headers = $head; $header->id = $mailId; $header->isDraft = (!isset($head->date)) ? true : false; + $header->mimeVersion = (\preg_match("/MIME-Version\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; + $header->xVirusScanned = (\preg_match("/X-Virus-Scanned\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; + $header->organization = (\preg_match("/Organization\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; + $header->contentType = (\preg_match("/Content-Type\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; + $header->xMailer = (\preg_match("/X-Mailer\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; + $header->contentLanguage = (\preg_match("/Content-Language\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; + $header->xSenderIp = (\preg_match("/X-Sender-IP\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; $header->priority = (\preg_match("/Priority\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; $header->importance = (\preg_match("/Importance\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; $header->sensitivity = (\preg_match("/Sensitivity\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; @@ -1192,12 +1199,17 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object $fileName = $this->decodeRFC2231($fileName); } - $partStructure_id = ($partStructure->ifid && isset($partStructure->id)) ? $partStructure->id : null; + $partStructure_id = ($partStructure->ifid && isset($partStructure->id)) ? \trim($partStructure->id) : null; $attachment = new IncomingMailAttachment(); $attachment->id = \bin2hex(\random_bytes(20)); $attachment->contentId = isset($partStructure_id) ? \trim($partStructure_id, ' <>') : null; + $attachment->type = isset($partStructure->type) ? \trim($partStructure->type) : null; + $attachment->encoding = isset($partStructure->encoding) ? \trim($partStructure->encoding) : null; + $attachment->subtype = ($partStructure->ifsubtype && isset($partStructure->subtype)) ? \trim($partStructure->subtype) : null; + $attachment->description = ($partStructure->ifdescription && isset($partStructure->description)) ? \trim($partStructure->description) : null; $attachment->name = $fileName; + $attachment->sizeInBytes = isset($partStructure->bytes) ? $partStructure->bytes : null; $attachment->disposition = (isset($partStructure->disposition) && \is_string($partStructure->disposition)) ? $partStructure->disposition : null; /** @var scalar|array|object|resource|null */ From aaa18e32a2f7f21bef08a639eb7bd5a750515bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=A4tzig?= Date: Sun, 17 May 2020 21:51:55 +0200 Subject: [PATCH 19/73] Fixed 'trim expects string, int given' --- 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 8b601184..450efdb3 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1204,8 +1204,8 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object $attachment = new IncomingMailAttachment(); $attachment->id = \bin2hex(\random_bytes(20)); $attachment->contentId = isset($partStructure_id) ? \trim($partStructure_id, ' <>') : null; - $attachment->type = isset($partStructure->type) ? \trim($partStructure->type) : null; - $attachment->encoding = isset($partStructure->encoding) ? \trim($partStructure->encoding) : null; + $attachment->type = isset($partStructure->type) ? $partStructure->type : null; + $attachment->encoding = isset($partStructure->encoding) ? $partStructure->encoding : null; $attachment->subtype = ($partStructure->ifsubtype && isset($partStructure->subtype)) ? \trim($partStructure->subtype) : null; $attachment->description = ($partStructure->ifdescription && isset($partStructure->description)) ? \trim($partStructure->description) : null; $attachment->name = $fileName; From c69f786fb2b1bb2d0e39ba555b50e30f29134cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=A4tzig?= Date: Sun, 17 May 2020 22:32:46 +0200 Subject: [PATCH 20/73] #416: Added file info properties to attachments --- composer.json | 2 +- src/PhpImap/IncomingMail.php | 2 +- src/PhpImap/IncomingMailAttachment.php | 33 +++++++++++++++++++++----- src/PhpImap/Mailbox.php | 6 +++++ 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index a57ff16d..f9cafcd7 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,7 @@ ] }, "suggest": { - "ext-fileinfo": "To facilitate IncomingMailAttachment::getMimeType() auto-detection" + "ext-fileinfo": "To facilitate IncomingMailAttachment::getFileInfo() auto-detection" }, "autoload-dev": { "psr-4": { diff --git a/src/PhpImap/IncomingMail.php b/src/PhpImap/IncomingMail.php index c253e830..5d962459 100644 --- a/src/PhpImap/IncomingMail.php +++ b/src/PhpImap/IncomingMail.php @@ -215,7 +215,7 @@ public function embedImageAttachments(): void foreach ($this->getAttachments() as $attachment) { if ($attachment->contentId == $cid && 'inline' == $attachment->disposition) { $contents = $attachment->getContents(); - $contentType = $attachment->getMimeType(); + $contentType = $attachment->getFileInfo(FILEINFO_MIME); if (!\strstr($contentType, 'image')) { continue; diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 72984b64..c4f58ae7 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -49,6 +49,21 @@ class IncomingMailAttachment /** @var bool|null */ public $emlOrigin; + /** @var string|null */ + public $fileInfoRaw; + + /** @var string|null */ + public $fileInfo; + + /** @var string|null */ + public $mime; + + /** @var string|null */ + public $mimeEncoding; + + /** @var string|null */ + public $fileExtension; + /** @var string|null */ private $file_path; @@ -106,17 +121,23 @@ public function addDataPartInfo(DataPartInfo $dataInfo): void } /** - * Gets the MIME type. + * Gets information about a file. + * + * @param const $fileinfo_const Any predefined constant. See https://www.php.net/manual/en/fileinfo.constants.php */ - public function getMimeType(): string + public function getFileInfo($fileinfo_const = FILEINFO_NONE): string { - if (!$this->mimeType) { - $finfo = new finfo(FILEINFO_MIME); + if (($fileinfo_const == FILEINFO_MIME) AND ($this->mimeType != false)) { + return $this->mimeType; + } + + $finfo = new finfo($fileinfo_const); - $this->mimeType = $finfo->buffer($this->getContents()); + if (!$finfo) { + return null; } - return $this->mimeType; + return $finfo->buffer($this->getContents()); } /** diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 450efdb3..d690650c 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1223,6 +1223,12 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object $attachment->addDataPartInfo($dataInfo); + $attachment->fileInfoRaw = $attachment->getFileInfo(FILEINFO_RAW); + $attachment->fileInfo = $attachment->getFileInfo(FILEINFO_NONE); + $attachment->mime = $attachment->getFileInfo(FILEINFO_MIME); + $attachment->mimeEncoding = $attachment->getFileInfo(FILEINFO_MIME_ENCODING); + $attachment->fileExtension = $attachment->getFileInfo(FILEINFO_EXTENSION); + $attachmentsDir = $this->getAttachmentsDir(); if (null != $attachmentsDir) { From a1f383d804b8bdead93ba2b415179ebc6120fc2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=A4tzig?= Date: Sun, 17 May 2020 22:43:46 +0200 Subject: [PATCH 21/73] Added try-catch to avoid not catched exception error messages --- src/PhpImap/IncomingMailAttachment.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index c4f58ae7..68563fdc 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -4,6 +4,7 @@ namespace PhpImap; +use Exception; use finfo; use UnexpectedValueException; @@ -131,7 +132,11 @@ public function getFileInfo($fileinfo_const = FILEINFO_NONE): string return $this->mimeType; } - $finfo = new finfo($fileinfo_const); + try { + $finfo = new finfo($fileinfo_const); + } catch (Exception $ex) { + return null; + } if (!$finfo) { return null; From 69860180e8afb4e5acd6e3c934d5e03e5dd0b59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=A4tzig?= Date: Sun, 17 May 2020 22:50:48 +0200 Subject: [PATCH 22/73] Updated comment formatting --- src/PhpImap/IncomingMailAttachment.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 68563fdc..3ec52423 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -71,9 +71,7 @@ class IncomingMailAttachment /** @var DataPartInfo|null */ private $dataInfo; - /** - * @var string|null - */ + /** @var string|null */ private $mimeType; /** @var string|null */ From fd345799cff6e203603093871745f205f269991e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=A4tzig?= Date: Sun, 17 May 2020 23:32:53 +0200 Subject: [PATCH 23/73] #406: Added imapPath and mailboxFolder as property to IncomingMailHeader --- src/PhpImap/IncomingMailHeader.php | 6 ++++++ src/PhpImap/Mailbox.php | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/PhpImap/IncomingMailHeader.php b/src/PhpImap/IncomingMailHeader.php index 69e55cf4..b2d48255 100644 --- a/src/PhpImap/IncomingMailHeader.php +++ b/src/PhpImap/IncomingMailHeader.php @@ -14,6 +14,12 @@ class IncomingMailHeader /** @var int|null The IMAP message ID - not the "Message-ID:"-header of the email */ public $id; + /** @var string */ + public $imapPath; + + /** @var string */ + public $mailboxFolder; + /** @var bool */ public $isDraft = false; diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index d690650c..10a82a19 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -104,6 +104,9 @@ class Mailbox /** @var string */ protected $pathDelimiter = '.'; + /** @var string */ + protected $mailboxFolder; + /** @var resource|null */ private $imapStream; @@ -119,6 +122,8 @@ public function __construct(string $imapPath, string $login, string $password, s if (null != $attachmentsDir) { $this->setAttachmentsDir($attachmentsDir); } + + $this->setMailboxFolder(); } /** @@ -426,6 +431,17 @@ public function decodeStringFromUtf7ImapToUtf8(string $str): string return $out; } + /** + * Sets the folder of the current mailbox. + * + * @return void + */ + public function setMailboxFolder(): void + { + $imapPathParts = explode('}', $this->imapPath); + $this->mailboxFolder = (!empty($imapPathParts[1])) ? $imapPathParts[1] : 'INBOX'; + } + /** * Switch mailbox without opening a new connection. * @@ -439,6 +455,8 @@ public function switchMailbox(string $imapPath, bool $absolute = true): void $this->imapPath = $this->getCombinedPath($imapPath, $absolute); } + $this->setMailboxFolder(); + Imap::reopen($this->getImapStream(), $this->imapPath); } @@ -1021,6 +1039,8 @@ public function getMailHeader(int $mailId): IncomingMailHeader $header->headersRaw = $headersRaw; $header->headers = $head; $header->id = $mailId; + $header->imapPath = $this->imapPath; + $header->mailboxFolder = $this->mailboxFolder; $header->isDraft = (!isset($head->date)) ? true : false; $header->mimeVersion = (\preg_match("/MIME-Version\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; $header->xVirusScanned = (\preg_match("/X-Virus-Scanned\:(.*)/i", $headersRaw, $matches)) ? \trim($matches[1]) : ''; From 24d6afb9bc3b68b296f2ed04a49c2ddb541e0d48 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 10:15:09 +0100 Subject: [PATCH 24/73] php-cs-fixer: phpdoc_scalar --- src/PhpImap/IncomingMailAttachment.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 3ec52423..082f9af5 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -23,10 +23,10 @@ class IncomingMailAttachment /** @var string|null */ public $contentId; - /** @var integer|null */ + /** @var int|null */ public $type; - /** @var integer|null */ + /** @var int|null */ public $encoding; /** @var string|null */ @@ -38,7 +38,7 @@ class IncomingMailAttachment /** @var string|null */ public $name; - /** @var integer|null */ + /** @var int|null */ public $sizeInBytes; /** @var string|null */ From 91c32a882fac97deee8cdd5eaa9ec4891d59591d Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 10:16:24 +0100 Subject: [PATCH 25/73] php-cs-fixer: lowercase_keywords --- src/PhpImap/IncomingMailAttachment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 082f9af5..94b52b59 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -126,7 +126,7 @@ public function addDataPartInfo(DataPartInfo $dataInfo): void */ public function getFileInfo($fileinfo_const = FILEINFO_NONE): string { - if (($fileinfo_const == FILEINFO_MIME) AND ($this->mimeType != false)) { + if (($fileinfo_const == FILEINFO_MIME) and ($this->mimeType != false)) { return $this->mimeType; } From 63e90ab35192c6963ee4a2551df51b778fc13532 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 10:17:01 +0100 Subject: [PATCH 26/73] php-cs-fixer: yoda_style --- src/PhpImap/IncomingMailAttachment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 94b52b59..02abd055 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -126,7 +126,7 @@ public function addDataPartInfo(DataPartInfo $dataInfo): void */ public function getFileInfo($fileinfo_const = FILEINFO_NONE): string { - if (($fileinfo_const == FILEINFO_MIME) and ($this->mimeType != false)) { + if ((FILEINFO_MIME == $fileinfo_const) and (false != $this->mimeType)) { return $this->mimeType; } From f95efd434f30e8d9f4a4e254cb6dbfdeafd8c1a0 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 10:17:56 +0100 Subject: [PATCH 27/73] php-cs-fixer: no_superfluous_phpdoc_tags,phpdoc_trim --- src/PhpImap/Mailbox.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 612b5d18..ad922a01 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -433,8 +433,6 @@ public function decodeStringFromUtf7ImapToUtf8(string $str): string /** * Sets the folder of the current mailbox. - * - * @return void */ public function setMailboxFolder(): void { From 1d92ad1aebf3c7d7c4b9feda08a98c5881c31ab7 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 10:18:16 +0100 Subject: [PATCH 28/73] php-cs-fixer: native_function_invocation --- 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 ad922a01..a177b71e 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -436,7 +436,7 @@ public function decodeStringFromUtf7ImapToUtf8(string $str): string */ public function setMailboxFolder(): void { - $imapPathParts = explode('}', $this->imapPath); + $imapPathParts = \explode('}', $this->imapPath); $this->mailboxFolder = (!empty($imapPathParts[1])) ? $imapPathParts[1] : 'INBOX'; } From d69972a714f056c478a4f4212ab515631e256ea3 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 10:54:01 +0100 Subject: [PATCH 29/73] import used consts --- src/PhpImap/IncomingMailAttachment.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 02abd055..65b0e258 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -5,6 +5,8 @@ namespace PhpImap; use Exception; +use const FILEINFO_MIME; +use const FILEINFO_NONE; use finfo; use UnexpectedValueException; From 974da39e1144c761498e1163c1a57958b72fbb0a Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 10:54:36 +0100 Subject: [PATCH 30/73] satisfying psalm re: param & return signature * const is not a type that psalm recognises * declaring a psalm-type with the supported consts hardcoded might not be preferrable in the long-run * a method with a scalar return type whose body returns null should not use a non-nullable scalar return type --- src/PhpImap/IncomingMailAttachment.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 65b0e258..cec76f4c 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -16,6 +16,8 @@ * @author Barbushin Sergey http://linkedin.com/in/barbushin * * @property string $filePath lazy attachment data file + * + * @psalm-type fileinfoconst = 0|2|16|1024|1040|8|32|128|256|16777216 */ class IncomingMailAttachment { @@ -124,9 +126,13 @@ public function addDataPartInfo(DataPartInfo $dataInfo): void /** * Gets information about a file. * - * @param const $fileinfo_const Any predefined constant. See https://www.php.net/manual/en/fileinfo.constants.php + * @param int $fileinfo_const Any predefined constant. See https://www.php.net/manual/en/fileinfo.constants.php + * + * @psalm-param fileinfoconst $fileinfo_const + * + * @return string|null */ - public function getFileInfo($fileinfo_const = FILEINFO_NONE): string + public function getFileInfo($fileinfo_const = FILEINFO_NONE) { if ((FILEINFO_MIME == $fileinfo_const) and (false != $this->mimeType)) { return $this->mimeType; From eac8776a1dd1d51f360472f6cecb356ae7884a33 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 10:57:56 +0100 Subject: [PATCH 31/73] removing redundant falsey check + return one does not need to perform a conditional return for falsey types if one returns inside a try-catch loop against an object constructor. --- src/PhpImap/IncomingMailAttachment.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index cec76f4c..87e5f5a1 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -140,15 +140,11 @@ public function getFileInfo($fileinfo_const = FILEINFO_NONE) try { $finfo = new finfo($fileinfo_const); - } catch (Exception $ex) { - return null; - } - if (!$finfo) { + return $finfo->buffer($this->getContents()); + } catch (Exception $ex) { return null; } - - return $finfo->buffer($this->getContents()); } /** From 219eee26a2f94d314f633f9e14b10734a2a36059 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 10:59:49 +0100 Subject: [PATCH 32/73] swapping Exception for Throwable --- src/PhpImap/IncomingMailAttachment.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 87e5f5a1..85ef0000 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -4,10 +4,10 @@ namespace PhpImap; -use Exception; use const FILEINFO_MIME; use const FILEINFO_NONE; use finfo; +use Throwable; use UnexpectedValueException; /** @@ -142,7 +142,7 @@ public function getFileInfo($fileinfo_const = FILEINFO_NONE) $finfo = new finfo($fileinfo_const); return $finfo->buffer($this->getContents()); - } catch (Exception $ex) { + } catch (Throwable $ex) { return null; } } From 91fa8bb44972c39c6e8effb31ebde0986e9d66a9 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 11:00:04 +0100 Subject: [PATCH 33/73] adjusting new property docblocks properties not initialised in a class constructor that have no default value need to be nullable. --- src/PhpImap/IncomingMailHeader.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpImap/IncomingMailHeader.php b/src/PhpImap/IncomingMailHeader.php index b2d48255..6f03a40d 100644 --- a/src/PhpImap/IncomingMailHeader.php +++ b/src/PhpImap/IncomingMailHeader.php @@ -14,10 +14,10 @@ class IncomingMailHeader /** @var int|null The IMAP message ID - not the "Message-ID:"-header of the email */ public $id; - /** @var string */ + /** @var string|null */ public $imapPath; - /** @var string */ + /** @var string|null */ public $mailboxFolder; /** @var bool */ From a563ad9f70eae3ade88af10b1a97ce54c5ba62b5 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 11:01:11 +0100 Subject: [PATCH 34/73] throwing on unexpected types --- src/PhpImap/Mailbox.php | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index a177b71e..6717790c 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -1217,17 +1217,35 @@ public function downloadAttachment(DataPartInfo $dataInfo, array $params, object $fileName = $this->decodeRFC2231($fileName); } + /** @var scalar|array|object|null */ + $sizeInBytes = isset($partStructure->bytes) ? $partStructure->bytes : null; + + /** @var scalar|array|object|null */ + $encoding = isset($partStructure->encoding) ? $partStructure->encoding : null; + + if (null !== $sizeInBytes && !\is_int($sizeInBytes)) { + throw new UnexpectedValueException('Supplied part structure specifies a non-integer, non-null bytes header!'); + } + if (null !== $encoding && !\is_int($encoding)) { + throw new UnexpectedValueException('Supplied part structure specifies a non-integer, non-null encoding header!'); + } + if (isset($partStructure->type) && !\is_int($partStructure->type)) { + throw new UnexpectedValueException('Supplied part structure specifies a non-integer, non-null type header!'); + } + $partStructure_id = ($partStructure->ifid && isset($partStructure->id)) ? \trim($partStructure->id) : null; $attachment = new IncomingMailAttachment(); $attachment->id = \bin2hex(\random_bytes(20)); $attachment->contentId = isset($partStructure_id) ? \trim($partStructure_id, ' <>') : null; - $attachment->type = isset($partStructure->type) ? $partStructure->type : null; - $attachment->encoding = isset($partStructure->encoding) ? $partStructure->encoding : null; + if (isset($partStructure->type)) { + $attachment->type = $partStructure->type; + } + $attachment->encoding = $encoding; $attachment->subtype = ($partStructure->ifsubtype && isset($partStructure->subtype)) ? \trim($partStructure->subtype) : null; - $attachment->description = ($partStructure->ifdescription && isset($partStructure->description)) ? \trim($partStructure->description) : null; + $attachment->description = ($partStructure->ifdescription && isset($partStructure->description)) ? \trim((string) $partStructure->description) : null; $attachment->name = $fileName; - $attachment->sizeInBytes = isset($partStructure->bytes) ? $partStructure->bytes : null; + $attachment->sizeInBytes = $sizeInBytes; $attachment->disposition = (isset($partStructure->disposition) && \is_string($partStructure->disposition)) ? $partStructure->disposition : null; /** @var scalar|array|object|resource|null */ From 84388937477e8d976bef5b8a27f44d93b5fd7d5e Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 18 May 2020 11:01:20 +0100 Subject: [PATCH 35/73] typecasting to avoid extra condition check --- src/PhpImap/IncomingMail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpImap/IncomingMail.php b/src/PhpImap/IncomingMail.php index 5d962459..dbfd9822 100644 --- a/src/PhpImap/IncomingMail.php +++ b/src/PhpImap/IncomingMail.php @@ -215,7 +215,7 @@ public function embedImageAttachments(): void foreach ($this->getAttachments() as $attachment) { if ($attachment->contentId == $cid && 'inline' == $attachment->disposition) { $contents = $attachment->getContents(); - $contentType = $attachment->getFileInfo(FILEINFO_MIME); + $contentType = (string) $attachment->getFileInfo(FILEINFO_MIME); if (!\strstr($contentType, 'image')) { continue; From 8cee644504a9b172bdd38916821bc2e10bff4f8b Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 10:26:40 +0100 Subject: [PATCH 36/73] updating baseline --- psalm.baseline.xml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/psalm.baseline.xml b/psalm.baseline.xml index 36fc39b2..574fdf31 100644 --- a/psalm.baseline.xml +++ b/psalm.baseline.xml @@ -1,5 +1,5 @@ - + $mailbox @@ -34,13 +34,6 @@ $element->charset $element->text - - array - - - $lowercase_encodings - $lowercase_encodings - setConnectionRetry setConnectionRetryDelay From 424d87d213ad3b26f15b2bf6ddcd01e949b026a6 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 10:16:25 +0100 Subject: [PATCH 37/73] throw connection exception --- src/PhpImap/Imap.php | 79 +++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/src/PhpImap/Imap.php b/src/PhpImap/Imap.php index c767616d..4cc1a73e 100644 --- a/src/PhpImap/Imap.php +++ b/src/PhpImap/Imap.php @@ -21,6 +21,7 @@ use const SORTSIZE; use const SORTSUBJECT; use const SORTTO; +use Throwable; use UnexpectedValueException; /** @@ -79,7 +80,7 @@ public static function append( ): bool { \imap_errors(); // flush errors - $imap_stream = self::EnsureResource($imap_stream, __METHOD__, 1); + $imap_stream = self::EnsureConnection($imap_stream, __METHOD__, 1); if (null !== $options && null !== $internal_date) { $result = \imap_append( @@ -113,7 +114,7 @@ public static function body( \imap_errors(); // flush errors $result = \imap_body( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), $msg_number, $options ); @@ -132,7 +133,7 @@ public static function check($imap_stream): object { \imap_errors(); // flush errors - $result = \imap_check(self::EnsureResource($imap_stream, __METHOD__, 1)); + $result = \imap_check(self::EnsureConnection($imap_stream, __METHOD__, 1)); if (false === $result) { throw new UnexpectedValueException('Could not check imap mailbox!', 0, self::HandleErrors(\imap_errors(), 'imap_check')); @@ -157,7 +158,7 @@ public static function clearflag_full( \imap_errors(); // flush errors $result = \imap_clearflag_full( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), self::encodeStringToUtf7Imap(static::EnsureRange( $sequence, __METHOD__, @@ -187,7 +188,7 @@ public static function close($imap_stream, int $flag = 0): bool { \imap_errors(); // flush errors - $result = \imap_close(self::EnsureResource($imap_stream, __METHOD__, 1), $flag); + $result = \imap_close(self::EnsureConnection($imap_stream, __METHOD__, 1), $flag); if (false === $result) { $message = 'Could not close imap connection'; @@ -213,7 +214,7 @@ public static function createmailbox($imap_stream, string $mailbox): bool \imap_errors(); // flush errors $result = \imap_createmailbox( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), static::encodeStringToUtf7Imap($mailbox) ); @@ -249,7 +250,7 @@ public static function delete( \imap_errors(); // flush errors $result = \imap_delete( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), $msg_number, $options ); @@ -271,7 +272,7 @@ public static function deletemailbox($imap_stream, string $mailbox): bool \imap_errors(); // flush errors $result = \imap_deletemailbox( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), static::encodeStringToUtf7Imap($mailbox) ); @@ -292,7 +293,7 @@ public static function expunge($imap_stream): bool \imap_errors(); // flush errors $result = \imap_expunge( - self::EnsureResource($imap_stream, __METHOD__, 1) + self::EnsureConnection($imap_stream, __METHOD__, 1) ); if (false === $result) { @@ -318,7 +319,7 @@ public static function fetch_overview( \imap_errors(); // flush errors $result = \imap_fetch_overview( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), self::encodeStringToUtf7Imap(self::EnsureRange( $sequence, __METHOD__, @@ -353,7 +354,7 @@ public static function fetchbody( \imap_errors(); // flush errors $result = \imap_fetchbody( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), $msg_number, self::encodeStringToUtf7Imap((string) $section), $options @@ -377,7 +378,7 @@ public static function fetchheader( \imap_errors(); // flush errors $result = \imap_fetchheader( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), $msg_number, $options ); @@ -402,7 +403,7 @@ public static function fetchstructure( \imap_errors(); // flush errors $result = \imap_fetchstructure( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), $msg_number, $options ); @@ -427,7 +428,7 @@ public static function get_quotaroot( \imap_errors(); // flush errors $result = \imap_get_quotaroot( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), self::encodeStringToUtf7Imap($quota_root) ); @@ -453,7 +454,7 @@ public static function getmailboxes( \imap_errors(); // flush errors $result = \imap_getmailboxes( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), $ref, $pattern ); @@ -491,7 +492,7 @@ public static function getsubscribed( \imap_errors(); // flush errors $result = \imap_getsubscribed( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), $ref, $pattern ); @@ -512,7 +513,7 @@ public static function headers($imap_stream): array \imap_errors(); // flush errors $result = \imap_headers( - self::EnsureResource($imap_stream, __METHOD__, 1) + self::EnsureConnection($imap_stream, __METHOD__, 1) ); if (false === $result) { @@ -534,7 +535,7 @@ public static function listOfMailboxes($imap_stream, string $ref, string $patter \imap_errors(); // flush errors $result = \imap_list( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), static::encodeStringToUtf7Imap($ref), static::encodeStringToUtf7Imap($pattern) ); @@ -589,7 +590,7 @@ public static function mail_copy( \imap_errors(); // flush errors $result = \imap_mail_copy( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), static::encodeStringToUtf7Imap(self::EnsureRange( $msglist, __METHOD__, @@ -622,7 +623,7 @@ public static function mail_move( \imap_errors(); // flush errors $result = \imap_mail_move( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), static::encodeStringToUtf7Imap(self::EnsureRange( $msglist, __METHOD__, @@ -648,7 +649,7 @@ public static function mailboxmsginfo($imap_stream): object \imap_errors(); // flush errors $result = \imap_mailboxmsginfo( - self::EnsureResource($imap_stream, __METHOD__, 1) + self::EnsureConnection($imap_stream, __METHOD__, 1) ); if (false === $result) { @@ -665,7 +666,7 @@ public static function num_msg($imap_stream): int { \imap_errors(); // flush errors - $result = \imap_num_msg(self::EnsureResource($imap_stream, __METHOD__, 1)); + $result = \imap_num_msg(self::EnsureConnection($imap_stream, __METHOD__, 1)); if (false === $result) { throw new UnexpectedValueException('Could not get the number of messages in the mailbox!', 0, self::HandleErrors(\imap_errors(), 'imap_num_msg')); @@ -730,7 +731,7 @@ public static function renamemailbox( string $old_mbox, string $new_mbox ): bool { - $imap_stream = self::EnsureResource($imap_stream, __METHOD__, 1); + $imap_stream = self::EnsureConnection($imap_stream, __METHOD__, 1); $old_mbox = static::encodeStringToUtf7Imap($old_mbox); $new_mbox = static::encodeStringToUtf7Imap($new_mbox); @@ -757,7 +758,7 @@ public static function reopen( int $options = 0, int $n_retries = 0 ): bool { - $imap_stream = self::EnsureResource($imap_stream, __METHOD__, 1); + $imap_stream = self::EnsureConnection($imap_stream, __METHOD__, 1); $mailbox = static::encodeStringToUtf7Imap($mailbox); @@ -785,7 +786,7 @@ public static function savebody( string $part_number = '', int $options = 0 ): bool { - $imap_stream = self::EnsureResource($imap_stream, __METHOD__, 1); + $imap_stream = self::EnsureConnection($imap_stream, __METHOD__, 1); $file = \is_string($file) ? $file : self::EnsureResource($file, __METHOD__, 2); $part_number = self::encodeStringToUtf7Imap($part_number); @@ -815,7 +816,7 @@ public static function search( ): array { \imap_errors(); // flush errors - $imap_stream = static::EnsureResource($imap_stream, __METHOD__, 1); + $imap_stream = static::EnsureConnection($imap_stream, __METHOD__, 1); $criteria = static::encodeStringToUtf7Imap($criteria); if (\is_string($charset)) { @@ -862,7 +863,7 @@ public static function setflag_full( \imap_errors(); // flush errors $result = \imap_setflag_full( - self::EnsureResource($imap_stream, __METHOD__, 1), + self::EnsureConnection($imap_stream, __METHOD__, 1), self::encodeStringToUtf7Imap(static::EnsureRange( $sequence, __METHOD__, @@ -900,7 +901,7 @@ public static function sort( ): array { \imap_errors(); // flush errors - $imap_stream = self::EnsureResource($imap_stream, __METHOD__, 1); + $imap_stream = self::EnsureConnection($imap_stream, __METHOD__, 1); $reverse = (int) $reverse; if (null !== $search_criteria && null !== $charset) { @@ -947,7 +948,7 @@ public static function status( string $mailbox, int $options ): object { - $imap_stream = self::EnsureResource($imap_stream, __METHOD__, 1); + $imap_stream = self::EnsureConnection($imap_stream, __METHOD__, 1); $mailbox = static::encodeStringToUtf7Imap($mailbox); @@ -969,7 +970,7 @@ public static function subscribe( $imap_stream, string $mailbox ): void { - $imap_stream = self::EnsureResource($imap_stream, __METHOD__, 1); + $imap_stream = self::EnsureConnection($imap_stream, __METHOD__, 1); $mailbox = static::encodeStringToUtf7Imap($mailbox); @@ -1013,7 +1014,7 @@ public static function unsubscribe( $imap_stream, string $mailbox ): void { - $imap_stream = self::EnsureResource($imap_stream, __METHOD__, 1); + $imap_stream = self::EnsureConnection($imap_stream, __METHOD__, 1); $mailbox = static::encodeStringToUtf7Imap($mailbox); @@ -1075,6 +1076,22 @@ private static function EnsureResource($maybe, string $method, int $argument) return $maybe; } + /** + * @param false|resource $maybe + * + * @throws Exceptions\ConnectionException if $maybe is not a valid resource + * + * @return resource + */ + private static function EnsureConnection($maybe, string $method, int $argument) + { + try { + return self::EnsureResource($maybe, $method, $argument); + } catch (Throwable $e) { + throw new Exceptions\ConnectionException('Argument '.(string) $argument.' passed to '.$method.' must be valid resource!', 0, $e); + } + } + /** * @param array|false $errors */ From 4221f9826b3650288a1974e735e04b80d811467b Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 10:31:15 +0100 Subject: [PATCH 38/73] remove redundant try-catch block, restoring string return type --- src/PhpImap/IncomingMailAttachment.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index 85ef0000..a9b97cdb 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -7,7 +7,6 @@ use const FILEINFO_MIME; use const FILEINFO_NONE; use finfo; -use Throwable; use UnexpectedValueException; /** @@ -129,22 +128,16 @@ public function addDataPartInfo(DataPartInfo $dataInfo): void * @param int $fileinfo_const Any predefined constant. See https://www.php.net/manual/en/fileinfo.constants.php * * @psalm-param fileinfoconst $fileinfo_const - * - * @return string|null */ - public function getFileInfo($fileinfo_const = FILEINFO_NONE) + public function getFileInfo($fileinfo_const = FILEINFO_NONE): string { if ((FILEINFO_MIME == $fileinfo_const) and (false != $this->mimeType)) { return $this->mimeType; } - try { $finfo = new finfo($fileinfo_const); return $finfo->buffer($this->getContents()); - } catch (Throwable $ex) { - return null; - } } /** From d684d615dc334c84ef41224e623a5bbdea28a3e6 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 10:31:38 +0100 Subject: [PATCH 39/73] adjusting indentation --- src/PhpImap/IncomingMailAttachment.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpImap/IncomingMailAttachment.php b/src/PhpImap/IncomingMailAttachment.php index a9b97cdb..66a60784 100644 --- a/src/PhpImap/IncomingMailAttachment.php +++ b/src/PhpImap/IncomingMailAttachment.php @@ -135,9 +135,9 @@ public function getFileInfo($fileinfo_const = FILEINFO_NONE): string return $this->mimeType; } - $finfo = new finfo($fileinfo_const); + $finfo = new finfo($fileinfo_const); - return $finfo->buffer($this->getContents()); + return $finfo->buffer($this->getContents()); } /** From 41c1a68a2fe62fa89675c39b54a42243e156d86e Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 25 May 2020 08:49:48 +0100 Subject: [PATCH 40/73] modify php-cs-fixer config to import consts as per https://github.com/barbushin/php-imap/pull/504#discussion_r429778492 --- .php_cs.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/.php_cs.dist b/.php_cs.dist index 1459ad4d..c2827a2b 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -18,6 +18,7 @@ return PhpCsFixer\Config::create() 'import_constants' => true, 'import_functions' => false, ], + 'native_constant_invocation' => true, 'native_function_invocation' => true, 'php_unit_test_case_static_method_calls' => [ 'call_type' => 'this', From 6f605b4534089c42915803bbfdde8165c2ab4b25 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 25 May 2020 08:51:05 +0100 Subject: [PATCH 41/73] import used consts --- src/PhpImap/DataPartInfo.php | 5 ++++ src/PhpImap/Imap.php | 1 + src/PhpImap/IncomingMail.php | 1 + src/PhpImap/Mailbox.php | 33 ++++++++++++++++++++++++++ tests/unit/IncomingMailTest.php | 2 ++ tests/unit/LiveMailboxIssue490Test.php | 1 + tests/unit/LiveMailboxTest.php | 4 ++++ tests/unit/MailboxTest.php | 15 ++++++++++++ 8 files changed, 62 insertions(+) diff --git a/src/PhpImap/DataPartInfo.php b/src/PhpImap/DataPartInfo.php index 3598844f..b02c1c94 100644 --- a/src/PhpImap/DataPartInfo.php +++ b/src/PhpImap/DataPartInfo.php @@ -4,6 +4,11 @@ namespace PhpImap; +use const ENC8BIT; +use const ENCBASE64; +use const ENCBINARY; +use const ENCQUOTEDPRINTABLE; + /** * @see https://github.com/barbushin/php-imap * diff --git a/src/PhpImap/Imap.php b/src/PhpImap/Imap.php index c767616d..76efd8c9 100644 --- a/src/PhpImap/Imap.php +++ b/src/PhpImap/Imap.php @@ -14,6 +14,7 @@ use const IMAP_WRITETIMEOUT; use InvalidArgumentException; use const NIL; +use const SE_FREE; use const SORTARRIVAL; use const SORTCC; use const SORTDATE; diff --git a/src/PhpImap/IncomingMail.php b/src/PhpImap/IncomingMail.php index dbfd9822..a0a573f5 100644 --- a/src/PhpImap/IncomingMail.php +++ b/src/PhpImap/IncomingMail.php @@ -4,6 +4,7 @@ namespace PhpImap; +use const FILEINFO_MIME; use InvalidArgumentException; /** diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 6717790c..4e242f91 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -4,14 +4,47 @@ namespace PhpImap; +use const CL_EXPUNGE; use function count; +use const CP_UID; +use const DATE_RFC3339; use DateTime; use const DIRECTORY_SEPARATOR; use Exception; +use const FILEINFO_EXTENSION; +use const FILEINFO_MIME; +use const FILEINFO_MIME_ENCODING; +use const FILEINFO_NONE; +use const FILEINFO_RAW; +use const FT_PEEK; +use const FT_PREFETCHTEXT; +use const FT_UID; +use const IMAP_CLOSETIMEOUT; +use const IMAP_OPENTIMEOUT; +use const IMAP_READTIMEOUT; +use const IMAP_WRITETIMEOUT; use InvalidArgumentException; +use const OP_ANONYMOUS; +use const OP_DEBUG; +use const OP_HALFOPEN; +use const OP_PROTOTYPE; +use const OP_READONLY; +use const OP_SECURE; +use const OP_SHORTCACHE; +use const OP_SILENT; +use const PATHINFO_EXTENSION; use PhpImap\Exceptions\ConnectionException; use PhpImap\Exceptions\InvalidParameterException; +use const SA_ALL; +use const SE_FREE; +use const SE_UID; +use const SORT_NUMERIC; +use const SORTARRIVAL; +use const ST_UID; use stdClass; +use const TYPEMESSAGE; +use const TYPEMULTIPART; +use const TYPETEXT; use UnexpectedValueException; /** diff --git a/tests/unit/IncomingMailTest.php b/tests/unit/IncomingMailTest.php index 03f3e136..a43ca775 100644 --- a/tests/unit/IncomingMailTest.php +++ b/tests/unit/IncomingMailTest.php @@ -6,6 +6,8 @@ namespace PhpImap; +use const DATE_RFC3339; +use const ENCOTHER; use PHPUnit\Framework\TestCase; class IncomingMailTest extends TestCase diff --git a/tests/unit/LiveMailboxIssue490Test.php b/tests/unit/LiveMailboxIssue490Test.php index fbc1e0e1..059ba8a6 100644 --- a/tests/unit/LiveMailboxIssue490Test.php +++ b/tests/unit/LiveMailboxIssue490Test.php @@ -12,6 +12,7 @@ use Exception; use ParagonIE\HiddenString\HiddenString; +use const TYPEMULTIPART; use const TYPETEXT; /** diff --git a/tests/unit/LiveMailboxTest.php b/tests/unit/LiveMailboxTest.php index 20f9d72e..b548d91d 100644 --- a/tests/unit/LiveMailboxTest.php +++ b/tests/unit/LiveMailboxTest.php @@ -11,9 +11,13 @@ namespace PhpImap; use function date; +use const ENCBASE64; use Exception; use Generator; use ParagonIE\HiddenString\HiddenString; +use const SORTARRIVAL; +use const TYPEAPPLICATION; +use const TYPEMULTIPART; use const TYPETEXT; /** diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index b28f27c4..d754021f 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -8,9 +8,24 @@ namespace PhpImap; +use const CL_EXPUNGE; use DateTime; +use const IMAP_CLOSETIMEOUT; +use const IMAP_OPENTIMEOUT; +use const IMAP_READTIMEOUT; +use const IMAP_WRITETIMEOUT; +use const OP_ANONYMOUS; +use const OP_DEBUG; +use const OP_HALFOPEN; +use const OP_PROTOTYPE; +use const OP_READONLY; +use const OP_SECURE; +use const OP_SHORTCACHE; +use const OP_SILENT; use PhpImap\Exceptions\InvalidParameterException; use PHPUnit\Framework\TestCase; +use const SE_FREE; +use const SE_UID; final class MailboxTest extends TestCase { From 49fdd9610f3b8322159e14124492323a4f1eebf3 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 25 May 2020 11:20:22 +0100 Subject: [PATCH 42/73] add test for barbushin/php-imap#509 --- tests/unit/Issue509.php | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/unit/Issue509.php diff --git a/tests/unit/Issue509.php b/tests/unit/Issue509.php new file mode 100644 index 00000000..89c2e1e2 --- /dev/null +++ b/tests/unit/Issue509.php @@ -0,0 +1,56 @@ +decodeMimeStrDefaultCharset = 'EUC-KR'; + $decoded = $mailbox->decodeMimeStr(\base64_decode(self::base64)); + + $this->assertSame(self::sha256, \hash('sha256', $decoded)); + } +} From 8592c57dcdaeaa50165c7ab984859d2f005dc4a3 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 25 May 2020 11:20:54 +0100 Subject: [PATCH 43/73] allow Mailbox::decodeMimeStr() default charset to be overridden --- src/PhpImap/Mailbox.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 6717790c..b3991b9b 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -55,6 +55,9 @@ class Mailbox const PART_TYPE_TWO = 2; + /** @var string */ + public $decodeMimeStrDefaultCharset = 'default'; + /** @var string */ protected $imapPath; @@ -1304,18 +1307,24 @@ public function decodeMimeStr(string $string): string } foreach ($elements as $element) { - switch (\strtolower($element->charset)) { + $charset = \strtolower($element->charset); + + if ('default' === $charset) { + $charset = $this->decodeMimeStrDefaultCharset; + } + + switch ($charset) { case 'default': // Charset default is already ASCII (not encoded) case 'utf-8': // Charset UTF-8 is OK $newString .= $element->text; break; default: // If charset exists in mb_list_encodings(), convert using mb_convert function - if (\in_array(\strtolower($element->charset), $this->lowercase_mb_list_encodings())) { - $newString .= \mb_convert_encoding($element->text, 'UTF-8', $element->charset); + if (\in_array($charset, $this->lowercase_mb_list_encodings())) { + $newString .= \mb_convert_encoding($element->text, 'UTF-8', $charset); } else { // Fallback: Try to convert with iconv() - $iconv_converted_string = @\iconv($element->charset, 'UTF-8', $element->text); + $iconv_converted_string = @\iconv($charset, 'UTF-8', $element->text); if (!$iconv_converted_string) { // If iconv() could also not convert, return string as it is // (unknown charset) From 9357b22ae13be6bca79cfd0940531bd9d57676a6 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 24 May 2020 11:26:57 +0100 Subject: [PATCH 44/73] having test method always return fixture --- tests/unit/MailboxTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index d754021f..e504a940 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -755,8 +755,8 @@ public function testAttachmentDirFailure(string $initialDir, string $attachments $mailbox->setAttachmentsDir($attachmentsDir); } - protected function getMailbox(): Mailbox + protected function getMailbox(): Fixtures\Mailbox { - return new Mailbox($this->imapPath, $this->login, $this->password, $this->attachmentsDir, $this->serverEncoding); + return new Fixtures\Mailbox($this->imapPath, $this->login, $this->password, $this->attachmentsDir, $this->serverEncoding); } } From 560a13f39020d33c34f77a48a39686a4c6016185 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 24 May 2020 11:27:16 +0100 Subject: [PATCH 45/73] assert options have been set as expected --- tests/unit/Fixtures/Mailbox.php | 5 +++++ tests/unit/MailboxTest.php | 1 + 2 files changed, 6 insertions(+) diff --git a/tests/unit/Fixtures/Mailbox.php b/tests/unit/Fixtures/Mailbox.php index 60c7e736..0e9fa456 100644 --- a/tests/unit/Fixtures/Mailbox.php +++ b/tests/unit/Fixtures/Mailbox.php @@ -12,4 +12,9 @@ public function getImapPassword(): string { return $this->imapPassword; } + + public function getImapOptions(): int + { + return $this->imapOptions; + } } diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index e504a940..274360a2 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -642,6 +642,7 @@ public function testSetConnectionArgs(string $assertMethod, int $option, int $re if ('expectException' == $assertMethod) { $this->expectException(InvalidParameterException::class); $mailbox->setConnectionArgs($option, $retriesNum, $param); + $this->assertSame($option, $mailbox->getImapOptions()); } elseif ('assertNull' == $assertMethod) { $this->assertNull($mailbox->setConnectionArgs($option, $retriesNum, $param)); } From 012e933087a929f5e813700e2f05af73abcf9102 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 24 May 2020 11:27:58 +0100 Subject: [PATCH 46/73] remove duplicate test cases, switch to generator generator return type more easily allows test cases to be dynamically compiled --- tests/unit/MailboxTest.php | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index 274360a2..49c08926 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -10,6 +10,7 @@ use const CL_EXPUNGE; use DateTime; +use Generator; use const IMAP_CLOSETIMEOUT; use const IMAP_OPENTIMEOUT; use const IMAP_READTIMEOUT; @@ -599,31 +600,44 @@ public function testSetTimeouts(string $assertMethod, int $timeout, array $types /** * Provides test data for testing connection args. * - * @psalm-return list}> + * @psalm-return Generator}> */ - public function connectionArgsProvider(): array + public function connectionArgsProvider(): Generator { - /** @psalm-var list}> */ - return [ - ['assertNull', OP_READONLY, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + yield from [ + 'readonly, disable gssapi' => ['assertNull', OP_READONLY, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'anonymous, disable gssapi' => ['assertNull', OP_ANONYMOUS, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'half open, disable gssapi' => ['assertNull', OP_HALFOPEN, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'expunge on close, disable gssapi' => ['assertNull', CL_EXPUNGE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'debug, disable gssapi' => ['assertNull', OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'short cache, disable gssapi' => ['assertNull', OP_SHORTCACHE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'silent, disable gssapi' => ['assertNull', OP_SILENT, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'return driver prototype, disable gssapi' => ['assertNull', OP_PROTOTYPE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'don\'t do non-secure authentication, disable gssapi' => ['assertNull', OP_SECURE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, disable gssapi, 1 retry' => ['assertNull', OP_READONLY, 1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, disable gssapi, 3 retries' => ['assertNull', OP_READONLY, 3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, disable gssapi, 12 retries' => ['assertNull', OP_READONLY, 12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - + 'readonly debug, disable gssapi' => ['expectException', OP_READONLY | OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, -1 retries' => ['expectException', OP_READONLY, -1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, -3 retries' => ['expectException', OP_READONLY, -3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, -12 retries' => ['expectException', OP_READONLY, -12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - ['expectException', OP_READONLY, -1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, null options' => ['expectException', OP_READONLY, 0, [null]], ]; } From 050c93d60aa2c0cb9f6cc98997744eccf8669135 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 24 May 2020 11:29:22 +0100 Subject: [PATCH 47/73] satisy php-cs-fixer --- tests/unit/MailboxTest.php | 51 +++++++++++++------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index 49c08926..49f5b406 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -605,40 +605,23 @@ public function testSetTimeouts(string $assertMethod, int $timeout, array $types public function connectionArgsProvider(): Generator { yield from [ - 'readonly, disable gssapi' => - ['assertNull', OP_READONLY, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'anonymous, disable gssapi' => - ['assertNull', OP_ANONYMOUS, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'half open, disable gssapi' => - ['assertNull', OP_HALFOPEN, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'expunge on close, disable gssapi' => - ['assertNull', CL_EXPUNGE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'debug, disable gssapi' => - ['assertNull', OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'short cache, disable gssapi' => - ['assertNull', OP_SHORTCACHE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'silent, disable gssapi' => - ['assertNull', OP_SILENT, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'return driver prototype, disable gssapi' => - ['assertNull', OP_PROTOTYPE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'don\'t do non-secure authentication, disable gssapi' => - ['assertNull', OP_SECURE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'readonly, disable gssapi, 1 retry' => - ['assertNull', OP_READONLY, 1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'readonly, disable gssapi, 3 retries' => - ['assertNull', OP_READONLY, 3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'readonly, disable gssapi, 12 retries' => - ['assertNull', OP_READONLY, 12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'readonly debug, disable gssapi' => - ['expectException', OP_READONLY | OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'readonly, -1 retries' => - ['expectException', OP_READONLY, -1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'readonly, -3 retries' => - ['expectException', OP_READONLY, -3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'readonly, -12 retries' => - ['expectException', OP_READONLY, -12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'readonly, null options' => - ['expectException', OP_READONLY, 0, [null]], + 'readonly, disable gssapi' => ['assertNull', OP_READONLY, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'anonymous, disable gssapi' => ['assertNull', OP_ANONYMOUS, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'half open, disable gssapi' => ['assertNull', OP_HALFOPEN, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'expunge on close, disable gssapi' => ['assertNull', CL_EXPUNGE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'debug, disable gssapi' => ['assertNull', OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'short cache, disable gssapi' => ['assertNull', OP_SHORTCACHE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'silent, disable gssapi' => ['assertNull', OP_SILENT, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'return driver prototype, disable gssapi' => ['assertNull', OP_PROTOTYPE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'don\'t do non-secure authentication, disable gssapi' => ['assertNull', OP_SECURE, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, disable gssapi, 1 retry' => ['assertNull', OP_READONLY, 1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, disable gssapi, 3 retries' => ['assertNull', OP_READONLY, 3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, disable gssapi, 12 retries' => ['assertNull', OP_READONLY, 12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly debug, disable gssapi' => ['expectException', OP_READONLY | OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, -1 retries' => ['expectException', OP_READONLY, -1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, -3 retries' => ['expectException', OP_READONLY, -3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, -12 retries' => ['expectException', OP_READONLY, -12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly, null options' => ['expectException', OP_READONLY, 0, [null]], ]; } From d84155377e6714aa800be53dba6fb8e8bcc26cd4 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 24 May 2020 11:30:01 +0100 Subject: [PATCH 48/73] dynamically compile mostly-exhaustive combinations this commit will fail as it lacks the replacement options validation --- tests/unit/MailboxTest.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index 49f5b406..8d02978a 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -623,6 +623,40 @@ public function connectionArgsProvider(): Generator 'readonly, -12 retries' => ['expectException', OP_READONLY, -12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], 'readonly, null options' => ['expectException', OP_READONLY, 0, [null]], ]; + + /** @psalm-var list */ + $options = [ + [OP_DEBUG, 'debug'], // 1 + [OP_READONLY, 'readonly'], // 2 + [OP_ANONYMOUS, 'anonymous'], // 4 + [OP_SHORTCACHE, 'short cache'], // 8 + [OP_SILENT, 'silent'], // 16 + [OP_PROTOTYPE, 'return driver prototype'], // 32 + [OP_HALFOPEN, 'half-open'], // 64 + [OP_SECURE, 'don\'t do non-secure authnetication'], // 256 + [CL_EXPUNGE, 'expunge on close'], // 32768 + ]; + + foreach ($options as $i => $option) { + $value = $option[0]; + + for ($j = $i + 1; $j < \count($options); ++$j) { + $value |= $options[$j][0]; + + $fields = []; + + foreach ($options as $option) { + if (0 !== ($value & $option[0])) { + $fields[] = $option[1]; + } + } + + $key = \implode(', ', $fields); + + yield $key => ['assertNull', $value, 0, []]; + yield ('INVALID + '.$key) => ['expectException', $value | 128, 0, []]; + } + } } /** From 7250e5574cf7e8594f832d739014b59e00080759 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 24 May 2020 11:33:32 +0100 Subject: [PATCH 49/73] allow bitmask options, fixes barbushin/php-imap#510 --- src/PhpImap/Mailbox.php | 15 +++++++++++++-- tests/unit/MailboxTest.php | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index 04762f9d..a50befbf 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -88,6 +88,18 @@ class Mailbox const PART_TYPE_TWO = 2; + const IMAP_OPTIONS_SUPPORTED_VALUES = + OP_READONLY // 2 + | OP_ANONYMOUS // 4 + | OP_HALFOPEN // 64 + | CL_EXPUNGE // 32768 + | OP_DEBUG // 1 + | OP_SHORTCACHE // 8 + | OP_SILENT // 16 + | OP_PROTOTYPE // 32 + | OP_SECURE // 256 + ; + /** @var string */ public $decodeMimeStrDefaultCharset = 'default'; @@ -338,8 +350,7 @@ public function getLogin(): string public function setConnectionArgs(int $options = 0, int $retriesNum = 0, array $params = null): void { if (0 !== $options) { - $supported_options = [OP_READONLY, OP_ANONYMOUS, OP_HALFOPEN, CL_EXPUNGE, OP_DEBUG, OP_SHORTCACHE, OP_SILENT, OP_PROTOTYPE, OP_SECURE]; - if (!\in_array($options, $supported_options, true)) { + 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; diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index 8d02978a..f1a54b1a 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -617,7 +617,7 @@ public function connectionArgsProvider(): Generator 'readonly, disable gssapi, 1 retry' => ['assertNull', OP_READONLY, 1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], 'readonly, disable gssapi, 3 retries' => ['assertNull', OP_READONLY, 3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], 'readonly, disable gssapi, 12 retries' => ['assertNull', OP_READONLY, 12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], - 'readonly debug, disable gssapi' => ['expectException', OP_READONLY | OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], + 'readonly debug, disable gssapi' => ['assertNull', OP_READONLY | OP_DEBUG, 0, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], 'readonly, -1 retries' => ['expectException', OP_READONLY, -1, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], 'readonly, -3 retries' => ['expectException', OP_READONLY, -3, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], 'readonly, -12 retries' => ['expectException', OP_READONLY, -12, ['DISABLE_AUTHENTICATOR' => 'GSSAPI']], From e9a70178189cc95f2b19fb87d65e40e72d75acb4 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 24 May 2020 11:38:48 +0100 Subject: [PATCH 50/73] add example of bitmask usage --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index bc222963..d97e108d 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,12 @@ $mailbox = new PhpImap\Mailbox( 'UTF-8' // Server encoding (optional) ); +// set some connection arguments (if appropriate) +$mailbox->setConnectionArgs( + CL_EXPUNGE // expunge deleted mails upon mailbox close + | OP_SECURE // don't do non-secure authentication +); + try { // Get all emails (messages) // PHP.net imap_search criteria: http://php.net/manual/en/function.imap-search.php From 86328f2cf9f6d6d424a38d52e6065c7b11c99446 Mon Sep 17 00:00:00 2001 From: Marv Date: Sun, 24 May 2020 11:40:41 +0100 Subject: [PATCH 51/73] explicitly disconnect during testing --- tests/unit/MailboxTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/MailboxTest.php b/tests/unit/MailboxTest.php index f1a54b1a..d3bd6387 100644 --- a/tests/unit/MailboxTest.php +++ b/tests/unit/MailboxTest.php @@ -677,6 +677,8 @@ public function testSetConnectionArgs(string $assertMethod, int $option, int $re } elseif ('assertNull' == $assertMethod) { $this->assertNull($mailbox->setConnectionArgs($option, $retriesNum, $param)); } + + $mailbox->disconnect(); } /** From f6b5cc504b923e30d76ad2128d029b3aa8432c74 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:21:21 +0100 Subject: [PATCH 52/73] moving methods for reuse --- tests/unit/AbstractLiveMailboxTest.php | 137 +++++++++++++++++++++++++ tests/unit/LiveMailboxTest.php | 117 --------------------- 2 files changed, 137 insertions(+), 117 deletions(-) diff --git a/tests/unit/AbstractLiveMailboxTest.php b/tests/unit/AbstractLiveMailboxTest.php index ff21ea5f..1578686c 100644 --- a/tests/unit/AbstractLiveMailboxTest.php +++ b/tests/unit/AbstractLiveMailboxTest.php @@ -10,6 +10,7 @@ namespace PhpImap; +use Generator; use ParagonIE\HiddenString\HiddenString; use PHPUnit\Framework\TestCase; @@ -21,6 +22,17 @@ * 3:string, * 4?:string * } + * @psalm-type COMPOSE_ENVELOPE = array{ + * subject?:string + * } + * @psalm-type COMPOSE_BODY = list */ abstract class AbstractLiveMailboxTest extends TestCase { @@ -44,6 +56,118 @@ public function MailBoxProvider(): array return $sets; } + /** + * @psalm-return Generator + */ + public function ComposeProvider(): Generator + { + yield from []; + } + + /** + * @psalm-return Generator + */ + public function AppendProvider(): Generator + { + foreach ($this->MailBoxProvider() as $mailbox_args) { + foreach ($this->ComposeProvider() as $compose_args) { + [$envelope, $body, $expected_compose_result] = $compose_args; + + yield [$mailbox_args, $envelope, $body, $expected_compose_result, false]; + } + + foreach ($this->ComposeProvider() as $compose_args) { + [$envelope, $body, $expected_compose_result] = $compose_args; + + yield [$mailbox_args, $envelope, $body, $expected_compose_result, true]; + } + } + } + + /** + * @dataProvider AppendProvider + * + * @group live + * + * @depends testGetImapStream + * @depends testMailCompose + * + * @psalm-param MAILBOX_ARGS $mailbox_args + * @psalm-param COMPOSE_ENVELOPE $envelope + * @psalm-param COMPOSE_BODY $body + */ + public function testAppend( + array $mailbox_args, + array $envelope, + array $body, + string $_expected_compose_result, + bool $pre_compose + ): void { + if ($this->MaybeSkipAppendTest($envelope)) { + return; + } + + list($search_criteria) = $this->SubjectSearchCriteriaAndSubject($envelope); + + list($mailbox, $remove_mailbox, $path) = $this->getMailboxFromArgs( + $mailbox_args + ); + + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 0, + $search, + ( + 'If a subject was found,'. + ' then the message is insufficiently unique to assert that'. + ' a newly-appended message was actually created.' + ) + ); + + $message = [$envelope, $body]; + + if ($pre_compose) { + $message = Imap::mail_compose($envelope, $body); + } + + $mailbox->appendMessageToMailbox($message); + + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 1, + $search, + ( + 'If a subject was not found, '. + ' then Mailbox::appendMessageToMailbox() failed'. + ' despite not throwing an exception.' + ) + ); + + $mailbox->deleteMail($search[0]); + + $mailbox->expungeDeletedMails(); + + $mailbox->switchMailbox($path->getString()); + $mailbox->deleteMailbox($remove_mailbox); + + $this->assertCount( + 0, + $mailbox->searchMailbox($search_criteria), + ( + 'If a subject was found,'. + ' then the message is was not expunged as requested.' + ) + ); + } + /** * Get instance of Mailbox, pre-set to a random mailbox. * @@ -106,4 +230,17 @@ protected function SubjectSearchCriteriaAndSubject(array $envelope): array /** @psalm-var array{0:string, 1:string} */ return [$search_criteria, (string) $subject]; } + + protected function MaybeSkipAppendTest(array $envelope): bool + { + if (!isset($envelope['subject'])) { + $this->markTestSkipped( + 'Cannot search for message by subject, no subject specified!' + ); + + return true; + } + + return false; + } } diff --git a/tests/unit/LiveMailboxTest.php b/tests/unit/LiveMailboxTest.php index b548d91d..b7475e44 100644 --- a/tests/unit/LiveMailboxTest.php +++ b/tests/unit/LiveMailboxTest.php @@ -314,110 +314,6 @@ public function testMailCompose(array $envelope, array $body, string $expected_r $this->assertSame($expected_result, $actual_result); } - /** - * @psalm-return Generator - */ - public function AppendProvider(): Generator - { - foreach ($this->MailBoxProvider() as $mailbox_args) { - foreach ($this->ComposeProvider() as $compose_args) { - [$envelope, $body, $expected_compose_result] = $compose_args; - - yield [$mailbox_args, $envelope, $body, $expected_compose_result, false]; - } - - foreach ($this->ComposeProvider() as $compose_args) { - [$envelope, $body, $expected_compose_result] = $compose_args; - - yield [$mailbox_args, $envelope, $body, $expected_compose_result, true]; - } - } - } - - /** - * @dataProvider AppendProvider - * - * @group live - * - * @depends testGetImapStream - * @depends testMailCompose - * - * @psalm-param MAILBOX_ARGS $mailbox_args - * @psalm-param COMPOSE_ENVELOPE $envelope - * @psalm-param COMPOSE_BODY $body - */ - public function testAppend( - array $mailbox_args, - array $envelope, - array $body, - string $_expected_compose_result, - bool $pre_compose - ): void { - if ($this->MaybeSkipAppendTest($envelope)) { - return; - } - - list($search_criteria) = $this->SubjectSearchCriteriaAndSubject($envelope); - - list($mailbox, $remove_mailbox, $path) = $this->getMailboxFromArgs( - $mailbox_args - ); - - $search = $mailbox->searchMailbox($search_criteria); - - $this->assertCount( - 0, - $search, - ( - 'If a subject was found,'. - ' then the message is insufficiently unique to assert that'. - ' a newly-appended message was actually created.' - ) - ); - - $message = [$envelope, $body]; - - if ($pre_compose) { - $message = Imap::mail_compose($envelope, $body); - } - - $mailbox->appendMessageToMailbox($message); - - $search = $mailbox->searchMailbox($search_criteria); - - $this->assertCount( - 1, - $search, - ( - 'If a subject was not found, '. - ' then Mailbox::appendMessageToMailbox() failed'. - ' despite not throwing an exception.' - ) - ); - - $mailbox->deleteMail($search[0]); - - $mailbox->expungeDeletedMails(); - - $mailbox->switchMailbox($path->getString()); - $mailbox->deleteMailbox($remove_mailbox); - - $this->assertCount( - 0, - $mailbox->searchMailbox($search_criteria), - ( - 'If a subject was found,'. - ' then the message is was not expunged as requested.' - ) - ); - } - /** * @dataProvider AppendProvider * @@ -750,19 +646,6 @@ public function testAppendRetrievalMatchesExpected( ); } - protected function MaybeSkipAppendTest(array $envelope): bool - { - if (!isset($envelope['subject'])) { - $this->markTestSkipped( - 'Cannot search for message by subject, no subject specified!' - ); - - return true; - } - - return false; - } - /** * @param string $expected_result * @param string $actual_result From 233871b4edd7b6b4829a09d94af6c0811ae2e6db Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:21:48 +0100 Subject: [PATCH 53/73] adding test for barbushin/php-imap#250 --- tests/unit/LiveMailboxIssue250Test.php | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/unit/LiveMailboxIssue250Test.php diff --git a/tests/unit/LiveMailboxIssue250Test.php b/tests/unit/LiveMailboxIssue250Test.php new file mode 100644 index 00000000..e4b6770e --- /dev/null +++ b/tests/unit/LiveMailboxIssue250Test.php @@ -0,0 +1,55 @@ + + */ +class LiveMailboxIssue250Test extends AbstractLiveMailboxTest +{ + /** + * @psalm-return Generator + */ + public function ComposeProvider(): Generator + { + $random_subject = 'barbushin/php-imap#250 测试: '.\bin2hex(\random_bytes(16)); + + yield [ + ['subject' => $random_subject], + [ + [ + 'type' => TYPETEXT, + 'contents.data' => 'test', + ], + ], + ( + 'Subject: '.$random_subject."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: TEXT/PLAIN; CHARSET=US-ASCII'."\r\n". + "\r\n". + 'test'."\r\n" + ), + ]; + } +} From 303dbce80f0f1c8611d8816b27f9f844c5342e02 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:25:53 +0100 Subject: [PATCH 54/73] wrap testAppend method to address it with a specific test group --- tests/unit/LiveMailboxIssue250Test.php | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/unit/LiveMailboxIssue250Test.php b/tests/unit/LiveMailboxIssue250Test.php index e4b6770e..b80ad7fb 100644 --- a/tests/unit/LiveMailboxIssue250Test.php +++ b/tests/unit/LiveMailboxIssue250Test.php @@ -11,9 +11,17 @@ namespace PhpImap; use Generator; +use ParagonIE\HiddenString\HiddenString; use const TYPETEXT; /** + * @psalm-type MAILBOX_ARGS = array{ + * 0:HiddenString, + * 1:HiddenString, + * 2:HiddenString, + * 3:string, + * 4?:string + * } * @psalm-type COMPOSE_ENVELOPE = array{ * subject?:string * } @@ -52,4 +60,30 @@ public function ComposeProvider(): Generator ), ]; } + + /** + * @dataProvider AppendProvider + * + * @group live + * @group live-issue-250 + * + * @psalm-param MAILBOX_ARGS $mailbox_args + * @psalm-param COMPOSE_ENVELOPE $envelope + * @psalm-param COMPOSE_BODY $body + */ + public function testAppend( + array $mailbox_args, + array $envelope, + array $body, + string $expected_compose_result, + bool $pre_compose + ): void { + parent::testAppend( + $mailbox_args, + $envelope, + $body, + $expected_compose_result, + $pre_compose + ); + } } From 9926dbb52fd6db14f28ffc10f5d3b9c450850342 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:32:28 +0100 Subject: [PATCH 55/73] switch to throwable --- tests/unit/LiveMailboxTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/LiveMailboxTest.php b/tests/unit/LiveMailboxTest.php index b7475e44..ee39b4e6 100644 --- a/tests/unit/LiveMailboxTest.php +++ b/tests/unit/LiveMailboxTest.php @@ -12,10 +12,10 @@ use function date; use const ENCBASE64; -use Exception; use Generator; use ParagonIE\HiddenString\HiddenString; use const SORTARRIVAL; +use Throwable; use const TYPEAPPLICATION; use const TYPEMULTIPART; use const TYPETEXT; @@ -66,7 +66,7 @@ public function testGetImapStream(HiddenString $imapPath, HiddenString $login, H $serverEncoding ); - /** @var Exception|null */ + /** @var Throwable|null */ $exception = null; try { @@ -129,7 +129,7 @@ public function testGetImapStream(HiddenString $imapPath, HiddenString $login, H $this->assertSame($check->Nmsgs, $mailbox->countMails(), 'Mailbox::checkMailbox()->Nmsgs did not match Mailbox::countMails()!'); } - } catch (Exception $ex) { + } catch (Throwable $ex) { $exception = $ex; } finally { $mailbox->switchMailbox($imapPath->getString()); From 02ff0124f0a9f6be5f0575e9a28b6bbb1d408622 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:32:58 +0100 Subject: [PATCH 56/73] cleanup on append --- tests/unit/AbstractLiveMailboxTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/unit/AbstractLiveMailboxTest.php b/tests/unit/AbstractLiveMailboxTest.php index 1578686c..6192ea3a 100644 --- a/tests/unit/AbstractLiveMailboxTest.php +++ b/tests/unit/AbstractLiveMailboxTest.php @@ -13,6 +13,7 @@ use Generator; use ParagonIE\HiddenString\HiddenString; use PHPUnit\Framework\TestCase; +use Throwable; /** * @psalm-type MAILBOX_ARGS = array{ @@ -119,6 +120,10 @@ public function testAppend( $mailbox_args ); + /** @var Throwable|null */ + $exception = null; + + try { $search = $mailbox->searchMailbox($search_criteria); $this->assertCount( @@ -166,6 +171,17 @@ public function testAppend( ' then the message is was not expunged as requested.' ) ); + } catch (Throwable $ex) { + $exception = $ex; + } finally { + $mailbox->switchMailbox($path->getString()); + $mailbox->deleteMailbox($remove_mailbox); + $mailbox->disconnect(); + } + + if (null !== $exception) { + throw $exception; + } } /** From b654dd6afb4af7cc8fc27470e698fea8ae795a71 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:33:15 +0100 Subject: [PATCH 57/73] adjusting indentation --- tests/unit/AbstractLiveMailboxTest.php | 76 +++++++++++++------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/tests/unit/AbstractLiveMailboxTest.php b/tests/unit/AbstractLiveMailboxTest.php index 6192ea3a..87667321 100644 --- a/tests/unit/AbstractLiveMailboxTest.php +++ b/tests/unit/AbstractLiveMailboxTest.php @@ -124,53 +124,53 @@ public function testAppend( $exception = null; try { - $search = $mailbox->searchMailbox($search_criteria); - - $this->assertCount( - 0, - $search, - ( - 'If a subject was found,'. - ' then the message is insufficiently unique to assert that'. - ' a newly-appended message was actually created.' - ) - ); + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 0, + $search, + ( + 'If a subject was found,'. + ' then the message is insufficiently unique to assert that'. + ' a newly-appended message was actually created.' + ) + ); - $message = [$envelope, $body]; + $message = [$envelope, $body]; - if ($pre_compose) { - $message = Imap::mail_compose($envelope, $body); - } + if ($pre_compose) { + $message = Imap::mail_compose($envelope, $body); + } - $mailbox->appendMessageToMailbox($message); + $mailbox->appendMessageToMailbox($message); - $search = $mailbox->searchMailbox($search_criteria); + $search = $mailbox->searchMailbox($search_criteria); - $this->assertCount( - 1, - $search, - ( - 'If a subject was not found, '. - ' then Mailbox::appendMessageToMailbox() failed'. - ' despite not throwing an exception.' - ) - ); + $this->assertCount( + 1, + $search, + ( + 'If a subject was not found, '. + ' then Mailbox::appendMessageToMailbox() failed'. + ' despite not throwing an exception.' + ) + ); - $mailbox->deleteMail($search[0]); + $mailbox->deleteMail($search[0]); - $mailbox->expungeDeletedMails(); + $mailbox->expungeDeletedMails(); - $mailbox->switchMailbox($path->getString()); - $mailbox->deleteMailbox($remove_mailbox); + $mailbox->switchMailbox($path->getString()); + $mailbox->deleteMailbox($remove_mailbox); - $this->assertCount( - 0, - $mailbox->searchMailbox($search_criteria), - ( - 'If a subject was found,'. - ' then the message is was not expunged as requested.' - ) - ); + $this->assertCount( + 0, + $mailbox->searchMailbox($search_criteria), + ( + 'If a subject was found,'. + ' then the message is was not expunged as requested.' + ) + ); } catch (Throwable $ex) { $exception = $ex; } finally { From 2a30efbf4dd857095bcc296a967967428bb3f0f8 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:41:32 +0100 Subject: [PATCH 58/73] check if mailbox has been deleted --- tests/unit/AbstractLiveMailboxTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/unit/AbstractLiveMailboxTest.php b/tests/unit/AbstractLiveMailboxTest.php index 87667321..19bdf0e9 100644 --- a/tests/unit/AbstractLiveMailboxTest.php +++ b/tests/unit/AbstractLiveMailboxTest.php @@ -123,6 +123,8 @@ public function testAppend( /** @var Throwable|null */ $exception = null; + $mailboxDeleted = false; + try { $search = $mailbox->searchMailbox($search_criteria); @@ -162,6 +164,7 @@ public function testAppend( $mailbox->switchMailbox($path->getString()); $mailbox->deleteMailbox($remove_mailbox); + $mailboxDeleted = true; $this->assertCount( 0, @@ -175,7 +178,9 @@ public function testAppend( $exception = $ex; } finally { $mailbox->switchMailbox($path->getString()); + if (!$mailboxDeleted) { $mailbox->deleteMailbox($remove_mailbox); + } $mailbox->disconnect(); } From a6fa62000a3a55802c4b6c07b87baa60d6a9e9d0 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:41:45 +0100 Subject: [PATCH 59/73] adjusting indentation --- tests/unit/AbstractLiveMailboxTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/AbstractLiveMailboxTest.php b/tests/unit/AbstractLiveMailboxTest.php index 19bdf0e9..d1b25d69 100644 --- a/tests/unit/AbstractLiveMailboxTest.php +++ b/tests/unit/AbstractLiveMailboxTest.php @@ -179,7 +179,7 @@ public function testAppend( } finally { $mailbox->switchMailbox($path->getString()); if (!$mailboxDeleted) { - $mailbox->deleteMailbox($remove_mailbox); + $mailbox->deleteMailbox($remove_mailbox); } $mailbox->disconnect(); } From ff9f60672ba46400d71d6fe65e93e70cdeb1e846 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:48:09 +0100 Subject: [PATCH 60/73] make utf7 for criteria optional --- src/PhpImap/Imap.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PhpImap/Imap.php b/src/PhpImap/Imap.php index d4ab5018..895fb780 100644 --- a/src/PhpImap/Imap.php +++ b/src/PhpImap/Imap.php @@ -813,12 +813,16 @@ public static function search( $imap_stream, string $criteria, int $options = SE_FREE, - string $charset = null + string $charset = null, + bool $encodeCriteriaAsUtf7Imap = true ): array { \imap_errors(); // flush errors $imap_stream = static::EnsureConnection($imap_stream, __METHOD__, 1); + + if ($encodeCriteriaAsUtf7Imap) { $criteria = static::encodeStringToUtf7Imap($criteria); + } if (\is_string($charset)) { $result = \imap_search( From 42a6c29b90bdeab553d49911903e26ae288a9d75 Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:49:22 +0100 Subject: [PATCH 61/73] adjusting indentation --- src/PhpImap/Imap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpImap/Imap.php b/src/PhpImap/Imap.php index 895fb780..4bb9098d 100644 --- a/src/PhpImap/Imap.php +++ b/src/PhpImap/Imap.php @@ -821,7 +821,7 @@ public static function search( $imap_stream = static::EnsureConnection($imap_stream, __METHOD__, 1); if ($encodeCriteriaAsUtf7Imap) { - $criteria = static::encodeStringToUtf7Imap($criteria); + $criteria = static::encodeStringToUtf7Imap($criteria); } if (\is_string($charset)) { From 01e430276caa4b98e168aacd5433a765fa63754c Mon Sep 17 00:00:00 2001 From: Marv Date: Tue, 19 May 2020 11:49:41 +0100 Subject: [PATCH 62/73] change default criteria encode mode * this change does not appear to break any existing tests * this change fixes barbushin/php-imap#250 --- src/PhpImap/Imap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpImap/Imap.php b/src/PhpImap/Imap.php index 4bb9098d..3762410f 100644 --- a/src/PhpImap/Imap.php +++ b/src/PhpImap/Imap.php @@ -814,7 +814,7 @@ public static function search( string $criteria, int $options = SE_FREE, string $charset = null, - bool $encodeCriteriaAsUtf7Imap = true + bool $encodeCriteriaAsUtf7Imap = false ): array { \imap_errors(); // flush errors From dfa5e97476f582c03a2e66629a96b88fb8b7f117 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 08:06:33 +0100 Subject: [PATCH 63/73] expand type hinting --- tests/unit/AbstractLiveMailboxTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/AbstractLiveMailboxTest.php b/tests/unit/AbstractLiveMailboxTest.php index d1b25d69..cae4f8a3 100644 --- a/tests/unit/AbstractLiveMailboxTest.php +++ b/tests/unit/AbstractLiveMailboxTest.php @@ -32,6 +32,10 @@ * charset?:string, * subtype?:string, * description?:string, + * 'disposition.type'?:string, + * 'type.parameters'?:array{name:string}, + * 'contents.data'?:string, + * id?:string, * disposition?:array{filename:string} * }> */ From b3b28d07ee3102c3e1021c8512325aa61ae242b3 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 08:07:25 +0100 Subject: [PATCH 64/73] updating psalm to allow type importing --- composer.json | 2 +- psalm.baseline.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e750d67d..14603fe2 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,7 @@ "psalm/plugin-phpunit": "^0.10.0", "roave/security-advisories": "dev-master", "sebastian/phpcpd": "^4.1", - "vimeo/psalm": "^3.11" + "vimeo/psalm": "^3.11.5" }, "scripts": { "static-analysis": [ diff --git a/psalm.baseline.xml b/psalm.baseline.xml index 574fdf31..34fb0c77 100644 --- a/psalm.baseline.xml +++ b/psalm.baseline.xml @@ -1,5 +1,5 @@ - + $mailbox From 0a83777adf5f3971b7a1109f0ba9fa8e0aafc639 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 15:45:22 +0100 Subject: [PATCH 65/73] swap vendor cache for composer cache --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f7a2f01d..4855f448 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ matrix: cache: directories: - - ./vendor + - $HOME/.composer/cache - ./psalm/cache before_script: From 94cd45a28ab375945e807a5a08707430d784a377 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 15:45:51 +0100 Subject: [PATCH 66/73] implementing test for barbushin/php-imap#514 --- tests/unit/Fixtures/rgbkw5x1.png | Bin 0 -> 74 bytes tests/unit/Fixtures/rgbkw5x1.webp | Bin 0 -> 34 bytes tests/unit/LiveMailboxIssue514Test.php | 216 +++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 tests/unit/Fixtures/rgbkw5x1.png create mode 100644 tests/unit/Fixtures/rgbkw5x1.webp create mode 100644 tests/unit/LiveMailboxIssue514Test.php diff --git a/tests/unit/Fixtures/rgbkw5x1.png b/tests/unit/Fixtures/rgbkw5x1.png new file mode 100644 index 0000000000000000000000000000000000000000..aebc850729a878d18d7daa93b89c2b240e4c3125 GIT binary patch literal 74 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1j!2~2{&iT9qNC|qnIEHXsPyTWKzyXHi|Nk>H YsJ&$Uy(~guJy4Rt)78&qol`;+0DK%33;+NC literal 0 HcmV?d00001 diff --git a/tests/unit/Fixtures/rgbkw5x1.webp b/tests/unit/Fixtures/rgbkw5x1.webp new file mode 100644 index 0000000000000000000000000000000000000000..80f26216fb183a79f71e0e69853bccc0114b4b0f GIT binary patch literal 34 ncmWIYbaRtpU|MgkuTp literal 0 HcmV?d00001 diff --git a/tests/unit/LiveMailboxIssue514Test.php b/tests/unit/LiveMailboxIssue514Test.php new file mode 100644 index 00000000..b58b68c8 --- /dev/null +++ b/tests/unit/LiveMailboxIssue514Test.php @@ -0,0 +1,216 @@ + 'barbushin/php-imap#514--'.\bin2hex(\random_bytes(16)), + ]; + + list($search_criteria) = $this->SubjectSearchCriteriaAndSubject($envelope); + + $body = [ + [ + 'type' => TYPEMULTIPART, + ], + [ + 'type' => TYPETEXT, + 'subtype' => 'plain', + 'contents.data' => 'foo', + ], + [ + 'type' => TYPETEXT, + 'subtype' => 'html', + 'contents.data' => \implode('', [ + 'png', + 'webp', + ]), + ], + [ + 'type' => TYPEIMAGE, + 'subtype' => 'png', + 'encoding' => ENCBASE64, + 'id' => 'foo.png', + 'description' => 'foo.png', + 'disposition' => ['filename' => 'foo.png'], + 'disposition.type' => 'inline', + 'type.parameters' => ['name' => 'foo.png'], + 'contents.data' => \base64_encode( + \file_get_contents(__DIR__.'/Fixtures/rgbkw5x1.png') + ), + ], + [ + 'type' => TYPEIMAGE, + 'subtype' => 'webp', + 'encoding' => ENCBASE64, + 'id' => 'foo.webp', + 'description' => 'foo.webp', + 'disposition' => ['filename' => 'foo.webp'], + 'disposition.type' => 'inline', + 'type.parameters' => ['name' => 'foo.webp'], + 'contents.data' => \base64_encode( + \file_get_contents(__DIR__.'/Fixtures/rgbkw5x1.webp') + ), + ], + ]; + + $message = Imap::mail_compose( + $envelope, + $body + ); + + list($mailbox, $remove_mailbox, $path) = $this->getMailboxFromArgs([ + $imapPath, + $login, + $password, + $attachmentsDir, + $serverEncoding, + ]); + + $result = null; + + try { + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 0, + $search, + ( + 'If a subject was found,'. + ' then the message is insufficiently unique to assert that'. + ' a newly-appended message was actually created.' + ) + ); + + $mailbox->appendMessageToMailbox($message); + + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 1, + $search, + ( + 'If a subject was not found, '. + ' then Mailbox::appendMessageToMailbox() failed'. + ' despite not throwing an exception.' + ) + ); + + $result = $mailbox->getMail($search[0], false); + + /** @var array */ + $counts = []; + + foreach ($result->getAttachments() as $attachment) { + if (!isset($counts[(string) $attachment->contentId])) { + $counts[(string) $attachment->contentId] = 0; + } + + ++$counts[(string) $attachment->contentId]; + } + + $this->assertCount( + 2, + $counts, + ( + 'counts should only contain foo.png and foo.webp, found: '. + \implode( + ', ', + \array_keys($counts) + ) + ) + ); + + foreach ($counts as $cid => $count) { + $this->assertSame( + 1, + $count, + $cid.' had '.(string) $count.', expected 1.' + ); + } + + $this->assertSame( + 'foo', + $result->textPlain, + 'plain text body did not match expected result!' + ); + + $this->assertSame( + $body[2]['contents.data'], + $result->textHtml, + 'unembeded html body did not match expected result!' + ); + + $result->embedImageAttachments(); + + $this->assertSame( + \implode('', [ + 'png', + 'webp', + ]), + $result->textHtml, + 'embeded html body did not match expected result!' + ); + + $mailbox->deleteMail($search[0]); + } catch (Throwable $ex) { + $exception = $ex; + } finally { + $mailbox->switchMailbox($path->getString()); + + if (!$mailboxDeleted) { + $mailbox->deleteMailbox($remove_mailbox); + } + + $mailbox->disconnect(); + } + + if (null !== $exception) { + throw $exception; + } + } +} From a928614a38f04a812e7866b6348adc1e87780477 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 15:49:17 +0100 Subject: [PATCH 67/73] implementing fix for barbushin/php-imap#514 --- src/PhpImap/IncomingMail.php | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/PhpImap/IncomingMail.php b/src/PhpImap/IncomingMail.php index d5b75185..6f63d5c6 100644 --- a/src/PhpImap/IncomingMail.php +++ b/src/PhpImap/IncomingMail.php @@ -57,10 +57,15 @@ public function __get(string $name): string if ('textHtml' == $name) { $type = DataPartInfo::TEXT_HTML; } + if (('textPlain' === $name || 'textHtml' === $name) && isset($this->$name)) { + return (string) $this->$name; + } if (false === $type) { \trigger_error("Undefined property: IncomingMail::$name"); } + if (!isset($this->$name)) { $this->$name = ''; + } foreach ($this->dataInfo[$type] as $data) { $this->$name .= \trim($data->fetch()); } @@ -205,18 +210,14 @@ public function embedImageAttachments(): void \preg_match_all("/\bcid:[^'\"\s]{1,256}/mi", $fetchedHtml ?? '', $matches); - /** @psalm-var list> */ - $matches = $matches; - - if (\count($matches)) { + if (isset($matches[0]) && \is_array($matches[0]) && \count($matches[0])) { + /** @var list */ + $matches = $matches[0]; + $attachments = $this->getAttachments(); foreach ($matches as $match) { - if (!isset($match[0])) { - continue; - } - - $cid = \str_replace('cid:', '', $match[0]); + $cid = \str_replace('cid:', '', $match); - foreach ($this->getAttachments() as $attachment) { + foreach ($attachments as $attachment) { if ($attachment->contentId == $cid && 'inline' == $attachment->disposition) { $contents = $attachment->getContents(); $contentType = (string) $attachment->getFileInfo(FILEINFO_MIME); @@ -230,7 +231,7 @@ public function embedImageAttachments(): void $base64encoded = \base64_encode($contents); $replacement = 'data:'.$contentType.';base64, '.$base64encoded; - $this->textHtml = \str_replace($match[0], $replacement, $this->textHtml); + $this->textHtml = \str_replace($match, $replacement, $this->textHtml); $this->removeAttachment($attachment->id); } From 97474bf42eccdf3e7d3d30de1e991972f806fddc Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 15:49:27 +0100 Subject: [PATCH 68/73] updating baseline --- psalm.baseline.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/psalm.baseline.xml b/psalm.baseline.xml index 34fb0c77..76fee147 100644 --- a/psalm.baseline.xml +++ b/psalm.baseline.xml @@ -13,9 +13,8 @@ - + replaceInternalLinks - embedImageAttachments $this->dataInfo @@ -26,7 +25,7 @@ \in_array($imapSearchOption, $supported_options, true) \in_array($key, $supported_params, true) - + $element->charset $element->charset $element->text From 58723c42ceaf54ae962f9dcd0da373a4ae698c94 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 16:09:19 +0100 Subject: [PATCH 69/73] further tests for barbushin/php-imap#514 and barbushin/php-imap#496 --- tests/unit/LiveMailboxIssue514Test.php | 62 +++++++++++++++++++++----- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/tests/unit/LiveMailboxIssue514Test.php b/tests/unit/LiveMailboxIssue514Test.php index b58b68c8..3482904a 100644 --- a/tests/unit/LiveMailboxIssue514Test.php +++ b/tests/unit/LiveMailboxIssue514Test.php @@ -173,6 +173,57 @@ public function testEmbed( 'plain text body did not match expected result!' ); + $embedded = \implode('', [ + 'png', + 'webp', + ]); + + $this->assertSame( + [ + 'foo.png' => 'cid:foo.png', + 'foo.webp' => 'cid:foo.webp', + ], + $result->getInternalLinksPlaceholders(), + 'Internal link placeholders did not match expected result!' + ); + + $replaced = \implode('', [ + 'png', + 'webp', + ]); + + foreach ($result->getAttachments() as $attachment) { + if ('foo.png' === $attachment->contentId) { + $replaced = \str_replace( + 'foo.png', + '/' . basename($attachment->filePath), + $replaced + ); + } elseif ('foo.webp' === $attachment->contentId) { + $replaced = \str_replace( + 'foo.webp', + '/' . basename($attachment->filePath), + $replaced + ); + } + } + + $this->assertSame( + $replaced, + $result->replaceInternalLinks(''), + 'replaced html body did not match expected result!' + ); + $this->assertSame( $body[2]['contents.data'], $result->textHtml, @@ -182,16 +233,7 @@ public function testEmbed( $result->embedImageAttachments(); $this->assertSame( - \implode('', [ - 'png', - 'webp', - ]), + $embedded, $result->textHtml, 'embeded html body did not match expected result!' ); From c5debb612e8979daf21df85f9f011188264a8190 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 16:11:33 +0100 Subject: [PATCH 70/73] implement fix for barbushin/php-imap#496 --- psalm.baseline.xml | 3 --- src/PhpImap/IncomingMail.php | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/psalm.baseline.xml b/psalm.baseline.xml index 76fee147..6c8796f8 100644 --- a/psalm.baseline.xml +++ b/psalm.baseline.xml @@ -13,9 +13,6 @@ - - replaceInternalLinks - $this->dataInfo diff --git a/src/PhpImap/IncomingMail.php b/src/PhpImap/IncomingMail.php index 6f63d5c6..468f552d 100644 --- a/src/PhpImap/IncomingMail.php +++ b/src/PhpImap/IncomingMail.php @@ -169,7 +169,9 @@ public function removeAttachment(string $id): bool */ public function getInternalLinksPlaceholders(): array { - $match = \preg_match_all('/=["\'](ci?d:([\w\.%*@-]+))["\']/i', $this->textHtml, $matches); + $fetchedHtml = (string) $this->__get('textHtml'); + + $match = \preg_match_all('/=["\'](ci?d:([\w\.%*@-]+))["\']/i', $fetchedHtml, $matches); /** @psalm-var array{1:list, 2:list} */ $matches = $matches; From d2d8d9602929eada905715c8f9380f423e1fb801 Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 16:12:01 +0100 Subject: [PATCH 71/73] pull in fix for barbushin/php-imap#496 calling `$this->textHtml` within class scope does not guarantee that `$this->textHtml` has been populated. --- src/PhpImap/IncomingMail.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PhpImap/IncomingMail.php b/src/PhpImap/IncomingMail.php index 468f552d..88da828f 100644 --- a/src/PhpImap/IncomingMail.php +++ b/src/PhpImap/IncomingMail.php @@ -207,10 +207,9 @@ public function replaceInternalLinks(string $baseUri): string */ public function embedImageAttachments(): void { - /** @var string|null */ - $fetchedHtml = $this->textHtml; + $fetchedHtml = (string) $this->__get('textHtml'); - \preg_match_all("/\bcid:[^'\"\s]{1,256}/mi", $fetchedHtml ?? '', $matches); + \preg_match_all("/\bcid:[^'\"\s]{1,256}/mi", $fetchedHtml, $matches); if (isset($matches[0]) && \is_array($matches[0]) && \count($matches[0])) { /** @var list */ From 415130c343160306774239406f8c5790621cfbbc Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 16:15:48 +0100 Subject: [PATCH 72/73] php-cs-fixer --- src/PhpImap/IncomingMail.php | 2 +- tests/unit/LiveMailboxIssue514Test.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpImap/IncomingMail.php b/src/PhpImap/IncomingMail.php index 88da828f..02188357 100644 --- a/src/PhpImap/IncomingMail.php +++ b/src/PhpImap/IncomingMail.php @@ -64,7 +64,7 @@ public function __get(string $name): string \trigger_error("Undefined property: IncomingMail::$name"); } if (!isset($this->$name)) { - $this->$name = ''; + $this->$name = ''; } foreach ($this->dataInfo[$type] as $data) { $this->$name .= \trim($data->fetch()); diff --git a/tests/unit/LiveMailboxIssue514Test.php b/tests/unit/LiveMailboxIssue514Test.php index 3482904a..91cc4b6e 100644 --- a/tests/unit/LiveMailboxIssue514Test.php +++ b/tests/unit/LiveMailboxIssue514Test.php @@ -206,13 +206,13 @@ public function testEmbed( if ('foo.png' === $attachment->contentId) { $replaced = \str_replace( 'foo.png', - '/' . basename($attachment->filePath), + '/'.\basename($attachment->filePath), $replaced ); } elseif ('foo.webp' === $attachment->contentId) { $replaced = \str_replace( 'foo.webp', - '/' . basename($attachment->filePath), + '/'.\basename($attachment->filePath), $replaced ); } From c7d447d60e723083ebd2f79e16ddb14bd876abbf Mon Sep 17 00:00:00 2001 From: Marv Date: Mon, 1 Jun 2020 16:24:58 +0100 Subject: [PATCH 73/73] restoring entry removed from baseline due to travis weirdness --- psalm.baseline.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/psalm.baseline.xml b/psalm.baseline.xml index 6c8796f8..76fee147 100644 --- a/psalm.baseline.xml +++ b/psalm.baseline.xml @@ -13,6 +13,9 @@ + + replaceInternalLinks + $this->dataInfo