Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ParameterizedHeader.php 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  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\Encoder\Rfc2231Encoder;
  12. /**
  13. * @author Chris Corbyn
  14. *
  15. * @experimental in 4.3
  16. */
  17. final class ParameterizedHeader extends UnstructuredHeader
  18. {
  19. /**
  20. * RFC 2231's definition of a token.
  21. *
  22. * @var string
  23. */
  24. const TOKEN_REGEX = '(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+)';
  25. private $encoder;
  26. private $parameters = [];
  27. public function __construct(string $name, string $value, array $parameters = [])
  28. {
  29. parent::__construct($name, $value);
  30. foreach ($parameters as $k => $v) {
  31. $this->setParameter($k, $v);
  32. }
  33. if ('content-disposition' === strtolower($name)) {
  34. $this->encoder = new Rfc2231Encoder();
  35. }
  36. }
  37. public function setParameter(string $parameter, ?string $value)
  38. {
  39. $this->setParameters(array_merge($this->getParameters(), [$parameter => $value]));
  40. }
  41. public function getParameter(string $parameter): string
  42. {
  43. return $this->getParameters()[$parameter] ?? '';
  44. }
  45. /**
  46. * @param string[] $parameters
  47. */
  48. public function setParameters(array $parameters)
  49. {
  50. $this->parameters = $parameters;
  51. }
  52. /**
  53. * @return string[]
  54. */
  55. public function getParameters(): array
  56. {
  57. return $this->parameters;
  58. }
  59. public function getBodyAsString(): string
  60. {
  61. $body = parent::getBodyAsString();
  62. foreach ($this->parameters as $name => $value) {
  63. if (null !== $value) {
  64. $body .= '; '.$this->createParameter($name, $value);
  65. }
  66. }
  67. return $body;
  68. }
  69. /**
  70. * Generate a list of all tokens in the final header.
  71. *
  72. * This doesn't need to be overridden in theory, but it is for implementation
  73. * reasons to prevent potential breakage of attributes.
  74. */
  75. protected function toTokens(string $string = null): array
  76. {
  77. $tokens = parent::toTokens(parent::getBodyAsString());
  78. // Try creating any parameters
  79. foreach ($this->parameters as $name => $value) {
  80. if (null !== $value) {
  81. // Add the semi-colon separator
  82. $tokens[\count($tokens) - 1] .= ';';
  83. $tokens = array_merge($tokens, $this->generateTokenLines(' '.$this->createParameter($name, $value)));
  84. }
  85. }
  86. return $tokens;
  87. }
  88. /**
  89. * Render a RFC 2047 compliant header parameter from the $name and $value.
  90. */
  91. private function createParameter(string $name, string $value): string
  92. {
  93. $origValue = $value;
  94. $encoded = false;
  95. // Allow room for parameter name, indices, "=" and DQUOTEs
  96. $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1;
  97. $firstLineOffset = 0;
  98. // If it's not already a valid parameter value...
  99. if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) {
  100. // TODO: text, or something else??
  101. // ... and it's not ascii
  102. if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) {
  103. $encoded = true;
  104. // Allow space for the indices, charset and language
  105. $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1;
  106. $firstLineOffset = \strlen($this->getCharset()."'".$this->getLanguage()."'");
  107. }
  108. }
  109. // Encode if we need to
  110. if ($encoded || \strlen($value) > $maxValueLength) {
  111. if (null !== $this->encoder) {
  112. $value = $this->encoder->encodeString($origValue, $this->getCharset(), $firstLineOffset, $maxValueLength);
  113. } else {
  114. // We have to go against RFC 2183/2231 in some areas for interoperability
  115. $value = $this->getTokenAsEncodedWord($origValue);
  116. $encoded = false;
  117. }
  118. }
  119. $valueLines = $this->encoder ? explode("\r\n", $value) : [$value];
  120. // Need to add indices
  121. if (\count($valueLines) > 1) {
  122. $paramLines = [];
  123. foreach ($valueLines as $i => $line) {
  124. $paramLines[] = $name.'*'.$i.$this->getEndOfParameterValue($line, true, 0 === $i);
  125. }
  126. return implode(";\r\n ", $paramLines);
  127. } else {
  128. return $name.$this->getEndOfParameterValue($valueLines[0], $encoded, true);
  129. }
  130. }
  131. /**
  132. * Returns the parameter value from the "=" and beyond.
  133. *
  134. * @param string $value to append
  135. */
  136. private function getEndOfParameterValue(string $value, bool $encoded = false, bool $firstLine = false): string
  137. {
  138. if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) {
  139. $value = '"'.$value.'"';
  140. }
  141. $prepend = '=';
  142. if ($encoded) {
  143. $prepend = '*=';
  144. if ($firstLine) {
  145. $prepend = '*='.$this->getCharset()."'".$this->getLanguage()."'";
  146. }
  147. }
  148. return $prepend.$value;
  149. }
  150. }