mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2025-08-04 13:18:00 +02:00
Compare commits
110 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
83ab08bc1a | ||
|
2739fa5462 | ||
|
b91833877a | ||
|
abba77a80b | ||
|
7cfc44654a | ||
|
8c153eef3a | ||
|
524cd08a59 | ||
|
5a90c92d83 | ||
|
f03e1a2c48 | ||
|
a93250f251 | ||
|
5a8e48d672 | ||
|
cb5a742574 | ||
|
ff41146439 | ||
|
aa83689188 | ||
|
3d15f5253b | ||
|
21e32042e9 | ||
|
ce0ccc4bff | ||
|
ab7bbefe8a | ||
|
0f7b138aaf | ||
|
4b6b3b31e8 | ||
|
5a01e6535d | ||
|
b74425bee5 | ||
|
39068e6d08 | ||
|
b81690c17e | ||
|
4005ffd563 | ||
|
89b3fe431e | ||
|
3cb77da11d | ||
|
c1167edbf1 | ||
|
c7b5148c4f | ||
|
f8c830de12 | ||
|
0737a6e916 | ||
|
d85d39da45 | ||
|
f33d1f8e99 | ||
|
6d6d88512a | ||
|
bb7ad66526 | ||
|
64baeda65c | ||
|
67c3798922 | ||
|
df64746caa | ||
|
ab9c9f30fd | ||
|
5988f29583 | ||
|
ce0ede24de | ||
|
17f80cd74b | ||
|
e11f7c9802 | ||
|
d21213e0d3 | ||
|
9b3f856fb9 | ||
|
95e1bae318 | ||
|
ff16ed3de4 | ||
|
1df505296f | ||
|
b9bc1039da | ||
|
cb4871f446 | ||
|
65d5cdee50 | ||
|
b45c6f5363 | ||
|
6d50e5282a | ||
|
5bc7c72608 | ||
|
98984546d4 | ||
|
c7a2f6f0df | ||
|
fd24de69a3 | ||
|
5688656174 | ||
|
d728205767 | ||
|
8836ae05aa | ||
|
b90295deda | ||
|
de82f9845f | ||
|
9d2d75d8bc | ||
|
74f123a84c | ||
|
7e11c271b9 | ||
|
66bbae73a9 | ||
|
5886326cd0 | ||
|
564af61809 | ||
|
b19dcb0ba5 | ||
|
586abc63e4 | ||
|
5b6a3f55bf | ||
|
0c31b22240 | ||
|
5662efc936 | ||
|
353c96f156 | ||
|
4047a6230b | ||
|
9195cb7a2e | ||
|
39c4c359ad | ||
|
bb3f86e80a | ||
|
d16e73e63e | ||
|
f145f64bf4 | ||
|
5fdec87fe9 | ||
|
4462559459 | ||
|
12185143ef | ||
|
17a90a951a | ||
|
0bab4b9fd0 | ||
|
bd92f3531b | ||
|
0d5ab2fe13 | ||
|
d41a59e422 | ||
|
8e4cacf0a7 | ||
|
c82051c3e1 | ||
|
d4a96463ef | ||
|
1b7d684d07 | ||
|
5070404376 | ||
|
cef27f750d | ||
|
59463c5c39 | ||
|
d19d648a26 | ||
|
20b40a5441 | ||
|
34d252cbbc | ||
|
8b28e571fe | ||
|
3ae21ce511 | ||
|
3ba9133b21 | ||
|
dc8702160c | ||
|
4dc68aa920 | ||
|
08eee90e15 | ||
|
1ef4375dbb | ||
|
6a221a3045 | ||
|
246fc8946a | ||
|
1ce2fde400 | ||
|
1f982d279f | ||
|
8be8cee9b3 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,5 +1,6 @@
|
|||||||
/.gitattributes export-ignore
|
/.gitattributes export-ignore
|
||||||
/.gitignore export-ignore
|
/.gitignore export-ignore
|
||||||
|
/.travis.yml export-ignore
|
||||||
/Doxyfile export-ignore
|
/Doxyfile export-ignore
|
||||||
/art/ export-ignore
|
/art/ export-ignore
|
||||||
/benchmarks/ export-ignore
|
/benchmarks/ export-ignore
|
||||||
|
14
.travis.yml
Normal file
14
.travis.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
language: php
|
||||||
|
php:
|
||||||
|
- '5.4'
|
||||||
|
- '5.5'
|
||||||
|
- '5.6'
|
||||||
|
- '7.0'
|
||||||
|
- '7.1'
|
||||||
|
- '7.2'
|
||||||
|
- '7.3'
|
||||||
|
before_script:
|
||||||
|
- git clone --depth=50 https://github.com/ezyang/simpletest.git
|
||||||
|
- cp test-settings.travis.php test-settings.php
|
||||||
|
script:
|
||||||
|
- php tests/index.php
|
2
Doxyfile
2
Doxyfile
@@ -31,7 +31,7 @@ PROJECT_NAME = HTMLPurifier
|
|||||||
# This could be handy for archiving the generated documentation or
|
# This could be handy for archiving the generated documentation or
|
||||||
# if some version control system is used.
|
# if some version control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 4.8.0
|
PROJECT_NUMBER = 4.11.0
|
||||||
|
|
||||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||||
# base path where the generated documentation will be put.
|
# base path where the generated documentation will be put.
|
||||||
|
36
INSTALL
36
INSTALL
@@ -15,7 +15,7 @@ with these contents.
|
|||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
1. Compatibility
|
1. Compatibility
|
||||||
|
|
||||||
HTML Purifier is PHP 5 and PHP 7, and is actively tested from PHP 5.0.5
|
HTML Purifier is PHP 5 and PHP 7, and is actively tested from PHP 5.3
|
||||||
and up. It has no core dependencies with other libraries.
|
and up. It has no core dependencies with other libraries.
|
||||||
|
|
||||||
These optional extensions can enhance the capabilities of HTML Purifier:
|
These optional extensions can enhance the capabilities of HTML Purifier:
|
||||||
@@ -101,31 +101,6 @@ Autoload compatibility
|
|||||||
autoloader, but there are some cases where you will need to change
|
autoloader, but there are some cases where you will need to change
|
||||||
your own code to accomodate HTML Purifier. These are those cases:
|
your own code to accomodate HTML Purifier. These are those cases:
|
||||||
|
|
||||||
PHP VERSION IS LESS THAN 5.1.2, AND YOU'VE DEFINED __autoload
|
|
||||||
Because spl_autoload_register() doesn't exist in early versions
|
|
||||||
of PHP 5, HTML Purifier has no way of adding itself to the autoload
|
|
||||||
stack. Modify your __autoload function to test
|
|
||||||
HTMLPurifier_Bootstrap::autoload($class)
|
|
||||||
|
|
||||||
For example, suppose your autoload function looks like this:
|
|
||||||
|
|
||||||
function __autoload($class) {
|
|
||||||
require str_replace('_', '/', $class) . '.php';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
A modified version with HTML Purifier would look like this:
|
|
||||||
|
|
||||||
function __autoload($class) {
|
|
||||||
if (HTMLPurifier_Bootstrap::autoload($class)) return true;
|
|
||||||
require str_replace('_', '/', $class) . '.php';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Note that there *is* some custom behavior in our autoloader; the
|
|
||||||
original autoloader in our example would work for 99% of the time,
|
|
||||||
but would fail when including language files.
|
|
||||||
|
|
||||||
AN __autoload FUNCTION IS DECLARED AFTER OUR AUTOLOADER IS REGISTERED
|
AN __autoload FUNCTION IS DECLARED AFTER OUR AUTOLOADER IS REGISTERED
|
||||||
spl_autoload_register() has the curious behavior of disabling
|
spl_autoload_register() has the curious behavior of disabling
|
||||||
the existing __autoload() handler. Users need to explicitly
|
the existing __autoload() handler. Users need to explicitly
|
||||||
@@ -138,11 +113,6 @@ Autoload compatibility
|
|||||||
|
|
||||||
spl_autoload_register('__autoload')
|
spl_autoload_register('__autoload')
|
||||||
|
|
||||||
Users should also be on guard if they use a version of PHP previous
|
|
||||||
to 5.1.2 without an autoloader--HTML Purifier will define __autoload()
|
|
||||||
for you, which can collide with an autoloader that was added by *you*
|
|
||||||
later.
|
|
||||||
|
|
||||||
|
|
||||||
For better performance
|
For better performance
|
||||||
----------------------
|
----------------------
|
||||||
@@ -204,9 +174,7 @@ For advanced users
|
|||||||
HTMLPurifier.autoload.php
|
HTMLPurifier.autoload.php
|
||||||
Registers our autoload handler HTMLPurifier_Bootstrap::autoload($class).
|
Registers our autoload handler HTMLPurifier_Bootstrap::autoload($class).
|
||||||
|
|
||||||
You can do these operations by yourself--in fact, you must modify your own
|
You can do these operations by yourself, if you like.
|
||||||
autoload handler if you are using a version of PHP earlier than PHP 5.1.2
|
|
||||||
(See "Autoload compatibility" above).
|
|
||||||
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
@@ -11,7 +11,7 @@ pied de page, mais je recommande de lire le document.
|
|||||||
|
|
||||||
1. Compatibilité
|
1. Compatibilité
|
||||||
|
|
||||||
HTML Purifier fonctionne avec PHP 5. PHP 5.0.5 est la dernière version testée.
|
HTML Purifier fonctionne avec PHP 5. PHP 5.3 est la dernière version testée.
|
||||||
Il ne dépend pas d'autres librairies.
|
Il ne dépend pas d'autres librairies.
|
||||||
|
|
||||||
Les extensions optionnelles sont iconv (généralement déjà installée) et tidy
|
Les extensions optionnelles sont iconv (généralement déjà installée) et tidy
|
||||||
|
93
NEWS
93
NEWS
@@ -9,6 +9,99 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
|
|||||||
. Internal change
|
. Internal change
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
4.11.0, released 2019-07-14
|
||||||
|
# SafeScripting now matches case-sensitively against its whitelist (previously it was
|
||||||
|
case-insensitive.) Thanks Dimitri Gritsajuk <gritsajuk.dimitri@gmail.com>
|
||||||
|
for reporting.
|
||||||
|
! New directive %Core.AllowParseManyTags which allows parsing of many nested tags.
|
||||||
|
Thanks M. Suzuki <msuzuki1986@gmail.com> for contributing the patch.
|
||||||
|
! purifyArray now supports multidimensional arrays. Thanks
|
||||||
|
Sandro Miguel Marques <sandromiguel@sandromiguel.com> for contributing this patch.
|
||||||
|
! initial and inherit settings available for width, height, and the min-/max-
|
||||||
|
versions thereof. Thanks Michael Kliewe <info@phpgansta.de> for contributing
|
||||||
|
this patch.
|
||||||
|
! More color names are supported. Thanks Daijobou for contributing.
|
||||||
|
- Compatibility fixes for PHP 7.3, including new CI for PHP 7.3
|
||||||
|
(thank you Lukas Neumann <lksnmnn@gmail.com>) and removal of
|
||||||
|
reserved words in our constants (thanks Darko Hrgovic <darko@darkodev.com>
|
||||||
|
- Compatibility fixes for HHVM. Thanks Mateusz Turcza for contributing
|
||||||
|
this fix.
|
||||||
|
- HTML Purifier now never defines __autoload, fixing #196. Thanks
|
||||||
|
Michael Kliewe for reporting.
|
||||||
|
- In some situations, Config.php would report an undefined index: class
|
||||||
|
error; this has been fixed. Thanks DiLong Fa for contributing
|
||||||
|
this fix.
|
||||||
|
- We no longer produce <script /> tags; we always explicitly write
|
||||||
|
out the open and close tag. Thanks Dimitri Gritsajuk
|
||||||
|
<gritsajuk.dimitri@gmail.com> for contributing this fix.
|
||||||
|
- Better compatibility when IDNA constants are not present. Thanks
|
||||||
|
Mateusz Turcza <xemlock@gmail.com> for contributing this fix.
|
||||||
|
|
||||||
|
4.10.0, released 2018-02-22
|
||||||
|
# PHP 5.3 is no longer officially supported by HTML Purifier
|
||||||
|
(we did not specifically break support, but we are no longer
|
||||||
|
testing on PHP 5.3)
|
||||||
|
! Relative CSS length units are now supported
|
||||||
|
- A few PHP 7.2 compatibility fixes, thanks John Flatness
|
||||||
|
<john@zerocrates.org>
|
||||||
|
- Improve portability with old versions of libxml which don't
|
||||||
|
support accessing the data of a node
|
||||||
|
- IDNA2008 is now used for converting domains to ASCII, fixing
|
||||||
|
some rather strange bugs with international domains
|
||||||
|
- Fix race condition resulting in E_WARNING when creating
|
||||||
|
directories with Serializer
|
||||||
|
|
||||||
|
4.9.3, released 2017-06-02
|
||||||
|
- Workaround PHP 7.1 infinite loop when opcode cache is enabled.
|
||||||
|
Thanks @Xiphin (#134, #135)
|
||||||
|
- Don't use autoloader when testing for DOMDocument. Hypothetically,
|
||||||
|
this could cause your install to start using DirectLex if you had
|
||||||
|
previously been monkeypatching in a custom, autoloaded implementation
|
||||||
|
of DOMDocument. Don't do that. Thanks @Izumi-kun (#130)
|
||||||
|
|
||||||
|
4.9.2, released 2017-03-12
|
||||||
|
- Fixes PHP 5.3 compatibility
|
||||||
|
- Fix breakage when decoding decimal entities. Thanks @rybakit (#129)
|
||||||
|
|
||||||
|
4.9.1, released 2017-03-08
|
||||||
|
! %URI.DefaultScheme can now be set to null, in which case
|
||||||
|
all relative paths are removed.
|
||||||
|
! New CSS properties: min-width, max-width, min-height, max-height (#94)
|
||||||
|
! Transparency (rgba) and hsl/hsla supported where color CSS is present.
|
||||||
|
Thanks @fxbt for contributing the patch. (#118)
|
||||||
|
- When idn_to_ascii is defined, we might accept malformed
|
||||||
|
hostnames. Apply validation to the result in such cases.
|
||||||
|
- Close directory when done in Serializer DefinitionCache (#100)
|
||||||
|
- Deleted some asserts to avoid linters from choking (#97)
|
||||||
|
- Rework Serializer cache behavior to avoid chmod'ing if possible (#32)
|
||||||
|
- Embedded semicolons in strings in CSS are now handled correctly!
|
||||||
|
- We accidentally dropped certain Unicode characters if there was
|
||||||
|
one or more invalid characters. This has been fixed, thanks
|
||||||
|
to mpyw <ryosuke_i_628@yahoo.co.jp>
|
||||||
|
- Fix for "Don't truncate upon encountering </div> when using DOMLex"
|
||||||
|
caused a regression with HTML 4.01 Strict parsing with libxml 2.9.1
|
||||||
|
(and maybe later versions, but known OK with libxml 2.9.4). The
|
||||||
|
fix is to go about handling truncation a bit more cleverly so that
|
||||||
|
we can wrap with divs (sidestepping the bug) but slurping out the
|
||||||
|
rest of the text in case it ran off the end. (#78)
|
||||||
|
- Fix PREG_BACKTRACK_LIMIT_ERROR in HTMLPurifier_Filter_ExtractStyle.
|
||||||
|
Thanks @breathbath for contributing the report and fix (#120)
|
||||||
|
- Fix entity decoding algorithm to be more conservative about
|
||||||
|
decoding entities that are missing trailing semicolon.
|
||||||
|
To get old behavior, set %Core.LegacyEntityDecoder to true.
|
||||||
|
(#119)
|
||||||
|
- Workaround libxml bug when HTML tags are embedded inside
|
||||||
|
script tags. To disable workaround set %Core.AggressivelyRemoveScript
|
||||||
|
to false. (#83)
|
||||||
|
# By default, when a link has a target attribute associated
|
||||||
|
with it, we now also add rel="noopener" in order to
|
||||||
|
prevent the new window from being able to overwrite
|
||||||
|
the original frame. To disable this protection,
|
||||||
|
set %HTML.TargetNoopener to FALSE.
|
||||||
|
|
||||||
|
4.9.0 was cut on Git but never properly released; when we did the
|
||||||
|
real release we decided to skip this version number.
|
||||||
|
|
||||||
4.8.0, released 2016-07-16
|
4.8.0, released 2016-07-16
|
||||||
# By default, when a link has a target attribute associated
|
# By default, when a link has a target attribute associated
|
||||||
with it, we now also add rel="noreferrer" in order to
|
with it, we now also add rel="noreferrer" in order to
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
HTML Purifier
|
HTML Purifier [](http://travis-ci.org/ezyang/htmlpurifier)
|
||||||
=============
|
=============
|
||||||
|
|
||||||
HTML Purifier is an HTML filtering solution that uses a unique combination
|
HTML Purifier is an HTML filtering solution that uses a unique combination
|
||||||
of robust whitelists and agressive parsing to ensure that not only are
|
of robust whitelists and aggressive parsing to ensure that not only are
|
||||||
XSS attacks thwarted, but the resulting HTML is standards compliant.
|
XSS attacks thwarted, but the resulting HTML is standards compliant.
|
||||||
|
|
||||||
HTML Purifier is oriented towards richly formatted documents from
|
HTML Purifier is oriented towards richly formatted documents from
|
||||||
@@ -26,4 +26,4 @@ Package available on [Composer](https://packagist.org/packages/ezyang/htmlpurifi
|
|||||||
|
|
||||||
If you're using Composer to manage dependencies, you can use
|
If you're using Composer to manage dependencies, you can use
|
||||||
|
|
||||||
$ composer require "ezyang/htmlpurifier": "dev-master"
|
$ composer require ezyang/htmlpurifier
|
||||||
|
16
WHATSNEW
16
WHATSNEW
@@ -1,9 +1,7 @@
|
|||||||
HTML Purifier 4.8.0 is a bugfix release, collecting a year
|
HTML Purifier 4.11.x is a maintenance release, collecting a year
|
||||||
of accumulated bug fixes. In particular, we fixed some minor
|
and a half of accumulated bug fixes. Most notable fixes are
|
||||||
bugs and now declare full PHP 7 compatibility. The primary
|
compatibility with PHP 7.3, and case-sensitive matching for
|
||||||
backwards-incompatible change is that HTML Purifier will now
|
the SafeScripting whitelist. There are a number small feature
|
||||||
add rel="noreferrer" to all links with target attributes
|
enhancements, including an expanded supported color list,
|
||||||
(you can disable this with %HTML.TargetNoReferrer.) Other
|
initial and inherit support for {min-,max-,}{width,height}
|
||||||
changes: new configuration options %CSS.AllowDuplicates and
|
and multidimensional array support for purifyArray.
|
||||||
%Attr.ID.HTML5; border-radius is partially supported when
|
|
||||||
%CSS.AllowProprietary, and tel URIs are supported by default.
|
|
||||||
|
@@ -1 +1,7 @@
|
|||||||
Deny from all
|
<IfModule mod_authz_core.c>
|
||||||
|
Require all denied
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_authz_core.c>
|
||||||
|
Deny from all
|
||||||
|
</ifModule>
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"keywords": ["html"],
|
"keywords": ["html"],
|
||||||
"homepage": "http://htmlpurifier.org/",
|
"homepage": "http://htmlpurifier.org/",
|
||||||
"license": "LGPL",
|
"license": "LGPL-2.1-or-later",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Edward Z. Yang",
|
"name": "Edward Z. Yang",
|
||||||
@@ -15,6 +15,9 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.2"
|
"php": ">=5.2"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": { "HTMLPurifier": "library/" },
|
"psr-0": { "HTMLPurifier": "library/" },
|
||||||
"files": ["library/HTMLPurifier.composer.php"]
|
"files": ["library/HTMLPurifier.composer.php"]
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
</file>
|
</file>
|
||||||
<file name="HTMLPurifier/Lexer.php">
|
<file name="HTMLPurifier/Lexer.php">
|
||||||
<line>85</line>
|
<line>85</line>
|
||||||
<line>315</line>
|
<line>326</line>
|
||||||
</file>
|
</file>
|
||||||
<file name="HTMLPurifier/Lexer/DirectLex.php">
|
<file name="HTMLPurifier/Lexer/DirectLex.php">
|
||||||
<line>67</line>
|
<line>67</line>
|
||||||
@@ -19,37 +19,37 @@
|
|||||||
</directive>
|
</directive>
|
||||||
<directive id="CSS.MaxImgLength">
|
<directive id="CSS.MaxImgLength">
|
||||||
<file name="HTMLPurifier/CSSDefinition.php">
|
<file name="HTMLPurifier/CSSDefinition.php">
|
||||||
<line>226</line>
|
<line>240</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="CSS.Proprietary">
|
<directive id="CSS.Proprietary">
|
||||||
<file name="HTMLPurifier/CSSDefinition.php">
|
<file name="HTMLPurifier/CSSDefinition.php">
|
||||||
<line>319</line>
|
<line>365</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="CSS.AllowTricky">
|
<directive id="CSS.AllowTricky">
|
||||||
<file name="HTMLPurifier/CSSDefinition.php">
|
<file name="HTMLPurifier/CSSDefinition.php">
|
||||||
<line>323</line>
|
<line>369</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="CSS.Trusted">
|
<directive id="CSS.Trusted">
|
||||||
<file name="HTMLPurifier/CSSDefinition.php">
|
<file name="HTMLPurifier/CSSDefinition.php">
|
||||||
<line>327</line>
|
<line>373</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="CSS.AllowImportant">
|
<directive id="CSS.AllowImportant">
|
||||||
<file name="HTMLPurifier/CSSDefinition.php">
|
<file name="HTMLPurifier/CSSDefinition.php">
|
||||||
<line>331</line>
|
<line>377</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="CSS.AllowedProperties">
|
<directive id="CSS.AllowedProperties">
|
||||||
<file name="HTMLPurifier/CSSDefinition.php">
|
<file name="HTMLPurifier/CSSDefinition.php">
|
||||||
<line>460</line>
|
<line>506</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="CSS.ForbiddenProperties">
|
<directive id="CSS.ForbiddenProperties">
|
||||||
<file name="HTMLPurifier/CSSDefinition.php">
|
<file name="HTMLPurifier/CSSDefinition.php">
|
||||||
<line>476</line>
|
<line>522</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Cache.DefinitionImpl">
|
<directive id="Cache.DefinitionImpl">
|
||||||
@@ -79,19 +79,19 @@
|
|||||||
</directive>
|
</directive>
|
||||||
<directive id="Core.Encoding">
|
<directive id="Core.Encoding">
|
||||||
<file name="HTMLPurifier/Encoder.php">
|
<file name="HTMLPurifier/Encoder.php">
|
||||||
<line>374</line>
|
<line>380</line>
|
||||||
<line>422</line>
|
<line>428</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Test.ForceNoIconv">
|
<directive id="Test.ForceNoIconv">
|
||||||
<file name="HTMLPurifier/Encoder.php">
|
<file name="HTMLPurifier/Encoder.php">
|
||||||
<line>382</line>
|
<line>388</line>
|
||||||
<line>433</line>
|
<line>439</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Core.EscapeNonASCIICharacters">
|
<directive id="Core.EscapeNonASCIICharacters">
|
||||||
<file name="HTMLPurifier/Encoder.php">
|
<file name="HTMLPurifier/Encoder.php">
|
||||||
<line>423</line>
|
<line>429</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Output.CommentScriptContents">
|
<directive id="Output.CommentScriptContents">
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
<line>122</line>
|
<line>122</line>
|
||||||
</file>
|
</file>
|
||||||
<file name="HTMLPurifier/Lexer.php">
|
<file name="HTMLPurifier/Lexer.php">
|
||||||
<line>297</line>
|
<line>308</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Output.Newline">
|
<directive id="Output.Newline">
|
||||||
@@ -172,7 +172,8 @@
|
|||||||
<line>234</line>
|
<line>234</line>
|
||||||
</file>
|
</file>
|
||||||
<file name="HTMLPurifier/Lexer.php">
|
<file name="HTMLPurifier/Lexer.php">
|
||||||
<line>302</line>
|
<line>313</line>
|
||||||
|
<line>353</line>
|
||||||
</file>
|
</file>
|
||||||
<file name="HTMLPurifier/HTMLModule/Image.php">
|
<file name="HTMLPurifier/HTMLModule/Image.php">
|
||||||
<line>37</line>
|
<line>37</line>
|
||||||
@@ -232,6 +233,11 @@
|
|||||||
<line>276</line>
|
<line>276</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
|
<directive id="HTML.TargetNoopener">
|
||||||
|
<file name="HTMLPurifier/HTMLModuleManager.php">
|
||||||
|
<line>279</line>
|
||||||
|
</file>
|
||||||
|
</directive>
|
||||||
<directive id="Attr.IDBlacklist">
|
<directive id="Attr.IDBlacklist">
|
||||||
<file name="HTMLPurifier/IDAccumulator.php">
|
<file name="HTMLPurifier/IDAccumulator.php">
|
||||||
<line>27</line>
|
<line>27</line>
|
||||||
@@ -255,14 +261,41 @@
|
|||||||
<line>62</line>
|
<line>62</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
|
<directive id="Core.LegacyEntityDecoder">
|
||||||
|
<file name="HTMLPurifier/Lexer.php">
|
||||||
|
<line>215</line>
|
||||||
|
<line>337</line>
|
||||||
|
</file>
|
||||||
|
</directive>
|
||||||
<directive id="Core.ConvertDocumentToFragment">
|
<directive id="Core.ConvertDocumentToFragment">
|
||||||
<file name="HTMLPurifier/Lexer.php">
|
<file name="HTMLPurifier/Lexer.php">
|
||||||
<line>313</line>
|
<line>324</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Core.RemoveProcessingInstructions">
|
<directive id="Core.RemoveProcessingInstructions">
|
||||||
<file name="HTMLPurifier/Lexer.php">
|
<file name="HTMLPurifier/Lexer.php">
|
||||||
<line>334</line>
|
<line>347</line>
|
||||||
|
</file>
|
||||||
|
</directive>
|
||||||
|
<directive id="Core.HiddenElements">
|
||||||
|
<file name="HTMLPurifier/Lexer.php">
|
||||||
|
<line>351</line>
|
||||||
|
</file>
|
||||||
|
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
|
||||||
|
<line>36</line>
|
||||||
|
</file>
|
||||||
|
</directive>
|
||||||
|
<directive id="Core.AggressivelyRemoveScript">
|
||||||
|
<file name="HTMLPurifier/Lexer.php">
|
||||||
|
<line>352</line>
|
||||||
|
</file>
|
||||||
|
</directive>
|
||||||
|
<directive id="Core.RemoveScriptContents">
|
||||||
|
<file name="HTMLPurifier/Lexer.php">
|
||||||
|
<line>353</line>
|
||||||
|
</file>
|
||||||
|
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
|
||||||
|
<line>35</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="URI.">
|
<directive id="URI.">
|
||||||
@@ -313,7 +346,7 @@
|
|||||||
</directive>
|
</directive>
|
||||||
<directive id="Core.ColorKeywords">
|
<directive id="Core.ColorKeywords">
|
||||||
<file name="HTMLPurifier/AttrDef/CSS/Color.php">
|
<file name="HTMLPurifier/AttrDef/CSS/Color.php">
|
||||||
<line>19</line>
|
<line>29</line>
|
||||||
</file>
|
</file>
|
||||||
<file name="HTMLPurifier/AttrDef/HTML/Color.php">
|
<file name="HTMLPurifier/AttrDef/HTML/Color.php">
|
||||||
<line>19</line>
|
<line>19</line>
|
||||||
@@ -377,7 +410,7 @@
|
|||||||
</directive>
|
</directive>
|
||||||
<directive id="Core.EnableIDNA">
|
<directive id="Core.EnableIDNA">
|
||||||
<file name="HTMLPurifier/AttrDef/URI/Host.php">
|
<file name="HTMLPurifier/AttrDef/URI/Host.php">
|
||||||
<line>105</line>
|
<line>109</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Attr.DefaultTextDir">
|
<directive id="Attr.DefaultTextDir">
|
||||||
@@ -423,13 +456,13 @@
|
|||||||
</directive>
|
</directive>
|
||||||
<directive id="Cache.SerializerPath">
|
<directive id="Cache.SerializerPath">
|
||||||
<file name="HTMLPurifier/DefinitionCache/Serializer.php">
|
<file name="HTMLPurifier/DefinitionCache/Serializer.php">
|
||||||
<line>183</line>
|
<line>185</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Cache.SerializerPermissions">
|
<directive id="Cache.SerializerPermissions">
|
||||||
<file name="HTMLPurifier/DefinitionCache/Serializer.php">
|
<file name="HTMLPurifier/DefinitionCache/Serializer.php">
|
||||||
<line>200</line>
|
<line>202</line>
|
||||||
<line>219</line>
|
<line>218</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Filter.ExtractStyleBlocks.TidyImpl">
|
<directive id="Filter.ExtractStyleBlocks.TidyImpl">
|
||||||
@@ -439,12 +472,12 @@
|
|||||||
</directive>
|
</directive>
|
||||||
<directive id="Filter.ExtractStyleBlocks.Scope">
|
<directive id="Filter.ExtractStyleBlocks.Scope">
|
||||||
<file name="HTMLPurifier/Filter/ExtractStyleBlocks.php">
|
<file name="HTMLPurifier/Filter/ExtractStyleBlocks.php">
|
||||||
<line>122</line>
|
<line>125</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Filter.ExtractStyleBlocks.Escaping">
|
<directive id="Filter.ExtractStyleBlocks.Escaping">
|
||||||
<file name="HTMLPurifier/Filter/ExtractStyleBlocks.php">
|
<file name="HTMLPurifier/Filter/ExtractStyleBlocks.php">
|
||||||
<line>327</line>
|
<line>330</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="HTML.SafeIframe">
|
<directive id="HTML.SafeIframe">
|
||||||
@@ -506,6 +539,11 @@
|
|||||||
<line>54</line>
|
<line>54</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
|
<directive id="Core.AllowParseManyTags">
|
||||||
|
<file name="HTMLPurifier/Lexer/DOMLex.php">
|
||||||
|
<line>72</line>
|
||||||
|
</file>
|
||||||
|
</directive>
|
||||||
<directive id="Core.DirectLexLineNumberSyncInterval">
|
<directive id="Core.DirectLexLineNumberSyncInterval">
|
||||||
<file name="HTMLPurifier/Lexer/DirectLex.php">
|
<file name="HTMLPurifier/Lexer/DirectLex.php">
|
||||||
<line>84</line>
|
<line>84</line>
|
||||||
@@ -534,16 +572,6 @@
|
|||||||
<line>32</line>
|
<line>32</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Core.RemoveScriptContents">
|
|
||||||
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
|
|
||||||
<line>35</line>
|
|
||||||
</file>
|
|
||||||
</directive>
|
|
||||||
<directive id="Core.HiddenElements">
|
|
||||||
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
|
|
||||||
<line>36</line>
|
|
||||||
</file>
|
|
||||||
</directive>
|
|
||||||
<directive id="URI.HostBlacklist">
|
<directive id="URI.HostBlacklist">
|
||||||
<file name="HTMLPurifier/URIFilter/HostBlacklist.php">
|
<file name="HTMLPurifier/URIFilter/HostBlacklist.php">
|
||||||
<line>25</line>
|
<line>25</line>
|
||||||
|
@@ -75,6 +75,7 @@ Core is the potpourri of directives, mostly regarding some minor behavioral
|
|||||||
tweaks for HTML handling abilities.
|
tweaks for HTML handling abilities.
|
||||||
|
|
||||||
AggressivelyFixLt
|
AggressivelyFixLt
|
||||||
|
AllowParseManyTags
|
||||||
ConvertDocumentToFragment
|
ConvertDocumentToFragment
|
||||||
DirectLexLineNumberSyncInterval
|
DirectLexLineNumberSyncInterval
|
||||||
LexerImpl
|
LexerImpl
|
||||||
|
@@ -228,7 +228,7 @@ Test.Example</pre>
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>mixed</td>
|
<td>mixed</td>
|
||||||
<td>new stdclass</td>
|
<td>new stdClass</td>
|
||||||
<td>Any PHP variable is fine</td>
|
<td>Any PHP variable is fine</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
15
extras/HTMLPurifierExtras.autoload-legacy.php
Normal file
15
extras/HTMLPurifierExtras.autoload-legacy.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Legacy autoloader for systems lacking spl_autoload_register
|
||||||
|
*
|
||||||
|
* Must be separate to prevent deprecation warning on PHP 7.2
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __autoload($class)
|
||||||
|
{
|
||||||
|
return HTMLPurifierExtras::autoload($class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: et sw=4 sts=4
|
@@ -17,10 +17,7 @@ if (function_exists('spl_autoload_register')) {
|
|||||||
spl_autoload_register('__autoload');
|
spl_autoload_register('__autoload');
|
||||||
}
|
}
|
||||||
} elseif (!function_exists('__autoload')) {
|
} elseif (!function_exists('__autoload')) {
|
||||||
function __autoload($class)
|
require dirname(__FILE__) . '/HTMLPurifierExtras.autoload-legacy.php';
|
||||||
{
|
|
||||||
return HTMLPurifierExtras::autoload($class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
15
library/HTMLPurifier.autoload-legacy.php
Normal file
15
library/HTMLPurifier.autoload-legacy.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Legacy autoloader for systems lacking spl_autoload_register
|
||||||
|
*
|
||||||
|
* Must be separate to prevent deprecation warning on PHP 7.2
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __autoload($class)
|
||||||
|
{
|
||||||
|
return HTMLPurifier_Bootstrap::autoload($class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: et sw=4 sts=4
|
@@ -14,10 +14,7 @@ if (function_exists('spl_autoload_register') && function_exists('spl_autoload_un
|
|||||||
spl_autoload_register('__autoload');
|
spl_autoload_register('__autoload');
|
||||||
}
|
}
|
||||||
} elseif (!function_exists('__autoload')) {
|
} elseif (!function_exists('__autoload')) {
|
||||||
function __autoload($class)
|
require dirname(__FILE__) . '/HTMLPurifier.autoload-legacy.php';
|
||||||
{
|
|
||||||
return HTMLPurifier_Bootstrap::autoload($class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ini_get('zend.ze1_compatibility_mode')) {
|
if (ini_get('zend.ze1_compatibility_mode')) {
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
* primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
|
* primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
|
||||||
* FILE, changes will be overwritten the next time the script is run.
|
* FILE, changes will be overwritten the next time the script is run.
|
||||||
*
|
*
|
||||||
* @version 4.8.0
|
* @version 4.11.0
|
||||||
*
|
*
|
||||||
* @warning
|
* @warning
|
||||||
* You must *not* include any other HTML Purifier files before this file,
|
* You must *not* include any other HTML Purifier files before this file,
|
||||||
@@ -137,6 +137,7 @@ require 'HTMLPurifier/AttrTransform/SafeObject.php';
|
|||||||
require 'HTMLPurifier/AttrTransform/SafeParam.php';
|
require 'HTMLPurifier/AttrTransform/SafeParam.php';
|
||||||
require 'HTMLPurifier/AttrTransform/ScriptRequired.php';
|
require 'HTMLPurifier/AttrTransform/ScriptRequired.php';
|
||||||
require 'HTMLPurifier/AttrTransform/TargetBlank.php';
|
require 'HTMLPurifier/AttrTransform/TargetBlank.php';
|
||||||
|
require 'HTMLPurifier/AttrTransform/TargetNoopener.php';
|
||||||
require 'HTMLPurifier/AttrTransform/TargetNoreferrer.php';
|
require 'HTMLPurifier/AttrTransform/TargetNoreferrer.php';
|
||||||
require 'HTMLPurifier/AttrTransform/Textarea.php';
|
require 'HTMLPurifier/AttrTransform/Textarea.php';
|
||||||
require 'HTMLPurifier/ChildDef/Chameleon.php';
|
require 'HTMLPurifier/ChildDef/Chameleon.php';
|
||||||
@@ -176,6 +177,7 @@ require 'HTMLPurifier/HTMLModule/StyleAttribute.php';
|
|||||||
require 'HTMLPurifier/HTMLModule/Tables.php';
|
require 'HTMLPurifier/HTMLModule/Tables.php';
|
||||||
require 'HTMLPurifier/HTMLModule/Target.php';
|
require 'HTMLPurifier/HTMLModule/Target.php';
|
||||||
require 'HTMLPurifier/HTMLModule/TargetBlank.php';
|
require 'HTMLPurifier/HTMLModule/TargetBlank.php';
|
||||||
|
require 'HTMLPurifier/HTMLModule/TargetNoopener.php';
|
||||||
require 'HTMLPurifier/HTMLModule/TargetNoreferrer.php';
|
require 'HTMLPurifier/HTMLModule/TargetNoreferrer.php';
|
||||||
require 'HTMLPurifier/HTMLModule/Text.php';
|
require 'HTMLPurifier/HTMLModule/Text.php';
|
||||||
require 'HTMLPurifier/HTMLModule/Tidy.php';
|
require 'HTMLPurifier/HTMLModule/Tidy.php';
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
HTML Purifier 4.8.0 - Standards Compliant HTML Filtering
|
HTML Purifier 4.11.0 - Standards Compliant HTML Filtering
|
||||||
Copyright (C) 2006-2008 Edward Z. Yang
|
Copyright (C) 2006-2008 Edward Z. Yang
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
@@ -58,12 +58,12 @@ class HTMLPurifier
|
|||||||
* Version of HTML Purifier.
|
* Version of HTML Purifier.
|
||||||
* @type string
|
* @type string
|
||||||
*/
|
*/
|
||||||
public $version = '4.8.0';
|
public $version = '4.11.0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constant with version of HTML Purifier.
|
* Constant with version of HTML Purifier.
|
||||||
*/
|
*/
|
||||||
const VERSION = '4.8.0';
|
const VERSION = '4.11.0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global configuration object.
|
* Global configuration object.
|
||||||
@@ -240,12 +240,16 @@ class HTMLPurifier
|
|||||||
public function purifyArray($array_of_html, $config = null)
|
public function purifyArray($array_of_html, $config = null)
|
||||||
{
|
{
|
||||||
$context_array = array();
|
$context_array = array();
|
||||||
foreach ($array_of_html as $key => $html) {
|
foreach($array_of_html as $key=>$value){
|
||||||
$array_of_html[$key] = $this->purify($html, $config);
|
if (is_array($value)) {
|
||||||
|
$array[$key] = $this->purifyArray($value, $config);
|
||||||
|
} else {
|
||||||
|
$array[$key] = $this->purify($value, $config);
|
||||||
|
}
|
||||||
$context_array[$key] = $this->context;
|
$context_array[$key] = $this->context;
|
||||||
}
|
}
|
||||||
$this->context = $context_array;
|
$this->context = $context_array;
|
||||||
return $array_of_html;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -131,6 +131,7 @@ require_once $__dir . '/HTMLPurifier/AttrTransform/SafeObject.php';
|
|||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php';
|
||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php';
|
||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetBlank.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetBlank.php';
|
||||||
|
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetNoopener.php';
|
||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetNoreferrer.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetNoreferrer.php';
|
||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/Textarea.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/Textarea.php';
|
||||||
require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php';
|
require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php';
|
||||||
@@ -170,6 +171,7 @@ require_once $__dir . '/HTMLPurifier/HTMLModule/StyleAttribute.php';
|
|||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tables.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/Tables.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/Target.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/Target.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetBlank.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetBlank.php';
|
||||||
|
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetNoopener.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetNoreferrer.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetNoreferrer.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/Text.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/Text.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy.php';
|
||||||
|
@@ -19,8 +19,8 @@ class HTMLPurifier_Arborize
|
|||||||
if ($token instanceof HTMLPurifier_Token_End) {
|
if ($token instanceof HTMLPurifier_Token_End) {
|
||||||
$token->start = null; // [MUT]
|
$token->start = null; // [MUT]
|
||||||
$r = array_pop($stack);
|
$r = array_pop($stack);
|
||||||
assert($r->name === $token->name);
|
//assert($r->name === $token->name);
|
||||||
assert(empty($token->attr));
|
//assert(empty($token->attr));
|
||||||
$r->endCol = $token->col;
|
$r->endCol = $token->col;
|
||||||
$r->endLine = $token->line;
|
$r->endLine = $token->line;
|
||||||
$r->endArmor = $token->armor;
|
$r->endArmor = $token->armor;
|
||||||
@@ -32,7 +32,7 @@ class HTMLPurifier_Arborize
|
|||||||
$stack[] = $node;
|
$stack[] = $node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(count($stack) == 1);
|
//assert(count($stack) == 1);
|
||||||
return $stack[0];
|
return $stack[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -86,7 +86,13 @@ abstract class HTMLPurifier_AttrDef
|
|||||||
*/
|
*/
|
||||||
protected function mungeRgb($string)
|
protected function mungeRgb($string)
|
||||||
{
|
{
|
||||||
return preg_replace('/rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)/', 'rgb(\1,\2,\3)', $string);
|
$p = '\s*(\d+(\.\d+)?([%]?))\s*';
|
||||||
|
|
||||||
|
if (preg_match('/(rgba|hsla)\(/', $string)) {
|
||||||
|
return preg_replace('/(rgba|hsla)\('.$p.','.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8,\11)', $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return preg_replace('/(rgb|hsl)\('.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8)', $string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -27,13 +27,38 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
|
|||||||
$definition = $config->getCSSDefinition();
|
$definition = $config->getCSSDefinition();
|
||||||
$allow_duplicates = $config->get("CSS.AllowDuplicates");
|
$allow_duplicates = $config->get("CSS.AllowDuplicates");
|
||||||
|
|
||||||
// we're going to break the spec and explode by semicolons.
|
|
||||||
// This is because semicolon rarely appears in escaped form
|
|
||||||
// Doing this is generally flaky but fast
|
|
||||||
// IT MIGHT APPEAR IN URIs, see HTMLPurifier_AttrDef_CSSURI
|
|
||||||
// for details
|
|
||||||
|
|
||||||
$declarations = explode(';', $css);
|
// According to the CSS2.1 spec, the places where a
|
||||||
|
// non-delimiting semicolon can appear are in strings
|
||||||
|
// escape sequences. So here is some dumb hack to
|
||||||
|
// handle quotes.
|
||||||
|
$len = strlen($css);
|
||||||
|
$accum = "";
|
||||||
|
$declarations = array();
|
||||||
|
$quoted = false;
|
||||||
|
for ($i = 0; $i < $len; $i++) {
|
||||||
|
$c = strcspn($css, ";'\"", $i);
|
||||||
|
$accum .= substr($css, $i, $c);
|
||||||
|
$i += $c;
|
||||||
|
if ($i == $len) break;
|
||||||
|
$d = $css[$i];
|
||||||
|
if ($quoted) {
|
||||||
|
$accum .= $d;
|
||||||
|
if ($d == $quoted) {
|
||||||
|
$quoted = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($d == ";") {
|
||||||
|
$declarations[] = $accum;
|
||||||
|
$accum = "";
|
||||||
|
} else {
|
||||||
|
$accum .= $d;
|
||||||
|
$quoted = $d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($accum != "") $declarations[] = $accum;
|
||||||
|
|
||||||
$propvalues = array();
|
$propvalues = array();
|
||||||
$new_declarations = '';
|
$new_declarations = '';
|
||||||
|
|
||||||
|
@@ -6,6 +6,16 @@
|
|||||||
class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
|
class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type HTMLPurifier_AttrDef_CSS_AlphaValue
|
||||||
|
*/
|
||||||
|
protected $alpha;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->alpha = new HTMLPurifier_AttrDef_CSS_AlphaValue();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $color
|
* @param string $color
|
||||||
* @param HTMLPurifier_Config $config
|
* @param HTMLPurifier_Config $config
|
||||||
@@ -29,59 +39,104 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
|
|||||||
return $colors[$lower];
|
return $colors[$lower];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strpos($color, 'rgb(') !== false) {
|
if (preg_match('#(rgb|rgba|hsl|hsla)\(#', $color, $matches) === 1) {
|
||||||
// rgb literal handling
|
|
||||||
$length = strlen($color);
|
$length = strlen($color);
|
||||||
if (strpos($color, ')') !== $length - 1) {
|
if (strpos($color, ')') !== $length - 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$triad = substr($color, 4, $length - 4 - 1);
|
|
||||||
$parts = explode(',', $triad);
|
// get used function : rgb, rgba, hsl or hsla
|
||||||
if (count($parts) !== 3) {
|
$function = $matches[1];
|
||||||
|
|
||||||
|
$parameters_size = 3;
|
||||||
|
$alpha_channel = false;
|
||||||
|
if (substr($function, -1) === 'a') {
|
||||||
|
$parameters_size = 4;
|
||||||
|
$alpha_channel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allowed types for values :
|
||||||
|
* parameter_position => [type => max_value]
|
||||||
|
*/
|
||||||
|
$allowed_types = array(
|
||||||
|
1 => array('percentage' => 100, 'integer' => 255),
|
||||||
|
2 => array('percentage' => 100, 'integer' => 255),
|
||||||
|
3 => array('percentage' => 100, 'integer' => 255),
|
||||||
|
);
|
||||||
|
$allow_different_types = false;
|
||||||
|
|
||||||
|
if (strpos($function, 'hsl') !== false) {
|
||||||
|
$allowed_types = array(
|
||||||
|
1 => array('integer' => 360),
|
||||||
|
2 => array('percentage' => 100),
|
||||||
|
3 => array('percentage' => 100),
|
||||||
|
);
|
||||||
|
$allow_different_types = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$values = trim(str_replace($function, '', $color), ' ()');
|
||||||
|
|
||||||
|
$parts = explode(',', $values);
|
||||||
|
if (count($parts) !== $parameters_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$type = false; // to ensure that they're all the same type
|
|
||||||
|
$type = false;
|
||||||
$new_parts = array();
|
$new_parts = array();
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
foreach ($parts as $part) {
|
foreach ($parts as $part) {
|
||||||
|
$i++;
|
||||||
$part = trim($part);
|
$part = trim($part);
|
||||||
|
|
||||||
if ($part === '') {
|
if ($part === '') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$length = strlen($part);
|
|
||||||
if ($part[$length - 1] === '%') {
|
// different check for alpha channel
|
||||||
// handle percents
|
if ($alpha_channel === true && $i === count($parts)) {
|
||||||
if (!$type) {
|
$result = $this->alpha->validate($part, $config, $context);
|
||||||
$type = 'percentage';
|
|
||||||
} elseif ($type !== 'percentage') {
|
if ($result === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$num = (float)substr($part, 0, $length - 1);
|
|
||||||
if ($num < 0) {
|
$new_parts[] = (string)$result;
|
||||||
$num = 0;
|
continue;
|
||||||
}
|
}
|
||||||
if ($num > 100) {
|
|
||||||
$num = 100;
|
if (substr($part, -1) === '%') {
|
||||||
}
|
$current_type = 'percentage';
|
||||||
$new_parts[] = "$num%";
|
|
||||||
} else {
|
} else {
|
||||||
// handle integers
|
$current_type = 'integer';
|
||||||
if (!$type) {
|
}
|
||||||
$type = 'integer';
|
|
||||||
} elseif ($type !== 'integer') {
|
if (!array_key_exists($current_type, $allowed_types[$i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$num = (int)$part;
|
|
||||||
if ($num < 0) {
|
if (!$type) {
|
||||||
$num = 0;
|
$type = $current_type;
|
||||||
}
|
}
|
||||||
if ($num > 255) {
|
|
||||||
$num = 255;
|
if ($allow_different_types === false && $type != $current_type) {
|
||||||
}
|
return false;
|
||||||
$new_parts[] = (string)$num;
|
}
|
||||||
|
|
||||||
|
$max_value = $allowed_types[$i][$current_type];
|
||||||
|
|
||||||
|
if ($current_type == 'integer') {
|
||||||
|
// Return value between range 0 -> $max_value
|
||||||
|
$new_parts[] = (int)max(min($part, $max_value), 0);
|
||||||
|
} elseif ($current_type == 'percentage') {
|
||||||
|
$new_parts[] = (float)max(min(rtrim($part, '%'), $max_value), 0) . '%';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$new_triad = implode(',', $new_parts);
|
|
||||||
$color = "rgb($new_triad)";
|
$new_values = implode(',', $new_parts);
|
||||||
|
|
||||||
|
$color = $function . '(' . $new_values . ')';
|
||||||
} else {
|
} else {
|
||||||
// hexadecimal handling
|
// hexadecimal handling
|
||||||
if ($color[0] === '#') {
|
if ($color[0] === '#') {
|
||||||
@@ -100,6 +155,7 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
|
|||||||
}
|
}
|
||||||
return $color;
|
return $color;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
@@ -97,7 +97,11 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
|
|||||||
|
|
||||||
// PHP 5.3 and later support this functionality natively
|
// PHP 5.3 and later support this functionality natively
|
||||||
if (function_exists('idn_to_ascii')) {
|
if (function_exists('idn_to_ascii')) {
|
||||||
return idn_to_ascii($string);
|
if (defined('IDNA_NONTRANSITIONAL_TO_ASCII') && defined('INTL_IDNA_VARIANT_UTS46')) {
|
||||||
|
$string = idn_to_ascii($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
|
||||||
|
} else {
|
||||||
|
$string = idn_to_ascii($string);
|
||||||
|
}
|
||||||
|
|
||||||
// If we have Net_IDNA2 support, we can support IRIs by
|
// If we have Net_IDNA2 support, we can support IRIs by
|
||||||
// punycoding them. (This is the most portable thing to do,
|
// punycoding them. (This is the most portable thing to do,
|
||||||
@@ -123,13 +127,14 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$string = implode('.', $new_parts);
|
$string = implode('.', $new_parts);
|
||||||
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// XXX error reporting
|
// XXX error reporting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Try again
|
||||||
|
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
37
library/HTMLPurifier/AttrTransform/TargetNoopener.php
Normal file
37
library/HTMLPurifier/AttrTransform/TargetNoopener.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// must be called POST validation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds rel="noopener" to any links which target a different window
|
||||||
|
* than the current one. This is used to prevent malicious websites
|
||||||
|
* from silently replacing the original window, which could be used
|
||||||
|
* to do phishing.
|
||||||
|
* This transform is controlled by %HTML.TargetNoopener.
|
||||||
|
*/
|
||||||
|
class HTMLPurifier_AttrTransform_TargetNoopener extends HTMLPurifier_AttrTransform
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param array $attr
|
||||||
|
* @param HTMLPurifier_Config $config
|
||||||
|
* @param HTMLPurifier_Context $context
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function transform($attr, $config, $context)
|
||||||
|
{
|
||||||
|
if (isset($attr['rel'])) {
|
||||||
|
$rels = explode(' ', $attr['rel']);
|
||||||
|
} else {
|
||||||
|
$rels = array();
|
||||||
|
}
|
||||||
|
if (isset($attr['target']) && !in_array('noopener', $rels)) {
|
||||||
|
$rels[] = 'noopener';
|
||||||
|
}
|
||||||
|
if (!empty($rels) || isset($attr['rel'])) {
|
||||||
|
$attr['rel'] = implode(' ', $rels);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $attr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -220,7 +220,21 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
|
|||||||
array(
|
array(
|
||||||
new HTMLPurifier_AttrDef_CSS_Length('0'),
|
new HTMLPurifier_AttrDef_CSS_Length('0'),
|
||||||
new HTMLPurifier_AttrDef_CSS_Percentage(true),
|
new HTMLPurifier_AttrDef_CSS_Percentage(true),
|
||||||
new HTMLPurifier_AttrDef_Enum(array('auto'))
|
new HTMLPurifier_AttrDef_Enum(array('auto', 'initial', 'inherit'))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite(
|
||||||
|
array(
|
||||||
|
new HTMLPurifier_AttrDef_CSS_Length('0'),
|
||||||
|
new HTMLPurifier_AttrDef_CSS_Percentage(true),
|
||||||
|
new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit'))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite(
|
||||||
|
array(
|
||||||
|
new HTMLPurifier_AttrDef_CSS_Length('0'),
|
||||||
|
new HTMLPurifier_AttrDef_CSS_Percentage(true),
|
||||||
|
new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit'))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$max = $config->get('CSS.MaxImgLength');
|
$max = $config->get('CSS.MaxImgLength');
|
||||||
@@ -241,6 +255,38 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
|
|||||||
// For everyone else:
|
// For everyone else:
|
||||||
$trusted_wh
|
$trusted_wh
|
||||||
);
|
);
|
||||||
|
$this->info['min-width'] =
|
||||||
|
$this->info['min-height'] =
|
||||||
|
$max === null ?
|
||||||
|
$trusted_min_wh :
|
||||||
|
new HTMLPurifier_AttrDef_Switch(
|
||||||
|
'img',
|
||||||
|
// For img tags:
|
||||||
|
new HTMLPurifier_AttrDef_CSS_Composite(
|
||||||
|
array(
|
||||||
|
new HTMLPurifier_AttrDef_CSS_Length('0', $max),
|
||||||
|
new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit'))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// For everyone else:
|
||||||
|
$trusted_min_wh
|
||||||
|
);
|
||||||
|
$this->info['max-width'] =
|
||||||
|
$this->info['max-height'] =
|
||||||
|
$max === null ?
|
||||||
|
$trusted_max_wh :
|
||||||
|
new HTMLPurifier_AttrDef_Switch(
|
||||||
|
'img',
|
||||||
|
// For img tags:
|
||||||
|
new HTMLPurifier_AttrDef_CSS_Composite(
|
||||||
|
array(
|
||||||
|
new HTMLPurifier_AttrDef_CSS_Length('0', $max),
|
||||||
|
new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit'))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// For everyone else:
|
||||||
|
$trusted_max_wh
|
||||||
|
);
|
||||||
|
|
||||||
$this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();
|
$this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@ class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef
|
|||||||
// a little sanity check to make sure it's not ALL whitespace
|
// a little sanity check to make sure it's not ALL whitespace
|
||||||
$all_whitespace = true;
|
$all_whitespace = true;
|
||||||
|
|
||||||
$current_li = false;
|
$current_li = null;
|
||||||
|
|
||||||
foreach ($children as $node) {
|
foreach ($children as $node) {
|
||||||
if (!empty($node->is_whitespace)) {
|
if (!empty($node->is_whitespace)) {
|
||||||
@@ -71,7 +71,7 @@ class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef
|
|||||||
// to handle non-list elements; non-list elements should
|
// to handle non-list elements; non-list elements should
|
||||||
// not be appended to an existing li; only li created
|
// not be appended to an existing li; only li created
|
||||||
// for non-list. This distinction is not currently made.
|
// for non-list. This distinction is not currently made.
|
||||||
if ($current_li === false) {
|
if ($current_li === null) {
|
||||||
$current_li = new HTMLPurifier_Node_Element('li');
|
$current_li = new HTMLPurifier_Node_Element('li');
|
||||||
$result[] = $current_li;
|
$result[] = $current_li;
|
||||||
}
|
}
|
||||||
|
@@ -203,7 +203,7 @@ class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef
|
|||||||
$current_tr_tbody->children[] = $node;
|
$current_tr_tbody->children[] = $node;
|
||||||
break;
|
break;
|
||||||
case '#PCDATA':
|
case '#PCDATA':
|
||||||
assert($node->is_whitespace);
|
//assert($node->is_whitespace);
|
||||||
if ($current_tr_tbody === null) {
|
if ($current_tr_tbody === null) {
|
||||||
$ret[] = $node;
|
$ret[] = $node;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -21,7 +21,7 @@ class HTMLPurifier_Config
|
|||||||
* HTML Purifier's version
|
* HTML Purifier's version
|
||||||
* @type string
|
* @type string
|
||||||
*/
|
*/
|
||||||
public $version = '4.8.0';
|
public $version = '4.11.0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not to automatically finalize
|
* Whether or not to automatically finalize
|
||||||
@@ -333,7 +333,7 @@ class HTMLPurifier_Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Raw type might be negative when using the fully optimized form
|
// Raw type might be negative when using the fully optimized form
|
||||||
// of stdclass, which indicates allow_null == true
|
// of stdClass, which indicates allow_null == true
|
||||||
$rtype = is_int($def) ? $def : $def->type;
|
$rtype = is_int($def) ? $def : $def->type;
|
||||||
if ($rtype < 0) {
|
if ($rtype < 0) {
|
||||||
$type = -$rtype;
|
$type = -$rtype;
|
||||||
@@ -890,7 +890,7 @@ class HTMLPurifier_Config
|
|||||||
// zip(tail(trace), trace) -- but PHP is not Haskell har har
|
// zip(tail(trace), trace) -- but PHP is not Haskell har har
|
||||||
for ($i = 0, $c = count($trace); $i < $c - 1; $i++) {
|
for ($i = 0, $c = count($trace); $i < $c - 1; $i++) {
|
||||||
// XXX this is not correct on some versions of HTML Purifier
|
// XXX this is not correct on some versions of HTML Purifier
|
||||||
if ($trace[$i + 1]['class'] === 'HTMLPurifier_Config') {
|
if (isset($trace[$i + 1]['class']) && $trace[$i + 1]['class'] === 'HTMLPurifier_Config') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$frame = $trace[$i];
|
$frame = $trace[$i];
|
||||||
|
@@ -24,11 +24,11 @@ class HTMLPurifier_ConfigSchema
|
|||||||
*
|
*
|
||||||
* array(
|
* array(
|
||||||
* 'Namespace' => array(
|
* 'Namespace' => array(
|
||||||
* 'Directive' => new stdclass(),
|
* 'Directive' => new stdClass(),
|
||||||
* )
|
* )
|
||||||
* )
|
* )
|
||||||
*
|
*
|
||||||
* The stdclass may have the following properties:
|
* The stdClass may have the following properties:
|
||||||
*
|
*
|
||||||
* - If isAlias isn't set:
|
* - If isAlias isn't set:
|
||||||
* - type: Integer type of directive, see HTMLPurifier_VarParser for definitions
|
* - type: Integer type of directive, see HTMLPurifier_VarParser for definitions
|
||||||
@@ -39,8 +39,8 @@ class HTMLPurifier_ConfigSchema
|
|||||||
* - namespace: Namespace this directive aliases to
|
* - namespace: Namespace this directive aliases to
|
||||||
* - name: Directive name this directive aliases to
|
* - name: Directive name this directive aliases to
|
||||||
*
|
*
|
||||||
* In certain degenerate cases, stdclass will actually be an integer. In
|
* In certain degenerate cases, stdClass will actually be an integer. In
|
||||||
* that case, the value is equivalent to an stdclass with the type
|
* that case, the value is equivalent to an stdClass with the type
|
||||||
* property set to the integer. If the integer is negative, type is
|
* property set to the integer. If the integer is negative, type is
|
||||||
* equal to the absolute value of integer, and allow_null is true.
|
* equal to the absolute value of integer, and allow_null is true.
|
||||||
*
|
*
|
||||||
@@ -100,12 +100,12 @@ class HTMLPurifier_ConfigSchema
|
|||||||
* @param string $key Name of directive
|
* @param string $key Name of directive
|
||||||
* @param mixed $default Default value of directive
|
* @param mixed $default Default value of directive
|
||||||
* @param string $type Allowed type of the directive. See
|
* @param string $type Allowed type of the directive. See
|
||||||
* HTMLPurifier_DirectiveDef::$type for allowed values
|
* HTMLPurifier_VarParser::$types for allowed values
|
||||||
* @param bool $allow_null Whether or not to allow null values
|
* @param bool $allow_null Whether or not to allow null values
|
||||||
*/
|
*/
|
||||||
public function add($key, $default, $type, $allow_null)
|
public function add($key, $default, $type, $allow_null)
|
||||||
{
|
{
|
||||||
$obj = new stdclass();
|
$obj = new stdClass();
|
||||||
$obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type];
|
$obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type];
|
||||||
if ($allow_null) {
|
if ($allow_null) {
|
||||||
$obj->allow_null = true;
|
$obj->allow_null = true;
|
||||||
@@ -152,14 +152,14 @@ class HTMLPurifier_ConfigSchema
|
|||||||
*/
|
*/
|
||||||
public function addAlias($key, $new_key)
|
public function addAlias($key, $new_key)
|
||||||
{
|
{
|
||||||
$obj = new stdclass;
|
$obj = new stdClass;
|
||||||
$obj->key = $new_key;
|
$obj->key = $new_key;
|
||||||
$obj->isAlias = true;
|
$obj->isAlias = true;
|
||||||
$this->info[$key] = $obj;
|
$this->info[$key] = $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces any stdclass that only has the type property with type integer.
|
* Replaces any stdClass that only has the type property with type integer.
|
||||||
*/
|
*/
|
||||||
public function postProcess()
|
public function postProcess()
|
||||||
{
|
{
|
||||||
|
Binary file not shown.
@@ -6,7 +6,7 @@ DEFAULT: false
|
|||||||
<p>
|
<p>
|
||||||
When enabled, HTML Purifier will treat any elements that contain only
|
When enabled, HTML Purifier will treat any elements that contain only
|
||||||
non-breaking spaces as well as regular whitespace as empty, and remove
|
non-breaking spaces as well as regular whitespace as empty, and remove
|
||||||
them when %AutoForamt.RemoveEmpty is enabled.
|
them when %AutoFormat.RemoveEmpty is enabled.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
See %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions for a list of elements
|
See %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions for a list of elements
|
||||||
|
@@ -0,0 +1,16 @@
|
|||||||
|
Core.AggressivelyRemoveScript
|
||||||
|
TYPE: bool
|
||||||
|
VERSION: 4.9.0
|
||||||
|
DEFAULT: true
|
||||||
|
--DESCRIPTION--
|
||||||
|
<p>
|
||||||
|
This directive enables aggressive pre-filter removal of
|
||||||
|
script tags. This is not necessary for security,
|
||||||
|
but it can help work around a bug in libxml where embedded
|
||||||
|
HTML elements inside script sections cause the parser to
|
||||||
|
choke. To revert to pre-4.9.0 behavior, set this to false.
|
||||||
|
This directive has no effect if %Core.Trusted is true,
|
||||||
|
%Core.RemoveScriptContents is false, or %Core.HiddenElements
|
||||||
|
does not contain script.
|
||||||
|
</p>
|
||||||
|
--# vim: et sw=4 sts=4
|
@@ -0,0 +1,12 @@
|
|||||||
|
Core.AllowParseManyTags
|
||||||
|
TYPE: bool
|
||||||
|
DEFAULT: false
|
||||||
|
VERSION: 4.10.1
|
||||||
|
--DESCRIPTION--
|
||||||
|
<p>
|
||||||
|
This directive allows parsing of many nested tags.
|
||||||
|
If you set true, relaxes any hardcoded limit from the parser.
|
||||||
|
However, in that case it may cause a Dos attack.
|
||||||
|
Be careful when enabling it.
|
||||||
|
</p>
|
||||||
|
--# vim: et sw=4 sts=4
|
@@ -3,23 +3,154 @@ TYPE: hash
|
|||||||
VERSION: 2.0.0
|
VERSION: 2.0.0
|
||||||
--DEFAULT--
|
--DEFAULT--
|
||||||
array (
|
array (
|
||||||
'maroon' => '#800000',
|
'aliceblue' => '#F0F8FF',
|
||||||
'red' => '#FF0000',
|
'antiquewhite' => '#FAEBD7',
|
||||||
'orange' => '#FFA500',
|
|
||||||
'yellow' => '#FFFF00',
|
|
||||||
'olive' => '#808000',
|
|
||||||
'purple' => '#800080',
|
|
||||||
'fuchsia' => '#FF00FF',
|
|
||||||
'white' => '#FFFFFF',
|
|
||||||
'lime' => '#00FF00',
|
|
||||||
'green' => '#008000',
|
|
||||||
'navy' => '#000080',
|
|
||||||
'blue' => '#0000FF',
|
|
||||||
'aqua' => '#00FFFF',
|
'aqua' => '#00FFFF',
|
||||||
'teal' => '#008080',
|
'aquamarine' => '#7FFFD4',
|
||||||
|
'azure' => '#F0FFFF',
|
||||||
|
'beige' => '#F5F5DC',
|
||||||
|
'bisque' => '#FFE4C4',
|
||||||
'black' => '#000000',
|
'black' => '#000000',
|
||||||
'silver' => '#C0C0C0',
|
'blanchedalmond' => '#FFEBCD',
|
||||||
|
'blue' => '#0000FF',
|
||||||
|
'blueviolet' => '#8A2BE2',
|
||||||
|
'brown' => '#A52A2A',
|
||||||
|
'burlywood' => '#DEB887',
|
||||||
|
'cadetblue' => '#5F9EA0',
|
||||||
|
'chartreuse' => '#7FFF00',
|
||||||
|
'chocolate' => '#D2691E',
|
||||||
|
'coral' => '#FF7F50',
|
||||||
|
'cornflowerblue' => '#6495ED',
|
||||||
|
'cornsilk' => '#FFF8DC',
|
||||||
|
'crimson' => '#DC143C',
|
||||||
|
'cyan' => '#00FFFF',
|
||||||
|
'darkblue' => '#00008B',
|
||||||
|
'darkcyan' => '#008B8B',
|
||||||
|
'darkgoldenrod' => '#B8860B',
|
||||||
|
'darkgray' => '#A9A9A9',
|
||||||
|
'darkgrey' => '#A9A9A9',
|
||||||
|
'darkgreen' => '#006400',
|
||||||
|
'darkkhaki' => '#BDB76B',
|
||||||
|
'darkmagenta' => '#8B008B',
|
||||||
|
'darkolivegreen' => '#556B2F',
|
||||||
|
'darkorange' => '#FF8C00',
|
||||||
|
'darkorchid' => '#9932CC',
|
||||||
|
'darkred' => '#8B0000',
|
||||||
|
'darksalmon' => '#E9967A',
|
||||||
|
'darkseagreen' => '#8FBC8F',
|
||||||
|
'darkslateblue' => '#483D8B',
|
||||||
|
'darkslategray' => '#2F4F4F',
|
||||||
|
'darkslategrey' => '#2F4F4F',
|
||||||
|
'darkturquoise' => '#00CED1',
|
||||||
|
'darkviolet' => '#9400D3',
|
||||||
|
'deeppink' => '#FF1493',
|
||||||
|
'deepskyblue' => '#00BFFF',
|
||||||
|
'dimgray' => '#696969',
|
||||||
|
'dimgrey' => '#696969',
|
||||||
|
'dodgerblue' => '#1E90FF',
|
||||||
|
'firebrick' => '#B22222',
|
||||||
|
'floralwhite' => '#FFFAF0',
|
||||||
|
'forestgreen' => '#228B22',
|
||||||
|
'fuchsia' => '#FF00FF',
|
||||||
|
'gainsboro' => '#DCDCDC',
|
||||||
|
'ghostwhite' => '#F8F8FF',
|
||||||
|
'gold' => '#FFD700',
|
||||||
|
'goldenrod' => '#DAA520',
|
||||||
'gray' => '#808080',
|
'gray' => '#808080',
|
||||||
|
'grey' => '#808080',
|
||||||
|
'green' => '#008000',
|
||||||
|
'greenyellow' => '#ADFF2F',
|
||||||
|
'honeydew' => '#F0FFF0',
|
||||||
|
'hotpink' => '#FF69B4',
|
||||||
|
'indianred' => '#CD5C5C',
|
||||||
|
'indigo' => '#4B0082',
|
||||||
|
'ivory' => '#FFFFF0',
|
||||||
|
'khaki' => '#F0E68C',
|
||||||
|
'lavender' => '#E6E6FA',
|
||||||
|
'lavenderblush' => '#FFF0F5',
|
||||||
|
'lawngreen' => '#7CFC00',
|
||||||
|
'lemonchiffon' => '#FFFACD',
|
||||||
|
'lightblue' => '#ADD8E6',
|
||||||
|
'lightcoral' => '#F08080',
|
||||||
|
'lightcyan' => '#E0FFFF',
|
||||||
|
'lightgoldenrodyellow' => '#FAFAD2',
|
||||||
|
'lightgray' => '#D3D3D3',
|
||||||
|
'lightgrey' => '#D3D3D3',
|
||||||
|
'lightgreen' => '#90EE90',
|
||||||
|
'lightpink' => '#FFB6C1',
|
||||||
|
'lightsalmon' => '#FFA07A',
|
||||||
|
'lightseagreen' => '#20B2AA',
|
||||||
|
'lightskyblue' => '#87CEFA',
|
||||||
|
'lightslategray' => '#778899',
|
||||||
|
'lightslategrey' => '#778899',
|
||||||
|
'lightsteelblue' => '#B0C4DE',
|
||||||
|
'lightyellow' => '#FFFFE0',
|
||||||
|
'lime' => '#00FF00',
|
||||||
|
'limegreen' => '#32CD32',
|
||||||
|
'linen' => '#FAF0E6',
|
||||||
|
'magenta' => '#FF00FF',
|
||||||
|
'maroon' => '#800000',
|
||||||
|
'mediumaquamarine' => '#66CDAA',
|
||||||
|
'mediumblue' => '#0000CD',
|
||||||
|
'mediumorchid' => '#BA55D3',
|
||||||
|
'mediumpurple' => '#9370DB',
|
||||||
|
'mediumseagreen' => '#3CB371',
|
||||||
|
'mediumslateblue' => '#7B68EE',
|
||||||
|
'mediumspringgreen' => '#00FA9A',
|
||||||
|
'mediumturquoise' => '#48D1CC',
|
||||||
|
'mediumvioletred' => '#C71585',
|
||||||
|
'midnightblue' => '#191970',
|
||||||
|
'mintcream' => '#F5FFFA',
|
||||||
|
'mistyrose' => '#FFE4E1',
|
||||||
|
'moccasin' => '#FFE4B5',
|
||||||
|
'navajowhite' => '#FFDEAD',
|
||||||
|
'navy' => '#000080',
|
||||||
|
'oldlace' => '#FDF5E6',
|
||||||
|
'olive' => '#808000',
|
||||||
|
'olivedrab' => '#6B8E23',
|
||||||
|
'orange' => '#FFA500',
|
||||||
|
'orangered' => '#FF4500',
|
||||||
|
'orchid' => '#DA70D6',
|
||||||
|
'palegoldenrod' => '#EEE8AA',
|
||||||
|
'palegreen' => '#98FB98',
|
||||||
|
'paleturquoise' => '#AFEEEE',
|
||||||
|
'palevioletred' => '#DB7093',
|
||||||
|
'papayawhip' => '#FFEFD5',
|
||||||
|
'peachpuff' => '#FFDAB9',
|
||||||
|
'peru' => '#CD853F',
|
||||||
|
'pink' => '#FFC0CB',
|
||||||
|
'plum' => '#DDA0DD',
|
||||||
|
'powderblue' => '#B0E0E6',
|
||||||
|
'purple' => '#800080',
|
||||||
|
'rebeccapurple' => '#663399',
|
||||||
|
'red' => '#FF0000',
|
||||||
|
'rosybrown' => '#BC8F8F',
|
||||||
|
'royalblue' => '#4169E1',
|
||||||
|
'saddlebrown' => '#8B4513',
|
||||||
|
'salmon' => '#FA8072',
|
||||||
|
'sandybrown' => '#F4A460',
|
||||||
|
'seagreen' => '#2E8B57',
|
||||||
|
'seashell' => '#FFF5EE',
|
||||||
|
'sienna' => '#A0522D',
|
||||||
|
'silver' => '#C0C0C0',
|
||||||
|
'skyblue' => '#87CEEB',
|
||||||
|
'slateblue' => '#6A5ACD',
|
||||||
|
'slategray' => '#708090',
|
||||||
|
'slategrey' => '#708090',
|
||||||
|
'snow' => '#FFFAFA',
|
||||||
|
'springgreen' => '#00FF7F',
|
||||||
|
'steelblue' => '#4682B4',
|
||||||
|
'tan' => '#D2B48C',
|
||||||
|
'teal' => '#008080',
|
||||||
|
'thistle' => '#D8BFD8',
|
||||||
|
'tomato' => '#FF6347',
|
||||||
|
'turquoise' => '#40E0D0',
|
||||||
|
'violet' => '#EE82EE',
|
||||||
|
'wheat' => '#F5DEB3',
|
||||||
|
'white' => '#FFFFFF',
|
||||||
|
'whitesmoke' => '#F5F5F5',
|
||||||
|
'yellow' => '#FFFF00',
|
||||||
|
'yellowgreen' => '#9ACD32'
|
||||||
)
|
)
|
||||||
--DESCRIPTION--
|
--DESCRIPTION--
|
||||||
|
|
||||||
|
@@ -0,0 +1,36 @@
|
|||||||
|
Core.LegacyEntityDecoder
|
||||||
|
TYPE: bool
|
||||||
|
VERSION: 4.9.0
|
||||||
|
DEFAULT: false
|
||||||
|
--DESCRIPTION--
|
||||||
|
<p>
|
||||||
|
Prior to HTML Purifier 4.9.0, entities were decoded by performing
|
||||||
|
a global search replace for all entities whose decoded versions
|
||||||
|
did not have special meanings under HTML, and replaced them with
|
||||||
|
their decoded versions. We would match all entities, even if they did
|
||||||
|
not have a trailing semicolon, but only if there weren't any trailing
|
||||||
|
alphanumeric characters.
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Original</th><th>Text</th><th>Attribute</th></tr>
|
||||||
|
<tr><td>&yen;</td><td>¥</td><td>¥</td></tr>
|
||||||
|
<tr><td>&yen</td><td>¥</td><td>¥</td></tr>
|
||||||
|
<tr><td>&yena</td><td>&yena</td><td>&yena</td></tr>
|
||||||
|
<tr><td>&yen=</td><td>¥=</td><td>¥=</td></tr>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
In HTML Purifier 4.9.0, we changed the behavior of entity parsing
|
||||||
|
to match entities that had missing trailing semicolons in less
|
||||||
|
cases, to more closely match HTML5 parsing behavior:
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Original</th><th>Text</th><th>Attribute</th></tr>
|
||||||
|
<tr><td>&yen;</td><td>¥</td><td>¥</td></tr>
|
||||||
|
<tr><td>&yen</td><td>¥</td><td>¥</td></tr>
|
||||||
|
<tr><td>&yena</td><td>¥a</td><td>&yena</td></tr>
|
||||||
|
<tr><td>&yen=</td><td>¥=</td><td>&yen=</td></tr>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
This flag reverts back to pre-HTML Purifier 4.9.0 behavior.
|
||||||
|
</p>
|
||||||
|
--# vim: et sw=4 sts=4
|
@@ -0,0 +1,10 @@
|
|||||||
|
--# vim: et sw=4 sts=4
|
||||||
|
HTML.TargetNoopener
|
||||||
|
TYPE: bool
|
||||||
|
VERSION: 4.8.0
|
||||||
|
DEFAULT: TRUE
|
||||||
|
--DESCRIPTION--
|
||||||
|
If enabled, noopener rel attributes are added to links which have
|
||||||
|
a target attribute associated with them. This prevents malicious
|
||||||
|
destinations from overwriting the original window.
|
||||||
|
--# vim: et sw=4 sts=4
|
@@ -1,5 +1,5 @@
|
|||||||
URI.DefaultScheme
|
URI.DefaultScheme
|
||||||
TYPE: string
|
TYPE: string/null
|
||||||
DEFAULT: 'http'
|
DEFAULT: 'http'
|
||||||
--DESCRIPTION--
|
--DESCRIPTION--
|
||||||
|
|
||||||
@@ -7,4 +7,9 @@ DEFAULT: 'http'
|
|||||||
Defines through what scheme the output will be served, in order to
|
Defines through what scheme the output will be served, in order to
|
||||||
select the proper object validator when no scheme information is present.
|
select the proper object validator when no scheme information is present.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Starting with HTML Purifier 4.9.0, the default scheme can be null, in
|
||||||
|
which case we reject all URIs which do not have explicit schemes.
|
||||||
|
</p>
|
||||||
--# vim: et sw=4 sts=4
|
--# vim: et sw=4 sts=4
|
||||||
|
@@ -112,6 +112,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
|
|||||||
}
|
}
|
||||||
unlink($dir . '/' . $filename);
|
unlink($dir . '/' . $filename);
|
||||||
}
|
}
|
||||||
|
closedir($dh);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +143,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
|
|||||||
unlink($dir . '/' . $filename);
|
unlink($dir . '/' . $filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
closedir($dh);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,11 +200,8 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
|
|||||||
if ($result !== false) {
|
if ($result !== false) {
|
||||||
// set permissions of the new file (no execute)
|
// set permissions of the new file (no execute)
|
||||||
$chmod = $config->get('Cache.SerializerPermissions');
|
$chmod = $config->get('Cache.SerializerPermissions');
|
||||||
if ($chmod === null) {
|
if ($chmod !== null) {
|
||||||
// don't do anything
|
chmod($file, $chmod & 0666);
|
||||||
} else {
|
|
||||||
$chmod = $chmod & 0666;
|
|
||||||
chmod($file, $chmod);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
@@ -217,6 +216,16 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
|
|||||||
{
|
{
|
||||||
$directory = $this->generateDirectoryPath($config);
|
$directory = $this->generateDirectoryPath($config);
|
||||||
$chmod = $config->get('Cache.SerializerPermissions');
|
$chmod = $config->get('Cache.SerializerPermissions');
|
||||||
|
if ($chmod === null) {
|
||||||
|
if (!@mkdir($directory) && !is_dir($directory)) {
|
||||||
|
trigger_error(
|
||||||
|
'Could not create directory ' . $directory . '',
|
||||||
|
E_USER_WARNING
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (!is_dir($directory)) {
|
if (!is_dir($directory)) {
|
||||||
$base = $this->generateBaseDirectoryPath($config);
|
$base = $this->generateBaseDirectoryPath($config);
|
||||||
if (!is_dir($base)) {
|
if (!is_dir($base)) {
|
||||||
@@ -229,25 +238,14 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
|
|||||||
} elseif (!$this->_testPermissions($base, $chmod)) {
|
} elseif (!$this->_testPermissions($base, $chmod)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($chmod === null) {
|
if (!@mkdir($directory, $chmod) && !is_dir($directory)) {
|
||||||
trigger_error(
|
trigger_error(
|
||||||
'Base directory ' . $base . ' does not exist,
|
'Could not create directory ' . $directory . '',
|
||||||
please create or change using %Cache.SerializerPath',
|
|
||||||
E_USER_WARNING
|
E_USER_WARNING
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($chmod !== null) {
|
|
||||||
mkdir($directory, $chmod);
|
|
||||||
} else {
|
|
||||||
mkdir($directory);
|
|
||||||
}
|
|
||||||
if (!$this->_testPermissions($directory, $chmod)) {
|
if (!$this->_testPermissions($directory, $chmod)) {
|
||||||
trigger_error(
|
|
||||||
'Base directory ' . $base . ' does not exist,
|
|
||||||
please create or change using %Cache.SerializerPath',
|
|
||||||
E_USER_WARNING
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} elseif (!$this->_testPermissions($directory, $chmod)) {
|
} elseif (!$this->_testPermissions($directory, $chmod)) {
|
||||||
|
@@ -101,6 +101,14 @@ class HTMLPurifier_Encoder
|
|||||||
* It will parse according to UTF-8 and return a valid UTF8 string, with
|
* It will parse according to UTF-8 and return a valid UTF8 string, with
|
||||||
* non-SGML codepoints excluded.
|
* non-SGML codepoints excluded.
|
||||||
*
|
*
|
||||||
|
* Specifically, it will permit:
|
||||||
|
* \x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}
|
||||||
|
* Source: https://www.w3.org/TR/REC-xml/#NT-Char
|
||||||
|
* Arguably this function should be modernized to the HTML5 set
|
||||||
|
* of allowed characters:
|
||||||
|
* https://www.w3.org/TR/html5/syntax.html#preprocessing-the-input-stream
|
||||||
|
* which simultaneously expand and restrict the set of allowed characters.
|
||||||
|
*
|
||||||
* @param string $str The string to clean
|
* @param string $str The string to clean
|
||||||
* @param bool $force_php
|
* @param bool $force_php
|
||||||
* @return string
|
* @return string
|
||||||
@@ -122,15 +130,12 @@ class HTMLPurifier_Encoder
|
|||||||
* function that needs to be able to understand UTF-8 characters.
|
* function that needs to be able to understand UTF-8 characters.
|
||||||
* As of right now, only smart lossless character encoding converters
|
* As of right now, only smart lossless character encoding converters
|
||||||
* would need that, and I'm probably not going to implement them.
|
* would need that, and I'm probably not going to implement them.
|
||||||
* Once again, PHP 6 should solve all our problems.
|
|
||||||
*/
|
*/
|
||||||
public static function cleanUTF8($str, $force_php = false)
|
public static function cleanUTF8($str, $force_php = false)
|
||||||
{
|
{
|
||||||
// UTF-8 validity is checked since PHP 4.3.5
|
// UTF-8 validity is checked since PHP 4.3.5
|
||||||
// This is an optimization: if the string is already valid UTF-8, no
|
// This is an optimization: if the string is already valid UTF-8, no
|
||||||
// need to do PHP stuff. 99% of the time, this will be the case.
|
// need to do PHP stuff. 99% of the time, this will be the case.
|
||||||
// The regexp matches the XML char production, as well as well as excluding
|
|
||||||
// non-SGML codepoints U+007F to U+009F
|
|
||||||
if (preg_match(
|
if (preg_match(
|
||||||
'/^[\x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]*$/Du',
|
'/^[\x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]*$/Du',
|
||||||
$str
|
$str
|
||||||
@@ -255,6 +260,7 @@ class HTMLPurifier_Encoder
|
|||||||
// 7F-9F is not strictly prohibited by XML,
|
// 7F-9F is not strictly prohibited by XML,
|
||||||
// but it is non-SGML, and thus we don't allow it
|
// but it is non-SGML, and thus we don't allow it
|
||||||
(0xA0 <= $mUcs4 && 0xD7FF >= $mUcs4) ||
|
(0xA0 <= $mUcs4 && 0xD7FF >= $mUcs4) ||
|
||||||
|
(0xE000 <= $mUcs4 && 0xFFFD >= $mUcs4) ||
|
||||||
(0x10000 <= $mUcs4 && 0x10FFFF >= $mUcs4)
|
(0x10000 <= $mUcs4 && 0x10FFFF >= $mUcs4)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
@@ -16,6 +16,138 @@ class HTMLPurifier_EntityParser
|
|||||||
*/
|
*/
|
||||||
protected $_entity_lookup;
|
protected $_entity_lookup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback regex string for entities in text.
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
protected $_textEntitiesRegex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback regex string for entities in attributes.
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
protected $_attrEntitiesRegex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if the beginning of a string is a semi-optional regex
|
||||||
|
*/
|
||||||
|
protected $_semiOptionalPrefixRegex;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
// From
|
||||||
|
// http://stackoverflow.com/questions/15532252/why-is-reg-being-rendered-as-without-the-bounding-semicolon
|
||||||
|
$semi_optional = "quot|QUOT|lt|LT|gt|GT|amp|AMP|AElig|Aacute|Acirc|Agrave|Aring|Atilde|Auml|COPY|Ccedil|ETH|Eacute|Ecirc|Egrave|Euml|Iacute|Icirc|Igrave|Iuml|Ntilde|Oacute|Ocirc|Ograve|Oslash|Otilde|Ouml|REG|THORN|Uacute|Ucirc|Ugrave|Uuml|Yacute|aacute|acirc|acute|aelig|agrave|aring|atilde|auml|brvbar|ccedil|cedil|cent|copy|curren|deg|divide|eacute|ecirc|egrave|eth|euml|frac12|frac14|frac34|iacute|icirc|iexcl|igrave|iquest|iuml|laquo|macr|micro|middot|nbsp|not|ntilde|oacute|ocirc|ograve|ordf|ordm|oslash|otilde|ouml|para|plusmn|pound|raquo|reg|sect|shy|sup1|sup2|sup3|szlig|thorn|times|uacute|ucirc|ugrave|uml|uuml|yacute|yen|yuml";
|
||||||
|
|
||||||
|
// NB: three empty captures to put the fourth match in the right
|
||||||
|
// place
|
||||||
|
$this->_semiOptionalPrefixRegex = "/&()()()($semi_optional)/";
|
||||||
|
|
||||||
|
$this->_textEntitiesRegex =
|
||||||
|
'/&(?:'.
|
||||||
|
// hex
|
||||||
|
'[#]x([a-fA-F0-9]+);?|'.
|
||||||
|
// dec
|
||||||
|
'[#]0*(\d+);?|'.
|
||||||
|
// string (mandatory semicolon)
|
||||||
|
// NB: order matters: match semicolon preferentially
|
||||||
|
'([A-Za-z_:][A-Za-z0-9.\-_:]*);|'.
|
||||||
|
// string (optional semicolon)
|
||||||
|
"($semi_optional)".
|
||||||
|
')/';
|
||||||
|
|
||||||
|
$this->_attrEntitiesRegex =
|
||||||
|
'/&(?:'.
|
||||||
|
// hex
|
||||||
|
'[#]x([a-fA-F0-9]+);?|'.
|
||||||
|
// dec
|
||||||
|
'[#]0*(\d+);?|'.
|
||||||
|
// string (mandatory semicolon)
|
||||||
|
// NB: order matters: match semicolon preferentially
|
||||||
|
'([A-Za-z_:][A-Za-z0-9.\-_:]*);|'.
|
||||||
|
// string (optional semicolon)
|
||||||
|
// don't match if trailing is equals or alphanumeric (URL
|
||||||
|
// like)
|
||||||
|
"($semi_optional)(?![=;A-Za-z0-9])".
|
||||||
|
')/';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Substitute entities with the parsed equivalents. Use this on
|
||||||
|
* textual data in an HTML document (as opposed to attributes.)
|
||||||
|
*
|
||||||
|
* @param string $string String to have entities parsed.
|
||||||
|
* @return string Parsed string.
|
||||||
|
*/
|
||||||
|
public function substituteTextEntities($string)
|
||||||
|
{
|
||||||
|
return preg_replace_callback(
|
||||||
|
$this->_textEntitiesRegex,
|
||||||
|
array($this, 'entityCallback'),
|
||||||
|
$string
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Substitute entities with the parsed equivalents. Use this on
|
||||||
|
* attribute contents in documents.
|
||||||
|
*
|
||||||
|
* @param string $string String to have entities parsed.
|
||||||
|
* @return string Parsed string.
|
||||||
|
*/
|
||||||
|
public function substituteAttrEntities($string)
|
||||||
|
{
|
||||||
|
return preg_replace_callback(
|
||||||
|
$this->_attrEntitiesRegex,
|
||||||
|
array($this, 'entityCallback'),
|
||||||
|
$string
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function for substituteNonSpecialEntities() that does the work.
|
||||||
|
*
|
||||||
|
* @param array $matches PCRE matches array, with 0 the entire match, and
|
||||||
|
* either index 1, 2 or 3 set with a hex value, dec value,
|
||||||
|
* or string (respectively).
|
||||||
|
* @return string Replacement string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected function entityCallback($matches)
|
||||||
|
{
|
||||||
|
$entity = $matches[0];
|
||||||
|
$hex_part = @$matches[1];
|
||||||
|
$dec_part = @$matches[2];
|
||||||
|
$named_part = empty($matches[3]) ? (empty($matches[4]) ? "" : $matches[4]) : $matches[3];
|
||||||
|
if ($hex_part !== NULL && $hex_part !== "") {
|
||||||
|
return HTMLPurifier_Encoder::unichr(hexdec($hex_part));
|
||||||
|
} elseif ($dec_part !== NULL && $dec_part !== "") {
|
||||||
|
return HTMLPurifier_Encoder::unichr((int) $dec_part);
|
||||||
|
} else {
|
||||||
|
if (!$this->_entity_lookup) {
|
||||||
|
$this->_entity_lookup = HTMLPurifier_EntityLookup::instance();
|
||||||
|
}
|
||||||
|
if (isset($this->_entity_lookup->table[$named_part])) {
|
||||||
|
return $this->_entity_lookup->table[$named_part];
|
||||||
|
} else {
|
||||||
|
// exact match didn't match anything, so test if
|
||||||
|
// any of the semicolon optional match the prefix.
|
||||||
|
// Test that this is an EXACT match is important to
|
||||||
|
// prevent infinite loop
|
||||||
|
if (!empty($matches[3])) {
|
||||||
|
return preg_replace_callback(
|
||||||
|
$this->_semiOptionalPrefixRegex,
|
||||||
|
array($this, 'entityCallback'),
|
||||||
|
$entity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LEGACY CODE BELOW
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback regex string for parsing entities.
|
* Callback regex string for parsing entities.
|
||||||
* @type string
|
* @type string
|
||||||
@@ -144,7 +276,7 @@ class HTMLPurifier_EntityParser
|
|||||||
$entity;
|
$entity;
|
||||||
} else {
|
} else {
|
||||||
return isset($this->_special_ent2dec[$matches[3]]) ?
|
return isset($this->_special_ent2dec[$matches[3]]) ?
|
||||||
$this->_special_ent2dec[$matches[3]] :
|
$this->_special_dec2str[$this->_special_ent2dec[$matches[3]]] :
|
||||||
$entity;
|
$entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -95,7 +95,10 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
|
|||||||
if ($tidy !== null) {
|
if ($tidy !== null) {
|
||||||
$this->_tidy = $tidy;
|
$this->_tidy = $tidy;
|
||||||
}
|
}
|
||||||
$html = preg_replace_callback('#<style(?:\s.*)?>(.+)</style>#isU', array($this, 'styleCallback'), $html);
|
// NB: this must be NON-greedy because if we have
|
||||||
|
// <style>foo</style> <style>bar</style>
|
||||||
|
// we must not grab foo</style> <style>bar
|
||||||
|
$html = preg_replace_callback('#<style(?:\s.*)?>(.*)<\/style>#isU', array($this, 'styleCallback'), $html);
|
||||||
$style_blocks = $this->_styleMatches;
|
$style_blocks = $this->_styleMatches;
|
||||||
$this->_styleMatches = array(); // reset
|
$this->_styleMatches = array(); // reset
|
||||||
$context->register('StyleBlocks', $style_blocks); // $context must not be reused
|
$context->register('StyleBlocks', $style_blocks); // $context must not be reused
|
||||||
|
@@ -146,7 +146,7 @@ class HTMLPurifier_Generator
|
|||||||
$attr = $this->generateAttributes($token->attr, $token->name);
|
$attr = $this->generateAttributes($token->attr, $token->name);
|
||||||
if ($this->_flashCompat) {
|
if ($this->_flashCompat) {
|
||||||
if ($token->name == "object") {
|
if ($token->name == "object") {
|
||||||
$flash = new stdclass();
|
$flash = new stdClass();
|
||||||
$flash->attr = $token->attr;
|
$flash->attr = $token->attr;
|
||||||
$flash->param = array();
|
$flash->param = array();
|
||||||
$this->_flashStack[] = $flash;
|
$this->_flashStack[] = $flash;
|
||||||
|
@@ -23,13 +23,13 @@ class HTMLPurifier_HTMLModule_SafeScripting extends HTMLPurifier_HTMLModule
|
|||||||
$script = $this->addElement(
|
$script = $this->addElement(
|
||||||
'script',
|
'script',
|
||||||
'Inline',
|
'Inline',
|
||||||
'Empty',
|
'Optional:', // Not `Empty` to not allow to autoclose the <script /> tag @see https://www.w3.org/TR/html4/interact/scripts.html
|
||||||
null,
|
null,
|
||||||
array(
|
array(
|
||||||
// While technically not required by the spec, we're forcing
|
// While technically not required by the spec, we're forcing
|
||||||
// it to this value.
|
// it to this value.
|
||||||
'type' => 'Enum#text/javascript',
|
'type' => 'Enum#text/javascript',
|
||||||
'src*' => new HTMLPurifier_AttrDef_Enum(array_keys($allowed))
|
'src*' => new HTMLPurifier_AttrDef_Enum(array_keys($allowed), /*case sensitive*/ true)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$script->attr_transform_pre[] =
|
$script->attr_transform_pre[] =
|
||||||
|
21
library/HTMLPurifier/HTMLModule/TargetNoopener.php
Normal file
21
library/HTMLPurifier/HTMLModule/TargetNoopener.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module adds the target-based noopener attribute transformation to a tags. It
|
||||||
|
* is enabled by HTML.TargetNoopener
|
||||||
|
*/
|
||||||
|
class HTMLPurifier_HTMLModule_TargetNoopener extends HTMLPurifier_HTMLModule
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
public $name = 'TargetNoopener';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param HTMLPurifier_Config $config
|
||||||
|
*/
|
||||||
|
public function setup($config) {
|
||||||
|
$a = $this->addBlankElement('a');
|
||||||
|
$a->attr_transform_post[] = new HTMLPurifier_AttrTransform_TargetNoopener();
|
||||||
|
}
|
||||||
|
}
|
@@ -271,11 +271,14 @@ class HTMLPurifier_HTMLModuleManager
|
|||||||
if ($config->get('HTML.TargetBlank')) {
|
if ($config->get('HTML.TargetBlank')) {
|
||||||
$modules[] = 'TargetBlank';
|
$modules[] = 'TargetBlank';
|
||||||
}
|
}
|
||||||
// NB: HTML.TargetNoreferrer must be AFTER HTML.TargetBlank
|
// NB: HTML.TargetNoreferrer and HTML.TargetNoopener must be AFTER HTML.TargetBlank
|
||||||
// so that its post-attr-transform gets run afterwards.
|
// so that its post-attr-transform gets run afterwards.
|
||||||
if ($config->get('HTML.TargetNoreferrer')) {
|
if ($config->get('HTML.TargetNoreferrer')) {
|
||||||
$modules[] = 'TargetNoreferrer';
|
$modules[] = 'TargetNoreferrer';
|
||||||
}
|
}
|
||||||
|
if ($config->get('HTML.TargetNoopener')) {
|
||||||
|
$modules[] = 'TargetNoopener';
|
||||||
|
}
|
||||||
|
|
||||||
// merge in custom modules
|
// merge in custom modules
|
||||||
$modules = array_merge($modules, $this->userModules);
|
$modules = array_merge($modules, $this->userModules);
|
||||||
|
@@ -157,11 +157,13 @@ abstract class HTMLPurifier_Injector
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// check for exclusion
|
// check for exclusion
|
||||||
for ($i = count($this->currentNesting) - 2; $i >= 0; $i--) {
|
if (!empty($this->currentNesting)) {
|
||||||
$node = $this->currentNesting[$i];
|
for ($i = count($this->currentNesting) - 2; $i >= 0; $i--) {
|
||||||
$def = $this->htmlDefinition->info[$node->name];
|
$node = $this->currentNesting[$i];
|
||||||
if (isset($def->excludes[$name])) {
|
$def = $this->htmlDefinition->info[$node->name];
|
||||||
return false;
|
if (isset($def->excludes[$name])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@@ -8,4 +8,6 @@ $messages = array(
|
|||||||
'HTMLPurifier' => 'HTML Purifier X'
|
'HTMLPurifier' => 'HTML Purifier X'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$errorNames = array();
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
@@ -9,4 +9,6 @@ $messages = array(
|
|||||||
'HTMLPurifier' => 'HTML Purifier XNone'
|
'HTMLPurifier' => 'HTML Purifier XNone'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$errorNames = array();
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
@@ -26,12 +26,14 @@ class HTMLPurifier_Length
|
|||||||
protected $isValid;
|
protected $isValid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array Lookup array of units recognized by CSS 2.1
|
* Array Lookup array of units recognized by CSS 3
|
||||||
* @type array
|
* @type array
|
||||||
*/
|
*/
|
||||||
protected static $allowedUnits = array(
|
protected static $allowedUnits = array(
|
||||||
'em' => true, 'ex' => true, 'px' => true, 'in' => true,
|
'em' => true, 'ex' => true, 'px' => true, 'in' => true,
|
||||||
'cm' => true, 'mm' => true, 'pt' => true, 'pc' => true
|
'cm' => true, 'mm' => true, 'pt' => true, 'pc' => true,
|
||||||
|
'ch' => true, 'rem' => true, 'vw' => true, 'vh' => true,
|
||||||
|
'vmin' => true, 'vmax' => true
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -96,7 +96,7 @@ class HTMLPurifier_Lexer
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (class_exists('DOMDocument') &&
|
if (class_exists('DOMDocument', false) &&
|
||||||
method_exists('DOMDocument', 'loadHTML') &&
|
method_exists('DOMDocument', 'loadHTML') &&
|
||||||
!extension_loaded('domxml')
|
!extension_loaded('domxml')
|
||||||
) {
|
) {
|
||||||
@@ -169,21 +169,24 @@ class HTMLPurifier_Lexer
|
|||||||
''' => "'"
|
''' => "'"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public function parseText($string, $config) {
|
||||||
|
return $this->parseData($string, false, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseAttr($string, $config) {
|
||||||
|
return $this->parseData($string, true, $config);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses special entities into the proper characters.
|
* Parses special entities into the proper characters.
|
||||||
*
|
*
|
||||||
* This string will translate escaped versions of the special characters
|
* This string will translate escaped versions of the special characters
|
||||||
* into the correct ones.
|
* into the correct ones.
|
||||||
*
|
*
|
||||||
* @warning
|
|
||||||
* You should be able to treat the output of this function as
|
|
||||||
* completely parsed, but that's only because all other entities should
|
|
||||||
* have been handled previously in substituteNonSpecialEntities()
|
|
||||||
*
|
|
||||||
* @param string $string String character data to be parsed.
|
* @param string $string String character data to be parsed.
|
||||||
* @return string Parsed character data.
|
* @return string Parsed character data.
|
||||||
*/
|
*/
|
||||||
public function parseData($string)
|
public function parseData($string, $is_attr, $config)
|
||||||
{
|
{
|
||||||
// following functions require at least one character
|
// following functions require at least one character
|
||||||
if ($string === '') {
|
if ($string === '') {
|
||||||
@@ -209,7 +212,15 @@ class HTMLPurifier_Lexer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// hmm... now we have some uncommon entities. Use the callback.
|
// hmm... now we have some uncommon entities. Use the callback.
|
||||||
$string = $this->_entity_parser->substituteSpecialEntities($string);
|
if ($config->get('Core.LegacyEntityDecoder')) {
|
||||||
|
$string = $this->_entity_parser->substituteSpecialEntities($string);
|
||||||
|
} else {
|
||||||
|
if ($is_attr) {
|
||||||
|
$string = $this->_entity_parser->substituteAttrEntities($string);
|
||||||
|
} else {
|
||||||
|
$string = $this->_entity_parser->substituteTextEntities($string);
|
||||||
|
}
|
||||||
|
}
|
||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +334,9 @@ class HTMLPurifier_Lexer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// expand entities that aren't the big five
|
// expand entities that aren't the big five
|
||||||
$html = $this->_entity_parser->substituteNonSpecialEntities($html);
|
if ($config->get('Core.LegacyEntityDecoder')) {
|
||||||
|
$html = $this->_entity_parser->substituteNonSpecialEntities($html);
|
||||||
|
}
|
||||||
|
|
||||||
// clean into wellformed UTF-8 string for an SGML context: this has
|
// clean into wellformed UTF-8 string for an SGML context: this has
|
||||||
// to be done after entity expansion because the entities sometimes
|
// to be done after entity expansion because the entities sometimes
|
||||||
@@ -335,6 +348,13 @@ class HTMLPurifier_Lexer
|
|||||||
$html = preg_replace('#<\?.+?\?>#s', '', $html);
|
$html = preg_replace('#<\?.+?\?>#s', '', $html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hidden_elements = $config->get('Core.HiddenElements');
|
||||||
|
if ($config->get('Core.AggressivelyRemoveScript') &&
|
||||||
|
!($config->get('HTML.Trusted') || !$config->get('Core.RemoveScriptContents')
|
||||||
|
|| empty($hidden_elements["script"]))) {
|
||||||
|
$html = preg_replace('#<script[^>]*>.*?</script>#i', '', $html);
|
||||||
|
}
|
||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -68,16 +68,29 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
$doc = new DOMDocument();
|
$doc = new DOMDocument();
|
||||||
$doc->encoding = 'UTF-8'; // theoretically, the above has this covered
|
$doc->encoding = 'UTF-8'; // theoretically, the above has this covered
|
||||||
|
|
||||||
|
$options = 0;
|
||||||
|
if ($config->get('Core.AllowParseManyTags') && defined('LIBXML_PARSEHUGE')) {
|
||||||
|
$options |= LIBXML_PARSEHUGE;
|
||||||
|
}
|
||||||
|
|
||||||
set_error_handler(array($this, 'muteErrorHandler'));
|
set_error_handler(array($this, 'muteErrorHandler'));
|
||||||
$doc->loadHTML($html);
|
$doc->loadHTML($html, $options);
|
||||||
restore_error_handler();
|
restore_error_handler();
|
||||||
|
|
||||||
|
$body = $doc->getElementsByTagName('html')->item(0)-> // <html>
|
||||||
|
getElementsByTagName('body')->item(0); // <body>
|
||||||
|
|
||||||
|
$div = $body->getElementsByTagName('div')->item(0); // <div>
|
||||||
$tokens = array();
|
$tokens = array();
|
||||||
$this->tokenizeDOM(
|
$this->tokenizeDOM($div, $tokens, $config);
|
||||||
$doc->getElementsByTagName('html')->item(0)-> // <html>
|
// If the div has a sibling, that means we tripped across
|
||||||
getElementsByTagName('body')->item(0), // <body>
|
// a premature </div> tag. So remove the div we parsed,
|
||||||
$tokens
|
// and then tokenize the rest of body. We can't tokenize
|
||||||
);
|
// the sibling directly as we'll lose the tags in that case.
|
||||||
|
if ($div->nextSibling) {
|
||||||
|
$body->removeChild($div);
|
||||||
|
$this->tokenizeDOM($body, $tokens, $config);
|
||||||
|
}
|
||||||
return $tokens;
|
return $tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +101,7 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
* @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens.
|
* @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens.
|
||||||
* @return HTMLPurifier_Token of node appended to previously passed tokens.
|
* @return HTMLPurifier_Token of node appended to previously passed tokens.
|
||||||
*/
|
*/
|
||||||
protected function tokenizeDOM($node, &$tokens)
|
protected function tokenizeDOM($node, &$tokens, $config)
|
||||||
{
|
{
|
||||||
$level = 0;
|
$level = 0;
|
||||||
$nodes = array($level => new HTMLPurifier_Queue(array($node)));
|
$nodes = array($level => new HTMLPurifier_Queue(array($node)));
|
||||||
@@ -97,7 +110,7 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
while (!$nodes[$level]->isEmpty()) {
|
while (!$nodes[$level]->isEmpty()) {
|
||||||
$node = $nodes[$level]->shift(); // FIFO
|
$node = $nodes[$level]->shift(); // FIFO
|
||||||
$collect = $level > 0 ? true : false;
|
$collect = $level > 0 ? true : false;
|
||||||
$needEndingTag = $this->createStartNode($node, $tokens, $collect);
|
$needEndingTag = $this->createStartNode($node, $tokens, $collect, $config);
|
||||||
if ($needEndingTag) {
|
if ($needEndingTag) {
|
||||||
$closingNodes[$level][] = $node;
|
$closingNodes[$level][] = $node;
|
||||||
}
|
}
|
||||||
@@ -118,6 +131,41 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
} while ($level > 0);
|
} while ($level > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Portably retrieve the tag name of a node; deals with older versions
|
||||||
|
* of libxml like 2.7.6
|
||||||
|
* @param DOMNode $node
|
||||||
|
*/
|
||||||
|
protected function getTagName($node)
|
||||||
|
{
|
||||||
|
if (isset($node->tagName)) {
|
||||||
|
return $node->tagName;
|
||||||
|
} else if (isset($node->nodeName)) {
|
||||||
|
return $node->nodeName;
|
||||||
|
} else if (isset($node->localName)) {
|
||||||
|
return $node->localName;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Portably retrieve the data of a node; deals with older versions
|
||||||
|
* of libxml like 2.7.6
|
||||||
|
* @param DOMNode $node
|
||||||
|
*/
|
||||||
|
protected function getData($node)
|
||||||
|
{
|
||||||
|
if (isset($node->data)) {
|
||||||
|
return $node->data;
|
||||||
|
} else if (isset($node->nodeValue)) {
|
||||||
|
return $node->nodeValue;
|
||||||
|
} else if (isset($node->textContent)) {
|
||||||
|
return $node->textContent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param DOMNode $node DOMNode to be tokenized.
|
* @param DOMNode $node DOMNode to be tokenized.
|
||||||
* @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens.
|
* @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens.
|
||||||
@@ -127,13 +175,16 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
* @return bool if the token needs an endtoken
|
* @return bool if the token needs an endtoken
|
||||||
* @todo data and tagName properties don't seem to exist in DOMNode?
|
* @todo data and tagName properties don't seem to exist in DOMNode?
|
||||||
*/
|
*/
|
||||||
protected function createStartNode($node, &$tokens, $collect)
|
protected function createStartNode($node, &$tokens, $collect, $config)
|
||||||
{
|
{
|
||||||
// intercept non element nodes. WE MUST catch all of them,
|
// intercept non element nodes. WE MUST catch all of them,
|
||||||
// but we're not getting the character reference nodes because
|
// but we're not getting the character reference nodes because
|
||||||
// those should have been preprocessed
|
// those should have been preprocessed
|
||||||
if ($node->nodeType === XML_TEXT_NODE) {
|
if ($node->nodeType === XML_TEXT_NODE) {
|
||||||
$tokens[] = $this->factory->createText($node->data);
|
$data = $this->getData($node); // Handle variable data property
|
||||||
|
if ($data !== null) {
|
||||||
|
$tokens[] = $this->factory->createText($data);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
} elseif ($node->nodeType === XML_CDATA_SECTION_NODE) {
|
} elseif ($node->nodeType === XML_CDATA_SECTION_NODE) {
|
||||||
// undo libxml's special treatment of <script> and <style> tags
|
// undo libxml's special treatment of <script> and <style> tags
|
||||||
@@ -151,7 +202,7 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$tokens[] = $this->factory->createText($this->parseData($data));
|
$tokens[] = $this->factory->createText($this->parseText($data, $config));
|
||||||
return false;
|
return false;
|
||||||
} elseif ($node->nodeType === XML_COMMENT_NODE) {
|
} elseif ($node->nodeType === XML_COMMENT_NODE) {
|
||||||
// this is code is only invoked for comments in script/style in versions
|
// this is code is only invoked for comments in script/style in versions
|
||||||
@@ -163,21 +214,20 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
// not-well tested: there may be other nodes we have to grab
|
// not-well tested: there may be other nodes we have to grab
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$attr = $node->hasAttributes() ? $this->transformAttrToAssoc($node->attributes) : array();
|
$attr = $node->hasAttributes() ? $this->transformAttrToAssoc($node->attributes) : array();
|
||||||
|
$tag_name = $this->getTagName($node); // Handle variable tagName property
|
||||||
|
if (empty($tag_name)) {
|
||||||
|
return (bool) $node->childNodes->length;
|
||||||
|
}
|
||||||
// We still have to make sure that the element actually IS empty
|
// We still have to make sure that the element actually IS empty
|
||||||
if (!$node->childNodes->length) {
|
if (!$node->childNodes->length) {
|
||||||
if ($collect) {
|
if ($collect) {
|
||||||
$tokens[] = $this->factory->createEmpty($node->tagName, $attr);
|
$tokens[] = $this->factory->createEmpty($tag_name, $attr);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if ($collect) {
|
if ($collect) {
|
||||||
$tokens[] = $this->factory->createStart(
|
$tokens[] = $this->factory->createStart($tag_name, $attr);
|
||||||
$tag_name = $node->tagName, // somehow, it get's dropped
|
|
||||||
$attr
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -189,10 +239,10 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
*/
|
*/
|
||||||
protected function createEndNode($node, &$tokens)
|
protected function createEndNode($node, &$tokens)
|
||||||
{
|
{
|
||||||
$tokens[] = $this->factory->createEnd($node->tagName);
|
$tag_name = $this->getTagName($node); // Handle variable tagName property
|
||||||
|
$tokens[] = $this->factory->createEnd($tag_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a DOMNamedNodeMap of DOMAttr objects into an assoc array.
|
* Converts a DOMNamedNodeMap of DOMAttr objects into an assoc array.
|
||||||
*
|
*
|
||||||
@@ -252,7 +302,7 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
* @param HTMLPurifier_Context $context
|
* @param HTMLPurifier_Context $context
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function wrapHTML($html, $config, $context)
|
protected function wrapHTML($html, $config, $context, $use_div = true)
|
||||||
{
|
{
|
||||||
$def = $config->getDefinition('HTML');
|
$def = $config->getDefinition('HTML');
|
||||||
$ret = '';
|
$ret = '';
|
||||||
@@ -271,7 +321,11 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
|
|||||||
$ret .= '<html><head>';
|
$ret .= '<html><head>';
|
||||||
$ret .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
|
$ret .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
|
||||||
// No protection if $html contains a stray </div>!
|
// No protection if $html contains a stray </div>!
|
||||||
$ret .= '</head><body>' . $html . '</body></html>';
|
$ret .= '</head><body>';
|
||||||
|
if ($use_div) $ret .= '<div>';
|
||||||
|
$ret .= $html;
|
||||||
|
if ($use_div) $ret .= '</div>';
|
||||||
|
$ret .= '</body></html>';
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -129,12 +129,12 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
|
|||||||
// We are not inside tag and there still is another tag to parse
|
// We are not inside tag and there still is another tag to parse
|
||||||
$token = new
|
$token = new
|
||||||
HTMLPurifier_Token_Text(
|
HTMLPurifier_Token_Text(
|
||||||
$this->parseData(
|
$this->parseText(
|
||||||
substr(
|
substr(
|
||||||
$html,
|
$html,
|
||||||
$cursor,
|
$cursor,
|
||||||
$position_next_lt - $cursor
|
$position_next_lt - $cursor
|
||||||
)
|
), $config
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if ($maintain_line_numbers) {
|
if ($maintain_line_numbers) {
|
||||||
@@ -154,11 +154,11 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
|
|||||||
// Create Text of rest of string
|
// Create Text of rest of string
|
||||||
$token = new
|
$token = new
|
||||||
HTMLPurifier_Token_Text(
|
HTMLPurifier_Token_Text(
|
||||||
$this->parseData(
|
$this->parseText(
|
||||||
substr(
|
substr(
|
||||||
$html,
|
$html,
|
||||||
$cursor
|
$cursor
|
||||||
)
|
), $config
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if ($maintain_line_numbers) {
|
if ($maintain_line_numbers) {
|
||||||
@@ -324,8 +324,8 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
|
|||||||
$token = new
|
$token = new
|
||||||
HTMLPurifier_Token_Text(
|
HTMLPurifier_Token_Text(
|
||||||
'<' .
|
'<' .
|
||||||
$this->parseData(
|
$this->parseText(
|
||||||
substr($html, $cursor)
|
substr($html, $cursor), $config
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if ($maintain_line_numbers) {
|
if ($maintain_line_numbers) {
|
||||||
@@ -429,7 +429,7 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
|
|||||||
if ($value === false) {
|
if ($value === false) {
|
||||||
$value = '';
|
$value = '';
|
||||||
}
|
}
|
||||||
return array($key => $this->parseData($value));
|
return array($key => $this->parseAttr($value, $config));
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup loop environment
|
// setup loop environment
|
||||||
@@ -518,7 +518,7 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
|
|||||||
if ($value === false) {
|
if ($value === false) {
|
||||||
$value = '';
|
$value = '';
|
||||||
}
|
}
|
||||||
$array[$key] = $this->parseData($value);
|
$array[$key] = $this->parseAttr($value, $config);
|
||||||
$cursor++;
|
$cursor++;
|
||||||
} else {
|
} else {
|
||||||
// boolattr
|
// boolattr
|
||||||
|
@@ -21,7 +21,7 @@ class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex
|
|||||||
public function tokenizeHTML($html, $config, $context)
|
public function tokenizeHTML($html, $config, $context)
|
||||||
{
|
{
|
||||||
$new_html = $this->normalize($html, $config, $context);
|
$new_html = $this->normalize($html, $config, $context);
|
||||||
$new_html = $this->wrapHTML($new_html, $config, $context);
|
$new_html = $this->wrapHTML($new_html, $config, $context, false /* no div */);
|
||||||
try {
|
try {
|
||||||
$parser = new HTML5($new_html);
|
$parser = new HTML5($new_html);
|
||||||
$doc = $parser->save();
|
$doc = $parser->save();
|
||||||
@@ -34,9 +34,9 @@ class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex
|
|||||||
$tokens = array();
|
$tokens = array();
|
||||||
$this->tokenizeDOM(
|
$this->tokenizeDOM(
|
||||||
$doc->getElementsByTagName('html')->item(0)-> // <html>
|
$doc->getElementsByTagName('html')->item(0)-> // <html>
|
||||||
getElementsByTagName('body')->item(0) // <body>
|
getElementsByTagName('body')->item(0) // <body>
|
||||||
,
|
,
|
||||||
$tokens
|
$tokens, $config
|
||||||
);
|
);
|
||||||
return $tokens;
|
return $tokens;
|
||||||
}
|
}
|
||||||
@@ -1507,7 +1507,7 @@ class HTML5
|
|||||||
$entity = $this->character($start, $this->char);
|
$entity = $this->character($start, $this->char);
|
||||||
$cond = strlen($e_name) > 0;
|
$cond = strlen($e_name) > 0;
|
||||||
|
|
||||||
// The rest of the parsing happens bellow.
|
// The rest of the parsing happens below.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Anything else
|
// Anything else
|
||||||
@@ -1515,6 +1515,7 @@ class HTML5
|
|||||||
// Consume the maximum number of characters possible, with the
|
// Consume the maximum number of characters possible, with the
|
||||||
// consumed characters case-sensitively matching one of the
|
// consumed characters case-sensitively matching one of the
|
||||||
// identifiers in the first column of the entities table.
|
// identifiers in the first column of the entities table.
|
||||||
|
|
||||||
$e_name = $this->characters('0-9A-Za-z;', $this->char + 1);
|
$e_name = $this->characters('0-9A-Za-z;', $this->char + 1);
|
||||||
$len = strlen($e_name);
|
$len = strlen($e_name);
|
||||||
|
|
||||||
@@ -1534,7 +1535,7 @@ class HTML5
|
|||||||
}
|
}
|
||||||
|
|
||||||
$cond = isset($entity);
|
$cond = isset($entity);
|
||||||
// The rest of the parsing happens bellow.
|
// The rest of the parsing happens below.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1547,7 +1548,7 @@ class HTML5
|
|||||||
|
|
||||||
// Return a character token for the character corresponding to the
|
// Return a character token for the character corresponding to the
|
||||||
// entity name (as given by the second column of the entities table).
|
// entity name (as given by the second column of the entities table).
|
||||||
return html_entity_decode('&' . $entity . ';', ENT_QUOTES, 'UTF-8');
|
return html_entity_decode('&' . rtrim($entity, ';') . ';', ENT_QUOTES, 'UTF-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function emitToken($token)
|
private function emitToken($token)
|
||||||
|
@@ -48,7 +48,7 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
|
|||||||
$this->compress = $compress;
|
$this->compress = $compress;
|
||||||
// initialize sub-printers
|
// initialize sub-printers
|
||||||
$this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default();
|
$this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default();
|
||||||
$this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool();
|
$this->fields[HTMLPurifier_VarParser::C_BOOL] = new HTMLPurifier_Printer_ConfigForm_bool();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -339,7 +339,7 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer
|
|||||||
$value = '';
|
$value = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($type === HTMLPurifier_VarParser::MIXED) {
|
if ($type === HTMLPurifier_VarParser::C_MIXED) {
|
||||||
return 'Not supported';
|
return 'Not supported';
|
||||||
$value = serialize($value);
|
$value = serialize($value);
|
||||||
}
|
}
|
||||||
|
@@ -165,7 +165,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
|
|||||||
if (empty($zipper->front)) break;
|
if (empty($zipper->front)) break;
|
||||||
$token = $zipper->prev($token);
|
$token = $zipper->prev($token);
|
||||||
// indicate that other injectors should not process this token,
|
// indicate that other injectors should not process this token,
|
||||||
// but we need to reprocess it
|
// but we need to reprocess it. See Note [Injector skips]
|
||||||
unset($token->skip[$i]);
|
unset($token->skip[$i]);
|
||||||
$token->rewind = $i;
|
$token->rewind = $i;
|
||||||
if ($token instanceof HTMLPurifier_Token_Start) {
|
if ($token instanceof HTMLPurifier_Token_Start) {
|
||||||
@@ -210,6 +210,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
|
|||||||
if ($token instanceof HTMLPurifier_Token_Text) {
|
if ($token instanceof HTMLPurifier_Token_Text) {
|
||||||
foreach ($this->injectors as $i => $injector) {
|
foreach ($this->injectors as $i => $injector) {
|
||||||
if (isset($token->skip[$i])) {
|
if (isset($token->skip[$i])) {
|
||||||
|
// See Note [Injector skips]
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($token->rewind !== null && $token->rewind !== $i) {
|
if ($token->rewind !== null && $token->rewind !== $i) {
|
||||||
@@ -367,6 +368,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
|
|||||||
if ($ok) {
|
if ($ok) {
|
||||||
foreach ($this->injectors as $i => $injector) {
|
foreach ($this->injectors as $i => $injector) {
|
||||||
if (isset($token->skip[$i])) {
|
if (isset($token->skip[$i])) {
|
||||||
|
// See Note [Injector skips]
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($token->rewind !== null && $token->rewind !== $i) {
|
if ($token->rewind !== null && $token->rewind !== $i) {
|
||||||
@@ -422,6 +424,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
|
|||||||
$token->start = $current_parent;
|
$token->start = $current_parent;
|
||||||
foreach ($this->injectors as $i => $injector) {
|
foreach ($this->injectors as $i => $injector) {
|
||||||
if (isset($token->skip[$i])) {
|
if (isset($token->skip[$i])) {
|
||||||
|
// See Note [Injector skips]
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($token->rewind !== null && $token->rewind !== $i) {
|
if ($token->rewind !== null && $token->rewind !== $i) {
|
||||||
@@ -534,12 +537,17 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
|
|||||||
*/
|
*/
|
||||||
protected function processToken($token, $injector = -1)
|
protected function processToken($token, $injector = -1)
|
||||||
{
|
{
|
||||||
|
// Zend OpCache miscompiles $token = array($token), so
|
||||||
|
// avoid this pattern. See: https://github.com/ezyang/htmlpurifier/issues/108
|
||||||
|
|
||||||
// normalize forms of token
|
// normalize forms of token
|
||||||
if (is_object($token)) {
|
if (is_object($token)) {
|
||||||
$token = array(1, $token);
|
$tmp = $token;
|
||||||
|
$token = array(1, $tmp);
|
||||||
}
|
}
|
||||||
if (is_int($token)) {
|
if (is_int($token)) {
|
||||||
$token = array($token);
|
$tmp = $token;
|
||||||
|
$token = array($tmp);
|
||||||
}
|
}
|
||||||
if ($token === false) {
|
if ($token === false) {
|
||||||
$token = array(1);
|
$token = array(1);
|
||||||
@@ -561,7 +569,12 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
|
|||||||
list($old, $r) = $this->zipper->splice($this->token, $delete, $token);
|
list($old, $r) = $this->zipper->splice($this->token, $delete, $token);
|
||||||
|
|
||||||
if ($injector > -1) {
|
if ($injector > -1) {
|
||||||
// determine appropriate skips
|
// See Note [Injector skips]
|
||||||
|
// Determine appropriate skips. Here's what the code does:
|
||||||
|
// *If* we deleted one or more tokens, copy the skips
|
||||||
|
// of those tokens into the skips of the new tokens (in $token).
|
||||||
|
// Also, mark the newly inserted tokens as having come from
|
||||||
|
// $injector.
|
||||||
$oldskip = isset($old[0]) ? $old[0]->skip : array();
|
$oldskip = isset($old[0]) ? $old[0]->skip : array();
|
||||||
foreach ($token as $object) {
|
foreach ($token as $object) {
|
||||||
$object->skip = $oldskip;
|
$object->skip = $oldskip;
|
||||||
@@ -597,4 +610,50 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note [Injector skips]
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// When I originally designed this class, the idea behind the 'skip'
|
||||||
|
// property of HTMLPurifier_Token was to help avoid infinite loops
|
||||||
|
// in injector processing. For example, suppose you wrote an injector
|
||||||
|
// that bolded swear words. Naively, you might write it so that
|
||||||
|
// whenever you saw ****, you replaced it with <strong>****</strong>.
|
||||||
|
//
|
||||||
|
// When this happens, we will reprocess all of the tokens with the
|
||||||
|
// other injectors. Now there is an opportunity for infinite loop:
|
||||||
|
// if we rerun the swear-word injector on these tokens, we might
|
||||||
|
// see **** and then reprocess again to get
|
||||||
|
// <strong><strong>****</strong></strong> ad infinitum.
|
||||||
|
//
|
||||||
|
// Thus, the idea of a skip is that once we process a token with
|
||||||
|
// an injector, we mark all of those tokens as having "come from"
|
||||||
|
// the injector, and we never run the injector again on these
|
||||||
|
// tokens.
|
||||||
|
//
|
||||||
|
// There were two more complications, however:
|
||||||
|
//
|
||||||
|
// - With HTMLPurifier_Injector_RemoveEmpty, we noticed that if
|
||||||
|
// you had <b><i></i></b>, after you removed the <i></i>, you
|
||||||
|
// really would like this injector to go back and reprocess
|
||||||
|
// the <b> tag, discovering that it is now empty and can be
|
||||||
|
// removed. So we reintroduced the possibility of infinite looping
|
||||||
|
// by adding a "rewind" function, which let you go back to an
|
||||||
|
// earlier point in the token stream and reprocess it with injectors.
|
||||||
|
// Needless to say, we need to UN-skip the token so it gets
|
||||||
|
// reprocessed.
|
||||||
|
//
|
||||||
|
// - Suppose that you successfuly process a token, replace it with
|
||||||
|
// one with your skip mark, but now another injector wants to
|
||||||
|
// process the skipped token with another token. Should you continue
|
||||||
|
// to skip that new token, or reprocess it? If you reprocess,
|
||||||
|
// you can end up with an infinite loop where one injector converts
|
||||||
|
// <a> to <b>, and then another injector converts it back. So
|
||||||
|
// we inherit the skips, but for some reason, I thought that we
|
||||||
|
// should inherit the skip from the first token of the token
|
||||||
|
// that we deleted. Why? Well, it seems to work OK.
|
||||||
|
//
|
||||||
|
// If I were to redesign this functionality, I would absolutely not
|
||||||
|
// go about doing it this way: the semantics are just not very well
|
||||||
|
// defined, and in any case you probably wanted to operate on trees,
|
||||||
|
// not token streams.
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
@@ -26,7 +26,7 @@ abstract class HTMLPurifier_Token
|
|||||||
public $armor = array();
|
public $armor = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used during MakeWellFormed.
|
* Used during MakeWellFormed. See Note [Injector skips]
|
||||||
* @type
|
* @type
|
||||||
*/
|
*/
|
||||||
public $skip;
|
public $skip;
|
||||||
|
@@ -85,11 +85,13 @@ class HTMLPurifier_URI
|
|||||||
$def = $config->getDefinition('URI');
|
$def = $config->getDefinition('URI');
|
||||||
$scheme_obj = $def->getDefaultScheme($config, $context);
|
$scheme_obj = $def->getDefaultScheme($config, $context);
|
||||||
if (!$scheme_obj) {
|
if (!$scheme_obj) {
|
||||||
// something funky happened to the default scheme object
|
if ($def->defaultScheme !== null) {
|
||||||
trigger_error(
|
// something funky happened to the default scheme object
|
||||||
'Default scheme object "' . $def->defaultScheme . '" was not readable',
|
trigger_error(
|
||||||
E_USER_WARNING
|
'Default scheme object "' . $def->defaultScheme . '" was not readable',
|
||||||
);
|
E_USER_WARNING
|
||||||
|
);
|
||||||
|
} // suppress error if it's null
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,34 +7,34 @@
|
|||||||
class HTMLPurifier_VarParser
|
class HTMLPurifier_VarParser
|
||||||
{
|
{
|
||||||
|
|
||||||
const STRING = 1;
|
const C_STRING = 1;
|
||||||
const ISTRING = 2;
|
const ISTRING = 2;
|
||||||
const TEXT = 3;
|
const TEXT = 3;
|
||||||
const ITEXT = 4;
|
const ITEXT = 4;
|
||||||
const INT = 5;
|
const C_INT = 5;
|
||||||
const FLOAT = 6;
|
const C_FLOAT = 6;
|
||||||
const BOOL = 7;
|
const C_BOOL = 7;
|
||||||
const LOOKUP = 8;
|
const LOOKUP = 8;
|
||||||
const ALIST = 9;
|
const ALIST = 9;
|
||||||
const HASH = 10;
|
const HASH = 10;
|
||||||
const MIXED = 11;
|
const C_MIXED = 11;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup table of allowed types. Mainly for backwards compatibility, but
|
* Lookup table of allowed types. Mainly for backwards compatibility, but
|
||||||
* also convenient for transforming string type names to the integer constants.
|
* also convenient for transforming string type names to the integer constants.
|
||||||
*/
|
*/
|
||||||
public static $types = array(
|
public static $types = array(
|
||||||
'string' => self::STRING,
|
'string' => self::C_STRING,
|
||||||
'istring' => self::ISTRING,
|
'istring' => self::ISTRING,
|
||||||
'text' => self::TEXT,
|
'text' => self::TEXT,
|
||||||
'itext' => self::ITEXT,
|
'itext' => self::ITEXT,
|
||||||
'int' => self::INT,
|
'int' => self::C_INT,
|
||||||
'float' => self::FLOAT,
|
'float' => self::C_FLOAT,
|
||||||
'bool' => self::BOOL,
|
'bool' => self::C_BOOL,
|
||||||
'lookup' => self::LOOKUP,
|
'lookup' => self::LOOKUP,
|
||||||
'list' => self::ALIST,
|
'list' => self::ALIST,
|
||||||
'hash' => self::HASH,
|
'hash' => self::HASH,
|
||||||
'mixed' => self::MIXED
|
'mixed' => self::C_MIXED
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +42,7 @@ class HTMLPurifier_VarParser
|
|||||||
* allowed value lists.
|
* allowed value lists.
|
||||||
*/
|
*/
|
||||||
public static $stringTypes = array(
|
public static $stringTypes = array(
|
||||||
self::STRING => true,
|
self::C_STRING => true,
|
||||||
self::ISTRING => true,
|
self::ISTRING => true,
|
||||||
self::TEXT => true,
|
self::TEXT => true,
|
||||||
self::ITEXT => true,
|
self::ITEXT => true,
|
||||||
@@ -74,7 +74,7 @@ class HTMLPurifier_VarParser
|
|||||||
// These are basic checks, to make sure nothing horribly wrong
|
// These are basic checks, to make sure nothing horribly wrong
|
||||||
// happened in our implementations.
|
// happened in our implementations.
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case (self::STRING):
|
case (self::C_STRING):
|
||||||
case (self::ISTRING):
|
case (self::ISTRING):
|
||||||
case (self::TEXT):
|
case (self::TEXT):
|
||||||
case (self::ITEXT):
|
case (self::ITEXT):
|
||||||
@@ -85,17 +85,17 @@ class HTMLPurifier_VarParser
|
|||||||
$var = strtolower($var);
|
$var = strtolower($var);
|
||||||
}
|
}
|
||||||
return $var;
|
return $var;
|
||||||
case (self::INT):
|
case (self::C_INT):
|
||||||
if (!is_int($var)) {
|
if (!is_int($var)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return $var;
|
return $var;
|
||||||
case (self::FLOAT):
|
case (self::C_FLOAT):
|
||||||
if (!is_float($var)) {
|
if (!is_float($var)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return $var;
|
return $var;
|
||||||
case (self::BOOL):
|
case (self::C_BOOL):
|
||||||
if (!is_bool($var)) {
|
if (!is_bool($var)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ class HTMLPurifier_VarParser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $var;
|
return $var;
|
||||||
case (self::MIXED):
|
case (self::C_MIXED):
|
||||||
return $var;
|
return $var;
|
||||||
default:
|
default:
|
||||||
$this->errorInconsistent(get_class($this), $type);
|
$this->errorInconsistent(get_class($this), $type);
|
||||||
|
@@ -23,23 +23,23 @@ class HTMLPurifier_VarParser_Flexible extends HTMLPurifier_VarParser
|
|||||||
// Note: if code "breaks" from the switch, it triggers a generic
|
// Note: if code "breaks" from the switch, it triggers a generic
|
||||||
// exception to be thrown. Specific errors can be specifically
|
// exception to be thrown. Specific errors can be specifically
|
||||||
// done here.
|
// done here.
|
||||||
case self::MIXED:
|
case self::C_MIXED:
|
||||||
case self::ISTRING:
|
case self::ISTRING:
|
||||||
case self::STRING:
|
case self::C_STRING:
|
||||||
case self::TEXT:
|
case self::TEXT:
|
||||||
case self::ITEXT:
|
case self::ITEXT:
|
||||||
return $var;
|
return $var;
|
||||||
case self::INT:
|
case self::C_INT:
|
||||||
if (is_string($var) && ctype_digit($var)) {
|
if (is_string($var) && ctype_digit($var)) {
|
||||||
$var = (int)$var;
|
$var = (int)$var;
|
||||||
}
|
}
|
||||||
return $var;
|
return $var;
|
||||||
case self::FLOAT:
|
case self::C_FLOAT:
|
||||||
if ((is_string($var) && is_numeric($var)) || is_int($var)) {
|
if ((is_string($var) && is_numeric($var)) || is_int($var)) {
|
||||||
$var = (float)$var;
|
$var = (float)$var;
|
||||||
}
|
}
|
||||||
return $var;
|
return $var;
|
||||||
case self::BOOL:
|
case self::C_BOOL:
|
||||||
if (is_int($var) && ($var === 0 || $var === 1)) {
|
if (is_int($var) && ($var === 0 || $var === 1)) {
|
||||||
$var = (bool)$var;
|
$var = (bool)$var;
|
||||||
} elseif (is_string($var)) {
|
} elseif (is_string($var)) {
|
||||||
|
@@ -1 +1,7 @@
|
|||||||
Deny from all
|
<IfModule mod_authz_core.c>
|
||||||
|
Require all denied
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_authz_core.c>
|
||||||
|
Deny from all
|
||||||
|
</ifModule>
|
||||||
|
@@ -1080,7 +1080,7 @@ class HTML5
|
|||||||
$entity = $this->character($start, $this->char);
|
$entity = $this->character($start, $this->char);
|
||||||
$cond = strlen($e_name) > 0;
|
$cond = strlen($e_name) > 0;
|
||||||
|
|
||||||
// The rest of the parsing happens bellow.
|
// The rest of the parsing happens below.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Anything else
|
// Anything else
|
||||||
@@ -1102,7 +1102,7 @@ class HTML5
|
|||||||
}
|
}
|
||||||
|
|
||||||
$cond = isset($entity);
|
$cond = isset($entity);
|
||||||
// The rest of the parsing happens bellow.
|
// The rest of the parsing happens below.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,30 +0,0 @@
|
|||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
chdir(dirname(__FILE__));
|
|
||||||
require_once 'common.php';
|
|
||||||
assertCli();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Runs all generation/flush cache scripts to ensure that somewhat volatile
|
|
||||||
* generated files are up-to-date.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function e($cmd)
|
|
||||||
{
|
|
||||||
echo "\$ $cmd\n";
|
|
||||||
passthru($cmd, $status);
|
|
||||||
echo "\n";
|
|
||||||
if ($status) exit($status);
|
|
||||||
}
|
|
||||||
|
|
||||||
$php = empty($_SERVER['argv'][1]) ? 'php' : $_SERVER['argv'][1];
|
|
||||||
|
|
||||||
e($php . ' generate-includes.php');
|
|
||||||
e($php . ' generate-schema-cache.php');
|
|
||||||
e($php . ' flush-definition-cache.php');
|
|
||||||
e($php . ' generate-standalone.php');
|
|
||||||
e($php . ' config-scanner.php');
|
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
|
8
maintenance/flush.sh
Executable file
8
maintenance/flush.sh
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -ex
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||||
|
php "$DIR/generate-includes.php"
|
||||||
|
php "$DIR/generate-schema-cache.php"
|
||||||
|
php "$DIR/flush-definition-cache.php"
|
||||||
|
php "$DIR/generate-standalone.php"
|
||||||
|
php "$DIR/config-scanner.php"
|
@@ -1,34 +0,0 @@
|
|||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
chdir(dirname(__FILE__));
|
|
||||||
require_once 'common.php';
|
|
||||||
assertCli();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Converts all instances of $config->set and $config->get to the new
|
|
||||||
* format, as described by docs/dev-config-bcbreaks.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
$FS = new FSTools();
|
|
||||||
chdir(dirname(__FILE__) . '/..');
|
|
||||||
$raw_files = $FS->globr('.', '*.php');
|
|
||||||
foreach ($raw_files as $file) {
|
|
||||||
$file = substr($file, 2); // rm leading './'
|
|
||||||
if (strpos($file, 'library/standalone/') === 0) continue;
|
|
||||||
if (strpos($file, 'maintenance/update-config.php') === 0) continue;
|
|
||||||
if (strpos($file, 'test-settings.php') === 0) continue;
|
|
||||||
if (substr_count($file, '.') > 1) continue; // rm meta files
|
|
||||||
// process the file
|
|
||||||
$contents = file_get_contents($file);
|
|
||||||
$contents = preg_replace(
|
|
||||||
"#config->(set|get)\('(.+?)', '(.+?)'#",
|
|
||||||
"config->\\1('\\2.\\3'",
|
|
||||||
$contents
|
|
||||||
);
|
|
||||||
if ($contents === '') continue;
|
|
||||||
file_put_contents($file, $contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
|
@@ -53,5 +53,6 @@ $config->set('Core.Encoding', $GLOBALS['PHORUM']['DATA']['CHARSET']); // we'll c
|
|||||||
if (strtolower($GLOBALS['PHORUM']['DATA']['CHARSET']) !== 'utf-8') {
|
if (strtolower($GLOBALS['PHORUM']['DATA']['CHARSET']) !== 'utf-8') {
|
||||||
$config->set('Core.EscapeNonASCIICharacters', true);
|
$config->set('Core.EscapeNonASCIICharacters', true);
|
||||||
}
|
}
|
||||||
|
$config->set('Core.AllowParseManyTags', false);
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// Tags releases
|
|
||||||
|
|
||||||
if (php_sapi_name() != 'cli') {
|
|
||||||
echo 'Release script cannot be called from web-browser.';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
require 'svn.php';
|
|
||||||
|
|
||||||
$svn_info = my_svn_info('.');
|
|
||||||
|
|
||||||
$version = trim(file_get_contents('VERSION'));
|
|
||||||
|
|
||||||
$trunk_url = $svn_info['Repository Root'] . '/htmlpurifier/trunk';
|
|
||||||
$trunk_tag_url = $svn_info['Repository Root'] . '/htmlpurifier/tags/' . $version;
|
|
||||||
|
|
||||||
echo "Tagging trunk to tags/$version...";
|
|
||||||
passthru("svn copy --message \"Tag $version release.\" $trunk_url $trunk_tag_url");
|
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
|
@@ -1,5 +1,5 @@
|
|||||||
Type.mixed
|
Type.mixed
|
||||||
TYPE: mixed
|
TYPE: mixed
|
||||||
DEFAULT: new stdclass()
|
DEFAULT: new stdClass()
|
||||||
DESCRIPTION: The mixed type allows any type, and is not form-editable.
|
DESCRIPTION: The mixed type allows any type, and is not form-editable.
|
||||||
--# vim: et sw=4 sts=4
|
--# vim: et sw=4 sts=4
|
||||||
|
72
test-settings.travis.php
Normal file
72
test-settings.travis.php
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is the configuration for Travis testing.
|
||||||
|
|
||||||
|
// Note: The only external library you *need* is SimpleTest; everything else
|
||||||
|
// is optional.
|
||||||
|
|
||||||
|
// We've got a lot of tests, so we recommend turning the limit off.
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
|
// Turning off output buffering will prevent mysterious errors from core dumps.
|
||||||
|
$data = @ob_get_clean();
|
||||||
|
if ($data !== false && $data !== '') {
|
||||||
|
echo "Output buffer contains data [".urlencode($data)."]\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// REQUIRED SETTINGS
|
||||||
|
|
||||||
|
// Note on running SimpleTest:
|
||||||
|
// You want the Git copy of SimpleTest, found here:
|
||||||
|
// https://github.com/simpletest/simpletest/
|
||||||
|
//
|
||||||
|
// If SimpleTest is borked with HTML Purifier, please contact me or
|
||||||
|
// the SimpleTest devs; I am a developer for SimpleTest so I should be
|
||||||
|
// able to quickly assess a fix. SimpleTest's problem is my problem!
|
||||||
|
|
||||||
|
// Where is SimpleTest located? Remember to include a trailing slash!
|
||||||
|
$simpletest_location = dirname(__FILE__) . '/simpletest/';
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// OPTIONAL SETTINGS
|
||||||
|
|
||||||
|
// Note on running PHPT:
|
||||||
|
// Vanilla PHPT from https://github.com/tswicegood/PHPT_Core should
|
||||||
|
// work fine on Linux w/o multitest.
|
||||||
|
//
|
||||||
|
// To do multitest or Windows testing, you'll need some more
|
||||||
|
// patches at https://github.com/ezyang/PHPT_Core
|
||||||
|
//
|
||||||
|
// I haven't tested the Windows setup in a while so I don't know if
|
||||||
|
// it still works.
|
||||||
|
|
||||||
|
// Should PHPT tests be enabled?
|
||||||
|
$GLOBALS['HTMLPurifierTest']['PHPT'] = false;
|
||||||
|
|
||||||
|
// If PHPT isn't in your Path via PEAR, set that here:
|
||||||
|
// set_include_path('/path/to/phpt/Core/src' . PATH_SEPARATOR . get_include_path());
|
||||||
|
|
||||||
|
// Where is CSSTidy located? (Include trailing slash. Leave false to disable.)
|
||||||
|
$csstidy_location = false;
|
||||||
|
|
||||||
|
// For tests/multitest.php, which versions to test?
|
||||||
|
$versions_to_test = array();
|
||||||
|
|
||||||
|
// Stable PHP binary to use when invoking maintenance scripts.
|
||||||
|
$php = 'php';
|
||||||
|
|
||||||
|
// For tests/multitest.php, what is the multi-version executable? It must
|
||||||
|
// accept an extra parameter (version number) before all other arguments
|
||||||
|
$phpv = false;
|
||||||
|
|
||||||
|
// Should PEAR tests be run? If you've got a valid PEAR installation, set this
|
||||||
|
// to true (or, if it's not in the include path, to its install directory).
|
||||||
|
$GLOBALS['HTMLPurifierTest']['PEAR'] = false;
|
||||||
|
|
||||||
|
// If PEAR is enabled, what PEAR tests should be run? (Note: you will
|
||||||
|
// need to ensure these libraries are installed)
|
||||||
|
$GLOBALS['HTMLPurifierTest']['Net_IDNA2'] = true;
|
||||||
|
|
||||||
|
// vim: et sw=4 sts=4
|
@@ -12,12 +12,18 @@ class HTMLPurifier_AttrDef_CSS_BackgroundTest extends HTMLPurifier_AttrDefHarnes
|
|||||||
$this->assertDef($valid);
|
$this->assertDef($valid);
|
||||||
$this->assertDef('url(\'chess.png\') #333 50% top repeat fixed', $valid);
|
$this->assertDef('url(\'chess.png\') #333 50% top repeat fixed', $valid);
|
||||||
$this->assertDef(
|
$this->assertDef(
|
||||||
'rgb(34, 56, 33) url(chess.png) repeat fixed top',
|
'rgb(34%, 56%, 33%) url(chess.png) repeat fixed top',
|
||||||
'rgb(34,56,33) url("chess.png") repeat fixed top'
|
'rgb(34%,56%,33%) url("chess.png") repeat fixed top'
|
||||||
|
);
|
||||||
|
$this->assertDef(
|
||||||
|
'rgba(74, 12, 85, 0.35) repeat fixed bottom',
|
||||||
|
'rgba(74,12,85,.35) repeat fixed bottom'
|
||||||
|
);
|
||||||
|
$this->assertDef(
|
||||||
|
'hsl(244, 47.4%, 88.1%) right center',
|
||||||
|
'hsl(244,47.4%,88.1%) right center'
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
@@ -11,13 +11,33 @@ class HTMLPurifier_AttrDef_CSS_ColorTest extends HTMLPurifier_AttrDefHarness
|
|||||||
$this->assertDef('#fff');
|
$this->assertDef('#fff');
|
||||||
$this->assertDef('#eeeeee');
|
$this->assertDef('#eeeeee');
|
||||||
$this->assertDef('#808080');
|
$this->assertDef('#808080');
|
||||||
|
|
||||||
$this->assertDef('rgb(255, 0, 0)', 'rgb(255,0,0)'); // rm spaces
|
$this->assertDef('rgb(255, 0, 0)', 'rgb(255,0,0)'); // rm spaces
|
||||||
$this->assertDef('rgb(100%,0%,0%)');
|
$this->assertDef('rgb(100%,0%,0%)');
|
||||||
$this->assertDef('rgb(50.5%,23.2%,43.9%)'); // decimals okay
|
$this->assertDef('rgb(50.5%,23.2%,43.9%)'); // decimals okay
|
||||||
|
$this->assertDef('rgb(-5,0,0)', 'rgb(0,0,0)'); // negative values
|
||||||
|
$this->assertDef('rgb(295,0,0)', 'rgb(255,0,0)'); // max values
|
||||||
|
$this->assertDef('rgb(12%,150%,0%)', 'rgb(12%,100%,0%)'); // percentage max values
|
||||||
|
|
||||||
|
$this->assertDef('rgba(255, 0, 0, 0)', 'rgba(255,0,0,0)'); // rm spaces
|
||||||
|
$this->assertDef('rgba(100%,0%,0%,.4)');
|
||||||
|
$this->assertDef('rgba(38.1%,59.7%,1.8%,0.7)', 'rgba(38.1%,59.7%,1.8%,.7)'); // decimals okay
|
||||||
|
|
||||||
|
$this->assertDef('hsl(275, 45%, 81%)', 'hsl(275,45%,81%)'); // rm spaces
|
||||||
|
$this->assertDef('hsl(100,0%,0%)');
|
||||||
|
$this->assertDef('hsl(38,59.7%,1.8%)', 'hsl(38,59.7%,1.8%)'); // decimals okay
|
||||||
|
$this->assertDef('hsl(-11,-15%,25%)', 'hsl(0,0%,25%)'); // negative values
|
||||||
|
$this->assertDef('hsl(380,125%,0%)', 'hsl(360,100%,0%)'); // max values
|
||||||
|
|
||||||
|
$this->assertDef('hsla(100, 74%, 29%, 0)', 'hsla(100,74%,29%,0)'); // rm spaces
|
||||||
|
$this->assertDef('hsla(154,87%,21%,.4)');
|
||||||
|
$this->assertDef('hsla(45,94.3%,4.1%,0.7)', 'hsla(45,94.3%,4.1%,.7)'); // decimals okay
|
||||||
|
|
||||||
$this->assertDef('#G00', false);
|
$this->assertDef('#G00', false);
|
||||||
$this->assertDef('cmyk(40, 23, 43, 23)', false);
|
$this->assertDef('cmyk(40, 23, 43, 23)', false);
|
||||||
$this->assertDef('rgb(0%, 23, 68%)', false);
|
$this->assertDef('rgb(0%, 23, 68%)', false); // no mixed type
|
||||||
|
$this->assertDef('rgb(231, 144, 28.2%)', false); // no mixed type
|
||||||
|
$this->assertDef('hsl(18%,12%,89%)', false); // integer, percentage, percentage
|
||||||
|
|
||||||
// clip numbers outside sRGB gamut
|
// clip numbers outside sRGB gamut
|
||||||
$this->assertDef('rgb(200%, -10%, 0%)', 'rgb(100%,0%,0%)');
|
$this->assertDef('rgb(200%, -10%, 0%)', 'rgb(100%,0%,0%)');
|
||||||
|
@@ -27,6 +27,7 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
|
|||||||
$this->assertDef('background-color:rgb(0,0,255);');
|
$this->assertDef('background-color:rgb(0,0,255);');
|
||||||
$this->assertDef('background-color:transparent;');
|
$this->assertDef('background-color:transparent;');
|
||||||
$this->assertDef('background:#333 url("chess.png") repeat fixed 50% top;');
|
$this->assertDef('background:#333 url("chess.png") repeat fixed 50% top;');
|
||||||
|
$this->assertDef('background:#333 url("che;ss.png") repeat fixed 50% top;');
|
||||||
$this->assertDef('color:#F00;');
|
$this->assertDef('color:#F00;');
|
||||||
$this->assertDef('border-top-color:#F00;');
|
$this->assertDef('border-top-color:#F00;');
|
||||||
$this->assertDef('border-color:#F00 #FF0;');
|
$this->assertDef('border-color:#F00 #FF0;');
|
||||||
@@ -61,6 +62,16 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
|
|||||||
$this->assertDef('width:50px;');
|
$this->assertDef('width:50px;');
|
||||||
$this->assertDef('width:auto;');
|
$this->assertDef('width:auto;');
|
||||||
$this->assertDef('width:-50px;', false);
|
$this->assertDef('width:-50px;', false);
|
||||||
|
$this->assertDef('min-width:50%;');
|
||||||
|
$this->assertDef('min-width:50px;');
|
||||||
|
$this->assertDef('min-width:auto;', false);
|
||||||
|
$this->assertDef('min-width:initial;');
|
||||||
|
$this->assertDef('min-width:inherit;');
|
||||||
|
$this->assertDef('min-width:-50px;', false);
|
||||||
|
$this->assertDef('min-width:50ch;');
|
||||||
|
$this->assertDef('min-width:50rem;');
|
||||||
|
$this->assertDef('min-width:50vw;');
|
||||||
|
$this->assertDef('min-width:-50vw;', false);
|
||||||
$this->assertDef('text-decoration:underline;');
|
$this->assertDef('text-decoration:underline;');
|
||||||
$this->assertDef('font-family:sans-serif;');
|
$this->assertDef('font-family:sans-serif;');
|
||||||
$this->assertDef("font-family:Gill, 'Times New Roman', sans-serif;");
|
$this->assertDef("font-family:Gill, 'Times New Roman', sans-serif;");
|
||||||
|
@@ -38,7 +38,7 @@ class HTMLPurifier_AttrDef_URI_HostTest extends HTMLPurifier_AttrDefHarness
|
|||||||
$this->assertDef('f-.top', false);
|
$this->assertDef('f-.top', false);
|
||||||
$this->assertDef('1a');
|
$this->assertDef('1a');
|
||||||
|
|
||||||
$this->assertDef("\xE4\xB8\xAD\xE6\x96\x87.com.cn", false);
|
$this->assertDef("\xE4\xB8\xAD\xE6\x96\x87.com.cn", 'xn--fiq228c.com.cn', true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +49,7 @@ class HTMLPurifier_AttrDef_URI_HostTest extends HTMLPurifier_AttrDefHarness
|
|||||||
}
|
}
|
||||||
$this->config->set('Core.EnableIDNA', true);
|
$this->config->set('Core.EnableIDNA', true);
|
||||||
$this->assertDef("\xE4\xB8\xAD\xE6\x96\x87.com.cn", "xn--fiq228c.com.cn");
|
$this->assertDef("\xE4\xB8\xAD\xE6\x96\x87.com.cn", "xn--fiq228c.com.cn");
|
||||||
|
$this->assertDef("faß.de", "xn--fa-hia.de");
|
||||||
$this->assertDef("\xe2\x80\x85.com", false); // rejected
|
$this->assertDef("\xe2\x80\x85.com", false); // rejected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -81,6 +81,12 @@ class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
|
|||||||
$this->assertDef('http://example.com/foo/bar');
|
$this->assertDef('http://example.com/foo/bar');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDefaultSchemeNull()
|
||||||
|
{
|
||||||
|
$this->config->set('URI.DefaultScheme', null);
|
||||||
|
$this->assertDef('foo', false);
|
||||||
|
}
|
||||||
|
|
||||||
public function testAltSchemeNotRemoved()
|
public function testAltSchemeNotRemoved()
|
||||||
{
|
{
|
||||||
$this->assertDef('mailto:this-looks-like-a-path@example.com');
|
$this->assertDef('mailto:this-looks-like-a-path@example.com');
|
||||||
|
@@ -13,14 +13,18 @@ class HTMLPurifier_AttrDefHarness extends HTMLPurifier_Harness
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cannot be used for accumulator
|
// cannot be used for accumulator
|
||||||
public function assertDef($string, $expect = true)
|
public function assertDef($string, $expect = true, $or_false = false)
|
||||||
{
|
{
|
||||||
// $expect can be a string or bool
|
// $expect can be a string or bool
|
||||||
$result = $this->def->validate($string, $this->config, $this->context);
|
$result = $this->def->validate($string, $this->config, $this->context);
|
||||||
if ($expect === true) {
|
if ($expect === true) {
|
||||||
$this->assertIdentical($string, $result);
|
if (!($or_false && $result === false)) {
|
||||||
|
$this->assertIdentical($string, $result);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->assertIdentical($expect, $result);
|
if (!($or_false && $result === false)) {
|
||||||
|
$this->assertIdentical($expect, $result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,7 +10,8 @@ class HTMLPurifier_AttrValidator_ErrorsTest extends HTMLPurifier_ErrorsHarness
|
|||||||
$this->language = HTMLPurifier_LanguageFactory::instance()->create($config, $this->context);
|
$this->language = HTMLPurifier_LanguageFactory::instance()->create($config, $this->context);
|
||||||
$this->context->register('Locale', $this->language);
|
$this->context->register('Locale', $this->language);
|
||||||
$this->collector = new HTMLPurifier_ErrorCollector($this->context);
|
$this->collector = new HTMLPurifier_ErrorCollector($this->context);
|
||||||
$this->context->register('Generator', new HTMLPurifier_Generator($config, $this->context));
|
$gen = new HTMLPurifier_Generator($config, $this->context);
|
||||||
|
$this->context->register('Generator', $gen);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function invoke($input)
|
protected function invoke($input)
|
||||||
|
@@ -15,12 +15,12 @@ class HTMLPurifier_ConfigSchemaTest extends HTMLPurifier_Harness
|
|||||||
$this->schema->add('Car.Seats', 5, 'int', false);
|
$this->schema->add('Car.Seats', 5, 'int', false);
|
||||||
|
|
||||||
$this->assertIdentical($this->schema->defaults['Car.Seats'], 5);
|
$this->assertIdentical($this->schema->defaults['Car.Seats'], 5);
|
||||||
$this->assertIdentical($this->schema->info['Car.Seats']->type, HTMLPurifier_VarParser::INT);
|
$this->assertIdentical($this->schema->info['Car.Seats']->type, HTMLPurifier_VarParser::C_INT);
|
||||||
|
|
||||||
$this->schema->add('Car.Age', null, 'int', true);
|
$this->schema->add('Car.Age', null, 'int', true);
|
||||||
|
|
||||||
$this->assertIdentical($this->schema->defaults['Car.Age'], null);
|
$this->assertIdentical($this->schema->defaults['Car.Age'], null);
|
||||||
$this->assertIdentical($this->schema->info['Car.Age']->type, HTMLPurifier_VarParser::INT);
|
$this->assertIdentical($this->schema->info['Car.Age']->type, HTMLPurifier_VarParser::C_INT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ class HTMLPurifier_ConfigSchemaTest extends HTMLPurifier_Harness
|
|||||||
);
|
);
|
||||||
|
|
||||||
$this->assertIdentical($this->schema->defaults['QuantumNumber.Difficulty'], null);
|
$this->assertIdentical($this->schema->defaults['QuantumNumber.Difficulty'], null);
|
||||||
$this->assertIdentical($this->schema->info['QuantumNumber.Difficulty']->type, HTMLPurifier_VarParser::STRING);
|
$this->assertIdentical($this->schema->info['QuantumNumber.Difficulty']->type, HTMLPurifier_VarParser::C_STRING);
|
||||||
$this->assertIdentical($this->schema->info['QuantumNumber.Difficulty']->allow_null, true);
|
$this->assertIdentical($this->schema->info['QuantumNumber.Difficulty']->allow_null, true);
|
||||||
$this->assertIdentical($this->schema->info['QuantumNumber.Difficulty']->allowed,
|
$this->assertIdentical($this->schema->info['QuantumNumber.Difficulty']->allowed,
|
||||||
array(
|
array(
|
||||||
@@ -70,7 +70,7 @@ class HTMLPurifier_ConfigSchemaTest extends HTMLPurifier_Harness
|
|||||||
);
|
);
|
||||||
|
|
||||||
$this->assertIdentical($this->schema->defaults['Abbrev.HTH'], 'Happy to Help');
|
$this->assertIdentical($this->schema->defaults['Abbrev.HTH'], 'Happy to Help');
|
||||||
$this->assertIdentical($this->schema->info['Abbrev.HTH']->type, HTMLPurifier_VarParser::STRING);
|
$this->assertIdentical($this->schema->info['Abbrev.HTH']->type, HTMLPurifier_VarParser::C_STRING);
|
||||||
$this->assertIdentical($this->schema->info['Abbrev.HTH']->allowed,
|
$this->assertIdentical($this->schema->info['Abbrev.HTH']->allowed,
|
||||||
array(
|
array(
|
||||||
'Happy to Help' => true,
|
'Happy to Help' => true,
|
||||||
|
@@ -30,7 +30,8 @@ class HTMLPurifier_DefinitionCacheFactoryTest extends HTMLPurifier_Harness
|
|||||||
$this->factory->addDecorator('Memory');
|
$this->factory->addDecorator('Memory');
|
||||||
$cache = $this->factory->create('Test', $this->config);
|
$cache = $this->factory->create('Test', $this->config);
|
||||||
$cache_real = new HTMLPurifier_DefinitionCache_Decorator_Memory();
|
$cache_real = new HTMLPurifier_DefinitionCache_Decorator_Memory();
|
||||||
$cache_real = $cache_real->decorate(new HTMLPurifier_DefinitionCache_Serializer('Test'));
|
$ser = new HTMLPurifier_DefinitionCache_Serializer('Test');
|
||||||
|
$cache_real = $cache_real->decorate($ser);
|
||||||
$this->assertEqual($cache, $cache_real);
|
$this->assertEqual($cache, $cache_real);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +40,8 @@ class HTMLPurifier_DefinitionCacheFactoryTest extends HTMLPurifier_Harness
|
|||||||
$this->factory->addDecorator(new HTMLPurifier_DefinitionCache_Decorator_Memory());
|
$this->factory->addDecorator(new HTMLPurifier_DefinitionCache_Decorator_Memory());
|
||||||
$cache = $this->factory->create('Test', $this->config);
|
$cache = $this->factory->create('Test', $this->config);
|
||||||
$cache_real = new HTMLPurifier_DefinitionCache_Decorator_Memory();
|
$cache_real = new HTMLPurifier_DefinitionCache_Decorator_Memory();
|
||||||
$cache_real = $cache_real->decorate(new HTMLPurifier_DefinitionCache_Serializer('Test'));
|
$ser = new HTMLPurifier_DefinitionCache_Serializer('Test');
|
||||||
|
$cache_real = $cache_real->decorate($ser);
|
||||||
$this->assertEqual($cache, $cache_real);
|
$this->assertEqual($cache, $cache_real);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,6 +23,7 @@ class HTMLPurifier_EncoderTest extends HTMLPurifier_Harness
|
|||||||
$this->assertCleanUTF8('Normal string.');
|
$this->assertCleanUTF8('Normal string.');
|
||||||
$this->assertCleanUTF8("Test\tAllowed\nControl\rCharacters");
|
$this->assertCleanUTF8("Test\tAllowed\nControl\rCharacters");
|
||||||
$this->assertCleanUTF8("null byte: \0", 'null byte: ');
|
$this->assertCleanUTF8("null byte: \0", 'null byte: ');
|
||||||
|
$this->assertCleanUTF8("あ(い)う(え)お\0", "あ(い)う(え)お"); // test for issue #122
|
||||||
$this->assertCleanUTF8("\1\2\3\4\5\6\7", '');
|
$this->assertCleanUTF8("\1\2\3\4\5\6\7", '');
|
||||||
$this->assertCleanUTF8("\x7F", ''); // one byte invalid SGML char
|
$this->assertCleanUTF8("\x7F", ''); // one byte invalid SGML char
|
||||||
$this->assertCleanUTF8("\xC2\x80", ''); // two byte invalid SGML
|
$this->assertCleanUTF8("\xC2\x80", ''); // two byte invalid SGML
|
||||||
|
@@ -16,8 +16,12 @@ class HTMLPurifier_EntityParserTest extends HTMLPurifier_Harness
|
|||||||
$char_theta = $this->_entity_lookup->table['theta'];
|
$char_theta = $this->_entity_lookup->table['theta'];
|
||||||
$this->assertIdentical($char_theta,
|
$this->assertIdentical($char_theta,
|
||||||
$this->EntityParser->substituteNonSpecialEntities('θ') );
|
$this->EntityParser->substituteNonSpecialEntities('θ') );
|
||||||
|
$this->assertIdentical($char_theta,
|
||||||
|
$this->EntityParser->substituteTextEntities('θ') );
|
||||||
$this->assertIdentical('"',
|
$this->assertIdentical('"',
|
||||||
$this->EntityParser->substituteNonSpecialEntities('"') );
|
$this->EntityParser->substituteNonSpecialEntities('"') );
|
||||||
|
$this->assertIdentical('"',
|
||||||
|
$this->EntityParser->substituteTextEntities('"') );
|
||||||
|
|
||||||
// numeric tests, adapted from Feyd
|
// numeric tests, adapted from Feyd
|
||||||
$args = array();
|
$args = array();
|
||||||
@@ -71,6 +75,11 @@ class HTMLPurifier_EntityParserTest extends HTMLPurifier_Harness
|
|||||||
$expect,
|
$expect,
|
||||||
'Identical expectation [Hex: '. dechex($arg[0]) .']'
|
'Identical expectation [Hex: '. dechex($arg[0]) .']'
|
||||||
);
|
);
|
||||||
|
$this->assertIdentical(
|
||||||
|
$this->EntityParser->substituteTextEntities($string),
|
||||||
|
$expect,
|
||||||
|
'Identical expectation [Hex: '. dechex($arg[0]) .']'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -81,6 +90,10 @@ class HTMLPurifier_EntityParserTest extends HTMLPurifier_Harness
|
|||||||
"'",
|
"'",
|
||||||
$this->EntityParser->substituteSpecialEntities(''')
|
$this->EntityParser->substituteSpecialEntities(''')
|
||||||
);
|
);
|
||||||
|
$this->assertIdentical(
|
||||||
|
"'",
|
||||||
|
$this->EntityParser->substituteTextEntities(''')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -256,6 +256,12 @@ text-align:center
|
|||||||
$this->assertCleanCSS("a .foo #ID div.cl#foo {\nbackground:url(\"http://foo/BAR\")\n}");
|
$this->assertCleanCSS("a .foo #ID div.cl#foo {\nbackground:url(\"http://foo/BAR\")\n}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_extractStyleBlocks_backtracking()
|
||||||
|
{
|
||||||
|
$goo = str_repeat("a", 1000000); // 1M to trigger, sometimes it's less!
|
||||||
|
$this->assertExtractStyleBlocks("<style></style>" . $goo, $goo, array(''));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
@@ -384,6 +384,21 @@ a[href|title]
|
|||||||
$this->config->getHTMLDefinition();
|
$this->config->getHTMLDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_manyNestedTags()
|
||||||
|
{
|
||||||
|
$config = HTMLPurifier_Config::createDefault();
|
||||||
|
$config->set('Core.AllowParseManyTags', true);
|
||||||
|
$purifier = new HTMLPurifier($config);
|
||||||
|
|
||||||
|
$input = 'I am inside a lot of tags';
|
||||||
|
for ($i = 0; $i < 300; $i++) {
|
||||||
|
$input = '<div>' . $input . '</div>';
|
||||||
|
}
|
||||||
|
$output = $purifier->purify($input);
|
||||||
|
|
||||||
|
$this->assertIdentical($input, $output);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
@@ -20,7 +20,15 @@ class HTMLPurifier_HTMLModule_SafeScriptingTest extends HTMLPurifier_HTMLModuleH
|
|||||||
public function testGood()
|
public function testGood()
|
||||||
{
|
{
|
||||||
$this->assertResult(
|
$this->assertResult(
|
||||||
'<script type="text/javascript" src="http://localhost/foo.js" />'
|
'<script type="text/javascript" src="http://localhost/foo.js"></script>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGoodWithAutoclosedTag()
|
||||||
|
{
|
||||||
|
$this->assertResult(
|
||||||
|
'<script type="text/javascript" src="http://localhost/foo.js"/>',
|
||||||
|
'<script type="text/javascript" src="http://localhost/foo.js"></script>'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +38,10 @@ class HTMLPurifier_HTMLModule_SafeScriptingTest extends HTMLPurifier_HTMLModuleH
|
|||||||
'<script type="text/javascript" src="http://localhost/foobar.js" />',
|
'<script type="text/javascript" src="http://localhost/foobar.js" />',
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
|
$this->assertResult(
|
||||||
|
'<script type="text/javascript" src="http://localhost/FOO.JS" />',
|
||||||
|
''
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,14 @@ class HTMLPurifier_HTMLModule_TargetBlankTest extends HTMLPurifier_HTMLModuleHar
|
|||||||
{
|
{
|
||||||
$this->assertResult(
|
$this->assertResult(
|
||||||
'<a href="http://google.com">a</a><a href="/local">b</a><a href="mailto:foo@example.com">c</a>',
|
'<a href="http://google.com">a</a><a href="/local">b</a><a href="mailto:foo@example.com">c</a>',
|
||||||
'<a href="http://google.com" target="_blank" rel="noreferrer">a</a><a href="/local">b</a><a href="mailto:foo@example.com">c</a>'
|
'<a href="http://google.com" target="_blank" rel="noreferrer noopener">a</a><a href="/local">b</a><a href="mailto:foo@example.com">c</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTargetBlankNoDupe() {
|
||||||
|
$this->assertResult(
|
||||||
|
'<a href="http://google.com" target="_blank">a</a>',
|
||||||
|
'<a href="http://google.com" target="_blank" rel="noreferrer noopener">a</a>'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
tests/HTMLPurifier/HTMLModule/TargetNoopenerTest.php
Normal file
51
tests/HTMLPurifier/HTMLModule/TargetNoopenerTest.php
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class HTMLPurifier_HTMLModule_TargetNoopenerTest extends HTMLPurifier_HTMLModuleHarness
|
||||||
|
{
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->config->set('HTML.TargetNoreferrer', false);
|
||||||
|
$this->config->set('HTML.TargetNoopener', true);
|
||||||
|
$this->config->set('Attr.AllowedFrameTargets', '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNoreferrer()
|
||||||
|
{
|
||||||
|
$this->assertResult(
|
||||||
|
'<a href="http://google.com" target="_blank">x</a>',
|
||||||
|
'<a href="http://google.com" target="_blank" rel="noopener">x</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNoreferrerNoDupe()
|
||||||
|
{
|
||||||
|
$this->config->set('Attr.AllowedRel', 'noopener');
|
||||||
|
$this->assertResult(
|
||||||
|
'<a href="http://google.com" target="_blank" rel="noopener">x</a>',
|
||||||
|
'<a href="http://google.com" target="_blank" rel="noopener">x</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTargetBlankNoreferrer()
|
||||||
|
{
|
||||||
|
$this->config->set('HTML.TargetBlank', true);
|
||||||
|
$this->assertResult(
|
||||||
|
'<a href="http://google.com">x</a>',
|
||||||
|
'<a href="http://google.com" target="_blank" rel="noopener">x</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNoTarget()
|
||||||
|
{
|
||||||
|
$this->assertResult(
|
||||||
|
'<a href="http://google.com">x</a>',
|
||||||
|
'<a href="http://google.com">x</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: et sw=4 sts=4
|
@@ -7,6 +7,7 @@ class HTMLPurifier_HTMLModule_TargetNoreferrerTest extends HTMLPurifier_HTMLModu
|
|||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->config->set('HTML.TargetNoreferrer', true);
|
$this->config->set('HTML.TargetNoreferrer', true);
|
||||||
|
$this->config->set('HTML.TargetNoopener', false);
|
||||||
$this->config->set('Attr.AllowedFrameTargets', '_blank');
|
$this->config->set('Attr.AllowedFrameTargets', '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +37,14 @@ class HTMLPurifier_HTMLModule_TargetNoreferrerTest extends HTMLPurifier_HTMLModu
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNoTarget()
|
||||||
|
{
|
||||||
|
$this->assertResult(
|
||||||
|
'<a href="http://google.com">x</a>',
|
||||||
|
'<a href="http://google.com">x</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
7
tests/HTMLPurifier/HTMLT/t78.htmlt
Normal file
7
tests/HTMLPurifier/HTMLT/t78.htmlt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
--INI--
|
||||||
|
HTML.Doctype = HTML 4.01 Strict
|
||||||
|
--HTML--
|
||||||
|
<b>Vetgedrukt</b> <i>Schuingedrukt</i> <span>Hou</span><iframe></iframe><script></script> jij ook zo van vakjesdenken?
|
||||||
|
--EXPECT--
|
||||||
|
<b>Vetgedrukt</b> <i>Schuingedrukt</i> <span>Hou</span> jij ook zo van vakjesdenken?
|
||||||
|
--# vim: et sw=4 sts=4
|
@@ -78,6 +78,11 @@ class HTMLPurifier_Injector_RemoveEmptyTest extends HTMLPurifier_InjectorHarness
|
|||||||
$this->assertResult('<b> </b>', '');
|
$this->assertResult('<b> </b>', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRemoveLi()
|
||||||
|
{
|
||||||
|
$this->assertResult("<ul><li>\n\n\n</li></ul>", '');
|
||||||
|
}
|
||||||
|
|
||||||
public function testDontRemoveNbsp()
|
public function testDontRemoveNbsp()
|
||||||
{
|
{
|
||||||
$this->config->set('AutoFormat.RemoveEmpty.RemoveNbsp', true);
|
$this->config->set('AutoFormat.RemoveEmpty.RemoveNbsp', true);
|
||||||
|
@@ -46,11 +46,11 @@ class HTMLPurifier_LexerTest extends HTMLPurifier_Harness
|
|||||||
|
|
||||||
// HTMLPurifier_Lexer->parseData() -----------------------------------------
|
// HTMLPurifier_Lexer->parseData() -----------------------------------------
|
||||||
|
|
||||||
public function assertParseData($input, $expect = true)
|
public function assertParseData($input, $expect = true, $is_attr = false)
|
||||||
{
|
{
|
||||||
if ($expect === true) $expect = $input;
|
if ($expect === true) $expect = $input;
|
||||||
$lexer = new HTMLPurifier_Lexer();
|
$lexer = new HTMLPurifier_Lexer();
|
||||||
$this->assertIdentical($expect, $lexer->parseData($input));
|
$this->assertIdentical($expect, $lexer->parseData($input, $is_attr, $this->config));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_parseData_plainText()
|
public function test_parseData_plainText()
|
||||||
@@ -95,7 +95,58 @@ class HTMLPurifier_LexerTest extends HTMLPurifier_Harness
|
|||||||
|
|
||||||
public function test_parseData_improperEntityFaultToleranceTest()
|
public function test_parseData_improperEntityFaultToleranceTest()
|
||||||
{
|
{
|
||||||
$this->assertParseData('-');
|
$this->assertParseData('-', '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_parseData_noTrailingSemi()
|
||||||
|
{
|
||||||
|
$this->assertParseData('&A', '&A');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_parseData_noTrailingSemiAttr()
|
||||||
|
{
|
||||||
|
$this->assertParseData('&A', '&A', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_parseData_T119()
|
||||||
|
{
|
||||||
|
$this->assertParseData('&A', '&A', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_parseData_T119b()
|
||||||
|
{
|
||||||
|
$this->assertParseData('&trade=', true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_parseData_legacy1()
|
||||||
|
{
|
||||||
|
$this->config->set('Core.LegacyEntityDecoder', true);
|
||||||
|
$this->assertParseData('&a', true);
|
||||||
|
$this->assertParseData('&=', "&=");
|
||||||
|
$this->assertParseData('&a', true, true);
|
||||||
|
$this->assertParseData('&=', "&=", true);
|
||||||
|
$this->assertParseData('<a', true);
|
||||||
|
$this->assertParseData('<=', "<=");
|
||||||
|
$this->assertParseData('<a', true, true);
|
||||||
|
$this->assertParseData('<=', "<=", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_parseData_nonlegacy1()
|
||||||
|
{
|
||||||
|
$this->assertParseData('&a', "&a");
|
||||||
|
$this->assertParseData('&=', "&=");
|
||||||
|
$this->assertParseData('&a', true, true);
|
||||||
|
$this->assertParseData('&=', true, true);
|
||||||
|
$this->assertParseData('<a', "<a");
|
||||||
|
$this->assertParseData('<=', "<=");
|
||||||
|
$this->assertParseData('<a', true, true);
|
||||||
|
$this->assertParseData('<=', true, true);
|
||||||
|
$this->assertParseData('<a;', "<a;");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_parseData_noTrailingSemiNever()
|
||||||
|
{
|
||||||
|
$this->assertParseData('&imath');
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTMLPurifier_Lexer->extractBody() ---------------------------------------
|
// HTMLPurifier_Lexer->extractBody() ---------------------------------------
|
||||||
@@ -814,13 +865,21 @@ div {}
|
|||||||
public function test_tokenizeHTML_prematureDivClose()
|
public function test_tokenizeHTML_prematureDivClose()
|
||||||
{
|
{
|
||||||
$this->assertTokenization(
|
$this->assertTokenization(
|
||||||
'</div>dontdie',
|
'</div>dont<b>die</b>',
|
||||||
array(
|
array(
|
||||||
new HTMLPurifier_Token_End('div'),
|
new HTMLPurifier_Token_End('div'),
|
||||||
new HTMLPurifier_Token_Text('dontdie')
|
new HTMLPurifier_Token_Text('dont'),
|
||||||
|
new HTMLPurifier_Token_Start('b'),
|
||||||
|
new HTMLPurifier_Token_Text('die'),
|
||||||
|
new HTMLPurifier_Token_End('b'),
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'DOMLex' => $alt = array(new HTMLPurifier_Token_Text('dontdie')),
|
'DOMLex' => $alt = array(
|
||||||
|
new HTMLPurifier_Token_Text('dont'),
|
||||||
|
new HTMLPurifier_Token_Start('b'),
|
||||||
|
new HTMLPurifier_Token_Text('die'),
|
||||||
|
new HTMLPurifier_Token_End('b')
|
||||||
|
),
|
||||||
'PH5P' => $alt
|
'PH5P' => $alt
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@@ -189,7 +189,7 @@ class HTMLPurifier_Strategy_ValidateAttributesTest extends
|
|||||||
{
|
{
|
||||||
$this->config->set('Attr.AllowedFrameTargets', '_top');
|
$this->config->set('Attr.AllowedFrameTargets', '_top');
|
||||||
$this->config->set('HTML.Doctype', 'XHTML 1.0 Transitional');
|
$this->config->set('HTML.Doctype', 'XHTML 1.0 Transitional');
|
||||||
$this->assertResult('<a href="foo" target="_top" rel="noreferrer" />');
|
$this->assertResult('<a href="foo" target="_top" rel="noreferrer noopener" />');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveTargetWhenNotSupported()
|
public function testRemoveTargetWhenNotSupported()
|
||||||
|
@@ -53,7 +53,7 @@ class HTMLPurifier_VarParser_FlexibleTest extends HTMLPurifier_VarParserHarness
|
|||||||
|
|
||||||
public function testValidate_withMagicNumbers()
|
public function testValidate_withMagicNumbers()
|
||||||
{
|
{
|
||||||
$this->assertValid('foobar', HTMLPurifier_VarParser::STRING);
|
$this->assertValid('foobar', HTMLPurifier_VarParser::C_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testValidate_null()
|
public function testValidate_null()
|
||||||
|
@@ -22,6 +22,16 @@ class HTMLPurifierTest extends HTMLPurifier_Harness
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_purifyArray_nested()
|
||||||
|
{
|
||||||
|
$this->assertIdentical(
|
||||||
|
$this->purifier->purifyArray(
|
||||||
|
array('Good', '<b>Sketchy', 'foo' => array('bar' => '<script>bad</script>'))
|
||||||
|
),
|
||||||
|
array('Good', '<b>Sketchy</b>', 'foo' => array('bar' => ''))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testGetInstance()
|
public function testGetInstance()
|
||||||
{
|
{
|
||||||
$purifier = HTMLPurifier::getInstance();
|
$purifier = HTMLPurifier::getInstance();
|
||||||
|
@@ -7,7 +7,7 @@ if (!defined('HTMLPurifierTest')) {
|
|||||||
|
|
||||||
// setup our own autoload, checking for HTMLPurifier library if spl_autoload_register
|
// setup our own autoload, checking for HTMLPurifier library if spl_autoload_register
|
||||||
// is not allowed
|
// is not allowed
|
||||||
function __autoload($class)
|
function test_autoload($class)
|
||||||
{
|
{
|
||||||
if (!function_exists('spl_autoload_register')) {
|
if (!function_exists('spl_autoload_register')) {
|
||||||
if (HTMLPurifier_Bootstrap::autoload($class)) return true;
|
if (HTMLPurifier_Bootstrap::autoload($class)) return true;
|
||||||
@@ -17,7 +17,7 @@ function __autoload($class)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (function_exists('spl_autoload_register')) {
|
if (function_exists('spl_autoload_register')) {
|
||||||
spl_autoload_register('__autoload');
|
spl_autoload_register('test_autoload');
|
||||||
}
|
}
|
||||||
|
|
||||||
// default settings (protect against register_globals)
|
// default settings (protect against register_globals)
|
||||||
|
@@ -33,6 +33,10 @@ error_reporting(E_ALL | E_STRICT);
|
|||||||
// exercises an error condition to detect for it.
|
// exercises an error condition to detect for it.
|
||||||
ini_set('log_errors', false);
|
ini_set('log_errors', false);
|
||||||
|
|
||||||
|
// But make it easier for us to debug if there is some misconfiguration
|
||||||
|
// in the initial setup of the tests.
|
||||||
|
ini_set('display_errors', true);
|
||||||
|
|
||||||
define('HTMLPurifierTest', 1);
|
define('HTMLPurifierTest', 1);
|
||||||
define('HTMLPURIFIER_SCHEMA_STRICT', true); // validate schemas
|
define('HTMLPURIFIER_SCHEMA_STRICT', true); // validate schemas
|
||||||
chdir(dirname(__FILE__));
|
chdir(dirname(__FILE__));
|
||||||
@@ -212,6 +216,12 @@ if ($AC['file']) {
|
|||||||
|
|
||||||
if ($AC['dry']) $reporter->makeDry();
|
if ($AC['dry']) $reporter->makeDry();
|
||||||
|
|
||||||
$test->run($reporter);
|
$result = $test->run($reporter);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
exit(0); // Success!
|
||||||
|
} else {
|
||||||
|
exit(1); // Abject failure.
|
||||||
|
}
|
||||||
|
|
||||||
// vim: et sw=4 sts=4
|
// vim: et sw=4 sts=4
|
||||||
|
@@ -102,7 +102,7 @@ if (!$c) {
|
|||||||
}
|
}
|
||||||
file_put_contents('library/HTMLPurifier/Config.php', $config_c);
|
file_put_contents('library/HTMLPurifier/Config.php', $config_c);
|
||||||
|
|
||||||
passthru('php maintenance/flush.php');
|
passthru('maintenance/flush.sh');
|
||||||
|
|
||||||
if ($is_dev) echo "Review changes, write something in WHATSNEW and FOCUS, and then commit with log 'Release $version.'" . PHP_EOL;
|
if ($is_dev) echo "Review changes, write something in WHATSNEW and FOCUS, and then commit with log 'Release $version.'" . PHP_EOL;
|
||||||
else echo "Numbers updated to dev, no other modifications necessary!";
|
else echo "Numbers updated to dev, no other modifications necessary!";
|
Reference in New Issue
Block a user