Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to store multipart/alternative messages #36

Open
wants to merge 10 commits into
base: 2.13.x
Choose a base branch
from
6 changes: 3 additions & 3 deletions docs/book/message.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
`Laminas\Mime\Message` represents a MIME compliant message that can contain one or
more separate Parts (represented as [Laminas\Mime\Part](part.md) instances).
Encoding and boundary handling are handled transparently by the class.
`Message` instances can also be generated from MIME strings.
`Message` instances can also be generated from MIME-compliant strings.

## Instantiation

Expand All @@ -16,7 +16,7 @@ calling `->addPart($part)`

An array with all [Part](part.md) instances in the `Message` is returned from
the method `getParts()`. The `Part` instances can then be modified on
retrieveal, as they are stored in the array as references. If parts are added
retrieval, as they are stored in the array as references. If parts are added
to the array or the sequence is changed, the array needs to be passed back to
the `Message` instance by calling `setParts($partsArray)`.

Expand Down Expand Up @@ -46,7 +46,7 @@ strings and returning a `Laminas\Mime\Message` instance:
$message = Laminas\Mime\Message::createFromMessage($string, $boundary);
```

As of version 2.6.1, You may also parse a single-part message by omitting the
As of version 2.6.1, you may also parse a single-part message by omitting the
`$boundary` argument:

```php
Expand Down
49 changes: 40 additions & 9 deletions src/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

namespace Laminas\Mime;

use Laminas\Mail\Header\ContentDisposition;
use Laminas\Mail\Header\ContentType;
use Laminas\Mail\Header\HeaderInterface;
use Laminas\Mime\Mime;
use Laminas\Mime\Part;

use Laminas\Mail\Headers;
use function array_keys;
use function base64_decode;
use function count;
Expand All @@ -31,7 +31,7 @@ class Message
*
* @return Part[]
*/
public function getParts()
public function getParts(): array
{
return $this->parts;
}
Expand Down Expand Up @@ -139,13 +139,13 @@ public function generateMessage($EOL = Mime::LINEEND)

$boundaryLine = $mime->boundaryLine($EOL);
$body = 'This is a message in Mime Format. If you see this, '
. "your mail reader does not support this format." . $EOL;
. "your mail reader does not support this format." . $EOL;

foreach (array_keys($this->parts) as $p) {
$body .= $boundaryLine
. $this->getPartHeaders($p, $EOL)
. $EOL
. $this->getPartContent($p, $EOL);
. $this->getPartHeaders($p, $EOL)
. $EOL
. $this->getPartContent($p, $EOL);
}

$body .= $mime->mimeEnd($EOL);
Expand Down Expand Up @@ -309,10 +309,41 @@ public static function createFromMessage($message, $boundary = null, $EOL = Mime
}
}

$newPart = new Part($body);
/** @var Headers $headers */
$headers = $part['header'];

/**
* If the current message part's body has a content-type of "multipart/alternative",
* then create and add a new Part to the current message which has a Part for each
* sub/alternative Part in the message.
*/
if (
$headers->has('content-type')
&& $headers->get('content-type')->getType() === Mime::MULTIPART_ALTERNATIVE
) {
/** @var ContentType $contentTypeHeader */
$contentTypeHeader = $headers->get('content-type');

$message = self::createFromMessage($body, $contentTypeHeader->getParameter('boundary'), $EOL);
$newPart = new Part();
foreach ($message->getParts() as $alternativePart) {
$newPart->addPart($alternativePart);
}
} else {
$newPart = new Part($body);

if ($headers->has('content-disposition')) {
/** @var ContentDisposition $header */
$header = $headers->get('content-disposition');
if ($header->getParameter('filename') !== null) {
$newPart->setFileName($header->getParameter('filename'));
}
}
}
foreach ($properties as $key => $value) {
$newPart->$key = $value;
}

$res->addPart($newPart);
}

Expand Down
27 changes: 27 additions & 0 deletions src/Part.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,33 @@ class Part
/** @var array<array-key, resource> */
protected $filters = [];

/**
* Stores a list of sub parts of this part
*
* It supports RFC 1341 7.2.3: "The Multipart/alternative subtype".
* While it can store a list of parts without limitation, the intention,
* at this point, is to only store Part objects built from parsing
* Messages with a content-type of "multipart/alternative".
*
* @var Part[]
*/
protected array $parts = [];

/**
* Retrieve the sub-Parts of this Part
*
* @return Part[]
*/
public function getParts(): array
{
return $this->parts;
}

public function addPart(Part $part): void
{
$this->parts[] = $part;
}

/**
* create a new Mime Part.
* The (unencoded) content of the Part as passed
Expand Down
Loading
Loading