1<?php 2namespace TYPO3Fluid\Fluid\Core\Parser\Interceptor; 3 4/* 5 * This file belongs to the package "TYPO3 Fluid". 6 * See LICENSE.txt that was shipped with this package. 7 */ 8 9use TYPO3Fluid\Fluid\Core\Parser\InterceptorInterface; 10use TYPO3Fluid\Fluid\Core\Parser\ParsingState; 11use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\EscapingNode; 12use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\ExpressionNodeInterface; 13use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface; 14use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode; 15use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode; 16 17/** 18 * An interceptor adding the "Htmlspecialchars" viewhelper to the suitable places. 19 */ 20class Escape implements InterceptorInterface 21{ 22 23 /** 24 * Is the interceptor enabled right now for child nodes? 25 * 26 * @var boolean 27 */ 28 protected $childrenEscapingEnabled = true; 29 30 /** 31 * A stack of ViewHelperNodes which currently disable the interceptor. 32 * Needed to enable the interceptor again. 33 * 34 * @var NodeInterface[] 35 */ 36 protected $viewHelperNodesWhichDisableTheInterceptor = []; 37 38 /** 39 * Adds a ViewHelper node using the Format\HtmlspecialcharsViewHelper to the given node. 40 * If "escapingInterceptorEnabled" in the ViewHelper is FALSE, will disable itself inside the ViewHelpers body. 41 * 42 * @param NodeInterface $node 43 * @param integer $interceptorPosition One of the INTERCEPT_* constants for the current interception point 44 * @param ParsingState $parsingState the current parsing state. Not needed in this interceptor. 45 * @return NodeInterface 46 */ 47 public function process(NodeInterface $node, $interceptorPosition, ParsingState $parsingState) 48 { 49 if ($interceptorPosition === InterceptorInterface::INTERCEPT_OPENING_VIEWHELPER) { 50 /** @var ViewHelperNode $node */ 51 if (!$node->getUninitializedViewHelper()->isChildrenEscapingEnabled()) { 52 $this->childrenEscapingEnabled = false; 53 $this->viewHelperNodesWhichDisableTheInterceptor[] = $node; 54 } 55 } elseif ($interceptorPosition === InterceptorInterface::INTERCEPT_CLOSING_VIEWHELPER) { 56 if (end($this->viewHelperNodesWhichDisableTheInterceptor) === $node) { 57 array_pop($this->viewHelperNodesWhichDisableTheInterceptor); 58 if (count($this->viewHelperNodesWhichDisableTheInterceptor) === 0) { 59 $this->childrenEscapingEnabled = true; 60 } 61 } 62 /** @var ViewHelperNode $node */ 63 if ($this->childrenEscapingEnabled && $node->getUninitializedViewHelper()->isOutputEscapingEnabled()) { 64 $node = new EscapingNode($node); 65 } 66 } elseif ($this->childrenEscapingEnabled && ($node instanceof ObjectAccessorNode || $node instanceof ExpressionNodeInterface)) { 67 $node = new EscapingNode($node); 68 } 69 return $node; 70 } 71 72 /** 73 * This interceptor wants to hook into object accessor creation, and opening / closing ViewHelpers. 74 * 75 * @return array Array of INTERCEPT_* constants 76 */ 77 public function getInterceptionPoints() 78 { 79 return [ 80 InterceptorInterface::INTERCEPT_OPENING_VIEWHELPER, 81 InterceptorInterface::INTERCEPT_CLOSING_VIEWHELPER, 82 InterceptorInterface::INTERCEPT_OBJECTACCESSOR, 83 InterceptorInterface::INTERCEPT_EXPRESSION, 84 ]; 85 } 86} 87