1
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2025-08-02 20:27:40 +02:00

Compare commits

...

47 Commits

Author SHA1 Message Date
Edward Z. Yang
d0c392f77d Release 4.8.0
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-07-16 05:58:58 -07:00
Edward Z. Yang
d1c5d75027 Fix #73 with Attr.ID.HTML5
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-07-16 05:52:45 -07:00
Bart Butler
3747cb7efb avoid exif_imagetype exception with small files/corrupt data URI 2016-07-16 05:23:17 -07:00
Edward Z. Yang
0166c3728b Stop trying to chmod if SerializerPermissions is null, fixes #71
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-07-01 16:04:11 -04:00
Edward Z. Yang
ed180f595d Hack to fix #85
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-07-01 15:52:09 -04:00
Edward Z. Yang
3e4deabbb3 New smoketest for testing configuration HTML form.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-07-01 15:50:51 -04:00
Edward Z. Yang
44baee6a82 Partial border-radius support.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-06-30 22:22:13 -04:00
Cameron Ball
1675fc7caf Add %HTML.TargetNoreferrer, which adds rel="noreferrer" when target attribute is set
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-06-30 21:53:43 -04:00
Wes Cossick
cc35c8eb8c tel protocol support. 2016-06-30 21:19:49 -04:00
Edward Z. Yang
a11aeab4a6 Don't suggest 777, only 775.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-27 15:59:10 -07:00
Edward Z. Yang
43a9f052fd Fix #57, make flashvars check (and others) case-insensitive.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-27 15:56:30 -07:00
Edward Z. Yang
b4981c3395 Fix #67, don't use <body> tags in comments for %Core.ConvertDocumentToFragment
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-27 15:19:32 -07:00
Edward Z. Yang
f14076dc3e Fix #49; prevent readdir infinite loop when cache directory not listable.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-27 14:53:31 -07:00
Edward Z. Yang
91fd55c857 Fix #45, errors when ul/ol allowed without li.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-26 22:41:54 -07:00
Rodrigo Prado
096064dd0a Added more info in README 2016-03-24 20:32:54 -07:00
Mike Zukowsky
845edf16e2 Docblock update 2016-03-24 20:26:41 -07:00
Roman Kovalenko
2c4f889ca4 Remove BOM from file INSTALL.fr.utf8 It's only one file with BOM among project 2016-03-24 20:25:58 -07:00
Stefano Torresi
b3856d2040 Export maintenance and path2class scripts in composer.
These scripts could be used in continuously integrated environments
(e.g. `generate-standalone.php`).
2016-03-24 20:24:18 -07:00
Chimpzee
6e00b443cd Bug with tempnam("/tmp", "");
Some hostings have a different temporary path than "/tmp".
2016-03-24 20:19:57 -07:00
Edward Z. Yang
7e49ff3dcd Announce PHP 7 support.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-24 00:14:05 -07:00
Edward Z. Yang
1f3e282fde Fix a bounds error which now errors in PHP 7.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-24 00:13:08 -07:00
Edward Z. Yang
753c830239 Update to work with Git version of SimpleTest.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-24 00:08:03 -07:00
Edward Z. Yang
72123e23c9 Update ExtractStyleBlocks tests for modern CSSTidy at https://github.com/Cerdic/CSSTidy
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-23 23:39:38 -07:00
Edward Z. Yang
45161b4fb1 Accept leading digits in hostnames as per RFC 1123.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-23 22:42:21 -07:00
Synchro
25db9e1dd0 Don't use PHP4-style constructors 2016-03-16 17:09:41 -07:00
Edward Z. Yang
92aabf2b23 Fix #76, linkify includes dots at end of URL.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-02 02:05:54 -08:00
Edward Z. Yang
aebe1c02a2 Use idn_to_ascii when available.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2016-03-02 01:35:07 -08:00
Edward Z. Yang
913ac6955b CSS.AllowDuplicates for duplicate properties.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2015-12-20 11:53:54 -08:00
Edward Z. Yang
958ba65595 Don't truncate alts.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2015-09-29 15:36:53 -07:00
Edward Z. Yang
ae1828d955 Release 4.7.0.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2015-08-04 18:03:42 -07:00
Edward Z. Yang
e34a858ca9 Merge pull request #60 from sylfabre/patch-1
Missing @return
2015-08-03 10:36:45 -07:00
Sylvain
2c963dcc7f Missing @return
Adding PHPDoc @return statement for code completion in IDE
2015-08-03 10:21:47 +02:00
Edward Z. Yang
bfbf8a9da1 Revert "Fix autoloading in Composer."
This reverts commit 04cf6c8739.
2015-06-14 10:57:52 -07:00
Timothée Barray
04cf6c8739 Fix autoloading in Composer.
Per https://getcomposer.org/doc/04-schema.md#psr-0
2015-06-06 20:04:21 -07:00
Edward Z. Yang
0d7328dbb2 s/Include/Inclure/
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2015-05-05 13:43:49 -07:00
anthonybocci
7aeedd9071 Updated translation of installing in french 2015-05-05 10:50:42 -07:00
Edward Z. Yang
c67e4c2f7e All values, including empty, are valid HTML bools.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2015-02-11 16:36:44 -08:00
Edward Z. Yang
0c3e68dd03 Stop using umask to make definition cache. Fixes #32
This is not really the right way to solve the ACL problem,
but there isn't really any reason we should be mucking about
with the umask.

Mucked around with the test case to make it pass, but I think
it's probably a bit delicate now.

Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2014-12-08 18:30:54 -08:00
Jon Dufresne
b307f3d9ef Update gitattributes to produce slimmer packages for composer 2014-10-23 15:36:02 -07:00
Edward Z. Yang
cd60294ada Fix rgb in border attribute with spaces, fixes #30.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2014-08-31 12:12:38 +01:00
Edward Z. Yang
39d3df1fd7 Add AutoFormat.RemoveEmpty.Predicate, fixes #35.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2014-08-31 12:12:17 +01:00
Edward Z. Yang
b8704535a3 Update test.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2014-08-31 11:10:11 +01:00
Edward Z. Yang
4da38aca80 Update YouTube embed code to new style, fixes #28
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2014-08-31 09:30:16 +01:00
Edward Z. Yang
bf84df4f7d Move opacity to tricky. Fixes #16.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2014-08-31 09:24:11 +01:00
Edward Z. Yang
15d1a3003a Don't truncate in DOMLex when seeing closing div
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2014-08-31 08:50:33 +01:00
Edward Z. Yang
80ebd4322e Typo in docs, thanks Soleil Golden for reporting.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2014-02-04 12:17:24 -08:00
Edward Z. Yang
18b8a0e44a Make Composer work with PHP 5.2 and earlier. Reported by @voku
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2013-12-08 15:51:56 -08:00
94 changed files with 907 additions and 432 deletions

13
.gitattributes vendored
View File

@@ -1 +1,12 @@
configdoc/usage.xml -crlf
/.gitattributes export-ignore
/.gitignore export-ignore
/Doxyfile export-ignore
/art/ export-ignore
/benchmarks/ export-ignore
/configdoc/ export-ignore
/configdoc/usage.xml -crlf
/docs/ export-ignore
/phpdoc.ini
/smoketests/ export-ignore
/tests/* export-ignore
/tests/path2class.func.php -export-ignore

View File

@@ -31,7 +31,7 @@ PROJECT_NAME = HTMLPurifier
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 4.6.0
PROJECT_NUMBER = 4.8.0
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.

13
FOCUS
View File

@@ -1,13 +0,0 @@
9 - Major security fixes
[ Appendix A: Release focus IDs ]
0 - N/A
1 - Initial freshmeat announcement
2 - Documentation
3 - Code cleanup
4 - Minor feature enhancements
5 - Major feature enhancements
6 - Minor bugfixes
7 - Major bugfixes
8 - Minor security fixes
9 - Major security fixes

15
INSTALL
View File

@@ -15,10 +15,8 @@ with these contents.
---------------------------------------------------------------------------
1. Compatibility
HTML Purifier is PHP 5 only, and is actively tested from PHP 5.0.5 and
up. It has no core dependencies with other libraries. PHP
4 support was deprecated on December 31, 2007 with HTML Purifier 3.0.0.
HTML Purifier is not compatible with zend.ze1_compatibility_mode.
HTML Purifier is PHP 5 and PHP 7, and is actively tested from PHP 5.0.5
and up. It has no core dependencies with other libraries.
These optional extensions can enhance the capabilities of HTML Purifier:
@@ -29,7 +27,10 @@ These optional extensions can enhance the capabilities of HTML Purifier:
These optional libraries can enhance the capabilities of HTML Purifier:
* CSSTidy : Clean CSS stylesheets using %Core.ExtractStyleBlocks
Note: You should use the modernized fork of CSSTidy available
at https://github.com/Cerdic/CSSTidy
* Net_IDNA2 (PEAR) : IRI support using %Core.EnableIDNA
Note: This is not necessary for PHP 5.3 or later
---------------------------------------------------------------------------
2. Reconnaissance
@@ -305,11 +306,9 @@ appropriate permissions using:
chmod -R 0755 HTMLPurifier/DefinitionCache/Serializer
If the above command doesn't work, you may need to assign write permissions
to all. This may be necessary if your webserver runs as nobody, but is
not recommended since it means any other user can write files in the
directory. Use:
to group:
chmod -R 0777 HTMLPurifier/DefinitionCache/Serializer
chmod -R 0775 HTMLPurifier/DefinitionCache/Serializer
You can also chmod files via your FTP client; this option
is usually accessible by right clicking the corresponding directory and

View File

@@ -1,69 +1,60 @@

Installation
Comment installer HTML Purifier
Attention: Ce document a encode en UTF-8. Si les lettres avec les accents
est essoreuse, prenez un mieux editeur de texte.
À L'Aide: Je ne suis pas un diseur natif de français. Si vous trouvez une
erreur dans ce document, racontez-moi! Merci.
L'installation de HTML Purifier est trés simple, parce qu'il ne doit pas
la configuration. Dans le pied de de document, les utilisateurs
impatient peuvent trouver le code, mais je recommande que vous lisez
ce document pour quelques choses.
Attention : Ce document est encodé en UTF-8, si les lettres avec des accents
ne s'affichent pas, prenez un meilleur éditeur de texte.
L'installation de HTML Purifier est très simple, parce qu'il n'a pas besoin
de configuration. Pour les utilisateurs impatients, le code se trouve dans le
pied de page, mais je recommande de lire le document.
1. Compatibilité
HTML Purifier fonctionne dans PHP 5. PHP 5.0.5 est le dernier
version que je le testais. Il ne dépend de les autre librairies.
HTML Purifier fonctionne avec PHP 5. PHP 5.0.5 est la dernière version testée.
Il ne dépend pas d'autres librairies.
Les extensions optionnel est iconv (en général déjà installer) et
tidy (répandu aussi). Si vous utilisez UTF-8 et ne voulez pas
l'indentation, vous pouvez utiliser HTML Purifier sans ces extensions.
Les extensions optionnelles sont iconv (généralement déjà installée) et tidy
(répendue aussi). Si vous utilisez UTF-8 et que vous ne voulez pas l'indentation,
vous pouvez utiliser HTML Purifier sans ces extensions.
2. Inclure la librarie
2. Inclure la librairie
Utilisez:
Quand vous devez l'utilisez, incluez le :
require_once '/path/to/library/HTMLPurifier.auto.php';
require_once('/path/to/library/HTMLPurifier.auto.php');
...quand vous devez utiliser HTML Purifier (ne inclure pas quand vous
ne devez pas, parce que HTML Purifier est trés grand.)
Ne pas l'inclure si ce n'est pas nécessaire, car HTML Purifier est lourd.
HTML Purifier utilise 'autoload'. Si vous avez définu la fonction
__autoload, vous doivez ajoute cet programme:
HTML Purifier utilise "autoload". Si vous avez défini la fonction __autoload,
vous devez ajouter cette fonction :
spl_autoload_register('__autoload')
Plus d'information est dans le document 'INSTALL'.
Plus d'informations dans le document "INSTALL".
3. Installation rapide
3. Installation vite
Si votre site web est en UTF-8 et XHTML Transitional, utilisez:
Si votre site Web est en UTF-8 et XHTML Transitional, utilisez :
<?php
require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
require_once('/path/to/htmlpurifier/library/HTMLPurifier.auto.php');
$purificateur = new HTMLPurifier();
$html_propre = $purificateur->purify($html_salle);
$html_propre = $purificateur->purify($html_a_purifier);
?>
Sinon, utilisez:
Sinon, utilisez :
<?php
require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$config->set('Core', 'Encoding', 'ISO-8859-1'); //remplacez avec votre encoding
$config->set('Core', 'XHTML', true); //remplacez avec false si HTML 4.01
require_once('/path/to/html/purifier/library/HTMLPurifier.auto.load');
$config = $HTMLPurifier_Config::createDefault();
$config->set('Core', 'Encoding', 'ISO-8859-1'); //Remplacez par votre
encodage
$config->set('Core', 'XHTML', true); //Remplacer par false si HTML 4.01
$purificateur = new HTMLPurifier($config);
$html_propre = $purificateur->purify($html_salle);
$html_propre = $purificateur->purify($html_a_purifier);
?>
vim: et sw=4 sts=4

47
NEWS
View File

@@ -9,6 +9,53 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
. Internal change
==========================
4.8.0, released 2016-07-16
# By default, when a link has a target attribute associated
with it, we now also add rel="noreferrer" in order to
prevent the new window from being able to overwrite
the original frame. To disable this protection,
set %HTML.TargetNoreferrer to FALSE.
! Full PHP 7 compatibility, the test suite is ALL GO.
! %CSS.AllowDuplicates permits duplicate CSS properties.
! Support for 'tel' URIs.
! Partial support for 'border-radius' properties when %CSS.AllowProprietary is true.
The slash syntax, i.e., 'border-radius: 2em 1em 4em / 0.5em 3em' is not
yet supported.
! %Attr.ID.HTML5 turns on HTML5-style ID handling.
- alt truncation could result in malformed UTF-8 sequence. Don't
truncate. Thanks Brandon Farber for reporting.
- Linkify regex is smarter, based off of Gruber's regex.
- IDNA supported natively on PHP 5.3 and later.
- Non all-numeric top-level names (e.g., foo.1f, 1f) are now
allowed.
- Minor bounds error fix to squash a PHP 7 notice.
- Support non-/tmp temporary directories for data:// validation
- Give a better error message when a user attempts to allow
ul/ol without allowing li.
- On some versions of PHP, the Serializer DefinitionCache could
infinite loop when the directory exists but is not listable. (#49)
- Don't match for <body> inside comments with
%Core.ConvertDocumentToFragment. (#67)
- SafeObject is now less case sensitive. (#57)
- AutoFormat.RemoveEmpty.Predicate now correctly renders in
web form. (#85)
4.7.0, released 2015-08-04
# opacity is now considered a "tricky" CSS property rather than a
proprietary one.
! %AutoFormat.RemoveEmpty.Predicate for specifying exactly when
an element should be considered "empty" (maybe preserve if it
has attributes), and modify iframe support so that the iframe
is removed if it is missing a src attribute. Thanks meeva for
reporting.
- Don't truncate upon encountering </div> when using DOMLex. Thanks
Myrto Christina for finally convincing me to fix this.
- Update YouTube filter for new code.
- Fix parsing of rgb() values with spaces in them for 'border'
attribute.
- Don't remove foo="" attributes if foo is a boolean attribute. Thanks
valME for reporting.
4.6.0, released 2013-11-30
# Secure URI munge hashing algorithm has changed to hash_hmac("sha256", $url, $secret).
Please update any verification scripts you may have.

View File

@@ -1,6 +1,5 @@
README
All about HTML Purifier
HTML Purifier
=============
HTML Purifier is an HTML filtering solution that uses a unique combination
of robust whitelists and agressive parsing to ensure that not only are
@@ -19,6 +18,12 @@ Places to go:
an in-depth installation guide.
* See WYSIWYG for information on editors like TinyMCE and FCKeditor
HTML Purifier can be found on the web at: http://htmlpurifier.org/
HTML Purifier can be found on the web at: [http://htmlpurifier.org/](http://htmlpurifier.org/)
vim: et sw=4 sts=4
## Installation
Package available on [Composer](https://packagist.org/packages/ezyang/htmlpurifier).
If you're using Composer to manage dependencies, you can use
$ composer require "ezyang/htmlpurifier": "dev-master"

2
TODO
View File

@@ -32,7 +32,7 @@ Things to do as soon as possible:
FUTURE VERSIONS
---------------
4.6 release [OMG CONFIG PONIES]
4.9 release [OMG CONFIG PONIES]
! Fix Printer. It's from the old days when we didn't have decent XML classes
! Factor demo.php into a set of Printer classes, and then create a stub
file for users here (inside the actual HTML Purifier library)

View File

@@ -1 +1 @@
4.6.0
4.8.0

View File

@@ -1,5 +1,9 @@
HTML Purifier 4.6.0 is a major security release, fixing numerous bad
quadratic asymptotics in HTML Purifier's core algorithms. Most users will
see a decent speedup on large inputs, although small inputs may take
longer. Additionally, the secure URI munging algorithm has changed to
do a proper HMAC. There are some other miscellaneous bugfixes as well.
HTML Purifier 4.8.0 is a bugfix release, collecting a year
of accumulated bug fixes. In particular, we fixed some minor
bugs and now declare full PHP 7 compatibility. The primary
backwards-incompatible change is that HTML Purifier will now
add rel="noreferrer" to all links with target attributes
(you can disable this with %HTML.TargetNoReferrer.) Other
changes: new configuration options %CSS.AllowDuplicates and
%Attr.ID.HTML5; border-radius is partially supported when
%CSS.AllowProprietary, and tel URIs are supported by default.

View File

@@ -25,7 +25,7 @@ class RowTimer extends Benchmark_Timer
public $name;
public function RowTimer($name, $auto = false)
public function __construct($name, $auto = false)
{
$this->name = htmlentities($name);
$this->Benchmark_Timer($auto);

View File

@@ -44,12 +44,12 @@
</directive>
<directive id="CSS.AllowedProperties">
<file name="HTMLPurifier/CSSDefinition.php">
<line>447</line>
<line>460</line>
</file>
</directive>
<directive id="CSS.ForbiddenProperties">
<file name="HTMLPurifier/CSSDefinition.php">
<line>463</line>
<line>476</line>
</file>
</directive>
<directive id="Cache.DefinitionImpl">
@@ -227,6 +227,11 @@
<line>271</line>
</file>
</directive>
<directive id="HTML.TargetNoreferrer">
<file name="HTMLPurifier/HTMLModuleManager.php">
<line>276</line>
</file>
</directive>
<directive id="Attr.IDBlacklist">
<file name="HTMLPurifier/IDAccumulator.php">
<line>27</line>
@@ -296,6 +301,11 @@
<line>49</line>
</file>
</directive>
<directive id="CSS.AllowDuplicates">
<file name="HTMLPurifier/AttrDef/CSS.php">
<line>28</line>
</file>
</directive>
<directive id="URI.Disable">
<file name="HTMLPurifier/AttrDef/URI.php">
<line>47</line>
@@ -345,9 +355,14 @@
<line>58</line>
</file>
</directive>
<directive id="Attr.ID.HTML5">
<file name="HTMLPurifier/AttrDef/HTML/ID.php">
<line>75</line>
</file>
</directive>
<directive id="Attr.IDBlacklistRegexp">
<file name="HTMLPurifier/AttrDef/HTML/ID.php">
<line>89</line>
<line>97</line>
</file>
</directive>
<directive id="Attr.">
@@ -362,7 +377,7 @@
</directive>
<directive id="Core.EnableIDNA">
<file name="HTMLPurifier/AttrDef/URI/Host.php">
<line>96</line>
<line>105</line>
</file>
</directive>
<directive id="Attr.DefaultTextDir">
@@ -390,7 +405,7 @@
</directive>
<directive id="Attr.DefaultInvalidImageAlt">
<file name="HTMLPurifier/AttrTransform/ImgRequired.php">
<line>41</line>
<line>40</line>
</file>
</directive>
<directive id="HTML.Attr.Name.UseCDATA">
@@ -408,13 +423,13 @@
</directive>
<directive id="Cache.SerializerPath">
<file name="HTMLPurifier/DefinitionCache/Serializer.php">
<line>171</line>
<line>183</line>
</file>
</directive>
<directive id="Cache.SerializerPermissions">
<file name="HTMLPurifier/DefinitionCache/Serializer.php">
<line>188</line>
<line>206</line>
<line>200</line>
<line>219</line>
</file>
</directive>
<directive id="Filter.ExtractStyleBlocks.TidyImpl">
@@ -481,6 +496,11 @@
<line>47</line>
</file>
</directive>
<directive id="AutoFormat.RemoveEmpty.Predicate">
<file name="HTMLPurifier/Injector/RemoveEmpty.php">
<line>48</line>
</file>
</directive>
<directive id="Core.AggressivelyFixLt">
<file name="HTMLPurifier/Lexer/DOMLex.php">
<line>54</line>

View File

@@ -25,5 +25,6 @@ URIScheme - needs to have callable generic checks
mailto - doesn't validate emails, doesn't validate querystring
news - doesn't validate opaque path
nntp - doesn't constrain path
tel - doesn't validate phone numbers, only allows characters '+', '1-9', and 'x'
vim: et sw=4 sts=4

View File

@@ -1,4 +1,4 @@
<?php
if (!defined('HTMLPURIFIER_PREFIX')) {
define('HTMLPURIFIER_PREFIX', __DIR__);
define('HTMLPURIFIER_PREFIX', dirname(__FILE__));
}

View File

@@ -7,7 +7,7 @@
* 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.
*
* @version 4.6.0
* @version 4.8.0
*
* @warning
* 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/ScriptRequired.php';
require 'HTMLPurifier/AttrTransform/TargetBlank.php';
require 'HTMLPurifier/AttrTransform/TargetNoreferrer.php';
require 'HTMLPurifier/AttrTransform/Textarea.php';
require 'HTMLPurifier/ChildDef/Chameleon.php';
require 'HTMLPurifier/ChildDef/Custom.php';
@@ -175,6 +176,7 @@ require 'HTMLPurifier/HTMLModule/StyleAttribute.php';
require 'HTMLPurifier/HTMLModule/Tables.php';
require 'HTMLPurifier/HTMLModule/Target.php';
require 'HTMLPurifier/HTMLModule/TargetBlank.php';
require 'HTMLPurifier/HTMLModule/TargetNoreferrer.php';
require 'HTMLPurifier/HTMLModule/Text.php';
require 'HTMLPurifier/HTMLModule/Tidy.php';
require 'HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
@@ -225,5 +227,6 @@ require 'HTMLPurifier/URIScheme/https.php';
require 'HTMLPurifier/URIScheme/mailto.php';
require 'HTMLPurifier/URIScheme/news.php';
require 'HTMLPurifier/URIScheme/nntp.php';
require 'HTMLPurifier/URIScheme/tel.php';
require 'HTMLPurifier/VarParser/Flexible.php';
require 'HTMLPurifier/VarParser/Native.php';

View File

@@ -19,7 +19,7 @@
*/
/*
HTML Purifier 4.6.0 - Standards Compliant HTML Filtering
HTML Purifier 4.8.0 - Standards Compliant HTML Filtering
Copyright (C) 2006-2008 Edward Z. Yang
This library is free software; you can redistribute it and/or
@@ -58,12 +58,12 @@ class HTMLPurifier
* Version of HTML Purifier.
* @type string
*/
public $version = '4.6.0';
public $version = '4.8.0';
/**
* Constant with version of HTML Purifier.
*/
const VERSION = '4.6.0';
const VERSION = '4.8.0';
/**
* Global configuration object.
@@ -104,7 +104,7 @@ class HTMLPurifier
/**
* Initializes the purifier.
*
* @param HTMLPurifier_Config $config Optional HTMLPurifier_Config object
* @param HTMLPurifier_Config|mixed $config Optional HTMLPurifier_Config object
* for all instances of the purifier, if omitted, a default
* configuration is supplied (which can be overridden on a
* per-use basis).

View File

@@ -131,6 +131,7 @@ require_once $__dir . '/HTMLPurifier/AttrTransform/SafeObject.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetBlank.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetNoreferrer.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Textarea.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Custom.php';
@@ -169,6 +170,7 @@ require_once $__dir . '/HTMLPurifier/HTMLModule/StyleAttribute.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tables.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Target.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetBlank.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetNoreferrer.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Text.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
@@ -219,5 +221,6 @@ require_once $__dir . '/HTMLPurifier/URIScheme/https.php';
require_once $__dir . '/HTMLPurifier/URIScheme/mailto.php';
require_once $__dir . '/HTMLPurifier/URIScheme/news.php';
require_once $__dir . '/HTMLPurifier/URIScheme/nntp.php';
require_once $__dir . '/HTMLPurifier/URIScheme/tel.php';
require_once $__dir . '/HTMLPurifier/VarParser/Flexible.php';
require_once $__dir . '/HTMLPurifier/VarParser/Native.php';

View File

@@ -21,6 +21,11 @@ class HTMLPurifier_AttrCollections
* @param HTMLPurifier_HTMLModule[] $modules Hash array of HTMLPurifier_HTMLModule members
*/
public function __construct($attr_types, $modules)
{
$this->doConstruct($attr_types, $modules);
}
public function doConstruct($attr_types, $modules)
{
// load extensions from the modules
foreach ($modules as $module) {

View File

@@ -25,6 +25,7 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
$css = $this->parseCDATA($css);
$definition = $config->getCSSDefinition();
$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
@@ -34,6 +35,7 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
$declarations = explode(';', $css);
$propvalues = array();
$new_declarations = '';
/**
* Name of the current CSS property being validated.
@@ -83,7 +85,11 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
if ($result === false) {
continue;
}
$propvalues[$property] = $result;
if ($allow_duplicates) {
$new_declarations .= "$property:$result;";
} else {
$propvalues[$property] = $result;
}
}
$context->destroy('CurrentCSSProperty');
@@ -92,7 +98,6 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
// slightly inefficient, but it's the only way of getting rid of
// duplicates. Perhaps config to optimize it, but not now.
$new_declarations = '';
foreach ($propvalues as $prop => $value) {
$new_declarations .= "$prop:$value;";
}

View File

@@ -44,7 +44,7 @@ class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string);
$string = $this->mungeRgb($this->parseCDATA($string));
if ($string === '') {
return false;
}

View File

@@ -33,6 +33,9 @@ class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
return false;
}
$uri_string = substr($uri_string, 4);
if (strlen($uri_string) == 0) {
return false;
}
$new_length = strlen($uri_string) - 1;
if ($uri_string[$new_length] != ')') {
return false;

View File

@@ -32,9 +32,6 @@ class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef
*/
public function validate($string, $config, $context)
{
if (empty($string)) {
return false;
}
return $this->name;
}

View File

@@ -72,18 +72,26 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
// we purposely avoid using regex, hopefully this is faster
if (ctype_alpha($id)) {
$result = true;
} else {
if (!ctype_alpha(@$id[0])) {
if ($config->get('Attr.ID.HTML5') === true) {
if (preg_match('/[\t\n\x0b\x0c ]/', $id)) {
return false;
}
// primitive style of regexps, I suppose
$trim = trim(
$id,
'A..Za..z0..9:-._'
);
$result = ($trim === '');
} else {
if (ctype_alpha($id)) {
// OK
} else {
if (!ctype_alpha(@$id[0])) {
return false;
}
// primitive style of regexps, I suppose
$trim = trim(
$id,
'A..Za..z0..9:-._'
);
if ($trim !== '') {
return false;
}
}
}
$regexp = $config->get('Attr.IDBlacklistRegexp');
@@ -91,14 +99,14 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
return false;
}
if (!$this->selector && $result) {
if (!$this->selector) {
$id_accumulator->add($id);
}
// if no change was made to the ID, return the result
// else, return the new id if stripping whitespace made it
// valid, or return false.
return $result ? $id : false;
return $id;
}
}

View File

@@ -76,24 +76,33 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
// fairly well supported.
$underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : '';
// Based off of RFC 1738, but amended so that
// as per RFC 3696, the top label need only not be all numeric.
// The productions describing this are:
$a = '[a-z]'; // alpha
$an = '[a-z0-9]'; // alphanum
$and = "[a-z0-9-$underscore]"; // alphanum | "-"
// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
$domainlabel = "$an($and*$an)?";
// toplabel = alpha | alpha *( alphanum | "-" ) alphanum
$toplabel = "$a($and*$an)?";
$domainlabel = "$an(?:$and*$an)?";
// AMENDED as per RFC 3696
// toplabel = alphanum | alphanum *( alphanum | "-" ) alphanum
// side condition: not all numeric
$toplabel = "$an(?:$and*$an)?";
// hostname = *( domainlabel "." ) toplabel [ "." ]
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
return $string;
if (preg_match("/^(?:$domainlabel\.)*($toplabel)\.?$/i", $string, $matches)) {
if (!ctype_digit($matches[1])) {
return $string;
}
}
// PHP 5.3 and later support this functionality natively
if (function_exists('idn_to_ascii')) {
return idn_to_ascii($string);
// If we have Net_IDNA2 support, we can support IRIs by
// punycoding them. (This is the most portable thing to do,
// since otherwise we have to assume browsers support
if ($config->get('Core.EnableIDNA')) {
} elseif ($config->get('Core.EnableIDNA')) {
$idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true));
// we need to encode each period separately
$parts = explode('.', $string);

View File

@@ -32,8 +32,7 @@ class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
if ($src) {
$alt = $config->get('Attr.DefaultImageAlt');
if ($alt === null) {
// truncate if the alt is too long
$attr['alt'] = substr(basename($attr['src']), 0, 40);
$attr['alt'] = basename($attr['src']);
} else {
$attr['alt'] = $alt;
}

View File

@@ -0,0 +1,37 @@
<?php
// must be called POST validation
/**
* Adds rel="noreferrer" 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.TargetNoreferrer.
*/
class HTMLPurifier_AttrTransform_TargetNoreferrer 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('noreferrer', $rels)) {
$rels[] = 'noreferrer';
}
if (!empty($rels) || isset($attr['rel'])) {
$attr['rel'] = implode(' ', $rels);
}
return $attr;
}
}

View File

@@ -350,8 +350,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
// technically not proprietary, but CSS3, and no one supports it
$this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
// vendor specific prefixes of opacity
$this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
$this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
@@ -371,6 +370,19 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
);
$this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid'));
$border_radius = new HTMLPurifier_AttrDef_CSS_Composite(
array(
new HTMLPurifier_AttrDef_CSS_Percentage(true), // disallow negative
new HTMLPurifier_AttrDef_CSS_Length('0') // disallow negative
));
$this->info['border-top-left-radius'] =
$this->info['border-top-right-radius'] =
$this->info['border-bottom-right-radius'] =
$this->info['border-bottom-left-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 2);
// TODO: support SLASH syntax
$this->info['border-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 4);
}
/**
@@ -404,6 +416,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
array('visible', 'hidden', 'collapse')
);
$this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll'));
$this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
}
/**

View File

@@ -38,6 +38,12 @@ class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef
return false;
}
// if li is not allowed, delete parent node
if (!isset($config->getHTMLDefinition()->info['li'])) {
trigger_error("Cannot allow ul/ol without allowing li", E_USER_WARNING);
return false;
}
// the new set of children
$result = array();

View File

@@ -21,7 +21,7 @@ class HTMLPurifier_Config
* HTML Purifier's version
* @type string
*/
public $version = '4.6.0';
public $version = '4.8.0';
/**
* Whether or not to automatically finalize
@@ -646,16 +646,25 @@ class HTMLPurifier_Config
return $this->getDefinition($name, true, true);
}
/**
* @return HTMLPurifier_HTMLDefinition
*/
public function maybeGetRawHTMLDefinition()
{
return $this->getDefinition('HTML', true, true);
}
/**
* @return HTMLPurifier_CSSDefinition
*/
public function maybeGetRawCSSDefinition()
{
return $this->getDefinition('CSS', true, true);
}
/**
* @return HTMLPurifier_URIDefinition
*/
public function maybeGetRawURIDefinition()
{
return $this->getDefinition('URI', true, true);

View File

@@ -0,0 +1,10 @@
Attr.ID.HTML5
TYPE: bool/null
DEFAULT: null
VERSION: 4.8.0
--DESCRIPTION--
In HTML5, restrictions on the format of the id attribute have been significantly
relaxed, such that any string is valid so long as it contains no spaces and
is at least one character. In lieu of a general HTML5 compatibility flag,
set this configuration directive to true to use the relaxed rules.
--# vim: et sw=4 sts=4

View File

@@ -0,0 +1,14 @@
AutoFormat.RemoveEmpty.Predicate
TYPE: hash
VERSION: 4.7.0
DEFAULT: array('colgroup' => array(), 'th' => array(), 'td' => array(), 'iframe' => array('src'))
--DESCRIPTION--
<p>
Given that an element has no contents, it will be removed by default, unless
this predicate dictates otherwise. The predicate can either be an associative
map from tag name to list of attributes that must be present for the element
to be considered preserved: thus, the default always preserves <code>colgroup</code>,
<code>th</code> and <code>td</code>, and also <code>iframe</code> if it
has a <code>src</code>.
</p>
--# vim: et sw=4 sts=4

View File

@@ -0,0 +1,11 @@
CSS.AllowDuplicates
TYPE: bool
DEFAULT: false
VERSION: 4.8.0
--DESCRIPTION--
<p>
By default, HTML Purifier removes duplicate CSS properties,
like <code>color:red; color:blue</code>. If this is set to
true, duplicate properties are allowed.
</p>
--# vim: et sw=4 sts=4

View File

@@ -1,5 +1,5 @@
Cache.SerializerPermissions
TYPE: int
TYPE: int/null
VERSION: 4.3.0
DEFAULT: 0755
--DESCRIPTION--
@@ -8,4 +8,9 @@ DEFAULT: 0755
Directory permissions of the files and directories created inside
the DefinitionCache/Serializer or other custom serializer path.
</p>
<p>
In HTML Purifier 4.8.0, this also supports <code>NULL</code>,
which means that no chmod'ing or directory creation shall
occur.
</p>
--# vim: et sw=4 sts=4

View File

@@ -4,6 +4,6 @@ VERSION: 2.0.1
DEFAULT: NULL
--DESCRIPTION--
A custom doctype for power-users who defined there own document
A custom doctype for power-users who defined their own document
type. This directive only applies when %HTML.Doctype is blank.
--# vim: et sw=4 sts=4

View File

@@ -0,0 +1,9 @@
HTML.TargetNoreferrer
TYPE: bool
VERSION: 4.8.0
DEFAULT: TRUE
--DESCRIPTION--
If enabled, noreferrer 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

View File

@@ -8,6 +8,7 @@ array (
'ftp' => true,
'nntp' => true,
'news' => true,
'tel' => true,
)
--DESCRIPTION--
Whitelist that defines the schemes that a URI is allowed to have. This

View File

@@ -118,7 +118,7 @@ abstract class HTMLPurifier_DefinitionCache
/**
* Clears all expired (older version or revision) objects from cache
* @note Be carefuly implementing this method as flush. Flush must
* @note Be careful implementing this method as flush. Flush must
* not interfere with other Definition types, and cleanup()
* should not be repeatedly called by userland code.
* @param HTMLPurifier_Config $config

View File

@@ -97,6 +97,12 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
}
$dir = $this->generateDirectoryPath($config);
$dh = opendir($dir);
// Apparently, on some versions of PHP, readdir will return
// an empty string if you pass an invalid argument to readdir.
// So you need this test. See #49.
if (false === $dh) {
return false;
}
while (false !== ($filename = readdir($dh))) {
if (empty($filename)) {
continue;
@@ -106,6 +112,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
}
unlink($dir . '/' . $filename);
}
return true;
}
/**
@@ -119,6 +126,10 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
}
$dir = $this->generateDirectoryPath($config);
$dh = opendir($dir);
// See #49 (and above).
if (false === $dh) {
return false;
}
while (false !== ($filename = readdir($dh))) {
if (empty($filename)) {
continue;
@@ -131,6 +142,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
unlink($dir . '/' . $filename);
}
}
return true;
}
/**
@@ -186,11 +198,12 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
if ($result !== false) {
// set permissions of the new file (no execute)
$chmod = $config->get('Cache.SerializerPermissions');
if (!$chmod) {
$chmod = 0644; // invalid config or simpletest
if ($chmod === null) {
// don't do anything
} else {
$chmod = $chmod & 0666;
chmod($file, $chmod);
}
$chmod = $chmod & 0666;
chmod($file, $chmod);
}
return $result;
}
@@ -204,9 +217,6 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
{
$directory = $this->generateDirectoryPath($config);
$chmod = $config->get('Cache.SerializerPermissions');
if (!$chmod) {
$chmod = 0755; // invalid config or simpletest
}
if (!is_dir($directory)) {
$base = $this->generateBaseDirectoryPath($config);
if (!is_dir($base)) {
@@ -219,9 +229,27 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
} elseif (!$this->_testPermissions($base, $chmod)) {
return false;
}
$old = umask(0000);
mkdir($directory, $chmod);
umask($old);
if ($chmod === null) {
trigger_error(
'Base directory ' . $base . ' does not exist,
please create or change using %Cache.SerializerPath',
E_USER_WARNING
);
return false;
}
if ($chmod !== null) {
mkdir($directory, $chmod);
} else {
mkdir($directory);
}
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;
}
} elseif (!$this->_testPermissions($directory, $chmod)) {
return false;
}
@@ -250,7 +278,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
);
return false;
}
if (function_exists('posix_getuid')) {
if (function_exists('posix_getuid') && $chmod !== null) {
// POSIX system, we can give more specific advice
if (fileowner($dir) === posix_getuid()) {
// we can chmod it ourselves

View File

@@ -17,7 +17,7 @@ class HTMLPurifier_Filter_YouTube extends HTMLPurifier_Filter
public function preFilter($html, $config, $context)
{
$pre_regex = '#<object[^>]+>.+?' .
'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s';
'(?:http:)?//www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s';
$pre_replace = '<span class="youtube-embed">\1</span>';
return preg_replace($pre_regex, $pre_replace, $html);
}
@@ -51,10 +51,10 @@ class HTMLPurifier_Filter_YouTube extends HTMLPurifier_Filter
{
$url = $this->armorUrl($matches[1]);
return '<object width="425" height="350" type="application/x-shockwave-flash" ' .
'data="http://www.youtube.com/' . $url . '">' .
'<param name="movie" value="http://www.youtube.com/' . $url . '"></param>' .
'data="//www.youtube.com/' . $url . '">' .
'<param name="movie" value="//www.youtube.com/' . $url . '"></param>' .
'<!--[if IE]>' .
'<embed src="http://www.youtube.com/' . $url . '"' .
'<embed src="//www.youtube.com/' . $url . '"' .
'type="application/x-shockwave-flash"' .
'wmode="transparent" width="425" height="350" />' .
'<![endif]-->' .

View File

@@ -0,0 +1,21 @@
<?php
/**
* Module adds the target-based noreferrer attribute transformation to a tags. It
* is enabled by HTML.TargetNoreferrer
*/
class HTMLPurifier_HTMLModule_TargetNoreferrer extends HTMLPurifier_HTMLModule
{
/**
* @type string
*/
public $name = 'TargetNoreferrer';
/**
* @param HTMLPurifier_Config $config
*/
public function setup($config) {
$a = $this->addBlankElement('a');
$a->attr_transform_post[] = new HTMLPurifier_AttrTransform_TargetNoreferrer();
}
}

View File

@@ -271,6 +271,11 @@ class HTMLPurifier_HTMLModuleManager
if ($config->get('HTML.TargetBlank')) {
$modules[] = 'TargetBlank';
}
// NB: HTML.TargetNoreferrer must be AFTER HTML.TargetBlank
// so that its post-attr-transform gets run afterwards.
if ($config->get('HTML.TargetNoreferrer')) {
$modules[] = 'TargetNoreferrer';
}
// merge in custom modules
$modules = array_merge($modules, $this->userModules);

View File

@@ -31,9 +31,14 @@ class HTMLPurifier_Injector_Linkify extends HTMLPurifier_Injector
return;
}
// there is/are URL(s). Let's split the string:
// Note: this regex is extremely permissive
$bits = preg_split('#((?:https?|ftp)://[^\s\'",<>()]+)#Su', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE);
// there is/are URL(s). Let's split the string.
// We use this regex:
// https://gist.github.com/gruber/249502
// but with @cscott's backtracking fix and also
// the Unicode characters un-Unicodified.
$bits = preg_split(
'/\\b((?:[a-z][\\w\\-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/)(?:[^\\s()<>]|\\((?:[^\\s()<>]|(?:\\([^\\s()<>]+\\)))*\\))+(?:\\((?:[^\\s()<>]|(?:\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'".,<>?\x{00ab}\x{00bb}\x{201c}\x{201d}\x{2018}\x{2019}]))/iu',
$token->data, -1, PREG_SPLIT_DELIM_CAPTURE);
$token = array();

View File

@@ -28,10 +28,10 @@ class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector
private $removeNbspExceptions;
/**
* Cached contents of %AutoFormat.RemoveEmpty.Predicate
* @type array
* TODO: make me configurable
*/
private $_exclude = array('colgroup' => 1, 'th' => 1, 'td' => 1, 'iframe' => 1);
private $exclude;
/**
* @param HTMLPurifier_Config $config
@@ -45,6 +45,13 @@ class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector
$this->context = $context;
$this->removeNbsp = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp');
$this->removeNbspExceptions = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions');
$this->exclude = $config->get('AutoFormat.RemoveEmpty.Predicate');
foreach ($this->exclude as $key => $attrs) {
if (!is_array($attrs)) {
// HACK, see HTMLPurifier/Printer/ConfigForm.php
$this->exclude[$key] = explode(';', $attrs);
}
}
$this->attrValidator = new HTMLPurifier_AttrValidator();
}
@@ -75,11 +82,15 @@ class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector
break;
}
if (!$next || ($next instanceof HTMLPurifier_Token_End && $next->name == $token->name)) {
if (isset($this->_exclude[$token->name])) {
return;
}
$this->attrValidator->validateToken($token, $this->config, $this->context);
$token->armor['ValidateAttributes'] = true;
if (isset($this->exclude[$token->name])) {
$r = true;
foreach ($this->exclude[$token->name] as $elem) {
if (!isset($token->attr[$elem])) $r = false;
}
if ($r) return;
}
if (isset($token->attr['id']) || isset($token->attr['name'])) {
return;
}

View File

@@ -36,6 +36,7 @@ class HTMLPurifier_Injector_SafeObject extends HTMLPurifier_Injector
);
/**
* These are all lower-case keys.
* @type array
*/
protected $allowedParam = array(
@@ -43,7 +44,7 @@ class HTMLPurifier_Injector_SafeObject extends HTMLPurifier_Injector
'movie' => true,
'flashvars' => true,
'src' => true,
'allowFullScreen' => true, // if omitted, assume to be 'false'
'allowfullscreen' => true, // if omitted, assume to be 'false'
);
/**
@@ -93,9 +94,11 @@ class HTMLPurifier_Injector_SafeObject extends HTMLPurifier_Injector
$token->attr['name'] === $this->addParam[$n]) {
// keep token, and add to param stack
$this->paramStack[$i][$n] = true;
} elseif (isset($this->allowedParam[$n])) {
} elseif (isset($this->allowedParam[strtolower($n)])) {
// keep token, don't do anything to it
// (could possibly check for duplicates here)
// Note: In principle, parameters should be case sensitive.
// But it seems they are not really; so accept any case.
} else {
$token = false;
}

View File

@@ -345,12 +345,17 @@ class HTMLPurifier_Lexer
public function extractBody($html)
{
$matches = array();
$result = preg_match('!<body[^>]*>(.*)</body>!is', $html, $matches);
$result = preg_match('|(.*?)<body[^>]*>(.*)</body>|is', $html, $matches);
if ($result) {
return $matches[1];
} else {
return $html;
// Make sure it's not in a comment
$comment_start = strrpos($matches[1], '<!--');
$comment_end = strrpos($matches[1], '-->');
if ($comment_start === false ||
($comment_end !== false && $comment_end > $comment_start)) {
return $matches[2];
}
}
return $html;
}
}

View File

@@ -75,8 +75,7 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
$tokens = array();
$this->tokenizeDOM(
$doc->getElementsByTagName('html')->item(0)-> // <html>
getElementsByTagName('body')->item(0)-> // <body>
getElementsByTagName('div')->item(0), // <div>
getElementsByTagName('body')->item(0), // <body>
$tokens
);
return $tokens;
@@ -272,7 +271,7 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
$ret .= '<html><head>';
$ret .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
// No protection if $html contains a stray </div>!
$ret .= '</head><body><div>' . $html . '</div></body></html>';
$ret .= '</head><body>' . $html . '</body></html>';
return $ret;
}
}

View File

@@ -34,8 +34,7 @@ class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex
$tokens = array();
$this->tokenizeDOM(
$doc->getElementsByTagName('html')->item(0)-> // <html>
getElementsByTagName('body')->item(0)-> // <body>
getElementsByTagName('div')->item(0) // <div>
getElementsByTagName('body')->item(0) // <body>
,
$tokens
);

View File

@@ -327,6 +327,10 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer
case HTMLPurifier_VarParser::HASH:
$nvalue = '';
foreach ($value as $i => $v) {
if (is_array($v)) {
// HACK
$v = implode(";", $v);
}
$nvalue .= "$i:$v" . PHP_EOL;
}
$value = $nvalue;

View File

@@ -79,9 +79,18 @@ class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme
} else {
$raw_data = $data;
}
if ( strlen($raw_data) < 12 ) {
// error; exif_imagetype throws exception with small files,
// and this likely indicates a corrupt URI/failed parse anyway
return false;
}
// XXX probably want to refactor this into a general mechanism
// for filtering arbitrary content types
$file = tempnam("/tmp", "");
if (function_exists('sys_get_temp_dir')) {
$file = tempnam(sys_get_temp_dir(), "");
} else {
$file = tempnam("/tmp", "");
}
file_put_contents($file, $raw_data);
if (function_exists('exif_imagetype')) {
$image_code = exif_imagetype($file);

View File

@@ -0,0 +1,46 @@
<?php
/**
* Validates tel (for phone numbers).
*
* The relevant specifications for this protocol are RFC 3966 and RFC 5341,
* but this class takes a much simpler approach: we normalize phone
* numbers so that they only include (possibly) a leading plus,
* and then any number of digits and x'es.
*/
class HTMLPurifier_URIScheme_tel extends HTMLPurifier_URIScheme
{
/**
* @type bool
*/
public $browsable = false;
/**
* @type bool
*/
public $may_omit_host = true;
/**
* @param HTMLPurifier_URI $uri
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool
*/
public function doValidate(&$uri, $config, $context)
{
$uri->userinfo = null;
$uri->host = null;
$uri->port = null;
// Delete all non-numeric characters, non-x characters
// from phone number, EXCEPT for a leading plus sign.
$uri->path = preg_replace('/(?!^\+)[^\dx]/', '',
// Normalize e(x)tension to lower-case
str_replace('X', 'x', $uri->path));
return true;
}
}
// vim: et sw=4 sts=4

View File

@@ -35,7 +35,6 @@ foreach ($files as $file) {
postfix_is('.phpt', $file) ||
postfix_is('VERSION', $file) ||
postfix_is('WHATSNEW', $file) ||
postfix_is('FOCUS', $file) ||
postfix_is('configdoc/usage.xml', $file) ||
postfix_is('library/HTMLPurifier.includes.php', $file) ||
postfix_is('library/HTMLPurifier.safe-includes.php', $file) ||

View File

@@ -1,161 +0,0 @@
#!/usr/bin/php
<?php
chdir(dirname(__FILE__));
require_once 'common.php';
assertCli();
/**
* @file
* Updates Freshmeat's HTML Purifier with the latest information via XML RPC.
*/
class XmlRpc_Freshmeat
{
const URL = 'http://freshmeat.net/xmlrpc/';
public $chatty = false;
public $encodeOptions = array(
'encoding' => 'utf-8',
);
/**
* This array defines shortcut method signatures for dealing with simple
* XML RPC methods. More complex ones (publish_release) should use the named parameter
* syntax.
*/
public $signatures = array(
'login' => array('username', 'password'),
'fetch_branch_list' => array('project_name'),
'fetch_release' => array('project_name', 'branch_name', 'version'),
'withdraw_release' => array('project_name', 'branch_name', 'version'),
);
protected $sid = null;
/**
* @param $username Username to login with
* @param $password Password to login with
*/
public function __construct($username = null, $password = null)
{
if ($username && $password) {
$this->login($username, $password);
}
}
/**
* Performs a raw XML RPC call to self::URL
*/
protected function call($method, $params)
{
$request = xmlrpc_encode_request($method, $params, $this->encodeOptions);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, self::URL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: text/xml',
'Content-length: ' . strlen($request)
));
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
$data = curl_exec($ch);
if ($errno = curl_errno($ch)) {
throw new Exception("Curl error [$errno]: " . curl_error($ch));
} else {
curl_close($ch);
return xmlrpc_decode($data);
}
}
/**
* Performs an XML RPC call to Freshmeat.
* @param $name Name of method to call, can be methodName or method_name
* @param $args Arguments of call, in form array('key1', 'val1', 'key2' ...)
*/
public function __call($name, $args)
{
$method = $this->camelToUnderscore($name);
$params = array();
if ($this->sid) $params['SID'] = $this->sid;
if (isset($this->signatures[$method])) {
for ($i = 0, $c = count($this->signatures[$method]); $i < $c; $i++) {
$params[$this->signatures[$method][$i]] = $args[$i];
}
} else {
for ($i = 0, $c = count($args); $i + 1 < $c; $i += 2) {
$params[$args[$i]] = $args[$i + 1];
}
}
$result = $this->call($method, $params);
switch ($method) {
case 'login':
$this->sid = $result['SID'];
break;
case 'logout':
$this->sid = null;
break;
}
if ($this->chatty) print_r($result);
return $result;
}
/**
* Munge methodName to method_name
*/
private function camelToUnderscore($name)
{
$method = '';
for ($i = 0, $c = strlen($name); $i < $c; $i++) {
$v = $name[$i];
if (ctype_lower($v)) $method .= $v;
else $method .= '_' . strtolower($v);
}
return $method;
}
/**
* Automatically logout at end of scope
*/
public function __destruct()
{
if ($this->sid) $this->logout();
}
}
$rpc = new XmlRpc_Freshmeat($argv[1], $argv[2]);
$rpc->chatty = true;
$project = 'htmlpurifier';
$branch = 'Default';
$version = file_get_contents('../VERSION');
$result = $rpc->fetchRelease($project, $branch, $version);
if (!isset($result['faultCode'])) {
echo "Freshmeat release already exists.\n";
exit(0);
}
$changes = strtr(file_get_contents('../WHATSNEW'), array("\r" => '', "\n" => ' '));
$focus = (int) trim(file_get_contents('../FOCUS'));
if (strlen($changes) > 600) {
echo "WHATSNEW entry is too long.\n";
exit(1);
}
$rpc->publishRelease(
'project_name', $project,
'branch_name', $branch,
'version', $version,
'changes', $changes,
'release_focus', $focus,
'url_tgz', "http://htmlpurifier.org/releases/htmlpurifier-$version.tar.gz",
'url_zip', "http://htmlpurifier.org/releases/htmlpurifier-$version.zip",
'url_changelog', "http://htmlpurifier.org/svnroot/htmlpurifier/tags/$version/NEWS"
);
// vim: et sw=4 sts=4

View File

@@ -0,0 +1,75 @@
<?php
require_once 'common.php'; // load library
require_once 'HTMLPurifier/Printer/ConfigForm.php';
$config = HTMLPurifier_Config::loadArrayFromForm($_POST, 'config');
// you can do custom configuration!
if (file_exists('allConfigForm.settings.php')) {
include 'allConfigForm.settings.php';
}
$gen_config = HTMLPurifier_Config::createDefault();
$printer_config_form = new HTMLPurifier_Printer_ConfigForm(
'config',
'http://htmlpurifier.org/live/configdoc/plain.html#%s'
);
$purifier = new HTMLPurifier($config);
$html = isset($_POST['html']) ? $_POST['html'] : "";
$purified = $purifier->purify($html);
echo '<?xml version="1.0" encoding="UTF-8" ?>';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>HTML Purifier All Config Form smoketest</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
.hp-config {margin-left:auto; margin-right:auto;}
.HTMLPurifier_Printer table {border-collapse:collapse;
border:1px solid #000; width:600px;
margin:1em auto;font-family:sans-serif;font-size:75%;}
.HTMLPurifier_Printer td, .HTMLPurifier_Printer th {padding:3px;
border:1px solid #000;background:#CCC; vertical-align: baseline;}
.HTMLPurifier_Printer th {text-align:left;background:#CCF;width:20%;}
.HTMLPurifier_Printer caption {font-size:1.5em; font-weight:bold;}
.HTMLPurifier_Printer .heavy {background:#99C;text-align:center;}
.HTMLPurifier_Printer .unsafe {background:#C99;}
dt {font-weight:bold;}
</style>
<link rel="stylesheet" href="../library/HTMLPurifier/Printer/ConfigForm.css" type="text/css" />
<script defer="defer" type="text/javascript" src="../library/HTMLPurifier/Printer/ConfigForm.js"></script>
</head>
<body>
<h1>HTML Purifier All Config Form Smoketest</h1>
<p>This prints config form for everything we support.</p>
<form method="post" action="" name="hp-configform">
<table style="width:100%">
<tr><th>Input</th><th>Output</th>
<tr><td style="width:50%">
<textarea name="html" style="width:100%" rows="15"><?php echo htmlspecialchars($html) ?></textarea>
</td><td style="width:50%">
<textarea name="result" style="width:100%" rows="15"><?php echo htmlspecialchars($purified) ?></textarea>
</td></tr>
</table>
<input type="submit" />
<?php
echo $printer_config_form->render($config);
?>
</form>
<pre><?php
echo htmlspecialchars(var_export($config->getAll(), true));
?></pre>
<?php
// vim: et sw=4 sts=4

View File

@@ -21,10 +21,8 @@ if ($data !== false && $data !== '') {
// REQUIRED SETTINGS
// Note on running SimpleTest:
// Because HTML Purifier is PHP5-only and E_STRICT compliant, SimpleTest
// 1.0.1 will not work; you need to run SimpleTest off its trunk using:
//
// $ svn co https://simpletest.svn.sourceforge.net/svnroot/simpletest/simpletest/trunk 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

View File

@@ -76,7 +76,7 @@ class Debugger
public $scope_nextID = 1;
public $add_pre = true;
public function Debugger()
public function __construct()
{
$this->add_pre = !extension_loaded('xdebug');
}

View File

@@ -42,7 +42,7 @@ class HTMLPurifier_AttrCollectionsTest extends HTMLPurifier_Harness
'Brocolli' => array()
);
$collections->__construct($types, $modules);
$collections->doConstruct($types, $modules);
// this is without identifier expansion or inclusions
$this->assertIdentical(
$collections->info,
@@ -113,8 +113,8 @@ class HTMLPurifier_AttrCollectionsTest extends HTMLPurifier_Harness
$c_object = new HTMLPurifier_AttrDef_HTML_Color();
$u_object = new HTMLPurifier_AttrDef_URI();
$types->setReturnValue('get', $c_object, array('Color'));
$types->setReturnValue('get', $u_object, array('URI'));
$types->returns('get', $c_object, array('Color'));
$types->returns('get', $u_object, array('URI'));
$collections->expandIdentifiers($attr, $types);

View File

@@ -5,7 +5,7 @@ class HTMLPurifier_AttrDef_CSS_Composite_Testable extends
{
// we need to pass by ref to get the mocks in
public function HTMLPurifier_AttrDef_CSS_Composite_Testable(&$defs)
public function __construct(&$defs)
{
$this->defs =& $defs;
}
@@ -35,7 +35,7 @@ class HTMLPurifier_AttrDef_CSS_CompositeTest extends HTMLPurifier_AttrDefHarness
$output = 'foobar';
$def1_params = array($input, $config, $context);
$def1->expectOnce('validate', $def1_params);
$def1->setReturnValue('validate', $output, $def1_params);
$def1->returns('validate', $output, $def1_params);
$def2->expectNever('validate');
$result = $def->validate($input, $config, $context);
@@ -51,9 +51,9 @@ class HTMLPurifier_AttrDef_CSS_CompositeTest extends HTMLPurifier_AttrDefHarness
$output = 'booma';
$def_params = array($input, $config, $context);
$def1->expectOnce('validate', $def_params);
$def1->setReturnValue('validate', false, $def_params);
$def1->returns('validate', false, $def_params);
$def2->expectOnce('validate', $def_params);
$def2->setReturnValue('validate', $output, $def_params);
$def2->returns('validate', $output, $def_params);
$result = $def->validate($input, $config, $context);
$this->assertIdentical($output, $result);
@@ -68,9 +68,9 @@ class HTMLPurifier_AttrDef_CSS_CompositeTest extends HTMLPurifier_AttrDefHarness
$output = false;
$def_params = array($input, $config, $context);
$def1->expectOnce('validate', $def_params);
$def1->setReturnValue('validate', false, $def_params);
$def1->returns('validate', false, $def_params);
$def2->expectOnce('validate', $def_params);
$def2->setReturnValue('validate', false, $def_params);
$def2->returns('validate', false, $def_params);
$result = $def->validate($input, $config, $context);
$this->assertIdentical($output, $result);

View File

@@ -17,7 +17,7 @@ class HTMLPurifier_AttrDef_CSS_ImportantDecoratorTest extends HTMLPurifier_AttrD
{
if ($output === null) $output = $input;
$this->mock->expectOnce('validate', array($input, $this->config, $this->context));
$this->mock->setReturnValue('validate', $output);
$this->mock->returns('validate', $output);
}
public function testImportant()

View File

@@ -83,6 +83,8 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('background-position:left 90%;');
$this->assertDef('border-spacing:1em;');
$this->assertDef('border-spacing:1em 2em;');
$this->assertDef('border-color: rgb(0, 0, 0) rgb(10,0,10)', 'border-color:rgb(0,0,0) rgb(10,0,10);');
$this->assertDef('border: rgb(0, 0, 0)', 'border:rgb(0,0,0);');
// duplicates
$this->assertDef('text-align:right;text-align:left;',
@@ -127,11 +129,12 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('scrollbar-highlight-color:#ff69b4;');
$this->assertDef('scrollbar-shadow-color:#f0f;');
$this->assertDef('opacity:.2;');
$this->assertDef('-moz-opacity:.2;');
$this->assertDef('-khtml-opacity:.2;');
$this->assertDef('filter:alpha(opacity=20);');
$this->assertDef('border-top-left-radius:55pt 25pt;');
}
public function testImportant()
@@ -146,6 +149,7 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('display:none;');
$this->assertDef('visibility:visible;');
$this->assertDef('overflow:scroll;');
$this->assertDef('opacity:.2;');
}
public function testForbidden()
@@ -165,6 +169,13 @@ class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('z-index:-2;');
}
public function testAllowDuplicates()
{
$this->config->set('CSS.AllowDuplicates', true);
$this->assertDef('text-align:right;text-align:left;');
$this->assertDef('text-align:right;text-align:left;text-align:right;');
}
}
// vim: et sw=4 sts=4

View File

@@ -7,7 +7,7 @@ class HTMLPurifier_AttrDef_HTML_BoolTest extends HTMLPurifier_AttrDefHarness
{
$this->def = new HTMLPurifier_AttrDef_HTML_Bool('foo');
$this->assertDef('foo');
$this->assertDef('', false);
$this->assertDef('', 'foo');
$this->assertDef('bar', 'foo');
}

View File

@@ -105,6 +105,17 @@ class HTMLPurifier_AttrDef_HTML_IDTest extends HTMLPurifier_AttrDefHarness
}
public function testRelaxed()
{
$this->config->set('Attr.ID.HTML5', true);
$this->assertDef('123');
$this->assertDef('x[1]');
$this->assertDef('not ok', false);
$this->assertDef(' ', false);
$this->assertDef('', false);
}
}
// vim: et sw=4 sts=4

View File

@@ -19,7 +19,7 @@ class HTMLPurifier_AttrDef_SwitchTest extends HTMLPurifier_AttrDefHarness
$token = new HTMLPurifier_Token_Start('tag');
$this->context->register('CurrentToken', $token);
$this->with->expectOnce('validate');
$this->with->setReturnValue('validate', 'foo');
$this->with->returns('validate', 'foo');
$this->assertDef('bar', 'foo');
}
@@ -28,7 +28,7 @@ class HTMLPurifier_AttrDef_SwitchTest extends HTMLPurifier_AttrDefHarness
$token = new HTMLPurifier_Token_Start('other-tag');
$this->context->register('CurrentToken', $token);
$this->without->expectOnce('validate');
$this->without->setReturnValue('validate', 'foo');
$this->without->returns('validate', 'foo');
$this->assertDef('bar', 'foo');
}

View File

@@ -19,12 +19,13 @@ class HTMLPurifier_AttrDef_URI_HostTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('sub.test.');
$this->assertDef('.test', false);
$this->assertDef('ff');
$this->assertDef('1f', false);
$this->assertDef('1f'); // per RFC 1123
// See also http://serverfault.com/questions/638260/is-it-valid-for-a-hostname-to-start-with-a-digit
$this->assertDef('-f', false);
$this->assertDef('f1');
$this->assertDef('f-', false);
$this->assertDef('sub.ff');
$this->assertDef('sub.1f', false);
$this->assertDef('sub.1f'); // per RFC 1123
$this->assertDef('sub.-f', false);
$this->assertDef('sub.f1');
$this->assertDef('sub.f-', false);
@@ -35,6 +36,7 @@ class HTMLPurifier_AttrDef_URI_HostTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('f1.top');
$this->assertDef('f1_f2.ex.top', false);
$this->assertDef('f-.top', false);
$this->assertDef('1a');
$this->assertDef("\xE4\xB8\xAD\xE6\x96\x87.com.cn", false);
@@ -42,7 +44,7 @@ class HTMLPurifier_AttrDef_URI_HostTest extends HTMLPurifier_AttrDefHarness
public function testIDNA()
{
if (!$GLOBALS['HTMLPurifierTest']['Net_IDNA2']) {
if (!$GLOBALS['HTMLPurifierTest']['Net_IDNA2'] && !function_exists("idn_to_ascii")) {
return false;
}
$this->config->set('Core.EnableIDNA', true);

View File

@@ -22,6 +22,7 @@ class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
$this->assertDef('news:rec.alt');
$this->assertDef('nntp://news.example.com/324234');
$this->assertDef('mailto:bob@example.com');
$this->assertDef('tel:+15555555555');
}
public function testIntegrationWithPercentEncoder()
@@ -105,9 +106,9 @@ class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
generate_mock_once('HTMLPurifier_URIDefinition');
$uri_def = new HTMLPurifier_URIDefinitionMock();
$uri_def->expectOnce('filter', array($uri, '*', '*'));
$uri_def->setReturnValue('filter', true, array($uri, '*', '*'));
$uri_def->returns('filter', true, array($uri, '*', '*'));
$uri_def->expectOnce('postFilter', array($uri, '*', '*'));
$uri_def->setReturnValue('postFilter', true, array($uri, '*', '*'));
$uri_def->returns('postFilter', true, array($uri, '*', '*'));
$uri_def->setup = true;
// Since definitions are no longer passed by reference, we need
@@ -117,13 +118,13 @@ class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
// overload entire definitions.
generate_mock_once('HTMLPurifier_DefinitionCache');
$cache_mock = new HTMLPurifier_DefinitionCacheMock();
$cache_mock->setReturnValue('get', $uri_def);
$cache_mock->returns('get', $uri_def);
generate_mock_once('HTMLPurifier_DefinitionCacheFactory');
$factory_mock = new HTMLPurifier_DefinitionCacheFactoryMock();
$old = HTMLPurifier_DefinitionCacheFactory::instance();
HTMLPurifier_DefinitionCacheFactory::instance($factory_mock);
$factory_mock->setReturnValue('create', $cache_mock);
$factory_mock->returns('create', $cache_mock);
$this->assertDef('http://example.com');

View File

@@ -26,7 +26,7 @@ class HTMLPurifier_AttrValidator_ErrorsTest extends HTMLPurifier_ErrorsHarness
$transform = new HTMLPurifier_AttrTransformMock();
$input = array('original' => 'value');
$output = array('class' => 'value'); // must be valid
$transform->setReturnValue('transform', $output, array($input, new AnythingExpectation(), new AnythingExpectation()));
$transform->returns('transform', $output, array($input, new AnythingExpectation(), new AnythingExpectation()));
$def->info_attr_transform_pre[] = $transform;
$token = new HTMLPurifier_Token_Start('span', $input, 1);

View File

@@ -528,7 +528,7 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
$mock->expectNever('set');
$config->set('HTML.DefinitionID', 'HTMLPurifier_ConfigTest->testDefinitionCachingOptimized');
$mock->expectOnce('get');
$mock->setReturnValue('get', null);
$mock->returns('get', null);
$this->assertTrue($config->maybeGetRawHTMLDefinition());
$this->assertTrue($config->maybeGetRawHTMLDefinition());
$mock->expectOnce('add');
@@ -546,7 +546,7 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
$mock->expectNever('set');
$config->set('HTML.DefinitionID', 'HTMLPurifier_ConfigTest->testDefinitionCachingOptimizedHit');
$mock->expectOnce('get');
$mock->setReturnValue('get', $fake_def);
$mock->returns('get', $fake_def);
$this->assertNull($config->maybeGetRawHTMLDefinition());
$config->getDefinition('HTML');
$config->getDefinition('HTML');
@@ -564,7 +564,7 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
generate_mock_once("HTMLPurifier_DefinitionCache");
$mock = new HTMLPurifier_DefinitionCacheMock();
$config = HTMLPurifier_Config::createDefault();
$factory->setReturnValue('create', $mock, array($type, $config));
$factory->returns('create', $mock, array($type, $config));
return array($mock, $config);
}
protected function teardownCacheMock()

View File

@@ -14,21 +14,21 @@ class HTMLPurifier_DefinitionCache_Decorator_CleanupTest extends HTMLPurifier_De
public function setupMockForSuccess($op)
{
$this->mock->expectOnce($op, array($this->def, $this->config));
$this->mock->setReturnValue($op, true, array($this->def, $this->config));
$this->mock->returns($op, true, array($this->def, $this->config));
$this->mock->expectNever('cleanup');
}
public function setupMockForFailure($op)
{
$this->mock->expectOnce($op, array($this->def, $this->config));
$this->mock->setReturnValue($op, false, array($this->def, $this->config));
$this->mock->returns($op, false, array($this->def, $this->config));
$this->mock->expectOnce('cleanup', array($this->config));
}
public function test_get()
{
$this->mock->expectOnce('get', array($this->config));
$this->mock->setReturnValue('get', true, array($this->config));
$this->mock->returns('get', true, array($this->config));
$this->mock->expectNever('cleanup');
$this->assertEqual($this->cache->get($this->config), $this->def);
}
@@ -36,7 +36,7 @@ class HTMLPurifier_DefinitionCache_Decorator_CleanupTest extends HTMLPurifier_De
public function test_get_failure()
{
$this->mock->expectOnce('get', array($this->config));
$this->mock->setReturnValue('get', false, array($this->config));
$this->mock->returns('get', false, array($this->config));
$this->mock->expectOnce('cleanup', array($this->config));
$this->assertEqual($this->cache->get($this->config), false);
}

View File

@@ -14,21 +14,21 @@ class HTMLPurifier_DefinitionCache_Decorator_MemoryTest extends HTMLPurifier_Def
public function setupMockForSuccess($op)
{
$this->mock->expectOnce($op, array($this->def, $this->config));
$this->mock->setReturnValue($op, true, array($this->def, $this->config));
$this->mock->returns($op, true, array($this->def, $this->config));
$this->mock->expectNever('get');
}
public function setupMockForFailure($op)
{
$this->mock->expectOnce($op, array($this->def, $this->config));
$this->mock->setReturnValue($op, false, array($this->def, $this->config));
$this->mock->returns($op, false, array($this->def, $this->config));
$this->mock->expectOnce('get', array($this->config));
}
public function test_get()
{
$this->mock->expectOnce('get', array($this->config)); // only ONE call!
$this->mock->setReturnValue('get', $this->def, array($this->config));
$this->mock->returns('get', $this->def, array($this->config));
$this->assertEqual($this->cache->get($this->config), $this->def);
$this->assertEqual($this->cache->get($this->config), $this->def);
}

View File

@@ -14,7 +14,7 @@ class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_Definitio
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
$config = $this->generateConfigMock('serial');
$config->setReturnValue('get', 2, array('Test.DefinitionRev'));
$config->returns('get', 2, array('Test.DefinitionRev'));
$config->version = '1.0.0';
$config_md5 = '1.0.0,serial,2';
@@ -123,12 +123,12 @@ class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_Definitio
$config1 = $this->generateConfigMock();
$config1->version = '0.9.0';
$config1->setReturnValue('get', 574, array('Test.DefinitionRev'));
$config1->returns('get', 574, array('Test.DefinitionRev'));
$def1 = $this->generateDefinition(array('info' => 1));
$config2 = $this->generateConfigMock();
$config2->version = '1.0.0beta';
$config2->setReturnValue('get', 1, array('Test.DefinitionRev'));
$config2->returns('get', 1, array('Test.DefinitionRev'));
$def2 = $this->generateDefinition(array('info' => 3));
$cache->set($def1, $config1);
@@ -147,12 +147,12 @@ class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_Definitio
$config1 = $this->generateConfigMock('serial1');
$config1->version = '1.0.0';
$config1->setReturnValue('get', 1, array('Test.DefinitionRev'));
$config1->returns('get', 1, array('Test.DefinitionRev'));
$def1 = $this->generateDefinition(array('info' => 1));
$config2 = $this->generateConfigMock('serial2');
$config2->version = '1.0.0';
$config2->setReturnValue('get', 34, array('Test.DefinitionRev'));
$config2->returns('get', 34, array('Test.DefinitionRev'));
$def2 = $this->generateDefinition(array('info' => 3));
$cache->set($def1, $config1);
@@ -190,9 +190,9 @@ class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_Definitio
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
$config = $this->generateConfigMock('serial');
$config->version = '1.0.0';
$config->setReturnValue('get', 1, array('Test.DefinitionRev'));
$config->returns('get', 1, array('Test.DefinitionRev'));
$dir = dirname(__FILE__) . '/SerializerTest';
$config->setReturnValue('get', $dir, array('Cache.SerializerPath'));
$config->returns('get', $dir, array('Cache.SerializerPath'));
$def_original = $this->generateDefinition();
$cache->add($def_original, $config);
@@ -208,22 +208,36 @@ class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_Definitio
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
$config = $this->generateConfigMock('serial');
$config->version = '1.0.0';
$config->setReturnValue('get', 1, array('Test.DefinitionRev'));
$config->returns('get', 1, array('Test.DefinitionRev'));
$dir = dirname(__FILE__) . '/SerializerTest';
$config->setReturnValue('get', $dir, array('Cache.SerializerPath'));
$config->setReturnValue('get', 0777, array('Cache.SerializerPermissions'));
$config->returns('get', $dir, array('Cache.SerializerPath'));
$config->returns('get', 0700, array('Cache.SerializerPermissions'));
$def_original = $this->generateDefinition();
$cache->add($def_original, $config);
$this->assertFileExist($dir . '/Test/1.0.0,serial,1.ser');
$this->assertEqual(0666, 0777 & fileperms($dir . '/Test/1.0.0,serial,1.ser'));
$this->assertEqual(0777, 0777 & fileperms($dir . '/Test'));
$this->assertEqual(0600, 0777 & fileperms($dir . '/Test/1.0.0,serial,1.ser'));
$this->assertEqual(0700, 0777 & fileperms($dir . '/Test'));
unlink($dir . '/Test/1.0.0,serial,1.ser');
rmdir( $dir . '/Test');
}
public function testNoInfiniteLoop()
{
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
$config = $this->generateConfigMock('serial');
$config->version = '1.0.0';
$config->returns('get', 1, array('Test.DefinitionRev'));
$dir = dirname(__FILE__) . '/SerializerTest';
$config->returns('get', $dir, array('Cache.SerializerPath'));
$config->returns('get', 0400, array('Cache.SerializerPermissions'));
$cache->cleanup($config);
}
}
// vim: et sw=4 sts=4

View File

@@ -12,7 +12,7 @@ class HTMLPurifier_DefinitionCacheHarness extends HTMLPurifier_Harness
{
generate_mock_once('HTMLPurifier_Config');
$config = new HTMLPurifier_ConfigMock();
$config->setReturnValue('getBatchSerial', $serial, array('Test'));
$config->returns('getBatchSerial', $serial, array('Test'));
$config->version = '1.0.0';
return $config;
}

View File

@@ -11,8 +11,8 @@ class HTMLPurifier_DefinitionCacheTest extends HTMLPurifier_Harness
generate_mock_once('HTMLPurifier_Config');
$config = new HTMLPurifier_ConfigMock();
$config->version = '1.0.0'; // hopefully no conflicts
$config->setReturnValue('get', 10, array('Test.DefinitionRev'));
$config->setReturnValue('getBatchSerial', 'hash', array('Test'));
$config->returns('get', 10, array('Test.DefinitionRev'));
$config->returns('getBatchSerial', 'hash', array('Test'));
$this->assertIdentical($cache->isOld('1.0.0,hash,10', $config), false);
$this->assertIdentical($cache->isOld('1.5.0,hash,1', $config), true);

View File

@@ -15,9 +15,9 @@ class HTMLPurifier_ErrorCollectorTest extends HTMLPurifier_Harness
generate_mock_once('HTMLPurifier_Generator');
parent::setup();
$this->language = new HTMLPurifier_LanguageMock();
$this->language->setReturnValue('getErrorName', 'Error', array(E_ERROR));
$this->language->setReturnValue('getErrorName', 'Warning', array(E_WARNING));
$this->language->setReturnValue('getErrorName', 'Notice', array(E_NOTICE));
$this->language->returns('getErrorName', 'Error', array(E_ERROR));
$this->language->returns('getErrorName', 'Warning', array(E_WARNING));
$this->language->returns('getErrorName', 'Notice', array(E_NOTICE));
// this might prove to be troublesome if we need to set config
$this->generator = new HTMLPurifier_Generator($this->config, $this->context);
$this->line = false;
@@ -30,10 +30,10 @@ class HTMLPurifier_ErrorCollectorTest extends HTMLPurifier_Harness
public function test()
{
$language = $this->language;
$language->setReturnValue('getMessage', 'Message 1', array('message-1'));
$language->setReturnValue('formatMessage', 'Message 2', array('message-2', array(1 => 'param')));
$language->setReturnValue('formatMessage', ' at line 23', array('ErrorCollector: At line', array('line' => 23)));
$language->setReturnValue('formatMessage', ' at line 3', array('ErrorCollector: At line', array('line' => 3)));
$language->returns('getMessage', 'Message 1', array('message-1'));
$language->returns('formatMessage', 'Message 2', array('message-2', array(1 => 'param')));
$language->returns('formatMessage', ' at line 23', array('ErrorCollector: At line', array('line' => 23)));
$language->returns('formatMessage', ' at line 3', array('ErrorCollector: At line', array('line' => 3)));
$this->line = 23;
$this->collector->send(E_ERROR, 'message-1');
@@ -60,7 +60,7 @@ class HTMLPurifier_ErrorCollectorTest extends HTMLPurifier_Harness
public function testNoErrors()
{
$this->language->setReturnValue('getMessage', 'No errors', array('ErrorCollector: No errors'));
$this->language->returns('getMessage', 'No errors', array('ErrorCollector: No errors'));
$formatted_result = '<p>No errors</p>';
$this->assertIdentical(
@@ -71,8 +71,8 @@ class HTMLPurifier_ErrorCollectorTest extends HTMLPurifier_Harness
public function testNoLineNumbers()
{
$this->language->setReturnValue('getMessage', 'Message 1', array('message-1'));
$this->language->setReturnValue('getMessage', 'Message 2', array('message-2'));
$this->language->returns('getMessage', 'Message 1', array('message-1'));
$this->language->returns('getMessage', 'Message 2', array('message-2'));
$this->collector->send(E_ERROR, 'message-1');
$this->collector->send(E_ERROR, 'message-2');
@@ -98,12 +98,12 @@ class HTMLPurifier_ErrorCollectorTest extends HTMLPurifier_Harness
// 0
$current_token = new HTMLPurifier_Token_Start('a', array('href' => 'http://example.com'), 32);
$this->language->setReturnValue('formatMessage', 'Token message',
$this->language->returns('formatMessage', 'Token message',
array('message-data-token', array('CurrentToken' => $current_token)));
$this->collector->send(E_NOTICE, 'message-data-token');
$current_attr = 'href';
$this->language->setReturnValue('formatMessage', '$CurrentAttr.Name => $CurrentAttr.Value',
$this->language->returns('formatMessage', '$CurrentAttr.Name => $CurrentAttr.Value',
array('message-attr', array('CurrentToken' => $current_token)));
// 1
@@ -125,10 +125,10 @@ class HTMLPurifier_ErrorCollectorTest extends HTMLPurifier_Harness
/*
public function testNestedErrors()
{
$this->language->setReturnValue('getMessage', 'Message 1', array('message-1'));
$this->language->setReturnValue('getMessage', 'Message 2', array('message-2'));
$this->language->setReturnValue('formatMessage', 'End Message', array('end-message', array(1 => 'param')));
$this->language->setReturnValue('formatMessage', ' at line 4', array('ErrorCollector: At line', array('line' => 4)));
$this->language->returns('getMessage', 'Message 1', array('message-1'));
$this->language->returns('getMessage', 'Message 2', array('message-2'));
$this->language->returns('formatMessage', 'End Message', array('end-message', array(1 => 'param')));
$this->language->returns('formatMessage', ' at line 4', array('ErrorCollector: At line', array('line' => 4)));
$this->line = 4;
$this->collector->start();

View File

@@ -15,8 +15,8 @@ class HTMLPurifier_Filter_ExtractStyleBlocksTest extends HTMLPurifier_Harness
$this->assertIdentical($result, 'Test');
$this->assertIdentical($purifier->context->get('StyleBlocks'),
array(
".foo {\ntext-align:center;\n}",
"* {\nfont-size:12pt;\n}"
".foo {\ntext-align:center\n}",
"* {\nfont-size:12pt\n}"
)
);
}
@@ -85,7 +85,7 @@ class HTMLPurifier_Filter_ExtractStyleBlocksTest extends HTMLPurifier_Harness
public function test_cleanCSS_selector()
{
$this->assertCleanCSS("a .foo #id div.cl#foo {\nfont-weight:700;\n}");
$this->assertCleanCSS("a .foo #id div.cl#foo {\nfont-weight:700\n}");
}
public function test_cleanCSS_angledBrackets()
@@ -110,7 +110,7 @@ class HTMLPurifier_Filter_ExtractStyleBlocksTest extends HTMLPurifier_Harness
public function test_cleanCSS_bogus()
{
$this->assertCleanCSS("div {bogus:tree;}", "div {\n}");
$this->assertCleanCSS("div {bogus:tree}", "div {\n}");
}
/* [CONTENT]
@@ -134,8 +134,8 @@ class HTMLPurifier_Filter_ExtractStyleBlocksTest extends HTMLPurifier_Harness
{
$this->config->set('Filter.ExtractStyleBlocks.Scope', '#foo');
$this->assertCleanCSS(
"p {\ntext-indent:1em;\n}",
"#foo p {\ntext-indent:1em;\n}"
"p {\ntext-indent:1em\n}",
"#foo p {\ntext-indent:1em\n}"
);
}
@@ -143,29 +143,29 @@ class HTMLPurifier_Filter_ExtractStyleBlocksTest extends HTMLPurifier_Harness
{
$this->config->set('Filter.ExtractStyleBlocks.Scope', '#foo');
$this->assertCleanCSS(
"b, i {\ntext-decoration:underline;\n}",
"#foo b, #foo i {\ntext-decoration:underline;\n}"
"b, i {\ntext-decoration:underline\n}",
"#foo b, #foo i {\ntext-decoration:underline\n}"
);
}
public function test_cleanCSS_scopeWithNaughtySelector()
{
$this->config->set('Filter.ExtractStyleBlocks.Scope', '#foo');
$this->assertCleanCSS(" + p {\ntext-indent:1em;\n}", '');
$this->assertCleanCSS(" + p {\ntext-indent:1em\n}", "#foo p {\ntext-indent:1em\n}");
}
public function test_cleanCSS_scopeWithMultipleNaughtySelectors()
{
$this->config->set('Filter.ExtractStyleBlocks.Scope', '#foo');
$this->assertCleanCSS(" ++ ++ p {\ntext-indent:1em;\n}", '');
$this->assertCleanCSS(" ++ ++ p {\ntext-indent:1em\n}", "#foo p {\ntext-indent:1em\n}");
}
public function test_cleanCSS_scopeWithCommas()
{
$this->config->set('Filter.ExtractStyleBlocks.Scope', '#foo, .bar');
$this->assertCleanCSS(
"p {\ntext-indent:1em;\n}",
"#foo p, .bar p {\ntext-indent:1em;\n}"
"p {\ntext-indent:1em\n}",
"#foo p, .bar p {\ntext-indent:1em\n}"
);
}
@@ -173,8 +173,8 @@ class HTMLPurifier_Filter_ExtractStyleBlocksTest extends HTMLPurifier_Harness
{
$this->config->set('Filter.ExtractStyleBlocks.Scope', '#foo, .bar');
$this->assertCleanCSS(
"p, div {\ntext-indent:1em;\n}",
"#foo p, .bar p, #foo div, .bar div {\ntext-indent:1em;\n}"
"p, div {\ntext-indent:1em\n}",
"#foo p, .bar p, #foo div, .bar div {\ntext-indent:1em\n}"
);
}
@@ -183,19 +183,19 @@ class HTMLPurifier_Filter_ExtractStyleBlocksTest extends HTMLPurifier_Harness
$this->config->set('Filter.ExtractStyleBlocks.Scope', 'p');
$this->assertCleanCSS(
"div {
text-align:right;
text-align:right
}
p div {
text-align:left;
text-align:left
}",
"p div {
text-align:right;
text-align:right
}
p p div {
text-align:left;
text-align:left
}"
);
}
@@ -205,11 +205,11 @@ text-align:left;
$this->assertCleanCSS(
"<!--
div {
text-align:right;
text-align:right
}
-->",
"div {
text-align:right;
text-align:right
}"
);
}
@@ -218,7 +218,7 @@ text-align:right;
{
$this->assertCleanCSS(
"{
b { text-align: center; }
b { text-align: center }
}",
""
);
@@ -228,24 +228,24 @@ text-align:right;
{
$this->assertCleanCSS(
"&, & {
text-align: center;
text-align: center
}",
""
);
$this->assertCleanCSS(
"&, b {
text-align:center;
text-align:center
}",
"b {
text-align:center;
text-align:center
}"
);
$this->assertCleanCSS(
"& a #foo:hover.bar +b > i {
text-align:center;
text-align:center
}",
"a #foo:hover.bar + b \\3E i {
text-align:center;
text-align:center
}"
);
$this->assertCleanCSS("doesnt-exist { text-align:center }", "");
@@ -253,7 +253,7 @@ text-align:center;
public function test_cleanCSS_caseSensitive()
{
$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}");
}
}

View File

@@ -326,7 +326,7 @@ a[href|title]
generate_mock_once('HTMLPurifier_Injector');
$injector = new HTMLPurifier_InjectorMock();
$injector->name = 'MyInjector';
$injector->setReturnValue('checkNeeded', false);
$injector->returns('checkNeeded', false);
$module = $this->config->getHTMLDefinition(true)->getAnonymousModule();
$module->info_injector[] = $injector;
@@ -343,7 +343,7 @@ a[href|title]
generate_mock_once('HTMLPurifier_Injector');
$injector = new HTMLPurifier_InjectorMock();
$injector->name = 'MyInjector';
$injector->setReturnValue('checkNeeded', 'a');
$injector->returns('checkNeeded', 'a');
$module = $this->config->getHTMLDefinition(true)->getAnonymousModule();
$module->info_injector[] = $injector;

View File

@@ -13,7 +13,7 @@ class HTMLPurifier_HTMLModule_TargetBlankTest extends HTMLPurifier_HTMLModuleHar
{
$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" target="_blank">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>'
);
}

View File

@@ -0,0 +1,42 @@
<?php
class HTMLPurifier_HTMLModule_TargetNoreferrerTest extends HTMLPurifier_HTMLModuleHarness
{
public function setUp()
{
parent::setUp();
$this->config->set('HTML.TargetNoreferrer', 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="noreferrer">x</a>'
);
}
public function testNoreferrerNoDupe()
{
$this->config->set('Attr.AllowedRel', 'noreferrer');
$this->assertResult(
'<a href="http://google.com" target="_blank" rel="noreferrer">x</a>',
'<a href="http://google.com" target="_blank" rel="noreferrer">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="noreferrer">x</a>'
);
}
}
// vim: et sw=4 sts=4

View File

@@ -57,7 +57,7 @@ class HTMLPurifier_HTMLModule_TidyTest extends HTMLPurifier_Harness
'heavy-fix-1' => $hf1 = $j++,
'heavy-fix-2' => $hf2 = $j++
);
$module->setReturnValue('makeFixes', $fixes);
$module->returns('makeFixes', $fixes);
$config = HTMLPurifier_Config::create(array(
'HTML.TidyLevel' => 'none'

View File

@@ -14,7 +14,7 @@ class HTMLPurifier_HTMLModuleManagerTest extends HTMLPurifier_Harness
generate_mock_once('HTMLPurifier_AttrDef');
$attrdef = new HTMLPurifier_AttrDefMock();
$attrdef->setReturnValue('make', $attrdef_nmtokens);
$attrdef->returns('make', $attrdef_nmtokens);
$manager->attrTypes->set('NMTOKENS', $attrdef);
return $manager;
}

View File

@@ -27,6 +27,9 @@ class HTMLPurifier_HTMLT extends HTMLPurifier_Harness
$this->config->loadIni($ini_file);
}
$expect = isset($hash['EXPECT']) ? $hash['EXPECT'] : $hash['HTML'];
if (isset($hash['ERROR'])) {
$this->expectError($hash['ERROR']);
}
$this->assertPurification(rtrim($hash['HTML']), rtrim($expect));
if (isset($hash['INI'])) unlink($ini_file);
}

View File

@@ -0,0 +1,7 @@
ERROR: Cannot allow ul/ol without allowing li
--INI--
HTML.AllowedElements = ul
--HTML--
<ul><li>foo</li></ul>
--EXPECT--
--# vim: et sw=4 sts=4

View File

@@ -52,6 +52,14 @@ class HTMLPurifier_Injector_LinkifyTest extends HTMLPurifier_InjectorHarness
$this->assertResult('<a><span>http://example.com</span></a>');
}
public function testRegexIsSmart()
{
$this->assertResult('http://example.com/foo.', '<a href="http://example.com/foo">http://example.com/foo</a>.');
$this->assertResult('“http://example.com/foo”', '“<a href="http://example.com/foo">http://example.com/foo</a>”');
$this->assertResult('“http://example.com”', '“<a href="http://example.com">http://example.com</a>”');
$this->assertResult('(http://example.com/f(o)o)', '(<a href="http://example.com/f(o)o">http://example.com/f(o)o</a>)');
}
}
// vim: et sw=4 sts=4

View File

@@ -91,6 +91,25 @@ class HTMLPurifier_Injector_RemoveEmptyTest extends HTMLPurifier_InjectorHarness
$this->assertResult('<b>&nbsp;</b>', "<b>\xC2\xA0</b>");
}
public function testRemoveIframe()
{
$this->config->set('HTML.SafeIframe', true);
$this->assertResult('<iframe></iframe>', '');
}
public function testNoRemoveIframe()
{
$this->config->set('HTML.SafeIframe', true);
$this->assertResult('<iframe src="http://google.com"></iframe>', '');
}
public function testRemoveDisallowedIframe()
{
$this->config->set('HTML.SafeIframe', true);
$this->config->set('URI.SafeIframeRegexp', '%^http://www.youtube.com/embed/%');
$this->assertResult('<iframe src="http://google.com"></iframe>', '');
}
}
// vim: et sw=4 sts=4

View File

@@ -57,7 +57,7 @@ class HTMLPurifier_Injector_SafeObjectTest extends HTMLPurifier_InjectorHarness
public function testIgnoreBogusData()
{
$this->assertResult(
'<object><param name="allowScriptAccess" value="always" /><param name="allowNetworking" value="always" /></object>',
'<object><param name="allowscriptaccess" value="always" /><param name="allowNetworking" value="always" /></object>',
'<object><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /></object>'
);
}
@@ -94,6 +94,13 @@ class HTMLPurifier_Injector_SafeObjectTest extends HTMLPurifier_InjectorHarness
);
}
public function testCaseInsensitive()
{
$this->assertResult(
'<object><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><param name="flashVars" value="a" /><param name="FlashVars" value="b" /></object>'
);
}
}
// vim: et sw=4 sts=4

View File

@@ -169,6 +169,16 @@ class HTMLPurifier_LexerTest extends HTMLPurifier_Harness
$this->assertExtractBody('<body>foo</body>bar</body>', 'foo</body>bar');
}
public function test_extractBody_ignoreCommented()
{
$this->assertExtractBody('$<!-- <body>foo</body> -->^');
}
public function test_extractBody_butCanStillWork()
{
$this->assertExtractBody('<!-- b --><body>a</body>', 'a');
}
// HTMLPurifier_Lexer->tokenizeHTML() --------------------------------------
public function assertTokenization($input, $expect, $alt_expect = array())
@@ -264,7 +274,8 @@ class HTMLPurifier_LexerTest extends HTMLPurifier_Harness
new HTMLPurifier_Token_End('poolasdf'),
new HTMLPurifier_Token_End('pooloka'),
),
'PH5P' => $alt,
// 20140831: Weird, but whatever...
'PH5P' => array(new HTMLPurifier_Token_Empty('asdf')),
)
);
}
@@ -800,6 +811,21 @@ div {}
);
}
public function test_tokenizeHTML_prematureDivClose()
{
$this->assertTokenization(
'</div>dontdie',
array(
new HTMLPurifier_Token_End('div'),
new HTMLPurifier_Token_Text('dontdie')
),
array(
'DOMLex' => $alt = array(new HTMLPurifier_Token_Text('dontdie')),
'PH5P' => $alt
)
);
}
/*

View File

@@ -47,13 +47,13 @@ class HTMLPurifier_Strategy_CompositeTest extends HTMLPurifier_Harness
$params_3 = array($input_3, $config, $context);
$mock_1->expectOnce('execute', $params_1);
$mock_1->setReturnValue('execute', $input_2, $params_1);
$mock_1->returns('execute', $input_2, $params_1);
$mock_2->expectOnce('execute', $params_2);
$mock_2->setReturnValue('execute', $input_3, $params_2);
$mock_2->returns('execute', $input_3, $params_2);
$mock_3->expectOnce('execute', $params_3);
$mock_3->setReturnValue('execute', $input_4, $params_3);
$mock_3->returns('execute', $input_4, $params_3);
// perform test

View File

@@ -151,6 +151,13 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness
$this->assertResult('<pre><font><font></font></font></pre>');
}
public function testDoubleKill()
{
$this->config->set('HTML.Allowed', 'ul');
$this->expectError('Cannot allow ul/ol without allowing li');
$this->assertResult('<ul>foo</ul>', '');
}
}
// vim: et sw=4 sts=4

View File

@@ -27,7 +27,7 @@ class HTMLPurifier_Strategy_MakeWellFormed_InjectorTest extends HTMLPurifier_Str
$i->start->skip = array(0 => true, 1 => true);
$mock->expectAt(1, 'handleEnd', array($i));
$mock->expectCallCount('handleEnd', 2);
$mock->setReturnValue('getRewindOffset', false);
$mock->returns('getRewindOffset', false);
$this->config->set('AutoFormat.AutoParagraph', false);
$this->config->set('AutoFormat.Linkify', false);
$this->config->set('AutoFormat.Custom', array($mock));

View File

@@ -189,7 +189,7 @@ class HTMLPurifier_Strategy_ValidateAttributesTest extends
{
$this->config->set('Attr.AllowedFrameTargets', '_top');
$this->config->set('HTML.Doctype', 'XHTML 1.0 Transitional');
$this->assertResult('<a href="foo" target="_top" />');
$this->assertResult('<a href="foo" target="_top" rel="noreferrer" />');
}
public function testRemoveTargetWhenNotSupported()

View File

@@ -10,8 +10,8 @@ class HTMLPurifier_URIDefinitionTest extends HTMLPurifier_URIHarness
$mock = new HTMLPurifier_URIFilterMock();
if ($expect) $mock->expectOnce('filter');
else $mock->expectNever('filter');
$mock->setReturnValue('filter', $result);
$mock->setReturnValue('prepare', $setup);
$mock->returns('filter', $result);
$mock->returns('prepare', $setup);
$mock->name = $i++;
$mock->post = $post;
return $mock;

View File

@@ -37,6 +37,11 @@ class HTMLPurifier_URIFilter_MakeAbsoluteTest extends HTMLPurifier_URIFilterHarn
$this->assertFiltering('mailto:bob@example.com');
}
public function testPreserveAltSchemeWithTel()
{
$this->assertFiltering('tel:+15555555555');
}
public function testFilterIgnoreHTTPSpecialCase()
{
$this->assertFiltering('http:/', 'http://example.com/');

View File

@@ -69,6 +69,14 @@ class HTMLPurifier_URIParserTest extends HTMLPurifier_Harness
);
}
public function testTelURI()
{
$this->assertParsing(
'tel:+1 (555) 555-5555',
'tel', null, null, null, '+1 (555) 555-5555', null, null
);
}
public function testIPv4Address()
{
$this->assertParsing(

View File

@@ -172,6 +172,42 @@ class HTMLPurifier_URISchemeTest extends HTMLPurifier_URIHarness
);
}
public function test_tel_strip_punctuation()
{
$this->assertValidation(
'tel:+1 (555) 555-5555', 'tel:+15555555555'
);
}
public function test_tel_regular()
{
$this->assertValidation(
'tel:+15555555555'
);
}
public function test_tel_with_extension()
{
$this->assertValidation(
'tel:+1-555-555-5555x123', 'tel:+15555555555x123'
);
}
public function test_tel_no_plus()
{
$this->assertValidation(
'tel:555-555-5555', 'tel:5555555555'
);
}
public function test_tel_strip_letters()
{
$this->assertValidation(
'tel:abcd1234',
'tel:1234'
);
}
public function test_data_png()
{
$this->assertValidation(
@@ -216,6 +252,16 @@ class HTMLPurifier_URISchemeTest extends HTMLPurifier_URIHarness
$this->assertValidation('ftp:///example.com', false);
}
public function test_data_bad_base64()
{
$this->assertValidation('data:image/png;base64,aGVsbG90aGVyZXk|', false);
}
public function test_data_too_short()
{
$this->assertValidation('data:image/png;base64,aGVsbG90aGVyZXk=', false);
}
}
// vim: et sw=4 sts=4

View File

@@ -32,14 +32,14 @@ class HTMLPurifier_URITest extends HTMLPurifier_URIHarness
{
$registry = $this->setUpSchemeRegistryMock();
$scheme_mock = new HTMLPurifier_URISchemeMock();
$registry->setReturnValue('getScheme', $scheme_mock, array($name, '*', '*'));
$registry->returns('getScheme', $scheme_mock, array($name, '*', '*'));
return $scheme_mock;
}
protected function setUpNoValidSchemes()
{
$registry = $this->setUpSchemeRegistryMock();
$registry->setReturnValue('getScheme', false, array('*', '*', '*'));
$registry->returns('getScheme', false, array('*', '*', '*'));
}
protected function tearDownSchemeRegistryMock()