From 926a1820a208cb8cc7b1415a2c3f599171fe3469 Mon Sep 17 00:00:00 2001 From: Matt Dwyer Date: Thu, 7 Sep 2023 17:02:02 +1000 Subject: [PATCH 1/2] Make the MimePart::getBody() method compatible with the newer version of psr/http-message that has return types which causes a Fatal Error on PHP 8; Add a MimePart::getBodyString() helper method that converts MimePart::getBody()'s StreamInterface into a string and update all the calling code for MimePart::getBody() over to MimePart::getBodyString() --- composer.json | 4 ++-- src/CryptoHelper.php | 4 ++-- src/Management.php | 10 +++++----- src/MimePart.php | 25 ++++++++++++++++++------- src/Server.php | 6 +++--- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index 4203b11..54262e6 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ ], "license": "MIT", "require": { - "php": "^7.1 || ^7.2 || ^7.3 || ^7.4 || ^8.0", + "php": "^7.1 || ^7.2 || ^7.3 || ^7.4 || ^8.0 || ^8.1", "ext-openssl": "*", "ext-zlib": "*", "ext-ctype": "*", @@ -27,7 +27,7 @@ "psr/log": "^1.1" }, "require-dev": { - "phpunit/phpunit": "^7.5", + "phpunit/phpunit": "^10.3", "symfony/var-dumper": "^4.0" }, "autoload": { diff --git a/src/CryptoHelper.php b/src/CryptoHelper.php index 6f35319..cb28ad3 100644 --- a/src/CryptoHelper.php +++ b/src/CryptoHelper.php @@ -32,7 +32,7 @@ public static function calculateMIC($payload, $algo = 'sha256', $includeHeaders $digest = base64_encode( hash( $digestAlgorithm, - $includeHeaders ? $payload : $payload->getBody(), + $includeHeaders ? $payload : $payload->getBodyString(), true ) ); @@ -236,7 +236,7 @@ public static function compress($data, $encoding = null) public static function decompress($data) { if ($data instanceof MimePart) { - $data = $data->getBody(); + $data = $data->getBodyString(); } /** @noinspection CallableParameterUseCaseInTypeContextInspection */ diff --git a/src/Management.php b/src/Management.php index 783a0cc..4d426bf 100644 --- a/src/Management.php +++ b/src/Management.php @@ -206,7 +206,7 @@ public function buildMessage(MessageInterface $message, $payload) $as2headers[$name] = implode(', ', $values); } - $as2Message = new MimePart($as2headers, $payload->getBody()); + $as2Message = new MimePart($as2headers, $payload->getBodyString()); $message->setHeaders($as2Message->getHeaderLines()); @@ -230,7 +230,7 @@ public function processMessage(MessageInterface $message, MimePart $payload) ] ); - $body = Utils::normalizeBase64($payload->getBody()); + $body = Utils::normalizeBase64($payload->getBodyString()); // Force encode binary data to base64, `openssl_pkcs7_` doesn't work with binary data if (! Utils::decodeBase64($body)) { @@ -366,7 +366,7 @@ public function sendMessage(MessageInterface $message, $payload) try { $options = [ 'headers' => $payload->getHeaders(), - 'body' => $payload->getBody(), + 'body' => $payload->getBodyString(), // 'cert' => '' // TODO: partner https cert ? ]; @@ -452,7 +452,7 @@ public function processMdn(MessageInterface $message, $payload) if ($part->getParsedHeader('content-type', 0, 0) === 'message/disposition-notification') { $this->getLogger()->debug('Found MDN report for message', [$messageId]); try { - $bodyPayload = MimePart::fromString($part->getBody()); + $bodyPayload = MimePart::fromString($part->getBodyString()); if ($bodyPayload->hasHeader('disposition')) { $mdnStatus = $bodyPayload->getParsedHeader('Disposition', 0, 1); if ($mdnStatus === 'processed') { @@ -651,7 +651,7 @@ public function sendMdn(MessageInterface $message) $mdn = MimePart::fromString($message->getMdnPayload()); $options = [ - 'body' => $mdn->getBody(), + 'body' => $mdn->getBodyString(), 'headers' => $mdn->getHeaders(), ]; diff --git a/src/MimePart.php b/src/MimePart.php index 8fa996f..27d1754 100644 --- a/src/MimePart.php +++ b/src/MimePart.php @@ -5,8 +5,10 @@ namespace AS2; use GuzzleHttp\Psr7\MessageTrait; -use Psr\Http\Message\MessageInterface as PsrMessageInterface; +use Psr\Http\Message\StreamInterface; +use GuzzleHttp\Psr7\Utils as PsrUtils; use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\MessageInterface as PsrMessageInterface; class MimePart implements PsrMessageInterface { @@ -116,9 +118,9 @@ public static function createIfBinaryPart(self $message): ?self $temp = new self($message->getHeaders()); foreach ($message->getParts() as $part) { - if (Utils::isBinary($part->getBody())) { + if (Utils::isBinary($part->getBodyString())) { $hasBinary = true; - $recreatedPart = new self($part->getHeaders(), Utils::encodeBase64($part->getBody())); + $recreatedPart = new self($part->getHeaders(), Utils::encodeBase64($part->getBodyString())); $temp->addPart($recreatedPart); } else { $temp->addPart($part); @@ -303,9 +305,9 @@ public function getParsedHeader($header, $index = null, $param = null) /** * Return the currently set message body. * - * @return string + * @return StreamInterface Returns the body as a stream. */ - public function getBody() + public function getBody(): StreamInterface { $body = $this->body; if (count($this->parts) > 0) { @@ -321,7 +323,16 @@ public function getBody() } } - return $body; + return PsrUtils::streamFor($body); + } + + /** + * Return the currently set message body as a string. + * + * @return string Returns the body as a string. + */ + public function getBodyString(): string { + return PsrUtils::copyToString($this->getBody()); } /** @@ -393,7 +404,7 @@ public function toString() return $this->rawMessage; } - return $this->getHeaderLines() . self::EOL . $this->getBody(); + return $this->getHeaderLines() . self::EOL . $this->getBodyString(); } /** diff --git a/src/Server.php b/src/Server.php index 507f0b8..ad5877e 100644 --- a/src/Server.php +++ b/src/Server.php @@ -106,7 +106,7 @@ public function execute(ServerRequestInterface $request = null) $origMessageId = null; foreach ($payload->getParts() as $part) { if ($part->getParsedHeader('content-type', 0, 0) === 'message/disposition-notification') { - $bodyPayload = MimePart::fromString($part->getBody()); + $bodyPayload = MimePart::fromString($part->getBodyString()); $origMessageId = trim($bodyPayload->getParsedHeader('original-message-id', 0, 0), '<>'); } } @@ -164,7 +164,7 @@ public function execute(ServerRequestInterface $request = null) ) ); $responseHeaders = $mdn->getHeaders(); - $responseBody = $mdn->getBody(); + $responseBody = $mdn->getBodyString(); } else { $this->getLogger()->debug( sprintf( @@ -195,7 +195,7 @@ public function execute(ServerRequestInterface $request = null) // Build the mdn for the message based on processing status $mdn = $this->manager->buildMdn($message, null, $e->getMessage()); $responseHeaders = $mdn->getHeaders(); - $responseBody = $mdn->getBody(); + $responseBody = $mdn->getBodyString(); } else { $responseStatus = 500; $responseBody = $e->getMessage(); From 885c0a5df50f93828b6dfa56a8d6fd693a8e472e Mon Sep 17 00:00:00 2001 From: Matt Dwyer Date: Thu, 7 Sep 2023 17:05:53 +1000 Subject: [PATCH 2/2] Update the PHPUnit tests to use the new MimePart::getBodyString() method --- tests/Unit/CryptoHelperTest.php | 4 ++-- tests/Unit/ManagementTest.php | 6 +++--- tests/Unit/MimePartTest.php | 13 ++++++------- tests/Unit/ServerTest.php | 14 +++++++------- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/tests/Unit/CryptoHelperTest.php b/tests/Unit/CryptoHelperTest.php index ba5c3fe..2733132 100644 --- a/tests/Unit/CryptoHelperTest.php +++ b/tests/Unit/CryptoHelperTest.php @@ -91,7 +91,7 @@ public function testCompress() 'compressed-data', $payload->getParsedHeader('content-type', 0, 'smime-type') ); - $body = base64_decode($payload->getBody()); + $body = base64_decode($payload->getBodyString()); self::assertEquals(0x30, ord($body[0])); self::assertEquals(0x82, ord($body[1])); self::assertEquals(0x02, ord($body[2])); @@ -114,6 +114,6 @@ public function testDecompress() $payload = CryptoHelper::decompress($payload); self::assertEquals('Application/EDI-X12', $payload->getHeaderLine('content-type')); - self::assertEquals(2247, strlen($payload->getBody())); + self::assertEquals(2247, strlen($payload->getBodyString())); } } diff --git a/tests/Unit/ManagementTest.php b/tests/Unit/ManagementTest.php index d2a2b1e..735ae4d 100644 --- a/tests/Unit/ManagementTest.php +++ b/tests/Unit/ManagementTest.php @@ -126,7 +126,7 @@ public function testBuildMdn() $report = $this->management->buildMdn($message); - self::assertNull($report->getBody()); + self::assertEmpty($report->getBodyString()); $message->setHeaders('disposition-notification-to: test@example.com'); @@ -135,10 +135,10 @@ public function testBuildMdn() self::assertTrue($report->isReport()); self::assertEquals($report->getHeaderLine('as2-to'), $sender->getAs2Id()); self::assertEquals($report->getHeaderLine('as2-from'), $receiver->getAs2Id()); - self::assertEquals('custom', trim($report->getPart(0)->getBody())); + self::assertEquals('custom', trim($report->getPart(0)->getBodyString())); $headers = new MimePart( - Utils::parseHeaders($report->getPart(1)->getBody()) + Utils::parseHeaders($report->getPart(1)->getBodyString()) ); self::assertEquals('', $headers->getHeaderLine('Original-Message-ID')); diff --git a/tests/Unit/MimePartTest.php b/tests/Unit/MimePartTest.php index 71af164..e355ca8 100644 --- a/tests/Unit/MimePartTest.php +++ b/tests/Unit/MimePartTest.php @@ -92,8 +92,7 @@ public function testIsMultipart() $mimePart = new MimePart( [ - 'Content-Type' => 'multipart/mixed; -boundary="'.$boundary.'"', + 'Content-Type' => 'multipart/mixed; boundary="'.$boundary.'"', ] ); $mimePart->addPart('1'); @@ -106,13 +105,13 @@ public function testIsMultipart() public function testBody(): void { $mimePart = MimePart::fromString("content-type:text/plain;\n\ntest"); - self::assertEquals('test', $mimePart->getBody()); + self::assertEquals('test', $mimePart->getBodyString()); $mimePart->setBody('test2'); - self::assertEquals('test2', $mimePart->getBody()); + self::assertEquals('test2', $mimePart->getBodyString()); $mimePart = MimePart::fromString("content-type:multipart/mixed;\r\n\r\ntest"); - self::assertEquals('test', $mimePart->getBody()); + self::assertEquals('test', $mimePart->getBodyString()); $mimePart->setBody(new MimePart([], '1')); self::assertEquals(1, $mimePart->getCountParts()); @@ -131,7 +130,7 @@ public function testMultipart(): void self::assertStringStartsWith('application/pkcs7-signature', $mime->getPart(1)->getHeaderLine('content-type')); self::assertEquals('application/EDI-Consent', $mime->getPart(0)->getHeaderLine('content-type')); self::assertEquals('binary', $mime->getPart(0)->getHeaderLine('Content-Transfer-Encoding')); - self::assertStringStartsWith('UNB+UNOA', $mime->getPart(0)->getBody()); + self::assertStringStartsWith('UNB+UNOA', $mime->getPart(0)->getBodyString()); } public function testBodyWithoutHeaders(): void @@ -139,7 +138,7 @@ public function testBodyWithoutHeaders(): void $res = MimePart::fromString($this->loadFixture('test.edi')); self::assertEmpty($res->getHeaders()); - self::assertStringStartsWith('UNB+UNOA', $res->getBody()); + self::assertStringStartsWith('UNB+UNOA', $res->getBodyString()); } public function testCreateIfBinaryPartNotBinary(): void diff --git a/tests/Unit/ServerTest.php b/tests/Unit/ServerTest.php index 65a0d41..0c4564f 100644 --- a/tests/Unit/ServerTest.php +++ b/tests/Unit/ServerTest.php @@ -51,17 +51,17 @@ public function testSignedMdn() self::assertTrue($report->isReport()); $content = $report->getPart(0); - self::assertEquals("Your message was successfully received and processed.\r\n", $content->getBody()); + self::assertEquals("Your message was successfully received and processed.\r\n", $content->getBodyString()); self::assertEquals('7bit', $content->getHeaderLine('Content-Transfer-Encoding')); $disposition = $report->getPart(1); - self::assertStringContainsString('Original-Recipient: rfc822; B', $disposition->getBody()); - self::assertStringContainsString('Original-Recipient: rfc822; B', $disposition->getBody()); - self::assertStringContainsString('Final-Recipient: rfc822; B', $disposition->getBody()); - self::assertStringContainsString('Original-Message-ID: ', $disposition->getBody()); + self::assertStringContainsString('Original-Recipient: rfc822; B', $disposition->getBodyString()); + self::assertStringContainsString('Original-Recipient: rfc822; B', $disposition->getBodyString()); + self::assertStringContainsString('Final-Recipient: rfc822; B', $disposition->getBodyString()); + self::assertStringContainsString('Original-Message-ID: ', $disposition->getBodyString()); self::assertStringContainsString('Disposition: automatic-action/MDN-sent-automatically; processed', - $disposition->getBody()); - self::assertStringContainsString('oVDpnrSnpq+V99dXaarQ9HFyRUaFNsp9tdBBSmRhX4s=, sha256', $disposition->getBody()); + $disposition->getBodyString()); + self::assertStringContainsString('oVDpnrSnpq+V99dXaarQ9HFyRUaFNsp9tdBBSmRhX4s=, sha256', $disposition->getBodyString()); } protected function setUp(): void