1
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2025-08-04 21:28:06 +02:00

Compare commits

..

32 Commits

Author SHA1 Message Date
Edward Z. Yang
587d642826 Release 3.1.0.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1728 48356398-32a2-884e-a903-53898d9a118a
2008-05-18 05:46:06 +00:00
Edward Z. Yang
0bef016271 [3.1.0] Get testing working again for all versions
- Standalone testing setup properly with autoload
- Bootstrap autoloader deals more robustly with classes that don't exist, preventing class_exists($class, true) from barfing.
- Cleanup $_reporter to $reporter

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1727 48356398-32a2-884e-a903-53898d9a118a
2008-05-16 01:49:33 +00:00
Edward Z. Yang
ef6a1c9274 Allow for users to load Language class files themselves. Messages are still HTML Purifier dependent; we need to figure out a way around that.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1725 48356398-32a2-884e-a903-53898d9a118a
2008-05-15 23:22:34 +00:00
Edward Z. Yang
86b1da9b6f [3.1.0] Fixed bug with fallback languages in LanguageFactory
- Also, reverted bogus Generator changes

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1723 48356398-32a2-884e-a903-53898d9a118a
2008-05-15 23:04:46 +00:00
Edward Z. Yang
00ea2062d4 [3.1.0] Fix buggy LanguageFactory. This revision is incomplete.
- Some bogus commits to Generator were made, and will be reverted next revision.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1722 48356398-32a2-884e-a903-53898d9a118a
2008-05-15 17:47:47 +00:00
Edward Z. Yang
cb5d5d0648 [3.1.0] Revamp URI handling of percent encoding and validation.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1709 48356398-32a2-884e-a903-53898d9a118a
2008-05-14 02:19:00 +00:00
Edward Z. Yang
77ce3e8b4a [3.1.0] Extend scanner to catch $this->config; chmod new directories from Serializer. I'm not exactly sure what the implications of the bugfix are, but hopefully it won't blow up.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1708 48356398-32a2-884e-a903-53898d9a118a
2008-05-13 03:17:38 +00:00
Edward Z. Yang
e0c0d8eab6 [3.1.0] Allow arbitrary whitespace in %HTML.Allowed
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1707 48356398-32a2-884e-a903-53898d9a118a
2008-05-13 02:02:27 +00:00
Edward Z. Yang
ce46fb618c [3.1.0] Add missing tests and errors for forbidden attributes
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1706 48356398-32a2-884e-a903-53898d9a118a
2008-05-13 01:41:25 +00:00
Edward Z. Yang
9f37764614 Update TODO with items from Denis.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1702 48356398-32a2-884e-a903-53898d9a118a
2008-05-06 03:08:09 +00:00
Edward Z. Yang
aaf6ba421c Sync with SimpleTest codebase
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1701 48356398-32a2-884e-a903-53898d9a118a
2008-04-28 19:52:13 +00:00
Edward Z. Yang
4b862f64e6 [3.1.0] Fix ScriptRequired bug with trusted installs
- Generator now takes $config and $context during instantiation
- Double quotes outside of attributes are not escaped


git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1700 48356398-32a2-884e-a903-53898d9a118a
2008-04-28 01:35:07 +00:00
Edward Z. Yang
be2cfb7918 Fix latest batch of SimpleTest changes. Also, commit forgotten NEWS.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1699 48356398-32a2-884e-a903-53898d9a118a
2008-04-26 19:50:27 +00:00
Edward Z. Yang
2f29c27a59 [3.1.0] Fix broken PH5P in latest versions of DOM with bandaid; punt to DirectLex.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1698 48356398-32a2-884e-a903-53898d9a118a
2008-04-26 19:47:22 +00:00
Edward Z. Yang
144bd6f07a [3.1.0] Fix bug with 3.1.0-dev version number (the dash caused problems, so we switched to commas)
- Refactored out null definition cache during HTMLDefinition tests


git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1697 48356398-32a2-884e-a903-53898d9a118a
2008-04-26 19:28:14 +00:00
Edward Z. Yang
a95f600e76 Fix another fatal error from SimpleTest refactoring.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1696 48356398-32a2-884e-a903-53898d9a118a
2008-04-26 03:18:07 +00:00
Edward Z. Yang
84aa2ca390 [3.1.0] Implement tag@attr for Allowed and Forbidden
- Fix (or null) bug in configdoc

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1695 48356398-32a2-884e-a903-53898d9a118a
2008-04-26 03:14:01 +00:00
Edward Z. Yang
1f8619cda5 [3.1.0] Fix and revamp configForm.php smoketest
- Fix bool/null ConfigForm field

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1694 48356398-32a2-884e-a903-53898d9a118a
2008-04-26 01:13:58 +00:00
Edward Z. Yang
04b1ec33cb [3.1.0] version -> VERSION
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1693 48356398-32a2-884e-a903-53898d9a118a
2008-04-25 05:47:36 +00:00
Edward Z. Yang
6d9643a92e [3.1.0] Add const version to HTMLPurifier, also bump version to 3.1.0-dev; this apparently is a good idea!
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1692 48356398-32a2-884e-a903-53898d9a118a
2008-04-25 05:26:10 +00:00
Edward Z. Yang
438d973073 Renumber as 3.1.0, however, NOT releasing (WHATSNEW isn't updated)
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1691 48356398-32a2-884e-a903-53898d9a118a
2008-04-25 03:54:38 +00:00
Edward Z. Yang
f295465ad4 [3.1.0] Allow index to be false for config from for creation
- Static-ify Printer_ConfigForm's get* functions

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1690 48356398-32a2-884e-a903-53898d9a118a
2008-04-25 02:43:31 +00:00
Edward Z. Yang
eaabccdd9b [3.1.0] More PHP4->PHP5 conversions, notably reference removal of most methods that return objects
- Removed HTMLPurifier_Error
- Documentation updates
- Removed more copy() methods in favor of clone
- HTMLPurifier::getInstance() to HTMLPurifier::instance()
- Fix InterchangeBuilder to use HTMLPURIFIER_PREFIX

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1689 48356398-32a2-884e-a903-53898d9a118a
2008-04-23 02:40:17 +00:00
Edward Z. Yang
893cdd0301 All 3.1.0 TODOs are done!
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1687 48356398-32a2-884e-a903-53898d9a118a
2008-04-23 00:17:52 +00:00
Edward Z. Yang
1ba77fedd4 [3.1.0] Implement DenyElementDecorator for imagecrash-protection against CSS width/height
- Misc doc changes
- Add missing inheritance for AttrDef_CSS decorators


git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1684 48356398-32a2-884e-a903-53898d9a118a
2008-04-22 22:28:54 +00:00
Edward Z. Yang
fae720115a Update TODO
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1683 48356398-32a2-884e-a903-53898d9a118a
2008-04-22 20:57:11 +00:00
Edward Z. Yang
c0f2e69c9f [3.1.0] Update French documentation.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1682 48356398-32a2-884e-a903-53898d9a118a
2008-04-22 20:43:47 +00:00
Edward Z. Yang
ca6b20ff2b [phorum-3.0.0.1] Improve installation documentation.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1681 48356398-32a2-884e-a903-53898d9a118a
2008-04-22 18:30:01 +00:00
Edward Z. Yang
c4aa3ee40c [3.1.0] Encoder optimization, as suggested by Diego
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1680 48356398-32a2-884e-a903-53898d9a118a
2008-04-22 18:14:40 +00:00
Edward Z. Yang
e9c7873057 [3.1.0] Fix validation error with missing li.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1679 48356398-32a2-884e-a903-53898d9a118a
2008-04-22 17:35:39 +00:00
Edward Z. Yang
d45f42e6a8 Update docs.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1678 48356398-32a2-884e-a903-53898d9a118a
2008-04-22 17:32:42 +00:00
Edward Z. Yang
f46aef698e Post rc skirmishes.
- Update docs
- Update source code comments in generated files
- release1-update.php now flushes after it finishes
- Make InterchangeBuilder alphabetize

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1676 48356398-32a2-884e-a903-53898d9a118a
2008-04-22 16:20:45 +00:00
117 changed files with 1639 additions and 835 deletions

View File

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

View File

@@ -17,7 +17,7 @@ ce document pour quelques choses.
1. Compatibilité
HTML Purifier fonctionne dans PHP 5. PHP 5.0.0 est le dernier
HTML Purifier fonctionne dans PHP 5. PHP 5.0.5 est le dernier
version que je le testais. Il ne dépend de les autre librairies.
Les extensions optionnel est iconv (en général déjà installer) et
@@ -34,19 +34,15 @@ Utilisez:
...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:
HTML Purifier utilise 'autoload'. Si vous avez définu la fonction
__autoload, vous doivez ajoute cet programme:
require_once 'HTMLPurifier.php';
spl_autoload_register('__autoload')
Seuleument les contents dans library/ est essentiel; vous peut enlever
les autre fichiers quand vous est dans une atmosphère professionnel.
Plus d'information est dans le document 'INSTALL'.
[En cours de construction]
6. Installation vite
3. Installation vite
Si votre site web est en UTF-8 et XHTML Transitional, utilisez:

54
NEWS
View File

@@ -9,6 +9,60 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
. Internal change
==========================
3.1.0, released 2008-05-18
# Unnecessary references to objects (vestiges of PHP4) removed from method
signatures. The following methods do not need references when assigning from
them and will result in E_STRICT errors if you try:
+ HTMLPurifier_Config->get*Definition() [* = HTML, CSS]
+ HTMLPurifier_ConfigSchema::instance()
+ HTMLPurifier_DefinitionCacheFactory::instance()
+ HTMLPurifier_DefinitionCacheFactory->create()
+ HTMLPurifier_DoctypeRegistry->register()
+ HTMLPurifier_DoctypeRegistry->get()
+ HTMLPurifier_HTMLModule->addElement()
+ HTMLPurifier_HTMLModule->addBlankElement()
+ HTMLPurifier_LanguageFactory::instance()
# Printer_ConfigForm's get*() functions were static-ified
# %HTML.ForbiddenAttributes requires attribute declarations to be in the
form of tag@attr, NOT tag.attr (which will throw an error and won't do
anything). This is for forwards compatibility with XML; you'd do best
to migrate an %HTML.AllowedAttributes directives to this syntax too.
! Allow index to be false for config from form creation
! Added HTMLPurifier::VERSION constant
! Commas, not dashes, used for serializer IDs. This change is forwards-compatible
and allows for version numbers like "3.1.0-dev".
! %HTML.Allowed deals gracefully with whitespace anywhere, anytime!
! HTML Purifier's URI handling is a lot more robust, with much stricter
validation checks and better percent encoding handling.
! Bootstrap autoloader deals more robustly with classes that don't exist,
preventing class_exists($class, true) from barfing.
- InterchangeBuilder now alphabetizes its lists
- Validation error in configdoc output fixed
- Iconv and other encoding errors muted even with custom error handlers that
do not honor error_reporting
- Add protection against imagecrash attack with CSS height/width
- HTMLPurifier::instance() created for consistency, is equivalent to getInstance()
- Fixed and revamped broken ConfigForm smoketest
- Bug with bool/null fields in Printer_ConfigForm fixed
- Bug with global forbidden attributes fixed
- Improved error messages for allowed and forbidden HTML elements and attributes
- Missing (or null) in configdoc documentation restored
- If DOM throws and exception during parsing with PH5P (occurs in newer versions
of DOM), HTML Purifier punts to DirectLex
- Fatal error with unserialization of ScriptRequired
- Created directories are now chmod'ed properly
- Fixed bug with fallback languages in LanguageFactory
- Standalone testing setup properly with autoload
. Out-of-date documentation revised
. UTF-8 encoding check optimization as suggested by Diego
. HTMLPurifier_Error removed in favor of exceptions
. More copy() function removed; should use clone instead
. More extensive unit tests for HTMLDefinition
. assertPurification moved to central harness
. HTMLPurifier_Generator accepts $config and $context parameters during
instantiation, not runtime
. Double-quotes outside of attribute values are now unescaped
3.1.0rc1, released 2008-04-22
# Autoload support added. Internal require_once's removed in favor of an
explicit require list or autoloading. To use HTML Purifier,

118
TODO
View File

@@ -7,48 +7,32 @@ TODO List
? Maybe I'll Do It
==========================
If no interest is expressed for a feature that may required a considerable
If no interest is expressed for a feature that may require a considerable
amount of effort to implement, it may get endlessly delayed. Do not be
afraid to cast your vote for the next feature to be implemented!
UPCOMING RELEASE
----------------
IMPORTANT
- Release candidate, because of the major changes
DOCUMENTATION
- Update French translation of README
IMPORTANT FEATURES
- Factor out command line parser into its own class, and unit test it
NICE FEATURES
- Factor demo.php into a set of Printer classes, and then create a stub
file for users here (inside the actual HTML Purifier library)
- Support exporting configuration, so users can easily tweak settings
in the demo, and then copy-paste into their own setup
BUGS
- Style attribute height/width limiting for images
- Easy way to blacklist elements and attributes
- Investigate iconv error emitting
- Investigate UTF-8 optimization <http://htmlpurifier.org/phorum/read.php?3,1496>
- Figure out what to do about target="" and name="", since they show up so often
- Implement validation for query and for fragment
FUTURE VERSIONS
---------------
3.2 release [Error'ed]
# Error logging for filtering/cleanup procedures
- XSS-attempt detection
3.2 release [It's All About Trust] (floating)
# Implement untrusted, dangerous elements/attributes
- Objects and Forms are especially wanted
# Implement IDREF support (harder than it seems, since you cannot have
IDREFs to non-existent IDs)
# Frameset XHTML 1.0 and HTML 4.01 doctypes
- Research and implement a "safe" version of the Object module
3.3 release [Do What I Mean, Not What I Say]
3.3 release [Error'ed]
# Error logging for filtering/cleanup procedures
- XSS-attempt detection--certain errors are flagged XSS-like
3.4 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 <address> (block -> <br>)
- Remove redundant tags, ex. <u><u>Underlined</u></u>. Implementation notes:
? Remove redundant tags, ex. <u><u>Underlined</u></u>. Implementation notes:
1. Analyzing which tags to remove duplicants
2. Ensure attributes are merged into the parent tag
3. Extend the tag exclusion system to specify whether or not the
@@ -58,27 +42,21 @@ FUTURE VERSIONS
- Remove empty inline tags<i></i>
- Append something to duplicate IDs so they're still usable (impl. note: the
dupe detector would also need to detect the suffix as well)
- Externalize inline CSS to promote clean HTML
3.4 release [It's All About Trust] (floating)
# Implement untrusted, dangerous elements/attributes
- Objects and Forms are especially wanted
# Implement IDREF support (harder than it seems, since you cannot have
IDREFs to non-existent IDs)
# Frameset XHTML 1.0 and HTML 4.01 doctypes
- Externalize inline CSS to promote clean HTML, proposed by Sander Tekelenburg
4.0 release [Beyond HTML]
# Legit token based CSS parsing (will require revamping almost every
AttrDef class). Probably will use CSSTidy class
# More control over allowed CSS properties (maybe modularize it in the
same fashion!)
AttrDef class). Probably will use CSSTidy class?
# More control over allowed CSS properties using a modularization
# HTML 5 support
# IRI support
- Standardize token armor for all areas of processing
- Convert RTL/LTR override characters to <bdo> tags, or vice versa on demand.
Also, enable disabling of directionality
- Table of Contents generation (XHTML Compiler might be reusable)
5.0 release [To XML and Beyond]
- AllowedAttributes and ForbiddenAttributes step on the toes of XML by
using periods; this needs to be changed.
- Extended HTML capabilities based on namespacing and tag transforms (COMPLEX)
- Hooks for adding custom processors to custom namespaced tags and
attributes, offer default implementation
@@ -86,45 +64,63 @@ FUTURE VERSIONS
Ongoing
- More refactoring to take advantage of PHP5's facilities
- Lots of profiling, make it faster!
- Refactor unit tests into lots of test methods
- Plugins for major CMSes (COMPLEX)
- phpBB
- Drupal needs loving!
- Phorum need loving!
- more! (look for ones that use WYSIWYGs)
- Complete basic smoketests
- Also, maybe a FAQ for extension writers with HTML Purifier
AutoFormat
- Smileys
- Syntax highlighting with <pre> and possibly <?php
- Syntax highlighting (with GeSHi) with <pre> and possibly <?php
- Look at http://drupal.org/project/Modules/category/63 for ideas
Unknown release (on a scratch-an-itch basis)
# CHMOD install script for PEAR installs
? Have 'lang' attribute be checked against official lists, achieved by
encoding all characters that have string entity equivalents
- Abstract ChildDef_BlockQuote to work with all elements that only
allow blocks in them, required or optional
- Reorganize Unit Tests
Optimizations
- Reduce size of internal data-structures (esp. HTMLDefinition)
- Research memory usage of objects versus arrays
- Combine multiple strategies into a single, single-pass strategy
- Get PH5P working with the latest versions of DOM, which have much more
stringent error checking procedures. Maybe convert straight to tokens.
- Get rid of set_include_path(). Save this for another major release.
Neat feature related
! Factor demo.php into a set of Printer classes, and then create a stub
file for users here (inside the actual HTML Purifier library)
! Support exporting configuration, so users can easily tweak settings
in the demo, and then copy-paste into their own setup
- Advanced URI filtering schemes (see docs/proposal-new-directives.txt)
- Implement lenient <ruby> child validation
- Allow scoped="scoped" attribute in <style> tags; may be troublesome
because regular CSS has no way of uniquely identifying nodes, so we'd
have to generate IDs
- Explain how to use HTML Purifier in non-PHP languages / create
a simple command line stub (or complicated?)
- 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
- Table of Contents generation (XHTML Compiler might be reusable). May also
be out-of-band information.
- Full set of color keywords. Also, a way to add onto them without
finalizing the configuration object.
- Write a var_export and memcached DefinitionCache - Denis
Maintenance related (slightly boring)
# CHMOD install script for PEAR installs
! Factor out command line parser into its own class, and unit test it
! Nested configuration namespaces
- Distinguish between default settings and explicitly set settings, so
configurations can be merged
- Nested configuration namespaces
- Allow scoped="scoped" attribute in <style> tags; may be troublesome
because regular CSS has no way of uniquely identifying nodes, so we'd
have to generate IDs
- Time PHPT tests
Requested
ChildDef related (very boring)
- Abstract ChildDef_BlockQuote to work with all elements that only
allow blocks in them, required or optional
- Implement lenient <ruby> child validation
Wontfix
- Non-lossy smart alternate character encoding transformations (unless
patch provided)
- Pretty-printing HTML: users can use Tidy on the output on entire page
- Native content compression, whitespace stripping (don't rely on Tidy, make
sure we don't remove from <pre> or related tags): use gzip if this is
- Native content compression, whitespace stripping: use gzip if this is
really important

View File

@@ -1 +1 @@
3.1.0rc1
3.1.0

View File

@@ -1,8 +1,10 @@
Release 3.1.0rc1 is a release candidate aimed primarily at ironing out bugs
in HTML Purifier's shiny new __autoload system. There are lots of new features,
however; some notable ones include support for the !important CSS modifier,
display and visibility CSS properties with %CSS.AllowTricky, marquee
with %HTML.Proprietary (had you scared for a moment, hmm?), a kses() wrapper,
%CSS.AllowedProperties, %HTML.ForbiddenAttributes and %HTML.ForbiddenElements
and a totally revamped ConfigDoc system. And of course, the usual slew of
bugfixes.
HTML Purifier 3.1.0 is the second release series for HTML Purifier on PHP 5
as well as a security update related to URIs. It shifts over to using
autoload, and also includes support for the !important CSS modifier,
display and visibility CSS properties with %CSS.AllowTricky, marquee with
%HTML.Proprietary (had you scared for a moment, hmm?), a kses() wrapper,
%CSS.AllowedProperties, %HTML.ForbiddenAttributes and
%HTML.ForbiddenElements and a totally revamped ConfigDoc system. Since the
release candidate, there have also been a number of stability fixes such as
improved URI escaping, a change in serializer ID format, and a relaxed
format for %HTML.Allowed. And as always, numerous bugfixes.

View File

@@ -15,7 +15,7 @@ TODO:
- add blurbs to ToC
*/
if (version_compare(PHP_VERSION, '5.2.0', '<')) exit('PHP 5.2.0 or greater required.');
if (version_compare(PHP_VERSION, '5.2', '<')) exit('PHP 5.2+ required.');
error_reporting(E_ALL | E_STRICT);
chdir(dirname(__FILE__));
@@ -38,6 +38,7 @@ $configdoc_xml = 'configdoc.xml';
$xml_builder = new HTMLPurifier_ConfigSchema_Builder_Xml();
$xml_builder->openURI($configdoc_xml);
$xml_builder->build($interchange);
unset($xml_builder); // free handle
$xslt = new ConfigDoc_HTMLXSLTProcessor();
$xslt->importStylesheet(dirname(__FILE__) . "/styles/$style.xsl");

View File

@@ -227,7 +227,7 @@
</tr>
</xsl:template>
<xsl:template match="constraints/external/project">
<xsl:value-of select="." />
<li><xsl:value-of select="." /></li>
</xsl:template>
</xsl:stylesheet>

View File

@@ -5,7 +5,7 @@
<line>131</line>
</file>
<file name="HTMLPurifier/Lexer.php">
<line>93</line>
<line>85</line>
</file>
<file name="HTMLPurifier/Lexer/DirectLex.php">
<line>50</line>
@@ -18,22 +18,22 @@
</directive>
<directive id="CSS.Proprietary">
<file name="HTMLPurifier/CSSDefinition.php">
<line>201</line>
<line>202</line>
</file>
</directive>
<directive id="CSS.AllowTricky">
<file name="HTMLPurifier/CSSDefinition.php">
<line>205</line>
<line>206</line>
</file>
</directive>
<directive id="CSS.AllowImportant">
<file name="HTMLPurifier/CSSDefinition.php">
<line>209</line>
<line>210</line>
</file>
</directive>
<directive id="CSS.AllowedProperties">
<file name="HTMLPurifier/CSSDefinition.php">
<line>261</line>
<line>262</line>
</file>
</directive>
<directive id="Cache.DefinitionImpl">
@@ -63,19 +63,19 @@
</directive>
<directive id="Core.Encoding">
<file name="HTMLPurifier/Encoder.php">
<line>267</line>
<line>285</line>
<line>281</line>
<line>305</line>
</file>
</directive>
<directive id="Test.ForceNoIconv">
<file name="HTMLPurifier/Encoder.php">
<line>269</line>
<line>290</line>
<line>283</line>
<line>310</line>
</file>
</directive>
<directive id="Core.EscapeNonASCIICharacters">
<file name="HTMLPurifier/Encoder.php">
<line>287</line>
<line>307</line>
</file>
</directive>
<directive id="Core.MaintainLineNumbers">
@@ -83,7 +83,7 @@
<line>81</line>
</file>
<file name="HTMLPurifier/Lexer.php">
<line>90</line>
<line>82</line>
</file>
<file name="HTMLPurifier/Lexer/DirectLex.php">
<line>45</line>
@@ -91,17 +91,17 @@
</directive>
<directive id="Output.CommentScriptContents">
<file name="HTMLPurifier/Generator.php">
<line>40</line>
<line>41</line>
</file>
</directive>
<directive id="Output.TidyFormat">
<file name="HTMLPurifier/Generator.php">
<line>61</line>
<line>70</line>
</file>
</directive>
<directive id="Output.Newline">
<file name="HTMLPurifier/Generator.php">
<line>86</line>
<line>84</line>
</file>
</directive>
<directive id="HTML.BlockWrapper">
@@ -131,12 +131,12 @@
</directive>
<directive id="HTML.ForbiddenElements">
<file name="HTMLPurifier/HTMLDefinition.php">
<line>303</line>
<line>328</line>
</file>
</directive>
<directive id="HTML.ForbiddenAttributes">
<file name="HTMLPurifier/HTMLDefinition.php">
<line>304</line>
<line>329</line>
</file>
</directive>
<directive id="HTML.Trusted">
@@ -144,7 +144,7 @@
<line>198</line>
</file>
<file name="HTMLPurifier/Lexer.php">
<line>245</line>
<line>238</line>
</file>
<file name="HTMLPurifier/Lexer/DirectLex.php">
<line>34</line>
@@ -172,17 +172,17 @@
</directive>
<directive id="Core.Language">
<file name="HTMLPurifier/LanguageFactory.php">
<line>85</line>
<line>88</line>
</file>
</directive>
<directive id="Core.LexerImpl">
<file name="HTMLPurifier/Lexer.php">
<line>78</line>
<line>70</line>
</file>
</directive>
<directive id="Core.ConvertDocumentToFragment">
<file name="HTMLPurifier/Lexer.php">
<line>237</line>
<line>230</line>
</file>
</directive>
<directive id="URI.Host">
@@ -215,12 +215,12 @@
</directive>
<directive id="URI.Disable">
<file name="HTMLPurifier/AttrDef/URI.php">
<line>24</line>
<line>23</line>
</file>
</directive>
<directive id="URI.Munge">
<file name="HTMLPurifier/AttrDef/URI.php">
<line>78</line>
<line>68</line>
</file>
</directive>
<directive id="Core.ColorKeywords">

View File

@@ -367,7 +367,7 @@ Test.Example</pre>
For example, <code>HTMLPurifier_ConfigSchema_Builder_ConfigSchema</code>
generates a runtime <code>HTMLPurifier_ConfigSchema</code> object,
which <code>HTMLPurifier_Config</code> uses to validate its incoming
data. There is also a planned documentation builder.
data. There is also an XML serializer, which is used to build documentation.
</p>
<div id="version">$Id$</div>

View File

@@ -158,7 +158,7 @@
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
$def =& $config->getHTMLDefinition(true);</pre>
$def = $config->getHTMLDefinition(true);</pre>
<p>
Assuming that HTML Purifier has already been properly loaded (hint:
@@ -214,7 +214,7 @@ $def =& $config->getHTMLDefinition(true);</pre>
$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>
$def = $config->getHTMLDefinition(true);</pre>
<p>
A few things should be mentioned about the caching mechanism before
@@ -270,7 +270,7 @@ $def =& $config->getHTMLDefinition(true);</pre>
$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 = $config->getHTMLDefinition(true);
<strong>$def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');</strong></pre>
<p>
@@ -388,7 +388,7 @@ $def =& $config->getHTMLDefinition(true);
$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 = $config->getHTMLDefinition(true);
<strong>$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
array('_blank','_self','_target','_top')
));</strong></pre>
@@ -735,11 +735,11 @@ $def =& $config->getHTMLDefinition(true);
$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 = $config->getHTMLDefinition(true);
$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
array('_blank','_self','_target','_top')
));
<strong>$form =& $def->addElement(
<strong>$form = $def->addElement(
'form', // name
'Block', // content set
'Flow', // allowed children

View File

@@ -35,7 +35,7 @@
{
public $name = '<strong>NameOfFilter</strong>';
public function prepare($config) {}
public function filter(&$uri, $config, &$context) {}
public function filter(&$uri, $config, $context) {}
}</pre>
<p>
@@ -60,8 +60,8 @@
public function HTMLPurifier_URI($scheme, $userinfo, $host, $port, $path, $query, $fragment);
public function toString();
public function copy();
public function getSchemeObj($config, &$context);
public function validate($config, &$context);
public function getSchemeObj($config, $context);
public function validate($config, $context);
}</pre>
<p>
@@ -139,7 +139,7 @@
<pre>class HTMLPurifier_URIFilter_ConvertIDNToPunycode extends HTMLPurifier_URIFilter
{
public $name = 'ConvertIDNToPunycode';
public function filter(&$uri, $config, &$context) {
public function filter(&$uri, $config, $context) {
if (is_null($uri->host)) return true;
if ($uri->host == utf8_decode($uri->host)) {
// is ASCII, abort
@@ -163,7 +163,7 @@
to use it. Fortunately, this part's simple:
</p>
<pre>$uri =& $config->getDefinition('URI');
<pre>$uri = $config->getDefinition('URI');
$uri->addFilter(new HTMLPurifier_URIFilter_<strong>NameOfFilter</strong>());</pre>
<p>
@@ -177,7 +177,7 @@ $uri->addFilter(new HTMLPurifier_URIFilter_<strong>NameOfFilter</strong>());</pr
'URI', '<strong>NameOfFilter</strong>', false, 'bool',
'<strong>What your filter does.</strong>'
);
$uri =& $config->getDefinition('URI', true);
$uri = $config->getDefinition('URI', true);
$uri->registerFilter(new HTMLPurifier_URIFilter_<strong>NameOfFilter</strong>());
</pre>

View File

@@ -75,9 +75,7 @@ passes through HTML Purifier <em>unharmed</em>.
<p>And the corresponding usage:</p>
<pre>&lt;?php
// assuming $purifier is an instance of HTMLPurifier
require_once 'HTMLPurifier/Filter/YouTube.php';
$purifier-&gt;addFilter(new HTMLPurifier_Filter_YouTube());
$config->set('Filter', 'YouTube', true);
?&gt;</pre>
<p>There is a bit going in the two code snippets, so let's explain.</p>

View File

@@ -7,7 +7,7 @@
* primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
* FILE, changes will be overwritten the next time the script is run.
*
* @version 3.0.0
* @version 3.1.0
*
* @warning
* You must *not* include any other HTML Purifier files before this file,
@@ -41,7 +41,6 @@ require 'HTMLPurifier/ElementDef.php';
require 'HTMLPurifier/Encoder.php';
require 'HTMLPurifier/EntityLookup.php';
require 'HTMLPurifier/EntityParser.php';
require 'HTMLPurifier/Error.php';
require 'HTMLPurifier/ErrorCollector.php';
require 'HTMLPurifier/Exception.php';
require 'HTMLPurifier/Filter.php';
@@ -82,6 +81,7 @@ require 'HTMLPurifier/AttrDef/CSS/BackgroundPosition.php';
require 'HTMLPurifier/AttrDef/CSS/Border.php';
require 'HTMLPurifier/AttrDef/CSS/Color.php';
require 'HTMLPurifier/AttrDef/CSS/Composite.php';
require 'HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php';
require 'HTMLPurifier/AttrDef/CSS/Filter.php';
require 'HTMLPurifier/AttrDef/CSS/Font.php';
require 'HTMLPurifier/AttrDef/CSS/FontFamily.php';
@@ -116,6 +116,7 @@ require 'HTMLPurifier/AttrTransform/ImgSpace.php';
require 'HTMLPurifier/AttrTransform/Lang.php';
require 'HTMLPurifier/AttrTransform/Length.php';
require 'HTMLPurifier/AttrTransform/Name.php';
require 'HTMLPurifier/AttrTransform/ScriptRequired.php';
require 'HTMLPurifier/ChildDef/Chameleon.php';
require 'HTMLPurifier/ChildDef/Custom.php';
require 'HTMLPurifier/ChildDef/Empty.php';

View File

@@ -15,13 +15,11 @@
* -# Generating HTML from the purified tokens.
*
* However, most users will only need to interface with the HTMLPurifier
* class, so this massive amount of infrastructure is usually concealed.
* If you plan on working with the internals, be sure to include
* HTMLPurifier_ConfigSchema and HTMLPurifier_Config.
* and HTMLPurifier_Config.
*/
/*
HTML Purifier 3.1.0rc1 - Standards Compliant HTML Filtering
HTML Purifier 3.1.0 - Standards Compliant HTML Filtering
Copyright (C) 2006-2008 Edward Z. Yang
This library is free software; you can redistribute it and/or
@@ -57,7 +55,10 @@ class HTMLPurifier
{
/** Version of HTML Purifier */
public $version = '3.1.0rc1';
public $version = '3.1.0';
/** Constant with version of HTML Purifier */
const VERSION = '3.1.0';
/** Global configuration object */
public $config;
@@ -89,7 +90,6 @@ class HTMLPurifier
$this->config = HTMLPurifier_Config::create($config);
$this->strategy = new HTMLPurifier_Strategy_Core();
$this->generator = new HTMLPurifier_Generator();
}
@@ -123,8 +123,8 @@ class HTMLPurifier
$context = new HTMLPurifier_Context();
// our friendly neighborhood generator, all primed with configuration too!
$this->generator->generateFromTokens(array(), $config, $context);
// setup HTML generator
$this->generator = new HTMLPurifier_Generator($config, $context);
$context->register('Generator', $this->generator);
// set up global context variables
@@ -177,8 +177,7 @@ class HTMLPurifier
$html, $config, $context
),
$config, $context
),
$config, $context
)
);
for ($i = $filter_size - 1; $i >= 0; $i--) {
@@ -209,9 +208,10 @@ class HTMLPurifier
/**
* Singleton for enforcing just one HTML Purifier in your system
* @param $prototype Optional prototype HTMLPurifier instance to
* overload singleton with.
* overload singleton with, or HTMLPurifier_Config
* instance to configure the generated version with.
*/
public static function getInstance($prototype = null) {
public static function instance($prototype = null) {
if (!self::$instance || $prototype) {
if ($prototype instanceof HTMLPurifier) {
self::$instance = $prototype;
@@ -224,4 +224,11 @@ class HTMLPurifier
return self::$instance;
}
/**
* @note Backwards compatibility, see instance()
*/
public static function getInstance($prototype = null) {
return HTMLPurifier::instance($prototype);
}
}

View File

@@ -35,7 +35,6 @@ require_once $__dir . '/HTMLPurifier/ElementDef.php';
require_once $__dir . '/HTMLPurifier/Encoder.php';
require_once $__dir . '/HTMLPurifier/EntityLookup.php';
require_once $__dir . '/HTMLPurifier/EntityParser.php';
require_once $__dir . '/HTMLPurifier/Error.php';
require_once $__dir . '/HTMLPurifier/ErrorCollector.php';
require_once $__dir . '/HTMLPurifier/Exception.php';
require_once $__dir . '/HTMLPurifier/Filter.php';
@@ -76,6 +75,7 @@ require_once $__dir . '/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Border.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Color.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Composite.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Filter.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Font.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/FontFamily.php';
@@ -110,6 +110,7 @@ require_once $__dir . '/HTMLPurifier/AttrTransform/ImgSpace.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Lang.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Length.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Name.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Custom.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Empty.php';

View File

@@ -70,9 +70,10 @@ abstract class HTMLPurifier_AttrDef
* @return Created AttrDef object corresponding to $string
*/
public function make($string) {
// default implementation, return flyweight of this object
// if overloaded, it is *necessary* for you to clone the
// object (usually by instantiating a new copy) and return that
// default implementation, return a flyweight of this object.
// If $string has an effect on the returned object (i.e. you
// need to overload this method), it is best
// to clone or instantiate new copies. (Instantiation is safer.)
return $this;
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* Decorator which enables CSS properties to be disabled for specific elements.
*/
class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef
{
protected $def, $element;
/**
* @param $def Definition to wrap
* @param $element Element to deny
*/
public function __construct($def, $element) {
$this->def = $def;
$this->element = $element;
}
/**
* Checks if CurrentToken is set and equal to $this->element
*/
public function validate($string, $config, $context) {
$token = $context->get('CurrentToken', true);
if ($token && $token->name == $this->element) return false;
return $this->def->validate($string, $config, $context);
}
}

View File

@@ -3,7 +3,7 @@
/**
* Decorator which enables !important to be used in CSS values.
*/
class HTMLPurifier_AttrDef_CSS_ImportantDecorator
class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef
{
protected $def, $allow;

View File

@@ -7,7 +7,7 @@
class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
{
protected $parser, $percentEncoder;
protected $parser;
protected $embedsResource;
/**
@@ -15,7 +15,6 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
*/
public function __construct($embeds_resource = false) {
$this->parser = new HTMLPurifier_URIParser();
$this->percentEncoder = new HTMLPurifier_PercentEncoder();
$this->embedsResource = (bool) $embeds_resource;
}
@@ -23,9 +22,7 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
if ($config->get('URI', 'Disable')) return false;
// initial operations
$uri = $this->parseCDATA($uri);
$uri = $this->percentEncoder->normalize($uri);
// parse the URI
$uri = $this->parser->parse($uri);
@@ -42,7 +39,7 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
if (!$result) break;
// chained filtering
$uri_def =& $config->getDefinition('URI');
$uri_def = $config->getDefinition('URI');
$result = $uri_def->filter($uri, $config, $context);
if (!$result) break;
@@ -61,13 +58,6 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
$context->destroy('EmbeddedURI');
if (!$ok) return false;
// munge scheme off if necessary (this must be last)
if (!is_null($uri->scheme) && is_null($uri->host)) {
if ($uri_def->defaultScheme == $uri->scheme) {
$uri->scheme = null;
}
}
// back to string
$result = $uri->toString();

View File

@@ -36,11 +36,23 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
$ipv4 = $this->ipv4->validate($string, $config, $context);
if ($ipv4 !== false) return $ipv4;
// validate a domain name here, do filtering, etc etc etc
// A regular domain name.
// We could use this, but it would break I18N domain names
//$match = preg_match('/^[a-z0-9][\w\-\.]*[a-z0-9]$/i', $string);
//if (!$match) return false;
// This breaks I18N domain names, but we don't have proper IRI support,
// so force users to insert Punycode. If there's complaining we'll
// try to fix things into an international friendly form.
// The productions describing this are:
$a = '[a-z]'; // alpha
$an = '[a-z0-9]'; // alphanum
$and = '[a-z0-9-]'; // alphanum | "-"
// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
$domainlabel = "$an($and*$an)?";
// toplabel = alpha | alpha *( alphanum | "-" ) alphanum
$toplabel = "$a($and*$an)?";
// hostname = *( domainlabel "." ) toplabel [ "." ]
$match = preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string);
if (!$match) return false;
return $string;
}

View File

@@ -0,0 +1,14 @@
<?php
/**
* Implements required attribute stipulation for <script>
*/
class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) {
if (!isset($attr['type'])) {
$attr['type'] = 'text/javascript';
}
return $attr;
}
}

View File

@@ -37,7 +37,7 @@ class HTMLPurifier_Bootstrap
public static function autoload($class) {
$file = HTMLPurifier_Bootstrap::getPath($class);
if (!$file) return false;
require $file;
require HTMLPURIFIER_PREFIX . '/' . $file;
return true;
}
@@ -48,11 +48,13 @@ class HTMLPurifier_Bootstrap
if (strncmp('HTMLPurifier', $class, 12) !== 0) return false;
// Custom implementations
if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) {
$code = str_replace('_', '-', substr($class, 22));
return 'HTMLPurifier/Language/classes/' . $code . '.php';
$code = str_replace('_', '-', substr($class, 22));
$file = 'HTMLPurifier/Language/classes/' . $code . '.php';
} else {
$file = str_replace('_', '/', $class) . '.php';
}
// Standard implementation
return str_replace('_', '/', $class) . '.php';
if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) return false;
return $file;
}
/**

View File

@@ -150,12 +150,13 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
));
$this->info['width'] =
$this->info['height'] =
$this->info['height'] =
new HTMLPurifier_AttrDef_CSS_DenyElementDecorator(
new HTMLPurifier_AttrDef_CSS_Composite(array(
new HTMLPurifier_AttrDef_CSS_Length(true),
new HTMLPurifier_AttrDef_CSS_Percentage(true),
new HTMLPurifier_AttrDef_Enum(array('auto'))
));
)), 'img');
$this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();

View File

@@ -3,7 +3,7 @@
/**
* Defines allowed child nodes and validates tokens against it.
*/
class HTMLPurifier_ChildDef
abstract class HTMLPurifier_ChildDef
{
/**
* Type of child definition, usually right-most part of class name lowercase.
@@ -34,9 +34,7 @@ class HTMLPurifier_ChildDef
* @return bool false to remove parent node
* @return array of replacement child tokens
*/
public function validateChildren($tokens_of_children, $config, $context) {
trigger_error('Call to abstract function', E_USER_ERROR);
}
abstract public function validateChildren($tokens_of_children, $config, $context);
}

View File

@@ -20,7 +20,7 @@ class HTMLPurifier_Config
/**
* HTML Purifier's version
*/
public $version = '3.1.0rc1';
public $version = '3.1.0';
/**
* Bool indicator whether or not to automatically finalize
@@ -72,7 +72,7 @@ class HTMLPurifier_Config
* @param $definition HTMLPurifier_ConfigSchema that defines what directives
* are allowed.
*/
public function __construct(&$definition) {
public function __construct($definition) {
$this->conf = $definition->defaults; // set up, copy in defaults
$this->def = $definition; // keep a copy around for checking
$this->parser = new HTMLPurifier_VarParser_Flexible();
@@ -107,7 +107,7 @@ class HTMLPurifier_Config
* @return Default HTMLPurifier_Config object.
*/
public static function createDefault() {
$definition =& HTMLPurifier_ConfigSchema::instance();
$definition = HTMLPurifier_ConfigSchema::instance();
$config = new HTMLPurifier_Config($definition);
return $config;
}
@@ -254,21 +254,21 @@ class HTMLPurifier_Config
}
/**
* Retrieves reference to the HTML definition.
* Retrieves object reference to the HTML definition.
* @param $raw Return a copy that has not been setup yet. Must be
* called before it's been setup, otherwise won't work.
*/
public function &getHTMLDefinition($raw = false) {
$def =& $this->getDefinition('HTML', $raw);
return $def; // prevent PHP 4.4.0 from complaining
public function getHTMLDefinition($raw = false) {
return $this->getDefinition('HTML', $raw);
}
/**
* Retrieves reference to the CSS definition
* Retrieves object reference to the CSS definition
* @param $raw Return a copy that has not been setup yet. Must be
* called before it's been setup, otherwise won't work.
*/
public function &getCSSDefinition($raw = false) {
$def =& $this->getDefinition('CSS', $raw);
return $def;
public function getCSSDefinition($raw = false) {
return $this->getDefinition('CSS', $raw);
}
/**
@@ -276,7 +276,7 @@ class HTMLPurifier_Config
* @param $type Type of definition: HTML, CSS, etc
* @param $raw Whether or not definition should be returned raw
*/
public function &getDefinition($type, $raw = false) {
public function getDefinition($type, $raw = false) {
if (!$this->finalized && $this->autoFinalize) $this->finalize();
$factory = HTMLPurifier_DefinitionCacheFactory::instance();
$cache = $factory->create($type, $this);
@@ -310,17 +310,13 @@ class HTMLPurifier_Config
} elseif ($type == 'URI') {
$this->definitions[$type] = new HTMLPurifier_URIDefinition();
} else {
trigger_error("Definition of $type type not supported");
$false = false;
return $false;
throw new HTMLPurifier_Exception("Definition of $type type not supported");
}
// quick abort if raw
if ($raw) {
if (is_null($this->get($type, 'DefinitionID'))) {
// fatally error out if definition ID not set
trigger_error("Cannot retrieve raw version without specifying %$type.DefinitionID", E_USER_ERROR);
$false = new HTMLPurifier_Error();
return $false;
throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID");
}
return $this->definitions[$type];
}
@@ -407,7 +403,7 @@ class HTMLPurifier_Config
* @param $mq_fix Boolean whether or not to enable magic quotes fix
* @param $schema Instance of HTMLPurifier_ConfigSchema to use, if not global copy
*/
public static function loadArrayFromForm($array, $index, $allowed = true, $mq_fix = true, $schema = null) {
public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
$ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema);
$config = HTMLPurifier_Config::create($ret, $schema);
return $config;
@@ -417,7 +413,7 @@ class HTMLPurifier_Config
* Merges in configuration values from $_GET/$_POST to object. NOT STATIC.
* @note Same parameters as loadArrayFromForm
*/
public function mergeArrayFromForm($array, $index, $allowed = true, $mq_fix = true) {
public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) {
$ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def);
$this->loadArray($ret);
}
@@ -426,8 +422,8 @@ class HTMLPurifier_Config
* Prepares an array from a form into something usable for the more
* strict parts of HTMLPurifier_Config
*/
public static function prepareArrayFromForm($array, $index, $allowed = true, $mq_fix = true, $schema = null) {
$array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
$mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc();
$allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema);

View File

@@ -3,7 +3,7 @@
/**
* Base class for configuration entity
*/
class HTMLPurifier_ConfigDef {
abstract class HTMLPurifier_ConfigDef {
public $class = false;
}

View File

@@ -40,7 +40,7 @@ class HTMLPurifier_ConfigSchema {
/**
* Retrieves an instance of the application-wide configuration definition.
*/
public static function &instance($prototype = null) {
public static function instance($prototype = null) {
if ($prototype !== null) {
HTMLPurifier_ConfigSchema::$singleton = $prototype;
} elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) {
@@ -104,9 +104,8 @@ class HTMLPurifier_ConfigSchema {
* @param $allowed Lookup array of allowed values
*/
public function addAllowedValues($namespace, $name, $allowed) {
$directive =& $this->info[$namespace][$name];
$type = $directive->type;
$directive->allowed = $allowed;
$type = $this->info[$namespace][$name]->type;
$this->info[$namespace][$name]->allowed = $allowed;
}
/**
@@ -130,21 +129,21 @@ class HTMLPurifier_ConfigSchema {
$type = $type_values[0];
$modifier = isset($type_values[1]) ? $type_values[1] : false;
$allow_null = ($modifier === 'null');
$def =& HTMLPurifier_ConfigSchema::instance();
$def = HTMLPurifier_ConfigSchema::instance();
$def->add($namespace, $name, $default, $type, $allow_null);
}
/** @see HTMLPurifier_ConfigSchema->addNamespace() */
public static function defineNamespace($namespace, $description) {
HTMLPurifier_ConfigSchema::deprecated(__METHOD__);
$def =& HTMLPurifier_ConfigSchema::instance();
$def = HTMLPurifier_ConfigSchema::instance();
$def->addNamespace($namespace);
}
/** @see HTMLPurifier_ConfigSchema->addValueAliases() */
public static function defineValueAliases($namespace, $name, $aliases) {
HTMLPurifier_ConfigSchema::deprecated(__METHOD__);
$def =& HTMLPurifier_ConfigSchema::instance();
$def = HTMLPurifier_ConfigSchema::instance();
$def->addValueAliases($namespace, $name, $aliases);
}
@@ -155,14 +154,14 @@ class HTMLPurifier_ConfigSchema {
foreach ($allowed_values as $value) {
$allowed[$value] = true;
}
$def =& HTMLPurifier_ConfigSchema::instance();
$def = HTMLPurifier_ConfigSchema::instance();
$def->addAllowedValues($namespace, $name, $allowed);
}
/** @see HTMLPurifier_ConfigSchema->addAlias() */
public static function defineAlias($namespace, $name, $new_namespace, $new_name) {
HTMLPurifier_ConfigSchema::deprecated(__METHOD__);
$def =& HTMLPurifier_ConfigSchema::instance();
$def = HTMLPurifier_ConfigSchema::instance();
$def->addAlias($namespace, $name, $new_namespace, $new_name);
}

View File

@@ -71,8 +71,10 @@ class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter
$this->startElement('constraints');
if ($directive->version) $this->writeElement('version', $directive->version);
$this->writeElement('type', $directive->type);
if ($directive->typeAllowsNull) $this->writeAttribute('allow-null', 'yes');
$this->startElement('type');
if ($directive->typeAllowsNull) $this->writeAttribute('allow-null', 'yes');
$this->text($directive->type);
$this->endElement(); // type
if ($directive->allowed) {
$this->startElement('allowed');
foreach ($directive->allowed as $value => $x) $this->writeElement('value', $value);

View File

@@ -17,21 +17,27 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
$builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder();
$interchange = new HTMLPurifier_ConfigSchema_Interchange();
if (!$dir) $dir = realpath(dirname(__FILE__) . '/schema/');
if (!$dir) $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema/';
$info = parse_ini_file($dir . 'info.ini');
$interchange->name = $info['name'];
$files = array();
$dh = opendir($dir);
while (false !== ($file = readdir($dh))) {
if (!$file || $file[0] == '.' || strrchr($file, '.') !== '.txt') {
continue;
}
$files[] = $file;
}
closedir($dh);
sort($files);
foreach ($files as $file) {
$builder->build(
$interchange,
new HTMLPurifier_StringHash( $parser->parseFile($dir . $file) )
);
}
closedir($dh);
return $interchange;
}

File diff suppressed because one or more lines are too long

View File

@@ -21,3 +21,17 @@ $styles = $purifier->context->get('StyleBlocks');
foreach ($styles as $style) {
echo '<style type="text/css">' . $style . "</style>\n";
}]]></pre>
<p>
<strong>Warning:</strong> It is possible for a user to mount an
imagecrash attack using this CSS. Counter-measures are difficult;
it is not simply enough to limit the range of CSS lengths (using
relative lengths with many nesting levels allows for large values
to be attained without actually specifying them in the stylesheet),
and the flexible nature of selectors makes it difficult to selectively
disable lengths on image tags (HTML Purifier, however, does disable
CSS width and height in inline styling). There are probably two effective
counter measures: an explicit width and height set to auto in all
images in your document (unlikely) or the disabling of width and
height (somewhat reasonable). Whether or not these measures should be
used is left to the reader.
</p>

View File

@@ -4,7 +4,17 @@ VERSION: 3.1.0
DEFAULT: array()
--DESCRIPTION--
<p>
This directive complements %HTML.ForbiddenElements and is the inverse of
%HTML.AllowedAttributes. Please see the former for a discussion of why you
While this directive is similar to %HTML.AllowedAttributes, for
forwards-compatibility with XML, this attribute has a different syntax. Instead of
<code>tag.attr</code>, use <code>tag@attr</code>. To disallow <code>href</code>
attributes in <code>a</code> tags, set this directive to
<code>a@href</code>. You can also disallow an attribute globally with
<code>attr</code> or <code>*@attr</code> (either syntax is fine; the latter
is provided for consistency with %HTML.AllowedAttributes).
</p>
<p>
<strong>Warning:</strong> This directive complements %HTML.ForbiddenElements,
accordingly, check
out that directive for a discussion of why you
should think twice before using this directive.
</p>

View File

@@ -4,6 +4,8 @@
* Registry object that contains information about the current context.
* @warning Is a bit buggy when variables are set to null: it thinks
* they don't exist! So use false instead, please.
* @note Since the variables Context deals with may not be objects,
* references are very important here! Do not remove!
*/
class HTMLPurifier_Context
{
@@ -16,7 +18,7 @@ class HTMLPurifier_Context
/**
* Registers a variable into the context.
* @param $name String name
* @param $ref Variable to be registered
* @param $ref Reference to variable to be registered
*/
public function register($name, &$ref) {
if (isset($this->_storage[$name])) {

View File

@@ -26,8 +26,8 @@ abstract class HTMLPurifier_DefinitionCache
* @param Instance of HTMLPurifier_Config
*/
public function generateKey($config) {
return $config->version . '-' . // possibly replace with function calls
$config->getBatchSerial($this->type) . '-' .
return $config->version . ',' . // possibly replace with function calls
$config->getBatchSerial($this->type) . ',' .
$config->get($this->type, 'DefinitionRev');
}
@@ -38,8 +38,8 @@ abstract class HTMLPurifier_DefinitionCache
* @param $config Instance of HTMLPurifier_Config to test against
*/
public function isOld($key, $config) {
if (substr_count($key, '-') < 2) return true;
list($version, $hash, $revision) = explode('-', $key, 3);
if (substr_count($key, ',') < 2) return true;
list($version, $hash, $revision) = explode(',', $key, 3);
$compare = version_compare($version, $config->version);
// version mismatch, is always old
if ($compare != 0) return true;

View File

@@ -100,18 +100,7 @@ class HTMLPurifier_DefinitionCache_Serializer extends
* @return Number of bytes written if success, or false if failure.
*/
private function _write($file, $data) {
static $file_put_contents;
if ($file_put_contents === null) {
$file_put_contents = function_exists('file_put_contents');
}
if ($file_put_contents) {
return file_put_contents($file, $data);
}
$fh = fopen($file, 'w');
if (!$fh) return false;
$status = fwrite($fh, $data);
fclose($fh);
return $status;
return file_put_contents($file, $data);
}
/**
@@ -130,7 +119,9 @@ class HTMLPurifier_DefinitionCache_Serializer extends
} elseif (!$this->_testPermissions($base)) {
return false;
}
$old = umask(0022); // disable group and world writes
mkdir($directory);
umask($old);
} elseif (!$this->_testPermissions($directory)) {
return false;
}

View File

@@ -20,7 +20,7 @@ class HTMLPurifier_DefinitionCacheFactory
/**
* Retrieves an instance of global definition cache factory.
*/
public static function &instance($prototype = null) {
public static function instance($prototype = null) {
static $instance;
if ($prototype !== null) {
$instance = $prototype;
@@ -45,11 +45,10 @@ class HTMLPurifier_DefinitionCacheFactory
* @param $name Name of definitions handled by cache
* @param $config Instance of HTMLPurifier_Config
*/
public function &create($type, $config) {
public function create($type, $config) {
$method = $config->get('Cache', 'DefinitionImpl');
if ($method === null) {
$null = new HTMLPurifier_DefinitionCache_Null($type);
return $null;
return new HTMLPurifier_DefinitionCache_Null($type);
}
if (!empty($this->caches[$method][$type])) {
return $this->caches[$method][$type];

View File

@@ -21,9 +21,9 @@ class HTMLPurifier_DoctypeRegistry
* @param $modules Modules doctype will load
* @param $modules_for_modes Modules doctype will load for certain modes
* @param $aliases Alias names for doctype
* @return Reference to registered doctype (usable for further editing)
* @return Editable registered doctype
*/
public function &register($doctype, $xml = true, $modules = array(),
public function register($doctype, $xml = true, $modules = array(),
$tidy_modules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null
) {
if (!is_array($modules)) $modules = array($modules);
@@ -34,7 +34,7 @@ class HTMLPurifier_DoctypeRegistry
$doctype, $xml, $modules, $tidy_modules, $aliases, $dtd_public, $dtd_system
);
}
$this->doctypes[$doctype->name] =& $doctype;
$this->doctypes[$doctype->name] = $doctype;
$name = $doctype->name;
// hookup aliases
foreach ($doctype->aliases as $alias) {
@@ -51,9 +51,9 @@ class HTMLPurifier_DoctypeRegistry
* @note This function resolves aliases
* @note When possible, use the more fully-featured make()
* @param $doctype Name of doctype
* @return Reference to doctype object
* @return Editable doctype object
*/
public function &get($doctype) {
public function get($doctype) {
if (isset($this->aliases[$doctype])) $doctype = $this->aliases[$doctype];
if (!isset($this->doctypes[$doctype])) {
trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR);

View File

@@ -14,6 +14,11 @@ class HTMLPurifier_Encoder
trigger_error('Cannot instantiate encoder, call methods statically', E_USER_ERROR);
}
/**
* Error-handler that mutes errors, alternative to shut-up operator.
*/
private static function muteErrorHandler() {}
/**
* Cleans a UTF-8 string for well-formedness and SGML validity
*
@@ -57,9 +62,18 @@ class HTMLPurifier_Encoder
static $iconv = null;
if ($iconv === null) $iconv = function_exists('iconv');
// UTF-8 validity is checked since PHP 4.3.5
// This is an optimization: if the string is already valid UTF-8, no
// need to do iconv/php stuff. 99% of the time, this will be the case.
if (preg_match('/^.{1}/us', $str)) {
return strtr($str, $non_sgml_chars);
}
if ($iconv && !$force_php) {
// do the shortcut way
$str = @iconv('UTF-8', 'UTF-8//IGNORE', $str);
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
$str = iconv('UTF-8', 'UTF-8//IGNORE', $str);
restore_error_handler();
return strtr($str, $non_sgml_chars);
}
@@ -267,9 +281,15 @@ class HTMLPurifier_Encoder
$encoding = $config->get('Core', 'Encoding');
if ($encoding === 'utf-8') return $str;
if ($iconv && !$config->get('Test', 'ForceNoIconv')) {
return @iconv($encoding, 'utf-8//IGNORE', $str);
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
$str = iconv($encoding, 'utf-8//IGNORE', $str);
restore_error_handler();
return $str;
} elseif ($encoding === 'iso-8859-1') {
return @utf8_encode($str);
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
$str = utf8_encode($str);
restore_error_handler();
return $str;
}
trigger_error('Encoding not supported', E_USER_ERROR);
}
@@ -288,9 +308,15 @@ class HTMLPurifier_Encoder
$str = HTMLPurifier_Encoder::convertToASCIIDumbLossless($str);
}
if ($iconv && !$config->get('Test', 'ForceNoIconv')) {
return @iconv('utf-8', $encoding . '//IGNORE', $str);
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
$str = iconv('utf-8', $encoding . '//IGNORE', $str);
restore_error_handler();
return $str;
} elseif ($encoding === 'iso-8859-1') {
return @utf8_decode($str);
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
$str = utf8_decode($str);
restore_error_handler();
return $str;
}
trigger_error('Encoding not supported', E_USER_ERROR);
}

View File

@@ -1,7 +0,0 @@
<?php
/**
* Return object from functions that signifies error when null doesn't cut it
*/
class HTMLPurifier_Error {}

View File

@@ -15,7 +15,7 @@ class HTMLPurifier_ErrorCollector
public function __construct($context) {
$this->locale =& $context->get('Locale');
$this->generator =& $context->get('Generator');
$this->context =& $context;
$this->context = $context;
}
/**

View File

@@ -11,81 +11,79 @@ class HTMLPurifier_Generator
{
/**
* Bool cache of %HTML.XHTML
* @private
* Whether or not generator should produce XML output
*/
private $_xhtml = true;
/**
* Bool cache of %Output.CommentScriptContents
* @private
* :HACK: Whether or not generator should comment the insides of <script> tags
*/
private $_scriptFix = false;
/**
* Cache of HTMLDefinition
* @private
* Cache of HTMLDefinition during HTML output to determine whether or
* not attributes should be minimized.
*/
private $_def;
/**
* Configuration for the generator
*/
protected $config;
/**
* @param $config Instance of HTMLPurifier_Config
* @param $context Instance of HTMLPurifier_Context
*/
public function __construct($config = null, $context = null) {
if (!$config) $config = HTMLPurifier_Config::createDefault();
$this->config = $config;
$this->_scriptFix = $config->get('Output', 'CommentScriptContents');
$this->_def = $config->getHTMLDefinition();
$this->_xhtml = $this->_def->doctype->xml;
}
/**
* Generates HTML from an array of tokens.
* @param $tokens Array of HTMLPurifier_Token
* @param $config HTMLPurifier_Config object
* @return Generated HTML
*/
public function generateFromTokens($tokens, $config, $context) {
$html = '';
if (!$config) $config = HTMLPurifier_Config::createDefault();
$this->_scriptFix = $config->get('Output', 'CommentScriptContents');
$this->_def = $config->getHTMLDefinition();
$this->_xhtml = $this->_def->doctype->xml;
public function generateFromTokens($tokens) {
if (!$tokens) return '';
// Basic algorithm
$html = '';
for ($i = 0, $size = count($tokens); $i < $size; $i++) {
if ($this->_scriptFix && $tokens[$i]->name === 'script'
&& $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) {
// script special case
// the contents of the script block must be ONE token
// for this to work
// for this to work.
$html .= $this->generateFromToken($tokens[$i++]);
$html .= $this->generateScriptFromToken($tokens[$i++]);
// We're not going to do this: it wouldn't be valid anyway
//while ($tokens[$i]->name != 'script') {
// $html .= $this->generateScriptFromToken($tokens[$i++]);
//}
}
$html .= $this->generateFromToken($tokens[$i]);
}
if ($config->get('Output', 'TidyFormat') && extension_loaded('tidy')) {
$tidy_options = array(
// Tidy cleanup
if (extension_loaded('tidy') && $this->config->get('Output', 'TidyFormat')) {
$tidy = new Tidy;
$tidy->parseString($html, array(
'indent'=> true,
'output-xhtml' => $this->_xhtml,
'show-body-only' => true,
'indent-spaces' => 2,
'wrap' => 68,
);
if (version_compare(PHP_VERSION, '5', '<')) {
tidy_set_encoding('utf8');
foreach ($tidy_options as $key => $value) {
tidy_setopt($key, $value);
}
tidy_parse_string($html);
tidy_clean_repair();
$html = tidy_get_output();
} else {
$tidy = new Tidy;
$tidy->parseString($html, $tidy_options, 'utf8');
$tidy->cleanRepair();
$html = (string) $tidy;
}
), 'utf8');
$tidy->cleanRepair();
$html = (string) $tidy; // explicit cast necessary
}
// normalize newlines to system
$nl = $config->get('Output', 'Newline');
// Normalize newlines to system defined value
$nl = $this->config->get('Output', 'Newline');
if ($nl === null) $nl = PHP_EOL;
$html = str_replace("\n", $nl, $html);
if ($nl !== "\n") $html = str_replace("\n", $nl, $html);
return $html;
}
@@ -95,8 +93,11 @@ class HTMLPurifier_Generator
* @return Generated HTML
*/
public function generateFromToken($token) {
if (!$token instanceof HTMLPurifier_Token) return '';
if ($token instanceof HTMLPurifier_Token_Start) {
if (!$token instanceof HTMLPurifier_Token) {
trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING);
return '';
} elseif ($token instanceof HTMLPurifier_Token_Start) {
$attr = $this->generateAttributes($token->attr, $token->name);
return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>';
@@ -106,11 +107,11 @@ class HTMLPurifier_Generator
} elseif ($token instanceof HTMLPurifier_Token_Empty) {
$attr = $this->generateAttributes($token->attr, $token->name);
return '<' . $token->name . ($attr ? ' ' : '') . $attr .
( $this->_xhtml ? ' /': '' )
( $this->_xhtml ? ' /': '' ) // <br /> v. <br>
. '>';
} elseif ($token instanceof HTMLPurifier_Token_Text) {
return $this->escape($token->data);
return $this->escape($token->data, ENT_NOQUOTES);
} elseif ($token instanceof HTMLPurifier_Token_Comment) {
return '<!--' . $token->data . '-->';
@@ -127,25 +128,27 @@ class HTMLPurifier_Generator
*/
public function generateScriptFromToken($token) {
if (!$token instanceof HTMLPurifier_Token_Text) return $this->generateFromToken($token);
// return '<!--' . "\n" . trim($token->data) . "\n" . '// -->';
// more advanced version:
// thanks <http://lachy.id.au/log/2005/05/script-comments>
// Thanks <http://lachy.id.au/log/2005/05/script-comments>
$data = preg_replace('#//\s*$#', '', $token->data);
return '<!--//--><![CDATA[//><!--' . "\n" . trim($data) . "\n" . '//--><!]]>';
}
/**
* Generates attribute declarations from attribute array.
* @note This does not include the leading or trailing space.
* @param $assoc_array_of_attributes Attribute array
* @param $element Name of element attributes are for, used to check
* attribute minimization.
* @return Generate HTML fragment for insertion.
*/
public function generateAttributes($assoc_array_of_attributes, $element) {
public function generateAttributes($assoc_array_of_attributes, $element = false) {
$html = '';
foreach ($assoc_array_of_attributes as $key => $value) {
if (!$this->_xhtml) {
// remove namespaced attributes
// Remove namespaced attributes
if (strpos($key, ':') !== false) continue;
if (!empty($this->_def->info[$element]->attr[$key]->minimized)) {
// Check if we should minimize the attribute: val="val" -> val
if ($element && !empty($this->_def->info[$element]->attr[$key]->minimized)) {
$html .= $key . ' ';
continue;
}
@@ -157,11 +160,16 @@ class HTMLPurifier_Generator
/**
* Escapes raw text data.
* @todo This really ought to be protected, but until we have a facility
* for properly generating HTML here w/o using tokens, it stays
* public.
* @param $string String data to escape for HTML.
* @param $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is
* permissible for non-attribute output.
* @return String escaped data.
*/
public function escape($string) {
return htmlspecialchars($string, ENT_COMPAT, 'UTF-8');
public function escape($string, $quote = ENT_COMPAT) {
return htmlspecialchars($string, $quote, 'UTF-8');
}
}

View File

@@ -95,11 +95,11 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
* HTMLPurifier_AttrTypes for details
*/
public function addAttribute($element_name, $attr_name, $def) {
$module =& $this->getAnonymousModule();
$module = $this->getAnonymousModule();
if (!isset($module->info[$element_name])) {
$element =& $module->addBlankElement($element_name);
$element = $module->addBlankElement($element_name);
} else {
$element =& $module->info[$element_name];
$element = $module->info[$element_name];
}
$element->attr[$attr_name] = $def;
}
@@ -109,11 +109,11 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
* @note See HTMLPurifier_HTMLModule::addElement for detailed
* parameter and return value descriptions.
*/
public function &addElement($element_name, $type, $contents, $attr_collections, $attributes) {
$module =& $this->getAnonymousModule();
public function addElement($element_name, $type, $contents, $attr_collections, $attributes) {
$module = $this->getAnonymousModule();
// assume that if the user is calling this, the element
// is safe. This may not be a good idea
$element =& $module->addElement($element_name, $type, $contents, $attr_collections, $attributes);
$element = $module->addElement($element_name, $type, $contents, $attr_collections, $attributes);
return $element;
}
@@ -123,9 +123,9 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
* @note See HTMLPurifier_HTMLModule::addBlankElement for detailed
* parameter and return value descriptions.
*/
public function &addBlankElement($element_name) {
$module =& $this->getAnonymousModule();
$element =& $module->addBlankElement($element_name);
public function addBlankElement($element_name) {
$module = $this->getAnonymousModule();
$element = $module->addBlankElement($element_name);
return $element;
}
@@ -134,7 +134,7 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
* bust out advanced features without having to make your own
* module.
*/
public function &getAnonymousModule() {
public function getAnonymousModule() {
if (!$this->_anonModule) {
$this->_anonModule = new HTMLPurifier_HTMLModule();
$this->_anonModule->name = 'Anonymous';
@@ -233,10 +233,10 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
$support = "(for information on implementing this, see the ".
"support forums) ";
// setup allowed elements
// setup allowed elements -----------------------------------------
$allowed_elements = $config->get('HTML', 'AllowedElements');
$allowed_attributes = $config->get('HTML', 'AllowedAttributes');
$allowed_attributes = $config->get('HTML', 'AllowedAttributes'); // retrieve early
if (!is_array($allowed_elements) && !is_array($allowed_attributes)) {
$allowed = $config->get('HTML', 'Allowed');
@@ -252,55 +252,80 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
}
// emit errors
foreach ($allowed_elements as $element => $d) {
// :TODO: Is this htmlspecialchars() call really necessary?
$element = htmlspecialchars($element);
$element = htmlspecialchars($element); // PHP doesn't escape errors, be careful!
trigger_error("Element '$element' is not supported $support", E_USER_WARNING);
}
}
// setup allowed attributes ---------------------------------------
$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"]);
// This actually doesn't do anything, since we went away from
// global attributes. It's possible that userland code uses
// it, but HTMLModuleManager doesn't!
foreach ($this->info_global_attr as $attr => $x) {
$keys = array($attr, "*@$attr", "*.$attr");
$delete = true;
foreach ($keys as $key) {
if ($delete && isset($allowed_attributes[$key])) {
$delete = false;
}
if (isset($allowed_attributes_mutable[$key])) {
unset($allowed_attributes_mutable[$key]);
}
}
if ($delete) unset($this->info_global_attr[$attr]);
}
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"]);
foreach ($info->attr as $attr => $x) {
$keys = array("$tag@$attr", $attr, "*@$attr", "$tag.$attr", "*.$attr");
$delete = true;
foreach ($keys as $key) {
if ($delete && isset($allowed_attributes[$key])) {
$delete = false;
}
if (isset($allowed_attributes_mutable[$key])) {
unset($allowed_attributes_mutable[$key]);
}
}
if ($delete) unset($this->info[$tag]->attr[$attr]);
}
}
// emit errors
foreach ($allowed_attributes_mutable as $elattr => $d) {
list($element, $attribute) = explode('.', $elattr);
// :TODO: Is this htmlspecialchars() call really necessary?
$element = htmlspecialchars($element);
$attribute = htmlspecialchars($attribute);
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);
$bits = preg_split('/[.@]/', $elattr, 2);
$c = count($bits);
switch ($c) {
case 2:
if ($bits[0] !== '*') {
$element = htmlspecialchars($bits[0]);
$attribute = htmlspecialchars($bits[1]);
if (!isset($this->info[$element])) {
trigger_error("Cannot allow attribute '$attribute' if element '$element' is not allowed/supported $support");
} else {
trigger_error("Attribute '$attribute' in element '$element' not supported $support",
E_USER_WARNING);
}
break;
}
// otherwise fall through
case 1:
$attribute = htmlspecialchars($bits[0]);
trigger_error("Global attribute '$attribute' is not ".
"supported in any elements $support",
E_USER_WARNING);
break;
}
}
}
// setup forbidden elements
$forbidden_elements = $config->get('HTML', 'ForbiddenElements');
// setup forbidden elements ---------------------------------------
$forbidden_elements = $config->get('HTML', 'ForbiddenElements');
$forbidden_attributes = $config->get('HTML', 'ForbiddenAttributes');
foreach ($this->info as $tag => $info) {
@@ -308,13 +333,28 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
unset($this->info[$tag]);
continue;
}
foreach ($info->attr as $name => $def) {
if (isset($forbidden_attributes["$tag.$name"])) {
unset($this->info[$tag]->attr[$name]);
foreach ($info->attr as $attr => $x) {
if (
isset($forbidden_attributes["$tag@$attr"]) ||
isset($forbidden_attributes["*@$attr"]) ||
isset($forbidden_attributes[$attr])
) {
unset($this->info[$tag]->attr[$attr]);
continue;
} // this segment might get removed eventually
elseif (isset($forbidden_attributes["$tag.$attr"])) {
// $tag.$attr are not user supplied, so no worries!
trigger_error("Error with $tag.$attr: tag.attr syntax not supported for HTML.ForbiddenAttributes; use tag@attr instead", E_USER_WARNING);
}
}
}
foreach ($forbidden_attributes as $key => $v) {
if (strlen($key) < 2) continue;
if ($key[0] != '*') continue;
if ($key[1] == '.') {
trigger_error("Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead", E_USER_WARNING);
}
}
}
@@ -329,6 +369,8 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
*/
public function parseTinyMCEAllowedList($list) {
$list = str_replace(array(' ', "\t"), '', $list);
$elements = array();
$attributes = array();

View File

@@ -116,10 +116,10 @@ class HTMLPurifier_HTMLModule
* element?
* @param $attr What unique attributes does the element define?
* @note See ElementDef for in-depth descriptions of these parameters.
* @return Reference to created element definition object, so you
* @return Created element definition object, so you
* can set advanced parameters
*/
public function &addElement($element, $type, $contents, $attr_includes = array(), $attr = array()) {
public function addElement($element, $type, $contents, $attr_includes = array(), $attr = array()) {
$this->elements[] = $element;
// parse content_model
list($content_model_type, $content_model) = $this->parseContents($contents);
@@ -140,9 +140,9 @@ class HTMLPurifier_HTMLModule
* Convenience function that creates a totally blank, non-standalone
* element.
* @param $element Name of element to create
* @return Reference to created element
* @return Created element
*/
public function &addBlankElement($element) {
public function addBlankElement($element) {
if (!isset($this->info[$element])) {
$this->elements[] = $element;
$this->info[$element] = new HTMLPurifier_ElementDef();

View File

@@ -13,7 +13,7 @@ class HTMLPurifier_HTMLModule_Bdo extends HTMLPurifier_HTMLModule
);
public function __construct() {
$bdo =& $this->addElement(
$bdo = $this->addElement(
'bdo', 'Inline', 'Inline', array('Core', 'Lang'),
array(
'dir' => 'Enum#ltr,rtl', // required

View File

@@ -9,7 +9,7 @@ class HTMLPurifier_HTMLModule_Hypertext extends HTMLPurifier_HTMLModule
public $name = 'Hypertext';
public function __construct() {
$a =& $this->addElement(
$a = $this->addElement(
'a', 'Inline', 'Inline', 'Common',
array(
// 'accesskey' => 'Character',

View File

@@ -11,7 +11,7 @@ class HTMLPurifier_HTMLModule_Image extends HTMLPurifier_HTMLModule
public $name = 'Image';
public function __construct() {
$img =& $this->addElement(
$img = $this->addElement(
'img', 'Inline', 'Empty', 'Common',
array(
'alt*' => 'Text',

View File

@@ -49,40 +49,40 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
$align = 'Enum#left,right,center,justify';
$address =& $this->addBlankElement('address');
$address = $this->addBlankElement('address');
$address->content_model = 'Inline | #PCDATA | p';
$address->content_model_type = 'optional';
$address->child = false;
$blockquote =& $this->addBlankElement('blockquote');
$blockquote = $this->addBlankElement('blockquote');
$blockquote->content_model = 'Flow | #PCDATA';
$blockquote->content_model_type = 'optional';
$blockquote->child = false;
$br =& $this->addBlankElement('br');
$br = $this->addBlankElement('br');
$br->attr['clear'] = 'Enum#left,all,right,none';
$caption =& $this->addBlankElement('caption');
$caption = $this->addBlankElement('caption');
$caption->attr['align'] = 'Enum#top,bottom,left,right';
$div =& $this->addBlankElement('div');
$div = $this->addBlankElement('div');
$div->attr['align'] = $align;
$dl =& $this->addBlankElement('dl');
$dl = $this->addBlankElement('dl');
$dl->attr['compact'] = 'Bool#compact';
for ($i = 1; $i <= 6; $i++) {
$h =& $this->addBlankElement("h$i");
$h = $this->addBlankElement("h$i");
$h->attr['align'] = $align;
}
$hr =& $this->addBlankElement('hr');
$hr = $this->addBlankElement('hr');
$hr->attr['align'] = $align;
$hr->attr['noshade'] = 'Bool#noshade';
$hr->attr['size'] = 'Pixels';
$hr->attr['width'] = 'Length';
$img =& $this->addBlankElement('img');
$img = $this->addBlankElement('img');
$img->attr['align'] = 'Enum#top,middle,bottom,left,right';
$img->attr['border'] = 'Pixels';
$img->attr['hspace'] = 'Pixels';
@@ -90,43 +90,43 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
// figure out this integer business
$li =& $this->addBlankElement('li');
$li = $this->addBlankElement('li');
$li->attr['value'] = new HTMLPurifier_AttrDef_Integer();
$li->attr['type'] = 'Enum#s:1,i,I,a,A,disc,square,circle';
$ol =& $this->addBlankElement('ol');
$ol = $this->addBlankElement('ol');
$ol->attr['compact'] = 'Bool#compact';
$ol->attr['start'] = new HTMLPurifier_AttrDef_Integer();
$ol->attr['type'] = 'Enum#s:1,i,I,a,A';
$p =& $this->addBlankElement('p');
$p = $this->addBlankElement('p');
$p->attr['align'] = $align;
$pre =& $this->addBlankElement('pre');
$pre = $this->addBlankElement('pre');
$pre->attr['width'] = 'Number';
// script omitted
$table =& $this->addBlankElement('table');
$table = $this->addBlankElement('table');
$table->attr['align'] = 'Enum#left,center,right';
$table->attr['bgcolor'] = 'Color';
$tr =& $this->addBlankElement('tr');
$tr = $this->addBlankElement('tr');
$tr->attr['bgcolor'] = 'Color';
$th =& $this->addBlankElement('th');
$th = $this->addBlankElement('th');
$th->attr['bgcolor'] = 'Color';
$th->attr['height'] = 'Length';
$th->attr['nowrap'] = 'Bool#nowrap';
$th->attr['width'] = 'Length';
$td =& $this->addBlankElement('td');
$td = $this->addBlankElement('td');
$td->attr['bgcolor'] = 'Color';
$td->attr['height'] = 'Length';
$td->attr['nowrap'] = 'Bool#nowrap';
$td->attr['width'] = 'Length';
$ul =& $this->addBlankElement('ul');
$ul = $this->addBlankElement('ul');
$ul->attr['compact'] = 'Bool#compact';
$ul->attr['type'] = 'Enum#square,disc,circle';

View File

@@ -15,9 +15,9 @@ class HTMLPurifier_HTMLModule_Ruby extends HTMLPurifier_HTMLModule
'Common');
$this->addElement('rbc', false, 'Required: rb', 'Common');
$this->addElement('rtc', false, 'Required: rt', 'Common');
$rb =& $this->addElement('rb', false, 'Inline', 'Common');
$rb = $this->addElement('rb', false, 'Inline', 'Common');
$rb->excludes = array('ruby' => true);
$rt =& $this->addElement('rt', false, 'Inline', 'Common', array('rbspan' => 'Number'));
$rt = $this->addElement('rt', false, 'Inline', 'Common', array('rbspan' => 'Number'));
$rt->excludes = array('ruby' => true);
$this->addElement('rp', false, 'Optional: #PCDATA', 'Common');
}

View File

@@ -7,19 +7,6 @@ INSIDE HTML PURIFIER DOCUMENTS. USE ONLY WITH TRUSTED USER INPUT!!!
*/
/**
* Implements required attribute stipulation for <script>
*/
class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) {
if (!isset($attr['type'])) {
$attr['type'] = 'text/javascript';
}
return $attr;
}
}
/**
* XHTML 1.1 Scripting module, defines elements that are used to contain
* information pertaining to executable scripts or the lack of support

View File

@@ -11,7 +11,7 @@ class HTMLPurifier_HTMLModule_Target extends HTMLPurifier_HTMLModule
public function __construct() {
$elements = array('a');
foreach ($elements as $name) {
$e =& $this->addBlankElement($name);
$e = $this->addBlankElement($name);
$e->attr = array(
'target' => new HTMLPurifier_AttrDef_HTML_FrameTarget()
);

View File

@@ -42,7 +42,7 @@ class HTMLPurifier_HTMLModule_Text extends HTMLPurifier_HTMLModule
// Block Phrasal --------------------------------------------------
$this->addElement('address', 'Block', 'Inline', 'Common');
$this->addElement('blockquote', 'Block', 'Optional: Heading | Block | List', 'Common', array('cite' => 'URI') );
$pre =& $this->addElement('pre', 'Block', 'Inline', 'Common');
$pre = $this->addElement('pre', 'Block', 'Inline', 'Common');
$pre->excludes = $this->makeLookup(
'img', 'big', 'small', 'object', 'applet', 'font', 'basefont' );
$this->addElement('h1', 'Heading', 'Inline', 'Common');

View File

@@ -128,14 +128,16 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
if (isset($params['element'])) {
$element = $params['element'];
if (empty($this->info[$element])) {
$e =& $this->addBlankElement($element);
$e = $this->addBlankElement($element);
} else {
$e =& $this->info[$element];
$e = $this->info[$element];
}
} else {
$type = "info_$type";
$e =& $this;
$e = $this;
}
// PHP does some weird parsing when I do
// $e->$type[$attr], so I have to assign a ref.
$f =& $e->$type;
$f[$attr] = $fix;
break;
@@ -146,9 +148,9 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
case 'content_model_type':
$element = $params['element'];
if (empty($this->info[$element])) {
$e =& $this->addBlankElement($element);
$e = $this->addBlankElement($element);
} else {
$e =& $this->info[$element];
$e = $this->info[$element];
}
$e->$type = $fix;
break;

View File

@@ -1,5 +1,9 @@
<?php
/**
* Represents a language and defines localizable string formatting and
* other functions, as well as the localized messages for HTML Purifier.
*/
class HTMLPurifier_Language
{
@@ -23,6 +27,13 @@ class HTMLPurifier_Language
*/
public $errorNames = array();
/**
* True if no message file was found for this language, so English
* is being used instead. Check this if you'd like to notify the
* user that they've used a non-supported language.
*/
public $error = false;
/**
* Has the language object been loaded yet?
* @todo Make it private, fix usage in HTMLPurifier_LanguageTest
@@ -36,7 +47,7 @@ class HTMLPurifier_Language
public function __construct($config, $context) {
$this->config = $config;
$this->context =& $context;
$this->context = $context;
}
/**
@@ -122,7 +133,7 @@ class HTMLPurifier_Language
// could be introduced for all types of tokens. This
// may need to be factored out into a dedicated class
if (!empty($value->attr)) {
$stripped_token = $value->copy();
$stripped_token = clone $value;
$stripped_token->attr = array();
$subst['$'.$i.'.Compact'] = $generator->generateFromToken($stripped_token);
}

View File

@@ -0,0 +1,11 @@
<?php
// private language message file for unit testing purposes
// this language file has no class associated with it
$fallback = 'en';
$messages = array(
'HTMLPurifier' => 'HTML Purifier XNone'
);

View File

@@ -5,6 +5,7 @@
* caching and fallbacks.
* @note Thanks to MediaWiki for the general logic, although this version
* has been entirely rewritten
* @todo Serialized cache for languages
*/
class HTMLPurifier_LanguageFactory
{
@@ -53,7 +54,7 @@ class HTMLPurifier_LanguageFactory
* @param $prototype Optional prototype to overload sole instance with,
* or bool true to reset to default factory.
*/
public static function &instance($prototype = null) {
public static function instance($prototype = null) {
static $instance = null;
if ($prototype !== null) {
$instance = $prototype;
@@ -77,41 +78,43 @@ class HTMLPurifier_LanguageFactory
* Creates a language object, handles class fallbacks
* @param $config Instance of HTMLPurifier_Config
* @param $context Instance of HTMLPurifier_Context
* @param $code Code to override configuration with. Private parameter.
*/
public function create($config, $context) {
public function create($config, $context, $code = false) {
// validate language code
$code = $this->validator->validate(
$config->get('Core', 'Language'), $config, $context
);
if ($code === false) {
$code = $this->validator->validate(
$config->get('Core', 'Language'), $config, $context
);
} else {
$code = $this->validator->validate($code, $config, $context);
}
if ($code === false) $code = 'en'; // malformed code becomes English
$pcode = str_replace('-', '_', $code); // make valid PHP classname
static $depth = 0; // recursion protection
if ($code == 'en') {
$class = 'HTMLPurifier_Language';
$file = $this->dir . '/Language.php';
$lang = new HTMLPurifier_Language($config, $context);
} else {
$class = 'HTMLPurifier_Language_' . $pcode;
$file = $this->dir . '/Language/classes/' . $code . '.php';
// PHP5/APC deps bug workaround can go here
// you can bypass the conditional include by loading the
// file yourself
if (file_exists($file) && !class_exists($class, false)) {
include_once $file;
if (file_exists($file) || class_exists($class, false)) {
$lang = new $class($config, $context);
} else {
// Go fallback
$raw_fallback = $this->getFallbackFor($code);
$fallback = $raw_fallback ? $raw_fallback : 'en';
$depth++;
$lang = $this->create($config, $context, $fallback);
if (!$raw_fallback) {
$lang->error = true;
}
$depth--;
}
}
if (!class_exists($class, false)) {
// go fallback
$fallback = HTMLPurifier_LanguageFactory::getFallbackFor($code);
$depth++;
$lang = HTMLPurifier_LanguageFactory::factory( $fallback );
$depth--;
} else {
$lang = new $class($config, $context);
}
$lang->code = $code;
return $lang;

View File

@@ -11,7 +11,8 @@
*
* A lexer is HTML-oriented: it might work with XML, but it's not
* recommended, as we adhere to a subset of the specification for optimization
* reasons.
* reasons. This might change in the future. Also, most tokenizers are not
* expected to handle DTDs or PIs.
*
* This class should not be directly instantiated, but you may use create() to
* retrieve a default copy of the lexer. Being a supertype, this class
@@ -20,7 +21,8 @@
*
* @note The unit tests will instantiate this class for testing purposes, as
* many of the utility functions require a class to be instantiated.
* Be careful when porting this class to PHP 5.
* This means that, even though this class is not runnable, it will
* not be declared abstract.
*
* @par
*
@@ -28,18 +30,14 @@
* We use tokens rather than create a DOM representation because DOM would:
*
* @par
* -# Require more processing power to create,
* -# Require recursion to iterate,
* -# Must be compatible with PHP 5's DOM (otherwise duplication),
* -# Has the entire document structure (html and body not needed), and
* -# Has unknown readability improvement.
* -# Require more processing and memory to create,
* -# Is not streamable, and
* -# Has the entire document structure (html and body not needed).
*
* @par
* What the last item means is that the functions for manipulating tokens are
* already fairly compact, and when well-commented, more abstraction may not
* be needed.
*
* @see HTMLPurifier_Token
* However, DOM is helpful in that it makes it easy to move around nodes
* without a lot of lookaheads to see when a tag is closed. This is a
* limitation of the token system and some workarounds would be nice.
*/
class HTMLPurifier_Lexer
{
@@ -49,22 +47,16 @@ class HTMLPurifier_Lexer
/**
* Retrieves or sets the default Lexer as a Prototype Factory.
*
* Depending on what PHP version you are running, the abstract base
* Lexer class will determine which concrete Lexer is best for you:
* HTMLPurifier_Lexer_DirectLex for PHP 4, and HTMLPurifier_Lexer_DOMLex
* for PHP 5 and beyond. This general rule has a few exceptions to it
* involving special features that only DirectLex implements.
* By default HTMLPurifier_Lexer_DOMLex will be returned. There are
* a few exceptions involving special features that only DirectLex
* implements.
*
* @note The behavior of this class has changed, rather than accepting
* a prototype object, it now accepts a configuration object.
* To specify your own prototype, set %Core.LexerImpl to it.
* This change in behavior de-singletonizes the lexer object.
*
* @note In PHP4, it is possible to call this factory method from
* subclasses, such usage is not recommended and not
* forwards-compatible.
*
* @param $prototype Optional prototype lexer or configuration object
* @param $config Instance of HTMLPurifier_Config
* @return Concrete lexer.
*/
public static function create($config) {
@@ -96,8 +88,9 @@ class HTMLPurifier_Lexer
break;
}
if (version_compare(PHP_VERSION, "5", ">=") && // check for PHP5
class_exists('DOMDocument')) { // check for DOM support
if (class_exists('DOMDocument')) {
// check for DOM support, because, surprisingly enough,
// it's *not* part of the core!
$lexer = 'DOMLex';
} else {
$lexer = 'DirectLex';

View File

@@ -2,17 +2,28 @@
/**
* Experimental HTML5-based parser using Jeroen van der Meer's PH5P library.
* Requires PHP5, and occupies space in the HTML5 pseudo-namespace (may
* cause conflicts, sorry).
* Occupies space in the HTML5 pseudo-namespace, which may cause conflicts.
*
* @note
* Recent changes to PHP's DOM extension have resulted in some fatal
* error conditions with the original version of PH5P. Pending changes,
* this lexer will punt to DirectLex if DOM throughs an exception.
*/
class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex {
public function tokenizeHTML($html, $config, $context) {
$html = $this->normalize($html, $config, $context);
$html = $this->wrapHTML( $html, $config, $context);
$parser = new HTML5($html);
$doc = $parser->save();
$new_html = $this->normalize($html, $config, $context);
$new_html = $this->wrapHTML($new_html, $config, $context);
try {
$parser = new HTML5($new_html);
$doc = $parser->save();
} catch (DOMException $e) {
// Uh oh, it failed. Punt to DirectLex.
$lexer = new HTMLPurifier_Lexer_DirectLex();
$context->register('PH5PError', $e); // save the error, so we can detect it
return $lexer->tokenizeHTML($html, $config, $context); // use original HTML
}
$tokens = array();
$this->tokenizeDOM(
$doc->getElementsByTagName('html')->item(0)-> // <html>

View File

@@ -2,12 +2,68 @@
/**
* Class that handles operations involving percent-encoding in URIs.
*
* @warning
* Be careful when reusing instances of PercentEncoder. The object
* you use for normalize() SHOULD NOT be used for encode(), or
* vice-versa.
*/
class HTMLPurifier_PercentEncoder
{
/**
* Fix up percent-encoding by decoding unreserved characters and normalizing
* Reserved characters to preserve when using encode().
*/
protected $preserve = array();
/**
* String of characters that should be preserved while using encode().
*/
public function __construct($preserve = false) {
// unreserved letters, ought to const-ify
for ($i = 48; $i <= 57; $i++) $this->preserve[$i] = true; // digits
for ($i = 65; $i <= 90; $i++) $this->preserve[$i] = true; // upper-case
for ($i = 97; $i <= 122; $i++) $this->preserve[$i] = true; // lower-case
$this->preserve[45] = true; // Dash -
$this->preserve[46] = true; // Period .
$this->preserve[95] = true; // Underscore _
$this->preserve[126]= true; // Tilde ~
// extra letters not to escape
if ($preserve !== false) {
for ($i = 0, $c = strlen($preserve); $i < $c; $i++) {
$this->preserve[ord($preserve[$i])] = true;
}
}
}
/**
* Our replacement for urlencode, it encodes all non-reserved characters,
* as well as any extra characters that were instructed to be preserved.
* @note
* Assumes that the string has already been normalized, making any
* and all percent escape sequences valid. Percents will not be
* re-escaped, regardless of their status in $preserve
* @param $string String to be encoded
* @return Encoded string.
*/
public function encode($string) {
$ret = '';
for ($i = 0, $c = strlen($string); $i < $c; $i++) {
if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])]) ) {
$ret .= '%' . sprintf('%02X', $int);
} else {
$ret .= $string[$i];
}
}
return $ret;
}
/**
* Fix up percent-encoding by decoding unreserved characters and normalizing.
* @warning This function is affected by $preserve, even though the
* usual desired behavior is for this not to preserve those
* characters. Be careful when reusing instances of PercentEncoder!
* @param $string String to normalize
*/
public function normalize($string) {
@@ -27,12 +83,7 @@ class HTMLPurifier_PercentEncoder
continue;
}
$int = hexdec($encoding);
if (
($int >= 48 && $int <= 57) || // digits
($int >= 65 && $int <= 90) || // uppercase letters
($int >= 97 && $int <= 122) || // lowercase letters
$int == 126 || $int == 45 || $int == 46 || $int == 95 // ~-._
) {
if (isset($this->preserve[$int])) {
$ret .= chr($int) . $text;
continue;
}

View File

@@ -1,6 +1,7 @@
<?php
// OUT OF DATE, NEEDS UPDATING!
// USE XMLWRITER!
class HTMLPurifier_Printer
{

View File

@@ -55,14 +55,14 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
/**
* Retrieves styling, in case it is not accessible by webserver
*/
public function getCSS() {
public static function getCSS() {
return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css');
}
/**
* Retrieves JavaScript, in case it is not accessible by webserver
*/
public function getJavaScript() {
public static function getJavaScript() {
return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js');
}
@@ -86,8 +86,8 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
$ret .= $this->start('table', array('class' => 'hp-config'));
$ret .= $this->start('thead');
$ret .= $this->start('tr');
$ret .= $this->element('th', 'Directive');
$ret .= $this->element('th', 'Value');
$ret .= $this->element('th', 'Directive', array('class' => 'hp-directive'));
$ret .= $this->element('th', 'Value', array('class' => 'hp-value'));
$ret .= $this->end('tr');
$ret .= $this->end('thead');
foreach ($all as $ns => $directives) {
@@ -194,6 +194,10 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
'id' => "$name:Null_$ns.$directive",
'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!!
);
if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) {
// modify inline javascript slightly
$attr['onclick'] = "toggleWriteability('$name:Yes_$ns.$directive',checked);toggleWriteability('$name:No_$ns.$directive',checked)";
}
if ($value === null) $attr['checked'] = 'checked';
$ret .= $this->elementEmpty('input', $attr);
$ret .= $this->text(' or ');
@@ -291,7 +295,8 @@ class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer {
'id' => "$name:Yes_$ns.$directive",
'value' => '1'
);
if ($value) $attr['checked'] = 'checked';
if ($value === true) $attr['checked'] = 'checked';
if ($value === null) $attr['disabled'] = 'disabled';
$ret .= $this->elementEmpty('input', $attr);
$ret .= $this->start('label', array('for' => "$name:No_$ns.$directive"));
@@ -305,7 +310,8 @@ class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer {
'id' => "$name:No_$ns.$directive",
'value' => '0'
);
if (!$value) $attr['checked'] = 'checked';
if ($value === false) $attr['checked'] = 'checked';
if ($value === null) $attr['disabled'] = 'disabled';
$ret .= $this->elementEmpty('input', $attr);
$ret .= $this->end('div');

View File

@@ -37,7 +37,7 @@ class HTMLPurifier_TagTransform_Font extends HTMLPurifier_TagTransform
public function transform($tag, $config, $context) {
if ($tag instanceof HTMLPurifier_Token_End) {
$new_tag = $tag->copy();
$new_tag = clone $tag;
$new_tag->name = $this->transform_to;
return $new_tag;
}
@@ -81,7 +81,7 @@ class HTMLPurifier_TagTransform_Font extends HTMLPurifier_TagTransform
$prepend_style;
}
$new_tag = $tag->copy();
$new_tag = clone $tag;
$new_tag->name = $this->transform_to;
$new_tag->attr = $attr;

View File

@@ -20,7 +20,7 @@ class HTMLPurifier_TagTransform_Simple extends HTMLPurifier_TagTransform
}
public function transform($tag, $config, $context) {
$new_tag = $tag->copy();
$new_tag = clone $tag;
$new_tag->name = $this->transform_to;
if (!is_null($this->style) &&
($new_tag instanceof HTMLPurifier_Token_Start || $new_tag instanceof HTMLPurifier_Token_Empty)

View File

@@ -14,14 +14,6 @@ class HTMLPurifier_Token {
*/
public $armor = array();
/**
* Copies the tag into a new one (clone substitute).
* @return Copied token
*/
public function copy() {
return unserialize(serialize($this));
}
public function __get($n) {
if ($n === 'type') {
trigger_error('Deprecated type property called; use instanceof', E_USER_NOTICE);

View File

@@ -1,15 +1,15 @@
<?php
/**
* Factory for token generation (PHP 5 only).
* Factory for token generation.
*
* @note Doing some benchmarking indicates that the new operator is much
* slower than the clone operator (even discounting the cost of the
* constructor). This class is for that optimization. We may want to
* consider porting this to PHP 4 by virtue of the fact it makes the code
* easier to read. Other then that, there's not much point as we don't
* constructor). This class is for that optimization.
* Other then that, there's not much point as we don't
* maintain parallel HTMLPurifier_Token hierarchies (the main reason why
* you'd want to use an abstract factory).
* @todo Port DirectLex to use this
*/
class HTMLPurifier_TokenFactory
{

View File

@@ -1,7 +1,12 @@
<?php
/**
* HTML Purifier's internal representation of a URI
* HTML Purifier's internal representation of a URI.
* @note
* Internal data-structures are completely escaped. If the data needs
* to be used in a non-URI context (which is very unlikely), be sure
* to decode it first. The URI may not necessarily be well-formed until
* validate() is called.
*/
class HTMLPurifier_URI
{
@@ -49,13 +54,27 @@ class HTMLPurifier_URI
}
/**
* Generic validation method applicable for all schemes
* Generic validation method applicable for all schemes. May modify
* this URI in order to get it into a compliant form.
* @param $config Instance of HTMLPurifier_Config
* @param $context Instance of HTMLPurifier_Context
* @return True if validation/filtering succeeds, false if failure
*/
public function validate($config, $context) {
// ABNF definitions from RFC 3986
$chars_sub_delims = '!$&\'()*+,;=';
$chars_gen_delims = ':/?#[]@';
$chars_pchar = $chars_sub_delims . ':@';
// validate scheme (MUST BE FIRST!)
if (!is_null($this->scheme) && is_null($this->host)) {
$def = $config->getDefinition('URI');
if ($def->defaultScheme === $this->scheme) {
$this->scheme = null;
}
}
// validate host
if (!is_null($this->host)) {
$host_def = new HTMLPurifier_AttrDef_URI_Host();
@@ -63,18 +82,51 @@ class HTMLPurifier_URI
if ($this->host === false) $this->host = null;
}
// validate username
if (!is_null($this->userinfo)) {
$encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . ':');
$this->userinfo = $encoder->encode($this->userinfo);
}
// validate port
if (!is_null($this->port)) {
if ($this->port < 1 || $this->port > 65535) $this->port = null;
}
// query and fragment are quite simple in terms of definition:
// *( pchar / "/" / "?" ), so define their validation routines
// when we start fixing percent encoding
// path gets to be validated against a hodge-podge of rules depending
// on the status of authority and scheme, but it's not that important,
// esp. since it won't be applicable to everyone
// validate path
$path_parts = array();
$segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/');
if (!is_null($this->host)) {
// path-abempty (hier and relative)
$this->path = $segments_encoder->encode($this->path);
} elseif ($this->path !== '' && $this->path[0] === '/') {
// path-absolute (hier and relative)
if (strlen($this->path) >= 2 && $this->path[1] === '/') {
// This shouldn't ever happen!
$this->path = '';
} else {
$this->path = $segments_encoder->encode($this->path);
}
} elseif (!is_null($this->scheme) && $this->path !== '') {
// path-rootless (hier)
// Short circuit evaluation means we don't need to check nz
$this->path = $segments_encoder->encode($this->path);
} elseif (is_null($this->scheme) && $this->path !== '') {
// path-noscheme (relative)
// (once again, not checking nz)
$segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@');
$c = strpos($this->path, '/');
if ($c !== false) {
$this->path =
$segment_nc_encoder->encode(substr($this->path, 0, $c)) .
$segments_encoder->encode(substr($this->path, $c));
} else {
$this->path = $segment_nc_encoder->encode($this->path);
}
} else {
// path-empty (hier and relative)
$this->path = ''; // just to be safe
}
return true;

View File

@@ -26,7 +26,7 @@ abstract class HTMLPurifier_URIFilter
/**
* Filter a URI object
* @param &$uri Reference to URI object
* @param $uri Reference to URI object variable
* @param $config Instance of HTMLPurifier_Config
* @param $context Instance of HTMLPurifier_Context
* @return bool Whether or not to continue processing: false indicates

View File

@@ -2,24 +2,39 @@
/**
* Parses a URI into the components and fragment identifier as specified
* by RFC 2396.
* @todo Replace regexps with a native PHP parser
* by RFC 3986.
*/
class HTMLPurifier_URIParser
{
/**
* Parses a URI
* Instance of HTMLPurifier_PercentEncoder to do normalization with.
*/
protected $percentEncoder;
public function __construct() {
$this->percentEncoder = new HTMLPurifier_PercentEncoder();
}
/**
* Parses a URI.
* @param $uri string URI to parse
* @return HTMLPurifier_URI representation of URI
* @return HTMLPurifier_URI representation of URI. This representation has
* not been validated yet and may not conform to RFC.
*/
public function parse($uri) {
$uri = $this->percentEncoder->normalize($uri);
// Regexp is as per Appendix B.
// Note that ["<>] are an addition to the RFC's recommended
// characters, because they represent external delimeters.
$r_URI = '!'.
'(([^:/?#<>\'"]+):)?'. // 2. Scheme
'(//([^/?#<>\'"]*))?'. // 4. Authority
'([^?#<>\'"]*)'. // 5. Path
'(\?([^#<>\'"]*))?'. // 7. Query
'(#([^<>\'"]*))?'. // 8. Fragment
'(([^:/?#"<>]+):)?'. // 2. Scheme
'(//([^/?#"<>]*))?'. // 4. Authority
'([^?#"<>]*)'. // 5. Path
'(\?([^#"<>]*))?'. // 7. Query
'(#([^"<>]*))?'. // 8. Fragment
'!';
$matches = array();
@@ -36,13 +51,7 @@ class HTMLPurifier_URIParser
// further parse authority
if ($authority !== null) {
// ridiculously inefficient: it's a stacked regex!
$HEXDIG = '[A-Fa-f0-9]';
$unreserved = 'A-Za-z0-9-._~'; // make sure you wrap with []
$sub_delims = '!$&\'()'; // needs []
$pct_encoded = "%$HEXDIG$HEXDIG";
$r_userinfo = "(?:[$unreserved$sub_delims:]|$pct_encoded)*";
$r_authority = "/^(($r_userinfo)@)?(\[[^\]]+\]|[^:]*)(:(\d*))?/";
$r_authority = "/^((.+?)@)?(\[[^\]]+\]|[^:]*)(:(\d*))?/";
$matches = array();
preg_match($r_authority, $authority, $matches);
$userinfo = !empty($matches[1]) ? $matches[2] : null;

View File

@@ -62,7 +62,19 @@ foreach ($files as $file) {
$tokens = token_get_all(file_get_contents($file));
$file = str_replace('\\', '/', $file);
for ($i = 0, $c = count($tokens); $i < $c; $i++) {
if (!testToken($tokens[$i], T_VARIABLE, '$config')) continue;
$ok = false;
// Match $config
if (!$ok && testToken($tokens[$i], T_VARIABLE, '$config')) $ok = true;
// Match $this->config
while (!$ok && testToken($tokens[$i], T_VARIABLE, '$this')) {
consumeWhitespace($tokens, $i);
if (!testToken($tokens[$i], T_OBJECT_OPERATOR)) break;
consumeWhitespace($tokens, $i);
if (testToken($tokens[$i], T_STRING, 'config')) $ok = true;
break;
}
if (!$ok) continue;
$ok = false;
for($i++; $i < $c; $i++) {
if ($tokens[$i] === ',' || $tokens[$i] === ')' || $tokens[$i] === ';') {
@@ -86,31 +98,40 @@ foreach ($files as $file) {
$full_counter++;
// The T_CONSTANT_ENCAPSED_STRING may hide some more obscure use-cases;
// it may be useful to log these.
consumeWhitespace($tokens, $i);
if (!testToken($tokens[$i], T_CONSTANT_ENCAPSED_STRING)) continue;
$namespace = substr($tokens[$i][1], 1, -1);
$matched = false;
do {
// What we currently don't match are batch retrievals, and
// wildcard retrievals. This data might be useful in the future,
// which is why we have a do {} while loop that doesn't actually
// do anything.
consumeWhitespace($tokens, $i);
if (!testToken($tokens[$i], T_CONSTANT_ENCAPSED_STRING)) continue;
$namespace = substr($tokens[$i][1], 1, -1);
consumeWhitespace($tokens, $i);
if (!testToken($tokens[$i], ',')) continue;
consumeWhitespace($tokens, $i);
if (!testToken($tokens[$i], T_CONSTANT_ENCAPSED_STRING)) continue;
$directive = substr($tokens[$i][1], 1, -1);
$counter++;
$matched = true;
$id = "$namespace.$directive";
if (!isset($tracker[$id])) $tracker[$id] = array();
if (!isset($tracker[$id][$file])) $tracker[$id][$file] = array();
$tracker[$id][$file][] = $line;
} while (0);
consumeWhitespace($tokens, $i);
if (!testToken($tokens[$i], ',')) continue;
consumeWhitespace($tokens, $i);
if (!testToken($tokens[$i], T_CONSTANT_ENCAPSED_STRING)) continue;
$directive = substr($tokens[$i][1], 1, -1);
$counter++;
$id = "$namespace.$directive";
if (!isset($tracker[$id])) $tracker[$id] = array();
if (!isset($tracker[$id][$file])) $tracker[$id][$file] = array();
$tracker[$id][$file][] = $line;
// echo "$file:$line uses $namespace.$directive\n";
//echo "$file:$line uses $namespace.$directive\n";
}
}
echo "\n$counter/$full_counter instances of \$config found in source code.\n";
echo "\n$counter/$full_counter instances of \$config or \$this->config found in source code.\n";
echo "Generating XML... ";

View File

@@ -10,6 +10,7 @@ Changelog HTMLPurifier : Phorum Mod
==========================
Version 3.0.0.1 for Phorum 5.2, unknown release date
! Better installation documentation
- Fixed double encoded quotes
- Fixed fatal error when migrate.php is blank

79
plugins/phorum/INSTALL Normal file
View File

@@ -0,0 +1,79 @@
Install
How to install the Phorum HTML Purifier plugin
1. UNZIP
--------
Unzip phorum-htmlpurifier-x.y.z, producing an htmlpurifier folder.
You've already done this step if you're reading this!
2. MOVE
-------
Move the htmlpurifier folder to the mods/ folder of your Phorum
installation, so the directory structure looks like:
phorum/
mods/
htmlpurifier/
INSTALL - this install file
info.txt, ... - the module files
htmlpurifier/
3. INSTALL HTML PURIFIER
------------------------
Download and unzip HTML Purifier <htmlpurifier.org>. Place the contents of
the library/ folder in the htmlpurifier/htmlpurifier folder. Your directory
structure will look like:
phorum/
mods/
htmlpurifier/
htmlpurifier/
HTMLPurifier.auto.php
... - other files
HTMLPurifier/
Advanced users:
If you have HTML Purifier installed elsewhere on your server,
all you need is an HTMLPurifier.auto.php file in the library folder which
includes the HTMLPurifier.auto.php file in your install.
4. MIGRATE
----------
If you're setting up a new Phorum installation, all you need to do is create
a blank migrate.php file in the htmlpurifier module folder (NOT the library
folder.
If you have an old Phorum installation and was using BBCode,
copy migrate.bbcode.php to migrate.php. If you were using a different input
format, follow the instructions in migrate.bbcode.php to create your own custom
migrate.php file.
Your directory structure should now look like this:
phorum/
mods/
htmlpurifier/
migrate.php
5. ENABLE
---------
Navigate to your Phorum admin panel at http://example.com/phorum/admin.php,
click on Global Settings > Modules, scroll to "HTML Purifier Phorum Mod" and
turn it On.
6. MIGRATE SIGNATURES
---------------------
If you're setting up a new Phorum installation, skip this step.
If you allowed your users to make signatures, navigate to the module settings
page of HTML Purifier (Global Settings > Modules > HTML Purifier Phorum Mod >
Configure), type in "yes" in the "Confirm" box, and press "Migrate."
ONLY DO THIS ONCE! BE SURE TO BACK UP YOUR DATABASE!
7. CONFIGURE
------------
Configure using Edit settings. See that page for more information.

View File

@@ -24,21 +24,23 @@ $version = trim($argv[1]);
file_put_contents('VERSION', $version);
// ...in NEWS
$date = date('Y-m-d');
$news_c = str_replace(
$l = "$version, unknown release date",
"$version, released $date",
file_get_contents('NEWS'),
$c
);
if (!$c) {
echo 'Could not update NEWS, missing ' . $l . PHP_EOL;
exit;
} elseif ($c > 1) {
echo 'More than one release declaration in NEWS replaced' . PHP_EOL;
exit;
if ($is_dev = (strpos($version, 'dev') === false)) {
$date = date('Y-m-d');
$news_c = str_replace(
$l = "$version, unknown release date",
"$version, released $date",
file_get_contents('NEWS'),
$c
);
if (!$c) {
echo 'Could not update NEWS, missing ' . $l . PHP_EOL;
exit;
} elseif ($c > 1) {
echo 'More than one release declaration in NEWS replaced' . PHP_EOL;
exit;
}
file_put_contents('NEWS', $news_c);
}
file_put_contents('NEWS', $news_c);
// ...in Doxyfile
$doxyfile_c = preg_replace(
@@ -72,7 +74,17 @@ $htmlpurifier_c = preg_replace(
1, $c
);
if (!$c) {
echo 'Could not update HTMLPurifier.php, missing var $version.' . PHP_EOL;
echo 'Could not update HTMLPurifier.php, missing public $version.' . PHP_EOL;
exit;
}
$htmlpurifier_c = preg_replace(
'/const VERSION = \'.+?\';/',
"const VERSION = '$version';",
$htmlpurifier_c,
1, $c
);
if (!$c) {
echo 'Could not update HTMLPurifier.php, missing const $version.' . PHP_EOL;
exit;
}
file_put_contents('library/HTMLPurifier.php', $htmlpurifier_c);
@@ -85,10 +97,12 @@ $config_c = preg_replace(
1, $c
);
if (!$c) {
echo 'Could not update Config.php, missing var $version.' . PHP_EOL;
echo 'Could not update Config.php, missing public $version.' . PHP_EOL;
exit;
}
file_put_contents('library/HTMLPurifier/Config.php', $config_c);
echo "Review changes, write something in WHATSNEW, and then SVN commit with log 'Release $version.'" . PHP_EOL;
passthru('php maintenance/flush.php');
if ($is_dev) echo "Review changes, write something in WHATSNEW, and then SVN commit with log 'Release $version.'" . PHP_EOL;
else echo "Numbers updated to dev, no other modifications necessary!";

View File

@@ -2,31 +2,37 @@
require_once 'common.php';
// Setup environment
require_once '../extras/HTMLPurifierExtras.auto.php';
$interchange = HTMLPurifier_ConfigSchema_InterchangeBuilder::buildFromDirectory('test-schema/');
$interchange->validate();
if (isset($_GET['doc'])) {
if (
file_exists('testSchema.html') &&
filemtime('testSchema.php') < filemtime('testSchema.html') &&
!isset($_GET['purge'])
) {
echo file_get_contents('testSchema.html');
// Hijack page generation to supply documentation
if (file_exists('test-schema.html') && !isset($_GET['purge'])) {
echo file_get_contents('test-schema.html');
exit;
}
if (version_compare('5', PHP_VERSION, '>')) exit('Requires PHP 5 or higher.');
// setup ConfigDoc environment
require_once '../configdoc/library/ConfigDoc.auto.php';
// perform the ConfigDoc generation
$configdoc = new ConfigDoc();
$html = $configdoc->generate($new_schema, 'plain', array(
'css' => '../configdoc/styles/plain.css',
'title' => 'Sample Configuration Documentation'
$style = 'plain';
$configdoc_xml = 'test-schema.xml';
$xml_builder = new HTMLPurifier_ConfigSchema_Builder_Xml();
$xml_builder->openURI($configdoc_xml);
$xml_builder->build($interchange);
unset($xml_builder); // free handle
$xslt = new ConfigDoc_HTMLXSLTProcessor();
$xslt->importStylesheet("../configdoc/styles/$style.xsl");
$xslt->setParameters(array(
'css' => '../configdoc/styles/plain.css',
));
$configdoc->cleanup();
$html = $xslt->transformToHTML($configdoc_xml);
file_put_contents('testSchema.html', $html);
unlink('test-schema.xml');
file_put_contents('test-schema.html', $html);
echo $html;
exit;
@@ -50,15 +56,11 @@ of directive possible.</p>
style="float:right;">
<?php
require_once 'HTMLPurifier/Printer/ConfigForm.php';
$schema_builder = new HTMLPurifier_ConfigSchema_Builder_ConfigSchema();
$schema = $schema_builder->build($interchange);
HTMLPurifier_ConfigSchema::instance($schema);
// fictional set, attempts to cover every possible data-type
// see source at ConfigTest.php
require_once 'testSchema.php';
HTMLPurifier_ConfigSchema::instance($custom_schema);
// cleanup ( this should be rolled into Config )
$config = HTMLPurifier_Config::loadArrayFromForm($_GET, 'config');
$config = HTMLPurifier_Config::loadArrayFromForm($_GET, 'config');
$printer = new HTMLPurifier_Printer_ConfigForm('config', '?doc#%s');
echo $printer->render($config);
@@ -66,7 +68,7 @@ echo $printer->render($config);
</form>
<pre>
<?php
echo htmlspecialchars(print_r($config->getAll(), true));
echo htmlspecialchars(var_export($config->getAll(), true));
?>
</pre>
</body>

View File

@@ -0,0 +1,5 @@
Directive.Allowed
TYPE: string
DEFAULT: 'apple'
ALLOWED: 'apple', 'orange', 'pear', 'peach', 'mango'
DESCRIPTION: This directive has a constrained set of allowed values.

View File

@@ -0,0 +1,6 @@
Directive.Deprecated
TYPE: int
DEFAULT: 0
DESCRIPTION: This is a deprecated directive that shouldn't show up on the form.
DEPRECATED-VERSION: 1.0.0
DEPRECATED-USE: Directive.Allowed

View File

@@ -0,0 +1,2 @@
Directive
DESCRIPTION: Other custom options with directives.

View File

@@ -0,0 +1,4 @@
Type.bool
TYPE: bool
DEFAULT: false
DESCRIPTION: The boolean type is true or false.

View File

@@ -0,0 +1,4 @@
Type.float
TYPE: float
DEFAULT: 3.1415
DESCRIPTION: The float type is a floating point number.

View File

@@ -0,0 +1,4 @@
Type.hash
TYPE: hash
DEFAULT: array('key1' => 'val1', 'key2' => 'val2')
DESCRIPTION: The hash type is an associative array of string keys and string values.

View File

@@ -0,0 +1,4 @@
Type.int
TYPE: int
DEFAULT: 23
DESCRIPTION: The int type is an signed integer.

View File

@@ -0,0 +1,4 @@
Type.istring
TYPE: istring
DEFAULT: 'case insensitive'
DESCRIPTION: The istring type is short (no newlines), must be ASCII and is case-insensitive.

View File

@@ -0,0 +1,4 @@
Type.itext
TYPE: itext
DEFAULT: "case\ninsensitive\nand\npossibly\nquite\nlong"
DESCRIPTION: The text type has newlines, must be ASCII and is case-insensitive.

View File

@@ -0,0 +1,4 @@
Type.list
TYPE: list
DEFAULT: array('item1', 'item2')
DESCRIPTION: The list type is a numerically indexed array of strings.

View File

@@ -0,0 +1,4 @@
Type.lookup
TYPE: lookup
DEFAULT: array('key1' => true, 'key2' => true)
DESCRIPTION: The lookup type acts just like list, except its elements are unique and are checked with <code>isset($var[$key])</code>.

View File

@@ -0,0 +1,4 @@
Type.mixed
TYPE: mixed
DEFAULT: new stdclass()
DESCRIPTION: The mixed type allows any type, and is not form-editable.

View File

@@ -0,0 +1,6 @@
Type.nullbool
TYPE: bool/null
DEFAULT: null
--DESCRIPTION--
Null booleans need to be treated a little specially. See %Type.nullstring
for information on what the null flag does.

View File

@@ -0,0 +1,8 @@
Type.nullstring
TYPE: string/null
DEFAULT: null
--DESCRIPTION--
The null type is not a type, but a flag that can be added to any type
making null a valid value for that entry. It's useful for saying, "Let
the software pick the value for me," or "Don't use this element" when
false has a special meaning.

View File

@@ -0,0 +1,4 @@
Type.string
TYPE: string
DEFAULT: 'Case sensitive'
DESCRIPTION: The string type is short (no newlines) and case-sensitive.

View File

@@ -0,0 +1,4 @@
Type.text
TYPE: text
DEFAULT: "Case sensitive\nand\npossibly\nquite long..."
DESCRIPTION: The text type has newlines and is case-sensitive.

View File

@@ -0,0 +1,2 @@
Type
DESCRIPTION: Directives demonstration the variable types ConfigSchema supports.

View File

@@ -0,0 +1 @@
name = "Test Schema"

View File

@@ -1,41 +0,0 @@
<?php
// overload default configuration schema temporarily
$custom_schema = new HTMLPurifier_ConfigSchema();
$custom_schema->addNamespace('Element', 'Chemical substances that cannot be further decomposed');
$custom_schema->add('Element', 'Abbr', 'H', 'string', false, 'Abbreviation of element name.');
$custom_schema->add('Element', 'Name', 'hydrogen', 'istring', false, 'Full name of atoms.');
$custom_schema->add('Element', 'Number', 1, 'int', false, 'Atomic number, is identity.');
$custom_schema->add('Element', 'Mass', 1.00794, 'float', false, 'Atomic mass.');
$custom_schema->add('Element', 'Radioactive', false, 'bool', false, 'Does it have rapid decay?');
$custom_schema->add('Element', 'Isotopes', array('1' => true, '2' => true, '3' => true), 'lookup', false,
'What numbers of neutrons for this element have been observed?');
$custom_schema->add('Element', 'Traits', array('nonmetallic', 'odorless', 'flammable'), 'list', false,
'What are general properties of the element?');
$custom_schema->add('Element', 'IsotopeNames', array('1' => 'protium', '2' => 'deuterium', '3' => 'tritium'), 'hash', false,
'Lookup hash of neutron counts to formal names.');
$custom_schema->addNamespace('Instrument', 'Of the musical type.');
$custom_schema->add('Instrument', 'Manufacturer', 'Yamaha', 'string', false, 'Who made it?');
$custom_schema->addAllowedValues('Instrument', 'Manufacturer', array(
'Yamaha', 'Conn-Selmer', 'Vandoren', 'Laubin', 'Buffet', 'other'));
$custom_schema->addValueAliases('Instrument', 'Manufacturer', array(
'Selmer' => 'Conn-Selmer'));
$custom_schema->add('Instrument', 'Family', 'woodwind', 'istring', false, 'What family is it?');
$custom_schema->addAllowedValues('Instrument', 'Family', array(
'brass', 'woodwind', 'percussion', 'string', 'keyboard', 'electronic'));
$custom_schema->addValueAliases('Instrument', 'Family', array(
'synth' => 'electronic'));
$custom_schema->addNamespace('ReportCard', 'It is for grades.');
$custom_schema->add('ReportCard', 'English', null, 'string', true, 'Grade from English class.');
$custom_schema->add('ReportCard', 'Absences', 0, 'int', false, 'How many times missing from school?');
$custom_schema->addNamespace('Text', 'This stuff is long, boring, and English.');
$custom_schema->add('Text', 'AboutUs', 'Nothing much, but this should be decently long so that a textarea would be better', 'text', false, 'Who are we? What are we up to?');
$custom_schema->add('Text', 'Hash', "not-case-sensitive\nstill-not-case-sensitive\nsuper-not-case-sensitive", 'itext', false, 'This is of limited utility, but of course it ends up being used.');

View File

@@ -14,6 +14,27 @@ class HTMLPurifier_AttrDef_URI_HostTest extends HTMLPurifier_AttrDefHarness
$this->assertDef('124.15.6.89'); // IPv4
$this->assertDef('www.google.com'); // reg-name
// more domain name tests
$this->assertDef('test.');
$this->assertDef('sub.test.');
$this->assertDef('.test', false);
$this->assertDef('ff');
$this->assertDef('1f', false);
$this->assertDef('-f', false);
$this->assertDef('f1');
$this->assertDef('f-', false);
$this->assertDef('sub.ff');
$this->assertDef('sub.1f', false);
$this->assertDef('sub.-f', false);
$this->assertDef('sub.f1');
$this->assertDef('sub.f-', false);
$this->assertDef('ff.top');
$this->assertDef('1f.top');
$this->assertDef('-f.top', false);
$this->assertDef('ff.top');
$this->assertDef('f1.top');
$this->assertDef('f-.top', false);
}
}

View File

@@ -29,6 +29,19 @@ class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
);
}
function testPercentEncoding() {
$this->assertDef(
'http:colon:mercenary',
'colon%3Amercenary'
);
}
function testPercentEncodingPreserve() {
$this->assertDef(
'http://www.example.com/abcABC123-_.!~*()\''
);
}
function testEmbeds() {
$this->def = new HTMLPurifier_AttrDef_URI(true);
$this->assertDef('http://sub.example.com/alas?foo=asd');
@@ -65,14 +78,31 @@ class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
$parser = new HTMLPurifier_URIParser();
$uri = $parser->parse('http://example.com');
$this->config->set('URI', 'DefinitionID', 'HTMLPurifier_AttrDef_URITest->testURIDefinitionValidation');
$uri_def =& $this->config->getDefinition('URI');
// overload with mock
generate_mock_once('HTMLPurifier_URIDefinition');
$uri_def = new HTMLPurifier_URIDefinitionMock();
$uri_def->expectOnce('filter', array($uri, '*', '*'));
$uri_def->setReturnValue('filter', true, array($uri, '*', '*'));
$uri_def->setup = true;
// Since definitions are no longer passed by reference, we need
// to muck around with the cache to insert our mock. This is
// technically a little bad, since the cache shouldn't change
// behavior, but I don't feel too good about letting users
// overload entire definitions.
generate_mock_once('HTMLPurifier_DefinitionCache');
$cache_mock = new HTMLPurifier_DefinitionCacheMock();
$cache_mock->setReturnValue('get', $uri_def);
generate_mock_once('HTMLPurifier_DefinitionCacheFactory');
$factory_mock = new HTMLPurifier_DefinitionCacheFactoryMock();
$old = HTMLPurifier_DefinitionCacheFactory::instance();
HTMLPurifier_DefinitionCacheFactory::instance($factory_mock);
$factory_mock->setReturnValue('create', $cache_mock);
$this->assertDef('http://example.com');
HTMLPurifier_DefinitionCacheFactory::instance($old);
}
/*

View File

@@ -11,7 +11,7 @@ class HTMLPurifier_AttrValidator_ErrorsTest extends HTMLPurifier_ErrorsHarness
function testAttributesTransformedGlobalPre() {
$this->config->set('HTML', 'DefinitionID',
'HTMLPurifier_AttrValidator_ErrorsTest::testAttributesTransformedGlobalPre');
$def =& $this->config->getHTMLDefinition(true);
$def = $this->config->getHTMLDefinition(true);
generate_mock_once('HTMLPurifier_AttrTransform');
$transform = new HTMLPurifier_AttrTransformMock();
$input = array('original' => 'value');

View File

@@ -35,11 +35,6 @@ class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
*/
protected $lexer;
/**
* Instance of HTMLPurifier_Generator
*/
protected $generator;
/**
* Default config to fall back on if no config is available
*/
@@ -52,7 +47,6 @@ class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
public function __construct() {
$this->lexer = new HTMLPurifier_Lexer_DirectLex();
$this->generator = new HTMLPurifier_Generator();
parent::__construct();
}
@@ -110,7 +104,8 @@ class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
* Generate textual HTML from tokens
*/
protected function generate($tokens) {
return $this->generator->generateFromTokens($tokens, $this->config, $this->context);
$generator = new HTMLPurifier_Generator($this->config, $this->context);
return $generator->generateFromTokens($tokens);
}
}

View File

@@ -219,27 +219,25 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
$def = $config->getCSSDefinition();
$this->assertIsA($def, 'HTMLPurifier_CSSDefinition');
$def =& $config->getHTMLDefinition();
$def2 =& $config->getHTMLDefinition();
$def = $config->getHTMLDefinition();
$def2 = $config->getHTMLDefinition();
$this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
$this->assertReference($def, $def2);
$this->assertSame($def, $def2);
$this->assertTrue($def->setup);
// test re-calculation if HTML changes
unset($def, $def2);
$def2 = $config->getHTMLDefinition(); // forcibly de-reference
$old_def = clone $def2;
$config->set('HTML', 'Doctype', 'HTML 4.01 Transitional');
$def = $config->getHTMLDefinition();
$this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
$this->assertNotEqual($def, $def2);
$this->assertNotEqual($def, $old_def);
$this->assertTrue($def->setup);
// test retrieval of raw definition
$config->set('HTML', 'DefinitionID', 'HTMLPurifier_ConfigTest->test_getHTMLDefinition()');
$config->set('HTML', 'DefinitionRev', 3);
$def =& $config->getHTMLDefinition(true);
$this->assertNotEqual($def, $def2);
$def = $config->getHTMLDefinition(true);
$this->assertNotEqual($def, $old_def);
$this->assertEqual(false, $def->setup);
// auto initialization
@@ -250,8 +248,8 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
function test_getHTMLDefinition_rawError() {
$config = HTMLPurifier_Config::createDefault();
$this->expectError('Cannot retrieve raw version without specifying %HTML.DefinitionID');
$def =& $config->getHTMLDefinition(true);
$this->expectException(new HTMLPurifier_Exception('Cannot retrieve raw version without specifying %HTML.DefinitionID'));
$def = $config->getHTMLDefinition(true);
}
function test_getCSSDefinition() {
@@ -265,7 +263,7 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
$this->schema->add('Cache', 'DefinitionImpl', null, 'string', true);
$this->schema->addNamespace('Crust', 'Krusty Krabs');
$config = new HTMLPurifier_Config($this->schema);
$this->expectError("Definition of Crust type not supported");
$this->expectException(new HTMLPurifier_Exception("Definition of Crust type not supported"));
$config->getDefinition('Crust');
}

View File

@@ -11,7 +11,7 @@ class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_Definitio
$config->setReturnValue('get', 2, array('Test', 'DefinitionRev'));
$config->version = '1.0.0';
$config_md5 = '1.0.0-serial-2';
$config_md5 = '1.0.0,serial,2';
$file = realpath(
$rel_file = HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer/Test/' .
@@ -186,9 +186,9 @@ class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_Definitio
$def_original = $this->generateDefinition();
$cache->add($def_original, $config);
$this->assertFileExist($dir . '/Test/1.0.0-serial-1.ser');
$this->assertFileExist($dir . '/Test/1.0.0,serial,1.ser');
unlink($dir . '/Test/1.0.0-serial-1.ser');
unlink($dir . '/Test/1.0.0,serial,1.ser');
rmdir( $dir . '/Test');
}

View File

@@ -13,16 +13,17 @@ class HTMLPurifier_DefinitionCacheTest extends HTMLPurifier_Harness
$config->setReturnValue('get', 10, array('Test', 'DefinitionRev'));
$config->setReturnValue('getBatchSerial', 'hash', array('Test'));
$this->assertIdentical($cache->isOld('1.0.0-hash-10', $config), false);
$this->assertIdentical($cache->isOld('1.5.0-hash-1', $config), true);
$this->assertIdentical($cache->isOld('1.0.0,hash,10', $config), false);
$this->assertIdentical($cache->isOld('1.5.0,hash,1', $config), true);
$this->assertIdentical($cache->isOld('0.9.0-hash-1', $config), true);
$this->assertIdentical($cache->isOld('1.0.0-hash-1', $config), true);
$this->assertIdentical($cache->isOld('1.0.0beta-hash-11', $config), true);
$this->assertIdentical($cache->isOld('0.9.0,hash,1', $config), true);
$this->assertIdentical($cache->isOld('1.0.0,hash,1', $config), true);
$this->assertIdentical($cache->isOld('1.0.0beta,hash,11', $config), true);
$this->assertIdentical($cache->isOld('0.9.0-hash2-1', $config), true);
$this->assertIdentical($cache->isOld('1.0.0-hash2-1', $config), false); // if hash is different, don't touch!
$this->assertIdentical($cache->isOld('1.0.0beta-hash2-11', $config), true);
$this->assertIdentical($cache->isOld('0.9.0,hash2,1', $config), true);
$this->assertIdentical($cache->isOld('1.0.0,hash2,1', $config), false); // if hash is different, don't touch!
$this->assertIdentical($cache->isOld('1.0.0beta,hash2,11', $config), true);
$this->assertIdentical($cache->isOld('1.0.0-dev,hash2,11', $config), true);
}

View File

@@ -7,7 +7,7 @@ class HTMLPurifier_DoctypeRegistryTest extends HTMLPurifier_Harness
$registry = new HTMLPurifier_DoctypeRegistry();
$d =& $registry->register(
$d = $registry->register(
$name = 'XHTML 1.0 Transitional',
$xml = true,
$modules = array('module-one', 'module-two'),
@@ -18,10 +18,10 @@ class HTMLPurifier_DoctypeRegistryTest extends HTMLPurifier_Harness
$d2 = new HTMLPurifier_Doctype($name, $xml, $modules, $tidyModules, $aliases);
$this->assertIdentical($d, $d2);
$this->assertReference($d, $registry->get('XHTML 1.0 Transitional'));
$this->assertSame($d, $registry->get('XHTML 1.0 Transitional'));
// test shorthand
$d =& $registry->register(
$d = $registry->register(
$name = 'XHTML 1.0 Strict', true, 'module', 'Tidy', 'X10S'
);
$d2 = new HTMLPurifier_Doctype($name, true, array('module'), array('Tidy'), array('X10S'));
@@ -49,26 +49,26 @@ class HTMLPurifier_DoctypeRegistryTest extends HTMLPurifier_Harness
$registry = new HTMLPurifier_DoctypeRegistry();
$d1 =& $registry->register('Doc1', true, array(), array(), array('1'));
$d1 = $registry->register('Doc1', true, array(), array(), array('1'));
$this->assertReference($d1, $registry->get('Doc1'));
$this->assertReference($d1, $registry->get('1'));
$this->assertSame($d1, $registry->get('Doc1'));
$this->assertSame($d1, $registry->get('1'));
$d2 =& $registry->register('Doc2', true, array(), array(), array('2'));
$d2 = $registry->register('Doc2', true, array(), array(), array('2'));
$this->assertReference($d2, $registry->get('Doc2'));
$this->assertReference($d2, $registry->get('2'));
$this->assertSame($d2, $registry->get('Doc2'));
$this->assertSame($d2, $registry->get('2'));
$d3 =& $registry->register('1', true, array(), array(), array());
$d3 = $registry->register('1', true, array(), array(), array());
// literal name overrides alias
$this->assertReference($d3, $registry->get('1'));
$this->assertSame($d3, $registry->get('1'));
$d4 =& $registry->register('One', true, array(), array(), array('1'));
$d4 = $registry->register('One', true, array(), array(), array('1'));
$this->assertReference($d4, $registry->get('One'));
$this->assertSame($d4, $registry->get('One'));
// still it overrides
$this->assertReference($d3, $registry->get('1'));
$this->assertSame($d3, $registry->get('1'));
}

Some files were not shown because too many files have changed in this diff Show More