]> git.mxchange.org Git - friendica.git/commitdiff
Add implementation of the Content-Type header value from the MIME type RFC
authorHypolite Petovan <hypolite@mrpetovan.com>
Fri, 29 Sep 2023 01:17:40 +0000 (21:17 -0400)
committerHypolite Petovan <hypolite@mrpetovan.com>
Tue, 3 Oct 2023 23:58:50 +0000 (19:58 -0400)
- Add tests for the new classes

src/Network/Entity/MimeType.php [new file with mode: 0644]
src/Network/Factory/MimeType.php [new file with mode: 0644]
tests/src/Network/MimeTypeTest.php [new file with mode: 0644]

diff --git a/src/Network/Entity/MimeType.php b/src/Network/Entity/MimeType.php
new file mode 100644 (file)
index 0000000..4400a9d
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Network\Entity;
+
+use Friendica\BaseEntity;
+
+/**
+ * Implementation of the Content-Type header value from the MIME type RFC
+ *
+ * @see https://www.rfc-editor.org/rfc/rfc2045#section-5
+ *
+ * @property-read string $type
+ * @property-read string $subtype
+ * @property-read array $parameters
+ */
+class MimeType extends BaseEntity
+{
+       /** @var string */
+       protected $type;
+       /** @var string */
+       protected $subtype;
+       /** @var array */
+       protected $parameters;
+
+       public function __construct(string $type, string $subtype, array $parameters = [])
+       {
+               $this->type = $type;
+               $this->subtype = $subtype;
+               $this->parameters = $parameters;
+       }
+
+       public function __toString(): string
+       {
+               $parameters = array_map(function (string $attribute, string $value) {
+                       if (
+                               strpos($value, '"') !== false ||
+                               strpos($value, '\\') !== false ||
+                               strpos($value, "\r") !== false
+                       ) {
+                               $value = '"' . str_replace(['\\', '"', "\r"], ['\\\\', '\\"', "\\\r"], $value) . '"';
+                       }
+
+                       return '; ' . $attribute . '=' . $value;
+               }, array_keys($this->parameters), array_values($this->parameters));
+
+               return $this->type . '/' .
+                       $this->subtype .
+                       implode('', $parameters);
+       }
+}
diff --git a/src/Network/Factory/MimeType.php b/src/Network/Factory/MimeType.php
new file mode 100644 (file)
index 0000000..eb09658
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Network\Factory;
+
+use Friendica\BaseFactory;
+use Friendica\Core\System;
+use Friendica\Network\Entity;
+
+/**
+ * Implementation of the Content-Type header value from the MIME type RFC
+ *
+ * @see https://www.rfc-editor.org/rfc/rfc2045#section-5
+ */
+class MimeType extends BaseFactory
+{
+       public function createFromContentType(?string $contentType): Entity\MimeType
+       {
+               if ($contentType) {
+                       $parameterStrings = explode(';', $contentType);
+                       $mimetype = array_shift($parameterStrings);
+
+                       $types = explode('/', $mimetype);
+                       if (count($types) >= 2) {
+                               $filetype = strtolower($types[0]);
+                               $subtype = strtolower($types[1]);
+                       } else {
+                               $this->logger->notice('Unknown MimeType', ['type' => $contentType, 'callstack' => System::callstack(10)]);
+                       }
+
+                       $parameters = [];
+                       foreach ($parameterStrings as $parameterString) {
+                               $parameterString = trim($parameterString);
+                               $parameterParts = explode('=', $parameterString, 2);
+                               if (count($parameterParts) < 2) {
+                                       continue;
+                               }
+
+                               $attribute = trim($parameterParts[0]);
+                               $valueString = trim($parameterParts[1]);
+
+                               if ($valueString[0] == '"' && $valueString[strlen($valueString) - 1] == '"') {
+                                       $valueString = substr(str_replace(['\\"', '\\\\', "\\\r"], ['"', '\\', "\r"], $valueString), 1, -1);
+                               }
+
+                               $value = preg_replace('#\s*\([^()]*?\)#', '', $valueString);
+
+                               $parameters[$attribute] = $value;
+                       }
+               }
+
+               return new Entity\MimeType(
+                       $filetype ?? 'unkn',
+                       $subtype ?? 'unkn',
+                       $parameters ?? [],
+               );
+       }
+}
diff --git a/tests/src/Network/MimeTypeTest.php b/tests/src/Network/MimeTypeTest.php
new file mode 100644 (file)
index 0000000..64a52d8
--- /dev/null
@@ -0,0 +1,152 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Test\src\Network;
+
+use Friendica\Network\Entity;
+use Friendica\Network\Factory;
+use PHPUnit\Framework\TestCase;
+use Psr\Log\NullLogger;
+
+class MimeTypeTest extends TestCase
+{
+       public function dataCreateFromContentType(): array
+       {
+               return [
+                       'image/jpg' => [
+                               'expected' => new Entity\MimeType('image', 'jpg'),
+                               'contentType' => 'image/jpg',
+                       ],
+                       'image/jpg;charset=utf8' => [
+                               'expected' => new Entity\MimeType('image', 'jpg', ['charset' => 'utf8']),
+                               'contentType' => 'image/jpg; charset=utf8',
+                       ],
+                       'image/jpg; charset=utf8' => [
+                               'expected' => new Entity\MimeType('image', 'jpg', ['charset' => 'utf8']),
+                               'contentType' => 'image/jpg; charset=utf8',
+                       ],
+                       'image/jpg; charset = utf8' => [
+                               'expected' => new Entity\MimeType('image', 'jpg', ['charset' => 'utf8']),
+                               'contentType' => 'image/jpg; charset=utf8',
+                       ],
+                       'image/jpg; charset="utf8"' => [
+                               'expected' => new Entity\MimeType('image', 'jpg', ['charset' => 'utf8']),
+                               'contentType' => 'image/jpg; charset="utf8"',
+                       ],
+                       'image/jpg; charset="\"utf8\""' => [
+                               'expected' => new Entity\MimeType('image', 'jpg', ['charset' => '"utf8"']),
+                               'contentType' => 'image/jpg; charset="\"utf8\""',
+                       ],
+                       'image/jpg; charset="\"utf8\" (comment)"' => [
+                               'expected' => new Entity\MimeType('image', 'jpg', ['charset' => '"utf8"']),
+                               'contentType' => 'image/jpg; charset="\"utf8\" (comment)"',
+                       ],
+                       'image/jpg; charset=utf8 (comment)' => [
+                               'expected' => new Entity\MimeType('image', 'jpg', ['charset' => 'utf8']),
+                               'contentType' => 'image/jpg; charset="utf8 (comment)"',
+                       ],
+                       'image/jpg; charset=utf8; attribute=value' => [
+                               'expected' => new Entity\MimeType('image', 'jpg', ['charset' => 'utf8', 'attribute' => 'value']),
+                               'contentType' => 'image/jpg; charset=utf8; attribute=value',
+                       ],
+                       'empty' => [
+                               'expected' => new Entity\MimeType('unkn', 'unkn'),
+                               'contentType' => '',
+                       ],
+                       'unknown' => [
+                               'expected' => new Entity\MimeType('unkn', 'unkn'),
+                               'contentType' => 'unknown',
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider dataCreateFromContentType
+        * @param Entity\MimeType $expected
+        * @param string          $contentType
+        * @return void
+        */
+       public function testCreateFromContentType(Entity\MimeType $expected, string $contentType)
+       {
+               $factory = new Factory\MimeType(new NullLogger());
+
+               $this->assertEquals($expected, $factory->createFromContentType($contentType));
+       }
+
+       public function dataToString(): array
+       {
+               return [
+                       'image/jpg' => [
+                               'expected' => 'image/jpg',
+                               'mimeType' => new Entity\MimeType('image', 'jpg'),
+                       ],
+                       'image/jpg;charset=utf8' => [
+                               'expected' => 'image/jpg; charset=utf8',
+                               'mimeType' => new Entity\MimeType('image', 'jpg', ['charset' => 'utf8']),
+                       ],
+                       'image/jpg; charset="\"utf8\""' => [
+                               'expected' => 'image/jpg; charset="\"utf8\""',
+                               'mimeType' => new Entity\MimeType('image', 'jpg', ['charset' => '"utf8"']),
+                       ],
+                       'image/jpg; charset=utf8; attribute=value' => [
+                               'expected' => 'image/jpg; charset=utf8; attribute=value',
+                               'mimeType' => new Entity\MimeType('image', 'jpg', ['charset' => 'utf8', 'attribute' => 'value']),
+                       ],
+                       'empty' => [
+                               'expected' => 'unkn/unkn',
+                               'mimeType' => new Entity\MimeType('unkn', 'unkn'),
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider dataToString
+        * @param string          $expected
+        * @param Entity\MimeType $mimeType
+        * @return void
+        */
+       public function testToString(string $expected, Entity\MimeType $mimeType)
+       {
+               $this->assertEquals($expected, $mimeType->__toString());
+       }
+
+       public function dataRoundtrip(): array
+       {
+               return [
+                       ['image/jpg'],
+                       ['image/jpg; charset=utf8'],
+                       ['image/jpg; charset="\"utf8\""'],
+                       ['image/jpg; charset=utf8; attribute=value'],
+               ];
+       }
+
+       /**
+        * @dataProvider dataRoundtrip
+        * @param string $expected
+        * @return void
+        */
+       public function testRoundtrip(string $expected)
+       {
+               $factory = new Factory\MimeType(new NullLogger());
+
+               $this->assertEquals($expected, $factory->createFromContentType($expected)->__toString());
+       }
+}