mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2025-07-31 03:10:09 +02:00
Release 2.0.0, merged in 1026 to HEAD.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/branches/strict@1179 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
@@ -17,9 +17,12 @@
|
||||
<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,
|
||||
but as the user is always right, they'll need some method to overload
|
||||
these behaviors.</p>
|
||||
allowed elements, attributes, and behavior; specifically, this subset
|
||||
is the set of elements that are safe for untrusted users to use.
|
||||
However, HTML Purifier is often utilized to ensure standards-compliance
|
||||
from input that is trusted (making it a sort of Tidy substitute),
|
||||
and often users need to define new elements or attributes. The
|
||||
advanced API is oriented specifically for these use-cases.</p>
|
||||
|
||||
<p>Our goals are to let the user:</p>
|
||||
|
||||
@@ -27,20 +30,15 @@ these behaviors.</p>
|
||||
<dt>Select</dt>
|
||||
<dd><ul>
|
||||
<li>Doctype</li>
|
||||
<li>Mode: Lenient / Correctional</li>
|
||||
<!-- <li>Filterset</li> -->
|
||||
<li>Elements / Attributes / Modules</li>
|
||||
<li>Filterset</li>
|
||||
<li>Tidy</li>
|
||||
</ul></dd>
|
||||
<dt>Customize</dt>
|
||||
<dd><ul>
|
||||
<li>Attributes</li>
|
||||
<li>Elements</li>
|
||||
</ul></dd>
|
||||
<dt>Internals</dt>
|
||||
<dd><ul>
|
||||
<li>Modules / Elements / Attributes / Attribute Types</li>
|
||||
<li>Filtersets</li>
|
||||
<li>Doctype</li>
|
||||
<!--<li>Doctypes</li>-->
|
||||
</ul></dd>
|
||||
</dl>
|
||||
|
||||
@@ -68,136 +66,64 @@ 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.</p>
|
||||
|
||||
<h3>Selecting Mode</h3>
|
||||
|
||||
<p>Within doctypes, there are various <strong>modes</strong> of operation.
|
||||
These indicate variant behaviors that, while not strictly changing the
|
||||
allowed set of elements and attributes, definitely affect the output.
|
||||
Currently, we have two modes, which may be used together:</p>
|
||||
|
||||
<dl>
|
||||
<dt>Lenient</dt>
|
||||
<dd>
|
||||
<p>Deprecated elements and attributes will be transformed into
|
||||
standards-compliant alternatives when explicitly disallowed.</p>
|
||||
<p>For example, in the XHTML 1.0 Strict doctype, a <code>center</code>
|
||||
element would be turned into a <code>div</code> with the CSS property
|
||||
<code>text-align:center;</code>, but in XHTML 1.0 Transitional
|
||||
the element would be preserved.</p>
|
||||
<p>This mode is on by default.</p>
|
||||
</dd>
|
||||
<dt>Correctional[items to correct]</dt>
|
||||
<dd>
|
||||
<p>Deprecated elements and attributes will be transformed into
|
||||
standards-compliant alternatives whenever possible.
|
||||
It may have various levels of operation.</p>
|
||||
<p>Referring back to the previous example, the <code>center</code> element would
|
||||
be transformed in both cases. However, elements without a
|
||||
reasonable standards-compliant alternative will be preserved
|
||||
in their form.</p>
|
||||
<p>A user may want to correct certain deprecated attributes, but
|
||||
not others. For example, the <code>bgcolor</code> attribute may be
|
||||
acceptable, but the <code>center</code> 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.</p>
|
||||
<p>This mode is on by default.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<p>A possible call to select modes would be:</p>
|
||||
|
||||
<pre>$config->set('HTML', 'Mode', array('correctional', 'lenient'));</pre>
|
||||
|
||||
<p>If modes have extra parameters, a hash is necessary:</p>
|
||||
|
||||
<pre>$config->set('HTML', 'Mode', array(
|
||||
'correctional' => 'center,a.name',
|
||||
'lenient' => true // this one's just boolean
|
||||
));</pre>
|
||||
|
||||
<p>Modes may be specified along with the doctype declaration (we may want
|
||||
to get a better set of separator characters):</p>
|
||||
|
||||
<pre>$config->setDoctype('XHTML Transitional 1.0', '+correctional[center,a.name] -lenient');</pre>
|
||||
|
||||
<p>
|
||||
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 <code>center</code>
|
||||
element but not the <code>u</code> element, both of which are deprecated.
|
||||
Having an integer <q>level</q> will not work very well for such fine
|
||||
grained tweaking, but an array of specific settings might.</p>
|
||||
|
||||
<h3>Selecting Elements / Attributes / Modules</h3>
|
||||
|
||||
<p></p>
|
||||
<p>HTML Purifier will, by default, allow as many elements and attributes
|
||||
as possible. However, a user may decide to roll their own filterset by
|
||||
selecting modules, elements and attributes to allow for their own
|
||||
specific use-case. This can be done using %HTML.Allowed:</p>
|
||||
|
||||
<p>If this cookie cutter approach doesn't appeal to a user, they may
|
||||
decide to roll their own filterset by selecting modules, elements and
|
||||
attributes to allow.</p>
|
||||
<pre>$config->set('HTML', 'Allowed', 'a[href|title],em,p,blockquote');</pre>
|
||||
|
||||
<p class="technical">This would make use of the same facilities
|
||||
as a filterset author would use, except that it would go under an
|
||||
<q>anonymous</q> filterset that would be auto-selected if any of the
|
||||
relevant module/elements/attribute selection configuration directives were
|
||||
non-null.</p>
|
||||
<p class="technical">The directive %HTML.Allowed is a convenience feature
|
||||
that may be fully expressed with the legacy interface.</p>
|
||||
|
||||
<p>In practice, this is the most commonly demanded feature. Most users are
|
||||
perfectly happy defining a filterset that looks like:</p>
|
||||
|
||||
<pre>$config->setAllowedHTML('a[href,title];em;p;blockquote');</pre>
|
||||
|
||||
<p class="technical">The directive %HTML.Allowed is a convenience function
|
||||
that may be fully expressed with the legacy interface, and thus is
|
||||
given its own setter.</p>
|
||||
|
||||
<p>We currently support a separated interface, which also must be preserved:</p>
|
||||
<p>We currently support another interface from older versions:</p>
|
||||
|
||||
<pre>$config->set('HTML', 'AllowedElements', 'a,em,p,blockquote');
|
||||
$config->set('HTML', 'AllowedAttributes', 'a.href,a.title');</pre>
|
||||
|
||||
<p>A user may also choose to allow modules:</p>
|
||||
<p>A user may also choose to allow modules using a specialized
|
||||
directive:</p>
|
||||
|
||||
<pre>$config->set('HTML', 'AllowedModules', 'Hypertext,Text,Lists'); // or
|
||||
$config->setAllowedHTML('Hypertext,Text,Lists');</pre>
|
||||
<pre>$config->set('HTML', 'AllowedModules', 'Hypertext,Text,Lists');</pre>
|
||||
|
||||
<p>But it is not expected that this feature will be widely used.</p>
|
||||
|
||||
<p class="fixme">The granularity of these modules is too coarse for
|
||||
the average user (for example, the core module loads everything from
|
||||
the essential <code>p</code> element to the not-so-safe <code>h1</code>
|
||||
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.</p>
|
||||
<p class="technical">Module selection will work slightly differently
|
||||
from the other AllowedElements and AllowedAttributes directives by
|
||||
directly modifying the doctype you are operating in, in the spirit of
|
||||
XHTML 1.1's modularization. We stop users from shooting themselves in the
|
||||
foot by mandating the modules in %HTML.CoreModules be used.</p>
|
||||
|
||||
<p class="technical">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
|
||||
lower and uppercase letters in element names, XHTML uses only lower-case
|
||||
element names for sake of consistency.</p>
|
||||
|
||||
<p class="technical">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.</p>
|
||||
<h3>Selecting Tidy</h3>
|
||||
|
||||
<p>The name of this segment of functionality is inspired off of Dave
|
||||
Ragget's program HTML Tidy, which purported to help clean up HTML. In
|
||||
HTML Purifier, Tidy functionality involves turning unsupported and
|
||||
deprecated elements into standards-compliant ones, maintaining
|
||||
backwards compatibility, and enforcing best practices.</p>
|
||||
|
||||
<p>This is a complicated feature, and is explained more in depth at
|
||||
<a href="enduser-tidy.html">the Tidy documentation page</a>.</p>
|
||||
|
||||
<!--
|
||||
<h3>Unified selector</h3>
|
||||
|
||||
<p>Because selecting each and every one of these configuration options
|
||||
is a chore, we may wish to offer a specialized configuration method
|
||||
for selecting a filterset. Possibility:</p>
|
||||
|
||||
<pre>function selectFilter($doctype, $filterset, $mode)</pre>
|
||||
<pre>function selectFilter($doctype, $filterset, $tidy)</pre>
|
||||
|
||||
<p>...which is simply a light wrapper over the individual configuration
|
||||
calls. A custom config file format or text format could also be adopted.</p>
|
||||
-->
|
||||
|
||||
<h2>Customize</h2>
|
||||
|
||||
@@ -209,38 +135,34 @@ use-cases.</p>
|
||||
|
||||
<p>Note that the functions described here are only available if
|
||||
a raw copy of <code>HTMLPurifier_HTMLDefinition</code> was retrieved.
|
||||
<code>addAttribute</code> may work on a processed copy, but for
|
||||
consistency's sake we will mandate this for everything.</p>
|
||||
Furthermore, caching may prevent your changes from immediately
|
||||
being seen: consult <a href="enduser-customize.html">enduser-customize.html</a> on how
|
||||
to work around this.</p>
|
||||
|
||||
<h3>Attributes</h3>
|
||||
|
||||
<p>An attribute is bound to an element by a name and has a specific
|
||||
<code>AttrDef</code> that validates it. Thus, the interface should
|
||||
be:</p>
|
||||
<code>AttrDef</code> that validates it. The interface is therefore:</p>
|
||||
|
||||
<pre>function addAttribute($element, $attribute, $attribute_def);</pre>
|
||||
|
||||
<p>With a use-case that looks like:</p>
|
||||
<p>Example of the functionality in action:</p>
|
||||
|
||||
<pre>$def->addAttribute('a', 'rel', new HTMLPurifier_AttrDef_Enum(array('nofollow')));</pre>
|
||||
<pre>$def->addAttribute('a', 'rel', 'Enum#nofollow');</pre>
|
||||
|
||||
<p>The <code>$attribute_def</code> value can be a little flexible,
|
||||
to make things simpler. We'll let it also be:</p>
|
||||
<p>The <code>$attribute_def</code> value is flexible,
|
||||
to make things simpler. It can be a literal object or:</p>
|
||||
|
||||
<ul>
|
||||
<li>Class name: We'll instantiate it for you</li>
|
||||
<!--<li>Class name: We'll instantiate it for you</li>
|
||||
<li>Function name: We'll create an <code>HTMLPurifier_AttrDef_Anonymous</code>
|
||||
class with that function registered as a callback.</li>
|
||||
class with that function registered as a callback.</li>-->
|
||||
<li>String attribute type: We'll use <code>HTMLPurifier_AttrTypes</code>
|
||||
</li>
|
||||
<li>String starting with <code>enum(</code>: We'll explode it and stuff it in an
|
||||
<code>HTMLPurifier_AttrDef_Enum</code> for you.</li>
|
||||
to resolve it for you. Any data that follows a hash mark (#) will
|
||||
be used to customize the attribute type: in the example above,
|
||||
we specify which values for Enum to allow.</li>
|
||||
</ul>
|
||||
|
||||
<p>Making the previous example written as:</p>
|
||||
|
||||
<pre>$def->addAttribute('a', 'rel', 'enum(nofollow)');</pre>
|
||||
|
||||
<h3>Elements</h3>
|
||||
|
||||
<p>An element requires certain information as specified by
|
||||
@@ -255,7 +177,8 @@ the usual things required are:</p>
|
||||
|
||||
<p>This suggests an API like this:</p>
|
||||
|
||||
<pre>function addElement($element, $type, $content_model, $attributes = array());</pre>
|
||||
<pre>function addElement($element, $type, $contents,
|
||||
$attr_collections = array(); $attributes = array());</pre>
|
||||
|
||||
<p>Each parameter explained in depth:</p>
|
||||
|
||||
@@ -264,11 +187,15 @@ the usual things required are:</p>
|
||||
<dd>Element name, ex. 'label'</dd>
|
||||
<dt><code>$type</code></dt>
|
||||
<dd>Content set to register in, ex. 'Inline' or 'Flow'</dd>
|
||||
<dt><code>$content_model</code></dt>
|
||||
<dt><code>$contents</code></dt>
|
||||
<dd>Description of allowed children. This is a merged form of
|
||||
<code>HTMLPurifier_ElementDef</code>'s member variables
|
||||
<code>$content_model</code> and <code>$content_model_type</code>,
|
||||
where the form is <q>Type: Model</q>, ex. 'Optional: Inline'.</dd>
|
||||
where the form is <q>Type: Model</q>, ex. 'Optional: Inline'.
|
||||
There are also a number of predefined templates one may use.</dd>
|
||||
<dt><code>$attr_collections</code></dt>
|
||||
<dd>Array (or string if only one) of attribute collection(s) to
|
||||
merge into the attributes array.</dd>
|
||||
<dt><code>$attributes</code></dt>
|
||||
<dd>Array of attribute names to attribute definitions, much like
|
||||
the above-described attribute customization.</dd>
|
||||
@@ -276,11 +203,10 @@ the usual things required are:</p>
|
||||
|
||||
<p>A possible usage:</p>
|
||||
|
||||
<pre>$def->addElement('font', 'Inline', 'Optional: Inline',
|
||||
array(0 => array('Common'), 'color' => 'Color'));</pre>
|
||||
<pre>$def->addElement('font', 'Inline', 'Optional: Inline', 'Common',
|
||||
array('color' => 'Color'));</pre>
|
||||
|
||||
<p>We may want to Common attribute collection inclusion to be added
|
||||
by default.</p>
|
||||
<p>See <code>HTMLPurifier/HTMLModule.php</code> for details.</p>
|
||||
|
||||
<div id="version">$Id$</div>
|
||||
|
||||
|
791
docs/enduser-customize.html
Normal file
791
docs/enduser-customize.html
Normal file
@@ -0,0 +1,791 @@
|
||||
<?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="Tutorial for customizing HTML Purifier's tag and attribute sets." />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
|
||||
<title>Customize - HTML Purifier</title>
|
||||
|
||||
</head><body>
|
||||
|
||||
<h1 class="subtitled">Customize!</h1>
|
||||
<div class="subtitle">HTML Purifier is a Swiss-Army Knife</div>
|
||||
|
||||
<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://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
|
||||
|
||||
<div id="applicability">
|
||||
This document covers currently unreleased functionality and
|
||||
only applies to recent SVN checkouts.
|
||||
</div>
|
||||
|
||||
<p>
|
||||
You may have heard of the <a href="dev-advanced-api.html">Advanced API</a>.
|
||||
If you're interested in reading dry prose and boring functional
|
||||
specifications, feel free to click that link to get a no-nonsense overview
|
||||
on the Advanced API. For the rest of us, there's this tutorial. By the time
|
||||
you're finished reading this, you should have a pretty good idea on
|
||||
how to implement custom tags and attributes that HTML Purifier may not have.
|
||||
</p>
|
||||
|
||||
<h2>Is it necessary?</h2>
|
||||
|
||||
<p>
|
||||
Before we even write any code, it is paramount to consider whether or
|
||||
not the code we're writing is necessary or not. HTML Purifier, by default,
|
||||
contains a large set of elements and attributes: large enough so that
|
||||
<em>any</em> element or attribute in XHTML 1.0 (and its HTML variant)
|
||||
that can be safely used by the general public is implemented.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
So what needs to be implemented? (Feel free to skip this section if
|
||||
you know what you want).
|
||||
</p>
|
||||
|
||||
<h3>XHTML 1.0</h3>
|
||||
|
||||
<p>
|
||||
All of the modules listed below are based off of the
|
||||
<a href="http://www.w3.org/TR/2001/REC-xhtml-modularization-20010410/abstract_modules.html#sec_5.2.">modularization of
|
||||
XHTML</a>, which, while technically for XHTML 1.1, is quite a useful
|
||||
resource.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Structure</li>
|
||||
<li>Frames</li>
|
||||
<li>Applets (deprecated)</li>
|
||||
<li>Forms</li>
|
||||
<li>Image maps</li>
|
||||
<li>Objects</li>
|
||||
<li>Frames</li>
|
||||
<li>Events</li>
|
||||
<li>Meta-information</li>
|
||||
<li>Style sheets</li>
|
||||
<li>Link (not hypertext)</li>
|
||||
<li>Base</li>
|
||||
<li>Name</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If you don't recognize it, you probably don't need it. But the curious
|
||||
can look all of these modules up in the above-mentioned document. Note
|
||||
that inline scripting comes packaged with HTML Purifier (more on this
|
||||
later).
|
||||
</p>
|
||||
|
||||
<h3>XHTML 1.1</h3>
|
||||
|
||||
<p>
|
||||
We have not implemented the
|
||||
<a href="http://www.w3.org/TR/2001/REC-ruby-20010531/">Ruby module</a>,
|
||||
which defines a set of tags
|
||||
for publishing short annotations for text, used mostly in Japanese
|
||||
and Chinese school texts.
|
||||
</p>
|
||||
|
||||
<h3>XHTML 2.0</h3>
|
||||
|
||||
<p>
|
||||
<a href="http://www.w3.org/TR/xhtml2/">XHTML 2.0</a> is still a
|
||||
working draft, so any elements introduced in the
|
||||
specification have not been implemented and will not be implemented
|
||||
until we get a recommendation or proposal. Because XHTML 2.0 is
|
||||
an entirely new markup language, implementing rules for it will be
|
||||
no easy task.
|
||||
</p>
|
||||
|
||||
<h3>HTML 5</h3>
|
||||
|
||||
<p>
|
||||
<a href="http://www.whatwg.org/specs/web-apps/current-work/">HTML 5</a>
|
||||
is a fork of HTML 4.01 by WHATWG, who believed that XHTML 2.0 was headed
|
||||
in the wrong direction. It too is a working draft, and may change
|
||||
drastically before publication, but it should be noted that the
|
||||
<code>canvas</code> tag has been implemented by many browser vendors.
|
||||
</p>
|
||||
|
||||
<h3>Proprietary</h3>
|
||||
|
||||
<p>
|
||||
There are a number of proprietary tags still in the wild. Many of them
|
||||
have been documented in <a href="ref-proprietary-tags.txt">ref-proprietary-tags.txt</a>,
|
||||
but there is currently no implementation for any of them.
|
||||
</p>
|
||||
|
||||
<h3>Extensions</h3>
|
||||
|
||||
<p>
|
||||
There are also a number of other XML languages out there that can
|
||||
be embedded in HTML documents: two of the most popular are MathML and
|
||||
SVG, and I frequently get requests to implement these. But they are
|
||||
expansive, comprehensive specifications, and it would take far too long
|
||||
to implement them <em>correctly</em> (most systems I've seen go as far
|
||||
as whitelisting tags and no further; come on, what about nesting!)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Word of warning: HTML Purifier is currently <em>not</em> namespace
|
||||
aware.
|
||||
</p>
|
||||
|
||||
<h2>Giving back</h2>
|
||||
|
||||
<p>
|
||||
As you may imagine from the details above (don't be abashed if you didn't
|
||||
read it all: a glance over would have done), there's quite a bit that
|
||||
HTML Purifier doesn't implement. Recent architectural changes have
|
||||
allowed HTML Purifier to implement elements and attributes that are not
|
||||
safe! Don't worry, they won't be activated unless you set %HTML.Trusted
|
||||
to true, but they certainly help out users who need to put, say, forms
|
||||
on their page and don't want to go through the trouble of reading this
|
||||
and implementing it themself.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
So any of the above that you implement for your own application could
|
||||
help out some other poor sap on the other side of the globe. Help us
|
||||
out, and send back code so that it can be hammered into a module and
|
||||
released with the core. Any code would be greatly appreciated!
|
||||
</p>
|
||||
|
||||
<h2>And now...</h2>
|
||||
|
||||
<p>
|
||||
Enough philosophical talk, time for some code:
|
||||
</p>
|
||||
|
||||
<pre>$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
|
||||
$config->set('HTML', 'DefinitionRev', 1);
|
||||
$def =& $config->getHTMLDefinition(true);</pre>
|
||||
|
||||
<p>
|
||||
Assuming that HTML Purifier has already been properly loaded (hint:
|
||||
include <code>HTMLPurifier.auto.php</code>), this code will set up
|
||||
the environment that you need to start customizing the HTML definition.
|
||||
What's going on?
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
The first three lines are regular configuration code:
|
||||
<ul>
|
||||
<li>
|
||||
%HTML.DefinitionID is set to a unique identifier for your
|
||||
custom HTML definition. This prevents it from clobbering
|
||||
other custom definitions on the same installation.
|
||||
</li>
|
||||
<li>
|
||||
%HTML.DefinitionRev is a revision integer of your HTML
|
||||
definition. Because HTML definitions are cached, you'll need
|
||||
to increment this whenever you make a change in order to flush
|
||||
the cache.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
The fourth line retrieves a raw <code>HTMLPurifier_HTMLDefinition</code>
|
||||
object that we will be tweaking. If the parameter was removed, we
|
||||
would be retrieving a fully formed definition object, which is somewhat
|
||||
useless for customization purposes.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Broken backwards-compatibility</h3>
|
||||
|
||||
<p>
|
||||
Those of you who have already been twiddling around with the raw
|
||||
HTML definition object, you'll be noticing that you're getting an error
|
||||
when you attempt to retrieve the raw definition object without specifying
|
||||
a DefinitionID. It is vital to caching (see below) that you make a unique
|
||||
name for your customized definition, so make up something right now and
|
||||
things will operate again.
|
||||
</p>
|
||||
|
||||
<h2>Turn off caching</h2>
|
||||
|
||||
<p>
|
||||
To make development easier, we're going to temporarily turn off
|
||||
definition caching:
|
||||
</p>
|
||||
|
||||
<pre>$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
|
||||
$config->set('HTML', 'DefinitionRev', 1);
|
||||
<strong>$config->set('Core', 'DefinitionCache', null); // remove this later!</strong>
|
||||
$def =& $config->getHTMLDefinition(true);</pre>
|
||||
|
||||
<p>
|
||||
A few things should be mentioned about the caching mechanism before
|
||||
we move on. For performance reasons, HTML Purifier caches generated
|
||||
<code>HTMLPurifier_Definition</code> objects in serialized files
|
||||
stored (by default) in <code>library/HTMLPurifier/DefinitionCache/Serializer</code>.
|
||||
A lot of processing is done in order to create these objects, so it
|
||||
makes little sense to repeat the same processing over and over again
|
||||
whenever HTML Purifier is called.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In order to identify a cache entry, HTML Purifier uses three variables:
|
||||
the library's version number, the value of %HTML.DefinitionRev and
|
||||
a serial of relevant configuration. Whenever any of these changes,
|
||||
a new HTML definition is generated. Notice that there is no way
|
||||
for the definition object to track changes to customizations: here, it
|
||||
is up to you to supply appropriate information to DefinitionID and
|
||||
DefinitionRev.
|
||||
</p>
|
||||
|
||||
<h2 id="addAttribute">Add an attribute</h2>
|
||||
|
||||
<p>
|
||||
For this example, we're going to implement the <code>target</code> attribute found
|
||||
on <code>a</code> elements. To implement an attribute, we have to
|
||||
ask a few questions:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>What element is it found on?</li>
|
||||
<li>What is its name?</li>
|
||||
<li>Is it required or optional?</li>
|
||||
<li>What are valid values for it?</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
The first three are easy: the element is <code>a</code>, the attribute
|
||||
is <code>target</code>, and it is not a required attribute. (If it
|
||||
was required, we'd need to append an asterisk to the attribute name,
|
||||
you'll see an example of this in the addElement() example).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The last question is a little trickier.
|
||||
Lets allow the special values: _blank, _self, _target and _top.
|
||||
The form of this is called an <strong>enumeration</strong>, a list of
|
||||
valid values, although only one can be used at a time. To translate
|
||||
this into code form, we write:
|
||||
</p>
|
||||
|
||||
<pre>$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
|
||||
$config->set('HTML', 'DefinitionRev', 1);
|
||||
$config->set('Core', 'DefinitionCache', null); // remove this later!
|
||||
$def =& $config->getHTMLDefinition(true);
|
||||
<strong>$def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');</strong></pre>
|
||||
|
||||
<p>
|
||||
The <code>Enum#_blank,_self,_target,_top</code> does all the magic.
|
||||
The string is split into two parts, separated by a hash mark (#):
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>The first part is the name of what we call an <code>AttrDef</code></li>
|
||||
<li>The second part is the parameter of the above-mentioned <code>AttrDef</code></li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
If that sounds vague and generic, it's because it is! HTML Purifier defines
|
||||
an assortment of different attribute types one can use, and each of these
|
||||
has their own specialized parameter format. Here are some of the more useful
|
||||
ones:
|
||||
</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Format</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Enum</th>
|
||||
<td><em>[s:]</em>value1,value2,...</td>
|
||||
<td>
|
||||
Attribute with a number of valid values, one of which may be used. When
|
||||
s: is present, the enumeration is case sensitive.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Bool</th>
|
||||
<td>attribute_name</td>
|
||||
<td>
|
||||
Boolean attribute, with only one valid value: the name
|
||||
of the attribute.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>CDATA</th>
|
||||
<td></td>
|
||||
<td>
|
||||
Attribute of arbitrary text. Can also be referred to as <strong>Text</strong>
|
||||
(the specification makes a semantic distinction between the two).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<td></td>
|
||||
<td>
|
||||
Attribute that specifies a unique ID
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Pixels</th>
|
||||
<td></td>
|
||||
<td>
|
||||
Attribute that specifies an integer pixel length
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Length</th>
|
||||
<td></td>
|
||||
<td>
|
||||
Attribute that specifies a pixel or percentage length
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>NMTOKENS</th>
|
||||
<td></td>
|
||||
<td>
|
||||
Attribute that specifies a number of name tokens, example: the
|
||||
<code>class</code> attribute
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>URI</th>
|
||||
<td></td>
|
||||
<td>
|
||||
Attribute that specifies a URI, example: the <code>href</code>
|
||||
attribute
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Number</th>
|
||||
<td></td>
|
||||
<td>
|
||||
Attribute that specifies an positive integer number
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
For a complete list, consult
|
||||
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/AttrTypes.php"><code>library/HTMLPurifier/AttrTypes.php</code></a>;
|
||||
more information on attributes that accept parameters can be found on their
|
||||
respective includes in
|
||||
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/AttrDef/"><code>library/HTMLPurifier/AttrDef</code></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Sometimes, the restrictive list in AttrTypes just doesn't cut it. Don't
|
||||
sweat: you can also use a fully instantiated object as the value. The
|
||||
equivalent, verbose form of the above example is:
|
||||
</p>
|
||||
|
||||
<pre>$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
|
||||
$config->set('HTML', 'DefinitionRev', 1);
|
||||
$config->set('Core', 'DefinitionCache', null); // remove this later!
|
||||
$def =& $config->getHTMLDefinition(true);
|
||||
<strong>$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
|
||||
array('_blank','_self','_target','_top')
|
||||
));</strong></pre>
|
||||
|
||||
<p>
|
||||
Trust me, you'll learn to love the shorthand.
|
||||
</p>
|
||||
|
||||
<h2>Add an element</h2>
|
||||
|
||||
<p>
|
||||
Adding attributes is really small-fry stuff, though, and it was possible
|
||||
to add them (albeit a bit more wordy) prior to 2.0. The real gem of
|
||||
the Advanced API is adding elements. There are five questions to
|
||||
ask when adding a new element:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>What is the element's name?</li>
|
||||
<li>What content set does this element belong to?</li>
|
||||
<li>What are the allowed children of this element?</li>
|
||||
<li>What attributes does the element allow that are general?</li>
|
||||
<li>What attributes does the element allow that are specific to this element?</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
It's a mouthful, and you'll be slightly lost if your not familiar with
|
||||
the HTML specification, so let's explain them step by step.
|
||||
</p>
|
||||
|
||||
<h3>Content set</h3>
|
||||
|
||||
<p>
|
||||
The HTML specification defines two major content sets: Inline
|
||||
and Block. Each of these
|
||||
content sets contain a list of elements: Inline contains things like
|
||||
<code>span</code> and <code>b</code> while Block contains things like
|
||||
<code>div</code> and <code>blockquote</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
These content sets amount to a macro mechanism for HTML definition. Most
|
||||
elements in HTML are organized into one of these two sets, and most
|
||||
elements in HTML allow elements from one of these sets. If we had
|
||||
to write each element verbatim into each other element's allowed
|
||||
children, we would have ridiculously large lists; instead we use
|
||||
content sets to compactify the declaration.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Practically speaking, there are several useful values you can use here:
|
||||
</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Content set</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Inline</th>
|
||||
<td>Character level elements, text</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Block</th>
|
||||
<td>Block-like elements, like paragraphs and lists</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><em>false</em></th>
|
||||
<td>
|
||||
Any element that doesn't fit into the mold, for example <code>li</code>
|
||||
or <code>tr</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
By specifying a valid value here, all other elements that use that
|
||||
content set will also allow your element, without you having to do
|
||||
anything. If you specify <em>false</em>, you'll have to register
|
||||
your element manually.
|
||||
</p>
|
||||
|
||||
<h3>Allowed children</h3>
|
||||
|
||||
<p>
|
||||
Allowed children defines the elements that this element can contain.
|
||||
The allowed values may range from none to a complex regexp depending on
|
||||
your element.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you've ever taken a look at the HTML DTD's before, you may have
|
||||
noticed declarations like this:
|
||||
</p>
|
||||
|
||||
<pre><!ELEMENT LI - O (%flow;)* -- list item --></pre>
|
||||
|
||||
<p>
|
||||
The <code>(%flow;)*</code> indicates the allowed children of the
|
||||
<code>li</code> tag: <code>li</code> allows any number of flow
|
||||
elements as its children. In HTML Purifier, we'd write it like
|
||||
<code>Flow</code> (here's where the content sets we were
|
||||
discussing earlier come into play). There are three shorthand content models you
|
||||
can specify:
|
||||
</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Content model</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Empty</th>
|
||||
<td>No children allowed, like <code>br</code> or <code>hr</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Inline</th>
|
||||
<td>Any number of inline elements and text, like <code>span</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Flow</th>
|
||||
<td>Any number of inline elements, block elements and text, like <code>div</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
This covers 90% of all the cases out there, but what about elements that
|
||||
break the mold like <code>ul</code>? This guy requires at least one
|
||||
child, and the only valid children for it are <code>li</code>. The
|
||||
content model is: <code>Required: li</code>. There are two parts: the
|
||||
first type determines what <code>ChildDef</code> will be used to validate
|
||||
content models. The most common values are:
|
||||
</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Required</th>
|
||||
<td>Children must be one or more of the valid elements</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Optional</th>
|
||||
<td>Children can be any number of the valid elements</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Custom</th>
|
||||
<td>Children must follow the DTD-style regex</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
You can also implement your own <code>ChildDef</code>: this was done
|
||||
for a few special cases in HTML Purifier such as <code>Chameleon</code>
|
||||
(for <code>ins</code> and <code>del</code>), <code>StrictBlockquote</code>
|
||||
and <code>Table</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The second part specifies either valid elements or a regular expression.
|
||||
Valid elements are separated with horizontal bars (|), i.e.
|
||||
"<code>a | b | c</code>". Use #PCDATA to represent plain text.
|
||||
Regular expressions are based off of DTD's style:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Parentheses () are used for grouping</li>
|
||||
<li>Commas (,) separate elements that should come one after another</li>
|
||||
<li>Horizontal bars (|) indicate one or the other elements should be used</li>
|
||||
<li>Plus signs (+) are used for a one or more match</li>
|
||||
<li>Asterisks (*) are used for a zero or more match</li>
|
||||
<li>Question marks (?) are used for a zero or one match</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
For example, "<code>a, b?, (c | d), e+, f*</code>" means "In this order,
|
||||
one <code>a</code> element, at most one <code>b</code> element,
|
||||
one <code>c</code> or <code>d</code> element (but not both), one or more
|
||||
<code>e</code> elements, and any number of <code>f</code> elements."
|
||||
Regex veterans should be able to jump right in, and those not so savvy
|
||||
can always copy-paste W3C's content model definitions into HTML Purifier
|
||||
and hope for the best.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A word of warning: while the regex format is extremely flexible on
|
||||
the developer's side, it is
|
||||
quite unforgiving on the user's side. If the user input does not <em>exactly</em>
|
||||
match the specification, the entire contents of the element will
|
||||
be nuked. This is why there is are specific content model types like
|
||||
Optional and Required: while they could be implemented as <code>Custom:
|
||||
(valid | elements)*</code>, the custom classes contain special recovery
|
||||
measures that make sure as much of the user's original content gets
|
||||
through. HTML Purifier's core, as a rule, does not use Custom.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One final note: you can also use Content Sets inside your valid elements
|
||||
lists or regular expressions. In fact, the three shorthand content models
|
||||
mentioned above are just that: abbreviations:
|
||||
</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Content model</th>
|
||||
<th>Implementation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Inline</th>
|
||||
<td>Optional: Inline | #PCDATA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Flow</th>
|
||||
<td>Optional: Flow | #PCDATA</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
When the definition is compiled, Inline will be replaced with a
|
||||
horizontal-bar separated list of inline elements. Also, notice that
|
||||
it does not contain text: you have to specify that yourself.
|
||||
</p>
|
||||
|
||||
<h3>Common attributes</h3>
|
||||
|
||||
<p>
|
||||
Congratulations: you have just gotten over the proverbial hump (Allowed
|
||||
children). Common attributes is much simpler, and boils down to
|
||||
one question: does your element have the <code>id</code>, <code>style</code>,
|
||||
<code>class</code>, <code>title</code> and <code>lang</code> attributes?
|
||||
If so, you'll want to specify the <code>Common</code> attribute collection,
|
||||
which contains these five attributes that are found on almost every
|
||||
HTML element in the specification.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There are a few more collections, but they're really edge cases:
|
||||
</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Collection</th>
|
||||
<th>Attributes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>I18N</th>
|
||||
<td><code>lang</code>, possibly <code>xml:lang</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Core</th>
|
||||
<td><code>style</code>, <code>class</code>, <code>id</code> and <code>title</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
Common is a combination of the above-mentioned collections.
|
||||
</p>
|
||||
|
||||
<h3>Attributes</h3>
|
||||
|
||||
<p>
|
||||
If you didn't read the <a href="#addAttribute">previous section on
|
||||
adding attributes</a>, read it now. The last parameter is simply
|
||||
array of attribute names to attribute implementations, in the exact
|
||||
same format as <code>addAttribute()</code>.
|
||||
</p>
|
||||
|
||||
<h3>Putting it all together</h3>
|
||||
|
||||
<p>
|
||||
We're going to implement <code>form</code>. Before we embark, lets
|
||||
grab a reference implementation from over at the
|
||||
<a href="http://www.w3.org/TR/html4/sgml/loosedtd.html">transitional DTD</a>:
|
||||
</p>
|
||||
|
||||
<pre><!ELEMENT FORM - - (%flow;)* -(FORM) -- interactive form -->
|
||||
<!ATTLIST FORM
|
||||
%attrs; -- %coreattrs, %i18n, %events --
|
||||
action %URI; #REQUIRED -- server-side form handler --
|
||||
method (GET|POST) GET -- HTTP method used to submit the form--
|
||||
enctype %ContentType; "application/x-www-form-urlencoded"
|
||||
accept %ContentTypes; #IMPLIED -- list of MIME types for file upload --
|
||||
name CDATA #IMPLIED -- name of form for scripting --
|
||||
onsubmit %Script; #IMPLIED -- the form was submitted --
|
||||
onreset %Script; #IMPLIED -- the form was reset --
|
||||
target %FrameTarget; #IMPLIED -- render in this frame --
|
||||
accept-charset %Charsets; #IMPLIED -- list of supported charsets --
|
||||
></pre>
|
||||
|
||||
<p>
|
||||
Juicy! With just this, we can answer four of our five questions:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>What is the element's name? <strong>form</strong></li>
|
||||
<li>What content set does this element belong to? <strong>Block</strong>
|
||||
(this needs a little sleuthing, I find the easiest way is to search
|
||||
the DTD for <code>FORM</code> and determine which set it is in.)</li>
|
||||
<li>What are the allowed children of this element? <strong>One
|
||||
or more flow elements, but no nested <code>form</code>s</strong></li>
|
||||
<li>What attributes does the element allow that are general? <strong>Common</strong></li>
|
||||
<li>What attributes does the element allow that are specific to this element? <strong>A whole bunch, see ATTLIST;
|
||||
we're going to the vital ones: <code>action</code>, <code>method</code> and <code>name</code></strong></li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
Time for some code:
|
||||
</p>
|
||||
|
||||
<pre>$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
|
||||
$config->set('HTML', 'DefinitionRev', 1);
|
||||
$config->set('Core', 'DefinitionCache', null); // remove this later!
|
||||
$def =& $config->getHTMLDefinition(true);
|
||||
$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
|
||||
array('_blank','_self','_target','_top')
|
||||
));
|
||||
<strong>$form =& $def->addElement(
|
||||
'form', // name
|
||||
'Block', // content set
|
||||
'Flow', // allowed children
|
||||
'Common', // attribute collection
|
||||
array( // attributes
|
||||
'action*' => 'URI',
|
||||
'method' => 'Enum#get|post',
|
||||
'name' => 'ID'
|
||||
)
|
||||
);
|
||||
$form->excludes = array('form' => true);</strong></pre>
|
||||
|
||||
<p>
|
||||
Each of the parameters corresponds to one of the questions we asked.
|
||||
Notice that we added an asterisk to the end of the <code>action</code>
|
||||
attribute to indicate that it is required. If someone specifies a
|
||||
<code>form</code> without that attribute, the tag will be axed.
|
||||
Also, the extra line at the end is a special extra declaration that
|
||||
prevents forms from being nested within each other.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
And that's all there is to it! Implementing the rest of the form
|
||||
module is left as an exercise to the user; to see more examples
|
||||
check the <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/HTMLModule/"><code>library/HTMLPurifier/HTMLModule/</code></a> directory
|
||||
in your local HTML Purifier installation.
|
||||
</p>
|
||||
|
||||
<h2>And beyond...</h2>
|
||||
|
||||
<p>
|
||||
Perceptive users may have realized that, to a certain extent, we
|
||||
have simply re-implemented the facilities of XML Schema or the
|
||||
Document Type Definition. What you are seeing here, however, is
|
||||
not just an XML Schema or Document Type Definition: it is a fully
|
||||
expressive method of specifying the definition of HTML that is
|
||||
a portable superset of the capabilities of the two above-mentioned schema
|
||||
languages. What makes HTMLDefinition so powerful is the fact that
|
||||
if we don't have an implementation for a content model or an attribute
|
||||
definition, you can supply it yourself by writing a PHP class.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There are many facets of HTMLDefinition beyond the Advanced API I have
|
||||
walked you through today. To find out more about these, you can
|
||||
check out these source files:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/HTMLModule.php"><code>library/HTMLPurifier/HTMLModule.php</code></a></li>
|
||||
<li><a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/ElementDef.php"><code>library/HTMLPurifier/ElementDef.php</code></a></li>
|
||||
</ul>
|
||||
|
||||
<div id="version">$Id: enduser-tidy.html 1158 2007-06-18 19:26:29Z Edward $</div>
|
||||
|
||||
</body></html>
|
@@ -8,15 +8,11 @@ to be effective. Things to remember:
|
||||
|
||||
1. Character Encoding: see enduser-utf8.html for more info.
|
||||
|
||||
2. Doctype: document pending feature completion
|
||||
Not strictly necessary, actually. More in-depth discussion once we figure
|
||||
out how to get strict loose mode working.
|
||||
2. IDs: see enduser-id.html for more info
|
||||
|
||||
3. IDs: see enduser-id.html for more info
|
||||
|
||||
4. Links: document pending feature completion
|
||||
3. Links: document pending feature completion
|
||||
Rudimentary blacklisting, we should also allow only relative URIs. We
|
||||
need a doc to explain the stuff.
|
||||
|
||||
5. CSS: document pending
|
||||
4. CSS: document pending
|
||||
Explain which CSS styles we blocked and why.
|
||||
|
235
docs/enduser-tidy.html
Normal file
235
docs/enduser-tidy.html
Normal file
@@ -0,0 +1,235 @@
|
||||
<?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="Tutorial for tweaking HTML Purifier's Tidy-like behavior." />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
|
||||
<title>Tidy - HTML Purifier</title>
|
||||
|
||||
</head><body>
|
||||
|
||||
<h1>Tidy</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://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
|
||||
|
||||
<div id="applicability">
|
||||
This document covers currently unreleased functionality and
|
||||
only applies to recent SVN checkouts.
|
||||
</div>
|
||||
|
||||
<p>You've probably heard of HTML Tidy, Dave Raggett's little piece
|
||||
of software that cleans up poorly written HTML. Let me say it straight
|
||||
out:</p>
|
||||
|
||||
<p class="emphasis">This ain't HTML Tidy!</p>
|
||||
|
||||
<p>Rather, Tidy stands for a cool set of Tidy-inspired in HTML Purifier
|
||||
that allows users to submit deprecated elements and attributes and get
|
||||
valid strict markup back. For example:</p>
|
||||
|
||||
<pre><center>Centered</center></pre>
|
||||
|
||||
<p>...becomes:</p>
|
||||
|
||||
<pre><div style="text-align:center;">Centered</div></pre>
|
||||
|
||||
<p>...when this particular fix is run on the HTML. This tutorial will give
|
||||
you down the lowdown of what exactly HTML Purifier will do when Tidy
|
||||
is on, and how to fine tune this behavior. Once again, <strong>you do
|
||||
not need Tidy installed on your PHP to use these features!</strong></p>
|
||||
|
||||
<h2>What does it do?</h2>
|
||||
|
||||
<p>Tidy will do several things to your HTML:</p>
|
||||
|
||||
<ul>
|
||||
<li>Convert deprecated elements and attributes to standards-compliant
|
||||
alternatives</li>
|
||||
<li>Enforce XHTML compatibility guidelines and other best practices</li>
|
||||
<li>Preserve data that would normally be removed as per W3C</li>
|
||||
</ul>
|
||||
|
||||
<h2>What are levels?</h2>
|
||||
|
||||
<p>Levels describe how aggressive the Tidy module should be when
|
||||
cleaning up HTML. There are four levels to pick: none, light, medium
|
||||
and heavy. Each of these levels has a well-defined set of behavior
|
||||
associated with it, although it may change depending on your doctype.</p>
|
||||
|
||||
<dl>
|
||||
<dt>light</dt>
|
||||
<dd>This is the <strong>lenient</strong> level. If a tag or attribute
|
||||
is about to be removed because it isn't supported by the
|
||||
doctype, Tidy will step in and change into an alternative that
|
||||
is supported.</dd>
|
||||
<dt>medium</dt>
|
||||
<dd>This is the <strong>correctional</strong> level. At this level,
|
||||
all the functions of light are performed, as well as some extra,
|
||||
non-essential best practices enforcement. Changes made on this
|
||||
level are very benign and are unlikely to cause problems.</dd>
|
||||
<dt>heavy</dt>
|
||||
<dd>This is the <strong>aggressive</strong> level. If a tag or
|
||||
attribute is deprecated, it will be converted into a non-deprecated
|
||||
version, no ifs ands or buts.</dd>
|
||||
</dl>
|
||||
|
||||
<p>By default, Tidy operates on the <strong>medium</strong> level. You can
|
||||
change the level of cleaning by setting the %HTML.TidyLevel configuration
|
||||
directive:</p>
|
||||
|
||||
<pre>$config->set('HTML', 'TidyLevel', 'heavy'); // burn baby burn!</pre>
|
||||
|
||||
<h2>Is the light level really light?</h2>
|
||||
|
||||
<p>It depends on what doctype you're using. If your documents are HTML
|
||||
4.01 <em>Transitional</em>, HTML Purifier will be lazy
|
||||
and won't clean up your <code>center</code>
|
||||
or <code>font</code> tags. But if you're using HTML 4.01 <em>Strict</em>,
|
||||
HTML Purifier has no choice: it has to convert them, or they will
|
||||
be nuked out of existence. So while light on Transitional will result
|
||||
in little to no changes, light on Strict will still result in quite
|
||||
a lot of fixes.</p>
|
||||
|
||||
<p>This is different behavior from 1.6 or before, where deprecated
|
||||
tags in transitional documents would
|
||||
always be cleaned up regardless. This is also better behavior.</p>
|
||||
|
||||
<h2>My pages look different!</h2>
|
||||
|
||||
<p>HTML Purifier is tasked with converting deprecated tags and
|
||||
attributes to standards-compliant alternatives, which usually
|
||||
need copious amounts of CSS. It's also not foolproof: sometimes
|
||||
things do get lost in the translation. This is why when HTML Purifier
|
||||
can get away with not doing cleaning, it won't; this is why
|
||||
the default value is <strong>medium</strong> and not heavy.</p>
|
||||
|
||||
<p>Fortunately, only a few attributes have problems with the switch
|
||||
over. They are described below:</p>
|
||||
|
||||
<table class="table">
|
||||
<thead><tr>
|
||||
<th>Element@Attr</th>
|
||||
<th>Changes</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>caption@align</td>
|
||||
<td>Firefox supports stuffing the caption on the
|
||||
left and right side of the table, a feature that
|
||||
Internet Explorer, understandably, does not have.
|
||||
When align equals right or left, the text will simply
|
||||
be aligned on the left or right side.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>img@align</td>
|
||||
<td>The implementation for align bottom is good, but not
|
||||
perfect. There are a few pixel differences.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>br@clear</td>
|
||||
<td>Clear both gets a little wonky in Internet Explorer. Haven't
|
||||
really been able to figure out why.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hr@noshade</td>
|
||||
<td>All browsers implement this slightly differently: we've
|
||||
chosen to make noshade horizontal rules gray.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>There are a few more minor, although irritating, bugs.
|
||||
Some older browsers support deprecated attributes,
|
||||
but not CSS. Transformed elements and attributes will look unstyled
|
||||
to said browsers. Also, CSS precedence is slightly different for
|
||||
inline styles versus presentational markup. In increasing precedence:</p>
|
||||
|
||||
<ol>
|
||||
<li>Presentational attributes</li>
|
||||
<li>External style sheets</li>
|
||||
<li>Inline styling</li>
|
||||
</ol>
|
||||
|
||||
<p>This means that styling that may have been masked by external CSS
|
||||
declarations will start showing up (a good thing, perhaps). Finally,
|
||||
if you've turned off the style attribute, almost all of
|
||||
these transformations will not work. Sorry mates.</p>
|
||||
|
||||
<p>You can review the rendering before and after of these transformations
|
||||
by consulting the <a
|
||||
href="http://htmlpurifier.org/live/smoketests/attrTransform.php">attrTransform.php
|
||||
smoketest</a>.</p>
|
||||
|
||||
<h2>I like the general idea, but the specifics bug me!</h2>
|
||||
|
||||
<p>So you want HTML Purifier to clean up your HTML, but you're not
|
||||
so happy about the br@clear implementation. That's perfectly fine!
|
||||
HTML Purifier will make accomodations:</p>
|
||||
|
||||
<pre>$config->set('HTML', 'Doctype', 'XHTML 1.0 Transitional');
|
||||
$config->set('HTML', 'TidyLevel', 'heavy'); // all changes, minus...
|
||||
<strong>$config->set('HTML', 'TidyRemove', 'br@clear');</strong></pre>
|
||||
|
||||
<p>That third line does the magic, removing the br@clear fix
|
||||
from the module, ensuring that <code><br clear="both" /></code>
|
||||
will pass through unharmed. The reverse is possible too:</p>
|
||||
|
||||
<pre>$config->set('HTML', 'Doctype', 'XHTML 1.0 Transitional');
|
||||
$config->set('HTML', 'TidyLevel', 'none'); // no changes, plus...
|
||||
<strong>$config->set('HTML', 'TidyAdd', 'p@align');</strong></pre>
|
||||
|
||||
<p>In this case, all transformations are shut off, except for the p@align
|
||||
one, which you found handy.</p>
|
||||
|
||||
<p>To find out what the names of fixes you want to turn on or off are,
|
||||
you'll have to consult the source code, specifically the files in
|
||||
<code>HTMLPurifier/HTMLModule/Tidy/</code>. There is, however, a
|
||||
general syntax:</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Example</th>
|
||||
<th>Interpretation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>element</td>
|
||||
<td>font</td>
|
||||
<td>Tag transform for <em>element</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>element@attr</td>
|
||||
<td>br@clear</td>
|
||||
<td>Attribute transform for <em>attr</em> on <em>element</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>@attr</td>
|
||||
<td>@lang</td>
|
||||
<td>Global attribute transform for <em>attr</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>e#content_model_type</td>
|
||||
<td>blockquote#content_model_type</td>
|
||||
<td>Change of child processing implementation for <em>e</em></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>So... what's the lowdown?</h2>
|
||||
|
||||
<p>The lowdown is, quite frankly, HTML Purifier's default settings are
|
||||
probably good enough. The next step is to bump the level up to heavy,
|
||||
and if that still doesn't satisfy your appetite, do some fine tuning.
|
||||
Other than that, don't worry about it: this all works silently and
|
||||
effectively in the background.</p>
|
||||
|
||||
<div id="version">$Id$</div>
|
||||
|
||||
</body></html>
|
@@ -8,8 +8,8 @@ require_once '../../library/HTMLPurifier.auto.php';
|
||||
$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
|
||||
$config->set('Core', 'Encoding', 'UTF-8'); // replace with your encoding
|
||||
$config->set('HTML', 'Doctype', 'XHTML 1.0 Transitional'); // replace with your doctype
|
||||
|
||||
$purifier = new HTMLPurifier($config);
|
||||
|
||||
|
@@ -34,6 +34,12 @@ information for casual developers using HTML Purifier.</p>
|
||||
<dt><a href="enduser-utf8.html">UTF-8: The Secret of Character Encoding</a></dt>
|
||||
<dd>Describes the rationale for using UTF-8, the ramifications otherwise, and how to make the switch.</dd>
|
||||
|
||||
<dt><a href="enduser-tidy.html">Tidy</a></dt>
|
||||
<dd>Tutorial for tweaking HTML Purifier's Tidy-like behavior.</dd>
|
||||
|
||||
<dt><a href="enduser-customize.html">Customize</a></dt>
|
||||
<dd>Tutorial for customizing HTML Purifier's tag and attribute sets.</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<h2>Development</h2>
|
||||
@@ -128,8 +134,8 @@ the code. They may be upgraded to HTML files or stay as TXT scratchpads.</p>
|
||||
|
||||
<tr>
|
||||
<td>Reference</td>
|
||||
<td><a href="ref-loose-vs-strict.txt">Loose vs.Strict</a></td>
|
||||
<td>Differences between HTML Strict and Transitional versions.</td>
|
||||
<td><a href="ref-content-models.txt">Handling Content Model Changes</a></td>
|
||||
<td>Discusses how to tidy up content model changes using custom ChildDef classes.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
@@ -140,14 +146,8 @@ the code. They may be upgraded to HTML files or stay as TXT scratchpads.</p>
|
||||
|
||||
<tr>
|
||||
<td>Reference</td>
|
||||
<td><a href="ref-strictness.txt">Strictness</a></td>
|
||||
<td>Short essay on how loose definition isn't really loose.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Reference</td>
|
||||
<td><a href="ref-xhtml-1.1.txt">XHTML 1.1</a></td>
|
||||
<td>What we'd have to do to support XHTML 1.1.</td>
|
||||
<td><a href="ref-html-modularization.txt">Modularization of HTMLDefinition</a></td>
|
||||
<td>Provides a high-level overview of the concepts behind HTMLModules.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@@ -12,29 +12,10 @@ the documentation in ConfigDef for more information on these namespaces.
|
||||
|
||||
Since configuration is dependant on context, internal classes require a
|
||||
configuration object to be passed as a parameter. (They also require a
|
||||
Context object).
|
||||
Context object). A majority of classes do not need the config object,
|
||||
but for those who do, it is a lifesaver.
|
||||
|
||||
In relation to HTMLDefinition and CSSDefinition, there could be a special class
|
||||
of directives that influence the *construction* of the Definition object.
|
||||
A theoretical call pattern would look like:
|
||||
|
||||
1. Client calls Config->getHTMLDefinition()
|
||||
2. Config calls HTMLDefinition->createNew(this)
|
||||
3. HTMLDefinition constructs itself with base configuration
|
||||
4. HTMLDefinition calls Config->get('HTML')
|
||||
5. Config returns array of directives
|
||||
6. HTMLDefinition performs operations and changes specified by directives
|
||||
7. HTMLPurifier returns constructed definition
|
||||
8. Config caches definition so it doesn't have to be generated again
|
||||
9. Config returns definition
|
||||
|
||||
You could also override Config's copy of the definition with your own
|
||||
custom copy, which OVERRIDES all directives. Only the base, vanilla copy
|
||||
is the Singleton, the object actually interfaced with is a operated-upon
|
||||
clone of that object. Also, if an update to the directives would update
|
||||
the definition, you'd have to force reconstruction.
|
||||
|
||||
In practice, the pulling directives from the config object are
|
||||
solely need-based, and the flex points are littered throughout the
|
||||
setup() function. Some sort of refactoring is likely in order. See
|
||||
ref-xhtml-1.1.txt for more info.
|
||||
Definition objects are complex datatypes influenced by their respective
|
||||
directive namespaces (HTMLDefinition with HTML and CSSDefinition with CSS).
|
||||
If any of these directives is updated, HTML Purifier forces the definition
|
||||
to be regenerated.
|
||||
|
@@ -2,23 +2,16 @@
|
||||
Filter Levels
|
||||
When one size *does not* fit all
|
||||
|
||||
The more I think about it, the less sense it makes for maintaining one huge
|
||||
monolithic HTMLDefinition class. There's simply so much variation that
|
||||
could go into this definition: the set of HTML good for blog entries is
|
||||
definitely too large for HTML that would be allowed in blog comments. Going
|
||||
from Transitional to Strict requires changes to the definition.
|
||||
It makes little sense to constrain users to one set of HTML elements and
|
||||
attributes and tell them that they are not allowed to mold this in
|
||||
any fashion. Many users demand to be able to custom-select which elements
|
||||
and attributes they want. This is fine: because HTML Purifier keeps close
|
||||
track of what elements are safe to use, there is no way for them to
|
||||
accidently allow an XSS-able tag.
|
||||
|
||||
Allowing users to specify their own whitelists is one step (implemented, btw),
|
||||
but I have doubts on only doing this. Simply put, the typical programmer is too
|
||||
lazy to actually go through the trouble of investigating which tags, attributes
|
||||
and properties to allow. HTMLDefinition makes a big part of what HTMLPurifier
|
||||
is.
|
||||
|
||||
The idea, then, is to setup fundamentally different set of definitions, which
|
||||
can further be customized using simpler configuration options. Alternatively,
|
||||
they could be implemented as configuration profiles, which simply load
|
||||
a set of recommended directives to acheive a desired affect (no simpler
|
||||
config options though).
|
||||
However, combing through the HTML spec to make your own whitelist can
|
||||
be a daunting task. HTML Purifier ought to offer pre-canned filter levels
|
||||
that amateur users can select based on what they think is their use-case.
|
||||
|
||||
Here are some fuzzy levels you could set:
|
||||
|
||||
@@ -46,6 +39,10 @@ make forbidden element to text transformations desirable (for example, images).
|
||||
|
||||
== Element Risk Analysis ==
|
||||
|
||||
Although none of the currently supported elements presents a security
|
||||
threat per-say, some can cause problems for page layouts or be
|
||||
extremely complicated.
|
||||
|
||||
Legend:
|
||||
[danger level] - regular tags / uncommon tags ~ deprecated tags
|
||||
[danger level]* - rare tags
|
||||
@@ -114,6 +111,10 @@ Partially presentational - table.cellpadding, table.cellspacing,
|
||||
|
||||
== CSS Risk Analysis ==
|
||||
|
||||
Currently, there is no support for fine-grained "allowed CSS" specification,
|
||||
mainly because I'm lazy, partially because no one has asked for it. However,
|
||||
this will be added eventually.
|
||||
|
||||
There are certain CSS elements that are extremely useful inline, but then
|
||||
as you get to more presentation oriented styling it may not always be
|
||||
appropriate to inline them.
|
||||
@@ -126,6 +127,7 @@ any CSS properties that are not currently implemented (such as position).
|
||||
Dangerous, can go outside container - float
|
||||
Easy to abuse - font-size, font-family (font), width
|
||||
Colored - background-color (background), border-color (border), color
|
||||
(see proposal-colors.html)
|
||||
Dramatic - border, list-style-position (list-style), margin, padding,
|
||||
text-align, text-indent, text-transform, vertical-align, line-height
|
||||
|
||||
|
48
docs/ref-content-models.txt
Normal file
48
docs/ref-content-models.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
Handling Content Model Changes
|
||||
|
||||
|
||||
1. Context
|
||||
|
||||
The distinction between Transitional and Strict document types is somewhat
|
||||
of an anomaly in the lineage of XHTML document types (following 1.0, no
|
||||
doctypes do not have flavors: instead, modularization is used to let
|
||||
document authors vary their elements). This transition is usually quite
|
||||
straight-forward, as W3C usually deprecates attributes or elements, which
|
||||
are quite easily handled using tag and attribute transforms.
|
||||
|
||||
However, for two elements, <blockquote>, <body> and <address>, W3C elected
|
||||
to also change the content model. <blockquote> and <body> originally
|
||||
accepted both inline and block elements, but in the strict doctype they
|
||||
only allow block elements. With <address>, the situation is inverted:
|
||||
<p> tags were now forbidden from appearing within this tag.
|
||||
|
||||
|
||||
2. Current situation
|
||||
|
||||
Currently, HTML Purifier treats <blockquote> specially during Tidy mode
|
||||
using a custom ChildDef class StrictBlockquote. StrictBlockquote
|
||||
operates similarly to Required, except that when it encounters an inline
|
||||
element, it will wrap it in a block tag (as specified by
|
||||
%HTML.BlockWrapper, the default is <p>). The naming suggests it can
|
||||
only be used for <blockquote>s, although it may be possible to
|
||||
genericize it to work on other cases of this nature (this would be of
|
||||
little practical application, as no other element in XHTML 1.1 or earlier
|
||||
has a block-only content model).
|
||||
|
||||
Tidy currently contains no custom, lenient implementation for <address>.
|
||||
If one were to be written, it would likely operate on the principle that,
|
||||
when a <p> tag were to be encountered, it would be replaced with a
|
||||
leading and trailing <br /> tag (the contents of <p>, being inline, are
|
||||
not an issue). There is no prior work with this sort of operation.
|
||||
|
||||
|
||||
3. Outside applicability
|
||||
|
||||
There are a number of other elements that contain restrictive content
|
||||
models, such as <ul> or <span> (the latter is restrictive in that it
|
||||
does not allow block elements). In the former case, an errant node
|
||||
is eliminated completely, in the latter case, the text of the node
|
||||
would is preserved (as the parent node does allow PCDATA). Custom
|
||||
content model implementations probably are not the best way of handling
|
||||
these cases, instead, node bubbling should be implemented instead.
|
@@ -1,10 +1,8 @@
|
||||
|
||||
XHTML 1.1 and HTML Purifier
|
||||
The Modularization of HTMLDefinition in HTML Purifier
|
||||
|
||||
Todo for XHTML 1.1 support <http://www.w3.org/TR/xhtml11/changes.html>
|
||||
1. Scratch lang entirely in favor of xml:lang
|
||||
2. Scratch name entirely in favor of id (partially-done)
|
||||
3. Support Ruby <http://www.w3.org/TR/2001/REC-ruby-20010531/>
|
||||
1. Support Ruby <http://www.w3.org/TR/2001/REC-ruby-20010531/>
|
||||
|
||||
HTML Purifier uses the modularization of XHTML
|
||||
<http://www.w3.org/TR/xhtml-modularization/> to organize the internals
|
||||
@@ -12,25 +10,10 @@ of HTMLDefinition into a more manageable and extensible fashion. Rather
|
||||
than have one super-object, HTMLDefinition is split into HTMLModules,
|
||||
each of which are responsible for defining elements, their attributes,
|
||||
and other properties (for a more indepth coverage, see
|
||||
/library/HTMLPurifier/HTMLModule.php's docblock comments).
|
||||
/library/HTMLPurifier/HTMLModule.php's docblock comments). These modules
|
||||
are managed by HTMLModuleManager.
|
||||
|
||||
The modules that W3C defines and we support are:
|
||||
|
||||
* 5.1. Attribute Collections (technically not a module
|
||||
* 5.2. Core Modules
|
||||
o 5.2.2. Text Module
|
||||
o 5.2.3. Hypertext Module
|
||||
o 5.2.4. List Module
|
||||
* 5.4. Text Extension Modules
|
||||
o 5.4.1. Presentation Module
|
||||
o 5.4.2. Edit Module
|
||||
o 5.4.3. Bi-directional Text Module
|
||||
* 5.6. Table Modules
|
||||
o 5.6.2. Tables Module
|
||||
* 5.7. Image Module
|
||||
* 5.18. Style Attribute Module
|
||||
|
||||
Modules that we don't support but coul support are:
|
||||
Modules that we don't support but could support are:
|
||||
|
||||
* 5.6. Table Modules
|
||||
o 5.6.1. Basic Tables Module [?]
|
||||
@@ -38,10 +21,8 @@ Modules that we don't support but coul support are:
|
||||
* 5.9. Server-side Image Map Module [?]
|
||||
* 5.12. Target Module [?]
|
||||
* 5.21. Name Identification Module [deprecated]
|
||||
* 5.22. Legacy Module [deprecated]
|
||||
|
||||
These modules will not be implemented due to their dangerousness or
|
||||
inapplicability as an XHTML fragment:
|
||||
These modules would be implemented as "unsafe":
|
||||
|
||||
* 5.2. Core Modules
|
||||
o 5.2.1. Structure Module
|
||||
@@ -64,11 +45,7 @@ of robust tools for handling them (the main problem is that all the
|
||||
current parsers are usually PHP 5 only and solely-validating, not
|
||||
correcting).
|
||||
|
||||
The abstraction of the HTMLDefinition creation process will also
|
||||
contribute to a need for a caching system. Cache invalidation would be
|
||||
difficult, but could be done by comparing the HTML and Attr config
|
||||
namespaces with a copy that was packaged along with the serialized
|
||||
HTMLDefinition object.
|
||||
This system may be generalized and ported over for CSS.
|
||||
|
||||
== General Use-Case ==
|
||||
|
||||
@@ -91,7 +68,7 @@ like this:
|
||||
<?php
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$def =& $config->getHTMLDefinition(true); // reference to raw
|
||||
unset($def->modules['Hypertext']); // rm ''a'' link
|
||||
$def->addElement('marquee', 'Block', 'Flow', 'Common');
|
||||
$purifier = new HTMLPurifier($config);
|
||||
$purifier->purify($html); // now the definition is finalized
|
||||
?>
|
||||
@@ -184,4 +161,4 @@ Content sets can be altered using HTMLModule->content_sets, an associative
|
||||
array of content set names to content set contents. If the content set
|
||||
already exists, your values are appended on to it (great for, say,
|
||||
registering the font tag as an inline element), otherwise it is
|
||||
created. They are substituted into content_model.
|
||||
created. They are substituted into content_model.
|
@@ -1,37 +0,0 @@
|
||||
|
||||
Loose versus Strict
|
||||
Changes from one doctype to another
|
||||
|
||||
There are changes. Wow, how insightful. Not everything changed is relevant
|
||||
to HTML Purifier, though, so let's take a look:
|
||||
|
||||
== Major incompatibilities ==
|
||||
|
||||
[done] BLOCKQUOTE changes from 'flow' to 'block'
|
||||
current behavior: inline inner contents should not be nuked, block-ify as necessary
|
||||
[partially-done] U, S, STRIKE cut
|
||||
current behavior: removed completely
|
||||
projected behavior: replace with appropriate inline span + CSS
|
||||
[done] ADDRESS from potpourri to Inline (removes p tags)
|
||||
current behavior: block tags silently dropped
|
||||
ideal behavior: replace tags with something like <br>. (not high priority)
|
||||
|
||||
== Things we can loosen up ==
|
||||
|
||||
Tags DIR, MENU, CENTER, ISINDEX, FONT, BASEFONT? allowed in loose
|
||||
current behavior: transform to strict-valid forms
|
||||
Attributes allowed in loose (see attribute transforms in 'dev-progress.html')
|
||||
current behavior: projected to transform into strict-valid forms
|
||||
|
||||
== Periphery issues ==
|
||||
|
||||
A tag's attribute 'target' (for selecting frames) cut
|
||||
current behavior: not allowed at all
|
||||
projected behavior: use loose doctype if needed, needs valid values
|
||||
[done] OL/LI tag's attribute 'start'/'value' (for renumbering lists) cut
|
||||
current behavior: no substitute, just delete when in strict, allow in loose
|
||||
Attribute 'name' deprecated in favor of 'id'
|
||||
current behavior: dropped silently
|
||||
projected behavior: create proper AttrTransform
|
||||
[done] PRE tag allows SUB/SUP? (strict dtd comment vs syntax, loose disallows)
|
||||
current behavior: disallow as usual
|
@@ -18,5 +18,7 @@ HTML Purifier context.
|
||||
|
||||
<listing>, monospace pre-variant (extremely rare)
|
||||
<plaintext>, escapes all tags to the end of document
|
||||
<ruby> and friends, (more research needed, appears to be XHTML 1.1 markup)
|
||||
<xmp>, monospace, replace with pre
|
||||
|
||||
These should be put into their own Tidy module, not loaded by default(?). These
|
||||
all qualify as "lenient" transforms.
|
@@ -1,37 +0,0 @@
|
||||
|
||||
Is HTML Purifier Strict or Transitional?
|
||||
A little bit of helpful guidance
|
||||
|
||||
Despite the fact that HTML Purifier professes to support both transitional and
|
||||
strict HTML, it rejects a lot of attributes and elements that are actually, indeed,
|
||||
valid. You can investigate progress.html to find out precisely what we
|
||||
are doing to these *deprecated* attributes.
|
||||
|
||||
However, users have found that Strict HTML imposes some quite unreasonable
|
||||
restrictions on certain things. The start and value attributes in ol and
|
||||
li (respectively) perhaps are the most contested. There's is currently no
|
||||
widely supported browser method short of JavaScript that can replace these
|
||||
two deprecated elements. It behooves us to allow these deprecated
|
||||
attributes when the output is transitional.
|
||||
|
||||
Fortunantely, that's the only real bugger case. The others have near-perfect
|
||||
CSS equivalents, and were presentational anyway. However, the other question
|
||||
pops up: should we always convert these to the CSS forms when 1. the spec
|
||||
allows them anyway and 2. older browsers support them better? After all, the
|
||||
whole point about CSS is to seperate styling from content, so inline styling
|
||||
doesn't solve that problem.
|
||||
|
||||
It's an icky question, and we'll have to deal with it as more and more
|
||||
transforms get implemented. As of right now, however, we currently support
|
||||
these loose-only constructs in loose mode:
|
||||
|
||||
- <ul start="1">, <li value="1"> attributes
|
||||
- <u>, <strike>, <s> tags
|
||||
- flow children in <blockquote>
|
||||
- mixed children in <address>
|
||||
|
||||
The changed child definitions as well as the ul.start li.value are the most
|
||||
compelling reasons why loose should be used. We may want offer disabling <u>,
|
||||
<strike> and <s> by themselves. We may also want to offer no pre-emptive
|
||||
deprecated conversions. This all must be unified.
|
||||
|
@@ -2,8 +2,23 @@
|
||||
Web Hypertext Application Technology Working Group
|
||||
WHATWG
|
||||
|
||||
I don't think we need to worry about them. Untrusted users shouldn't be
|
||||
submitting applications, eh? But if some interesting attribute pops up in
|
||||
their spec, and might be worth supporting, stick it here.
|
||||
== HTML 5 ==
|
||||
|
||||
(none so far, as you can see)
|
||||
URL: http://www.whatwg.org/specs/web-apps/current-work/
|
||||
|
||||
HTML 5 defines a kaboodle of new elements and attributes, as well as
|
||||
some well-defined, "quirks mode" HTML parsing. Although WHATWG professes
|
||||
to be targeted towards web applications, many of their semantic additions
|
||||
would be quite useful in regular documents. Eventually, HTML
|
||||
Purifier will need to audit their lists and figure out what changes need
|
||||
to be made. This process is complicated by the fact that the WHATWG
|
||||
doesn't buy into W3C's modularization of XHTML 1.1: we may need
|
||||
to remodularize HTML 5 (probably done by section name). No sense in
|
||||
committing ourselves till the spec stabilizes, though.
|
||||
|
||||
More immediately speaking though, however, is the well-defined parsing
|
||||
behavior that HTML 5 adds. While I have little interest in writing
|
||||
another DirectLex parser, other parsers like ph5p
|
||||
<http://jero.net/lab/ph5p/> can be adapted to DOMLex to support much more
|
||||
flexible HTML parsing (a cool feature I've seen is how they resolve
|
||||
<b>bold<i>both</b>italic</i>).
|
||||
|
@@ -25,6 +25,7 @@ h4 {font-family:sans-serif; font-size:0.9em; font-weight:bold; }
|
||||
.aside {margin-left:2em; font-family:sans-serif; font-size:0.9em; }
|
||||
blockquote .label {font-weight:bold; font-size:1em; margin:0 0 .1em;
|
||||
border-bottom:1px solid #CCC;}
|
||||
.emphasis {font-weight:bold; text-align:center; font-size:1.3em;}
|
||||
|
||||
/* A regular table */
|
||||
.table {border-collapse:collapse; border-bottom:2px solid #888; margin-left:2em; }
|
||||
@@ -66,3 +67,5 @@ q:after {
|
||||
/* Marks off sections that are lacking. */
|
||||
.fixme {margin-left:2em; }
|
||||
.fixme:before {content:"Fix me: "; font-weight:bold; color:#C00; }
|
||||
|
||||
#applicability {margin: 1em 5%; font-style:italic;}
|
||||
|
Reference in New Issue
Block a user