0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2025-01-08 07:01:53 +00:00

Merged 463:474 for 1.1.2 release.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/branches/1.1@475 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2006-09-30 19:10:07 +00:00
parent 6ef8abd04f
commit 8104145580
24 changed files with 554 additions and 405 deletions

View File

@ -4,7 +4,7 @@
# Project related configuration options # Project related configuration options
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
PROJECT_NAME = HTML Purifier PROJECT_NAME = HTML Purifier
PROJECT_NUMBER = 1.0.0 PROJECT_NUMBER = 1.1.2
OUTPUT_DIRECTORY = "C:/Documents and Settings/Edward/My Documents/My Webs/htmlpurifier/docs/doxygen" OUTPUT_DIRECTORY = "C:/Documents and Settings/Edward/My Documents/My Webs/htmlpurifier/docs/doxygen"
CREATE_SUBDIRS = NO CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English OUTPUT_LANGUAGE = English
@ -89,9 +89,12 @@ EXCLUDE =
EXCLUDE_SYMLINKS = NO EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS = */tests/* \ EXCLUDE_PATTERNS = */tests/* \
*/benchmarks/* \ */benchmarks/* \
*/docs/phpdoc/* \ */docs/* \
*/docs/doxygen/* \ */test-settings.php \
*/test-settings.php */configdoc/* \
*/test-settings.php \
*/maintenance/* \
*/smoketests/*
EXAMPLE_PATH = EXAMPLE_PATH =
EXAMPLE_PATTERNS = * EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO EXAMPLE_RECURSIVE = NO

184
INSTALL
View File

@ -2,145 +2,183 @@
Install Install
How to install HTML Purifier How to install HTML Purifier
Being a library, there's no fancy GUI that will take you step-by-step through HTML Purifier is designed to run out of the box, so actually using the library
configuring database credentials and other mumbo-jumbo. HTML Purifier is is extremely easy. (Although, if you were looking for a step-by-step
designed to run "out of the box." Regardless, there are still a couple of installation GUI, you've come to the wrong place!) The impatient can scroll
things you should be mindful of. down to the bottom of this INSTALL document to see the code, but you really
should make sure a few things are properly done.
0. Compatibility 1. Compatibility
HTML Purifier works in both PHP 4 and PHP 5. I have run the test suite on HTML Purifier works in both PHP 4 and PHP 5, from PHP 4.3.9 and up. It has no
these versions: core dependencies with other libraries. (Whoopee!)
- 4.3.9, 4.3.11 Optional extensions are iconv (usually installed) and tidy (also common).
- 4.4.0, 4.4.4 If you use UTF-8 and don't plan on pretty-printing HTML, you can get away with
- 5.0.0, 5.0.4 not having either of these extensions.
- 5.1.0, 5.1.6
And can confidently say that HTML Purifier should work in all versions
between and afterwards. HTML Purifier definitely does not support PHP 4.2,
and PHP 4.3 branch support may go further back than that, but I haven't tested
any earlier versions.
I have been unable to get PHP 5.0.5 working on my computer, so if someone
wants to test that, be my guest. All tests were done on Windows XP Home,
but operating system should not be a major factor in the library.
1. Including the proper files 2. Including the library
The library/ directory must be added to your path: HTML Purifier will not be Simply use:
able to find the necessary includes otherwise. This is as simple as:
set_include_path('/path/to/htmlpurifier/library' . PATH_SEPARATOR . require_once '/path/to/library/HTMLPurifier.auto.php';
get_include_path() );
...replacing /path/to/htmlpurifier with the actual location of the folder. Don't ...and you're good to go. Since HTML Purifier's codebase is fairly
worry, HTML Purifier is namespaced so unless you have another file named large, I recommend only including HTML Purifier when you need it.
HTMLPurifier.php, the files won't collide with any of your includes.
Then, it's a simple matter of including the base file: If you don't like your include_path to be fiddled around with, simply set
HTML Purifier's library/ directory to the include path yourself and then:
require_once 'HTMLPurifier.php'; require_once 'HTMLPurifier.php';
...and you're good to go. The library/ folder contains all the files you need, Only the contents in the library/ folder are necessary, so you can remove
so you can get rid of most of everything else when using the library in a everything else when using HTML Purifier in a production environment.
production environment.
2. Preparing the proper environment 3. Preparing the proper output environment
While no configuration is necessary, you first should take precautions regarding HTML Purifier is all about web-standards, so accordingly your webpages should
the other output HTML that the filtered content will be going along with. Here be standards compliant. HTML Purifier can deal with these doctypes:
is a (short) checklist:
* Have I specified XHTML 1.0 Transitional as the doctype? * XHTML 1.0 Transitional (default)
* Have I specified UTF-8 as the character encoding? * HTML 4.01 Transitional
...and these character encodings:
* UTF-8 (default)
* Any encoding iconv supports (support is crippled for i18n though)
The defaults are there for a reason: they are best-practice choices that
should not be changed lightly. For those of you in the dark, you can determine
the doctype from this code in your HTML documents:
To find out what these are, browse to your website and view its source code.
You can figure out the doctype from the a declaration that looks like
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
or no doctype. You can figure out the character encoding by looking for
...and the character encoding from this code:
<meta http-equiv="Content-type" content="text/html;charset=ENCODING"> <meta http-equiv="Content-type" content="text/html;charset=ENCODING">
I cannot stress the importance of these two bullets enough. Omitting either For legacy codebases these declarations may be missing. If that is the case,
of them could have dire consequences not only for security but for plain STOP, and read up on character encodings and doctypes (in that order). Here
old usability. You can find a more in-depth discussion of why this is needed are some links:
in docs/security.txt, in the meantime, try to change your output so this is
the case. If you can't, well, we might be able to accomodate you (read * http://www.joelonsoftware.com/articles/Unicode.html
section 3). * http://alistapart.com/stories/doctype/
You may currently be vulnerable to XSS and other security threats, and HTML
Purifier won't be able to fix that.
3. Configuring HTML Purifier 4. Configuration
HTML Purifier is designed to run out-of-the-box, but occasionally HTML HTML Purifier is designed to run out-of-the-box, but occasionally HTML
Purifier needs to be told what to do. Purifier needs to be told what to do. If you answered no to any of these
questions, read on, otherwise, you can skip to the next section (or, if you're
into configuring things just for the heck of it, skip to 4.3).
If, for some reason, you are unable to switch to UTF-8 immediately, you can * Am I using UTF-8?
switch HTML Purifier's encoding. Note that the availability of encodings is * Am I using XHTML 1.0 Transitional?
dependent on iconv, and you'll be missing characters if the charset you
choose doesn't have them. If you answered yes to any of these questions, instantiate a configuration
object and read on:
$config = HTMLPurifier_Config::createDefault();
4.1. Setting a different character encoding
You really shouldn't use any other encoding except UTF-8, especially if you
plan to support multilingual websites (read section three for more details).
However, switching to UTF-8 is not always immediately feasible, so we can
adapt.
HTML Purifier uses iconv to support other character encodings, as such,
any encoding that iconv supports <http://www.gnu.org/software/libiconv/>
HTML Purifier supports with this code:
$config->set('Core', 'Encoding', /* put your encoding here */); $config->set('Core', 'Encoding', /* put your encoding here */);
An example usage for Latin-1 websites: An example usage for Latin-1 websites (the most common encoding for English
websites):
$config->set('Core', 'Encoding', 'ISO-8859-1'); $config->set('Core', 'Encoding', 'ISO-8859-1');
Note that HTML Purifier's support for non-Unicode encodings is crippled by the
fact that any character not supported by that encoding will be silently
dropped, EVEN if it is ampersand escaped. This is a current limitation of
HTML Purifier that we are NOT actively working to fix. Patches are welcome,
but there are so many other gotchas and problems in I18N for non-Unicode
encodings that this functionality is low priority. See
<http://ppewww.ph.gla.ac.uk/~flavell/charset/form-i18n.html> for a more
detailed lowdown on the topic.
4.2. Setting a different doctype
For those of you stuck using HTML 4.01 Transitional, you can disable For those of you stuck using HTML 4.01 Transitional, you can disable
XHTML output like this: XHTML output like this:
$config->set('Core', 'XHTML', false); $config->set('Core', 'XHTML', false);
However, I strongly recommend that you use XHTML. Currently, we can only I recommend that you use XHTML, although not as much as I recommend UTF-8. If
guarantee transitional-complaint output, future versions will also allow strict your HTML 4.01 page validates, good for you!
output. There are more configuration directives which can be read about
here: http://hp.jpsband.org/live/configdoc/plain.html Currently, we can only guarantee transitional-complaint output, future
versions will also allow strict-compliant output.
3. Using the code 4.3. Other settings
There are more configuration directives which can be read about
here: <http://hp.jpsband.org/live/configdoc/plain.html> They're a bit boring,
but they can help out for those of you who like to exert maximum control over
your code.
5. Using the code
The interface is mind-numbingly simple: The interface is mind-numbingly simple:
$purifier = new HTMLPurifier(); $purifier = new HTMLPurifier();
$clean_html = $purifier->purify($dirty_html); $clean_html = $purifier->purify( $dirty_html );
Or, if you're using the configuration object: ...or, if you're using the configuration object:
$purifier = new HTMLPurifier($config); $purifier = new HTMLPurifier($config);
$clean_html = $purifier->purify($dirty_html); $clean_html = $purifier->purify( $dirty_html );
That's it. For more examples, check out docs/examples/. Also, SLOW gives That's it! For more examples, check out docs/examples/ (they aren't very
advice on what to do if HTML Purifier is slowing down your application. different though). Also, SLOW gives advice on what to do if HTML Purifier
is slowing down your application.
4. Quick install 6. Quick install
If your website is in UTF-8 and XHTML Transitional, use this code: If your website is in UTF-8 and XHTML Transitional, use this code:
<?php <?php
set_include_path('/path/to/htmlpurifier/library' require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
. PATH_SEPARATOR . get_include_path() );
require_once 'HTMLPurifier.php';
$purifier = new HTMLPurifier();
$purifier = new HTMLPurifier();
$clean_html = $purifier->purify($dirty_html); $clean_html = $purifier->purify($dirty_html);
?> ?>
If your website is in a different encoding or doctype, use this code: If your website is in a different encoding or doctype, use this code:
<?php <?php
set_include_path('/path/to/htmlpurifier/library' require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
. PATH_SEPARATOR . get_include_path() );
require_once 'HTMLPurifier.php';
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();
$config->set('Core', 'Encoding', 'ISO-8859-1'); //replace with your encoding $config->set('Core', 'Encoding', 'ISO-8859-1'); //replace with your encoding

57
NEWS
View File

@ -1,24 +1,37 @@
NEWS ( CHANGELOG and HISTORY ) HTMLPurifier NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1.1.1, released 2006-09-24 = KEY ====================
- Various documentation updates ! Feature
- Fixed parse error in configuration documentation script - Bugfix
- Fixed fatal error in benchmark scripts, slightly augmented + Sub-comment
- As far as possible, whitespace is preserved in-between table children . Internal change
- Configuration option to optionally Tidy up output for indentation to make up ==========================
for dropped whitespace by DOMLex (pretty-printing for the entire application
should be done by a page-wide Tidy) 1.1.2, released 2006-09-30
- Sample test-settings.php file included ! Add HTMLPurifier.auto.php stub file that automatically configures pathx
- Documentation updated
+ INSTALL document rewritten
+ TODO added semi-lossy conversion
+ API Doxygen docs' file exclusions updated
+ Added notes on HTML versus XML attribute whitespace handling
+ Noted that HTMLPurifier_ChildDef_Custom isn't being used
+ Noted that config object's definitions are cached versions
- Fixed lack of attribute parsing in HTMLPurifier_Lexer_PEARSax3
- ftp:// URIs now have their typecodes checked
- Hooked up HTMLPurifier_ChildDef_Custom's unit tests (they weren't being run)
. Line endings standardized throughout project (svn:eol-style standardized)
. Refactored parseData() to general Lexer class
. Tester named "HTML Purifier" not "HTMLPurifier"
1.1.0, released 2006-09-16 1.1.0, released 2006-09-16
! Directive documentation generation using XSLT
! XHTML can now be turned off, output becomes <br>
- Made URI validator more forgiving: will ignore leading and trailing - Made URI validator more forgiving: will ignore leading and trailing
quotes, apostrophes and less than or greater than signs. quotes, apostrophes and less than or greater than signs.
- Enforce alphanumeric namespace and directive names for configuration. - Enforce alphanumeric namespace and directive names for configuration.
- Directive documentation generation using XSLT
- Table child definition made more flexible, will fix up poorly ordered elements - Table child definition made more flexible, will fix up poorly ordered elements
- XHTML generation can now be turned off, allowing things like <br> . Renamed ConfigDef to ConfigSchema
- Renamed ConfigDef to ConfigSchema
1.0.1, released 2006-09-04 1.0.1, released 2006-09-04
- Fixed slight bug in DOMLex attribute parsing - Fixed slight bug in DOMLex attribute parsing
@ -28,17 +41,17 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
space in them. This manifested in TinyMCE. space in them. This manifested in TinyMCE.
1.0.0, released 2006-09-01 1.0.0, released 2006-09-01
! Shorthand CSS properties implemented: font, border, background, list-style
! Basic color keywords translated into hexadecimal values
! Table CSS properties implemented
! Support for charsets other than UTF-8 (defined by iconv)
! Malformed UTF-8 and non-SGML character detection and cleaning implemented
- Fixed broken numeric entity conversion - Fixed broken numeric entity conversion
- Malformed UTF-8 and non-SGML character detection and cleaning implemented
- API documentation completed - API documentation completed
- Shorthand CSS properties implemented: font, border, background, list-style . (HTML|CSS)Definition de-singleton-ized
- Basic color keywords translated into hexadecimal values
- Table CSS properties implemented
- (HTML|CSS)Definition de-singleton-ized
- Support for charsets other than UTF-8 (defined by iconv)
1.0.0beta, released 2006-08-16 1.0.0beta, released 2006-08-16
- First public release, most functionality implemented. Notable omissions are: ! First public release, most functionality implemented. Notable omissions are:
. Shorthand CSS properties + Shorthand CSS properties
. Table CSS properties + Table CSS properties
. Deprecated attribute transformations + Deprecated attribute transformations

24
README
View File

@ -1,13 +1,13 @@
README
All about HTMLPurifier
HTMLPurifier is an HTML filtering solution. It uses a unique combination of README
robust whitelists and agressive parsing to ensure that not only are XSS All about HTMLPurifier
attacks thwarted, but the resulting HTML is standards compliant.
HTMLPurifier is an HTML filtering solution. It uses a unique combination of
See INSTALL on how to use the library. See docs/ for more developer-oriented robust whitelists and agressive parsing to ensure that not only are XSS
documentation as well as some code examples. Users of TinyMCE or FCKeditor attacks thwarted, but the resulting HTML is standards compliant.
may be especially interested in WYSIWYG.
See INSTALL on how to use the library. See docs/ for more developer-oriented
HTMLPurifier can be found on the web at: http://hp.jpsband.org/ documentation as well as some code examples. Users of TinyMCE or FCKeditor
may be especially interested in WYSIWYG.
HTMLPurifier can be found on the web at: http://hp.jpsband.org/

2
TODO
View File

@ -45,6 +45,8 @@ Unknown release (on a scratch-an-itch basis)
empty-cells:show is applied to have compatibility with Internet Explorer empty-cells:show is applied to have compatibility with Internet Explorer
- Non-lossy dumb alternate character encoding transformations, achieved by - Non-lossy dumb alternate character encoding transformations, achieved by
numerically encoding all non-ASCII characters numerically encoding all non-ASCII characters
- Semi-lossy dumb alternate character encoding transformations, achieved by
encoding all characters that have string entity equivalents
Wontfix Wontfix
- Non-lossy smart alternate character encoding transformations - Non-lossy smart alternate character encoding transformations

View File

@ -1,7 +1,7 @@
table {border-collapse:collapse;} table {border-collapse:collapse;}
table td, table th {padding:0.2em;} table td, table th {padding:0.2em;}
table.constraints {margin:0 0 1em;} table.constraints {margin:0 0 1em;}
table.constraints th {text-align:left;padding-left:0.4em;} table.constraints th {text-align:left;padding-left:0.4em;}
table.constraints td {padding-right:0.4em;} table.constraints td {padding-right:0.4em;}
table.constraints td pre {margin:0;} table.constraints td pre {margin:0;}

View File

@ -1,105 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet <xsl:stylesheet
version = "1.0" version = "1.0"
xmlns = "http://www.w3.org/1999/xhtml" xmlns = "http://www.w3.org/1999/xhtml"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
> >
<xsl:output <xsl:output
method = "xml" method = "xml"
encoding = "UTF-8" encoding = "UTF-8"
doctype-public = "-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-public = "-//W3C//DTD XHTML 1.0 Transitional//EN"
doctype-system = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-system = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
indent = "no" indent = "no"
media-type = "text/html" media-type = "text/html"
/> />
<xsl:variable name="typeLookup" select="document('../types.xml')" /> <xsl:variable name="typeLookup" select="document('../types.xml')" />
<xsl:template match="/"> <xsl:template match="/">
<html lang="en" xml:lang="en"> <html lang="en" xml:lang="en">
<head> <head>
<title><xsl:value-of select="/configdoc/title" /> Configuration Documentation</title> <title><xsl:value-of select="/configdoc/title" /> Configuration Documentation</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="styles/plain.css" /> <link rel="stylesheet" type="text/css" href="styles/plain.css" />
</head> </head>
<body> <body>
<xsl:apply-templates /> <xsl:apply-templates />
</body> </body>
</html> </html>
</xsl:template> </xsl:template>
<xsl:template match="title"> <xsl:template match="title">
<h1><xsl:value-of select="/configdoc/title" /> Configuration Documentation</h1> <h1><xsl:value-of select="/configdoc/title" /> Configuration Documentation</h1>
</xsl:template> </xsl:template>
<xsl:template match="namespace"> <xsl:template match="namespace">
<xsl:apply-templates /> <xsl:apply-templates />
<xsl:if test="count(child::directive)=0"> <xsl:if test="count(child::directive)=0">
<p>No configuration directives defined for this namespace.</p> <p>No configuration directives defined for this namespace.</p>
</xsl:if> </xsl:if>
</xsl:template> </xsl:template>
<xsl:template match="namespace/name"> <xsl:template match="namespace/name">
<h2 id="{../@id}"><xsl:value-of select="text()" /></h2> <h2 id="{../@id}"><xsl:value-of select="text()" /></h2>
</xsl:template> </xsl:template>
<xsl:template match="namespace/description"> <xsl:template match="namespace/description">
<div class="description"> <div class="description">
<xsl:copy-of select="div/node()" /> <xsl:copy-of select="div/node()" />
</div> </div>
</xsl:template> </xsl:template>
<xsl:template match="directive"> <xsl:template match="directive">
<xsl:apply-templates /> <xsl:apply-templates />
</xsl:template> </xsl:template>
<xsl:template match="directive/name"> <xsl:template match="directive/name">
<h3 id="{../@id}"><xsl:value-of select="text()" /></h3> <h3 id="{../@id}"><xsl:value-of select="text()" /></h3>
</xsl:template> </xsl:template>
<xsl:template match="directive/constraints"> <xsl:template match="directive/constraints">
<table class="constraints"> <table class="constraints">
<xsl:apply-templates /> <xsl:apply-templates />
<!-- Calculated other values --> <!-- Calculated other values -->
<tr> <tr>
<th>Used by:</th> <th>Used by:</th>
<td> <td>
<xsl:for-each select="../descriptions/description"> <xsl:for-each select="../descriptions/description">
<xsl:if test="position()&gt;1">, </xsl:if> <xsl:if test="position()&gt;1">, </xsl:if>
<xsl:value-of select="@file" /> <xsl:value-of select="@file" />
</xsl:for-each> </xsl:for-each>
</td> </td>
</tr> </tr>
</table> </table>
</xsl:template> </xsl:template>
<xsl:template match="directive//description"> <xsl:template match="directive//description">
<div class="description"> <div class="description">
<xsl:copy-of select="div/node()" /> <xsl:copy-of select="div/node()" />
</div> </div>
</xsl:template> </xsl:template>
<xsl:template match="constraints/type"> <xsl:template match="constraints/type">
<tr> <tr>
<th>Type:</th> <th>Type:</th>
<td> <td>
<xsl:variable name="type" select="text()" /> <xsl:variable name="type" select="text()" />
<xsl:attribute name="class">type type-<xsl:value-of select="$type" /></xsl:attribute> <xsl:attribute name="class">type type-<xsl:value-of select="$type" /></xsl:attribute>
<xsl:value-of select="$typeLookup/types/type[@id=$type]/text()" /> <xsl:value-of select="$typeLookup/types/type[@id=$type]/text()" />
</td> </td>
</tr> </tr>
</xsl:template> </xsl:template>
<xsl:template match="constraints/allowed"> <xsl:template match="constraints/allowed">
<tr> <tr>
<th>Allowed values:</th> <th>Allowed values:</th>
<td> <td>
<xsl:for-each select="value"><!-- <xsl:for-each select="value"><!--
--><xsl:if test="position()&gt;1">, </xsl:if> --><xsl:if test="position()&gt;1">, </xsl:if>
&quot;<xsl:value-of select="." />&quot;<!-- &quot;<xsl:value-of select="." />&quot;<!--
--></xsl:for-each> --></xsl:for-each>
</td> </td>
</tr> </tr>
</xsl:template> </xsl:template>
<xsl:template match="constraints/default"> <xsl:template match="constraints/default">
<tr> <tr>
<th>Default:</th> <th>Default:</th>
<td><pre><xsl:value-of select="." xml:space="preserve" /></pre></td> <td><pre><xsl:value-of select="." xml:space="preserve" /></pre></td>
</tr> </tr>
</xsl:template> </xsl:template>
</xsl:stylesheet> </xsl:stylesheet>

View File

@ -0,0 +1,10 @@
<?php
/**
* This is a stub include that automatically configures the include path.
*/
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() );
require_once 'HTMLPurifier.php';
?>

View File

@ -3,7 +3,7 @@
/*! /*!
* @mainpage * @mainpage
* *
* HTMLPurifier is an HTML filter that will take an arbitrary snippet of * HTML Purifier is an HTML filter that will take an arbitrary snippet of
* HTML and rigorously test, validate and filter it into a version that * HTML and rigorously test, validate and filter it into a version that
* is safe for output onto webpages. It achieves this by: * is safe for output onto webpages. It achieves this by:
* *
@ -22,7 +22,7 @@
*/ */
/* /*
HTMLPurifier - Standards Compliant HTML Filtering HTML Purifier - Standards Compliant HTML Filtering
Copyright (C) 2006 Edward Z. Yang Copyright (C) 2006 Edward Z. Yang
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or

View File

@ -48,7 +48,16 @@ class HTMLPurifier_AttrDef
* *
* @note This method is not entirely standards compliant, as trim() removes * @note This method is not entirely standards compliant, as trim() removes
* more types of whitespace than specified in the spec. In practice, * more types of whitespace than specified in the spec. In practice,
* this is rarely a problem. * this is rarely a problem, as those extra characters usually have
* already been removed by HTMLPurifier_Encoder.
*
* @warning This processing is inconsistent with XML's whitespace handling
* as specified by section 3.3.3 and referenced XHTML 1.0 section
* 4.7. Compliant processing requires all line breaks normalized
* to "\n", so the fix is not as simple as fixing it in this
* function. Trim and whitespace collapsing are supposed to only
* occur in NMTOKENs. However, note that we are NOT necessarily
* parsing XML, thus, this behavior may still be correct.
* *
* @public * @public
*/ */

View File

@ -56,6 +56,8 @@ class HTMLPurifier_ChildDef
* *
* @warning Currently this class is an all or nothing proposition, that is, * @warning Currently this class is an all or nothing proposition, that is,
* it will only give a bool return value. * it will only give a bool return value.
* @note This class is currently not used by any code, although it is unit
* tested.
*/ */
class HTMLPurifier_ChildDef_Custom extends HTMLPurifier_ChildDef class HTMLPurifier_ChildDef_Custom extends HTMLPurifier_ChildDef
{ {

View File

@ -26,12 +26,12 @@ class HTMLPurifier_Config
var $def; var $def;
/** /**
* Instance of HTMLPurifier_HTMLDefinition * Cached instance of HTMLPurifier_HTMLDefinition
*/ */
var $html_definition; var $html_definition;
/** /**
* Instance of HTMLPurifier_CSSDefinition * Cached instance of HTMLPurifier_CSSDefinition
*/ */
var $css_definition; var $css_definition;

View File

@ -60,6 +60,60 @@ class HTMLPurifier_Lexer
$this->_entity_parser = new HTMLPurifier_EntityParser(); $this->_entity_parser = new HTMLPurifier_EntityParser();
} }
/**
* Most common entity to raw value conversion table for special entities.
* @protected
*/
var $_special_entity2str =
array(
'&quot;' => '"',
'&amp;' => '&',
'&lt;' => '<',
'&gt;' => '>',
'&#39;' => "'",
'&#039;' => "'",
'&#x27;' => "'"
);
/**
* Parses special entities into the proper characters.
*
* This string will translate escaped versions of the special characters
* into the correct ones.
*
* @warning
* You should be able to treat the output of this function as
* completely parsed, but that's only because all other entities should
* have been handled previously in substituteNonSpecialEntities()
*
* @param $string String character data to be parsed.
* @returns Parsed character data.
*/
function parseData($string) {
// following functions require at least one character
if ($string === '') return '';
// subtracts amps that cannot possibly be escaped
$num_amp = substr_count($string, '&') - substr_count($string, '& ') -
($string[strlen($string)-1] === '&' ? 1 : 0);
if (!$num_amp) return $string; // abort if no entities
$num_esc_amp = substr_count($string, '&amp;');
$string = strtr($string, $this->_special_entity2str);
// code duplication for sake of optimization, see above
$num_amp_2 = substr_count($string, '&') - substr_count($string, '& ') -
($string[strlen($string)-1] === '&' ? 1 : 0);
if ($num_amp_2 <= $num_esc_amp) return $string;
// hmm... now we have some uncommon entities. Use the callback.
$string = $this->_entity_parser->substituteSpecialEntities($string);
return $string;
}
var $_encoder; var $_encoder;
/** /**

View File

@ -12,64 +12,12 @@ require_once 'HTMLPurifier/Lexer.php';
* completely eventually. * completely eventually.
* *
* @todo Reread XML spec and document differences. * @todo Reread XML spec and document differences.
* @todo Add support for CDATA sections. *
* @todo Determine correct behavior in outputting comment data. (preserve dashes?) * @todo Determine correct behavior in transforming comment data. (preserve dashes?)
* @todo Optimize main function tokenizeHTML().
* @todo Less than sign (<) being prohibited (even as entity) in attr-values?
*/ */
class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
{ {
/**
* Most common entity to raw value conversion table for special entities.
* @protected
*/
var $_special_entity2str =
array(
'&quot;' => '"',
'&amp;' => '&',
'&lt;' => '<',
'&gt;' => '>',
'&#39;' => "'",
'&#039;' => "'",
'&#x27;' => "'"
);
/**
* Parses special entities into the proper characters.
*
* This string will translate escaped versions of the special characters
* into the correct ones.
*
* @warning
* You should be able to treat the output of this function as
* completely parsed, but that's only because all other entities should
* have been handled previously in substituteNonSpecialEntities()
*
* @param $string String character data to be parsed.
* @returns Parsed character data.
*/
function parseData($string) {
// subtracts amps that cannot possibly be escaped
$num_amp = substr_count($string, '&') - substr_count($string, '& ') -
($string[strlen($string)-1] === '&' ? 1 : 0);
if (!$num_amp) return $string; // abort if no entities
$num_esc_amp = substr_count($string, '&amp;');
$string = strtr($string, $this->_special_entity2str);
// code duplication for sake of optimization, see above
$num_amp_2 = substr_count($string, '&') - substr_count($string, '& ') -
($string[strlen($string)-1] === '&' ? 1 : 0);
if ($num_amp_2 <= $num_esc_amp) return $string;
// hmm... now we have some uncommon entities. Use the callback.
$string = $this->_entity_parser->substituteSpecialEntities($string);
return $string;
}
/** /**
* Whitespace characters for str(c)spn. * Whitespace characters for str(c)spn.
* @protected * @protected

View File

@ -18,6 +18,8 @@ require_once 'HTMLPurifier/Lexer.php';
* whatever it does for poorly formed HTML is up to it. * whatever it does for poorly formed HTML is up to it.
* *
* @todo Generalize so that XML_HTMLSax is also supported. * @todo Generalize so that XML_HTMLSax is also supported.
*
* @warning Entity-resolution inside attributes is broken.
*/ */
class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
@ -41,6 +43,8 @@ class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
$parser->set_element_handler('openHandler','closeHandler'); $parser->set_element_handler('openHandler','closeHandler');
$parser->set_data_handler('dataHandler'); $parser->set_data_handler('dataHandler');
$parser->set_escape_handler('escapeHandler'); $parser->set_escape_handler('escapeHandler');
// doesn't seem to work correctly for attributes
$parser->set_option('XML_OPTION_ENTITIES_PARSED', 1); $parser->set_option('XML_OPTION_ENTITIES_PARSED', 1);
$parser->parse($string); $parser->parse($string);
@ -53,6 +57,10 @@ class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
* Open tag event handler, interface is defined by PEAR package. * Open tag event handler, interface is defined by PEAR package.
*/ */
function openHandler(&$parser, $name, $attrs, $closed) { function openHandler(&$parser, $name, $attrs, $closed) {
// entities are not resolved in attrs
foreach ($attrs as $key => $attr) {
$attrs[$key] = $this->parseData($attr);
}
if ($closed) { if ($closed) {
$this->tokens[] = new HTMLPurifier_Token_Empty($name, $attrs); $this->tokens[] = new HTMLPurifier_Token_Empty($name, $attrs);
} else { } else {

View File

@ -4,7 +4,6 @@ require_once 'HTMLPurifier/URIScheme.php';
/** /**
* Validates ftp (File Transfer Protocol) URIs as defined by generic RFC 1738. * Validates ftp (File Transfer Protocol) URIs as defined by generic RFC 1738.
* @todo Typecode check on path
*/ */
class HTMLPurifier_URIScheme_ftp extends HTMLPurifier_URIScheme { class HTMLPurifier_URIScheme_ftp extends HTMLPurifier_URIScheme {
@ -16,7 +15,27 @@ class HTMLPurifier_URIScheme_ftp extends HTMLPurifier_URIScheme {
list($userinfo, $host, $port, $path, $query) = list($userinfo, $host, $port, $path, $query) =
parent::validateComponents( parent::validateComponents(
$userinfo, $host, $port, $path, $query, $config ); $userinfo, $host, $port, $path, $query, $config );
// typecode check needed on path $semicolon_pos = strrpos($path, ';'); // reverse
if ($semicolon_pos !== false) {
// typecode check
$type = substr($path, $semicolon_pos + 1); // no semicolon
$path = substr($path, 0, $semicolon_pos);
$type_ret = '';
if (strpos($type, '=') !== false) {
// figure out whether or not the declaration is correct
list($key, $typecode) = explode('=', $type, 2);
if ($key !== 'type') {
// invalid key, tack it back on encoded
$path .= '%3B' . $type;
} elseif ($typecode === 'a' || $typecode === 'i' || $typecode === 'd') {
$type_ret = ";type=$typecode";
}
} else {
$path .= '%3B' . $type;
}
$path = str_replace(';', '%3B', $path);
$path .= $type_ret;
}
return array($userinfo, $host, $port, $path, null); return array($userinfo, $host, $port, $path, null);
} }

View File

@ -1 +1 @@
Deny from all Deny from all

View File

@ -1,100 +1,100 @@
;; phpDocumentor parse configuration file ;; phpDocumentor parse configuration file
;; ;;
;; This file is designed to cut down on repetitive typing on the command-line or web interface ;; This file is designed to cut down on repetitive typing on the command-line or web interface
;; You can copy this file to create a number of configuration files that can be used with the ;; You can copy this file to create a number of configuration files that can be used with the
;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web ;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web
;; interface will automatically generate a list of .ini files that can be used. ;; interface will automatically generate a list of .ini files that can be used.
;; ;;
;; default.ini is used to generate the online manual at http://www.phpdoc.org/docs ;; default.ini is used to generate the online manual at http://www.phpdoc.org/docs
;; ;;
;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini ;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini
;; ;;
;; Copyright 2002, Greg Beaver <cellog@users.sourceforge.net> ;; Copyright 2002, Greg Beaver <cellog@users.sourceforge.net>
;; ;;
;; WARNING: do not change the name of any command-line parameters, phpDocumentor will ignore them ;; WARNING: do not change the name of any command-line parameters, phpDocumentor will ignore them
[Parse Data] [Parse Data]
;; title of all the documentation ;; title of all the documentation
;; legal values: any string ;; legal values: any string
title = HTML Purifier API Documentation title = HTML Purifier API Documentation
;; parse files that start with a . like .bash_profile ;; parse files that start with a . like .bash_profile
;; legal values: true, false ;; legal values: true, false
hidden = false hidden = false
;; show elements marked @access private in documentation by setting this to on ;; show elements marked @access private in documentation by setting this to on
;; legal values: on, off ;; legal values: on, off
parseprivate = off parseprivate = off
;; parse with javadoc-like description (first sentence is always the short description) ;; parse with javadoc-like description (first sentence is always the short description)
;; legal values: on, off ;; legal values: on, off
javadocdesc = on javadocdesc = on
;; add any custom @tags separated by commas here ;; add any custom @tags separated by commas here
;; legal values: any legal tagname separated by commas. ;; legal values: any legal tagname separated by commas.
;customtags = mytag1,mytag2 ;customtags = mytag1,mytag2
;; This is only used by the XML:DocBook/peardoc2 converter ;; This is only used by the XML:DocBook/peardoc2 converter
defaultcategoryname = Documentation defaultcategoryname = Documentation
;; what is the main package? ;; what is the main package?
;; legal values: alphanumeric string plus - and _ ;; legal values: alphanumeric string plus - and _
defaultpackagename = HTMLPurifier defaultpackagename = HTMLPurifier
;; output any parsing information? set to on for cron jobs ;; output any parsing information? set to on for cron jobs
;; legal values: on ;; legal values: on
;quiet = on ;quiet = on
;; parse a PEAR-style repository. Do not turn this on if your project does ;; parse a PEAR-style repository. Do not turn this on if your project does
;; not have a parent directory named "pear" ;; not have a parent directory named "pear"
;; legal values: on/off ;; legal values: on/off
;pear = on ;pear = on
;; where should the documentation be written? ;; where should the documentation be written?
;; legal values: a legal path ;; legal values: a legal path
target = docs/phpdoc target = docs/phpdoc
;; Which files should be parsed out as special documentation files, such as README, ;; Which files should be parsed out as special documentation files, such as README,
;; INSTALL and CHANGELOG? This overrides the default files found in ;; INSTALL and CHANGELOG? This overrides the default files found in
;; phpDocumentor.ini (this file is not a user .ini file, but the global file) ;; phpDocumentor.ini (this file is not a user .ini file, but the global file)
readmeinstallchangelog = README, INSTALL, NEWS, WYSIWYG, SLOW, LICENSE, CREDITS readmeinstallchangelog = README, INSTALL, NEWS, WYSIWYG, SLOW, LICENSE, CREDITS
;; limit output to the specified packages, even if others are parsed ;; limit output to the specified packages, even if others are parsed
;; legal values: package names separated by commas ;; legal values: package names separated by commas
;packageoutput = package1,package2 ;packageoutput = package1,package2
;; comma-separated list of files to parse ;; comma-separated list of files to parse
;; legal values: paths separated by commas ;; legal values: paths separated by commas
;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory ;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory
;; comma-separated list of directories to parse ;; comma-separated list of directories to parse
;; legal values: directory paths separated by commas ;; legal values: directory paths separated by commas
;directory = /path1,/path2,.,..,subdirectory ;directory = /path1,/path2,.,..,subdirectory
;directory = /home/jeichorn/cvs/pear ;directory = /home/jeichorn/cvs/pear
directory = ./ directory = ./
;; template base directory (the equivalent directory of <installdir>/phpDocumentor) ;; template base directory (the equivalent directory of <installdir>/phpDocumentor)
;templatebase = /path/to/my/templates ;templatebase = /path/to/my/templates
;; directory to find any example files in through @example and {@example} tags ;; directory to find any example files in through @example and {@example} tags
;examplesdir = /path/to/my/templates ;examplesdir = /path/to/my/templates
;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore ;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore
;; legal values: any wildcard strings separated by commas ;; legal values: any wildcard strings separated by commas
;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/ ;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/
ignore = pear-*,templates/,Documentation/,test*.php,Lexer.inc ignore = pear-*,templates/,Documentation/,test*.php,Lexer.inc
sourcecode = on sourcecode = on
;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format ;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format
;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib, ;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib,
;; HTML:frames:earthli, ;; HTML:frames:earthli,
;; HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de, ;; HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de,
;; HTML:frames:DOM/phphtmllib,HTML:frames:DOM/earthli ;; HTML:frames:DOM/phphtmllib,HTML:frames:DOM/earthli
;; HTML:Smarty:default,HTML:Smarty:PHP,HTML:Smarty:HandS ;; HTML:Smarty:default,HTML:Smarty:PHP,HTML:Smarty:HandS
;; PDF:default:default,CHM:default:default,XML:DocBook/peardoc2:default ;; PDF:default:default,CHM:default:default,XML:DocBook/peardoc2:default
output=HTML:frames:default output=HTML:frames:default
;; turn this option on if you want highlighted source code for every file ;; turn this option on if you want highlighted source code for every file
;; legal values: on/off ;; legal values: on/off
sourcecode = on sourcecode = on

View File

@ -46,18 +46,23 @@ class HTMLPurifier_ChildDefTest extends UnitTestCase
$this->def = new HTMLPurifier_ChildDef_Custom( $this->def = new HTMLPurifier_ChildDef_Custom(
'(a, b?, c*, d+, (a, b)*)'); '(a, b?, c*, d+, (a, b)*)');
$inputs = array();
$expect = array();
$config = array();
$inputs[0] = ''; $inputs[0] = '';
$expect[0] = false; $expect[0] = false;
$inputs[1] = '<a /><b /><c /><d /><a /><b />'; $inputs[1] = '<a /><b /><c /><d /><a /><b />';
$expect[1] = true; $expect[1] = true;
$inputs[2] = '<a /><d>Dob</d><a /><b>foo</b><a href="moo"><b>foo</b>'; $inputs[2] = '<a /><d>Dob</d><a /><b>foo</b><a href="moo" /><b>foo</b>';
$expect[2] = true; $expect[2] = true;
$inputs[3] = '<a /><a />'; $inputs[3] = '<a /><a />';
$expect[3] = false; $expect[3] = false;
$this->assertSeries($inputs, $expect, $config);
} }
function test_table() { function test_table() {

View File

@ -8,6 +8,7 @@ class HTMLPurifier_ConfigTest extends UnitTestCase
var $our_copy, $old_copy; var $our_copy, $old_copy;
function setUp() { function setUp() {
// set up a dummy schema object for testing
$our_copy = new HTMLPurifier_ConfigSchema(); $our_copy = new HTMLPurifier_ConfigSchema();
$this->old_copy = HTMLPurifier_ConfigSchema::instance(); $this->old_copy = HTMLPurifier_ConfigSchema::instance();
$this->our_copy =& HTMLPurifier_ConfigSchema::instance($our_copy); $this->our_copy =& HTMLPurifier_ConfigSchema::instance($our_copy);
@ -93,6 +94,17 @@ class HTMLPurifier_ConfigTest extends UnitTestCase
} }
function test_getDefinition() {
$config = HTMLPurifier_Config::createDefault();
$def = $config->getHTMLDefinition();
$this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
$def = $config->getCSSDefinition();
$this->assertIsA($def, 'HTMLPurifier_CSSDefinition');
}
} }
?> ?>

View File

@ -11,24 +11,6 @@ class HTMLPurifier_Lexer_DirectLexTest extends UnitTestCase
$this->DirectLex = new HTMLPurifier_Lexer_DirectLex(); $this->DirectLex = new HTMLPurifier_Lexer_DirectLex();
} }
function test_parseData() {
$HP =& $this->DirectLex;
$this->assertIdentical('asdf', $HP->parseData('asdf'));
$this->assertIdentical('&', $HP->parseData('&amp;'));
$this->assertIdentical('"', $HP->parseData('&quot;'));
$this->assertIdentical("'", $HP->parseData('&#039;'));
$this->assertIdentical("'", $HP->parseData('&#39;'));
$this->assertIdentical('&&&', $HP->parseData('&amp;&amp;&amp;'));
$this->assertIdentical('&&', $HP->parseData('&amp;&')); // [INVALID]
$this->assertIdentical('Procter & Gamble',
$HP->parseData('Procter & Gamble')); // [INVALID]
// This is not special, thus not converted. Test of fault tolerance,
// realistically speaking, this should never happen
$this->assertIdentical('&#x2D;', $HP->parseData('&#x2D;'));
}
// internals testing // internals testing
function test_parseAttributeString() { function test_parseAttributeString() {

View File

@ -38,6 +38,25 @@ class HTMLPurifier_LexerTest extends UnitTestCase
$this->assertIdentical($extract, $result); $this->assertIdentical($extract, $result);
} }
function test_parseData() {
$HP =& $this->Lexer;
$this->assertIdentical('asdf', $HP->parseData('asdf'));
$this->assertIdentical('&', $HP->parseData('&amp;'));
$this->assertIdentical('"', $HP->parseData('&quot;'));
$this->assertIdentical("'", $HP->parseData('&#039;'));
$this->assertIdentical("'", $HP->parseData('&#39;'));
$this->assertIdentical('&&&', $HP->parseData('&amp;&amp;&amp;'));
$this->assertIdentical('&&', $HP->parseData('&amp;&')); // [INVALID]
$this->assertIdentical('Procter & Gamble',
$HP->parseData('Procter & Gamble')); // [INVALID]
// This is not special, thus not converted. Test of fault tolerance,
// realistically speaking, this should never happen
$this->assertIdentical('&#x2D;', $HP->parseData('&#x2D;'));
}
function test_extractBody() { function test_extractBody() {
$this->assertExtractBody('<b>Bold</b>'); $this->assertExtractBody('<b>Bold</b>');
$this->assertExtractBody('<html><body><b>Bold</b></body></html>', '<b>Bold</b>'); $this->assertExtractBody('<html><body><b>Bold</b></body></html>', '<b>Bold</b>');
@ -249,13 +268,16 @@ class HTMLPurifier_LexerTest extends UnitTestCase
,new HTMLPurifier_Token_Text('Link') ,new HTMLPurifier_Token_Text('Link')
,new HTMLPurifier_Token_End('a') ,new HTMLPurifier_Token_End('a')
); );
$sax_expect[16] = false; // PEARSax doesn't support it!
// test that UTF-8 is preserved // test that UTF-8 is preserved
$char_hearts = $this->_entity_lookup->table['hearts']; $char_hearts = $this->_entity_lookup->table['hearts'];
$input[17] = $char_hearts; $input[17] = $char_hearts;
$expect[17] = array( new HTMLPurifier_Token_Text($char_hearts) ); $expect[17] = array( new HTMLPurifier_Token_Text($char_hearts) );
// test weird characters in attributes
$input[18] = '<br test="x &lt; 6" />';
$expect[18] = array( new HTMLPurifier_Token_Empty('br', array('test' => 'x < 6')) );
$default_config = HTMLPurifier_Config::createDefault(); $default_config = HTMLPurifier_Config::createDefault();
foreach($input as $i => $discard) { foreach($input as $i => $discard) {
if (!isset($config[$i])) $config[$i] = $default_config; if (!isset($config[$i])) $config[$i] = $default_config;

View File

@ -54,12 +54,34 @@ class HTMLPurifier_URISchemeTest extends UnitTestCase
$scheme = new HTMLPurifier_URIScheme_ftp(); $scheme = new HTMLPurifier_URIScheme_ftp();
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();
$this->assertIdentical( $this->assertIdentical(
$scheme->validateComponents( $scheme->validateComponents(
'user', 'www.example.com', 21, '/', 's=foobar', $config), 'user', 'www.example.com', 21, '/', 's=foobar', $config),
array('user', 'www.example.com', null, '/', null) array('user', 'www.example.com', null, '/', null)
); );
// valid typecode
$this->assertIdentical(
$scheme->validateComponents(
null, 'www.example.com', null, '/file.txt;type=a', null, $config),
array(null, 'www.example.com', null, '/file.txt;type=a', null)
);
// remove invalid typecode
$this->assertIdentical(
$scheme->validateComponents(
null, 'www.example.com', null, '/file.txt;type=z', null, $config),
array(null, 'www.example.com', null, '/file.txt', null)
);
// encode errant semicolons
$this->assertIdentical(
$scheme->validateComponents(
null, 'www.example.com', null, '/too;many;semicolons=1', null, $config),
array(null, 'www.example.com', null, '/too%3Bmany%3Bsemicolons=1', null)
);
} }
function test_news() { function test_news() {

View File

@ -114,14 +114,14 @@ if (isset($_GET['file']) && isset($test_file_lookup[$_GET['file']])) {
// execute only one test // execute only one test
$test_file = $_GET['file']; $test_file = $_GET['file'];
$test = new GroupTest('HTMLPurifier - ' . $test_file); $test = new GroupTest('HTML Purifier - ' . $test_file);
$path = 'HTMLPurifier/' . $test_file; $path = 'HTMLPurifier/' . $test_file;
require_once $path; require_once $path;
$test->addTestClass(htmlpurifier_path2class($path)); $test->addTestClass(htmlpurifier_path2class($path));
} else { } else {
$test = new GroupTest('HTMLPurifier'); $test = new GroupTest('HTML Purifier');
foreach ($test_files as $test_file) { foreach ($test_files as $test_file) {
$path = 'HTMLPurifier/' . $test_file; $path = 'HTMLPurifier/' . $test_file;