Skip to content

Commit

Permalink
Merge pull request #515 from bapcltd/issue/514
Browse files Browse the repository at this point in the history
fixes for #496 & #514
  • Loading branch information
Sebbo94BY authored Jun 14, 2020
2 parents b5e4cda + c7d447d commit fec86ca
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 22 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ matrix:

cache:
directories:
- ./vendor
- $HOME/.composer/cache
- ./psalm/cache

before_script:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
7 changes: 3 additions & 4 deletions psalm.baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="3.11.4@58e1d8e68e5098bf4fbfdfb420c38d563f882549">
<files psalm-version="3.11.5@3c60609c218d4d4b3b257728b8089094e5c6c6c2">
<file src="examples/get_and_parse_all_emails_without_saving_attachments.php">
<UnusedVariable occurrences="1">
<code>$mailbox</code>
Expand All @@ -13,9 +13,8 @@
</DocblockTypeContradiction>
</file>
<file src="src/PhpImap/IncomingMail.php">
<PossiblyUnusedMethod occurrences="2">
<PossiblyUnusedMethod occurrences="1">
<code>replaceInternalLinks</code>
<code>embedImageAttachments</code>
</PossiblyUnusedMethod>
<PropertyTypeCoercion occurrences="1">
<code>$this-&gt;dataInfo</code>
Expand All @@ -26,7 +25,7 @@
<code>\in_array($imapSearchOption, $supported_options, true)</code>
<code>\in_array($key, $supported_params, true)</code>
</DocblockTypeContradiction>
<InvalidArgument occurrences="6">
<InvalidArgument occurrences="3">
<code>$element-&gt;charset</code>
<code>$element-&gt;charset</code>
<code>$element-&gt;text</code>
Expand Down
34 changes: 18 additions & 16 deletions src/PhpImap/IncomingMail.php
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
$this->$name = '';
if (!isset($this->$name)) {
$this->$name = '';
}
foreach ($this->dataInfo[$type] as $data) {
$this->$name .= \trim($data->fetch());
}
Expand Down Expand Up @@ -164,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<string>, 2:list<string>} */
$matches = $matches;
Expand Down Expand Up @@ -200,23 +207,18 @@ 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);

/** @psalm-var list<list<string>> */
$matches = $matches;

if (\count($matches)) {
if (isset($matches[0]) && \is_array($matches[0]) && \count($matches[0])) {
/** @var list<string> */
$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);
Expand All @@ -230,7 +232,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);
}
Expand Down
4 changes: 4 additions & 0 deletions tests/unit/AbstractLiveMailboxTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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}
* }>
*/
Expand Down
Binary file added tests/unit/Fixtures/rgbkw5x1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/unit/Fixtures/rgbkw5x1.webp
Binary file not shown.
258 changes: 258 additions & 0 deletions tests/unit/LiveMailboxIssue514Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
<?php
/**
* Live Mailbox - PHPUnit tests.
*
* Runs tests on a live mailbox
*
* @author BAPCLTD-Marv
*/
declare(strict_types=1);

namespace PhpImap;

use const ENCBASE64;
use ParagonIE\HiddenString\HiddenString;
use Throwable;
use const TYPEIMAGE;
use const TYPEMULTIPART;
use const TYPETEXT;

/**
* @psalm-import-type COMPOSE_ENVELOPE from AbstractLiveMailboxTest
*/
class LiveMailboxIssue514Test extends AbstractLiveMailboxTest
{
/**
* @dataProvider MailBoxProvider
*
* @group live
* @group issue-514
*/
public function testEmbed(
HiddenString $imapPath,
HiddenString $login,
HiddenString $password,
string $attachmentsDir,
string $serverEncoding = 'UTF-8'
): void {
/** @var Throwable|null */
$exception = null;

$mailboxDeleted = false;

/** @psalm-var COMPOSE_ENVELOPE */
$envelope = [
'subject' => '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('', [
'<img alt="png" width="5" height="1" src="cid:foo.png">',
'<img alt="webp" width="5" height="1" src="cid:foo.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<string, int> */
$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!'
);

$embedded = \implode('', [
'<img alt="png" width="5" height="1" src="',
'data:image/png; charset=binary;base64, ',
$body[3]['contents.data'],
'">',
'<img alt="webp" width="5" height="1" src="',
'data:image/webp; charset=binary;base64, ',
$body[4]['contents.data'],
'">',
]);

$this->assertSame(
[
'foo.png' => 'cid:foo.png',
'foo.webp' => 'cid:foo.webp',
],
$result->getInternalLinksPlaceholders(),
'Internal link placeholders did not match expected result!'
);

$replaced = \implode('', [
'<img alt="png" width="5" height="1" src="',
'foo.png',
'">',
'<img alt="webp" width="5" height="1" src="',
'foo.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,
'unembeded html body did not match expected result!'
);

$result->embedImageAttachments();

$this->assertSame(
$embedded,
$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;
}
}
}

0 comments on commit fec86ca

Please sign in to comment.