html purifier 보강
This commit is contained in:
+2
-1
@@ -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
@@ -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
@@ -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',
|
||||
|
||||
Vendored
+1
-1
@@ -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',
|
||||
|
||||
Vendored
+9
-1
@@ -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',
|
||||
|
||||
Vendored
+42
@@ -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
@@ -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
@@ -0,0 +1,62 @@
|
||||
# HTML5 Definitions for HTML Purifier
|
||||
|
||||
[](https://travis-ci.org/xemlock/htmlpurifier-html5)
|
||||
[](https://packagist.org/packages/xemlock/htmlpurifier-html5)
|
||||
[](https://packagist.org/packages/xemlock/htmlpurifier-html5)
|
||||
[](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
@@ -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"
|
||||
}
|
||||
}
|
||||
+38
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user