.=< { Star Gans Tq } >=.

  • Home

  • Killme
  • Download
  • Current Path : /home/m/e/h/meharicl/www/phpBB3/vendor/s9e/text-formatter/src/Plugins/HTMLElements/
    Upload File
    @Command ~ $  
    Current File : /home/m/e/h/meharicl/www/phpBB3/vendor/s9e/text-formatter/src/Plugins/HTMLElements/Configurator.php

    <?php
    
    /**
    * @package   s9e\TextFormatter
    * @copyright Copyright (c) 2010-2020 The s9e authors
    * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
    */
    namespace s9e\TextFormatter\Plugins\HTMLElements;
    
    use InvalidArgumentException;
    use RuntimeException;
    use s9e\TextFormatter\Configurator\Helpers\RegexpBuilder;
    use s9e\TextFormatter\Configurator\Items\Tag;
    use s9e\TextFormatter\Configurator\Items\UnsafeTemplate;
    use s9e\TextFormatter\Configurator\JavaScript\Dictionary;
    use s9e\TextFormatter\Configurator\Validators\AttributeName;
    use s9e\TextFormatter\Configurator\Validators\TagName;
    use s9e\TextFormatter\Plugins\ConfiguratorBase;
    
    class Configurator extends ConfiguratorBase
    {
    	/**
    	* @var array 2D array using HTML element names as keys, each value being an associative array
    	*            using HTML attribute names as keys and their alias as values. A special empty entry
    	*            is used to store the HTML element's alias
    	*/
    	protected $aliases = [];
    
    	/**
    	* @var array  Default filter of a few known attributes
    	*
    	* It doesn't make much sense to try to declare every known HTML attribute here. Validation is
    	* not the purpose of this plugin. It does make sense however to declare URL attributes as such,
    	* so that they are subject to our constraints (disallowed hosts, etc...)
    	*
    	* @see scripts/patchHTMLElementConfigurator.php
    	*/
    	protected $attributeFilters = [
    		'action'     => '#url',
    		'cite'       => '#url',
    		'data'       => '#url',
    		'formaction' => '#url',
    		'href'       => '#url',
    		'icon'       => '#url',
    		'itemtype'   => '#url',
    		'longdesc'   => '#url',
    		'manifest'   => '#url',
    		'ping'       => '#url',
    		'poster'     => '#url',
    		'src'        => '#url'
    	];
    
    	/**
    	* @var array  Hash of allowed HTML elements. Element names are lowercased and used as keys for
    	*             this array
    	*/
    	protected $elements = [];
    
    	/**
    	* @var string Namespace prefix of the tags produced by this plugin's parser
    	*/
    	protected $prefix = 'html';
    
    	/**
    	* {@inheritdoc}
    	*/
    	protected $quickMatch = '<';
    
    	/**
    	* @var array  Blacklist of elements that are considered unsafe
    	*/
    	protected $unsafeElements = [
    		'base',
    		'embed',
    		'frame',
    		'iframe',
    		'meta',
    		'object',
    		'script'
    	];
    
    	/**
    	* @var array  Blacklist of attributes that are considered unsafe, in addition of any attribute
    	*             whose name starts with "on" such as "onmouseover"
    	*/
    	protected $unsafeAttributes = [
    		'style',
    		'target'
    	];
    
    	/**
    	* Alias the HTML attribute of given HTML element to a given attribute name
    	*
    	* NOTE: will *not* create the target attribute
    	*
    	* @param  string $elName   Name of the HTML element
    	* @param  string $attrName Name of the HTML attribute
    	* @param  string $alias    Alias
    	* @return void
    	*/
    	public function aliasAttribute($elName, $attrName, $alias)
    	{
    		$elName   = $this->normalizeElementName($elName);
    		$attrName = $this->normalizeAttributeName($attrName);
    
    		$this->aliases[$elName][$attrName] = AttributeName::normalize($alias);
    	}
    
    	/**
    	* Alias an HTML element to a given tag name
    	*
    	* NOTE: will *not* create the target tag
    	*
    	* @param  string $elName  Name of the HTML element
    	* @param  string $tagName Name of the tag
    	* @return void
    	*/
    	public function aliasElement($elName, $tagName)
    	{
    		$elName = $this->normalizeElementName($elName);
    
    		$this->aliases[$elName][''] = TagName::normalize($tagName);
    	}
    
    	/**
    	* Allow an HTML element to be used
    	*
    	* @param  string $elName Name of the element
    	* @return Tag            Tag that represents this element
    	*/
    	public function allowElement($elName)
    	{
    		return $this->allowElementWithSafety($elName, false);
    	}
    
    	/**
    	* Allow an unsafe HTML element to be used
    	*
    	* @param  string $elName Name of the element
    	* @return Tag            Tag that represents this element
    	*/
    	public function allowUnsafeElement($elName)
    	{
    		return $this->allowElementWithSafety($elName, true);
    	}
    
    	/**
    	* Allow a (potentially unsafe) HTML element to be used
    	*
    	* @param  string $elName      Name of the element
    	* @param  bool   $allowUnsafe Whether to allow unsafe elements
    	* @return Tag                 Tag that represents this element
    	*/
    	protected function allowElementWithSafety($elName, $allowUnsafe)
    	{
    		$elName  = $this->normalizeElementName($elName);
    		$tagName = $this->prefix . ':' . $elName;
    
    		if (!$allowUnsafe && in_array($elName, $this->unsafeElements))
    		{
    			throw new RuntimeException("'" . $elName . "' elements are unsafe and are disabled by default. Please use " . __CLASS__ . '::allowUnsafeElement() to bypass this security measure');
    		}
    
    		// Retrieve or create the tag
    		$tag = ($this->configurator->tags->exists($tagName))
    		     ? $this->configurator->tags->get($tagName)
    		     : $this->configurator->tags->add($tagName);
    
    		// Rebuild this tag's template
    		$this->rebuildTemplate($tag, $elName, $allowUnsafe);
    
    		// Record the element name
    		$this->elements[$elName] = 1;
    
    		return $tag;
    	}
    
    	/**
    	* Allow an attribute to be used in an HTML element
    	*
    	* @param  string $elName   Name of the element
    	* @param  string $attrName Name of the attribute
    	* @return \s9e\Configurator\Items\Attribute
    	*/
    	public function allowAttribute($elName, $attrName)
    	{
    		return $this->allowAttributeWithSafety($elName, $attrName, false);
    	}
    
    	/**
    	* Allow an unsafe attribute to be used in an HTML element
    	*
    	* @param  string $elName   Name of the element
    	* @param  string $attrName Name of the attribute
    	* @return \s9e\Configurator\Items\Attribute
    	*/
    	public function allowUnsafeAttribute($elName, $attrName)
    	{
    		return $this->allowAttributeWithSafety($elName, $attrName, true);
    	}
    
    	/**
    	* Allow a (potentially unsafe) attribute to be used in an HTML element
    	*
    	* @param  string $elName   Name of the element
    	* @param  string $attrName Name of the attribute
    	* @param  bool   $allowUnsafe
    	* @return \s9e\Configurator\Items\Attribute
    	*/
    	protected function allowAttributeWithSafety($elName, $attrName, $allowUnsafe)
    	{
    		$elName   = $this->normalizeElementName($elName);
    		$attrName = $this->normalizeAttributeName($attrName);
    		$tagName  = $this->prefix . ':' . $elName;
    
    		if (!isset($this->elements[$elName]))
    		{
    			throw new RuntimeException("Element '" . $elName . "' has not been allowed");
    		}
    
    		if (!$allowUnsafe)
    		{
    			if (substr($attrName, 0, 2) === 'on'
    			 || in_array($attrName, $this->unsafeAttributes))
    			{
    				throw new RuntimeException("'" . $attrName . "' attributes are unsafe and are disabled by default. Please use " . __CLASS__ . '::allowUnsafeAttribute() to bypass this security measure');
    			}
    		}
    
    		$tag = $this->configurator->tags->get($tagName);
    		if (!isset($tag->attributes[$attrName]))
    		{
    			$attribute = $tag->attributes->add($attrName);
    			$attribute->required = false;
    
    			if (isset($this->attributeFilters[$attrName]))
    			{
    				$filterName = $this->attributeFilters[$attrName];
    				$filter = $this->configurator->attributeFilters->get($filterName);
    
    				$attribute->filterChain->append($filter);
    			}
    		}
    
    		// Rebuild this tag's template
    		$this->rebuildTemplate($tag, $elName, $allowUnsafe);
    
    		return $tag->attributes[$attrName];
    	}
    
    	/**
    	* Validate and normalize an element name
    	*
    	* Accepts any name that would be valid, regardless of whether this element exists in HTML5.
    	* Might be slightly off as the HTML5 specs don't seem to require it to start with a letter but
    	* our implementation does.
    	*
    	* @link http://dev.w3.org/html5/spec/syntax.html#syntax-tag-name
    	*
    	* @param  string $elName Original element name
    	* @return string         Normalized element name, in lowercase
    	*/
    	protected function normalizeElementName($elName)
    	{
    		if (!preg_match('#^[a-z][a-z0-9]*$#Di', $elName))
    		{
    			throw new InvalidArgumentException("Invalid element name '" . $elName . "'");
    		}
    
    		return strtolower($elName);
    	}
    
    	/**
    	* Validate and normalize an attribute name
    	*
    	* More restrictive than the specs but allows all HTML5 attributes and more.
    	*
    	* @param  string $attrName Original attribute name
    	* @return string           Normalized attribute name, in lowercase
    	*/
    	protected function normalizeAttributeName($attrName)
    	{
    		if (!preg_match('#^[a-z][-\\w]*$#Di', $attrName))
    		{
    			throw new InvalidArgumentException("Invalid attribute name '" . $attrName . "'");
    		}
    
    		return strtolower($attrName);
    	}
    
    	/**
    	* Rebuild a tag's template
    	*
    	* @param  Tag    $tag         Source tag
    	* @param  string $elName      Name of the HTML element created by the template
    	* @param  bool   $allowUnsafe Whether to allow unsafe markup
    	* @return void
    	*/
    	protected function rebuildTemplate(Tag $tag, $elName, $allowUnsafe)
    	{
    		$template = '<' . $elName . '>';
    		foreach ($tag->attributes as $attrName => $attribute)
    		{
    			$template .= '<xsl:copy-of select="@' . $attrName . '"/>';
    		}
    		$template .= '<xsl:apply-templates/></' . $elName . '>';
    
    		if ($allowUnsafe)
    		{
    			$template = new UnsafeTemplate($template);
    		}
    
    		$tag->setTemplate($template);
    	}
    
    	/**
    	* Generate this plugin's config
    	*
    	* @return array|null
    	*/
    	public function asConfig()
    	{
    		if (empty($this->elements) && empty($this->aliases))
    		{
    			return;
    		}
    
    		/**
    		* Regexp used to match an attributes definition (name + value if applicable)
    		*
    		* @link http://dev.w3.org/html5/spec/syntax.html#attributes-0
    		*/
    		$attrRegexp = '[a-z][-a-z0-9]*(?>\\s*=\\s*(?>"[^"]*"|\'[^\']*\'|[^\\s"\'=<>`]+))?';
    		$tagRegexp  = RegexpBuilder::fromList(array_merge(
    			array_keys($this->aliases),
    			array_keys($this->elements)
    		));
    
    		$endTagRegexp   = '/(' . $tagRegexp . ')';
    		$startTagRegexp = '(' . $tagRegexp . ')((?>\\s+' . $attrRegexp . ')*+)\\s*/?';
    
    		$regexp = '#<(?>' . $endTagRegexp . '|' . $startTagRegexp . ')\\s*>#i';
    
    		$config = [
    			'quickMatch' => $this->quickMatch,
    			'prefix'     => $this->prefix,
    			'regexp'     => $regexp
    		];
    
    		if (!empty($this->aliases))
    		{
    			// Preserve the aliases array's keys in JavaScript
    			$config['aliases'] = new Dictionary;
    			foreach ($this->aliases as $elName => $aliases)
    			{
    				$config['aliases'][$elName] = new Dictionary($aliases);
    			}
    		}
    
    		return $config;
    	}
    
    	/**
    	* {@inheritdoc}
    	*/
    	public function getJSHints()
    	{
    		return ['HTMLELEMENTS_HAS_ALIASES' => (int) !empty($this->aliases)];
    	}
    }