vendor/shopware/core/Framework/Adapter/Twig/SecurityExtension.php line 122

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Adapter\Twig;
  3. use Shopware\Core\Framework\Log\Package;
  4. use Twig\Extension\AbstractExtension;
  5. use Twig\TwigFilter;
  6. /**
  7. * @internal
  8. */
  9. #[Package('system-settings')]
  10. class SecurityExtension extends AbstractExtension
  11. {
  12. /**
  13. * @var array<string>
  14. */
  15. private array $allowedPHPFunctions;
  16. /**
  17. * @param array<string> $allowedPHPFunctions
  18. */
  19. public function __construct(array $allowedPHPFunctions)
  20. {
  21. $this->allowedPHPFunctions = $allowedPHPFunctions;
  22. }
  23. /**
  24. * @return TwigFilter[]
  25. */
  26. public function getFilters(): array
  27. {
  28. return [
  29. new TwigFilter('map', [$this, 'map']),
  30. new TwigFilter('reduce', [$this, 'reduce']),
  31. new TwigFilter('filter', [$this, 'filter']),
  32. new TwigFilter('sort', [$this, 'sort']),
  33. ];
  34. }
  35. /**
  36. * @param iterable<mixed> $array
  37. * @param string|callable|\Closure $function
  38. *
  39. * @return array<mixed>
  40. */
  41. public function map(iterable $array, $function): array
  42. {
  43. if (\is_array($function)) {
  44. $function = implode('::', $function);
  45. }
  46. if (\is_string($function) && !\in_array($function, $this->allowedPHPFunctions, true)) {
  47. throw new \RuntimeException(sprintf('Function "%s" is not allowed', $function));
  48. }
  49. $result = [];
  50. foreach ($array as $key => $value) {
  51. // @phpstan-ignore-next-line
  52. $result[$key] = $function($value);
  53. }
  54. return $result;
  55. }
  56. /**
  57. * @param iterable<mixed> $array
  58. * @param string|callable|\Closure $function
  59. * @param mixed $initial
  60. *
  61. * @return mixed
  62. */
  63. public function reduce(iterable $array, $function, $initial = null)
  64. {
  65. if (\is_array($function)) {
  66. $function = implode('::', $function);
  67. }
  68. if (\is_string($function) && !\in_array($function, $this->allowedPHPFunctions, true)) {
  69. throw new \RuntimeException(sprintf('Function "%s" is not allowed', $function));
  70. }
  71. if (!\is_array($array)) {
  72. $array = iterator_to_array($array);
  73. }
  74. // @phpstan-ignore-next-line
  75. return array_reduce($array, $function, $initial);
  76. }
  77. /**
  78. * @param iterable<mixed> $array
  79. * @param string|callable|\Closure $arrow
  80. *
  81. * @return iterable<mixed>
  82. */
  83. public function filter(iterable $array, $arrow): iterable
  84. {
  85. if (\is_array($arrow)) {
  86. $arrow = implode('::', $arrow);
  87. }
  88. if (\is_string($arrow) && !\in_array($arrow, $this->allowedPHPFunctions, true)) {
  89. throw new \RuntimeException(sprintf('Function "%s" is not allowed', $arrow));
  90. }
  91. if (\is_array($array)) {
  92. // @phpstan-ignore-next-line
  93. return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH);
  94. }
  95. // @phpstan-ignore-next-line
  96. return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow);
  97. }
  98. /**
  99. * @param iterable<mixed> $array
  100. * @param string|callable|\Closure|null $arrow
  101. *
  102. * @return array<mixed>
  103. */
  104. public function sort(iterable $array, $arrow = null): array
  105. {
  106. if (\is_array($arrow)) {
  107. $arrow = implode('::', $arrow);
  108. }
  109. if (\is_string($arrow) && !\in_array($arrow, $this->allowedPHPFunctions, true)) {
  110. throw new \RuntimeException(sprintf('Function "%s" is not allowed', $arrow));
  111. }
  112. if ($array instanceof \Traversable) {
  113. $array = iterator_to_array($array);
  114. }
  115. if ($arrow !== null) {
  116. // @phpstan-ignore-next-line
  117. uasort($array, $arrow);
  118. } else {
  119. asort($array);
  120. }
  121. return $array;
  122. }
  123. }