0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2025-03-13 10:07:03 +00:00

Release 1.6.1, merged in 931 to HEAD.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/branches/strict@1026 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2007-05-05 20:49:49 +00:00
parent b829e76bbf
commit c35eb3e95f
89 changed files with 1780 additions and 424 deletions

View File

@ -4,7 +4,7 @@
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = HTML Purifier
PROJECT_NUMBER = 1.6.0
PROJECT_NUMBER = 1.6.1
OUTPUT_DIRECTORY = "C:/Documents and Settings/Edward/My Documents/My Webs/htmlpurifier/docs/doxygen"
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English

View File

@ -143,7 +143,7 @@ versions will also allow strict-compliant output.
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,
here: <http://htmlpurifier.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.

37
NEWS
View File

@ -9,6 +9,43 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
. Internal change
==========================
1.7.0, unknown release date
1.6.1, released 2007-05-05
! Support for more deprecated attributes via transformations:
+ hspace and vspace in img
+ size and noshade in hr
+ nowrap in td
+ clear in br
+ align in caption, table, img and hr
+ type in ul, ol and li
! DirectLex now preserves text in which a < bracket is followed by
a non-alphanumeric character. This means that certain emoticons
are now preserved.
! %Core.RemoveInvalidImg is now operational, when set to false invalid
images will hang around with an empty src
! target attribute in a tag supported, use %Attr.AllowedFrameTargets
to enable
! CSS property white-space now allows nowrap (supported in all modern
browsers) but not others (which have spotty browser implementations)
! XHTML 1.1 mode now sort-of works without any fatal errors, and
lang is now moved over to xml:lang.
! Attribute transformation smoketest available at smoketests/attrTransform.php
! Transformation of font's size attribute now handles super-large numbers
- Possibly fatal bug with __autoload() fixed in module manager
- Invert HTMLModuleManager->addModule() processing order to check
prefixes first and then the literal module
- Empty strings get converted to empty arrays instead of arrays with
an empty string in them.
- Merging in attribute lists now works.
. Demo script removed: it has been added to the website's repository
. Basic.php script modified to work out of the box
. Refactor AttrTransform classes to reduce duplication
. AttrTransform_TextAlign axed in favor of a more general
AttrTransform_EnumToCSS, refer to HTMLModule/TransformToStrict.php to
see how the new equivalent is implemented
. Unit tests now use exclusively assertIdentical
1.6.0, released 2007-04-01
! Support for most common deprecated attributes via transformations:
+ bgcolor in td, th, tr and table

2
README
View File

@ -19,4 +19,4 @@ 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://hp.jpsband.org/
HTML Purifier can be found on the web at: http://htmlpurifier.org/

2
TODO
View File

@ -13,6 +13,7 @@ TODO List
# Implement all deprecated tags and attributes
- Parse TinyMCE-style whitelist into our %HTML.Allow* whitelists (possibly
do this earlier)
? HTML interface for tweaking configuration to see changes
1.8 release [Refactor, refactor!]
# URI validation routines tighter (see docs/dev-code-quality.html) (COMPLEX)
@ -82,6 +83,7 @@ Unknown release (on a scratch-an-itch basis)
? Semi-lossy dumb alternate character encoding transfor
? Have 'lang' attribute be checked against official lists, achieved by
encoding all characters that have string entity equivalents
- Explain how to use HTML Purifier in non-PHP languages
Requested
? Native content compression, whitespace stripping (don't rely on Tidy, make

1
VERSION Normal file
View File

@ -0,0 +1 @@
1.6.1

7
WHATSNEW Normal file
View File

@ -0,0 +1,7 @@
The 1.6.1 release, code-named 'Ach! We missed something! Run!', completes
HTML Purifier's roster of attribute transformations. It also implements
a number of minor features (such as better font transformations, smarter
HTML parsing, the CSS property 'white-space' and XHTML 1.1), a few bug
fixes (most notably fixed __autoload compatibility issues) and a ton
of refactoring. 1.6 was for things that absolutely could not wait: this
release, developed in a more leisurely pace, fills in the gaps.

View File

@ -24,8 +24,7 @@ error_reporting(E_ALL);
// ---------------------------------------------------------------------------
// Include HTML Purifier library
set_include_path('../library' . PATH_SEPARATOR . get_include_path());
require_once 'HTMLPurifier.php';
require_once '../library/HTMLPurifier.auto.php';
// ---------------------------------------------------------------------------

View File

@ -14,7 +14,7 @@
<div id="filing">Filed under Development</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>HTML Purifier currently natively supports only a subset of HTML's
allowed elements, attributes, and behavior. This is by design,

View File

@ -1,31 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="description" content="Discusses code quality issues and places that need to be refactored in HTML Purifier." />
<link rel="stylesheet" type="text/css" href="./style.css" />
<title>Code Quality Issues - HTML Purifier</title>
Code Quality Issues
</head><body>
<h1>Code Quality Issues</h1>
<div id="filing">Filed under Development</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<p>Okay, face it. Programmers can get lazy, cut corners, or make mistakes. They
Okay, face it. Programmers can get lazy, cut corners, or make mistakes. They
also can do quick prototypes, and then forget to rewrite them later. Well,
while I can't list mistakes in here, I can list prototype-like segments
of code that should be aggressively refactored. This does not list
optimization issues, that needs to be done after intense profiling.</p>
optimization issues, that needs to be done after intense profiling.
<pre>
docs/examples/demo.php - ad hoc HTML/PHP soup to the extreme
AttrDef
AttrDef - a lot of duplication, more generic classes need to be created;
a lot of strtolower() calls, no legit casing
Class - doesn't support Unicode characters (fringe); uses regular
expressions
Lang - code duplication; premature optimization
@ -45,8 +30,3 @@ 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
</pre>
<div id="version">$Id$</div>
</body></html>

View File

@ -14,7 +14,7 @@
<div id="filing">Filed under Development</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>The classes in this library follow a few naming conventions, which may
help you find the correct functionality more quickly. Here they are:</p>

View File

@ -14,7 +14,7 @@
<div id="filing">Filed under Development</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>Here are some possible optimization techniques we can apply to code sections if
they turn out to be slow. Be sure not to prematurely optimize: if you get

View File

@ -32,7 +32,7 @@ thead th {text-align:left;padding:0.1em;background-color:#EEE;}
<div id="filing">Filed under Development</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<h2>Key</h2>
@ -142,7 +142,7 @@ thead th {text-align:left;padding:0.1em;background-color:#EEE;}
<tbody>
<tr><th colspan="2">Unknown</th></tr>
<tr class="danger css1 impl-yes"><td>background-image</td><td>Dangerous, target milestone 1.3</td></tr>
<tr class="danger css1 impl-yes"><td>background-image</td><td>Dangerous</td></tr>
<tr class="css1 impl-yes"><td>background-attachment</td><td>ENUM(scroll, fixed),
Depends on background-image</td></tr>
<tr class="css1 impl-yes"><td>background-position</td><td>Depends on background-image</td></tr>
@ -168,9 +168,9 @@ thead th {text-align:left;padding:0.1em;background-color:#EEE;}
<tr class="impl-no"><td>quotes</td><td>May be dropped from CSS2, fairly useless for inline context</td></tr>
<tr class="impl-no"><td>visibility</td><td>ENUM(visible, hidden, collapse),
Dangerous</td></tr>
<tr class="css1 feature"><td>white-space</td><td>ENUM(normal, pre, nowrap, pre-wrap,
<tr class="css1 feature impl-partial"><td>white-space</td><td>ENUM(normal, pre, nowrap, pre-wrap,
pre-line), Spotty implementation:
pre (no IE 5/6), nowrap (no IE 5),
pre (no IE 5/6), <em>nowrap</em> (no IE 5, supported),
pre-wrap (only Opera), pre-line (no support). Fixable? Unknown target milestone.</td></tr>
</tbody>
@ -238,7 +238,7 @@ Mozilla on inside and needs -moz-outline, no IE support.</td></tr>
<tr><th colspan="3">Questionable</th></tr>
<tr class="impl-no"><td>accesskey</td><td>A</td><td>May interfere with main interface</td></tr>
<tr class="impl-no"><td>tabindex</td><td>A</td><td>May interfere with main interface</td></tr>
<tr><td>target</td><td>A</td><td>Config enabled, only useful for frame layouts, disallowed in strict</td></tr>
<tr class="impl-yes"><td>target</td><td>A</td><td>Config enabled, only useful for frame layouts, disallowed in strict</td></tr>
</tbody>
<tbody>
@ -262,35 +262,35 @@ Mozilla on inside and needs -moz-outline, no IE support.</td></tr>
</tbody>
<tbody>
<tr><th colspan="3">Transform, target milestone 1.6</th></tr>
<tr><td rowspan="5">align</td><td>CAPTION</td><td>Near-equiv style 'caption-side', drop left and right</td></tr>
<tr><td>IMG</td><td rowspan="2">Margin-left and margin-right = auto or parent div</td></tr>
<tr><td>TABLE</td></tr>
<tr><td>HR</td><td>Near-equivalent style 'text-align' (Works for IE and Opera, but not Firefox). Also try <code>margin-right:auto; margin-left:0;</code> for left or <code>margin-right:0; margin-left:auto;</code> for right (optionally replacing 0 with the original margin for that side)</td></tr>
<tr><th colspan="3">Transform</th></tr>
<tr class="impl-yes"><td rowspan="5">align</td><td>CAPTION</td><td>'caption-side' for top/bottom, 'text-align' for left/right</td></tr>
<tr class="impl-yes"><td>IMG</td><td rowspan="3">See specimens/html-align-to-css.html</td></tr>
<tr class="impl-yes"><td>TABLE</td></tr>
<tr class="impl-yes"><td>HR</td></tr>
<tr class="impl-yes"><td>H1, H2, H3, H4, H5, H6, P</td><td>Equivalent style 'text-align'</td></tr>
<tr class="required impl-yes"><td>alt</td><td>IMG</td><td>Required, insert image filename if src is present or default invalid image text</td></tr>
<tr class="impl-yes"><td rowspan="3">bgcolor</td><td>TABLE</td><td>Superset style 'background-color'</td></tr>
<tr class="impl-yes"><td>TR</td><td>Superset style 'background-color'</td></tr>
<tr class="impl-yes"><td>TD, TH</td><td>Superset style 'background-color'</td></tr>
<tr class="impl-yes"><td>border</td><td>IMG</td><td>Equivalent style <code>border:[number]px solid</code></td></tr>
<tr><td>clear</td><td>BR</td><td>Near-equiv style 'clear', transform 'all' into 'both'</td></tr>
<tr class="impl-yes"><td>clear</td><td>BR</td><td>Near-equiv style 'clear', transform 'all' into 'both'</td></tr>
<tr class="impl-no"><td>compact</td><td>DL, OL, UL</td><td>Boolean, needs custom CSS class; rarely used anyway</td></tr>
<tr class="required impl-yes"><td>dir</td><td>BDO</td><td>Required, insert ltr (or configuration value) if none</td></tr>
<tr class="impl-yes"><td>height</td><td>TD, TH</td><td>Near-equiv style 'height', needs px suffix if original was in pixels</td></tr>
<tr><td>hspace</td><td>IMG</td><td>Near-equiv styles 'margin-top' and 'margin-bottom', needs px suffix</td></tr>
<tr class="impl-yes"><td>hspace</td><td>IMG</td><td>Near-equiv styles 'margin-top' and 'margin-bottom', needs px suffix</td></tr>
<tr class="impl-yes"><td>lang</td><td>*</td><td>Copy value to xml:lang</td></tr>
<tr class="impl-yes"><td rowspan="2">name</td><td>IMG</td><td>Turn into ID</td></tr>
<tr class="impl-yes"><td>A</td><td>Turn into ID</td></tr>
<tr><td>noshade</td><td>HR</td><td>Boolean, style 'border-style:solid;'</td></tr>
<tr><td>nowrap</td><td>TD, TH</td><td>Boolean, style 'white-space:nowrap;' (not compat with IE5)</td></tr>
<tr><td>size</td><td>HR</td><td>Near-equiv 'height', needs px suffix if original was pixels</td></tr>
<tr class="impl-yes"><td>noshade</td><td>HR</td><td>Boolean, style 'border-style:solid;'</td></tr>
<tr class="impl-yes"><td>nowrap</td><td>TD, TH</td><td>Boolean, style 'white-space:nowrap;' (not compat with IE5)</td></tr>
<tr class="impl-yes"><td>size</td><td>HR</td><td>Near-equiv 'height', needs px suffix if original was pixels</td></tr>
<tr class="required impl-yes"><td>src</td><td>IMG</td><td>Required, insert blank or default img if not set</td></tr>
<tr class="impl-yes"><td>start</td><td>OL</td><td>Poorly supported 'counter-reset', allowed in loose, dropped in strict</td></tr>
<tr><td rowspan="3">type</td><td>LI</td><td rowspan="3">Equivalent style 'list-style-type', different allowed values though. (needs testing)</td></tr>
<tr><td>OL</td></tr>
<tr><td>UL</td></tr>
<tr class="impl-yes"><td rowspan="3">type</td><td>LI</td><td rowspan="3">Equivalent style 'list-style-type', different allowed values though. (needs testing)</td></tr>
<tr class="impl-yes"><td>OL</td></tr>
<tr class="impl-yes"><td>UL</td></tr>
<tr class="impl-yes"><td>value</td><td>LI</td><td>Poorly supported 'counter-reset', allowed in loose, dropped in strict</td></tr>
<tr><td>vspace</td><td>IMG</td><td>Near-equiv styles 'margin-left' and 'margin-right', needs px suffix, see hspace</td></tr>
<tr class="impl-yes"><td>vspace</td><td>IMG</td><td>Near-equiv styles 'margin-left' and 'margin-right', needs px suffix, see hspace</td></tr>
<tr class="impl-yes"><td rowspan="2">width</td><td>HR</td><td rowspan="2">Near-equiv style 'width', needs px suffix if original was pixels</td></tr>
<tr class="impl-yes"><td>TD, TH</td></tr>
</tbody>

View File

@ -15,7 +15,7 @@
<div id="filing">Filed under End-User</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>Prior to HTML Purifier 1.2.0, this library blithely accepted user input that
looked like this:</p>

View File

@ -15,7 +15,7 @@
<div id="filing">Filed under End-User</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>HTML Purifier is a very powerful library. But with power comes great
responsibility, in the form of longer execution times. Remember, this

View File

@ -23,7 +23,7 @@ own advice for sake of portability. -->
<div id="filing">Filed under End-User</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>Character encoding and character sets are not that
difficult to understand, but so many people blithely stumble

View File

@ -15,7 +15,7 @@
<div id="filing">Filed under End-User</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>Clients like their YouTube videos. It gives them a warm fuzzy feeling when
they see a neat little embedded video player on their websites that can play
@ -70,7 +70,7 @@ into your documents. YouTube's code goes like this:</p>
class=&quot;embed-youtube&quot;&gt;AyPzM5WK8ys&lt;/span&gt;</code> your
application can reconstruct the full object from this small snippet that
passes through HTML Purifier <em>unharmed</em>.
<a href="http://hp.jpsband.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/Filter/YouTube.php">Show me the code!</a></p>
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/Filter/YouTube.php">Show me the code!</a></p>
<p>And the corresponding usage:</p>

View File

@ -1,14 +1,23 @@
<?php exit;
<?php
// This file demonstrates basic usage of HTMLPurifier.
require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
// replace this with the path to the HTML Purifier library
require_once '../../library/HTMLPurifier.auto.php';
$purifier = new HTMLPurifier();
$config = HTMLPurifier_Config::createDefault();
// configuration goes here:
$config->set('Core', 'Encoding', 'ISO-8859-1'); //replace with your encoding
$config->set('Core', 'XHTML', true); // set to false if HTML 4.01
$purifier = new HTMLPurifier($config);
// untrusted input HTML
$html = '<b>Simple and short';
$pure_html = $purifier->purify($html);
echo $pure_html;
echo '<pre>' . htmlspecialchars($pure_html) . '</pre>';
?>

View File

@ -1,136 +0,0 @@
<?php
// using _REQUEST because we accept GET and POST requests
$content = empty($_REQUEST['xml']) ? 'text/html' : 'application/xhtml+xml';
header("Content-type:$content;charset=UTF-8");
// prevent PHP versions with shorttags from barfing
echo '<?xml version="1.0" encoding="UTF-8" ?>
';
function getFormMethod() {
return (isset($_REQUEST['post'])) ? 'post' : 'get';
}
if (empty($_REQUEST['strict'])) {
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<?php
} else {
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<?php
}
?>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>HTML Purifier Live Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>HTML Purifier Live Demo</h1>
<?php
require_once '../../library/HTMLPurifier.auto.php';
if (!empty($_REQUEST['html'])) { // start result
if (strlen($_REQUEST['html']) > 50000) {
?>
<p>Request exceeds maximum allowed text size of 50kb.</p>
<?php
} else { // start main processing
$html = get_magic_quotes_gpc() ? stripslashes($_REQUEST['html']) : $_REQUEST['html'];
$config = HTMLPurifier_Config::createDefault();
$config->set('Core', 'TidyFormat', !empty($_REQUEST['tidy']));
$config->set('HTML', 'Strict', !empty($_REQUEST['strict']));
$purifier = new HTMLPurifier($config);
$pure_html = $purifier->purify($html);
?>
<p>Here is your purified HTML:</p>
<div style="border:5px solid #CCC;margin:0 10%;padding:1em;">
<?php if(getFormMethod() == 'get') { ?>
<div style="float:right;">
<a href="http://validator.w3.org/check?uri=referer"><img
src="http://www.w3.org/Icons/valid-xhtml10"
alt="Valid XHTML 1.0 Transitional" height="31" width="88" style="border:0;" /></a>
</div>
<?php } ?>
<?php
echo $pure_html;
?>
<div style="clear:both;"></div>
</div>
<p>Here is the source code of the purified HTML:</p>
<pre><?php
echo htmlspecialchars($pure_html, ENT_COMPAT, 'UTF-8');
?></pre>
<?php
if (getFormMethod() == 'post') { // start POST validation notice
?>
<p>If you would like to validate the code with
<a href="http://validator.w3.org/#validate-by-input">W3C's
validator</a>, copy and paste the <em>entire</em> demo page's source.</p>
<?php
} // end POST validation notice
} // end main processing
// end result
} else {
?>
<p>Welcome to the live demo. Enter some HTML and see how HTML Purifier
will filter it.</p>
<?php
}
?>
<form id="filter" action="demo.php<?php
echo '?' . getFormMethod();
if (isset($_REQUEST['profile']) || isset($_REQUEST['XDEBUG_PROFILE'])) {
echo '&amp;XDEBUG_PROFILE=1';
} ?>" method="<?php echo getFormMethod(); ?>">
<fieldset>
<legend>HTML Purifier Input (<?php echo getFormMethod(); ?>)</legend>
<textarea name="html" cols="60" rows="15"><?php
if (isset($html)) {
echo htmlspecialchars(
HTMLPurifier_Encoder::cleanUTF8($html), ENT_COMPAT, 'UTF-8');
}
?></textarea>
<?php if (getFormMethod() == 'get') { ?>
<p><strong>Warning:</strong> GET request method can only hold
8129 characters (probably less depending on your browser).
If you need to test anything
larger than that, try the <a href="demo.php?post">POST form</a>.</p>
<?php } ?>
<?php if (extension_loaded('tidy')) { ?>
<div>Nicely format output with Tidy? <input type="checkbox" value="1"
name="tidy"<?php if (!empty($_REQUEST['tidy'])) echo ' checked="checked"'; ?> /></div>
<?php } ?>
<div>XHTML 1.0 Strict output? <input type="checkbox" value="1"
name="strict"<?php if (!empty($_REQUEST['strict'])) echo ' checked="checked"'; ?> /></div>
<div>Serve as application/xhtml+xml? (not for IE) <input type="checkbox" value="1"
name="xml"<?php if (!empty($_REQUEST['xml'])) echo ' checked="checked"'; ?> /></div>
<div>
<input type="submit" value="Submit" name="submit" class="button" />
</div>
</fieldset>
</form>
<p>Return to <a href="http://hp.jpsband.org/">HTML Purifier's home page</a>.
Try the form in <a href="demo.php?get">GET</a> and <a href="demo.php?post">POST</a> request
flavors (GET is easy to validate with W3C, but POST allows larger inputs).</p>
</body>
</html>

View File

@ -13,7 +13,7 @@
<h1>Documentation</h1>
<p><strong><a href="http://hp.jpsband.org/">HTML Purifier</a></strong> has documentation for all types of people.
<p><strong><a href="http://htmlpurifier.org/">HTML Purifier</a></strong> has documentation for all types of people.
Here is an index of all of them.</p>
<h2>End-user</h2>
@ -42,9 +42,6 @@ conventions.</p>
<dl>
<dt><a href="dev-code-quality.html">Code Quality Issues</a></dt>
<dd>Discusses code quality issues and places that need to be refactored.</dd>
<dt><a href="dev-progress.html">Implementation Progress</a></dt>
<dd>Tables detailing HTML element and CSS property implementation coverage.</dd>
@ -105,6 +102,12 @@ the code. They may be upgraded to HTML files or stay as TXT scratchpads.</p>
<td>Common security issues that may still arise (half-baked).</td>
</tr>
<tr>
<td>Development</td>
<td><a href="enduser-code-quality.txt">Code Quality Issues</a></td>
<td>Enumerates code quality issues and places that need to be refactored.</td>
</tr>
<tr>
<td>Proposal</td>
<td><a href="proposal-filter-levels.txt">Filter levels</a></td>

View File

@ -15,7 +15,7 @@
<div id="filing">Filed under Proposals</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>Your website probably has a color-scheme.
<span style="color:#090; background:#FFF;">Green on white</span>,

View File

@ -15,7 +15,7 @@
<div id="filing">Filed under Reference</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://hp.jpsband.org/">HTML Purifier</a> End-User Documentation</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>Many thanks to the DevNetwork community for answering questions,
theorizing about design, and offering encouragement during

8
docs/specimens/LICENSE Normal file
View File

@ -0,0 +1,8 @@
Licensing of Specimens
Some files in this directory have different licenses:
windows-live-mail-desktop-beta.html - donated by laacz, public domain
img.png - LGPL, from <http://commons.wikimedia.org/wiki/Image:Pastille_chrome.png>
All other files are by me, and are licensed under LGPL.

View File

@ -0,0 +1,165 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>HTML align attribute to CSS - HTML Purifier Specimen</title>
<style type="text/css">
div.container {position:relative;height:110px;}
div.container.legend .test {text-align:center;line-height:100px;}
div.test {width:100px;height:100px;border:1px solid black;
position:absolute;top:10px;}
div.test.html {left:10px;}
div.test.css {left:140px;}
table {background:#F00;}
img {border:1px solid #000;}
hr {width:50px;}
div.segment {width:250px; float:left; margin-top:1em;}
</style>
</head>
<body>
<h1>HTML align attribute to CSS</h1>
<p>Inspect source for methodology.</p>
<div class="container legend">
<div class="test html">
HTML
</div>
<div class="test css">
CSS
</div>
</div>
<div class="segment">
<h2>table.align</h2>
<h3>left</h3>
<div class="container">
<div class="test html">
a<table align="left"><tr><td>O</td></tr></table>a
</div>
<div class="test css">
a<table style="float:left;"><tr><td>O</td></tr></table>a
</div>
</div>
<h3>center</h3>
<div class="container">
<div class="test html">
a<table align="center"><tr><td>O</td></tr></table>a
</div>
<div class="test css">
a<table style="margin-left:auto; margin-right:auto;"><tr><td>O</td></tr></table>a
</div>
</div>
<h3>right</h3>
<div class="container">
<div class="test html">
a<table align="right"><tr><td>O</td></tr></table>a
</div>
<div class="test css">
a<table style="float:right;"><tr><td>O</td></tr></table>a
</div>
</div>
</div>
<!-- ################################################################## -->
<div class="segment">
<h2>img.align</h2>
<h3>left</h3>
<div class="container">
<div class="test html">
a<img src="img.png" align="left">a
</div>
<div class="test css">
a<img src="img.png" style="float:left;">a
</div>
</div>
<h3>right</h3>
<div class="container">
<div class="test html">
a<img src="img.png" align="right">a
</div>
<div class="test css">
a<img src="img.png" style="float:right;">a
</div>
</div>
<h3>bottom</h3>
<div class="container">
<div class="test html">
a<img src="img.png" align="bottom">a
</div>
<div class="test css">
a<img src="img.png" style="vertical-align:baseline;">a
</div>
</div>
<h3>middle</h3>
<div class="container">
<div class="test html">
a<img src="img.png" align="middle">a
</div>
<div class="test css">
a<img src="img.png" style="vertical-align:middle;">a
</div>
</div>
<h3>top</h3>
<div class="container">
<div class="test html">
a<img src="img.png" align="top">a
</div>
<div class="test css">
a<img src="img.png" style="vertical-align:top;">a
</div>
</div>
</div>
<!-- ################################################################## -->
<div class="segment">
<h2>hr.align</h2>
<h3>left</h3>
<div class="container">
<div class="test html">
<hr align="left" />
</div>
<div class="test css">
<hr style="margin-right:auto; margin-left:0; text-align:left;" />
</div>
</div>
<h3>center</h3>
<div class="container">
<div class="test html">
<hr align="center" />
</div>
<div class="test css">
<hr style="margin-right:auto; margin-left:auto; text-align:center;" />
</div>
</div>
<h3>right</h3>
<div class="container">
<div class="test html">
<hr align="right" />
</div>
<div class="test css">
<hr style="margin-right:0; margin-left:auto; text-align:right;" />
</div>
</div>
</div>
</body>
</html>

BIN
docs/specimens/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,74 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML ChildAreas="4" xmlns:canvas><HEAD>
<META http-equiv=Content-Type content=text/html;charset=windows-1257>
<STYLE></STYLE>
<META content="MSHTML 6.00.6000.16414" name=GENERATOR></HEAD>
<BODY id=MailContainerBody
style="PADDING-RIGHT: 10px; PADDING-LEFT: 10px; FONT-SIZE: 10pt; COLOR: #000000; PADDING-TOP: 15px; FONT-FAMILY: Arial"
bgColor=#ff6600 leftMargin=0 background="" topMargin=0
name="Compose message area" acc_role="text" CanvasTabStop="false">
<DIV
style="BORDER-TOP: #dddddd 1px solid; FONT-SIZE: 10pt; WIDTH: 100%; MARGIN-RIGHT: 10px; PADDING-TOP: 5px; BORDER-BOTTOM: #dddddd 1px solid; FONT-FAMILY: Verdana; HEIGHT: 25px; BACKGROUND-COLOR: #ffffff"><NOBR><SPAN
title="View a slideshow of the pictures in this e-mail message."
style="PADDING-RIGHT: 20px"><A style="COLOR: #0088e4"
href="http://g.msn.com/5meen_us/171?path=/photomail/{6fc0065f-ffdd-4ca6-9a4c-cc5a93dc122f}&amp;image=47D7B182CFEFB10!127&amp;imagehi=47D7B182CFEFB10!125&amp;CID=323550092004883216">Play
slideshow </A></SPAN><SPAN style="COLOR: #909090"><SPAN>|</SPAN><SPAN
style="PADDING-LEFT: 20px"> Download the highest quality version of a picture by
clicking the + above it </SPAN></SPAN></NOBR></DIV>
<DIV
style="PADDING-RIGHT: 5px; PADDING-LEFT: 7px; PADDING-BOTTOM: 2px; WIDTH: 100%; PADDING-TOP: 2px">
<OL>
<LI><IMG title="Angry smile emoticon"
style="FLOAT: none; MARGIN: 0px; POSITION: static" tabIndex=-1
alt="Angry smile emoticon" src="cid:49F0C856199E4D688D2D740680733D74@wc"
MSNNonUserImageOrEmoticon="true">Un ka <FONT style="BACKGROUND-COLOR: #800000"
color=#cc99ff><STRONG>Tev</STRONG></FONT> iet, un ko tu dari?
<LI>Aha!</LI></OL>
<UL>
<LI>Buletets
<LI>
<DIV align=justify><A title=http://laacz.lv/blog/
href="http://laacz.lv/blog/">http://laacz.lv/blog/</A> un <A
title=http://google.com/ href="http://google.com/">gugle</A></DIV>
<LI>Sarakstucitis</LI></UL></DIV><SPAN><SPAN xmlns:canvas="canvas-namespace-id"
layoutEmptyTextWellFont="Tahoma"><SPAN
style="MARGIN-BOTTOM: 15px; OVERFLOW: visible; HEIGHT: 16px"></SPAN><SPAN
style="MARGIN-BOTTOM: 25px; VERTICAL-ALIGN: top; OVERFLOW: visible; MARGIN-RIGHT: 25px; HEIGHT: 234px">
<TABLE style="DISPLAY: inline">
<TBODY>
<TR>
<TD>
<DIV
style="FONT-WEIGHT: bold; FONT-SIZE: 12pt; FONT-FAMILY: arial; TEXT-ALIGN: center"><A
id=HiresARef
title="Click here to view or download a high resolution version of this picture"
style="COLOR: #0088e4; TEXT-DECORATION: none"
href="http://byfiles.storage.msn.com/x1pMvt0I80jTgT6DuaCpEMbprX3nk3jNv_vjigxV_EYVSMyM_PKgEvDEUtuNhQC-F-23mTTcKyqx6eGaeK2e_wMJ0ikwpDdFntk4SY7pfJUv2g2Ck6R2S2vAA?download">+</A></DIV>
<DIV
title="Click here to view the full image using the online photo viewer."
style="DISPLAY: inline; OVERFLOW: hidden; WIDTH: 140px; HEIGHT: 140px"><A
href="http://g.msn.com/5meen_us/171?path=/photomail/{6fc0065f-ffdd-4ca6-9a4c-cc5a93dc122f}&amp;image=47D7B182CFEFB10!127&amp;imagehi=47D7B182CFEFB10!125&amp;CID=323550092004883216"
border="0"><IMG
style="MARGIN-TOP: 15px; DISPLAY: inline-block; MARGIN-LEFT: 0px"
height=109 src="cid:006A71303B80404E9FB6184E55D6A446@wc" width=140
border=0></A></DIV></TD></TR>
<TR>
<TD>
<DIV
style="FONT-SIZE: 10pt; WIDTH: 140px; FONT-FAMILY: verdana; TEXT-ALIGN: center"><EM><STRONG>This
<U>is </U></STRONG><U>tit</U>le</EM> fo<STRONG>r <FONT
face="Arial Black">t<FONT color=#800000 size=7>h<U>i</U></FONT>s
</FONT>picture</STRONG></DIV></TD></TR></TBODY></TABLE></SPAN></SPAN></SPAN>
<DIV
style="PADDING-RIGHT: 5px; PADDING-LEFT: 7px; PADDING-BOTTOM: 2px; WIDTH: 100%; PADDING-TOP: 2px; HEIGHT: 50px">
<DIV>&nbsp;</DIV></DIV>
<DIV
style="BORDER-TOP: #dddddd 1px solid; FONT-SIZE: 10pt; MARGIN-BOTTOM: 10px; WIDTH: 100%; COLOR: #909090; MARGIN-RIGHT: 10px; PADDING-TOP: 9px; FONT-FAMILY: Verdana; HEIGHT: 42px; BACKGROUND-COLOR: #ffffff"><NOBR><SPAN
title="Join Windows Live to share photos using Windows Live Photo E-mail.">Online
pictures are available for 30 days. <A style="COLOR: #0088e4"
href="http://g.msn.com/5meen_us/175">Get Windows Live Mail desktop to create
your own photo e-mails. </A></SPAN></NOBR></DIV></BODY></HTML>

View File

@ -22,7 +22,7 @@
*/
/*
HTML Purifier 1.6.0 - Standards Compliant HTML Filtering
HTML Purifier 1.6.1 - Standards Compliant HTML Filtering
Copyright (C) 2006 Edward Z. Yang
This library is free software; you can redistribute it and/or
@ -64,7 +64,7 @@ require_once 'HTMLPurifier/Encoder.php';
class HTMLPurifier
{
var $version = '1.6.0';
var $version = '1.6.1';
var $config;
var $filters;

View File

@ -5,6 +5,9 @@ require_once 'HTMLPurifier/AttrDef.php';
// Enum = Enumerated
/**
* Validates a keyword against a list of valid values.
* @warning The case-insensitive compare of this function uses PHP's
* built-in strtolower and ctype_lower functions, which may
* cause problems with international comparisons
*/
class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
{
@ -34,6 +37,7 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
function validate($string, $config, &$context) {
$string = trim($string);
if (!$this->case_sensitive) {
// we may want to do full case-insensitive libraries
$string = ctype_lower($string) ? $string : strtolower($string);
}
$result = isset($this->valid_values[$string]);

View File

@ -0,0 +1,34 @@
<?php
HTMLPurifier_ConfigSchema::define(
'Attr', 'AllowedFrameTargets', array(), 'lookup',
'Lookup table of all allowed link frame targets. Some commonly used '.
'link targets include _blank, _self, _parent and _top. Values should '.
'be lowercase, as validation will be done in a case-sensitive manner '.
'despite W3C\'s recommendation. XHTML 1.0 Strict does not permit '.
'the target attribute so this directive will have no effect in that '.
'doctype. XHTML 1.1 does not enable the Target module by default, you '.
'will have to manually enable it (see the module documentation for more details.)'
);
require_once 'HTMLPurifier/AttrDef/Enum.php';
/**
* Special-case enum attribute definition that lazy loads allowed frame targets
*/
class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum
{
var $valid_values = false; // uninitialized value
var $case_sensitive = false;
function HTMLPurifier_AttrDef_HTML_FrameTarget() {}
function validate($string, $config, &$context) {
if ($this->valid_values === false) $this->valid_values = $config->get('Attr', 'AllowedFrameTargets');
return parent::validate($string, $config, $context);
}
}
?>

View File

@ -29,6 +29,30 @@ class HTMLPurifier_AttrTransform
function transform($attr, $config, &$context) {
trigger_error('Cannot call abstract function', E_USER_ERROR);
}
/**
* Prepends CSS properties to the style attribute, creating the
* attribute if it doesn't exist.
* @param $attr Attribute array to process (passed by reference)
* @param $css CSS to prepend
*/
function prependCSS(&$attr, $css) {
$attr['style'] = isset($attr['style']) ? $attr['style'] : '';
$attr['style'] = $css . $attr['style'];
}
/**
* Retrieves and removes an attribute
* @param $attr Attribute array to process (passed by reference)
* @param $key Key of attribute to confiscate
*/
function confiscateAttr(&$attr, $key) {
if (!isset($attr[$key])) return null;
$value = $attr[$key];
unset($attr[$key]);
return $value;
}
}
?>

View File

@ -12,12 +12,10 @@ extends HTMLPurifier_AttrTransform {
if (!isset($attr['bgcolor'])) return $attr;
$bgcolor = $attr['bgcolor'];
unset($attr['bgcolor']);
$bgcolor = $this->confiscateAttr($attr, 'bgcolor');
// some validation should happen here
$attr['style'] = isset($attr['style']) ? $attr['style'] : '';
$attr['style'] = "background-color:$bgcolor;" . $attr['style'];
$this->prependCSS($attr, "background-color:$bgcolor;");
return $attr;

View File

@ -0,0 +1,39 @@
<?php
require_once 'HTMLPurifier/AttrTransform.php';
/**
* Pre-transform that changes converts a boolean attribute to fixed CSS
*/
class HTMLPurifier_AttrTransform_BoolToCSS
extends HTMLPurifier_AttrTransform {
/**
* Name of boolean attribute that is trigger
*/
var $attr;
/**
* CSS declarations to add to style, needs trailing semicolon
*/
var $css;
/**
* @param $attr string attribute name to convert from
* @param $css string CSS declarations to add to style (needs semicolon)
*/
function HTMLPurifier_AttrTransform_BoolToCSS($attr, $css) {
$this->attr = $attr;
$this->css = $css;
}
function transform($attr, $config, &$context) {
if (!isset($attr[$this->attr])) return $attr;
unset($attr[$this->attr]);
$this->prependCSS($attr, $this->css);
return $attr;
}
}
?>

View File

@ -5,22 +5,14 @@ require_once 'HTMLPurifier/AttrTransform.php';
/**
* Pre-transform that changes deprecated border attribute to CSS.
*/
class HTMLPurifier_AttrTransform_Border
extends HTMLPurifier_AttrTransform {
class HTMLPurifier_AttrTransform_Border extends HTMLPurifier_AttrTransform {
function transform($attr, $config, &$context) {
if (!isset($attr['border'])) return $attr;
$border_width = $attr['border'];
unset($attr['border']);
$border_width = $this->confiscateAttr($attr, 'border');
// some validation should happen here
$attr['style'] = isset($attr['style']) ? $attr['style'] : '';
$attr['style'] = "border:{$border_width}px solid;" . $attr['style'];
$this->prependCSS($attr, "border:{$border_width}px solid;");
return $attr;
}
}

View File

@ -0,0 +1,60 @@
<?php
require_once 'HTMLPurifier/AttrTransform.php';
/**
* Generic pre-transform that converts an attribute with a fixed number of
* values (enumerated) to CSS.
*/
class HTMLPurifier_AttrTransform_EnumToCSS extends HTMLPurifier_AttrTransform {
/**
* Name of attribute to transform from
*/
var $attr;
/**
* Lookup array of attribute values to CSS
*/
var $enumToCSS = array();
/**
* Case sensitivity of the matching
* @warning Currently can only be guaranteed to work with ASCII
* values.
*/
var $caseSensitive = false;
/**
* @param $attr String attribute name to transform from
* @param $enumToCSS Lookup array of attribute values to CSS
* @param $case_sensitive Boolean case sensitivity indicator, default false
*/
function HTMLPurifier_AttrTransform_EnumToCSS($attr, $enum_to_css, $case_sensitive = false) {
$this->attr = $attr;
$this->enumToCSS = $enum_to_css;
$this->caseSensitive = (bool) $case_sensitive;
}
function transform($attr, $config, &$context) {
if (!isset($attr[$this->attr])) return $attr;
$value = trim($attr[$this->attr]);
unset($attr[$this->attr]);
if (!$this->caseSensitive) $value = strtolower($value);
if (!isset($this->enumToCSS[$value])) {
return $attr;
}
$this->prependCSS($attr, $this->enumToCSS[$value]);
return $attr;
}
}
?>

View File

@ -0,0 +1,47 @@
<?php
require_once 'HTMLPurifier/AttrTransform.php';
/**
* Pre-transform that changes deprecated hspace and vspace attributes to CSS
*/
class HTMLPurifier_AttrTransform_ImgSpace
extends HTMLPurifier_AttrTransform {
var $attr;
var $css = array(
'hspace' => array('left', 'right'),
'vspace' => array('top', 'bottom')
);
function HTMLPurifier_AttrTransform_ImgSpace($attr) {
$this->attr = $attr;
if (!isset($this->css[$attr])) {
trigger_error(htmlspecialchars($attr) . ' is not valid space attribute');
}
}
function transform($attr, $config, &$context) {
if (!isset($attr[$this->attr])) return $attr;
$width = $this->confiscateAttr($attr, $this->attr);
// some validation could happen here
if (!isset($this->css[$this->attr])) return $attr;
$style = '';
foreach ($this->css[$this->attr] as $suffix) {
$property = "margin-$suffix";
$style .= "$property:{$width}px;";
}
$this->prependCSS($attr, $style);
return $attr;
}
}
?>

View File

@ -18,13 +18,9 @@ class HTMLPurifier_AttrTransform_Length extends HTMLPurifier_AttrTransform
function transform($attr, $config, &$context) {
if (!isset($attr[$this->name])) return $attr;
$length = $attr[$this->name];
unset($attr[$this->name]);
$length = $this->confiscateAttr($attr, $this->name);
if(ctype_digit($length)) $length .= 'px';
$attr['style'] = isset($attr['style']) ? $attr['style'] : '';
$attr['style'] = $this->cssName . ":$length;" . $attr['style'];
$this->prependCSS($attr, $this->cssName . ":$length;");
return $attr;
}

View File

@ -9,21 +9,11 @@ class HTMLPurifier_AttrTransform_Name extends HTMLPurifier_AttrTransform
{
function transform($attr, $config, &$context) {
if (!isset($attr['name'])) return $attr;
$name = $attr['name'];
unset($attr['name']);
if (isset($attr['id'])) {
// ID already set, discard name
return $attr;
}
$attr['id'] = $name;
$id = $this->confiscateAttr($attr, 'name');
if ( isset($attr['id'])) return $attr;
$attr['id'] = $id;
return $attr;
}
}

View File

@ -1,36 +0,0 @@
<?php
require_once 'HTMLPurifier/AttrTransform.php';
/**
* Pre-transform that changes deprecated align attribute to text-align.
*/
class HTMLPurifier_AttrTransform_TextAlign
extends HTMLPurifier_AttrTransform {
function transform($attr, $config, &$context) {
if (!isset($attr['align'])) return $attr;
$align = strtolower(trim($attr['align']));
unset($attr['align']);
$values = array('left' => 1,
'right' => 1,
'center' => 1,
'justify' => 1);
if (!isset($values[$align])) {
return $attr;
}
$attr['style'] = isset($attr['style']) ? $attr['style'] : '';
$attr['style'] = "text-align:$align;" . $attr['style'];
return $attr;
}
}
?>

View File

@ -206,6 +206,9 @@ class HTMLPurifier_CSSDefinition
new HTMLPurifier_AttrDef_CSS_Percentage()
));
// partial support
$this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(array('nowrap'));
}
}

View File

@ -334,6 +334,10 @@ class HTMLPurifier_ConfigSchema {
case 'hash':
case 'lookup':
if (is_string($var)) {
// special case: technically, this is an array with
// a single empty string item, but having an empty
// array is more intuitive
if ($var == '') return array();
// simplistic string to array method that only works
// for simple lists of tag names or alphanumeric characters
$var = explode(',',$var);

View File

@ -95,7 +95,7 @@ class HTMLPurifier_ElementDef
// later keys takes precedence
foreach($def->attr as $k => $v) {
if ($k == 0) {
if ($k === 0) {
// merge in the includes
// sorry, no way to override an include
foreach ($v as $v2) {

View File

@ -183,9 +183,18 @@ class HTMLPurifier_HTMLDefinition
$this->manager->setup($this->config);
foreach ($this->manager->activeModules as $module) {
foreach($module->info_tag_transform as $k => $v) $this->info_tag_transform[$k] = $v;
foreach($module->info_attr_transform_pre as $k => $v) $this->info_attr_transform_pre[$k] = $v;
foreach($module->info_attr_transform_post as $k => $v) $this->info_attr_transform_post[$k]= $v;
foreach($module->info_tag_transform as $k => $v) {
if ($v === false) unset($this->info_tag_transform[$k]);
else $this->info_tag_transform[$k] = $v;
}
foreach($module->info_attr_transform_pre as $k => $v) {
if ($v === false) unset($this->info_attr_transform_pre[$k]);
else $this->info_attr_transform_pre[$k] = $v;
}
foreach($module->info_attr_transform_post as $k => $v) {
if ($v === false) unset($this->info_attr_transform_post[$k]);
else $this->info_attr_transform_post[$k] = $v;
}
}
$this->info = $this->manager->getElements($this->config);
@ -278,4 +287,4 @@ class HTMLPurifier_HTMLDefinition
}
?>
?>

View File

@ -12,7 +12,6 @@ class HTMLPurifier_HTMLModule_Bdo extends HTMLPurifier_HTMLModule
var $name = 'Bdo';
var $elements = array('bdo');
var $info = array();
var $content_sets = array('Inline' => 'bdo');
var $attr_collections = array(
'I18N' => array('dir' => false)

View File

@ -12,7 +12,6 @@ class HTMLPurifier_HTMLModule_Edit extends HTMLPurifier_HTMLModule
var $name = 'Edit';
var $elements = array('del', 'ins');
var $info = array();
var $content_sets = array('Inline' => 'del | ins');
function HTMLPurifier_HTMLModule_Edit() {

View File

@ -11,7 +11,6 @@ class HTMLPurifier_HTMLModule_Hypertext extends HTMLPurifier_HTMLModule
var $name = 'Hypertext';
var $elements = array('a');
var $info = array();
var $content_sets = array('Inline' => 'a');
function HTMLPurifier_HTMLModule_Hypertext() {

View File

@ -15,7 +15,6 @@ class HTMLPurifier_HTMLModule_Image extends HTMLPurifier_HTMLModule
var $name = 'Image';
var $elements = array('img');
var $info = array();
var $content_sets = array('Inline' => 'img');
function HTMLPurifier_HTMLModule_Image() {

View File

@ -10,7 +10,7 @@ class HTMLPurifier_HTMLModule_List extends HTMLPurifier_HTMLModule
var $name = 'List';
var $elements = array('dl', 'dt', 'dd', 'ol', 'ul', 'li');
var $info = array();
// According to the abstract schema, the List content set is a fully formed
// one or more expr, but it invariably occurs in an optional declaration
// so we're not going to do that subtlety. It might cause trouble

View File

@ -17,7 +17,6 @@ class HTMLPurifier_HTMLModule_Presentation extends HTMLPurifier_HTMLModule
var $name = 'Presentation';
var $elements = array('b', 'big', 'hr', 'i', 'small', 'sub', 'sup', 'tt');
var $info = array();
var $content_sets = array(
'Block' => 'hr',
'Inline' => 'b | big | i | small | sub | sup | tt'

View File

@ -0,0 +1,67 @@
<?php
/*
WARNING: THIS MODULE IS EXTREMELY DANGEROUS AS IT ENABLES INLINE SCRIPTING
INSIDE HTML PURIFIER DOCUMENTS. USE ONLY WITH TRUSTED USER INPUT!!!
Usage:
require_once 'HTMLPurifier/HTMLModule/Scripting.php';
$def =& $config->getHTMLDefinition(true); // get the raw version
$def->manager->addModule('Scripting');
This must come before any other calls to getHTMLDefinition()
*/
/**
* Implements required attribute stipulation for <script>
*/
class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform
{
function transform($attr, $config, &$context) {
if (!isset($attr['type'])) {
$attr['type'] = 'text/javascript';
}
return $attr;
}
}
/**
* XHTML 1.1 Scripting module, defines elements that are used to contain
* information pertaining to executable scripts or the lack of support
* for executable scripts.
* @note This module does not contain inline scripting elements
*/
class HTMLPurifier_HTMLModule_Scripting extends HTMLPurifier_HTMLModule
{
var $name = 'Scripting';
var $elements = array('script', 'noscript');
var $content_sets = array('Block' => 'script | noscript', 'Inline' => 'script | noscript');
function HTMLPurifier_HTMLModule_Scripting() {
// TODO: create custom child-definition for noscript that
// auto-wraps stray #PCDATA in a similar manner to
// blockquote's custom definition (we would use it but
// blockquote's contents are optional while noscript's contents
// are required)
foreach ($this->elements as $element) {
$this->info[$element] = new HTMLPurifier_ElementDef();
}
$this->info['noscript']->attr = array( 0 => array('Common') );
$this->info['noscript']->content_model = 'Heading | List | Block';
$this->info['noscript']->content_model_type = 'required';
$this->info['script']->attr = array(
'defer' => new HTMLPurifier_AttrDef_Enum(array('defer')),
'src' => new HTMLPurifier_AttrDef_URI(true),
'type' => new HTMLPurifier_AttrDef_Enum(array('text/javascript'))
);
$this->info['script']->content_model = '#PCDATA';
$this->info['script']->content_model_type = 'optional';
$this->info['script']->attr_transform_post['type'] =
new HTMLPurifier_AttrTransform_ScriptRequired();
}
}
?>

View File

@ -12,7 +12,6 @@ class HTMLPurifier_HTMLModule_Tables extends HTMLPurifier_HTMLModule
var $name = 'Tables';
var $elements = array('caption', 'table', 'td', 'th', 'tr', 'col',
'colgroup', 'tbody', 'thead', 'tfoot');
var $info = array();
var $content_sets = array('Block' => 'table');
function HTMLPurifier_HTMLModule_Tables() {

View File

@ -0,0 +1,26 @@
<?php
require_once 'HTMLPurifier/AttrDef/HTML/FrameTarget.php';
/**
* XHTML 1.1 Target Module, defines target attribute in link elements.
*/
class HTMLPurifier_HTMLModule_Target extends HTMLPurifier_HTMLModule
{
var $name = 'Target';
var $elements = array('a');
function HTMLPurifier_HTMLModule_Target() {
foreach ($this->elements as $e) {
$this->info[$e] = new HTMLPurifier_ElementDef();
$this->info[$e]->standalone = false;
$this->info[$e]->attr = array(
'target' => new HTMLPurifier_AttrDef_HTML_FrameTarget()
);
}
}
}
?>

View File

@ -22,8 +22,6 @@ class HTMLPurifier_HTMLModule_Text extends HTMLPurifier_HTMLModule
'h4', 'h5', 'h6', 'kbd', 'p', 'pre', 'q', 'samp', 'span', 'strong',
'var');
var $info = array();
var $content_sets = array(
'Heading' => 'h1 | h2 | h3 | h4 | h5 | h6',
'Block' => 'address | blockquote | div | p | pre',

View File

@ -7,11 +7,13 @@ require_once 'HTMLPurifier/TagTransform/Center.php';
require_once 'HTMLPurifier/TagTransform/Font.php';
require_once 'HTMLPurifier/AttrTransform/Lang.php';
require_once 'HTMLPurifier/AttrTransform/TextAlign.php';
require_once 'HTMLPurifier/AttrTransform/BgColor.php';
require_once 'HTMLPurifier/AttrTransform/BoolToCSS.php';
require_once 'HTMLPurifier/AttrTransform/Border.php';
require_once 'HTMLPurifier/AttrTransform/Name.php';
require_once 'HTMLPurifier/AttrTransform/Length.php';
require_once 'HTMLPurifier/AttrTransform/ImgSpace.php';
require_once 'HTMLPurifier/AttrTransform/EnumToCSS.php';
/**
* Proprietary module that transforms deprecated elements into Strict
@ -25,7 +27,8 @@ class HTMLPurifier_HTMLModule_TransformToStrict extends HTMLPurifier_HTMLModule
// we're actually modifying these elements, not defining them
var $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p',
'blockquote', 'table', 'td', 'th', 'tr', 'img', 'a', 'hr');
'blockquote', 'table', 'td', 'th', 'tr', 'img', 'a', 'hr', 'br',
'caption', 'ul', 'ol', 'li');
var $info_tag_transform = array(
// placeholders, see constructor for definitions
@ -47,6 +50,13 @@ class HTMLPurifier_HTMLModule_TransformToStrict extends HTMLPurifier_HTMLModule
function HTMLPurifier_HTMLModule_TransformToStrict() {
// behavior with transformations when there's another CSS property
// working on it is interesting: the CSS will *always* override
// the deprecated attribute, whereas an inline CSS declaration will
// override the corresponding declaration in, say, an external
// stylesheet. This behavior won't affect most people, but it
// does represent an operational difference we CANNOT fix.
// deprecated tag transforms
$this->info_tag_transform['font'] = new HTMLPurifier_TagTransform_Font();
$this->info_tag_transform['menu'] = new HTMLPurifier_TagTransform_Simple('ul');
@ -59,6 +69,11 @@ class HTMLPurifier_HTMLModule_TransformToStrict extends HTMLPurifier_HTMLModule
}
// deprecated attribute transforms
// align battery
$align_lookup = array();
$align_values = array('left', 'right', 'center', 'justify');
foreach ($align_values as $v) $align_lookup[$v] = "text-align:$v;";
$this->info['h1']->attr_transform_pre['align'] =
$this->info['h2']->attr_transform_pre['align'] =
$this->info['h3']->attr_transform_pre['align'] =
@ -66,7 +81,7 @@ class HTMLPurifier_HTMLModule_TransformToStrict extends HTMLPurifier_HTMLModule
$this->info['h5']->attr_transform_pre['align'] =
$this->info['h6']->attr_transform_pre['align'] =
$this->info['p'] ->attr_transform_pre['align'] =
new HTMLPurifier_AttrTransform_TextAlign();
new HTMLPurifier_AttrTransform_EnumToCSS('align', $align_lookup);
// xml:lang <=> lang mirroring, implement in TransformToStrict,
// this is overridden in TransformToXHTML11
@ -92,9 +107,86 @@ class HTMLPurifier_HTMLModule_TransformToStrict extends HTMLPurifier_HTMLModule
$this->info['th']->attr_transform_pre['width'] =
$this->info['hr']->attr_transform_pre['width'] = new HTMLPurifier_AttrTransform_Length('width');
$this->info['td']->attr_transform_pre['nowrap'] =
$this->info['th']->attr_transform_pre['nowrap'] = new HTMLPurifier_AttrTransform_BoolToCSS('nowrap', 'white-space:nowrap;');
$this->info['td']->attr_transform_pre['height'] =
$this->info['th']->attr_transform_pre['height'] = new HTMLPurifier_AttrTransform_Length('height');
$this->info['img']->attr_transform_pre['hspace'] = new HTMLPurifier_AttrTransform_ImgSpace('hspace');
$this->info['img']->attr_transform_pre['vspace'] = new HTMLPurifier_AttrTransform_ImgSpace('vspace');
$this->info['hr']->attr_transform_pre['size'] = new HTMLPurifier_AttrTransform_Length('size', 'height');
// this transformation is not precise but often good enough.
// different browsers use different styles to designate noshade
$this->info['hr']->attr_transform_pre['noshade'] = new HTMLPurifier_AttrTransform_BoolToCSS('noshade', 'color:#808080;background-color:#808080;border: 0;');
$this->info['br']->attr_transform_pre['clear'] =
new HTMLPurifier_AttrTransform_EnumToCSS('clear', array(
'left' => 'clear:left;',
'right' => 'clear:right;',
'all' => 'clear:both;',
'none' => 'clear:none;',
));
// this is a slightly unreasonable attribute
$this->info['caption']->attr_transform_pre['align'] =
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
// we're following IE's behavior, not Firefox's, due
// to the fact that no one supports caption-side:right,
// W3C included (with CSS 2.1)
'left' => 'text-align:left;',
'right' => 'text-align:right;',
'top' => 'caption-side:top;',
'bottom' => 'caption-side:bottom;' // not supported by IE
));
$this->info['table']->attr_transform_pre['align'] =
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
'left' => 'float:left;',
'center' => 'margin-left:auto;margin-right:auto;',
'right' => 'float:right;'
));
$this->info['img']->attr_transform_pre['align'] =
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
'left' => 'float:left;',
'right' => 'float:right;',
'top' => 'vertical-align:top;',
'middle' => 'vertical-align:middle;',
'bottom' => 'vertical-align:baseline;',
));
$this->info['hr']->attr_transform_pre['align'] =
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
'left' => 'margin-left:0;margin-right:auto;text-align:left;',
'center' => 'margin-left:auto;margin-right:auto;text-align:center;',
'right' => 'margin-left:auto;margin-right:0;text-align:right;'
));
$ul_types = array(
'disc' => 'list-style-type:disc;',
'square' => 'list-style-type:square;',
'circle' => 'list-style-type:circle;'
);
$ol_types = array(
'1' => 'list-style-type:decimal;',
'i' => 'list-style-type:lower-roman;',
'I' => 'list-style-type:upper-roman;',
'a' => 'list-style-type:lower-alpha;',
'A' => 'list-style-type:upper-alpha;'
);
$li_types = $ul_types + $ol_types;
$this->info['ul']->attr_transform_pre['type'] =
new HTMLPurifier_AttrTransform_EnumToCSS('type', $ul_types);
$this->info['ol']->attr_transform_pre['type'] =
new HTMLPurifier_AttrTransform_EnumToCSS('type', $ol_types, true);
$this->info['li']->attr_transform_pre['type'] =
new HTMLPurifier_AttrTransform_EnumToCSS('type', $li_types, true);
}
var $defines_child_def = true;

View File

@ -1,5 +1,7 @@
<?php
require_once 'HTMLPurifier/AttrTransform/Lang.php';
/**
* Proprietary module that transforms XHTML 1.0 deprecated aspects into
* XHTML 1.1 compliant ones, when possible. For maximum effectiveness,
@ -25,6 +27,10 @@ class HTMLPurifier_HTMLModule_TransformToXHTML11 extends HTMLPurifier_HTMLModule
'lang' => false // remove it
);
function HTMLPurifier_HTMLModule_TransformToXHTML11() {
$this->info_attr_transform_pre['lang'] = new HTMLPurifier_AttrTransform_Lang();
}
}
?>

View File

@ -22,6 +22,7 @@ require_once 'HTMLPurifier/HTMLModule/Tables.php';
require_once 'HTMLPurifier/HTMLModule/Image.php';
require_once 'HTMLPurifier/HTMLModule/StyleAttribute.php';
require_once 'HTMLPurifier/HTMLModule/Legacy.php';
require_once 'HTMLPurifier/HTMLModule/Target.php';
// proprietary modules
require_once 'HTMLPurifier/HTMLModule/TransformToStrict.php';
@ -134,6 +135,7 @@ class HTMLPurifier_HTMLModuleManager
'CommonAttributes',
'Text', 'Hypertext', 'List', 'Presentation',
'Edit', 'Bdo', 'Tables', 'Image', 'StyleAttribute',
'Target',
// define-redefine
'Legacy',
// redefine
@ -155,7 +157,7 @@ class HTMLPurifier_HTMLModuleManager
'HTML 4.01 Transitional' => array(array('XHTML 1.0 Transitional')),
'HTML 4.01 Strict' => array(array('XHTML 1.0 Strict')),
// XHTML definitions
'XHTML 1.0 Transitional' => array( array('XHTML 1.0 Strict'), 'Legacy' ),
'XHTML 1.0 Transitional' => array( array('XHTML 1.0 Strict'), 'Legacy', 'Target' ),
'XHTML 1.0 Strict' => array(array('_Common')),
'XHTML 1.1' => array(array('_Common')),
);
@ -206,20 +208,35 @@ class HTMLPurifier_HTMLModuleManager
* @param $module Mixed: string module name, with or without
* HTMLPurifier_HTMLModule prefix, or instance of
* subclass of HTMLPurifier_HTMLModule.
* @note This function will not call autoload, you must instantiate
* (and thus invoke) autoload outside the method.
* @note If a string is passed as a module name, different variants
* will be tested in this order:
* - Check for HTMLPurifier_HTMLModule_$name
* - Check all prefixes with $name in order they were added
* - Check for literal object name
* - Throw fatal error
* If your object name collides with an internal class, specify
* your module manually.
*/
function addModule($module) {
if (is_string($module)) {
$original_module = $module;
if (!class_exists($module)) {
foreach ($this->prefixes as $prefix) {
$module = $prefix . $original_module;
if (class_exists($module)) break;
$ok = false;
foreach ($this->prefixes as $prefix) {
$module = $prefix . $original_module;
if ($this->_classExists($module)) {
$ok = true;
break;
}
}
if (!class_exists($module)) {
trigger_error($original_module . ' module does not exist',
E_USER_ERROR);
return;
if (!$ok) {
$module = $original_module;
if (!$this->_classExists($module)) {
trigger_error($original_module . ' module does not exist',
E_USER_ERROR);
return;
}
}
$module = new $module();
}
@ -230,6 +247,23 @@ class HTMLPurifier_HTMLModuleManager
}
}
/**
* Safely tests for class existence without invoking __autoload in PHP5
* @param $name String class name to test
* @private
*/
function _classExists($name) {
static $is_php_4 = null;
if ($is_php_4 === null) {
$is_php_4 = version_compare(PHP_VERSION, '5', '<');
}
if ($is_php_4) {
return class_exists($name);
} else {
return class_exists($name, false);
}
}
/**
* Makes a collection active, while also making it valid if not
* already done so. See $activeModules for the semantics of "active".
@ -491,7 +525,8 @@ class HTMLPurifier_HTMLModuleManager
$elements = array();
foreach ($this->activeModules as $module) {
foreach ($module->elements as $name) {
foreach ($module->info as $name => $v) {
if (isset($elements[$name])) continue;
$elements[$name] = $this->getElement($name, $config);
}
}
@ -555,4 +590,4 @@ class HTMLPurifier_HTMLModuleManager
}
?>
?>

View File

@ -110,6 +110,23 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
continue;
}
// Check leading character is alnum, if not, we may
// have accidently grabbed an emoticon. Translate into
// text and go our merry way
if (!ctype_alnum($segment[0])) {
$array[] = new
HTMLPurifier_Token_Text(
'<' .
$this->parseData(
$segment
) .
'>'
);
$cursor = $position_next_gt + 1;
$inside_tag = false;
continue;
}
// Check if it is explicitly self closing, if so, remove
// trailing slash. Remember, we could have a tag like <br>, so
// any later token processing scripts must convert improperly

View File

@ -29,6 +29,7 @@ class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy
$generator = new HTMLPurifier_Generator();
$result = array();
$escape_invalid_tags = $config->get('Core', 'EscapeInvalidTags');
$remove_invalid_img = $config->get('Core', 'RemoveInvalidImg');
foreach($tokens as $token) {
if (!empty( $token->is_tag )) {
// DEFINITION CALL
@ -37,7 +38,7 @@ class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy
// hard-coded image special case, pre-emptively drop
// if not available. Probably not abstract-able
if ( $token->name == 'img' ) {
if ( $token->name == 'img' && $remove_invalid_img ) {
if (!isset($token->attr['src'])) {
continue;
}

View File

@ -20,6 +20,7 @@ class HTMLPurifier_TagTransform_Font extends HTMLPurifier_TagTransform
var $transform_to = 'span';
var $_size_lookup = array(
'0' => 'xx-small',
'1' => 'xx-small',
'2' => 'small',
'3' => 'medium',
@ -28,9 +29,10 @@ class HTMLPurifier_TagTransform_Font extends HTMLPurifier_TagTransform
'6' => 'xx-large',
'7' => '300%',
'-1' => 'smaller',
'+1' => 'larger',
'-2' => '60%',
'+1' => 'larger',
'+2' => '150%',
'+3' => '200%',
'+4' => '300%'
);
@ -58,6 +60,15 @@ class HTMLPurifier_TagTransform_Font extends HTMLPurifier_TagTransform
// handle size transform
if (isset($attr['size'])) {
// normalize large numbers
if ($attr['size']{0} == '+' || $attr['size']{0} == '-') {
$size = (int) $attr['size'];
if ($size < -2) $attr['size'] = '-2';
if ($size > 4) $attr['size'] = '+4';
} else {
$size = (int) $attr['size'];
if ($size > 7) $attr['size'] = '7';
}
if (isset($this->_size_lookup[$attr['size']])) {
$prepend_style .= 'font-size:' .
$this->_size_lookup[$attr['size']] . ';';

View File

@ -13,6 +13,7 @@ $pkg->setOptions(
'packagedirectory' => dirname(__FILE__) . '/library',
'filelistgenerator' => 'file',
'include' => array('*'),
'dir_roles' => array('/' => 'php'), // hack to put .ser in the right place
'ignore' => array('HTMLPurifier.auto.php'),
)
);
@ -27,17 +28,20 @@ $pkg->setDescription(
compliant.'
);
$pkg->addMaintainer('lead', 'edwardzyang', 'Edward Z. Yang', 'htmlpurifier@jpsband.org', 'yes');
$pkg->addMaintainer('lead', 'ezyang', 'Edward Z. Yang', 'admin@htmlpurifier.org', 'yes');
$pkg->setChannel('hp.jpsband.org');
$pkg->setAPIVersion('1.5');
$version = file_get_contents('VERSION');
$api_version = substr($version, 0, strrpos($version, '.'));
$pkg->setChannel('htmlpurifier.org');
$pkg->setAPIVersion($api_version);
$pkg->setAPIStability('stable');
$pkg->setReleaseVersion('1.5.0');
$pkg->setReleaseVersion($version);
$pkg->setReleaseStability('stable');
$pkg->addRelease();
$pkg->setNotes('Major bugs were fixed and some major internal refactoring was undertaken. The visible changes include XHTML 1.1-style modularization of HTMLDefinition, rudimentary internationalization, and a fix for a fatal error when the PHP4 DOM XML extension was loaded. The x subtag is now allowed in language codes. Element by element AllowedAttribute declaration is now possible for global attributes. Instead of *.class, you can write span.class. The old syntax still works, and enables the attribute for all elements.');
$pkg->setNotes(file_get_contents('WHATSNEW'));
$pkg->setPackageType('php');
$pkg->setPhpDep('4.3.9');

82
release.php Normal file
View File

@ -0,0 +1,82 @@
<?php
// release script
// PHP 5.0 only
if (php_sapi_name() != 'cli') {
echo 'Release script cannot be called from web-browser.';
exit;
}
if (!isset($argv[1])) {
echo
'php release.php [version]
HTML Purifier release script
';
exit;
}
$version = trim($argv[1]);
// Bump version numbers:
// ...in VERSION
file_put_contents('VERSION', $version);
// ...in NEWS
$date = date('Y-m-d');
$news_c = str_replace(
$l = "$version, unknown release date",
"$version, released $date",
file_get_contents('NEWS'),
$c
);
if (!$c) {
echo 'Could not update NEWS, missing ' . $l . PHP_EOL;
exit;
} elseif ($c > 1) {
echo 'More than one release declaration in NEWS replaced' . PHP_EOL;
exit;
}
file_put_contents('NEWS', $news_c);
// ...in Doxyfile
$doxyfile_c = preg_replace(
'/(?<=PROJECT_NUMBER {9}= )[^\s]+/m', // brittle
$version,
file_get_contents('Doxyfile'),
1, $c
);
if (!$c) {
echo 'Could not update Doxyfile, missing PROJECT_NUMBER.' . PHP_EOL;
exit;
}
file_put_contents('Doxyfile', $doxyfile_c);
// ...in HTMLPurifier.php
$htmlpurifier_c = file_get_contents('library/HTMLPurifier.php');
$htmlpurifier_c = preg_replace(
'/HTML Purifier .+? - /',
"HTML Purifier $version - ",
$htmlpurifier_c,
1, $c
);
if (!$c) {
echo 'Could not update HTMLPurifier.php, missing HTML Purifier [version] header.' . PHP_EOL;
exit;
}
$htmlpurifier_c = preg_replace(
'/var \$version = \'.+?\';/',
"var \$version = '$version';",
$htmlpurifier_c,
1, $c
);
if (!$c) {
echo 'Could not update HTMLPurifier.php, missing var $version.' . PHP_EOL;
exit;
}
file_put_contents('library/HTMLPurifier.php', $htmlpurifier_c);
echo "Review changes, write something in WHATSNEW, and then SVN commit with log 'Release $version.'" . PHP_EOL;
?>

View File

@ -0,0 +1,68 @@
<?php
require 'common.php';
?><!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>HTML Purifier Attribute Transformation Smoketest</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
div.container {position:relative;height:120px;border:1px solid #CCC;
margin-bottom:1em; width:225px; float:left; margin-top:1em;
margin-right:1em;}
h2 {clear:left;margin-bottom:0;}
div.container.legend .test {text-align:center;line-height:100px;}
div.test {width:100px;height:100px;border:1px solid black;
position:absolute;top:10px;overflow:auto;}
div.test.html {left:10px;border-right:none;background:#FCC;}
div.test.css {left:110px;background:#CFC;}
img.marked {border:1px solid #000;background:#FFF;}
table.bright {background-color:#F00;}
hr.short {width:50px;}
</style>
</head>
<body>
<h1>HTML Purifier Attribute Transformation Smoketest</h1>
<div class="container legend">
<div class="test html">
HTML
</div>
<div class="test css">
CSS
</div>
</div>
<?php
if (version_compare(PHP_VERSION, '5', '<')) exit('<p>Requires PHP 5.</p>');
$xml = simplexml_load_file('attrTransform.xml');
// attr transform enabled HTML Purifier
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
$title = isset($_GET['title']) ? $_GET['title'] : true;
foreach ($xml->group as $group) {
echo '<h2>' . $group['title'] . '</h2>';
foreach ($group->sample as $sample) {
$sample = (string) $sample;
?>
<div class="container">
<div class="test html">
<?php echo $sample; ?>
</div>
<div class="test css">
<?php echo $purifier->purify($sample); ?>
</div>
</div>
<?php
}
}
?>
</body>
</html>

View File

@ -0,0 +1,189 @@
<?xml version="1.0"?>
<samples>
<group title="menu,dir">
<sample><![CDATA[<menu><li>menu</li></menu>]]></sample>
<sample><![CDATA[<dir><li>dir</li></dir>]]></sample>
</group>
<group title="font">
<sample><![CDATA[<font color="red">Red</font>]]></sample>
<sample><![CDATA[<font color="#0000FF">#0000FF</font>]]></sample>
<sample><![CDATA[<font face="Arial">Arial</font>]]></sample>
</group>
<group title="font.size">
<sample><![CDATA[<font size="-2">-2</font>]]></sample>
<sample><![CDATA[<font size="-1">-1</font>]]></sample>
<sample><![CDATA[<font size="0">0</font>]]></sample>
<sample><![CDATA[<font size="1">1</font>]]></sample>
<sample><![CDATA[<font size="2">2</font>]]></sample>
<sample><![CDATA[<font size="3">3</font>]]></sample>
<sample><![CDATA[<font size="4">4</font>]]></sample>
<sample><![CDATA[<font size="5">5</font>]]></sample>
<sample><![CDATA[<font size="6">6</font>]]></sample>
<sample><![CDATA[<font size="7">7</font>]]></sample>
<sample><![CDATA[<font size="8">8</font>]]></sample>
<sample><![CDATA[<font size="+1">+1</font>]]></sample>
<sample><![CDATA[<font size="+2">+2</font>]]></sample>
<sample><![CDATA[<font size="+3">+3</font>]]></sample>
<sample><![CDATA[<font size="+4">+4</font>]]></sample>
<sample><![CDATA[<font size="+5">+5</font>]]></sample>
</group>
<group title="center">
<sample><![CDATA[<center>Centered</center>]]></sample>
</group>
<group title="p.align">
<sample><![CDATA[<p align="left">Left</p>]]></sample>
<sample><![CDATA[<p align="center">Center</p>]]></sample>
<sample><![CDATA[<p align="right">Right</p>]]></sample>
</group>
<group title="table.bgcolor">
<sample><![CDATA[
<table bgcolor="black" cellspacing="2" cellpadding="2" border="1">
<tr bgcolor="red">
<th bgcolor="green">To</th>
<td bgcolor="blue">Be</td>
</tr>
<tr>
<th bgcolor="green">Or</th>
<td>Not</td>
</tr>
<tr bgcolor="red">
<th>To</th>
<td>Be</td>
</tr>
</table>
]]></sample>
<sample><![CDATA[
<table class="bright" bgcolor="black" cellspacing="2" cellpadding="2" border="1">
<tr>
<th bgcolor="green">Or</th>
<td>Not</td>
</tr>
<tr bgcolor="blue">
<th bgcolor="green">To</th>
<td>Be</td>
</tr>
</table>
]]></sample>
</group>
<group title="img.border">
<sample><![CDATA[<img src="img.png" alt="I" border="2" />]]></sample>
<sample><![CDATA[<a href="http://example.com/"><img src="img.png" alt="I" border="2" /></a>]]></sample>
</group>
<group title="td,th,hr.width">
<sample><![CDATA[
<table border="1">
<tr>
<th width="20">x1</th>
<td width="40">x2</td>
</tr>
</table>
]]></sample>
<sample><![CDATA[
<table border="1">
<tr>
<th width="33%">x1</th>
<td width="67%">x2</td>
</tr>
</table>
]]></sample>
<sample><![CDATA[<hr width="70%" /><hr width="30" />]]></sample>
</group>
<group title="td,th.nowrap">
<sample><![CDATA[
<table border="1">
<tr>
<th>This wants to wrap</th>
<td>really badly yes it does</td>
</tr>
</table>
]]></sample>
<sample><![CDATA[
<table border="1">
<tr>
<th nowrap>This wants to wrap</th>
<td nowrap>really badly yes it does</td>
</tr>
</table>
]]></sample>
</group>
<group title="td,th.height">
<sample><![CDATA[<table border="1"><tr><td height="60">tall</td></tr></table>]]></sample>
</group>
<group title="img.vspace,hspace">
<sample><![CDATA[a<img src="img.png" alt="I" class="marked" hspace="7" />a]]></sample>
<sample><![CDATA[<img src="img.png" alt="I" class="marked" vspace="7" /><br />o]]></sample>
</group>
<group title="hr">
<sample><![CDATA[<hr size="4" />]]></sample>
<sample><![CDATA[<hr size="50" noshade />]]></sample>
</group>
<group title="br.clear">
<sample><![CDATA[<img src="img.png" alt="I" align="right" />B<br />A]]></sample>
<sample><![CDATA[<img src="img.png" alt="I" align="right" />B<br clear="right" />A]]></sample>
<sample><![CDATA[<img src="img.png" alt="I" align="right" /><img src="img.png" alt="I" align="left" />B<br />A]]></sample>
<sample><![CDATA[<img src="img.png" alt="I" align="right" /><img src="img.png" alt="I" align="left" />B<br clear="all" />A]]></sample>
</group>
<group title="caption.align">
<sample><![CDATA[
<table border="1">
<caption align="left">Left</caption>
<tr><td>1.1</td><td>1.2</td></tr>
</table>
]]></sample>
<sample><![CDATA[
<table border="1">
<caption align="right">Right</caption>
<tr><td>1.1</td><td>1.2</td></tr>
</table>
]]></sample>
<sample><![CDATA[
<table border="1">
<caption align="top">Top</caption>
<tr><td>1.1</td><td>1.2</td></tr>
</table>
]]></sample>
<sample><![CDATA[
<table border="1">
<caption align="bottom">Bottom</caption>
<tr><td>1.1</td><td>1.2</td></tr>
</table>
]]></sample>
</group>
<group title="img.align">
<sample><![CDATA[left<img src="img.png" alt="I" class="marked" align="left" />]]></sample>
<sample><![CDATA[right<img src="img.png" alt="I" class="marked" align="right" />]]></sample>
<sample><![CDATA[o<img src="img.png" alt="I" class="marked" align="top" /> top]]></sample>
<sample><![CDATA[o<img src="img.png" alt="I" class="marked" align="bottom" /> bottom]]></sample>
<sample><![CDATA[o<img src="img.png" alt="I" class="marked" align="middle" /> middle]]></sample>
</group>
<group title="table.align">
<sample><![CDATA[a<table align="left" class="bright"><tr><td>left</td></tr></table>a]]></sample>
<sample><![CDATA[a<table align="center" class="bright"><tr><td>center</td></tr></table>a]]></sample>
<sample><![CDATA[a<table align="right" class="bright"><tr><td>right</td></tr></table>a]]></sample>
</group>
<group title="hr.align">
<sample><![CDATA[<hr align="left" class="short" />left]]></sample>
<sample><![CDATA[<hr align="center" class="short" />center]]></sample>
<sample><![CDATA[<hr align="right" class="short" />right]]></sample>
</group>
<group title="ul,ol,li.type">
<sample><![CDATA[<ul type="disc"><li>1</li><li>2</li></ul>]]></sample>
<sample><![CDATA[<ul type="square"><li>1</li><li>2</li></ul>]]></sample>
<sample><![CDATA[<ul type="circle"><li>1</li><li>2</li></ul>]]></sample>
<sample><![CDATA[<ol type="a"><li>1</li><li>2</li></ul>]]></sample>
<sample><![CDATA[<ol type="A"><li>1</li><li>2</li></ul>]]></sample>
<sample><![CDATA[<ol type="i"><li>1</li><li>2</li></ul>]]></sample>
<sample><![CDATA[<ol type="I"><li>1</li><li>2</li></ul>]]></sample>
<sample><![CDATA[<ol type="1"><li>1</li><li>2</li></ul>]]></sample>
<sample><![CDATA[<ol><li type="a">1</li><li type="I">2</li></ul>]]></sample>
</group>
<!-- sample
<group title="">
<sample><![CDATA[]]></sample>
<sample><![CDATA[]]></sample>
<sample><![CDATA[]]></sample>
</group>
-->
</samples>

BIN
smoketests/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -105,7 +105,7 @@ transformation into a real array list or a lookup table).</p>
?>
<tr>
<th>
<a href="http://hp.jpsband.org/live/configdoc/plain.html#<?php echo $directive ?>">
<a href="http://htmlpurifier.org/live/configdoc/plain.html#<?php echo $directive ?>">
<label for="<?php echo $directive; ?>">%<?php echo $directive; ?></label>
</a>
</th>

View File

@ -0,0 +1,31 @@
<?php
require_once 'HTMLPurifier/AttrDefHarness.php';
require_once 'HTMLPurifier/AttrDef/HTML/FrameTarget.php';
class HTMLPurifier_AttrDef_HTML_FrameTargetTest extends HTMLPurifier_AttrDefHarness
{
function setup() {
parent::setup();
$this->def = new HTMLPurifier_AttrDef_HTML_FrameTarget();
}
function testNoneAllowed() {
$this->assertDef('', false);
$this->assertDef('foo', false);
$this->assertDef('_blank', false);
$this->assertDef('baz', false);
}
function test() {
$this->config->set('Attr', 'AllowedFrameTargets', 'foo,_blank');
$this->assertDef('', false);
$this->assertDef('foo');
$this->assertDef('_blank');
$this->assertDef('baz', false);
}
}
?>

View File

@ -9,11 +9,11 @@ class HTMLPurifier_AttrDefTest extends UnitTestCase
$def = new HTMLPurifier_AttrDef();
$this->assertEqual('', $def->parseCDATA(''));
$this->assertEqual('', $def->parseCDATA("\t\n\r \t\t"));
$this->assertEqual('foo', $def->parseCDATA("\t\n\r foo\t\t"));
$this->assertEqual('ignorelinefeeds', $def->parseCDATA("ignore\nline\nfeeds"));
$this->assertEqual('translate to space', $def->parseCDATA("translate\rto\tspace"));
$this->assertIdentical('', $def->parseCDATA(''));
$this->assertIdentical('', $def->parseCDATA("\t\n\r \t\t"));
$this->assertIdentical('foo', $def->parseCDATA("\t\n\r foo\t\t"));
$this->assertIdentical('ignorelinefeeds', $def->parseCDATA("ignore\nline\nfeeds"));
$this->assertIdentical('translate to space', $def->parseCDATA("translate\rto\tspace"));
}

View File

@ -0,0 +1,39 @@
<?php
require_once 'HTMLPurifier/AttrTransform/BoolToCSS.php';
require_once 'HTMLPurifier/AttrTransformHarness.php';
class HTMLPurifier_AttrTransform_BoolToCSSTest extends HTMLPurifier_AttrTransformHarness
{
function setUp() {
parent::setUp();
$this->obj = new HTMLPurifier_AttrTransform_BoolToCSS('foo', 'bar:3in;');
}
function test() {
$this->assertResult( array() );
$this->assertResult(
array('foo' => 'foo'),
array('style' => 'bar:3in;')
);
// boolean attribute just has to be set: we don't care about
// anything else
$this->assertResult(
array('foo' => 'no'),
array('style' => 'bar:3in;')
);
$this->assertResult(
array('foo' => 'foo', 'style' => 'background-color:#F00;'),
array('style' => 'bar:3in;background-color:#F00;')
);
}
}
?>

View File

@ -1,17 +1,17 @@
<?php
require_once 'HTMLPurifier/AttrTransform/TextAlign.php';
require_once 'HTMLPurifier/AttrTransform/EnumToCSS.php';
require_once 'HTMLPurifier/AttrTransformHarness.php';
class HTMLPurifier_AttrTransform_TextAlignTest extends HTMLPurifier_AttrTransformHarness
class HTMLPurifier_AttrTransform_EnumToCSSTest extends HTMLPurifier_AttrTransformHarness
{
function setUp() {
parent::setUp();
$this->obj = new HTMLPurifier_AttrTransform_TextAlign();
}
function test() {
function testRegular() {
$this->obj = new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
'left' => 'text-align:left;',
'right' => 'text-align:right;'
));
// leave empty arrays alone
$this->assertResult( array() );
@ -31,16 +31,6 @@ class HTMLPurifier_AttrTransform_TextAlignTest extends HTMLPurifier_AttrTransfor
array('style' => 'text-align:right;')
);
$this->assertResult(
array('align' => 'center'),
array('style' => 'text-align:center;')
);
$this->assertResult(
array('align' => 'justify'),
array('style' => 'text-align:justify;')
);
// drop garbage value
$this->assertResult(
array('align' => 'invalid'),
@ -53,10 +43,32 @@ class HTMLPurifier_AttrTransform_TextAlignTest extends HTMLPurifier_AttrTransfor
array('style' => 'text-align:left;font-weight:bold;')
);
}
function testCaseInsensitive() {
$this->obj = new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
'right' => 'text-align:right;'
));
// test case insensitivity
$this->assertResult(
array('align' => 'CENTER'),
array('style' => 'text-align:center;')
array('align' => 'RIGHT'),
array('style' => 'text-align:right;')
);
}
function testCaseSensitive() {
$this->obj = new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
'right' => 'text-align:right;'
), true);
// test case insensitivity
$this->assertResult(
array('align' => 'RIGHT'),
array()
);
}

View File

@ -34,7 +34,7 @@ class HTMLPurifier_AttrTransform_ImgRequiredTest extends HTMLPurifier_AttrTransf
$this->assertResult(
array('alt' => 'intrigue'),
array('src' => '', 'alt' => 'intrigue')
array('alt' => 'intrigue', 'src' => '')
);
}

View File

@ -0,0 +1,57 @@
<?php
require_once 'HTMLPurifier/AttrTransform/ImgSpace.php';
require_once 'HTMLPurifier/AttrTransformHarness.php';
class HTMLPurifier_AttrTransform_ImgSpaceTest extends HTMLPurifier_AttrTransformHarness
{
function setUp() {
parent::setUp();
}
function testVertical() {
$this->obj = new HTMLPurifier_AttrTransform_ImgSpace('vspace');
$this->assertResult( array() );
$this->assertResult(
array('vspace' => '1'),
array('style' => 'margin-top:1px;margin-bottom:1px;')
);
// no validation done here, we expect CSS validator to catch it
$this->assertResult(
array('vspace' => '10%'),
array('style' => 'margin-top:10%px;margin-bottom:10%px;')
);
$this->assertResult(
array('vspace' => '23', 'style' => 'font-weight:bold;'),
array('style' => 'margin-top:23px;margin-bottom:23px;font-weight:bold;')
);
}
function testHorizontal() {
$this->obj = new HTMLPurifier_AttrTransform_ImgSpace('hspace');
$this->assertResult(
array('hspace' => '1'),
array('style' => 'margin-left:1px;margin-right:1px;')
);
}
function testInvalid() {
$this->expectError('ispace is not valid space attribute');
$this->obj = new HTMLPurifier_AttrTransform_ImgSpace('ispace');
$this->assertResult(
array('ispace' => '1'),
array()
);
}
}
?>

View File

@ -33,7 +33,7 @@ class HTMLPurifier_AttrTransform_LangTest
// copy xml:lang to lang
$this->assertResult(
array('xml:lang' => 'en'),
array('lang' => 'en', 'xml:lang' => 'en')
array('xml:lang' => 'en', 'lang' => 'en')
);
// both set, override lang with xml:lang

View File

@ -0,0 +1,42 @@
<?php
require_once 'HTMLPurifier/AttrTransform.php';
class HTMLPurifier_AttrTransformTest extends UnitTestCase
{
function test_prependCSS() {
$t = new HTMLPurifier_AttrTransform();
$attr = array();
$t->prependCSS($attr, 'style:new;');
$this->assertIdentical(array('style' => 'style:new;'), $attr);
$attr = array('style' => 'style:original;');
$t->prependCSS($attr, 'style:new;');
$this->assertIdentical(array('style' => 'style:new;style:original;'), $attr);
$attr = array('style' => 'style:original;', 'misc' => 'un-related');
$t->prependCSS($attr, 'style:new;');
$this->assertIdentical(array('style' => 'style:new;style:original;', 'misc' => 'un-related'), $attr);
}
function test_confiscateAttr() {
$t = new HTMLPurifier_AttrTransform();
$attr = array('flavor' => 'sweet');
$this->assertIdentical('sweet', $t->confiscateAttr($attr, 'flavor'));
$this->assertIdentical(array(), $attr);
$attr = array('flavor' => 'sweet');
$this->assertIdentical(null, $t->confiscateAttr($attr, 'color'));
$this->assertIdentical(array('flavor' => 'sweet'), $attr);
}
}
?>

View File

@ -9,7 +9,7 @@ class HTMLPurifier_ChildDef_RequiredTest extends HTMLPurifier_ChildDefHarness
function testParsing() {
$def = new HTMLPurifier_ChildDef_Required('foobar | bang |gizmo');
$this->assertEqual($def->elements,
$this->assertIdentical($def->elements,
array(
'foobar' => true
,'bang' => true
@ -17,7 +17,7 @@ class HTMLPurifier_ChildDef_RequiredTest extends HTMLPurifier_ChildDefHarness
));
$def = new HTMLPurifier_ChildDef_Required(array('href', 'src'));
$this->assertEqual($def->elements,
$this->assertIdentical($def->elements,
array(
'href' => true
,'src' => true

View File

@ -277,14 +277,17 @@ class HTMLPurifier_ConfigSchemaTest extends UnitTestCase
$this->assertValid(array('1', '2', '3'), 'list');
$this->assertValid('foo,bar, cow', 'list', array('foo', 'bar', 'cow'));
$this->assertValid('', 'list', array());
$this->assertValid(array('1' => true, '2' => true), 'lookup');
$this->assertValid(array('1', '2'), 'lookup', array('1' => true, '2' => true));
$this->assertValid('foo,bar', 'lookup', array('foo' => true, 'bar' => true));
$this->assertValid('', 'lookup', array());
$this->assertValid(array('foo' => 'bar'), 'hash');
$this->assertValid(array(1 => 'moo'), 'hash');
$this->assertInvalid(array(0 => 'moo'), 'hash');
$this->assertValid('', 'hash', array());
$this->assertValid(23, 'mixed');

View File

@ -164,13 +164,13 @@ class HTMLPurifier_ConfigTest extends UnitTestCase
$config = HTMLPurifier_Config::createDefault();
$this->assertEqual($config->get('Home', 'Rug'), 3);
$this->assertIdentical($config->get('Home', 'Rug'), 3);
$this->expectError('Cannot get value from aliased directive, use real name');
$config->get('Home', 'Carpet');
$config->set('Home', 'Carpet', 999);
$this->assertEqual($config->get('Home', 'Rug'), 999);
$this->assertIdentical($config->get('Home', 'Rug'), 999);
}
@ -231,7 +231,7 @@ class HTMLPurifier_ConfigTest extends UnitTestCase
$def = $config->getHTMLDefinition();
$def2 = $config->getHTMLDefinition();
$this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
$this->assertEqual($def, $def2);
$this->assertIdentical($def, $def2);
$this->assertTrue($def->setup);
// test re-calculation if HTML changes
@ -298,8 +298,8 @@ class HTMLPurifier_ConfigTest extends UnitTestCase
)
));
$this->assertEqual($config_manual, $config_loadabbr);
$this->assertEqual($config_manual, $config_loadfull);
$this->assertIdentical($config_manual, $config_loadabbr);
$this->assertIdentical($config_manual, $config_loadfull);
}
@ -314,15 +314,15 @@ class HTMLPurifier_ConfigTest extends UnitTestCase
// test flat pass-through
$created_config = HTMLPurifier_Config::create($config);
$this->assertEqual($config, $created_config);
$this->assertIdentical($config, $created_config);
// test loadArray
$created_config = HTMLPurifier_Config::create(array('Cake.Sprinkles' => 42));
$this->assertEqual($config, $created_config);
$this->assertIdentical($config, $created_config);
// test loadIni
$created_config = HTMLPurifier_Config::create(dirname(__FILE__) . '/ConfigTest-create.ini');
$this->assertEqual($config, $created_config);
$this->assertIdentical($config, $created_config);
}

View File

@ -61,7 +61,7 @@ class HTMLPurifier_GeneratorTest extends HTMLPurifier_Harness
foreach ($inputs as $i => $input) {
$result = $this->obj->generateFromToken($input);
$this->assertEqual($result, $expect[$i]);
$this->assertIdentical($result, $expect[$i]);
paintIf($result, $result != $expect[$i]);
}
@ -90,7 +90,7 @@ class HTMLPurifier_GeneratorTest extends HTMLPurifier_Harness
foreach ($inputs as $i => $input) {
$result = $this->obj->generateAttributes($input);
$this->assertEqual($result, $expect[$i]);
$this->assertIdentical($result, $expect[$i]);
paintIf($result, $result != $expect[$i]);
}
@ -121,7 +121,7 @@ class HTMLPurifier_GeneratorTest extends HTMLPurifier_Harness
// normalized newlines, this probably should be put somewhere else
$result = str_replace("\r\n", "\n", $result);
$result = str_replace("\r", "\n", $result);
$this->assertEqual($expect, $result);
$this->assertIdentical($expect, $result);
}
function test_generateFromTokens_XHTMLoff() {

View File

@ -48,15 +48,15 @@ class HTMLPurifier_HTMLModuleManagerTest extends UnitTestCase
$this->manager->addModule($module);
$module_order = $this->manager->modules['Module']->order;
$module->order = $module_order;
$this->assertEqual($module, $this->manager->modules['Module']);
$this->assertIdentical($module, $this->manager->modules['Module']);
$this->manager->addModule($module2);
$module2_order = $this->manager->modules['Module2']->order;
$module2->order = $module2_order;
$this->assertEqual($module2, $this->manager->modules['Module2']);
$this->assertEqual($module_order + 1, $module2_order);
$this->assertIdentical($module2, $this->manager->modules['Module2']);
$this->assertIdentical($module_order + 1, $module2_order);
$this->assertEqual(
$this->assertIdentical(
$this->manager->collections['Default']['Generic Document 0.1'],
array('Module', 'Module2')
);

View File

@ -97,7 +97,7 @@ class HTMLPurifier_Harness extends UnitTestCase
}
}
$this->assertEqual($expect, $result);
$this->assertIdentical($expect, $result);
}

View File

@ -12,10 +12,10 @@ class HTMLPurifier_LanguageFactoryTest extends UnitTestCase
$language = $factory->create('en');
$this->assertIsA($language, 'HTMLPurifier_Language');
$this->assertEqual($language->code, 'en');
$this->assertIdentical($language->code, 'en');
// lazy loading test
$this->assertEqual(count($language->messages), 0);
$this->assertIdentical(count($language->messages), 0);
$language->load();
$this->assertNotEqual(count($language->messages), 0);
@ -30,15 +30,15 @@ class HTMLPurifier_LanguageFactoryTest extends UnitTestCase
$language = $factory->create('en-x-test');
$this->assertIsA($language, 'HTMLPurifier_Language_en_x_test');
$this->assertEqual($language->code, 'en-x-test');
$this->assertIdentical($language->code, 'en-x-test');
$language->load();
// test overloaded message
$this->assertEqual($language->getMessage('htmlpurifier'), 'HTML Purifier X');
$this->assertIdentical($language->getMessage('htmlpurifier'), 'HTML Purifier X');
// test inherited message
$this->assertEqual($language->getMessage('pizza'), 'Pizza');
$this->assertIdentical($language->getMessage('pizza'), 'Pizza');
}

View File

@ -58,7 +58,7 @@ class HTMLPurifier_Lexer_DirectLexTest extends UnitTestCase
$size = count($input);
for($i = 0; $i < $size; $i++) {
$result = $this->DirectLex->parseAttributeString($input[$i], $config, $context);
$this->assertEqual($expect[$i], $result, 'Test ' . $i . ': %s');
$this->assertIdentical($expect[$i], $result, 'Test ' . $i . ': %s');
paintIf($result, $expect[$i] != $result);
}

View File

@ -280,13 +280,25 @@ class HTMLPurifier_LexerTest extends UnitTestCase
$input[18] = '<br test="x &lt; 6" />';
$expect[18] = array( new HTMLPurifier_Token_Empty('br', array('test' => 'x < 6')) );
// test emoticon protection
$input[19] = '<b>Whoa! >.< That\'s not good >.></b>';
$expect[19] = array(
new HTMLPurifier_Token_Start('b'),
new HTMLPurifier_Token_Text('Whoa! >.'),
new HTMLPurifier_Token_Text('< That\'s not good >'),
new HTMLPurifier_Token_Text('.>'),
new HTMLPurifier_Token_End('b'),
);
$sax_expect[19] = false; // SAX drops the < character
$dom_expect[19] = false; // DOM drops the entire pseudo-tag
$default_config = HTMLPurifier_Config::createDefault();
$default_context = new HTMLPurifier_Context();
foreach($input as $i => $discard) {
if (!isset($config[$i])) $config[$i] = $default_config;
$result = $this->DirectLex->tokenizeHTML($input[$i], $config[$i], $default_context);
$this->assertEqual($expect[$i], $result, 'DirectLexTest '.$i.': %s');
$this->assertIdentical($expect[$i], $result, 'DirectLexTest '.$i.': %s');
paintIf($result, $expect[$i] != $result);
if ($this->_has_pear) {
@ -294,14 +306,14 @@ class HTMLPurifier_LexerTest extends UnitTestCase
$sax_result = $this->PEARSax3->tokenizeHTML($input[$i], $config[$i], $default_context);
if (!isset($sax_expect[$i])) {
// by default, assert with normal result
$this->assertEqual($expect[$i], $sax_result, 'PEARSax3Test '.$i.': %s');
$this->assertIdentical($expect[$i], $sax_result, 'PEARSax3Test '.$i.': %s');
paintIf($sax_result, $expect[$i] != $sax_result);
} elseif ($sax_expect[$i] === false) {
// assertions were turned off, optionally dump
// paintIf($sax_expect, $i == NUMBER);
} else {
// match with a custom SAX result array
$this->assertEqual($sax_expect[$i], $sax_result, 'PEARSax3Test (custom) '.$i.': %s');
$this->assertIdentical($sax_expect[$i], $sax_result, 'PEARSax3Test (custom) '.$i.': %s');
paintIf($sax_result, $sax_expect[$i] != $sax_result);
}
}
@ -310,12 +322,12 @@ class HTMLPurifier_LexerTest extends UnitTestCase
$dom_result = $this->DOMLex->tokenizeHTML($input[$i], $config[$i], $default_context);
// same structure as SAX
if (!isset($dom_expect[$i])) {
$this->assertEqual($expect[$i], $dom_result, 'DOMLexTest '.$i.': %s');
$this->assertIdentical($expect[$i], $dom_result, 'DOMLexTest '.$i.': %s');
paintIf($dom_result, $expect[$i] != $dom_result);
} elseif ($dom_expect[$i] === false) {
// paintIf($dom_result, $i == NUMBER);
} else {
$this->assertEqual($dom_expect[$i], $dom_result, 'DOMLexTest (custom) '.$i.': %s');
$this->assertIdentical($dom_expect[$i], $dom_result, 'DOMLexTest (custom) '.$i.': %s');
paintIf($dom_result, $dom_expect[$i] != $dom_result);
}
}

View File

@ -15,7 +15,7 @@ class HTMLPurifier_PercentEncoderTest extends UnitTestCase
function assertDecode($string, $expect = true) {
if ($expect === true) $expect = $string;
$this->assertEqual($this->PercentEncoder->{$this->func}($string), $expect);
$this->assertIdentical($this->PercentEncoder->{$this->func}($string), $expect);
}
function test_normalize() {

View File

@ -51,6 +51,15 @@ class HTMLPurifier_Strategy_RemoveForeignElementsTest
// test preservation of valid img tag
$this->assertResult('<img src="foobar.gif" />');
// test preservation of invalid img tag when removal is disabled
$this->assertResult(
'<img />',
true,
array(
'Core.RemoveInvalidImg' => false
)
);
}
}

View File

@ -13,14 +13,11 @@ class HTMLPurifier_Strategy_ValidateAttributesTest extends
$this->obj = new HTMLPurifier_Strategy_ValidateAttributes();
}
function test() {
// attribute order is VERY fragile, perhaps we should define
// an ordering scheme!
function testEmpty() {
$this->assertResult('');
// test ids
}
function testIDs() {
$this->assertResult(
'<div id="valid">Kill the ID.</div>',
'<div>Kill the ID.</div>'
@ -71,32 +68,68 @@ class HTMLPurifier_Strategy_ValidateAttributesTest extends
)
);
// test classes
// name rewritten as id
$this->assertResult(
'<a name="foobar" />',
'<a id="foobar" />',
array('HTML.EnableAttrID' => true)
);
}
function testClasses() {
$this->assertResult('<div class="valid">Valid</div>');
$this->assertResult(
'<div class="valid 0invalid">Keep valid.</div>',
'<div class="valid">Keep valid.</div>'
);
// test title
}
function testTitle() {
$this->assertResult(
'<acronym title="PHP: Hypertext Preprocessor">PHP</acronym>'
);
// test lang
}
function testLang() {
$this->assertResult(
'<span lang="fr">La soupe.</span>',
'<span lang="fr" xml:lang="fr">La soupe.</span>'
);
// test align
// test only xml:lang for XHTML 1.1
$this->assertResult(
'<b lang="en">asdf</b>',
'<b xml:lang="en">asdf</b>', array('HTML.Doctype' => 'XHTML 1.1')
);
}
function testAlign() {
$this->assertResult(
'<h1 align="center">Centered Headline</h1>',
'<h1 style="text-align:center;">Centered Headline</h1>'
);
$this->assertResult(
'<h1 align="right">Right-aligned Headline</h1>',
'<h1 style="text-align:right;">Right-aligned Headline</h1>'
);
$this->assertResult(
'<h1 align="left">Left-aligned Headline</h1>',
'<h1 style="text-align:left;">Left-aligned Headline</h1>'
);
$this->assertResult(
'<p align="justify">Justified Paragraph</p>',
'<p style="text-align:justify;">Justified Paragraph</p>'
);
$this->assertResult(
'<h1 align="invalid">Invalid Headline</h1>',
'<h1>Invalid Headline</h1>'
);
// test table
}
function testTable() {
$this->assertResult(
'<table frame="above" rules="rows" summary="A test table" border="2" cellpadding="5%" cellspacing="3" width="100%">
<col align="right" width="4*" />
@ -115,7 +148,64 @@ class HTMLPurifier_Strategy_ValidateAttributesTest extends
</table>'
);
// test URI
// test col.span is non-zero
$this->assertResult(
'<col span="0" />',
'<col />'
);
// lengths
$this->assertResult(
'<td height="10" width="5%" /><th height="5%" width="10" /><hr width="10" height="10" />',
'<td style="height:10px;width:5%;" /><th style="height:5%;width:10px;" /><hr style="width:10px;" />'
);
// td boolean transformation
$this->assertResult(
'<td nowrap />',
'<td style="white-space:nowrap;" />'
);
// caption align transformation
$this->assertResult(
'<caption align="left" />',
'<caption style="text-align:left;" />'
);
$this->assertResult(
'<caption align="right" />',
'<caption style="text-align:right;" />'
);
$this->assertResult(
'<caption align="top" />',
'<caption style="caption-side:top;" />'
);
$this->assertResult(
'<caption align="bottom" />',
'<caption style="caption-side:bottom;" />'
);
$this->assertResult(
'<caption align="nonsense" />',
'<caption />'
);
// align transformation
$this->assertResult(
'<table align="left" />',
'<table style="float:left;" />'
);
$this->assertResult(
'<table align="center" />',
'<table style="margin-left:auto;margin-right:auto;" />'
);
$this->assertResult(
'<table align="right" />',
'<table style="float:right;" />'
);
$this->assertResult(
'<table align="top" />',
'<table />'
);
}
function testURI() {
$this->assertResult('<a href="http://www.google.com/">Google</a>');
// test invalid URI
@ -123,9 +213,9 @@ class HTMLPurifier_Strategy_ValidateAttributesTest extends
'<a href="javascript:badstuff();">Google</a>',
'<a>Google</a>'
);
// test required attributes for img
}
function testImg() {
// (this should never happen, as RemoveForeignElements
// should have removed the offending image tag)
$this->assertResult(
@ -142,7 +232,40 @@ class HTMLPurifier_Strategy_ValidateAttributesTest extends
'<img alt="pretty picture" />',
'<img alt="pretty picture" src="" />'
);
// mailto in image is not allowed
$this->assertResult(
'<img src="mailto:foo@example.com" />',
'<img src="" alt="Invalid image" />'
);
// align transformation
$this->assertResult(
'<img src="foobar.jpg" alt="foobar" align="left" />',
'<img src="foobar.jpg" alt="foobar" style="float:left;" />'
);
$this->assertResult(
'<img src="foobar.jpg" alt="foobar" align="right" />',
'<img src="foobar.jpg" alt="foobar" style="float:right;" />'
);
$this->assertResult(
'<img src="foobar.jpg" alt="foobar" align="bottom" />',
'<img src="foobar.jpg" alt="foobar" style="vertical-align:baseline;" />'
);
$this->assertResult(
'<img src="foobar.jpg" alt="foobar" align="middle" />',
'<img src="foobar.jpg" alt="foobar" style="vertical-align:middle;" />'
);
$this->assertResult(
'<img src="foobar.jpg" alt="foobar" align="top" />',
'<img src="foobar.jpg" alt="foobar" style="vertical-align:top;" />'
);
$this->assertResult(
'<img src="foobar.jpg" alt="foobar" align="outerspace" />',
'<img src="foobar.jpg" alt="foobar" />'
);
}
function testBdo() {
// test required attributes for bdo
$this->assertResult(
'<bdo>Go left.</bdo>',
@ -153,44 +276,161 @@ class HTMLPurifier_Strategy_ValidateAttributesTest extends
'<bdo dir="blahblah">Invalid value!</bdo>',
'<bdo dir="ltr">Invalid value!</bdo>'
);
// see above, behavior is subtly different
}
function testDir() {
// see testBdo, behavior is subtly different
$this->assertResult(
'<span dir="blahblah">Invalid value!</span>',
'<span>Invalid value!</span>'
);
}
// test col.span is non-zero
$this->assertResult(
'<col span="0" />',
'<col />'
);
// mailto in image is not allowed
$this->assertResult(
'<img src="mailto:foo@example.com" />',
'<img src="" alt="Invalid image" />'
);
// name rewritten as id
$this->assertResult(
'<a name="foobar" />',
'<a id="foobar" />',
array('HTML.EnableAttrID' => true)
);
// lengths
$this->assertResult(
'<td height="10" width="5%" /><th height="5%" width="10" /><hr width="10" height="10" />',
'<td style="height:10px;width:5%;" /><th style="height:5%;width:10px;" /><hr style="width:10px;" />'
);
function testLinks() {
// link types
$this->assertResult(
'<a href="foo" rel="nofollow" />',
true,
array('Attr.AllowedRel' => 'nofollow')
);
// link targets
$this->assertResult(
'<a href="foo" target="_top" />',
true,
array('Attr.AllowedFrameTargets' => '_top')
);
$this->assertResult(
'<a href="foo" target="_top" />',
'<a href="foo" />'
);
$this->assertResult(
'<a href="foo" target="_top" />',
'<a href="foo" />',
array('Attr.AllowedFrameTargets' => '_top', 'HTML.Strict' => true)
);
}
function testBorder() {
// border
$this->assertResult(
'<img src="foo" alt="foo" hspace="1" vspace="3" />',
'<img src="foo" alt="foo" style="margin-top:3px;margin-bottom:3px;margin-left:1px;margin-right:1px;" />',
array('Attr.AllowedRel' => 'nofollow')
);
}
function testHr() {
$this->assertResult(
'<hr size="3" />',
'<hr style="height:3px;" />'
);
$this->assertResult(
'<hr noshade />',
'<hr style="color:#808080;background-color:#808080;border:0;" />'
);
// align transformation
$this->assertResult(
'<hr align="left" />',
'<hr style="margin-left:0;margin-right:auto;text-align:left;" />'
);
$this->assertResult(
'<hr align="center" />',
'<hr style="margin-left:auto;margin-right:auto;text-align:center;" />'
);
$this->assertResult(
'<hr align="right" />',
'<hr style="margin-left:auto;margin-right:0;text-align:right;" />'
);
$this->assertResult(
'<hr align="bottom" />',
'<hr />'
);
}
function testBr() {
// br clear transformation
$this->assertResult(
'<br clear="left" />',
'<br style="clear:left;" />'
);
$this->assertResult(
'<br clear="right" />',
'<br style="clear:right;" />'
);
$this->assertResult( // test both?
'<br clear="all" />',
'<br style="clear:both;" />'
);
$this->assertResult(
'<br clear="none" />',
'<br style="clear:none;" />'
);
$this->assertResult(
'<br clear="foo" />',
'<br />'
);
}
function testListTypeTransform() {
// ul
$this->assertResult(
'<ul type="disc" />',
'<ul style="list-style-type:disc;" />'
);
$this->assertResult(
'<ul type="square" />',
'<ul style="list-style-type:square;" />'
);
$this->assertResult(
'<ul type="circle" />',
'<ul style="list-style-type:circle;" />'
);
$this->assertResult( // case insensitive
'<ul type="CIRCLE" />',
'<ul style="list-style-type:circle;" />'
);
$this->assertResult(
'<ul type="a" />',
'<ul />'
);
// ol
$this->assertResult(
'<ol type="1" />',
'<ol style="list-style-type:decimal;" />'
);
$this->assertResult(
'<ol type="i" />',
'<ol style="list-style-type:lower-roman;" />'
);
$this->assertResult(
'<ol type="I" />',
'<ol style="list-style-type:upper-roman;" />'
);
$this->assertResult(
'<ol type="a" />',
'<ol style="list-style-type:lower-alpha;" />'
);
$this->assertResult(
'<ol type="A" />',
'<ol style="list-style-type:upper-alpha;" />'
);
$this->assertResult(
'<ol type="disc" />',
'<ol />'
);
// li
$this->assertResult(
'<li type="circle" />',
'<li style="list-style-type:circle;" />'
);
$this->assertResult(
'<li type="A" />',
'<li style="list-style-type:upper-alpha;" />'
);
$this->assertResult( // case sensitive
'<li type="CIRCLE" />',
'<li />'
);
}

View File

@ -49,14 +49,14 @@ class HTMLPurifier_TagTransformTest extends UnitTestCase
$context->loadArray($context_array);
// start tag transform
$this->assertEqual(
$this->assertIdentical(
new HTMLPurifier_Token_Start($expect_name, $expect_added_attributes),
$transformer->transform(
new HTMLPurifier_Token_Start($name), $config, $context)
);
// start tag transform with attributes
$this->assertEqual(
$this->assertIdentical(
new HTMLPurifier_Token_Start($expect_name, $expect_attributes),
$transformer->transform(
new HTMLPurifier_Token_Start($name, $attributes),
@ -65,7 +65,7 @@ class HTMLPurifier_TagTransformTest extends UnitTestCase
);
// end tag transform
$this->assertEqual(
$this->assertIdentical(
new HTMLPurifier_Token_End($expect_name),
$transformer->transform(
new HTMLPurifier_Token_End($name), $config, $context
@ -73,7 +73,7 @@ class HTMLPurifier_TagTransformTest extends UnitTestCase
);
// empty tag transform
$this->assertEqual(
$this->assertIdentical(
new HTMLPurifier_Token_Empty($expect_name, $expect_added_attributes),
$transformer->transform(
new HTMLPurifier_Token_Empty($name), $config, $context
@ -81,7 +81,7 @@ class HTMLPurifier_TagTransformTest extends UnitTestCase
);
// empty tag transform with attributes
$this->assertEqual(
$this->assertIdentical(
new HTMLPurifier_Token_Empty($expect_name, $expect_attributes),
$transformer->transform(
new HTMLPurifier_Token_Empty($name, $attributes),
@ -152,6 +152,7 @@ class HTMLPurifier_TagTransformTest extends UnitTestCase
);
// test the size transforms
$this->assertSizeToStyle($transformer, '0', 'xx-small');
$this->assertSizeToStyle($transformer, '1', 'xx-small');
$this->assertSizeToStyle($transformer, '2', 'small');
$this->assertSizeToStyle($transformer, '3', 'medium');
@ -160,10 +161,13 @@ class HTMLPurifier_TagTransformTest extends UnitTestCase
$this->assertSizeToStyle($transformer, '6', 'xx-large');
$this->assertSizeToStyle($transformer, '7', '300%');
$this->assertSizeToStyle($transformer, '-1', 'smaller');
$this->assertSizeToStyle($transformer, '+1', 'larger');
$this->assertSizeToStyle($transformer, '-2', '60%');
$this->assertSizeToStyle($transformer, '-3', '60%');
$this->assertSizeToStyle($transformer, '+1', 'larger');
$this->assertSizeToStyle($transformer, '+2', '150%');
$this->assertSizeToStyle($transformer, '+3', '200%');
$this->assertSizeToStyle($transformer, '+4', '300%');
$this->assertSizeToStyle($transformer, '+5', '300%');
// test multiple transforms, the alphabetical ordering is important
$this->assertTransformation(

View File

@ -72,7 +72,7 @@ class HTMLPurifier_Test extends UnitTestCase
$this->purifier = new HTMLPurifier();
$this->assertEqual(
$this->assertIdentical(
$this->purifier->purifyArray(
array('Good', '<b>Sketchy', 'foo' => '<script>bad</script>')
),

View File

@ -11,7 +11,7 @@ class HTMLPurifier_TokenFactoryTest extends UnitTestCase
$regular = new HTMLPurifier_Token_Start('a', array('href' => 'about:blank'));
$generated = $factory->createStart('a', array('href' => 'about:blank'));
$this->assertEqual($regular, $generated);
$this->assertIdentical($regular, $generated);
}
}

View File

@ -12,8 +12,8 @@ class HTMLPurifier_TokenTest extends UnitTestCase
if ($expect_attr === null) $expect_attr = $attr;
$token = new HTMLPurifier_Token_Start($name, $attr);
$this->assertEqual($expect_name, $token->name);
$this->assertEqual($expect_attr, $token->attr);
$this->assertIdentical($expect_name, $token->name);
$this->assertIdentical($expect_attr, $token->attr);
}
function testConstruct() {

View File

@ -21,6 +21,7 @@ $test_files[] = 'AttrDef/CSSTest.php';
$test_files[] = 'AttrDef/EnumTest.php';
$test_files[] = 'AttrDef/HTML/IDTest.php';
$test_files[] = 'AttrDef/HTML/LengthTest.php';
$test_files[] = 'AttrDef/HTML/FrameTargetTest.php';
$test_files[] = 'AttrDef/HTML/MultiLengthTest.php';
$test_files[] = 'AttrDef/HTML/NmtokensTest.php';
$test_files[] = 'AttrDef/HTML/PixelsTest.php';
@ -34,14 +35,17 @@ $test_files[] = 'AttrDef/URI/IPv4Test.php';
$test_files[] = 'AttrDef/URI/IPv6Test.php';
$test_files[] = 'AttrDef/URITest.php';
$test_files[] = 'AttrDefTest.php';
$test_files[] = 'AttrTransformTest.php';
$test_files[] = 'AttrTransform/BdoDirTest.php';
$test_files[] = 'AttrTransform/BgColorTest.php';
$test_files[] = 'AttrTransform/BoolToCSSTest.php';
$test_files[] = 'AttrTransform/BorderTest.php';
$test_files[] = 'AttrTransform/EnumToCSSTest.php';
$test_files[] = 'AttrTransform/ImgRequiredTest.php';
$test_files[] = 'AttrTransform/ImgSpaceTest.php';
$test_files[] = 'AttrTransform/LangTest.php';
$test_files[] = 'AttrTransform/LengthTest.php';
$test_files[] = 'AttrTransform/NameTest.php';
$test_files[] = 'AttrTransform/TextAlignTest.php';
$test_files[] = 'ChildDef/ChameleonTest.php';
$test_files[] = 'ChildDef/CustomTest.php';
$test_files[] = 'ChildDef/OptionalTest.php';