html purifier 보강

This commit is contained in:
2018-06-24 02:56:38 +09:00
parent 093c04bc24
commit 5c82edc4be
17 changed files with 812 additions and 4 deletions
+2 -1
View File
@@ -18,7 +18,8 @@
"php-extended/php-tail": "^2.1",
"pguardiario/phpuri": "^1.0",
"symfony/lock": "^4.1",
"ezyang/htmlpurifier": "^4.10"
"ezyang/htmlpurifier": "^4.10",
"xemlock/htmlpurifier-html5": "^0.1.7"
},
"autoload": {
"psr-4": {
Generated
+41 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "cdf923ea7b2d505b83ec019db08b2f9b",
"content-hash": "43da7d5e9d8441faa4311f32b16ee1c0",
"packages": [
{
"name": "brandonwamboldt/utilphp",
@@ -858,6 +858,46 @@
"validator"
],
"time": "2018-05-06T10:45:26+00:00"
},
{
"name": "xemlock/htmlpurifier-html5",
"version": "v0.1.7",
"source": {
"type": "git",
"url": "https://github.com/xemlock/htmlpurifier-html5.git",
"reference": "b4b35e51ec75e0207c23035f7d9a354bdcdac359"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/xemlock/htmlpurifier-html5/zipball/b4b35e51ec75e0207c23035f7d9a354bdcdac359",
"reference": "b4b35e51ec75e0207c23035f7d9a354bdcdac359",
"shasum": ""
},
"require": {
"ezyang/htmlpurifier": "^4.7",
"php": ">=5.2"
},
"require-dev": {
"phpunit/phpunit": "4.7.*|5.7.*"
},
"type": "library",
"autoload": {
"classmap": [
"library/HTMLPurifier/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "xemlock",
"email": "xemlock@gmail.com"
}
],
"description": "HTML Purifier definitions for HTML5 elements",
"time": "2018-06-07T14:30:17+00:00"
}
],
"packages-dev": [],
+8
View File
@@ -11,6 +11,14 @@ return array(
'DBTransaction' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'FB' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/fb.php',
'FirePHP' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php',
'HTMLPurifier_AttrDef_HTML_Bool2' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML/Bool2.php',
'HTMLPurifier_AttrDef_Regexp' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Regexp.php',
'HTMLPurifier_ChildDef_Details' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Details.php',
'HTMLPurifier_ChildDef_Figure' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Figure.php',
'HTMLPurifier_ChildDef_Media' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Media.php',
'HTMLPurifier_ChildDef_Picture' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Picture.php',
'HTMLPurifier_HTML5Config' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Config.php',
'HTMLPurifier_HTML5Definition' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Definition.php',
'MeekroDB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBEval' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBException' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
+1 -1
View File
@@ -6,9 +6,9 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'5b154887902198b16314243c6e0e3e19' => $vendorDir . '/pguardiario/phpuri/phpuri.php',
'870dc64919afa8b0f700701bb2c6a783' => $baseDir . '/f_config/config.php',
+9 -1
View File
@@ -7,9 +7,9 @@ namespace Composer\Autoload;
class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
{
public static $files = array (
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'5b154887902198b16314243c6e0e3e19' => __DIR__ . '/..' . '/pguardiario/phpuri/phpuri.php',
'870dc64919afa8b0f700701bb2c6a783' => __DIR__ . '/../..' . '/f_config/config.php',
@@ -138,6 +138,14 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
'DBTransaction' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'FB' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/fb.php',
'FirePHP' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php',
'HTMLPurifier_AttrDef_HTML_Bool2' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML/Bool2.php',
'HTMLPurifier_AttrDef_Regexp' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Regexp.php',
'HTMLPurifier_ChildDef_Details' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Details.php',
'HTMLPurifier_ChildDef_Figure' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Figure.php',
'HTMLPurifier_ChildDef_Media' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Media.php',
'HTMLPurifier_ChildDef_Picture' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Picture.php',
'HTMLPurifier_HTML5Config' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Config.php',
'HTMLPurifier_HTML5Definition' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Definition.php',
'MeekroDB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBEval' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBException' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
+42
View File
@@ -885,5 +885,47 @@
"validation",
"validator"
]
},
{
"name": "xemlock/htmlpurifier-html5",
"version": "v0.1.7",
"version_normalized": "0.1.7.0",
"source": {
"type": "git",
"url": "https://github.com/xemlock/htmlpurifier-html5.git",
"reference": "b4b35e51ec75e0207c23035f7d9a354bdcdac359"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/xemlock/htmlpurifier-html5/zipball/b4b35e51ec75e0207c23035f7d9a354bdcdac359",
"reference": "b4b35e51ec75e0207c23035f7d9a354bdcdac359",
"shasum": ""
},
"require": {
"ezyang/htmlpurifier": "^4.7",
"php": ">=5.2"
},
"require-dev": {
"phpunit/phpunit": "4.7.*|5.7.*"
},
"time": "2018-06-07T14:30:17+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"library/HTMLPurifier/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "xemlock",
"email": "xemlock@gmail.com"
}
],
"description": "HTML Purifier definitions for HTML5 elements"
}
]
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Xemlock
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+62
View File
@@ -0,0 +1,62 @@
# HTML5 Definitions for HTML Purifier
[![Build Status](https://travis-ci.org/xemlock/htmlpurifier-html5.svg?branch=master)](https://travis-ci.org/xemlock/htmlpurifier-html5)
[![Latest Stable Version](https://img.shields.io/packagist/v/xemlock/htmlpurifier-html5.svg)](https://packagist.org/packages/xemlock/htmlpurifier-html5)
[![Total Downloads](https://img.shields.io/packagist/dt/xemlock/htmlpurifier-html5.svg)](https://packagist.org/packages/xemlock/htmlpurifier-html5)
[![License](https://img.shields.io/packagist/l/xemlock/htmlpurifier-html5.svg)](https://packagist.org/packages/xemlock/htmlpurifier-html5)
This library provides HTML5 element definitions for [HTMLPurifier](http://htmlpurifier.org/).
## Installation
Install with [Composer](https://getcomposer.org/) by running the following command:
```
composer require xemlock/htmlpurifier-html5
```
## Usage
The most basic usage is similar to the original HTML Purifier. Create a HTML5-compatible config
using `HTMLPurifier_HTML5Config::createDefault()` factory method, and then pass it to an `HTMLPurifier` instance:
```php
$config = HTMLPurifier_HTML5Config::createDefault();
$purifier = new HTMLPurifier($config);
$clean_html5 = $purifier->purify($dirty_html5);
```
To modify the config you can either instantiate the config with a configuration array passed to
`HTMLPurifier_HTML5Config::create()`, or by calling `set` method on an already existing config instance.
For example, to allow `IFRAME`s with Youtube videos you can do the following:
```php
$config = HTMLPurifier_HTML5Config::create(array(
'HTML.SafeIframe' => true,
'URI.SafeIframeRegexp' => '%^//www\.youtube\.com/embed/%',
));
```
or equivalently:
```php
$config = HTMLPurifier_HTML5Config::createDefault();
$config->set('HTML.SafeIframe', true);
$config->set('URI.SafeIframeRegexp', '#^//www\.youtube\.com/embed/#');
```
## Supported HTML5 elements
Aside from HTML elements supported originally by HTML Purifier, this library
adds support for the following HTML5 elements:
article, aside, audio, details, figcaption, figure, footer, header, hgroup, main, nav, picture, section, source, summary, time, track, video
### Elements not (yet) supported
dialog, menu, menuitem, progress
## License
The MIT License (MIT). See the LICENSE file.
+25
View File
@@ -0,0 +1,25 @@
{
"name": "xemlock/htmlpurifier-html5",
"description": "HTML Purifier definitions for HTML5 elements",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "xemlock",
"email": "xemlock@gmail.com"
}
],
"require": {
"php": ">=5.2",
"ezyang/htmlpurifier": "^4.7"
},
"require-dev": {
"phpunit/phpunit": "4.7.*|5.7.*"
},
"autoload": {
"classmap": ["library/HTMLPurifier/"]
},
"scripts": {
"test": "phpunit"
}
}
@@ -0,0 +1,38 @@
<?php
/**
* Validates a boolean attribute
*
* HTMLPurifier 4.6.0 has broken support for boolean attributes, as reported
* in: http://htmlpurifier.org/phorum/read.php?3,7631,7631
* This issue has almost been fixed in 4.7.0, boolean attributes are properly
* parsed, but their values are not validated.
*/
class HTMLPurifier_AttrDef_HTML_Bool2 extends HTMLPurifier_AttrDef_HTML_Bool
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool
*/
public function validate($string, $config, $context)
{
$name = strlen($this->name) ? $this->name : $context->get('CurrentAttr');
// boolean attribute validates if its value is either empty
// or case-insensitively equal to attribute name
return $string === '' || strcasecmp($name, $string) === 0;
}
/**
* @param string $string Name of attribute
* @return HTMLPurifier_AttrDef_HTML_Bool2
*/
public function make($string)
{
return new self($string);
}
}
// vim: et sw=4 sts=4
@@ -0,0 +1,48 @@
<?php
class HTMLPurifier_AttrDef_Regexp extends HTMLPurifier_AttrDef
{
/**
* @var string
*/
protected $pattern;
/**
* @param string $pattern
*/
public function __construct($pattern = null)
{
if ($pattern !== null) {
$pattern = (string) $pattern;
if (false === @preg_match($pattern, 'Test')) {
throw new HTMLPurifier_Exception('Invalid regular expression pattern provided');
}
$this->pattern = $pattern;
}
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool
*/
public function validate($string, $config, $context)
{
if ($this->pattern) {
return (bool) preg_match($this->pattern, $string);
}
return false;
}
/**
* @param string $string
* @return HTMLPurifier_AttrDef_Regexp
*/
public function make($string)
{
return new self($string);
}
}
// vim: et sw=4 sts=4
@@ -0,0 +1,84 @@
<?php
class HTMLPurifier_ChildDef_Details extends HTMLPurifier_ChildDef
{
public $type = 'details';
public $elements = array(
'summary' => true,
);
protected $allowedElements;
/**
* @param HTMLPurifier_Config $config
* @return array
*/
public function getAllowedElements($config)
{
if (null === $this->allowedElements) {
// Add Flow content to allowed elements to prevent MakeWellFormed
// strategy moving them outside details element
$def = $config->getHTMLDefinition();
$this->allowedElements = array_merge(
$def->info_content_sets['Flow'],
$this->elements
);
}
return $this->allowedElements;
}
/**
* @param array $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
if (empty($children)) {
return false;
}
if (!isset($config->getHTMLDefinition()->info['summary'])) {
trigger_error("Cannot allow details without allowing summary", E_USER_WARNING);
return false;
}
$summary = null;
$result = array();
// Content model:
// One summary element followed by flow content
foreach ($children as $node) {
if (!$summary && $node->name === 'summary') {
$summary = $node;
continue;
}
if ($node->name === 'summary') {
// duplicated summary, add only its children
$result = array_merge($result, (array) $node->children);
} else {
$result[] = $node;
}
}
$whitespaceOnly = true;
foreach ($result as $node) {
$whitespaceOnly = $whitespaceOnly && !empty($node->is_whitespace);
}
if (!$summary) {
// remove parent node if there are no children or all children are whitespace-only
if ($whitespaceOnly) {
return false;
}
$summary = new HTMLPurifier_Node_Element('summary');
}
array_unshift($result, $summary);
return $result;
}
}
@@ -0,0 +1,89 @@
<?php
class HTMLPurifier_ChildDef_Figure extends HTMLPurifier_ChildDef
{
public $type = 'figure';
public $elements = array(
'figcaption' => true,
);
protected $allowedElements;
/**
* @param HTMLPurifier_Config $config
* @return array
*/
public function getAllowedElements($config)
{
if (null === $this->allowedElements) {
// Add Flow content to allowed elements to prevent MakeWellFormed
// strategy moving them outside 'figure' element
$def = $config->getHTMLDefinition();
$this->allowedElements = array_merge(
$def->info_content_sets['Flow'],
$this->elements
);
}
return $this->allowedElements;
}
/**
* @param array $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
$allowFigcaption = isset($config->getHTMLDefinition()->info['figcaption']);
$hasFigcaption = false;
$figcaptionPos = -1;
$result = array();
// Content model:
// Either: one figcaption element followed by flow content.
// Or: flow content followed by one figcaption element.
// Or: flow content.
// Scan through children, accept at most one figcaption. If additional
// figcaption appears replace it with div
foreach ($children as $node) {
if ($node->name === 'figcaption') {
if ($allowFigcaption && !$hasFigcaption) {
$hasFigcaption = true;
$figcaptionPos = count($result);
$result[] = $node;
continue;
}
$div = new HTMLPurifier_Node_Element('div', $node->attr);
$div->children = $node->children;
$result[] = $div;
continue;
}
// Figcaption must be a first or last child of a figure element.
// If it's not first, then we ignore all siblings that come after.
if ($hasFigcaption && $figcaptionPos > 0) {
break;
}
$result[] = $node;
}
$whitespaceOnly = true;
foreach ($result as $node) {
$whitespaceOnly = $whitespaceOnly && !empty($node->is_whitespace);
}
// remove parent node if there are no children or all children are whitespace-only
if (empty($result) || $whitespaceOnly) {
return false;
}
return $result;
}
}
@@ -0,0 +1,94 @@
<?php
class HTMLPurifier_ChildDef_Media extends HTMLPurifier_ChildDef
{
public $type = 'media';
public $elements = array(
'source' => true,
'track' => true,
);
protected $allowedElements;
/**
* @param HTMLPurifier_Config $config
* @return array
*/
public function getAllowedElements($config)
{
if (null === $this->allowedElements) {
// Add Flow content to allowed elements to prevent MakeWellFormed
// strategy moving them outside details element
$def = $config->getHTMLDefinition();
$this->allowedElements = array_merge(
$def->info_content_sets['Flow'],
$this->elements
);
unset(
$this->allowedElements['audio'],
$this->allowedElements['video']
);
}
return $this->allowedElements;
}
/**
* @param array $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
// Content model:
// If the element has a src attribute: zero or more track elements,
// then transparent, but with no media element descendants.
// If the element does not have a src attribute: zero or more source
// elements, then zero or more track elements, then transparent, but
// with no media element descendants.
$allowSource = isset($config->getHTMLDefinition()->info['source']);
$allowTrack = isset($config->getHTMLDefinition()->info['track']);
$sources = array();
$tracks = array();
$content = array();
foreach ($children as $node) {
switch ($node->name) {
case 'source':
if ($allowSource) {
$sources[] = $node;
}
break;
case 'track':
if ($allowTrack) {
$tracks[] = $node;
}
break;
default:
$content[] = $node;
break;
}
}
$currentNode = $context->get('CurrentNode');
$hasSrcAttr = $currentNode instanceof HTMLPurifier_Node_Element && isset($currentNode->attr['src']);
if ($hasSrcAttr) {
$result = array_merge($tracks, $content);
} else {
$result = array_merge($sources, $tracks, $content);
}
if (empty($result) && !$hasSrcAttr) {
return false;
}
return $result;
}
}
@@ -0,0 +1,54 @@
<?php
class HTMLPurifier_ChildDef_Picture extends HTMLPurifier_ChildDef
{
public $type = 'picture';
public $elements = array(
'img' => true,
'source' => true,
);
/**
* @param array $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
// if there are no tokens, delete parent node
if (empty($children)) {
return false;
}
if (!isset($config->getHTMLDefinition()->info['img'])) {
trigger_error("Cannot allow picture without allowing img", E_USER_WARNING);
return false;
}
$allowSource = isset($config->getHTMLDefinition()->info['source']);
$hasImg = false;
$result = array();
// Content model:
// Zero or more source elements, followed by one img element, optionally intermixed with script-supporting elements.
// https://html.spec.whatwg.org/multipage/embedded-content.html#the-picture-element
foreach ($children as $node) {
if (($allowSource && $node->name === 'source') || $node->name === 'img') {
$result[] = $node;
}
if ($node->name === 'img') {
$hasImg = true;
break;
}
}
if (!$hasImg || empty($result)) {
return false;
}
return $result;
}
}
@@ -0,0 +1,75 @@
<?php
class HTMLPurifier_HTML5Config extends HTMLPurifier_Config
{
const REVISION = 2018060702;
/**
* @param string|array|HTMLPurifier_Config $config
* @param HTMLPurifier_ConfigSchema $schema
* @return HTMLPurifier_Config
*/
public static function create($config, $schema = null)
{
if ($config instanceof HTMLPurifier_Config) {
$schema = $config->def;
$config = null;
}
if (!$schema instanceof HTMLPurifier_ConfigSchema) {
$schema = HTMLPurifier_ConfigSchema::instance();
}
$configObj = new self($schema);
$configObj->set('Core.Encoding', 'UTF-8');
$configObj->set('HTML.Doctype', 'HTML 4.01 Transitional');
$configObj->set('HTML.DefinitionID', __CLASS__);
$configObj->set('HTML.DefinitionRev', self::REVISION);
if (is_string($config)) {
$configObj->loadIni($config);
} elseif (is_array($config)) {
$configObj->loadArray($config);
}
return $configObj;
}
/**
* Creates a configuration object using the default config schema instance
*
* @return HTMLPurifier_Config
*/
public static function createDefault()
{
$schema = HTMLPurifier_ConfigSchema::instance();
$config = self::create(null, $schema);
return $config;
}
/**
* Creates a new config object that inherits from a previous one
*
* @param HTMLPurifier_Config $config
* @return HTMLPurifier_Config
*/
public static function inherit(HTMLPurifier_Config $config)
{
return new self($config->def, $config->plist);
}
public function getDefinition($type, $raw = false, $optimized = false)
{
// Setting HTML.* keys removes any previously instantiated HTML
// definition object, so set up HTML5 definition as late as possible
$needSetup = $type === 'HTML' && !isset($this->definitions[$type]);
if ($needSetup) {
if ($def = parent::getDefinition($type, true, true)) {
HTMLPurifier_HTML5Definition::setup($def);
}
}
return parent::getDefinition($type, $raw, $optimized);
}
}
@@ -0,0 +1,118 @@
<?php
class HTMLPurifier_HTML5Definition
{
/**
* Adds HTML5 element and attributes to a provided definition object.
*
* @param HTMLPurifier_HTMLDefinition $def
* @return HTMLPurifier_HTMLDefinition
*/
public static function setup(HTMLPurifier_HTMLDefinition $def)
{
// use fixed implementation of Boolean attributes, instead of a buggy
// one provided with 4.6.0
$def->manager->attrTypes->set('Bool', new HTMLPurifier_AttrDef_HTML_Bool2());
// http://developers.whatwg.org/sections.html
$def->addElement('section', 'Block', 'Flow', 'Common');
$def->addElement('nav', 'Block', 'Flow', 'Common');
$def->addElement('article', 'Block', 'Flow', 'Common');
$def->addElement('aside', 'Block', 'Flow', 'Common');
$def->addElement('header', 'Block', 'Flow', 'Common');
$def->addElement('footer', 'Block', 'Flow', 'Common');
$def->addElement('main', 'Block', 'Flow', 'Common');
// Content model actually excludes several tags, not modelled here
$def->addElement('address', 'Block', 'Flow', 'Common');
$def->addElement('hgroup', 'Block', 'Required: h1 | h2 | h3 | h4 | h5 | h6', 'Common');
// https://html.spec.whatwg.org/dev/grouping-content.html#the-figure-element
$def->addElement('figure', 'Block', new HTMLPurifier_ChildDef_Figure(), 'Common');
$def->addElement('figcaption', false, 'Flow', 'Common');
$mediaContent = new HTMLPurifier_ChildDef_Media();
// https://html.spec.whatwg.org/dev/media.html#the-video-element
$def->addElement('video', 'Flow', $mediaContent, 'Common', array(
'controls' => 'Bool',
'height' => 'Length',
'poster' => 'URI',
'preload' => 'Enum#auto,metadata,none',
'src' => 'URI',
'width' => 'Length',
));
$def->getAnonymousModule()->addElementToContentSet('video', 'Inline');
// https://html.spec.whatwg.org/dev/media.html#the-audio-element
$def->addElement('audio', 'Flow', $mediaContent, 'Common', array(
'controls' => 'Bool',
'preload' => 'Enum#auto,metadata,none',
'src' => 'URI',
));
$def->getAnonymousModule()->addElementToContentSet('audio', 'Inline');
// https://html.spec.whatwg.org/dev/embedded-content.html#the-source-element
$def->addElement('source', false, 'Empty', 'Common', array(
'media' => 'Text',
'sizes' => 'Text',
'src' => 'URI',
'srcset' => 'Text',
'type' => 'Text',
));
// https://html.spec.whatwg.org/dev/media.html#the-track-element
$def->addElement('track', false, 'Empty', 'Common', array(
'kind' => 'Enum#captions,chapters,descriptions,metadata,subtitles',
'src' => 'URI',
'srclang' => 'Text',
'label' => 'Text',
'default' => 'Bool',
));
// https://html.spec.whatwg.org/dev/embedded-content.html#the-picture-element
$def->addElement('picture', 'Flow', new HTMLPurifier_ChildDef_Picture(), 'Common');
$def->getAnonymousModule()->addElementToContentSet('picture', 'Inline');
// http://developers.whatwg.org/text-level-semantics.html
$def->addElement('s', 'Inline', 'Inline', 'Common');
$def->addElement('var', 'Inline', 'Inline', 'Common');
$def->addElement('sub', 'Inline', 'Inline', 'Common');
$def->addElement('sup', 'Inline', 'Inline', 'Common');
$def->addElement('mark', 'Inline', 'Inline', 'Common');
$def->addElement('wbr', 'Inline', 'Empty', 'Core');
// http://developers.whatwg.org/edits.html
$def->addElement('ins', 'Block', 'Flow', 'Common', array('cite' => 'URI', 'datetime' => 'Text'));
$def->addElement('del', 'Block', 'Flow', 'Common', array('cite' => 'URI', 'datetime' => 'Text'));
// TIME
$time = $def->addElement('time', 'Inline', 'Inline', 'Common', array('datetime' => 'Text', 'pubdate' => 'Bool'));
$time->excludes = array('time' => true);
// https://html.spec.whatwg.org/dev/text-level-semantics.html#the-a-element
$def->addElement('a', 'Flow', 'Flow', 'Common', array(
'download' => 'Text',
'hreflang' => 'Text',
'rel' => 'Text',
'target' => new HTMLPurifier_AttrDef_HTML_FrameTarget(),
'type' => 'Text',
));
// IMG
$def->addAttribute('img', 'srcset', 'Text');
$def->addAttribute('img', 'sizes', 'Text');
// IFRAME
$def->addAttribute('iframe', 'allowfullscreen', 'Bool');
// Interactive elements
// https://html.spec.whatwg.org/dev/interactive-elements.html#the-details-element
$def->addElement('details', 'Block', new HTMLPurifier_ChildDef_Details(), 'Common', array(
'open' => 'Bool',
));
$def->addElement('summary', false, 'Flow', 'Common');
return $def;
}
}