From b829e76bbf65edb8220bb03031ada1b2e6206c9b Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Mon, 2 Apr 2007 03:09:23 +0000 Subject: [PATCH] Release 1.6.0, merged in r875-930. git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/branches/strict@931 48356398-32a2-884e-a903-53898d9a118a --- Doxyfile | 2 +- INSTALL | 4 +- INSTALL.fr.utf8 | 71 +++ NEWS | 19 + TODO | 52 +- docs/dev-advanced-api.html | 261 ++++++---- docs/dev-progress.html | 28 +- docs/enduser-utf8.html | 6 +- library/HTMLPurifier.php | 4 +- library/HTMLPurifier/AttrDef/HTML/ID.php | 13 + library/HTMLPurifier/AttrDef/HTML/LinkTypes.php | 75 +++ library/HTMLPurifier/AttrTransform/BgColor.php | 28 ++ library/HTMLPurifier/AttrTransform/Border.php | 28 ++ library/HTMLPurifier/AttrTransform/Length.php | 33 ++ library/HTMLPurifier/AttrTransform/Name.php | 31 ++ library/HTMLPurifier/AttrTransform/TextAlign.php | 2 +- library/HTMLPurifier/CSSDefinition.php | 4 +- library/HTMLPurifier/HTMLDefinition.php | 531 +++++++++++---------- library/HTMLPurifier/HTMLModule/Hypertext.php | 5 +- .../HTMLPurifier/HTMLModule/TransformToStrict.php | 24 +- package.php | 52 ++ tests/HTMLPurifier/AttrDef/CSS/CompositeTest.php | 12 +- tests/HTMLPurifier/AttrDef/HTML/IDTest.php | 9 + tests/HTMLPurifier/AttrDef/HTML/LinkTypesTest.php | 24 + tests/HTMLPurifier/AttrTransform/BgColorTest.php | 43 ++ tests/HTMLPurifier/AttrTransform/BorderTest.php | 40 ++ tests/HTMLPurifier/AttrTransform/LengthTest.php | 37 ++ tests/HTMLPurifier/AttrTransform/NameTest.php | 28 ++ .../Strategy/ValidateAttributesTest.php | 20 + tests/test_files.php | 5 + 30 files changed, 1105 insertions(+), 386 deletions(-) create mode 100644 INSTALL.fr.utf8 create mode 100644 library/HTMLPurifier/AttrDef/HTML/LinkTypes.php create mode 100644 library/HTMLPurifier/AttrTransform/BgColor.php create mode 100644 library/HTMLPurifier/AttrTransform/Border.php create mode 100644 library/HTMLPurifier/AttrTransform/Length.php create mode 100644 library/HTMLPurifier/AttrTransform/Name.php create mode 100644 package.php create mode 100644 tests/HTMLPurifier/AttrDef/HTML/LinkTypesTest.php create mode 100644 tests/HTMLPurifier/AttrTransform/BgColorTest.php create mode 100644 tests/HTMLPurifier/AttrTransform/BorderTest.php create mode 100644 tests/HTMLPurifier/AttrTransform/LengthTest.php create mode 100644 tests/HTMLPurifier/AttrTransform/NameTest.php diff --git a/Doxyfile b/Doxyfile index c906929e..da12ad93 100644 --- a/Doxyfile +++ b/Doxyfile @@ -4,7 +4,7 @@ # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = HTML Purifier -PROJECT_NUMBER = 1.5.0 +PROJECT_NUMBER = 1.6.0 OUTPUT_DIRECTORY = "C:/Documents and Settings/Edward/My Documents/My Webs/htmlpurifier/docs/doxygen" CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff --git a/INSTALL b/INSTALL index 0013705c..5f41cfba 100644 --- a/INSTALL +++ b/INSTALL @@ -47,7 +47,9 @@ HTML Purifier is all about web-standards, so accordingly your webpages should be standards compliant. HTML Purifier can deal with these doctypes: * XHTML 1.0 Transitional (default) +* XHTML 1.0 Strict * HTML 4.01 Transitional +* HTML 4.01 Strict ...and these character encodings: @@ -87,7 +89,7 @@ into configuring things just for the heck of it, skip to 4.3). * Am I using UTF-8? * Am I using XHTML 1.0 Transitional? -If you answered yes to any of these questions, instantiate a configuration +If you answered no to any of these questions, instantiate a configuration object and read on: $config = HTMLPurifier_Config::createDefault(); diff --git a/INSTALL.fr.utf8 b/INSTALL.fr.utf8 new file mode 100644 index 00000000..625078e2 --- /dev/null +++ b/INSTALL.fr.utf8 @@ -0,0 +1,71 @@ + +Installation + Comment installer HTML Purifier + +Attention: Ce document a encode en UTF-8. Si les lettres avec les accents +est essoreuse, prenez un mieux editeur de texte. + +À L'Aide: Je ne suis pas un diseur natif de français. Si vous trouvez une +erreur dans ce document, racontez-moi! Merci. + + +L'installation de HTML Purifier est trés simple, parce qu'il ne doit pas +la configuration. Dans le pied de de document, les utilisateurs +impatient peuvent trouver le code, mais je recommande que vous lisez +ce document pour quelques choses. + + +1. Compatibilité + +HTML Purifier fonctionne dans PHP 4 et PHP 5. PHP 4.3.9 est le dernier +version que je le testais. Il ne dépend de les autre librairies. + +Les extensions optionnel est iconv (en général déjà installer) et +tidy (répandu aussi). Si vous utilisez UTF-8 et ne voulez pas +l'indentation, vous pouvez utiliser HTML Purifier sans ces extensions. + + +2. Inclure la librarie + +Utilisez: + + require_once '/path/to/library/HTMLPurifier.auto.php'; + +...quand vous devez utiliser HTML Purifier (ne inclure pas quand vous +ne devez pas, parce que HTML Purifier est trés grand.) + +Si vous n'aime pas que HTML Purifier change vos include_path, on peut +change vos include_path, et: + + require_once 'HTMLPurifier.php'; + +Seuleument les contents dans library/ est essentiel; vous peut enlever +les autre fichiers quand vous est dans une atmosphère professionnel. + + +[En cours de construction] + + +6. Installation vite + +Si votre site web est en UTF-8 et XHTML Transitional, utilisez: + +purify($html_salle); +?> + +Sinon, utilisez: + +set('Core', 'Encoding', 'ISO-8859-1'); //remplacez avec votre encoding + $config->set('Core', 'XHTML', true); //remplacez avec false si HTML 4.01 + $purificateur = new HTMLPurifier($config); + + $html_propre = $purificateur->purify($html_salle); +?> \ No newline at end of file diff --git a/NEWS b/NEWS index 9bd45a99..089922f0 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,25 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier . Internal change ========================== +1.6.0, released 2007-04-01 +! Support for most common deprecated attributes via transformations: + + bgcolor in td, th, tr and table + + border in img + + name in a and img + + width in td, th and hr + + height in td, th +! Support for CSS attribute 'height' added +! Support for rel and rev attributes in a tags added, use %Attr.AllowedRel + and %Attr.AllowedRev to activate +- You can define ID blacklists using regular expressions via + %Attr.IDBlacklistRegexp +- Error messages are emitted when you attempt to "allow" elements or + attributes that HTML Purifier does not support + +1.5.1, unknown release date +- Fix segfault in unit test. The problem is not very reproduceable and + I don't know what causes it, but a six line patch fixed it. + 1.5.0, released 2007-03-23 ! Added a rudimentary I18N and L10N system modeled off MediaWiki. It doesn't actually do anything yet, but keep your eyes peeled. diff --git a/TODO b/TODO index 436f4fd9..9901a429 100644 --- a/TODO +++ b/TODO @@ -4,33 +4,35 @@ TODO List = KEY ==================== # Flagship - Regular - ? At-risk + ? Maybe I'll Do It ========================== -1.6 release - # Implement all non-essential attribute transforms, configurable +1.7 release [Advanced API] + # Complete advanced API, and fully document it + # Implement all edge-case attribute transforms + # Implement all deprecated tags and attributes + - Parse TinyMCE-style whitelist into our %HTML.Allow* whitelists (possibly + do this earlier) + +1.8 release [Refactor, refactor!] # URI validation routines tighter (see docs/dev-code-quality.html) (COMPLEX) # Advanced URI filtering schemes (see docs/proposal-new-directives.txt) + - Configuration profiles: predefined directives set with one func call + - Implement IDREF support (harder than it seems, since you cannot have + IDREFs to non-existent IDs) + - Allow non-ASCII characters in font names + +1.9 release [Error'ed] # Error logging for filtering/cleanup procedures - Requires I18N facilities to be created first (COMPLEX) - ? Configuration profiles: sets of directives that get set with one func call - XSS-attempt detection - - Implement IDREF support - -1.7 release - # Add pre-packaged "levels" of cleaning (custom behavior already done) - More fine-grained control over escaping behavior - Silently drop content inbetween SCRIPT tags (can be generalized to allow specification of elements that, when detected as foreign, trigger removal of children, although unbalanced tags could wreck havoc (or at least delete the rest of the document)). - - Allow specifying global attributes on a tag-by-tag basis in - %HTML.AllowAttributes - ? More user-friendly warnings when %HTML.Allow* attempts to specify a - tag or attribute that is not supported - - Parse TinyMCE whitelist into our %HTML.Allow* whitelists -1.8 release +1.10 release [Do What I Mean, Not What I Say] # Additional support for poorly written HTML - Microsoft Word HTML cleaning (i.e. MsoNormal, but research essential!) - Friendly strict handling of
(block ->
) @@ -45,7 +47,7 @@ TODO List - Append something to duplicate IDs so they're still usable (impl. note: the dupe detector would also need to detect the suffix as well) -2.0 release +2.0 release [Beyond HTML] # Legit token based CSS parsing (will require revamping almost every AttrDef class) # Formatters for plaintext (COMPLEX) @@ -54,31 +56,31 @@ TODO List - Linkify URLs - Smileys - Linkification for HTML Purifier docs: notably configuration and classes - -3.0 release - - Extended HTML capabilities based on namespacing and tag transforms (COMPLEX) - - Hooks for adding custom processors to custom namespaced tags and - attributes, offer default implementation - - Lots of documentation and samples - Allow tags to be "armored", an internal flag that protects them from validation and passes them out unharmed - - XHTML 1.1 support - Fixes for Firefox's inability to handle COL alignment props (Bug 915) - Automatically add non-breaking spaces to empty table cells when empty-cells:show is applied to have compatibility with Internet Explorer - Convert RTL/LTR override characters to tags, or vice versa on demand. Also, enable disabling of directionality +3.0 release [To XML and Beyond] + - Extended HTML capabilities based on namespacing and tag transforms (COMPLEX) + - Hooks for adding custom processors to custom namespaced tags and + attributes, offer default implementation + - Lots of documentation and samples + - XHTML 1.1 support + Ongoing - Lots of profiling, make it faster! - Plugins for major CMSes (COMPLEX) - - WordPress + - WordPress (mostly written, needs beta-testing) - eFiction - more! (look for ones that use WYSIWYGs) Unknown release (on a scratch-an-itch basis) - - Have 'lang' attribute be checked against official lists - ? Semi-lossy dumb alternate character encoding transformations, achieved by + ? 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 Requested diff --git a/docs/dev-advanced-api.html b/docs/dev-advanced-api.html index 731397f2..abc83025 100644 --- a/docs/dev-advanced-api.html +++ b/docs/dev-advanced-api.html @@ -16,9 +16,10 @@
Return to the index.
HTML Purifier End-User Documentation
-

It makes no sense to adopt a one-size-fits-all approach to -filtersets: therefore, users must be able to define their own sets of -allowed elements, as well as switch in-between doctypes of HTML.

+

HTML Purifier currently natively supports only a subset of HTML's +allowed elements, attributes, and behavior. This is by design, +but as the user is always right, they'll need some method to overload +these behaviors.

Our goals are to let the user:

@@ -26,20 +27,18 @@ filtersets: therefore, users must be able to define their own sets of
Select
  • Doctype
  • -
  • Filtersets: Rich / Plain / Full ...
  • Mode: Lenient / Correctional
  • -
  • Collections (?): Safe / Unsafe
  • -
  • Modules / Tags / Attributes
  • +
  • Elements / Attributes / Modules
  • +
  • Filterset
Customize
    -
  • Tags / Attributes / Attribute Types
  • -
  • Filtersets
  • -
  • Root Node
  • +
  • Attributes
  • +
  • Elements
-
Create
+
Internals
    -
  • Modules / Tags / Attributes / Attribute Types
  • +
  • Modules / Elements / Attributes / Attribute Types
  • Filtersets
  • Doctype
@@ -47,11 +46,14 @@ filtersets: therefore, users must be able to define their own sets of

Select

+

For basic use, the user will have to specify some basic parameters. This +is not strictly necessary, as HTML Purifier's default setting will always +output safe code, but is required for standards-compliant output.

+

Selecting a Doctype

-

By default, users will use a doctype-based, permissive but secure -whitelist. They must define a doctype, and this serves -as the first method of determining a filterset.

+

The first thing to select is the doctype. This +is essential for standards-compliant output.

This identifier is based on the name the W3C has given to the document type and not @@ -61,116 +63,130 @@ the DTD identifier.

$config->set('HTML', 'Doctype', 'XHTML 1.0 Transitional');
-

Selecting a Filterset

- -

However, selecting this doctype doesn't mean much, because if we -adhered exactly to the definition we would be letting XSS and other -nasties through. HTML Purifier must, in its filterset, allow a subset -of the doctype, which we shall call a filterset.

- -

By default, HTML Purifier will use the Rich -filterset, which allows as many elements as possible with untrusted -sources. Other possible filtersets could be:

- -
-
Full
-
Allows the full span of elements in the doctype, good if you want - HTML Purifier to work as a Tidy substitute but not to strip - anything out.
-
Plain
-
Provides a minimum set of tags for semantic markup of things - like blog comments.
-
- -

Extension-authors would be able to define custom filtersets for -other users to use.

- -

A possible call to select a filterset would be:

- -
$config->set('HTML', 'Filterset', 'Rich');
+

Due to historical reasons, the default doctype is XHTML 1.0 +Transitional, however, we really shouldn't be guessing what the user's +doctype is. Fortunantely, people who can't be bothered to set this won't +be bothered when their pages stop validating.

Selecting Mode

-

Within filtersets, there are various modes of operation. +

Within doctypes, there are various modes of operation. These indicate variant behaviors that, while not strictly changing the -allowed set of elements and attributes, will definitely affect the output. +allowed set of elements and attributes, definitely affect the output. Currently, we have two modes, which may be used together:

Lenient
-
Deprecated elements and attributes will be transformed into - standards-compliant alternatives when explicitly disallowed. For - example, in the XHTML 1.0 Strict doctype, a center - tag would be turned into a div with the CSS property +
+

Deprecated elements and attributes will be transformed into + standards-compliant alternatives when explicitly disallowed.

+

For example, in the XHTML 1.0 Strict doctype, a center + element would be turned into a div with the CSS property text-align:center;, but in XHTML 1.0 Transitional - the tag would be preserved. This mode is on by default.

-
Correctional
-
Deprecated elements and attributes will be transformed into - standards-compliant alternatives whenever possible. Referring - back to the previous example, the center tag would - be transformed in both cases. However, tags without a + the element would be preserved.

+

This mode is on by default.

+
+
Correctional[items to correct]
+
+

Deprecated elements and attributes will be transformed into + standards-compliant alternatives whenever possible. + It may have various levels of operation.

+

Referring back to the previous example, the center element would + be transformed in both cases. However, elements without a reasonable standards-compliant alternative will be preserved - in their form. This mode is on by default. It may have - various levels of operation.

+ in their form.

+

A user may want to correct certain deprecated attributes, but + not others. For example, the bgcolor attribute may be + acceptable, but the center element not; also, possibly, + an HTML Purifier transformation may be buggy, so the user wants + to forgo it. Thus, correctional accepts an array defining which + elements and attributes to cleanup, or no parameter at all, which + means everything gets corrected. This also means that each + correction needs to be given a unique ID that can be referenced + in this manner. (We may also allow globbing, like *.name or a.* + for mass-enabling correction, and subtractive mode, where things + specified stop correction.) This array gets passed into the + constructor of the mode's module.

+

This mode is on by default.

+

A possible call to select modes would be:

$config->set('HTML', 'Mode', array('correctional', 'lenient'));
-

If modes have extra parameters, a hash might work well:

+

If modes have extra parameters, a hash is necessary:

$config->set('HTML', 'Mode', array(
-    'correctional' => 9, // strongest level
+    'correctional' => 'center,a.name',
     'lenient' => true // this one's just boolean
 ));
-

Modes may possibly be wrapped up with the filterset declaration:

+

Modes may be specified along with the doctype declaration (we may want +to get a better set of separator characters):

+ +
$config->setDoctype('XHTML Transitional 1.0', '+correctional[center,a.name] -lenient');
-
$config->set('HTML', 'Filterset', 'Rich: correctional, lenient');
+

+With regards to the various levels of operation conjectured in the +Correctional mode, this is prompted by the fact that a user may want to +correct certain problems but not others, for example, fix the center +element but not the u element, both of which are deprecated. +Having an integer level will not work very well for such fine +grained tweaking, but an array of specific settings might.

-

Further investigation in this field is necessary.

+

Selecting Elements / Attributes / Modules

-

Selecting Modules / Tags / Attributes

+

If this cookie cutter approach doesn't appeal to a user, they may -decide to roll their own filterset by selecting modules, tags and +decide to roll their own filterset by selecting modules, elements and attributes to allow.

This would make use of the same facilities as a filterset author would use, except that it would go under an anonymous filterset that would be auto-selected if any of the -relevant module/tag/attribute selection configuration directives were +relevant module/elements/attribute selection configuration directives were non-null.

-

On the highest level, a user will usually be most interested in -directly specifying which elements and attributes are desired. For -example:

+

In practice, this is the most commonly demanded feature. Most users are +perfectly happy defining a filterset that looks like:

-
$config->set('HTML', 'AllowedElements', 'a,b,em,p,blockquote,code,i');
+
$config->setAllowedHTML('a[href,title];em;p;blockquote');
-

Attribute declarations could be merged into this declaration as such:

+

The directive %HTML.Allowed is a convenience function +that may be fully expressed with the legacy interface, and thus is +given its own setter.

-
$config->set('HTML', 'Allowed', 'a[href,title],b,em,p[class],blockquote[cite],code,i');
+

We currently support a separated interface, which also must be preserved:

-

...or be kept separate:

+
$config->set('HTML', 'AllowedElements', 'a,em,p,blockquote');
+$config->set('HTML', 'AllowedAttributes', 'a.href,a.title');
-
$config->set('HTML', 'AllowedAttributes', 'a.href,a.title,p.class,blockquote.cite');
+

A user may also choose to allow modules:

-

Considering that, internally speaking, as mandated by -the XHTML 1.1 Modularization specification, we have organized our -elements around modules, considerable gymnastics will be needed to -get this sort of functionality working.

+
$config->set('HTML', 'AllowedModules', 'Hypertext,Text,Lists'); // or
+$config->setAllowedHTML('Hypertext,Text,Lists');
-

A user may also specify a module to load a class of elements and attributes -into their filterest:

- -
$config->set('HTML', 'Allowed', 'Hypertext,Core');
+

But it is not expected that this feature will be widely used.

The granularity of these modules is too coarse for the average user (for example, the core module loads everything from -the essential p tag to the not-so-safe h1 -tag). How do we make this still a viable solution?

+the essential p element to the not-so-safe h1 +element). How do we make this still a viable solution? Possible answers +may be sub-modules or module parameters. This may not even be a problem, +considering that most people won't be selecting modules.

+ +

Modules are distinguished from regular elements by the +case of their first letter. While XML distinguishes between and allows +lower and uppercase letters in element names, most well-known XML +languages use only lower-case +element names for sake of consistency.

+ +

Considering that, internally speaking, as mandated by +the XHTML 1.1 Modularization specification, we have organized our +elements around modules, considerable gymnastics will be needed to +get this sort of functionality working.

Unified selector

@@ -183,6 +199,89 @@ for selecting a filterset. Possibility:

...which is simply a light wrapper over the individual configuration calls. A custom config file format or text format could also be adopted.

+

Customize

+ +

By reviewing topic posts in the support forum, we determined that +there were two primarily demanded customization features people wanted: +to add an attribute to an existing element, and to add an element. +Thus, we'll want to create convenience functions for these common +use-cases.

+ +

Note that the functions described here are only available if +a raw copy of HTMLPurifier_HTMLDefinition was retrieved. +addAttribute may work on a processed copy, but for +consistency's sake we will mandate this for everything.

+ +

Attributes

+ +

An attribute is bound to an element by a name and has a specific +AttrDef that validates it. Thus, the interface should +be:

+ +
function addAttribute($element, $attribute, $attribute_def);
+ +

With a use-case that looks like:

+ +
$def->addAttribute('a', 'rel', new HTMLPurifier_AttrDef_Enum(array('nofollow')));
+ +

The $attribute_def value can be a little flexible, +to make things simpler. We'll let it also be:

+ +
    +
  • Class name: We'll instantiate it for you
  • +
  • Function name: We'll create an HTMLPurifier_AttrDef_Anonymous + class with that function registered as a callback.
  • +
  • String attribute type: We'll use HTMLPurifier_AttrTypes +
  • +
  • String starting with enum(: We'll explode it and stuff it in an + HTMLPurifier_AttrDef_Enum for you.
  • +
+ +

Making the previous example written as:

+ +
$def->addAttribute('a', 'rel', 'enum(nofollow)');
+ +

Elements

+ +

An element requires certain information as specified by +HTMLPurifier_ElementDef. However, not all of it is necessary, +the usual things required are:

+ +
    +
  • Attributes
  • +
  • Content model/type
  • +
  • Registration in a content set
  • +
+ +

This suggests an API like this:

+ +
function addElement($element, $type, $content_model, $attributes = array());
+ +

Each parameter explained in depth:

+ +
+
$element
+
Element name, ex. 'label'
+
$type
+
Content set to register in, ex. 'Inline' or 'Flow'
+
$content_model
+
Description of allowed children. This is a merged form of + HTMLPurifier_ElementDef's member variables + $content_model and $content_model_type, + where the form is Type: Model, ex. 'Optional: Inline'.
+
$attributes
+
Array of attribute names to attribute definitions, much like + the above-described attribute customization.
+
+ +

A possible usage:

+ +
$def->addElement('font', 'Inline', 'Optional: Inline',
+    array(0 => array('Common'), 'color' => 'Color'));
+ +

We may want to Common attribute collection inclusion to be added +by default.

+
$Id$
\ No newline at end of file diff --git a/docs/dev-progress.html b/docs/dev-progress.html index be35a9b6..c0da280a 100644 --- a/docs/dev-progress.html +++ b/docs/dev-progress.html @@ -151,7 +151,7 @@ thead th {text-align:left;padding:0.1em;background-color:#EEE;} will not implement list-item, run-in (Opera only) or table (no IE); inline-block has incomplete IE6 support and requires -moz-inline-box for Mozilla. Unknown target milestone. -heightInteresting, why use it? Unknown target milestone. +heightInteresting, why use it? Unknown target milestone. list-style-imageDangerous? max-heightNo IE 5/6 min-height @@ -244,8 +244,8 @@ Mozilla on inside and needs -moz-outline, no IE support. Miscellaneous datetimeDEL, INSNo visible effect, ISO format -relALargely user-defined: nofollow, tag (see microformats) -revALargely user-defined: vote-* +relALargely user-defined: nofollow, tag (see microformats) +revALargely user-defined: vote-* axisTD, THW3C only: No browser implementation charCOL, COLGROUP, TBODY, TD, TFOOT, TH, THEAD, TRW3C only: No browser implementation headersTD, THW3C only: No browser implementation @@ -262,28 +262,28 @@ Mozilla on inside and needs -moz-outline, no IE support. -Transform, target milestone 1.4 +Transform, target milestone 1.6 alignCAPTIONNear-equiv style 'caption-side', drop left and right IMGMargin-left and margin-right = auto or parent div TABLE HRNear-equivalent style 'text-align' (Works for IE and Opera, but not Firefox). Also try margin-right:auto; margin-left:0; for left or margin-right:0; margin-left:auto; for right (optionally replacing 0 with the original margin for that side) H1, H2, H3, H4, H5, H6, PEquivalent style 'text-align' altIMGRequired, insert image filename if src is present or default invalid image text -bgcolorTABLEEquivalent style 'background-color' - TREquivalent style 'background-color' - TD, THEquivalent style 'background-color' -borderIMGNear equivalent style 'border-width', as it only applies when link present +bgcolorTABLESuperset style 'background-color' + TRSuperset style 'background-color' + TD, THSuperset style 'background-color' +borderIMGEquivalent style border:[number]px solid clearBRNear-equiv style 'clear', transform 'all' into 'both' compactDL, OL, ULBoolean, needs custom CSS class; rarely used anyway dirBDORequired, insert ltr (or configuration value) if none -heightTD, THNear-equiv style 'height', needs px suffix if original was in pixels +heightTD, THNear-equiv style 'height', needs px suffix if original was in pixels hspaceIMGNear-equiv styles 'margin-top' and 'margin-bottom', needs px suffix lang*Copy value to xml:lang -nameIMGTurn into ID - ATurn into ID? (not deprecated, though in which specs?) +nameIMGTurn into ID + ATurn into ID noshadeHRBoolean, style 'border-style:solid;' nowrapTD, THBoolean, style 'white-space:nowrap;' (not compat with IE5) -sizeHRNear-equiv 'width', needs px suffix if original was pixels +sizeHRNear-equiv 'height', needs px suffix if original was pixels srcIMGRequired, insert blank or default img if not set startOLPoorly supported 'counter-reset', allowed in loose, dropped in strict typeLIEquivalent style 'list-style-type', different allowed values though. (needs testing) @@ -291,8 +291,8 @@ Mozilla on inside and needs -moz-outline, no IE support. UL valueLIPoorly supported 'counter-reset', allowed in loose, dropped in strict vspaceIMGNear-equiv styles 'margin-left' and 'margin-right', needs px suffix, see hspace -widthHRNear-equiv style 'width', needs px suffix if original was pixels - TD, TH +widthHRNear-equiv style 'width', needs px suffix if original was pixels + TD, TH diff --git a/docs/enduser-utf8.html b/docs/enduser-utf8.html index d8187c5d..351c44d1 100644 --- a/docs/enduser-utf8.html +++ b/docs/enduser-utf8.html @@ -1003,7 +1003,11 @@ when dealing with Unicode text:

-

...and always think in bytes, not characters. If you use strpos() +

Note: this list applies to UTF-8 encoded text only: if you have +a string that you are 100% sure is ASCII, be my guest and use +strtolower (HTML Purifier uses this function.)

+ +

Regardless, always think in bytes, not characters. If you use strpos() to find the position of a character, it will be in bytes, but this usually won't matter since substr() also operates with byte indices!

diff --git a/library/HTMLPurifier.php b/library/HTMLPurifier.php index feefea25..5a0ce99d 100644 --- a/library/HTMLPurifier.php +++ b/library/HTMLPurifier.php @@ -22,7 +22,7 @@ */ /* - HTML Purifier 1.5.0 - Standards Compliant HTML Filtering + HTML Purifier 1.6.0 - 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.5.0'; + var $version = '1.6.0'; var $config; var $filters; diff --git a/library/HTMLPurifier/AttrDef/HTML/ID.php b/library/HTMLPurifier/AttrDef/HTML/ID.php index 2a6d2c9a..c8bf2991 100644 --- a/library/HTMLPurifier/AttrDef/HTML/ID.php +++ b/library/HTMLPurifier/AttrDef/HTML/ID.php @@ -43,6 +43,14 @@ HTMLPurifier_ConfigSchema::define( 'is set to a non-empty value! This directive was available since 1.2.0.' ); +HTMLPurifier_ConfigSchema::define( + 'Attr', 'IDBlacklistRegexp', null, 'string/null', + 'PCRE regular expression to be matched against all IDs. If the expression '. + 'is matches, the ID is rejected. Use this with care: may cause '. + 'significant degradation. ID matching is done after all other '. + 'validation. This directive was available since 1.6.0.' +); + /** * Validates the HTML attribute ID. * @warning Even though this is the id processor, it @@ -94,6 +102,11 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef $result = ($trim === ''); } + $regexp = $config->get('Attr', 'IDBlacklistRegexp'); + if ($regexp && preg_match($regexp, $id)) { + return false; + } + if (/*!$this->ref && */$result) $id_accumulator->add($id); // if no change was made to the ID, return the result diff --git a/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php new file mode 100644 index 00000000..94a47ba9 --- /dev/null +++ b/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php @@ -0,0 +1,75 @@ + 'AllowedRel', + 'rev' => 'AllowedRev' + ); + + /** Name config attribute to pull. */ + var $name; + + function HTMLPurifier_AttrDef_HTML_LinkTypes($name) { + if (!isset($this->configLookup[$name])) { + trigger_error('Unrecognized attribute name for link '. + 'relationship.', E_USER_ERROR); + return; + } + $this->name = $this->configLookup[$name]; + } + + function validate($string, $config, &$context) { + + $allowed = $config->get('Attr', $this->name); + if (empty($allowed)) return false; + + $string = $this->parseCDATA($string); + $parts = explode(' ', $string); + + // lookup to prevent duplicates + $ret_lookup = array(); + foreach ($parts as $part) { + $part = strtolower(trim($part)); + if (!isset($allowed[$part])) continue; + $ret_lookup[$part] = true; + } + + if (empty($ret_lookup)) return false; + + $ret_array = array(); + foreach ($ret_lookup as $part => $bool) $ret_array[] = $part; + $string = implode(' ', $ret_array); + + return $string; + + } + +} + +?> \ No newline at end of file diff --git a/library/HTMLPurifier/AttrTransform/BgColor.php b/library/HTMLPurifier/AttrTransform/BgColor.php new file mode 100644 index 00000000..abfd0342 --- /dev/null +++ b/library/HTMLPurifier/AttrTransform/BgColor.php @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/library/HTMLPurifier/AttrTransform/Border.php b/library/HTMLPurifier/AttrTransform/Border.php new file mode 100644 index 00000000..0b745d30 --- /dev/null +++ b/library/HTMLPurifier/AttrTransform/Border.php @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/library/HTMLPurifier/AttrTransform/Length.php b/library/HTMLPurifier/AttrTransform/Length.php new file mode 100644 index 00000000..16d3d1d8 --- /dev/null +++ b/library/HTMLPurifier/AttrTransform/Length.php @@ -0,0 +1,33 @@ +name = $name; + $this->cssName = $css_name ? $css_name : $name; + } + + function transform($attr, $config, &$context) { + if (!isset($attr[$this->name])) return $attr; + $length = $attr[$this->name]; + unset($attr[$this->name]); + if(ctype_digit($length)) $length .= 'px'; + + $attr['style'] = isset($attr['style']) ? $attr['style'] : ''; + $attr['style'] = $this->cssName . ":$length;" . $attr['style']; + + return $attr; + } + +} + +?> \ No newline at end of file diff --git a/library/HTMLPurifier/AttrTransform/Name.php b/library/HTMLPurifier/AttrTransform/Name.php new file mode 100644 index 00000000..0f815b69 --- /dev/null +++ b/library/HTMLPurifier/AttrTransform/Name.php @@ -0,0 +1,31 @@ + \ No newline at end of file diff --git a/library/HTMLPurifier/AttrTransform/TextAlign.php b/library/HTMLPurifier/AttrTransform/TextAlign.php index 84e5a016..09088fe1 100644 --- a/library/HTMLPurifier/AttrTransform/TextAlign.php +++ b/library/HTMLPurifier/AttrTransform/TextAlign.php @@ -6,7 +6,7 @@ require_once 'HTMLPurifier/AttrTransform.php'; * Pre-transform that changes deprecated align attribute to text-align. */ class HTMLPurifier_AttrTransform_TextAlign - extends HTMLPurifier_AttrTransform { +extends HTMLPurifier_AttrTransform { function transform($attr, $config, &$context) { diff --git a/library/HTMLPurifier/CSSDefinition.php b/library/HTMLPurifier/CSSDefinition.php index 55f0adc9..5de49b69 100644 --- a/library/HTMLPurifier/CSSDefinition.php +++ b/library/HTMLPurifier/CSSDefinition.php @@ -162,7 +162,9 @@ class HTMLPurifier_CSSDefinition new HTMLPurifier_AttrDef_CSS_Percentage() )); - $this->info['width'] = new HTMLPurifier_AttrDef_CSS_Composite(array( + $this->info['width'] = + $this->info['height'] = + new HTMLPurifier_AttrDef_CSS_Composite(array( new HTMLPurifier_AttrDef_CSS_Length(true), new HTMLPurifier_AttrDef_CSS_Percentage(true), new HTMLPurifier_AttrDef_Enum(array('auto')) diff --git a/library/HTMLPurifier/HTMLDefinition.php b/library/HTMLPurifier/HTMLDefinition.php index 6fca7fb7..5f5a1670 100644 --- a/library/HTMLPurifier/HTMLDefinition.php +++ b/library/HTMLPurifier/HTMLDefinition.php @@ -1,250 +1,281 @@ -<blockquote>Foo</blockquote> '. - 'would become <blockquote><p>Foo</p></blockquote>. The '. - '<p> tags can be replaced '. - 'with whatever you desire, as long as it is a block level element. '. - 'This directive has been available since 1.3.0.' -); - -HTMLPurifier_ConfigSchema::define( - 'HTML', 'Parent', 'div', 'string', - 'String name of element that HTML fragment passed to library will be '. - 'inserted in. An interesting variation would be using span as the '. - 'parent element, meaning that only inline tags would be allowed. '. - 'This directive has been available since 1.3.0.' -); - -HTMLPurifier_ConfigSchema::define( - 'HTML', 'AllowedElements', null, 'lookup/null', - 'If HTML Purifier\'s tag set is unsatisfactory for your needs, you '. - 'can overload it with your own list of tags to allow. Note that this '. - 'method is subtractive: it does its job by taking away from HTML Purifier '. - 'usual feature set, so you cannot add a tag that HTML Purifier never '. - 'supported in the first place (like embed, form or head). If you change this, you '. - 'probably also want to change %HTML.AllowedAttributes. '. - 'Warning: If another directive conflicts with the '. - 'elements here, that directive will win and override. '. - 'This directive has been available since 1.3.0.' -); - -HTMLPurifier_ConfigSchema::define( - 'HTML', 'AllowedAttributes', null, 'lookup/null', - 'IF HTML Purifier\'s attribute set is unsatisfactory, overload it! '. - 'The syntax is \'tag.attr\' or \'*.attr\' for the global attributes '. - '(style, id, class, dir, lang, xml:lang).'. - 'Warning: If another directive conflicts with the '. - 'elements here, that directive will win and override. For '. - 'example, %HTML.EnableAttrID will take precedence over *.id in this '. - 'directive. You must set that directive to true before you can use '. - 'IDs at all. This directive has been available since 1.3.0.' -); - -/** - * Definition of the purified HTML that describes allowed children, - * attributes, and many other things. - * - * Conventions: - * - * All member variables that are prefixed with info - * (including the main $info array) are used by HTML Purifier internals - * and should not be directly edited when customizing the HTMLDefinition. - * They can usually be set via configuration directives or custom - * modules. - * - * On the other hand, member variables without the info prefix are used - * internally by the HTMLDefinition and MUST NOT be used by other HTML - * Purifier internals. Many of them, however, are public, and may be - * edited by userspace code to tweak the behavior of HTMLDefinition. - * - * HTMLPurifier_Printer_HTMLDefinition is a notable exception to this - * rule: in the interest of comprehensiveness, it will sniff everything. - */ -class HTMLPurifier_HTMLDefinition -{ - - /** FULLY-PUBLIC VARIABLES */ - - /** - * Associative array of element names to HTMLPurifier_ElementDef - * @public - */ - var $info = array(); - - /** - * Associative array of global attribute name to attribute definition. - * @public - */ - var $info_global_attr = array(); - - /** - * String name of parent element HTML will be going into. - * @public - */ - var $info_parent = 'div'; - - /** - * Definition for parent element, allows parent element to be a - * tag that's not allowed inside the HTML fragment. - * @public - */ - var $info_parent_def; - - /** - * String name of element used to wrap inline elements in block context - * @note This is rarely used except for BLOCKQUOTEs in strict mode - * @public - */ - var $info_block_wrapper = 'p'; - - /** - * Associative array of deprecated tag name to HTMLPurifier_TagTransform - * @public - */ - var $info_tag_transform = array(); - - /** - * Indexed list of HTMLPurifier_AttrTransform to be performed before validation. - * @public - */ - var $info_attr_transform_pre = array(); - - /** - * Indexed list of HTMLPurifier_AttrTransform to be performed after validation. - * @public - */ - var $info_attr_transform_post = array(); - - /** - * Nested lookup array of content set name (Block, Inline) to - * element name to whether or not it belongs in that content set. - * @public - */ - var $info_content_sets = array(); - - - - /** PUBLIC BUT INTERNAL VARIABLES */ - - var $setup = false; /**< Has setup() been called yet? */ - var $config; /**< Temporary instance of HTMLPurifier_Config */ - - var $manager; /**< Instance of HTMLPurifier_HTMLModuleManager */ - - /** - * Performs low-cost, preliminary initialization. - * @param $config Instance of HTMLPurifier_Config - */ - function HTMLPurifier_HTMLDefinition(&$config) { - $this->config =& $config; - $this->manager = new HTMLPurifier_HTMLModuleManager(); - } - - /** - * Processes internals into form usable by HTMLPurifier internals. - * Modifying the definition after calling this function should not - * be done. - */ - function setup() { - - // multiple call guard - if ($this->setup) {return;} else {$this->setup = true;} - - $this->processModules(); - $this->setupConfigStuff(); - - unset($this->config); - unset($this->manager); - - } - - /** - * Extract out the information from the manager - */ - function processModules() { - - $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; - } - - $this->info = $this->manager->getElements($this->config); - $this->info_content_sets = $this->manager->contentSets->lookup; - - } - - /** - * Sets up stuff based on config. We need a better way of doing this. - */ - function setupConfigStuff() { - - $block_wrapper = $this->config->get('HTML', 'BlockWrapper'); - if (isset($this->info_content_sets['Block'][$block_wrapper])) { - $this->info_block_wrapper = $block_wrapper; - } else { - trigger_error('Cannot use non-block element as block wrapper.', - E_USER_ERROR); - } - - $parent = $this->config->get('HTML', 'Parent'); - $def = $this->manager->getElement($parent, $this->config); - if ($def) { - $this->info_parent = $parent; - $this->info_parent_def = $def; - } else { - trigger_error('Cannot use unrecognized element as parent.', - E_USER_ERROR); - $this->info_parent_def = $this->manager->getElement( - $this->info_parent, $this->config); - } - - // setup allowed elements, SubtractiveWhitelist module - $allowed_elements = $this->config->get('HTML', 'AllowedElements'); - if (is_array($allowed_elements)) { - foreach ($this->info as $name => $d) { - if(!isset($allowed_elements[$name])) unset($this->info[$name]); - } - } - $allowed_attributes = $this->config->get('HTML', 'AllowedAttributes'); - if (is_array($allowed_attributes)) { - foreach ($this->info_global_attr as $attr_key => $info) { - if (!isset($allowed_attributes["*.$attr_key"])) { - unset($this->info_global_attr[$attr_key]); - } - } - foreach ($this->info as $tag => $info) { - foreach ($info->attr as $attr => $attr_info) { - if (!isset($allowed_attributes["$tag.$attr"]) && - !isset($allowed_attributes["*.$attr"])) { - unset($this->info[$tag]->attr[$attr]); - } - } - } - } - - } - - -} - -?> +<blockquote>Foo</blockquote> '. + 'would become <blockquote><p>Foo</p></blockquote>. The '. + '<p> tags can be replaced '. + 'with whatever you desire, as long as it is a block level element. '. + 'This directive has been available since 1.3.0.' +); + +HTMLPurifier_ConfigSchema::define( + 'HTML', 'Parent', 'div', 'string', + 'String name of element that HTML fragment passed to library will be '. + 'inserted in. An interesting variation would be using span as the '. + 'parent element, meaning that only inline tags would be allowed. '. + 'This directive has been available since 1.3.0.' +); + +HTMLPurifier_ConfigSchema::define( + 'HTML', 'AllowedElements', null, 'lookup/null', + 'If HTML Purifier\'s tag set is unsatisfactory for your needs, you '. + 'can overload it with your own list of tags to allow. Note that this '. + 'method is subtractive: it does its job by taking away from HTML Purifier '. + 'usual feature set, so you cannot add a tag that HTML Purifier never '. + 'supported in the first place (like embed, form or head). If you change this, you '. + 'probably also want to change %HTML.AllowedAttributes. '. + 'Warning: If another directive conflicts with the '. + 'elements here, that directive will win and override. '. + 'This directive has been available since 1.3.0.' +); + +HTMLPurifier_ConfigSchema::define( + 'HTML', 'AllowedAttributes', null, 'lookup/null', + 'IF HTML Purifier\'s attribute set is unsatisfactory, overload it! '. + 'The syntax is \'tag.attr\' or \'*.attr\' for the global attributes '. + '(style, id, class, dir, lang, xml:lang).'. + 'Warning: If another directive conflicts with the '. + 'elements here, that directive will win and override. For '. + 'example, %HTML.EnableAttrID will take precedence over *.id in this '. + 'directive. You must set that directive to true before you can use '. + 'IDs at all. This directive has been available since 1.3.0.' +); + +/** + * Definition of the purified HTML that describes allowed children, + * attributes, and many other things. + * + * Conventions: + * + * All member variables that are prefixed with info + * (including the main $info array) are used by HTML Purifier internals + * and should not be directly edited when customizing the HTMLDefinition. + * They can usually be set via configuration directives or custom + * modules. + * + * On the other hand, member variables without the info prefix are used + * internally by the HTMLDefinition and MUST NOT be used by other HTML + * Purifier internals. Many of them, however, are public, and may be + * edited by userspace code to tweak the behavior of HTMLDefinition. + * + * HTMLPurifier_Printer_HTMLDefinition is a notable exception to this + * rule: in the interest of comprehensiveness, it will sniff everything. + */ +class HTMLPurifier_HTMLDefinition +{ + + /** FULLY-PUBLIC VARIABLES */ + + /** + * Associative array of element names to HTMLPurifier_ElementDef + * @public + */ + var $info = array(); + + /** + * Associative array of global attribute name to attribute definition. + * @public + */ + var $info_global_attr = array(); + + /** + * String name of parent element HTML will be going into. + * @public + */ + var $info_parent = 'div'; + + /** + * Definition for parent element, allows parent element to be a + * tag that's not allowed inside the HTML fragment. + * @public + */ + var $info_parent_def; + + /** + * String name of element used to wrap inline elements in block context + * @note This is rarely used except for BLOCKQUOTEs in strict mode + * @public + */ + var $info_block_wrapper = 'p'; + + /** + * Associative array of deprecated tag name to HTMLPurifier_TagTransform + * @public + */ + var $info_tag_transform = array(); + + /** + * Indexed list of HTMLPurifier_AttrTransform to be performed before validation. + * @public + */ + var $info_attr_transform_pre = array(); + + /** + * Indexed list of HTMLPurifier_AttrTransform to be performed after validation. + * @public + */ + var $info_attr_transform_post = array(); + + /** + * Nested lookup array of content set name (Block, Inline) to + * element name to whether or not it belongs in that content set. + * @public + */ + var $info_content_sets = array(); + + + + /** PUBLIC BUT INTERNAL VARIABLES */ + + var $setup = false; /**< Has setup() been called yet? */ + var $config; /**< Temporary instance of HTMLPurifier_Config */ + + var $manager; /**< Instance of HTMLPurifier_HTMLModuleManager */ + + /** + * Performs low-cost, preliminary initialization. + * @param $config Instance of HTMLPurifier_Config + */ + function HTMLPurifier_HTMLDefinition(&$config) { + $this->config =& $config; + $this->manager = new HTMLPurifier_HTMLModuleManager(); + } + + /** + * Processes internals into form usable by HTMLPurifier internals. + * Modifying the definition after calling this function should not + * be done. + */ + function setup() { + + // multiple call guard + if ($this->setup) {return;} else {$this->setup = true;} + + $this->processModules(); + $this->setupConfigStuff(); + + unset($this->config); + unset($this->manager); + + } + + /** + * Extract out the information from the manager + */ + function processModules() { + + $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; + } + + $this->info = $this->manager->getElements($this->config); + $this->info_content_sets = $this->manager->contentSets->lookup; + + } + + /** + * Sets up stuff based on config. We need a better way of doing this. + */ + function setupConfigStuff() { + + $block_wrapper = $this->config->get('HTML', 'BlockWrapper'); + if (isset($this->info_content_sets['Block'][$block_wrapper])) { + $this->info_block_wrapper = $block_wrapper; + } else { + trigger_error('Cannot use non-block element as block wrapper.', + E_USER_ERROR); + } + + $parent = $this->config->get('HTML', 'Parent'); + $def = $this->manager->getElement($parent, $this->config); + if ($def) { + $this->info_parent = $parent; + $this->info_parent_def = $def; + } else { + trigger_error('Cannot use unrecognized element as parent.', + E_USER_ERROR); + $this->info_parent_def = $this->manager->getElement( + $this->info_parent, $this->config); + } + + // support template text + $support = "(for information on implementing this, see the ". + "support forums) "; + + // setup allowed elements, SubtractiveWhitelist module + $allowed_elements = $this->config->get('HTML', 'AllowedElements'); + if (is_array($allowed_elements)) { + foreach ($this->info as $name => $d) { + if(!isset($allowed_elements[$name])) unset($this->info[$name]); + unset($allowed_elements[$name]); + } + // emit errors + foreach ($allowed_elements as $element => $d) { + trigger_error("Element '$element' is not supported $support", E_USER_WARNING); + } + } + + $allowed_attributes = $this->config->get('HTML', 'AllowedAttributes'); + $allowed_attributes_mutable = $allowed_attributes; // by copy! + if (is_array($allowed_attributes)) { + foreach ($this->info_global_attr as $attr_key => $info) { + if (!isset($allowed_attributes["*.$attr_key"])) { + unset($this->info_global_attr[$attr_key]); + } elseif (isset($allowed_attributes_mutable["*.$attr_key"])) { + unset($allowed_attributes_mutable["*.$attr_key"]); + } + } + foreach ($this->info as $tag => $info) { + foreach ($info->attr as $attr => $attr_info) { + if (!isset($allowed_attributes["$tag.$attr"]) && + !isset($allowed_attributes["*.$attr"])) { + unset($this->info[$tag]->attr[$attr]); + } else { + if (isset($allowed_attributes_mutable["$tag.$attr"])) { + unset($allowed_attributes_mutable["$tag.$attr"]); + } elseif (isset($allowed_attributes_mutable["*.$attr"])) { + unset($allowed_attributes_mutable["*.$attr"]); + } + } + } + } + // emit errors + foreach ($allowed_attributes_mutable as $elattr => $d) { + list($element, $attribute) = explode('.', $elattr); + if ($element == '*') { + trigger_error("Global attribute '$attribute' is not ". + "supported in any elements $support", + E_USER_WARNING); + } else { + trigger_error("Attribute '$attribute' in element '$element' not supported $support", + E_USER_WARNING); + } + } + } + + } + + +} + +?> \ No newline at end of file diff --git a/library/HTMLPurifier/HTMLModule/Hypertext.php b/library/HTMLPurifier/HTMLModule/Hypertext.php index 0b8a2e98..e285e8ba 100644 --- a/library/HTMLPurifier/HTMLModule/Hypertext.php +++ b/library/HTMLPurifier/HTMLModule/Hypertext.php @@ -1,6 +1,7 @@ 'Charset', 'href' => 'URI', //'hreflang' => 'LanguageCode', - //'rel' => 'LinkTypes', - //'rev' => 'LinkTypes', + 'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'), + 'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'), //'tabindex' => 'Number', //'type' => 'ContentType', ); diff --git a/library/HTMLPurifier/HTMLModule/TransformToStrict.php b/library/HTMLPurifier/HTMLModule/TransformToStrict.php index d228f84f..cdbe3733 100644 --- a/library/HTMLPurifier/HTMLModule/TransformToStrict.php +++ b/library/HTMLPurifier/HTMLModule/TransformToStrict.php @@ -8,6 +8,10 @@ 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/Border.php'; +require_once 'HTMLPurifier/AttrTransform/Name.php'; +require_once 'HTMLPurifier/AttrTransform/Length.php'; /** * Proprietary module that transforms deprecated elements into Strict @@ -20,7 +24,8 @@ class HTMLPurifier_HTMLModule_TransformToStrict extends HTMLPurifier_HTMLModule var $name = 'TransformToStrict'; // we're actually modifying these elements, not defining them - var $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'blockquote'); + var $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', + 'blockquote', 'table', 'td', 'th', 'tr', 'img', 'a', 'hr'); var $info_tag_transform = array( // placeholders, see constructor for definitions @@ -73,6 +78,23 @@ class HTMLPurifier_HTMLModule_TransformToStrict extends HTMLPurifier_HTMLModule $this->info['blockquote']->content_model_type = 'strictblockquote'; $this->info['blockquote']->child = false; // recalculate please! + $this->info['table']->attr_transform_pre['bgcolor'] = + $this->info['tr']->attr_transform_pre['bgcolor'] = + $this->info['td']->attr_transform_pre['bgcolor'] = + $this->info['th']->attr_transform_pre['bgcolor'] = new HTMLPurifier_AttrTransform_BgColor(); + + $this->info['img']->attr_transform_pre['border'] = new HTMLPurifier_AttrTransform_Border(); + + $this->info['img']->attr_transform_pre['name'] = + $this->info['a']->attr_transform_pre['name'] = new HTMLPurifier_AttrTransform_Name(); + + $this->info['td']->attr_transform_pre['width'] = + $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['height'] = + $this->info['th']->attr_transform_pre['height'] = new HTMLPurifier_AttrTransform_Length('height'); + } var $defines_child_def = true; diff --git a/package.php b/package.php new file mode 100644 index 00000000..8ee09e55 --- /dev/null +++ b/package.php @@ -0,0 +1,52 @@ +setOptions( + array( + 'baseinstalldir' => '/', + 'packagefile' => 'package2.xml', + 'packagedirectory' => dirname(__FILE__) . '/library', + 'filelistgenerator' => 'file', + 'include' => array('*'), + 'ignore' => array('HTMLPurifier.auto.php'), + ) +); + +$pkg->setPackage('HTMLPurifier'); +$pkg->setLicense('LGPL', 'http://www.gnu.org/licenses/lgpl.html'); +$pkg->setSummary('Standards-compliant HTML filter'); +$pkg->setDescription( + 'HTML Purifier is an HTML filter that will remove all malicious code + (better known as XSS) with a thoroughly audited, secure yet permissive + whitelist and will also make sure your documents are standards + compliant.' +); + +$pkg->addMaintainer('lead', 'edwardzyang', 'Edward Z. Yang', 'htmlpurifier@jpsband.org', 'yes'); + +$pkg->setChannel('hp.jpsband.org'); +$pkg->setAPIVersion('1.5'); +$pkg->setAPIStability('stable'); +$pkg->setReleaseVersion('1.5.0'); +$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->setPackageType('php'); + +$pkg->setPhpDep('4.3.9'); +$pkg->setPearinstallerDep('1.4.3'); + +$pkg->generateContents(); + +$compat =& $pkg->exportCompatiblePackageFile1(); +$compat->writePackageFile(); +$pkg->writePackageFile(); + +?> \ No newline at end of file diff --git a/tests/HTMLPurifier/AttrDef/CSS/CompositeTest.php b/tests/HTMLPurifier/AttrDef/CSS/CompositeTest.php index 3ec60e7d..037131fb 100644 --- a/tests/HTMLPurifier/AttrDef/CSS/CompositeTest.php +++ b/tests/HTMLPurifier/AttrDef/CSS/CompositeTest.php @@ -40,8 +40,8 @@ class HTMLPurifier_AttrDef_CSS_CompositeTest extends HTMLPurifier_AttrDefHarness $def1->setReturnValue('validate', $output, $def1_params); $def2->expectNever('validate'); - $this->assertIdentical($output, - $def->validate($input, $config, $context)); + $result = $def->validate($input, $config, $context); + $this->assertIdentical($output, $result); $def1->tally(); $def2->tally(); @@ -60,8 +60,8 @@ class HTMLPurifier_AttrDef_CSS_CompositeTest extends HTMLPurifier_AttrDefHarness $def2->expectOnce('validate', $def_params); $def2->setReturnValue('validate', $output, $def_params); - $this->assertIdentical($output, - $def->validate($input, $config, $context)); + $result = $def->validate($input, $config, $context); + $this->assertIdentical($output, $result); $def1->tally(); $def2->tally(); @@ -80,8 +80,8 @@ class HTMLPurifier_AttrDef_CSS_CompositeTest extends HTMLPurifier_AttrDefHarness $def2->expectOnce('validate', $def_params); $def2->setReturnValue('validate', false, $def_params); - $this->assertIdentical($output, - $def->validate($input, $config, $context)); + $result = $def->validate($input, $config, $context); + $this->assertIdentical($output, $result); $def1->tally(); $def2->tally(); diff --git a/tests/HTMLPurifier/AttrDef/HTML/IDTest.php b/tests/HTMLPurifier/AttrDef/HTML/IDTest.php index a604ca0c..98fffbba 100644 --- a/tests/HTMLPurifier/AttrDef/HTML/IDTest.php +++ b/tests/HTMLPurifier/AttrDef/HTML/IDTest.php @@ -95,6 +95,15 @@ class HTMLPurifier_AttrDef_HTML_IDTest extends HTMLPurifier_AttrDefHarness } + function testRegexp() { + + $this->config->set('Attr', 'IDBlacklistRegexp', '/^g_/'); + + $this->assertDef('good_id'); + $this->assertDef('g_bad_id', false); + + } + } ?> \ No newline at end of file diff --git a/tests/HTMLPurifier/AttrDef/HTML/LinkTypesTest.php b/tests/HTMLPurifier/AttrDef/HTML/LinkTypesTest.php new file mode 100644 index 00000000..0acfac03 --- /dev/null +++ b/tests/HTMLPurifier/AttrDef/HTML/LinkTypesTest.php @@ -0,0 +1,24 @@ +def = new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'); + $this->config->set('Attr', 'AllowedRel', array('nofollow', 'foo')); + + $this->assertDef('', false); + $this->assertDef('nofollow', true); + $this->assertDef('nofollow foo', true); + $this->assertDef('nofollow bar', 'nofollow'); + $this->assertDef('bar', false); + + } + +} + +?> \ No newline at end of file diff --git a/tests/HTMLPurifier/AttrTransform/BgColorTest.php b/tests/HTMLPurifier/AttrTransform/BgColorTest.php new file mode 100644 index 00000000..6ad35bde --- /dev/null +++ b/tests/HTMLPurifier/AttrTransform/BgColorTest.php @@ -0,0 +1,43 @@ +obj = new HTMLPurifier_AttrTransform_BgColor(); + } + + function test() { + + $this->assertResult( array() ); + + // we currently rely on the CSS validator to fix any problems. + // This means that this transform, strictly speaking, supports + // a superset of the functionality. + + $this->assertResult( + array('bgcolor' => '#000000'), + array('style' => 'background-color:#000000;') + ); + + $this->assertResult( + array('bgcolor' => '#000000', 'style' => 'font-weight:bold'), + array('style' => 'background-color:#000000;font-weight:bold') + ); + + // this may change when we natively support the datatype and + // validate its contents before forwarding it on + $this->assertResult( + array('bgcolor' => '#F00'), + array('style' => 'background-color:#F00;') + ); + + } + +} + +?> \ No newline at end of file diff --git a/tests/HTMLPurifier/AttrTransform/BorderTest.php b/tests/HTMLPurifier/AttrTransform/BorderTest.php new file mode 100644 index 00000000..a592e41b --- /dev/null +++ b/tests/HTMLPurifier/AttrTransform/BorderTest.php @@ -0,0 +1,40 @@ +obj = new HTMLPurifier_AttrTransform_Border(); + } + + function test() { + + $this->assertResult( array() ); + + $this->assertResult( + array('border' => '1'), + array('style' => 'border:1px solid;') + ); + + // once again, no validation done here, we expect CSS validator + // to catch it + $this->assertResult( + array('border' => '10%'), + array('style' => 'border:10%px solid;') + ); + + $this->assertResult( + array('border' => '23', 'style' => 'font-weight:bold;'), + array('style' => 'border:23px solid;font-weight:bold;') + ); + + } + +} + +?> \ No newline at end of file diff --git a/tests/HTMLPurifier/AttrTransform/LengthTest.php b/tests/HTMLPurifier/AttrTransform/LengthTest.php new file mode 100644 index 00000000..e0c9474b --- /dev/null +++ b/tests/HTMLPurifier/AttrTransform/LengthTest.php @@ -0,0 +1,37 @@ +obj = new HTMLPurifier_AttrTransform_Length('width'); + } + + function test() { + $this->assertResult( array() ); + $this->assertResult( + array('width' => '10'), + array('style' => 'width:10px;') + ); + $this->assertResult( + array('width' => '10%'), + array('style' => 'width:10%;') + ); + $this->assertResult( + array('width' => '10%', 'style' => 'font-weight:bold'), + array('style' => 'width:10%;font-weight:bold') + ); + // this behavior might change + $this->assertResult( + array('width' => 'asdf'), + array('style' => 'width:asdf;') + ); + } + +} + +?> \ No newline at end of file diff --git a/tests/HTMLPurifier/AttrTransform/NameTest.php b/tests/HTMLPurifier/AttrTransform/NameTest.php new file mode 100644 index 00000000..da4498fb --- /dev/null +++ b/tests/HTMLPurifier/AttrTransform/NameTest.php @@ -0,0 +1,28 @@ +obj = new HTMLPurifier_AttrTransform_Name(); + } + + function test() { + $this->assertResult( array() ); + $this->assertResult( + array('name' => 'free'), + array('id' => 'free') + ); + $this->assertResult( + array('name' => 'tryit', 'id' => 'tobad'), + array('id' => 'tobad') + ); + } + +} + +?> \ No newline at end of file diff --git a/tests/HTMLPurifier/Strategy/ValidateAttributesTest.php b/tests/HTMLPurifier/Strategy/ValidateAttributesTest.php index 048369dd..7d800bab 100644 --- a/tests/HTMLPurifier/Strategy/ValidateAttributesTest.php +++ b/tests/HTMLPurifier/Strategy/ValidateAttributesTest.php @@ -172,6 +172,26 @@ class HTMLPurifier_Strategy_ValidateAttributesTest extends 'Invalid image' ); + // name rewritten as id + $this->assertResult( + '', + '', + array('HTML.EnableAttrID' => true) + ); + + // lengths + $this->assertResult( + '
', + '
' + ); + + // link types + $this->assertResult( + '
', + true, + array('Attr.AllowedRel' => 'nofollow') + ); + } } diff --git a/tests/test_files.php b/tests/test_files.php index 9a612181..c2fc532a 100644 --- a/tests/test_files.php +++ b/tests/test_files.php @@ -24,6 +24,7 @@ $test_files[] = 'AttrDef/HTML/LengthTest.php'; $test_files[] = 'AttrDef/HTML/MultiLengthTest.php'; $test_files[] = 'AttrDef/HTML/NmtokensTest.php'; $test_files[] = 'AttrDef/HTML/PixelsTest.php'; +$test_files[] = 'AttrDef/HTML/LinkTypesTest.php'; $test_files[] = 'AttrDef/IntegerTest.php'; $test_files[] = 'AttrDef/LangTest.php'; $test_files[] = 'AttrDef/TextTest.php'; @@ -34,8 +35,12 @@ $test_files[] = 'AttrDef/URI/IPv6Test.php'; $test_files[] = 'AttrDef/URITest.php'; $test_files[] = 'AttrDefTest.php'; $test_files[] = 'AttrTransform/BdoDirTest.php'; +$test_files[] = 'AttrTransform/BgColorTest.php'; +$test_files[] = 'AttrTransform/BorderTest.php'; $test_files[] = 'AttrTransform/ImgRequiredTest.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'; -- 2.11.4.GIT