From 5c82edc4bef2e1d4a735d02e6487dc043a43953b Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 24 Jun 2018 02:56:38 +0900 Subject: [PATCH] =?UTF-8?q?html=20purifier=20=EB=B3=B4=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 3 +- composer.lock | 42 ++++++- vendor/composer/autoload_classmap.php | 8 ++ vendor/composer/autoload_files.php | 2 +- vendor/composer/autoload_static.php | 10 +- vendor/composer/installed.json | 42 +++++++ vendor/xemlock/htmlpurifier-html5/LICENSE | 22 ++++ vendor/xemlock/htmlpurifier-html5/README.md | 62 +++++++++ .../xemlock/htmlpurifier-html5/composer.json | 25 ++++ .../HTMLPurifier/AttrDef/HTML/Bool2.php | 38 ++++++ .../library/HTMLPurifier/AttrDef/Regexp.php | 48 +++++++ .../library/HTMLPurifier/ChildDef/Details.php | 84 +++++++++++++ .../library/HTMLPurifier/ChildDef/Figure.php | 89 +++++++++++++ .../library/HTMLPurifier/ChildDef/Media.php | 94 ++++++++++++++ .../library/HTMLPurifier/ChildDef/Picture.php | 54 ++++++++ .../library/HTMLPurifier/HTML5Config.php | 75 +++++++++++ .../library/HTMLPurifier/HTML5Definition.php | 118 ++++++++++++++++++ 17 files changed, 812 insertions(+), 4 deletions(-) create mode 100644 vendor/xemlock/htmlpurifier-html5/LICENSE create mode 100644 vendor/xemlock/htmlpurifier-html5/README.md create mode 100644 vendor/xemlock/htmlpurifier-html5/composer.json create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML/Bool2.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Regexp.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Details.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Figure.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Media.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Picture.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Config.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Definition.php diff --git a/composer.json b/composer.json index 218dbccd..7158ebdf 100644 --- a/composer.json +++ b/composer.json @@ -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": { diff --git a/composer.lock b/composer.lock index 5e70d1a5..3c556fb3 100644 --- a/composer.lock +++ b/composer.lock @@ -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": [], diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 0f375530..f698c3fd 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -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', diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index db419d6f..c61c1246 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -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', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index b1fe0e54..1762a4fd 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -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', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 544eced6..1829b0a3 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -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" } ] diff --git a/vendor/xemlock/htmlpurifier-html5/LICENSE b/vendor/xemlock/htmlpurifier-html5/LICENSE new file mode 100644 index 00000000..cf02cf13 --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/LICENSE @@ -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. + diff --git a/vendor/xemlock/htmlpurifier-html5/README.md b/vendor/xemlock/htmlpurifier-html5/README.md new file mode 100644 index 00000000..aea27ebd --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/README.md @@ -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. diff --git a/vendor/xemlock/htmlpurifier-html5/composer.json b/vendor/xemlock/htmlpurifier-html5/composer.json new file mode 100644 index 00000000..3bdbe952 --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/composer.json @@ -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" + } +} diff --git a/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML/Bool2.php b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML/Bool2.php new file mode 100644 index 00000000..b063a9c6 --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML/Bool2.php @@ -0,0 +1,38 @@ +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 diff --git a/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Regexp.php b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Regexp.php new file mode 100644 index 00000000..edcfc338 --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Regexp.php @@ -0,0 +1,48 @@ +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 diff --git a/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Details.php b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Details.php new file mode 100644 index 00000000..fce75bd7 --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Details.php @@ -0,0 +1,84 @@ + 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; + } +} diff --git a/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Figure.php b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Figure.php new file mode 100644 index 00000000..b59f4041 --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Figure.php @@ -0,0 +1,89 @@ + 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; + } +} diff --git a/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Media.php b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Media.php new file mode 100644 index 00000000..d77a13da --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Media.php @@ -0,0 +1,94 @@ + 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; + } +} diff --git a/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Picture.php b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Picture.php new file mode 100644 index 00000000..192571f6 --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Picture.php @@ -0,0 +1,54 @@ + 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; + } +} diff --git a/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Config.php b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Config.php new file mode 100644 index 00000000..bbc9028d --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Config.php @@ -0,0 +1,75 @@ +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); + } +} diff --git a/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Definition.php b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Definition.php new file mode 100644 index 00000000..90dded61 --- /dev/null +++ b/vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Definition.php @@ -0,0 +1,118 @@ +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; + } +}