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.

168 lines
3.6 KiB

3 years ago
  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\HttpFoundation;
  11. // Help opcache.preload discover always-needed symbols
  12. class_exists(AcceptHeaderItem::class);
  13. /**
  14. * Represents an Accept-* header.
  15. *
  16. * An accept header is compound with a list of items,
  17. * sorted by descending quality.
  18. *
  19. * @author Jean-François Simon <contact@jfsimon.fr>
  20. */
  21. class AcceptHeader
  22. {
  23. /**
  24. * @var AcceptHeaderItem[]
  25. */
  26. private $items = [];
  27. /**
  28. * @var bool
  29. */
  30. private $sorted = true;
  31. /**
  32. * @param AcceptHeaderItem[] $items
  33. */
  34. public function __construct(array $items)
  35. {
  36. foreach ($items as $item) {
  37. $this->add($item);
  38. }
  39. }
  40. /**
  41. * Builds an AcceptHeader instance from a string.
  42. *
  43. * @return self
  44. */
  45. public static function fromString(?string $headerValue)
  46. {
  47. $index = 0;
  48. $parts = HeaderUtils::split($headerValue ?? '', ',;=');
  49. return new self(array_map(function ($subParts) use (&$index) {
  50. $part = array_shift($subParts);
  51. $attributes = HeaderUtils::combine($subParts);
  52. $item = new AcceptHeaderItem($part[0], $attributes);
  53. $item->setIndex($index++);
  54. return $item;
  55. }, $parts));
  56. }
  57. /**
  58. * Returns header value's string representation.
  59. *
  60. * @return string
  61. */
  62. public function __toString()
  63. {
  64. return implode(',', $this->items);
  65. }
  66. /**
  67. * Tests if header has given value.
  68. *
  69. * @return bool
  70. */
  71. public function has(string $value)
  72. {
  73. return isset($this->items[$value]);
  74. }
  75. /**
  76. * Returns given value's item, if exists.
  77. *
  78. * @return AcceptHeaderItem|null
  79. */
  80. public function get(string $value)
  81. {
  82. return $this->items[$value] ?? $this->items[explode('/', $value)[0].'/*'] ?? $this->items['*/*'] ?? $this->items['*'] ?? null;
  83. }
  84. /**
  85. * Adds an item.
  86. *
  87. * @return $this
  88. */
  89. public function add(AcceptHeaderItem $item)
  90. {
  91. $this->items[$item->getValue()] = $item;
  92. $this->sorted = false;
  93. return $this;
  94. }
  95. /**
  96. * Returns all items.
  97. *
  98. * @return AcceptHeaderItem[]
  99. */
  100. public function all()
  101. {
  102. $this->sort();
  103. return $this->items;
  104. }
  105. /**
  106. * Filters items on their value using given regex.
  107. *
  108. * @return self
  109. */
  110. public function filter(string $pattern)
  111. {
  112. return new self(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) {
  113. return preg_match($pattern, $item->getValue());
  114. }));
  115. }
  116. /**
  117. * Returns first item.
  118. *
  119. * @return AcceptHeaderItem|null
  120. */
  121. public function first()
  122. {
  123. $this->sort();
  124. return !empty($this->items) ? reset($this->items) : null;
  125. }
  126. /**
  127. * Sorts items by descending quality.
  128. */
  129. private function sort(): void
  130. {
  131. if (!$this->sorted) {
  132. uasort($this->items, function (AcceptHeaderItem $a, AcceptHeaderItem $b) {
  133. $qA = $a->getQuality();
  134. $qB = $b->getQuality();
  135. if ($qA === $qB) {
  136. return $a->getIndex() > $b->getIndex() ? 1 : -1;
  137. }
  138. return $qA > $qB ? -1 : 1;
  139. });
  140. $this->sorted = true;
  141. }
  142. }
  143. }