vendor/symfony/mime/Header/Headers.php line 22

  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <[email protected]>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Mime\Header;
  11. use Symfony\Component\Mime\Address;
  12. use Symfony\Component\Mime\Exception\LogicException;
  13. /**
  14.  * A collection of headers.
  15.  *
  16.  * @author Fabien Potencier <[email protected]>
  17.  */
  18. final class Headers
  19. {
  20.     private const UNIQUE_HEADERS = [
  21.         'date''from''sender''reply-to''to''cc''bcc',
  22.         'message-id''in-reply-to''references''subject',
  23.     ];
  24.     private const HEADER_CLASS_MAP = [
  25.         'date' => DateHeader::class,
  26.         'from' => MailboxListHeader::class,
  27.         'sender' => MailboxHeader::class,
  28.         'reply-to' => MailboxListHeader::class,
  29.         'to' => MailboxListHeader::class,
  30.         'cc' => MailboxListHeader::class,
  31.         'bcc' => MailboxListHeader::class,
  32.         'message-id' => IdentificationHeader::class,
  33.         'in-reply-to' => [UnstructuredHeader::class, IdentificationHeader::class], // `In-Reply-To` and `References` are less strict than RFC 2822 (3.6.4) to allow users entering the original email's ...
  34.         'references' => [UnstructuredHeader::class, IdentificationHeader::class], // ... `Message-ID`, even if that is no valid `msg-id`
  35.         'return-path' => PathHeader::class,
  36.     ];
  37.     /**
  38.      * @var HeaderInterface[][]
  39.      */
  40.     private array $headers = [];
  41.     private int $lineLength 76;
  42.     public function __construct(HeaderInterface ...$headers)
  43.     {
  44.         foreach ($headers as $header) {
  45.             $this->add($header);
  46.         }
  47.     }
  48.     public function __clone()
  49.     {
  50.         foreach ($this->headers as $name => $collection) {
  51.             foreach ($collection as $i => $header) {
  52.                 $this->headers[$name][$i] = clone $header;
  53.             }
  54.         }
  55.     }
  56.     public function setMaxLineLength(int $lineLength)
  57.     {
  58.         $this->lineLength $lineLength;
  59.         foreach ($this->all() as $header) {
  60.             $header->setMaxLineLength($lineLength);
  61.         }
  62.     }
  63.     public function getMaxLineLength(): int
  64.     {
  65.         return $this->lineLength;
  66.     }
  67.     /**
  68.      * @param array<Address|string> $addresses
  69.      *
  70.      * @return $this
  71.      */
  72.     public function addMailboxListHeader(string $name, array $addresses): static
  73.     {
  74.         return $this->add(new MailboxListHeader($nameAddress::createArray($addresses)));
  75.     }
  76.     /**
  77.      * @return $this
  78.      */
  79.     public function addMailboxHeader(string $nameAddress|string $address): static
  80.     {
  81.         return $this->add(new MailboxHeader($nameAddress::create($address)));
  82.     }
  83.     /**
  84.      * @return $this
  85.      */
  86.     public function addIdHeader(string $namestring|array $ids): static
  87.     {
  88.         return $this->add(new IdentificationHeader($name$ids));
  89.     }
  90.     /**
  91.      * @return $this
  92.      */
  93.     public function addPathHeader(string $nameAddress|string $path): static
  94.     {
  95.         return $this->add(new PathHeader($name$path instanceof Address $path : new Address($path)));
  96.     }
  97.     /**
  98.      * @return $this
  99.      */
  100.     public function addDateHeader(string $name\DateTimeInterface $dateTime): static
  101.     {
  102.         return $this->add(new DateHeader($name$dateTime));
  103.     }
  104.     /**
  105.      * @return $this
  106.      */
  107.     public function addTextHeader(string $namestring $value): static
  108.     {
  109.         return $this->add(new UnstructuredHeader($name$value));
  110.     }
  111.     /**
  112.      * @return $this
  113.      */
  114.     public function addParameterizedHeader(string $namestring $value, array $params = []): static
  115.     {
  116.         return $this->add(new ParameterizedHeader($name$value$params));
  117.     }
  118.     /**
  119.      * @return $this
  120.      */
  121.     public function addHeader(string $namemixed $argument, array $more = []): static
  122.     {
  123.         $headerClass self::HEADER_CLASS_MAP[strtolower($name)] ?? UnstructuredHeader::class;
  124.         if (\is_array($headerClass)) {
  125.             $headerClass $headerClass[0];
  126.         }
  127.         $parts explode('\\'$headerClass);
  128.         $method 'add'.ucfirst(array_pop($parts));
  129.         if ('addUnstructuredHeader' === $method) {
  130.             $method 'addTextHeader';
  131.         } elseif ('addIdentificationHeader' === $method) {
  132.             $method 'addIdHeader';
  133.         }
  134.         return $this->$method($name$argument$more);
  135.     }
  136.     public function has(string $name): bool
  137.     {
  138.         return isset($this->headers[strtolower($name)]);
  139.     }
  140.     /**
  141.      * @return $this
  142.      */
  143.     public function add(HeaderInterface $header): static
  144.     {
  145.         self::checkHeaderClass($header);
  146.         $header->setMaxLineLength($this->lineLength);
  147.         $name strtolower($header->getName());
  148.         if (\in_array($nameself::UNIQUE_HEADERStrue) && isset($this->headers[$name]) && \count($this->headers[$name]) > 0) {
  149.             throw new LogicException(sprintf('Impossible to set header "%s" as it\'s already defined and must be unique.'$header->getName()));
  150.         }
  151.         $this->headers[$name][] = $header;
  152.         return $this;
  153.     }
  154.     public function get(string $name): ?HeaderInterface
  155.     {
  156.         $name strtolower($name);
  157.         if (!isset($this->headers[$name])) {
  158.             return null;
  159.         }
  160.         $values array_values($this->headers[$name]);
  161.         return array_shift($values);
  162.     }
  163.     public function all(string $name null): iterable
  164.     {
  165.         if (null === $name) {
  166.             foreach ($this->headers as $name => $collection) {
  167.                 foreach ($collection as $header) {
  168.                     yield $name => $header;
  169.                 }
  170.             }
  171.         } elseif (isset($this->headers[strtolower($name)])) {
  172.             foreach ($this->headers[strtolower($name)] as $header) {
  173.                 yield $header;
  174.             }
  175.         }
  176.     }
  177.     public function getNames(): array
  178.     {
  179.         return array_keys($this->headers);
  180.     }
  181.     public function remove(string $name): void
  182.     {
  183.         unset($this->headers[strtolower($name)]);
  184.     }
  185.     public static function isUniqueHeader(string $name): bool
  186.     {
  187.         return \in_array(strtolower($name), self::UNIQUE_HEADERStrue);
  188.     }
  189.     /**
  190.      * @throws LogicException if the header name and class are not compatible
  191.      */
  192.     public static function checkHeaderClass(HeaderInterface $header): void
  193.     {
  194.         $name strtolower($header->getName());
  195.         $headerClasses self::HEADER_CLASS_MAP[$name] ?? [];
  196.         if (!\is_array($headerClasses)) {
  197.             $headerClasses = [$headerClasses];
  198.         }
  199.         if (!$headerClasses) {
  200.             return;
  201.         }
  202.         foreach ($headerClasses as $c) {
  203.             if ($header instanceof $c) {
  204.                 return;
  205.             }
  206.         }
  207.         throw new LogicException(sprintf('The "%s" header must be an instance of "%s" (got "%s").'$header->getName(), implode('" or "'$headerClasses), get_debug_type($header)));
  208.     }
  209.     public function toString(): string
  210.     {
  211.         $string '';
  212.         foreach ($this->toArray() as $str) {
  213.             $string .= $str."\r\n";
  214.         }
  215.         return $string;
  216.     }
  217.     public function toArray(): array
  218.     {
  219.         $arr = [];
  220.         foreach ($this->all() as $header) {
  221.             if ('' !== $header->getBodyAsString()) {
  222.                 $arr[] = $header->toString();
  223.             }
  224.         }
  225.         return $arr;
  226.     }
  227.     public function getHeaderBody(string $name)
  228.     {
  229.         return $this->has($name) ? $this->get($name)->getBody() : null;
  230.     }
  231.     /**
  232.      * @internal
  233.      */
  234.     public function setHeaderBody(string $typestring $namemixed $body): void
  235.     {
  236.         if ($this->has($name)) {
  237.             $this->get($name)->setBody($body);
  238.         } else {
  239.             $this->{'add'.$type.'Header'}($name$body);
  240.         }
  241.     }
  242.     public function getHeaderParameter(string $namestring $parameter): ?string
  243.     {
  244.         if (!$this->has($name)) {
  245.             return null;
  246.         }
  247.         $header $this->get($name);
  248.         if (!$header instanceof ParameterizedHeader) {
  249.             throw new LogicException(sprintf('Unable to get parameter "%s" on header "%s" as the header is not of class "%s".'$parameter$nameParameterizedHeader::class));
  250.         }
  251.         return $header->getParameter($parameter);
  252.     }
  253.     /**
  254.      * @internal
  255.      */
  256.     public function setHeaderParameter(string $namestring $parameter, ?string $value): void
  257.     {
  258.         if (!$this->has($name)) {
  259.             throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not defined.'$parameter$name));
  260.         }
  261.         $header $this->get($name);
  262.         if (!$header instanceof ParameterizedHeader) {
  263.             throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not of class "%s".'$parameter$nameParameterizedHeader::class));
  264.         }
  265.         $header->setParameter($parameter$value);
  266.     }
  267. }