SafeAnalysis.php 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. <?php
  2. class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
  3. {
  4. protected $data = array();
  5. public function getSafe(Twig_NodeInterface $node)
  6. {
  7. $hash = spl_object_hash($node);
  8. if (isset($this->data[$hash])) {
  9. foreach($this->data[$hash] as $bucket) {
  10. if ($bucket['key'] === $node) {
  11. return $bucket['value'];
  12. }
  13. }
  14. }
  15. return null;
  16. }
  17. protected function setSafe(Twig_NodeInterface $node, array $safe)
  18. {
  19. $hash = spl_object_hash($node);
  20. if (isset($this->data[$hash])) {
  21. foreach($this->data[$hash] as &$bucket) {
  22. if ($bucket['key'] === $node) {
  23. $bucket['value'] = $safe;
  24. return;
  25. }
  26. }
  27. }
  28. $this->data[$hash][] = array(
  29. 'key' => $node,
  30. 'value' => $safe,
  31. );
  32. }
  33. public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
  34. {
  35. return $node;
  36. }
  37. public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
  38. {
  39. if ($node instanceof Twig_Node_Expression_Constant) {
  40. // constants are marked safe for all
  41. $this->setSafe($node, array('all'));
  42. } elseif ($node instanceof Twig_Node_Expression_BlockReference) {
  43. // blocks are safe by definition
  44. $this->setSafe($node, array('all'));
  45. } elseif ($node instanceof Twig_Node_Expression_Parent) {
  46. // parent block is safe by definition
  47. $this->setSafe($node, array('all'));
  48. } elseif ($node instanceof Twig_Node_Expression_Conditional) {
  49. // intersect safeness of both operands
  50. $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
  51. $this->setSafe($node, $safe);
  52. } elseif ($node instanceof Twig_Node_Expression_Filter) {
  53. // filter expression is safe when the filter is safe
  54. $name = $node->getNode('filter')->getAttribute('value');
  55. $args = $node->getNode('arguments');
  56. if (false !== $filter = $env->getFilter($name)) {
  57. $this->setSafe($node, $filter->getSafe($args));
  58. } else {
  59. $this->setSafe($node, array());
  60. }
  61. } elseif ($node instanceof Twig_Node_Expression_Function) {
  62. // function expression is safe when the function is safe
  63. $name = $node->getAttribute('name');
  64. $args = $node->getNode('arguments');
  65. $function = $env->getFunction($name);
  66. if (false !== $function) {
  67. $this->setSafe($node, $function->getSafe($args));
  68. } else {
  69. $this->setSafe($node, array());
  70. }
  71. } elseif ($node instanceof Twig_Node_Expression_MethodCall) {
  72. if ($node->getAttribute('safe')) {
  73. $this->setSafe($node, array('all'));
  74. } else {
  75. $this->setSafe($node, array());
  76. }
  77. } else {
  78. $this->setSafe($node, array());
  79. }
  80. return $node;
  81. }
  82. protected function intersectSafe(array $a = null, array $b = null)
  83. {
  84. if (null === $a || null === $b) {
  85. return array();
  86. }
  87. if (in_array('all', $a)) {
  88. return $b;
  89. }
  90. if (in_array('all', $b)) {
  91. return $a;
  92. }
  93. return array_intersect($a, $b);
  94. }
  95. /**
  96. * {@inheritdoc}
  97. */
  98. public function getPriority()
  99. {
  100. return 0;
  101. }
  102. }