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

Compare commits

...

109 Commits

Author SHA1 Message Date
Edward Z. Yang
280211f70b Release 3.2.0.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-31 16:30:54 -04:00
Edward Z. Yang
3fd51d527c Add a nod to the RFC's recommendation that UTF-8 be used in URIs.
Mentioned in http://unspecified.wordpress.com/2008/06/29/do-browsers-encode-urls-correctly/

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-31 12:55:07 -04:00
Edward Z. Yang
0e6e2c4edf Bump descriptions to 3.2.0.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-31 12:25:43 -04:00
Edward Z. Yang
22d24e6b04 Add error planning documentation.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-25 02:11:58 -04:00
Edward Z. Yang
3a2fd0b5db Improve floating point scaling in UnitConverter.
When precision dictates that a number be zero padded, we cannot give sprintf()
a negative precision specifier.  This commit implements manual negative precision
printing of floats, taking into account common rounding errors with floating
point numbers.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-24 12:50:59 -04:00
Edward Z. Yang
25fa53c15b Fix misleading entry in NEWS.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-24 12:28:19 -04:00
David Morton
0b6ae1c3c1 Custom Injector to display URL address along with link text.
When viewing potentially hostile html, it may be helpful to see what
a given link was pointing to.  This new injector takes the href
attribute and adds the text after the link, and deletes the href
attribute.

Other forms of display could easily be contrived, but this seems to be
a good basic way to present the information.

Signed-off-by: David Morton <mortonda@dgrmm.net>
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-23 17:11:29 -04:00
Edward Z. Yang
ab263a0bf1 Rewrite spurious encoding test, as utf8 is sometimes useful.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-23 15:22:31 -04:00
Edward Z. Yang
c5b18d345c Fix validation error in documentation index.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-16 20:08:01 -04:00
Edward Z. Yang
d26418ca3a Ignore runtime files in Phorum plugin directory.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-11 23:20:12 -04:00
Edward Z. Yang
d304c5c976 Detect if domxml extension is loaded, and use DirectLex accordingly.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-08 17:06:10 -04:00
Edward Z. Yang
f7bc0b0875 Implement %Attr.DefaultImageAlt, allowing overriding default behavior for alt attributes.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-06 14:51:03 -04:00
Edward Z. Yang
70515dd48f Increase test coverage, and modify handleEnd behavior to only see correct tokens.
Previously, handleEnd was called for any end tag, except ones that were obviously
spurious because there were no parent tags. Now, it is only called for end tags
that are "approved." If an injector operates on the end tag, we automatically
punt. There may be some optimizations that could be made to this procedure,
but for now it's much more consistent.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-01 15:40:31 -04:00
Edward Z. Yang
1555cb617f Minor refactoring and bugfixing of Injector and MakeWellFormed.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-01 04:10:41 -04:00
Edward Z. Yang
cd4500457e More refactoring to MakeWellFormed and Injectors; they work better than ever now!
Major paradigm shift in this commit is bailing ship on the "skip" integers, which
were extremely buggy and error prone, and simply mark tokens as processed or
not processed by injectors. Other notable changes:

- Removed ad hoc decrements to inputIndex in favor of $reprocess flag variable
- Moved rewind outside of processToken()
- Make rewind properly ignore all other injectors
- Cleanup end of document code
- Reconfigure injector loops to account for skips and rewinds
- Punt the empty to start/end transformation
- Completely rewrite processToken to be array based
- Added skip and rewind member variables to tokens
- Fixed a longstanding bug with remove empty!

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-01 03:14:28 -04:00
Edward Z. Yang
fa413e96ac Implement Injector->handleEnd, with lots of refactoring for injector.
Previous design of injector streaming involved editability only to start, empty
and text tokens, because they could be safely modified without causing formedness
errors.  By modifying notifyEnd to operate before MakeWellFormed's safeguards
kick into effect, it can be converted into a handle function, allowing for
arbitrary modification of end tags.

This change involved quite a bit of restructuring of the MakeWellFormed code,
including the moving of end of document tags to inside the loop, so rewinding
on those tags would be functional, increased reuse of the end tag codepath by
code that inserts end tags (as they could be changed out from under you), and
processToken modified to have an extra parameter to force re-processing of
a token if the original token was an end token.

We're not exactly sure if handleEnd works at this point, but the important
talking point about this refactoring is that nothing else broke. Also, a number
of convenience functions were moved from AutoParagraph to the Injector
supertype (specifically: forward, forwardToEndToken, backward, and current).

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-10-01 00:54:51 -04:00
Edward Z. Yang
d0fdcc103e Add support for proprietary "background" attribute in table elements.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-09-27 21:19:35 -04:00
Edward Z. Yang
6a06b92f0c Setup ErrorCollector to maintain new error format, and output that HTML.
Also changed:
    - DirectLex keeps track of column numbers in context
    - New class HTMLPurifier_ErrorStruct

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-09-15 19:08:58 -04:00
Edward Z. Yang
3184fee468 Undo start()/end() error collector changes in AttrValidator.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-09-05 17:25:35 -04:00
Edward Z. Yang
ed7983b559 Refactor lexer instantiation logic with exceptions and forced line tracking.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-09-05 14:04:23 -04:00
Edward Z. Yang
92df9e5b28 Update customize docs to use new directive name for definition caching.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-09-02 16:38:40 -04:00
Edward Z. Yang
2f41bd07fa Update docs, removing $Id$ and linking to repo.or.cz.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-09-02 15:01:25 -04:00
Edward Z. Yang
c6914dce51 Track column numbers in addition to line numbers.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-09-01 14:10:10 -04:00
Edward Z. Yang
9977350143 Fix bug with anonymous module and the SafeObject/SafeEmbed modules.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-31 19:06:25 -04:00
Edward Z. Yang
d9e60350d3 Migrate AttrValidator to nested error format; modify generator logic in ErrorCollector.
AttrValidator's changes are fairly self-explanatory, but ErrorCollector's
changes are worth a little discussion.  ErrorCollector can use generators at
various points during its flow control; there are two distinct generators that
it should use: 1. The one used for the output, and 2. The one used for the
error output.  These will usually be the same, but in the odd case where they
need to be different, getHTMLFormatted() will accept an alterate configuration
object with an appropriate doctype.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-18 22:13:58 -04:00
Edward Z. Yang
c807ed5fe2 Implement nested error collection with start() and end() in ErrorCollector.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-16 00:41:34 -04:00
Edward Z. Yang
c9b6f125aa Forms implementation for %HTML.Trusted. Some backend changes:
* Added Charsets and Character attribute types
* Fix a heavily recursive form of ContentSets, this allows a content-set
  to include another content-set which includes another content-set, and
  so forth.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-15 18:57:44 -04:00
Edward Z. Yang
dc28346677 Fix bug where absolute paths with dots/double-dots were not collapsed.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-15 13:12:54 -04:00
Edward Z. Yang
8423daef05 Increase test coverage for MakeAbsolute.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-13 23:19:38 -04:00
Edward Z. Yang
617f70a8ac Improve auto-paragraph to preserve newlines and handle edge-cases better.
This is a very large commit that includes numerous improvements to the
AutoParagraph injector.  These are:

* Rewritten flow control of the injector to use almost exclusively
  binary conditionals.
* Improved inline documentation with "State" comments, which give concise
  examples of what the token stack looks like at flow points.
* Documentation for all flow branches, even those with no actions.
* Factoring out of common operations to improve readability, especially the
  new iterator private methods.
* Expanded test-suite which covers new flow points, and corrects some errors
  in previous cases.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-10 00:32:29 -04:00
Edward Z. Yang
0423985b45 Detect if HTML support in DOM is disabled by checking loadHTML().
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-07 18:44:21 -04:00
Edward Z. Yang
e013bc9126 Fix bug involving autoclose and inline elements in strict <blockquote>.
The newest autoclose code uses the elements property in whether or not an
element should be closed by a particular tag.  The heuristic is simple; if
the element doesn't allow that tag as a child, it closes the parent
container.  This doesn't work, however, with <blockquote>, which while not
allowing inline styles under Strict doctypes, requires them to be passed
through MakeWellFormed.

The fix was to transition MakeWellFormed to call a method to retrieve the
elements, and then have StrictBlockquote implement a special version of
this method.  Future versions of HTML Purifier may be more flexible in this
regard--further study of the HTML5 specification is required.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-01 20:52:06 -04:00
Edward Z. Yang
1d90bb2397 Allow <![CDATA[<body>...</body>]]> not to trigger Core.ConvertDocumentToFragment
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-01 19:06:28 -04:00
Edward Z. Yang
03dabec2c0 Fix documentation error in Filter.ExtractStyleBlocks and give better example.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-08-01 18:58:47 -04:00
Edward Z. Yang
85090520f1 Add double-munging protection by checking if the domains are the same.
Previously, if an absolute munge URL location was used, HTML passed through
HTML Purifier multiple times would be munged multiple times. This patch
checks if the output URI has the same URI as the input URI; if they do,
the munge is considered unnecessary and discarded.

Requested-by: Chris <justbittin@gmail.com>
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-26 22:45:19 -06:00
Edward Z. Yang
3b6aa10592 %URI.DisableExternal(Resources) uses %URI.Base if %URI.Host is not available.
As part of its duties, URIDefinition determine the base URL and the host URL
of the page based on the two corresponding configuration directives. The
DisableExternal URIFilter, however, bypassed this check by directly checking
%URI.Host. This fix forwards the call through URIDefinition.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-10 18:46:46 -04:00
Edward Z. Yang
3a4b92da81 Slight optimization in LinkTypes using array_keys().
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-08 21:47:52 -04:00
Edward Z. Yang
0ec9731184 Update TODO to add IDNA support along with IRI support.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-08 20:47:44 -04:00
Edward Z. Yang
e05bd77344 Implement HTMLT tests, and migrate HTMLPurifierTest to this format.
HTMLT tests are a compact and easy-to-use way of making assertPurification
type tests. They take the format of:

--INI--
Ns.Directive = "directive value"
--HTML--
Input HTML
--EXPECT--
Expected HTML

Expect more features and migration to be coming soon.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-07 08:59:33 -04:00
Edward Z. Yang
334ffac5b4 Various improvements to test script command line options, i.e. --type
The following changes were made:
* Create --type parameter which accepts 'htmlpurifier', 'phpt', 'vtest', etc.
  in order to execute only that class of tests. This supercedes --only-phpt.
* Create --quick parameter for multitest.php, run only the tips of each
  release series.
* Create --distro parameter for multitest.php, supercedes --exclude-normal
  and --exclude-standalone.

Also, a grep for htmlt tests was added, although add_tests() doesn't do
anything with it yet.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-07 08:59:29 -04:00
Edward Z. Yang
a227cb483a Allow empty sections in string hashes; previously they were left undefined.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-07 08:57:16 -04:00
Edward Z. Yang
aa0fdeee30 Refine Lexers for parsing stray angled brackets; %Core.AggressivelyFixLt = true
By default, the DirectLex and DOMLex behavior with stray angled brackets
varied a great deal due to their implementations. A little known directive
%Core.AggressivelyFixLt attempted to match DOMLex's behavior with DirectLex's,
but it was off by default. By turning it on by default, users now enjoy these
benefits, and performance-minded users can turn it back off.

Also, several refinements to stray angled bracket parsing was made. Specifically:

* DirectLex: Handle each left angled bracket individually, which prevents
  strange behavior as reported by eon.
* DOMLex: Iterate aggressive lt fix, so that stacked brackets like << are
  handled.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-07 08:52:29 -04:00
Edward Z. Yang
ba418a1f19 Redirect stderr to stdout when calling flush.php
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-05 03:15:36 -04:00
Edward Z. Yang
c845f0bb78 Give warnings when attempting to use encoding iconv doesn't support.
Previously, attempting to set %Core.Encoding to an encoding iconv didn't
know about would result in a silent failure, with the return of the
boolean false. Now it will fatally error out.

Reported-by: mcgrailm <mgm19@psu.edu>
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-05 03:14:32 -04:00
Edward Z. Yang
594268ca3b Fix two bugs in MakeAbsolute filter involving base URIs that have empty path.
The bugs are:
* Undefined $is_folder variable when path is empty, and
* Improper concatenation of host and path together.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-05 03:12:44 -04:00
Edward Z. Yang
965be3bd73 Add support for unrecognized elements in MakeWellFormed.
The MakeWellFormed strategy uses metadata from HTMLDefinition in order to
determine whether or not tokens need to be converted or tags need to be
auto-closed. While this functionality is good to have, it is by no means
essential, and MakeWellFormed should not error when this information is not
available.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-07-05 03:11:29 -04:00
Edward Z. Yang
700d5bcbfc Implement %AutoFormat.RemoveEmpty, end to start ref, and injector rewind.
Injector rewind: Injectors can now use the method rewind() in order to move
the input index backwards, so that they can reprocess tokens (other injectors
are not affected by a rewind). This functionality was necessary to implement
nested node removals in %AutoFormat.RemoveEmpty.

End to start ref: To facilitate rewinding, HTMLPurifier_Token_End now
maintains a reference called $start to the starting token for their node.

%AutoFormat.RemoveEmpty removes empty nodes. Lots of people have requested
it, so here is a partially effective implementation. Because it is implemented
as an Injector, it's not possible for it to handle newly introduced empty
nodes by later validators, specifically auto-closing and child validation.
The Injector is only meant to be used on HTML-ish languages.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-27 16:09:14 -04:00
Edward Z. Yang
fd384129bf Proper support for name attribute in <a> and <img>
Prior to this commit, the name attribute was unilaterally removed, except
for Strict doctypes or a heavy TidyLevel, when it was converted to an id
attribute. As name is actually permitted in both HTML 4.01 Strict and
XHTML 1.0 Strict, although deprecated, the more sensible default behavior
is to allow it unless TidyLevel is heavy.

Our implementation is slightly stricter than the specs, as name attributes are
treated as first class IDs, disallowing <a name="foo" id="foo"> or duplicate
names. The former should be treated as a special case, but that will be
a separate commit.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-27 15:44:27 -04:00
Edward Z. Yang
f8b47c64dd Make Strategy_MakeWellFormed operate in place.
Previously, MakeWellFormed processed tokens and appended them onto an output
array, which was presumably immutable and inaccessible to Injectors. By
having MakeWellFormed operate directly on the input array, the strategy
saves memory and will also allow for a rewind implementation, as a unifying
the two arrays allows Injectors to easily determine an index behind them they'd
like to reset state to.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-27 01:33:48 -04:00
Edward Z. Yang
a5ceb1e22a Update printTokens() debug function to work with new Generator API.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-27 01:33:20 -04:00
Edward Z. Yang
636e2883df Add ignore rules for configdoc generated files.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-27 00:14:39 -04:00
Edward Z. Yang
dba3ed7770 [3.1.2] Implement comments when %HTML.Trusted is on.
Some implementation notes: not all comments are valid; HTML makes sure
double-hyphens and trailing hyphens are not found in comments. In addition,
two new localizable messages were added.

Requested-by: Waldo Jaquith <waldo@vqronline.org>
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-25 23:12:19 -04:00
Edward Z. Yang
de9869d942 Ignore .phpt.skip.php files.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-25 23:10:03 -04:00
Edward Z. Yang
cfcdce0db8 Ignore test-settings.php 2008-06-25 22:47:12 -04:00
Edward Z. Yang
6bc04e0e10 Rename dummy file to proper location.
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-25 22:43:55 -04:00
Edward Z. Yang
24f6db6fb2 [3.1.2] Add %Output.SortAttr to deal with FCKeditor bug
If %Output.SortAttr is true, attributes are sorted to be
in alphabetical order. This was requested by frank farmer.

See also: http://htmlpurifier.org/phorum/read.php?2,1576

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-24 22:36:27 -04:00
Edward Z. Yang
85fb192d93 Remove incorrect information about bit-size
UTF-8 is a variable-width encoding that uses octets, UTF-16
is a variable-width encoding that uses 16-bit words, and
UCS-2 is an obsolete fixed-width encoding that doesn't not
support characters beyond the BMP. Explaining this would be
unwieldly, so we just removed the information.

See also: http://www.reddit.com/info/6mlqc/comments/c04aold

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-24 22:12:56 -04:00
Edward Z. Yang
7727cea112 Add Git specific files and configuration
* Setup usage.xml to be binary, as XMLWriter does not honor operating
  system's newline format.
* Setup various files to ignore (svn:ignore was not carried over)
* Add dummy files to prevent git from ignoring empty directories

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-24 22:02:16 -04:00
Edward Z. Yang
6bb8c1fcac Handle CRLF discrepancies
Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
2008-06-24 21:10:51 -04:00
Edward Z. Yang
a84b6d5be0 Add new NEWS entries
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1824 48356398-32a2-884e-a903-53898d9a118a
2008-06-21 05:00:17 +00:00
Edward Z. Yang
6e43cac9c9 Add some extra helpful data for FOCUS
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1821 48356398-32a2-884e-a903-53898d9a118a
2008-06-20 02:59:01 +00:00
Edward Z. Yang
656a0c95bf Add update Freshmeat script.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1818 48356398-32a2-884e-a903-53898d9a118a
2008-06-20 01:48:46 +00:00
Edward Z. Yang
7015aaff46 Release 3.1.1
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1808 48356398-32a2-884e-a903-53898d9a118a
2008-06-19 21:43:57 +00:00
Edward Z. Yang
1009bd41a6 var -> public
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1807 48356398-32a2-884e-a903-53898d9a118a
2008-06-19 21:24:50 +00:00
Edward Z. Yang
511dfe2d4a [3.1.1] Update Munge docs.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1804 48356398-32a2-884e-a903-53898d9a118a
2008-06-19 19:06:55 +00:00
Edward Z. Yang
463aa3a0fa [3.1.1] General munge improvements
- Add CurrentCSSProperty context variable
- Move Munge to its own class, derived off of SecureMunge.
- Rename %URI.SecureMunge to %URI.Munge
- Rename %URI.SecureMungeSecretKey to %URI.MungeSecretKey
- Add extra substitutions for munge

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1803 48356398-32a2-884e-a903-53898d9a118a
2008-06-18 03:29:27 +00:00
Edward Z. Yang
7189ec2790 Update TODO
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1802 48356398-32a2-884e-a903-53898d9a118a
2008-06-17 04:00:03 +00:00
Edward Z. Yang
e901d832ab Update Modx plugin to work with HTML Purifier 3.1.0.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1801 48356398-32a2-884e-a903-53898d9a118a
2008-06-17 03:41:40 +00:00
Edward Z. Yang
643ed1bddc [3.1.1] Fix text-decoration: none bug
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1799 48356398-32a2-884e-a903-53898d9a118a
2008-06-17 03:12:50 +00:00
Edward Z. Yang
41830cd902 Update TODO
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1798 48356398-32a2-884e-a903-53898d9a118a
2008-06-17 02:40:38 +00:00
Edward Z. Yang
261aa1aeaa Update news, installer, and add an extra specimen.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1796 48356398-32a2-884e-a903-53898d9a118a
2008-06-15 22:13:16 +00:00
Edward Z. Yang
486b401cf7 Fix broken tests.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1795 48356398-32a2-884e-a903-53898d9a118a
2008-06-12 03:12:39 +00:00
Edward Z. Yang
f2794e59c5 [3.1.1] Mimick movie value in data if not set in safe object.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1794 48356398-32a2-884e-a903-53898d9a118a
2008-06-11 23:12:38 +00:00
Edward Z. Yang
d702077d2e Undo redundant embedded URI check.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1782 48356398-32a2-884e-a903-53898d9a118a
2008-06-10 01:23:11 +00:00
Edward Z. Yang
36bd06d53e [3.1.1] Implement SafeEmbed. Also, miscellaneous bugfixes.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1781 48356398-32a2-884e-a903-53898d9a118a
2008-06-10 01:18:03 +00:00
Edward Z. Yang
13eb016e06 [3.1.1] Implement SafeObject.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1780 48356398-32a2-884e-a903-53898d9a118a
2008-06-10 00:13:44 +00:00
Edward Z. Yang
32025a12e1 [3.1.1] Allow injectors to be specified by modules.
- Make method for URI implemented
- Split out checkNeeded in Injector from prepare

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1779 48356398-32a2-884e-a903-53898d9a118a
2008-06-09 01:23:05 +00:00
Edward Z. Yang
7dae94c44b Update TODO.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1778 48356398-32a2-884e-a903-53898d9a118a
2008-06-08 16:57:48 +00:00
Edward Z. Yang
54cc691ba7 Update TODO.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1777 48356398-32a2-884e-a903-53898d9a118a
2008-06-04 22:52:48 +00:00
Edward Z. Yang
3af2ff8f98 Fix bug with SecureMunge regarding embedded URIs.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1775 48356398-32a2-884e-a903-53898d9a118a
2008-06-02 17:39:29 +00:00
Edward Z. Yang
36fb284d2f Add integration test, and fix broken SecureMunge
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1774 48356398-32a2-884e-a903-53898d9a118a
2008-05-27 17:47:25 +00:00
Edward Z. Yang
8d1f1e8e73 [3.1.1] Improved adherence to Unicode by checking for non-character codepoints. Thanks Geoffrey Sneddon for reporting.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1773 48356398-32a2-884e-a903-53898d9a118a
2008-05-26 21:27:52 +00:00
Edward Z. Yang
322288e6c0 [3.1.1] Implement %URI.SecureMunge and %URI.SecureMungeSecretKey, thanks Chris!
- URIFilter->prepare can return false in order to abort loading of the filter
- Implemented post URI filtering. Set member variable $post to true to set a URIFilter as such.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1772 48356398-32a2-884e-a903-53898d9a118a
2008-05-26 16:26:47 +00:00
Edward Z. Yang
3c4346cb1e Fix back-compat regressions. Also, compactify configuration code.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1771 48356398-32a2-884e-a903-53898d9a118a
2008-05-26 04:35:12 +00:00
Edward Z. Yang
14d934c7ca [3.1.1] Land vs's HTMLPurifier_Generator patch, and a number of other bugfixes for that change
- Convert a number of calls to use new constructor signature for Generator
- Make generator require configuration; this exposes a number of latent bugs
- Removed generator hack
- Convert Printers to use new optimized ConfigSchema format
- Hack with Printer configuration; pass an array(generator config, render config) to distinguish between output and target.
- HTML/CSS Printers need to be primed, otherwise fatal errors
- Convert a few test-cases to use member properties

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1770 48356398-32a2-884e-a903-53898d9a118a
2008-05-26 04:05:48 +00:00
Edward Z. Yang
bb16d8eae5 [3.1.1] Fix Shift_JIS encoding wonkiness with yen symbols and whatnot
- Improve parseCDATA algorithm to take into account newline normalization
- Fix regression in FontFamily validator. We now have a legit parser in place, albeit somewhat limited in use. Will be superseded by parser for entire grammar
- Convert EncoderTest to new format

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1769 48356398-32a2-884e-a903-53898d9a118a
2008-05-25 05:40:20 +00:00
Edward Z. Yang
10530d7f81 [3.1.1] Fix stray backslashes in font-family.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1768 48356398-32a2-884e-a903-53898d9a118a
2008-05-24 18:19:36 +00:00
Edward Z. Yang
c7e172f660 Update news: not 1/2, more like 1/3
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1767 48356398-32a2-884e-a903-53898d9a118a
2008-05-23 17:15:13 +00:00
Edward Z. Yang
917d2ea5ef [3.1.1] More ConfigSchema optimizations: degenerate form can accommodate type and allow_null
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1766 48356398-32a2-884e-a903-53898d9a118a
2008-05-23 17:10:26 +00:00
Edward Z. Yang
895141e0b5 [3.1.1] Further optimize ConfigSchema by eliminating stdclass when only type is set.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1765 48356398-32a2-884e-a903-53898d9a118a
2008-05-23 17:00:58 +00:00
Edward Z. Yang
8ab30e24b7 [3.1.1] Memory optimizations for ConfigSchema. Changes include:
- Elimination of ConfigDef and subclasses in favor of stdclass. Most property names stay the same
- Added benchmark script for ConfigSchema
- Types are internally handled as magic integers. Use HTMLPurifier_VarParser->getTypeName to convert to human readable form. HTMLPurifier_VarParser still accepts strings.
- Parser in config schema only used for legacy interface


git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1764 48356398-32a2-884e-a903-53898d9a118a
2008-05-23 16:43:24 +00:00
Edward Z. Yang
9db891c3aa Add benchmark script for ConfigSchema.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1763 48356398-32a2-884e-a903-53898d9a118a
2008-05-23 15:24:15 +00:00
Edward Z. Yang
eb9f9bc7f6 [3.1.1] Round up imagecrash support with HTML.MaxImgLength
- Add $max to AttrDef/HTML/Pixels.php
- Add %HTML.MaxImgLength
- CSS width/height allows percents when MaxImgLength is disabled


git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1762 48356398-32a2-884e-a903-53898d9a118a
2008-05-23 02:09:43 +00:00
Edward Z. Yang
fcebb7731d [3.1.1] Migrate all HTMLModules to use setup($config) rather than __construct
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1761 48356398-32a2-884e-a903-53898d9a118a
2008-05-22 19:36:59 +00:00
Edward Z. Yang
8d0d0d1a03 [3.1.1] construct() to setup() in HTMLModules
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1760 48356398-32a2-884e-a903-53898d9a118a
2008-05-22 04:34:19 +00:00
Edward Z. Yang
80f59206d7 [3.1.1] Implement percent encoding for URI query and fragment
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1758 48356398-32a2-884e-a903-53898d9a118a
2008-05-21 02:58:41 +00:00
Edward Z. Yang
af3f5190dc [3.1.1] Lazy token updating for HTMLPurifier/AttrValidator.php
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1757 48356398-32a2-884e-a903-53898d9a118a
2008-05-21 02:30:27 +00:00
Edward Z. Yang
5620241165 [3.1.1] Disable percent height/width attributes for img
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1756 48356398-32a2-884e-a903-53898d9a118a
2008-05-21 02:01:25 +00:00
Edward Z. Yang
c06727190e Update NEWS accordingly.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1755 48356398-32a2-884e-a903-53898d9a118a
2008-05-21 01:58:48 +00:00
Edward Z. Yang
1a95852007 [3.1.1] Implement more robust imagecrash protection for CSS width/height.
- Change API for HTMLPurifier_AttrDef_CSS_Length
- Implement HTMLPurifier_AttrDef_Switch class
- Implement HTMLPurifier_Length->compareTo, and make make() accept object instances

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1754 48356398-32a2-884e-a903-53898d9a118a
2008-05-21 01:56:48 +00:00
Edward Z. Yang
c3fab7200e Add support for pixel as a pseudo-English unit.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1753 48356398-32a2-884e-a903-53898d9a118a
2008-05-21 00:42:55 +00:00
Edward Z. Yang
6d7a17e9b6 Implement without-bcmath compatible UnitConverter. We might want to factor our floating point fudges. These calculations are only accurate for small precisions, and are architecture-dependent. (Unit tests seem to work on 32bit, though).
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1752 48356398-32a2-884e-a903-53898d9a118a
2008-05-21 00:29:31 +00:00
Edward Z. Yang
64b5581bf2 [3.1.1] Have CSS/Length.php use the new Length class. Also, put onus of non-negative to callee, which would compare $n.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1751 48356398-32a2-884e-a903-53898d9a118a
2008-05-20 23:15:20 +00:00
Edward Z. Yang
d8da5ff406 Finally stabilize the unit converter.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1750 48356398-32a2-884e-a903-53898d9a118a
2008-05-20 21:23:38 +00:00
Edward Z. Yang
fda310f1e7 Update UnitConverter to deal more correctly with X.XX... decimals. Not complete.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1749 48356398-32a2-884e-a903-53898d9a118a
2008-05-20 17:48:15 +00:00
Edward Z. Yang
fc7dbdbd33 Disable Tidy test completely.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1748 48356398-32a2-884e-a903-53898d9a118a
2008-05-20 17:14:08 +00:00
Edward Z. Yang
02ac821503 Update TODO and run flush.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1747 48356398-32a2-884e-a903-53898d9a118a
2008-05-20 01:31:51 +00:00
Edward Z. Yang
16fa73afa0 [3.1.1] Added HTMLPurifier_UnitConverter and HTMLPurifier_Length for convenient handling of CSS-style lengths.
- Fixed another de-underscoring in the SimpleTest library

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1746 48356398-32a2-884e-a903-53898d9a118a
2008-05-20 01:19:00 +00:00
Edward Z. Yang
32a6afa27c Update news.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1744 48356398-32a2-884e-a903-53898d9a118a
2008-05-18 20:12:25 +00:00
334 changed files with 12407 additions and 7617 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
configdoc/usage.xml -crlf

13
.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
conf/
test-settings.php
library/HTMLPurifier/DefinitionCache/Serializer/*/
library/standalone/
library/HTMLPurifier.standalone.php
configdoc/*.html
configdoc/configdoc.xml
*.phpt.diff
*.phpt.exp
*.phpt.log
*.phpt.out
*.phpt.php
*.phpt.skip.php

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.0
PROJECT_NUMBER = 3.2.0
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.

13
FOCUS Normal file
View File

@@ -0,0 +1,13 @@
5 - Major feature enhancements
[ Appendix A: Release focus IDs ]
0 - N/A
1 - Initial freshmeat announcement
2 - Documentation
3 - Code cleanup
4 - Minor feature enhancements
5 - Major feature enhancements
6 - Minor bugfixes
7 - Major bugfixes
8 - Minor security fixes
9 - Major security fixes

View File

@@ -24,6 +24,7 @@ August 8, 2008.
These optional extensions can enhance the capabilities of HTML Purifier:
* iconv : Converts text to and from non-UTF-8 encodings
* bcmath : Used for unit conversion and imagecrash protection
* tidy : Used for pretty-printing HTML

147
NEWS
View File

@@ -9,6 +9,150 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
. Internal change
==========================
3.2.0, released 2008-10-31
# Using %Core.CollectErrors forces line number/column tracking on, whereas
previously you could theoretically turn it off.
# HTMLPurifier_Injector->notifyEnd() is formally deprecated. Please
use handleEnd() instead.
! %Output.AttrSort for when you need your attributes in alphabetical order to
deal with a bug in FCKEditor. Requested by frank farmer.
! Enable HTML comments when %HTML.Trusted is on. Requested by Waldo Jaquith.
! Proper support for name attribute. It is now allowed and equivalent to the id
attribute in a and img tags, and is only converted to id when %HTML.TidyLevel
is heavy (for all doctypes).
! %AutoFormat.RemoveEmpty to remove some empty tags from documents. Please don't
use on hand-written HTML.
! Add error-cases for unsupported elements in MakeWellFormed. This enables
the strategy to be used, standalone, on untrusted input.
! %Core.AggressivelyFixLt is on by default. This causes more sensible
processing of left angled brackets in smileys and other whatnot.
! Test scripts now have a 'type' parameter, which lets you say 'htmlpurifier',
'phpt', 'vtest', etc. in order to only execute those tests. This supercedes
the --only-phpt parameter, although for backwards-compatibility the flag
will still work.
! AutoParagraph auto-formatter will now preserve double-newlines upon output.
Users who are not performing inbound filtering, this may seem a little
useless, but as a bonus, the test suite and handling of edge cases is also
improved.
! Experimental implementation of forms for %HTML.Trusted
! Track column numbers when maintain line numbers is on
! Proprietary 'background' attribute on table-related elements converted into
corresponding CSS. Thanks Fusemail for sponsoring this feature!
! Add forward(), forwardUntilEndToken(), backward() and current() to Injector
supertype.
! HTMLPurifier_Injector->handleEnd() permits modification to end tokens. The
time of operation varies slightly from notifyEnd() as *all* end tokens are
processed by the injector before they are subject to the well-formedness rules.
! %Attr.DefaultImageAlt allows overriding default behavior of setting alt to
basename of image when not present.
! %AutoFormat.DisplayLinkURI neuters <a> tags into plain text URLs.
- Fix two bugs in %URI.MakeAbsolute; one involving empty paths in base URLs,
the other involving an undefined $is_folder error.
- Throw error when %Core.Encoding is set to a spurious value. Previously,
this errored silently and returned false.
- Redirected stderr to stdout for flush error output.
- %URI.DisableExternal will now use the host in %URI.Base if %URI.Host is not
available.
- Do not re-munge URL if the output URL has the same host as the input URL.
Requested by Chris.
- Fix error in documentation regarding %Filter.ExtractStyleBlocks
- Prevent <![CDATA[<body></body>]]> from triggering %Core.ConvertDocumentToFragment
- Fix bug with inline elements in blockquotes conflicting with strict doctype
- Detect if HTML support is disabled for DOM by checking for loadHTML() method.
- Fix bug where dots and double-dots in absolute URLs without hostname were
not collapsed by URIFilter_MakeAbsolute.
- Fix bug with anonymous modules operating on SafeEmbed or SafeObject elements
by reordering their addition.
- Will now throw exception on many error conditions during lexer creation; also
throw an exception when MaintainLineNumbers is true, but a non-tracksLineNumbers
is being used.
- Detect if domxml extension is loaded, and use DirectLEx accordingly.
- Improve handling of big numbers with floating point arithmetic in UnitConverter.
Reported by David Morton.
. Strategy_MakeWellFormed now operates in-place, saving memory and allowing
for more interesting filter-backtracking
. New HTMLPurifier_Injector->rewind() functionality, allows injectors to rewind
index to reprocess tokens.
. StringHashParser now allows for multiline sections with "empty" content;
previously the section would remain undefined.
. Added --quick option to multitest.php, which tests only the most recent
release for each series.
. Added --distro option to multitest.php, which accepts either 'normal' or
'standalone'. This supercedes --exclude-normal and --exclude-standalone
3.1.1, released 2008-06-19
# %URI.Munge now, by default, does not munge resources (for example, <img src="">)
In order to enable this again, please set %URI.MungeResources to true.
! More robust imagecrash protection with height/width CSS with %CSS.MaxImgLength,
and height/width HTML with %HTML.MaxImgLength.
! %URI.MungeSecretKey for secure URI munging. Thanks Chris
for sponsoring this feature. Check out the corresponding documentation
for details. (Att Nightly testers: The API for this feature changed before
the general release. Namely, rename your directives %URI.SecureMungeSecretKey =>
%URI.MungeSecretKey and and %URI.SecureMunge => %URI.Munge)
! Implemented post URI filtering. Set member variable $post to true to set
a URIFilter as such.
! Allow modules to define injectors via $info_injector. Injectors are
automatically disabled if injector's needed elements are not found.
! Support for "safe" objects added, use %HTML.SafeObject and %HTML.SafeEmbed.
Thanks Chris for sponsoring. If you've been using ad hoc code from the
forums, PLEASE use this instead.
! Added substitutions for %e, %n, %a and %p in %URI.Munge (in order,
embedded, tag name, attribute name, CSS property name). See %URI.Munge
for more details. Requested by Jochem Blok.
- Disable percent height/width attributes for img.
- AttrValidator operations are now atomic; updates to attributes are not
manifest in token until end of operations. This prevents naughty internal
code from directly modifying CurrentToken when they're not supposed to.
This semantics change was requested by frank farmer.
- Percent encoding checks enabled for URI query and fragment
- Fix stray backslashes in font-family; CSS Unicode character escapes are
now properly resolved (although *only* in font-family). Thanks Takeshi Terada
for reporting.
- Improve parseCDATA algorithm to take into account newline normalization
- Account for browser confusion between Yen character and backslash in
Shift_JIS encoding. This fix generalizes to any other encoding which is not
a strict superset of printable ASCII. Thanks Takeshi Terada for reporting.
- Fix missing configuration parameter in Generator calls. Thanks vs for the
partial patch.
- Improved adherence to Unicode by checking for non-character codepoints.
Thanks Geoffrey Sneddon for reporting. This may result in degraded
performance for extremely large inputs.
- Allow CSS property-value pair ''text-decoration: none''. Thanks Jochem Blok
for reporting.
. Added HTMLPurifier_UnitConverter and HTMLPurifier_Length for convenient
handling of CSS-style lengths. HTMLPurifier_AttrDef_CSS_Length now uses
this class.
. API of HTMLPurifier_AttrDef_CSS_Length changed from __construct($disable_negative)
to __construct($min, $max). __construct(true) is equivalent to
__construct('0').
. Added HTMLPurifier_AttrDef_Switch class
. Rename HTMLPurifier_HTMLModule_Tidy->construct() to setup() and bubble method
up inheritance hierarchy to HTMLPurifier_HTMLModule. All HTMLModules
get this called with the configuration object. All modules now
use this rather than __construct(), although legacy code using constructors
will still work--the new format, however, lets modules access the
configuration object for HTML namespace dependant tweaks.
. AttrDef_HTML_Pixels now takes a single construction parameter, pixels.
. ConfigSchema data-structure heavily optimized; on average it uses a third
the memory it did previously. The interface has changed accordingly,
consult changes to HTMLPurifier_Config for details.
. Variable parsing types now are magic integers instead of strings
. Added benchmark for ConfigSchema
. HTMLPurifier_Generator requires $config and $context parameters. If you
don't know what they should be, use HTMLPurifier_Config::createDefault()
and new HTMLPurifier_Context().
. Printers now properly distinguish between output configuration, and
target configuration. This is not applicable to scripts using
the Printers for HTML Purifier related tasks.
. HTML/CSS Printers must be primed with prepareGenerator($gen_config), otherwise
fatal errors will ensue.
. URIFilter->prepare can return false in order to abort loading of the filter
. Factory for AttrDef_URI implemented, URI#embedded to indicate URI that embeds
an external resource.
. %URI.Munge functionality factored out into a post-filter class.
. Added CurrentCSSProperty context variable during CSS validation
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
@@ -33,7 +177,8 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
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.
validation checks and better percent encoding handling. Thanks Gareth Heyes
for indicating security vulnerabilities from lax percent encoding.
! Bootstrap autoloader deals more robustly with classes that don't exist,
preventing class_exists($class, true) from barfing.
- InterchangeBuilder now alphabetizes its lists

22
TODO
View File

@@ -11,24 +11,28 @@ 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!
- Implement validation for query and for fragment
- Investigate how early internal structures can be accessed; this would
prevent structures from being parsed and serialized multiple times.
- Built-in support for target="_blank" on all external links
- Allow <a id="asdf" name="asdf">
- Implement overflow CSS property (as per jlp09550)
FUTURE VERSIONS
---------------
3.2 release [It's All About Trust] (floating)
3.3 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
- Implement <area>
- Figure out how to simultaneously set %CSS.Trusted and %HTML.Trusted (?)
3.3 release [Error'ed]
3.4 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]
3.5 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>)
@@ -39,7 +43,6 @@ FUTURE VERSIONS
contents should be dropped or not (currently, there's code that could do
something like this if it didn't drop the inner text too.)
- Remove <span> tags that don't do anything (no attributes)
- 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, proposed by Sander Tekelenburg
@@ -49,14 +52,12 @@ FUTURE VERSIONS
AttrDef class). Probably will use CSSTidy class?
# More control over allowed CSS properties using a modularization
# HTML 5 support
# IRI support
# IRI support (this includes IDN)
- 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
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
@@ -104,6 +105,7 @@ Neat feature related
- 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
- Allow restriction of allowed class values
Maintenance related (slightly boring)
# CHMOD install script for PEAR installs

View File

@@ -1 +1 @@
3.1.0
3.2.0

View File

@@ -1,10 +1,6 @@
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.
HTML Purifier 3.2.0 is an amalgamation of new features and fixes that
have accumulated over a four month period. Some notable features
include %AutoFormat.RemoveEmpty, column tracking for tokens,
%AutoFormat.DisplayLinkURI and %Attr.DefaultImageAlt. There were also
major improvements to the test suite interface, error collection output
and the auto-formatter framework.

View File

@@ -0,0 +1,14 @@
<?php
chdir(dirname(__FILE__));
//require_once '../library/HTMLPurifier.path.php';
shell_exec('php ../maintenance/generate-schema-cache.php');
require_once '../library/HTMLPurifier.path.php';
require_once 'HTMLPurifier.includes.php';
$begin = xdebug_memory_usage();
$schema = HTMLPurifier_ConfigSchema::makeFromSerial();
echo xdebug_memory_usage() - $begin;

View File

@@ -19,7 +19,7 @@
<xsl:variable name="usageLookup" select="document('../usage.xml')/usage" />
<!-- Twiddle this variable to get the columns as even as possible -->
<xsl:variable name="maxNumberAdjust" select="1" />
<xsl:variable name="maxNumberAdjust" select="2" />
<xsl:template match="/">
<html lang="en" xml:lang="en">

View File

@@ -5,35 +5,40 @@
<line>131</line>
</file>
<file name="HTMLPurifier/Lexer.php">
<line>85</line>
<line>81</line>
</file>
<file name="HTMLPurifier/Lexer/DirectLex.php">
<line>50</line>
<line>62</line>
<line>327</line>
<line>53</line>
<line>73</line>
<line>348</line>
</file>
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>44</line>
<line>47</line>
</file>
</directive>
<directive id="CSS.MaxImgLength">
<file name="HTMLPurifier/CSSDefinition.php">
<line>157</line>
</file>
</directive>
<directive id="CSS.Proprietary">
<file name="HTMLPurifier/CSSDefinition.php">
<line>202</line>
<line>214</line>
</file>
</directive>
<directive id="CSS.AllowTricky">
<file name="HTMLPurifier/CSSDefinition.php">
<line>206</line>
<line>218</line>
</file>
</directive>
<directive id="CSS.AllowImportant">
<file name="HTMLPurifier/CSSDefinition.php">
<line>210</line>
<line>222</line>
</file>
</directive>
<directive id="CSS.AllowedProperties">
<file name="HTMLPurifier/CSSDefinition.php">
<line>262</line>
<line>274</line>
</file>
</directive>
<directive id="Cache.DefinitionImpl">
@@ -63,106 +68,116 @@
</directive>
<directive id="Core.Encoding">
<file name="HTMLPurifier/Encoder.php">
<line>281</line>
<line>305</line>
<line>267</line>
<line>300</line>
</file>
</directive>
<directive id="Test.ForceNoIconv">
<file name="HTMLPurifier/Encoder.php">
<line>283</line>
<line>310</line>
<line>272</line>
<line>308</line>
</file>
</directive>
<directive id="Core.EscapeNonASCIICharacters">
<file name="HTMLPurifier/Encoder.php">
<line>307</line>
</file>
</directive>
<directive id="Core.MaintainLineNumbers">
<file name="HTMLPurifier/ErrorCollector.php">
<line>81</line>
</file>
<file name="HTMLPurifier/Lexer.php">
<line>82</line>
</file>
<file name="HTMLPurifier/Lexer/DirectLex.php">
<line>45</line>
<line>304</line>
</file>
</directive>
<directive id="Output.CommentScriptContents">
<file name="HTMLPurifier/Generator.php">
<line>41</line>
<line>45</line>
</file>
</directive>
<directive id="Output.SortAttr">
<file name="HTMLPurifier/Generator.php">
<line>46</line>
</file>
</directive>
<directive id="Output.TidyFormat">
<file name="HTMLPurifier/Generator.php">
<line>70</line>
<line>75</line>
</file>
</directive>
<directive id="Output.Newline">
<file name="HTMLPurifier/Generator.php">
<line>84</line>
<line>89</line>
</file>
</directive>
<directive id="HTML.BlockWrapper">
<file name="HTMLPurifier/HTMLDefinition.php">
<line>213</line>
<line>222</line>
</file>
</directive>
<directive id="HTML.Parent">
<file name="HTMLPurifier/HTMLDefinition.php">
<line>221</line>
<line>230</line>
</file>
</directive>
<directive id="HTML.AllowedElements">
<file name="HTMLPurifier/HTMLDefinition.php">
<line>238</line>
<line>247</line>
</file>
</directive>
<directive id="HTML.AllowedAttributes">
<file name="HTMLPurifier/HTMLDefinition.php">
<line>239</line>
<line>248</line>
</file>
</directive>
<directive id="HTML.Allowed">
<file name="HTMLPurifier/HTMLDefinition.php">
<line>242</line>
<line>251</line>
</file>
</directive>
<directive id="HTML.ForbiddenElements">
<file name="HTMLPurifier/HTMLDefinition.php">
<line>328</line>
<line>337</line>
</file>
</directive>
<directive id="HTML.ForbiddenAttributes">
<file name="HTMLPurifier/HTMLDefinition.php">
<line>329</line>
<line>338</line>
</file>
</directive>
<directive id="HTML.Trusted">
<file name="HTMLPurifier/HTMLModuleManager.php">
<line>198</line>
<line>202</line>
</file>
<file name="HTMLPurifier/Lexer.php">
<line>238</line>
<line>258</line>
</file>
<file name="HTMLPurifier/HTMLModule/Image.php">
<line>27</line>
</file>
<file name="HTMLPurifier/Lexer/DirectLex.php">
<line>34</line>
<line>36</line>
</file>
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>23</line>
</file>
</directive>
<directive id="HTML.AllowedModules">
<file name="HTMLPurifier/HTMLModuleManager.php">
<line>205</line>
<line>209</line>
</file>
</directive>
<directive id="HTML.CoreModules">
<file name="HTMLPurifier/HTMLModuleManager.php">
<line>206</line>
<line>210</line>
</file>
</directive>
<directive id="HTML.Proprietary">
<file name="HTMLPurifier/HTMLModuleManager.php">
<line>220</line>
<line>221</line>
</file>
</directive>
<directive id="HTML.SafeObject">
<file name="HTMLPurifier/HTMLModuleManager.php">
<line>226</line>
</file>
</directive>
<directive id="HTML.SafeEmbed">
<file name="HTMLPurifier/HTMLModuleManager.php">
<line>229</line>
</file>
</directive>
<directive id="Attr.IDBlacklist">
@@ -177,30 +192,35 @@
</directive>
<directive id="Core.LexerImpl">
<file name="HTMLPurifier/Lexer.php">
<line>70</line>
<line>76</line>
</file>
</directive>
<directive id="Core.MaintainLineNumbers">
<file name="HTMLPurifier/Lexer.php">
<line>80</line>
</file>
<file name="HTMLPurifier/Lexer/DirectLex.php">
<line>48</line>
</file>
</directive>
<directive id="Core.ConvertDocumentToFragment">
<file name="HTMLPurifier/Lexer.php">
<line>230</line>
<line>267</line>
</file>
</directive>
<directive id="URI.Host">
<file name="HTMLPurifier/URIDefinition.php">
<line>57</line>
</file>
<file name="HTMLPurifier/URIFilter/DisableExternal.php">
<line>8</line>
<line>64</line>
</file>
</directive>
<directive id="URI.Base">
<file name="HTMLPurifier/URIDefinition.php">
<line>58</line>
<line>65</line>
</file>
</directive>
<directive id="URI.DefaultScheme">
<file name="HTMLPurifier/URIDefinition.php">
<line>65</line>
<line>72</line>
</file>
</directive>
<directive id="URI.AllowedSchemes">
@@ -215,12 +235,7 @@
</directive>
<directive id="URI.Disable">
<file name="HTMLPurifier/AttrDef/URI.php">
<line>23</line>
</file>
</directive>
<directive id="URI.Munge">
<file name="HTMLPurifier/AttrDef/URI.php">
<line>68</line>
<line>28</line>
</file>
</directive>
<directive id="Core.ColorKeywords">
@@ -275,9 +290,14 @@
<line>19</line>
</file>
</directive>
<directive id="Attr.DefaultImageAlt">
<file name="HTMLPurifier/AttrTransform/ImgRequired.php">
<line>25</line>
</file>
</directive>
<directive id="Attr.DefaultInvalidImageAlt">
<file name="HTMLPurifier/AttrTransform/ImgRequired.php">
<line>27</line>
<line>32</line>
</file>
</directive>
<directive id="Core.EscapeInvalidChildren">
@@ -305,6 +325,17 @@
<line>123</line>
</file>
</directive>
<directive id="HTML.MaxImgLength">
<file name="HTMLPurifier/HTMLModule/Image.php">
<line>14</line>
</file>
<file name="HTMLPurifier/HTMLModule/SafeEmbed.php">
<line>13</line>
</file>
<file name="HTMLPurifier/HTMLModule/SafeObject.php">
<line>19</line>
</file>
</directive>
<directive id="HTML.TidyLevel">
<file name="HTMLPurifier/HTMLModule/Tidy.php">
<line>45</line>
@@ -332,12 +363,12 @@
</directive>
<directive id="Core.DirectLexLineNumberSyncInterval">
<file name="HTMLPurifier/Lexer/DirectLex.php">
<line>59</line>
<line>70</line>
</file>
</directive>
<directive id="Core.EscapeInvalidTags">
<file name="HTMLPurifier/Strategy/MakeWellFormed.php">
<line>22</line>
<line>45</line>
</file>
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>19</line>
@@ -345,12 +376,12 @@
</directive>
<directive id="Core.RemoveScriptContents">
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>22</line>
<line>25</line>
</file>
</directive>
<directive id="Core.HiddenElements">
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>23</line>
<line>26</line>
</file>
</directive>
<directive id="URI.HostBlacklist">
@@ -358,4 +389,14 @@
<line>8</line>
</file>
</directive>
<directive id="URI.MungeResources">
<file name="HTMLPurifier/URIFilter/Munge.php">
<line>14</line>
</file>
</directive>
<directive id="URI.MungeSecretKey">
<file name="HTMLPurifier/URIFilter/Munge.php">
<line>15</line>
</file>
</directive>
</usage>

View File

@@ -213,6 +213,4 @@ the usual things required are:</p>
<p>See <code>HTMLPurifier/HTMLModule.php</code> for details.</p>
<div id="version">$Id$</div>
</body></html>

View File

@@ -239,15 +239,15 @@ Test.Example</pre>
object; users have a little bit of leeway when setting configuration
values (for example, a lookup value can be specified as a list;
HTML Purifier will flip it as necessary.) These types are defined
in <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/VarParser.php">
in <a href="http://repo.or.cz/w/htmlpurifier.git?a=blob;hb=HEAD;f=library/HTMLPurifier/VarParser.php">
library/HTMLPurifier/VarParser.php</a>.
</p>
<p>
For more information on what values are allowed, and how they are parsed,
consult <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php">
consult <a href="http://repo.or.cz/w/htmlpurifier.git?a=blob;hb=HEAD;f=library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php">
library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php</a>, as well
as <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php">
as <a href="http://repo.or.cz/w/htmlpurifier.git?a=blob;hb=HEAD;f=library/HTMLPurifier/ConfigSchema/Interchange/Directive.php">
library/HTMLPurifier/ConfigSchema/Interchange/Directive.php</a> for
the semantics of the parsed values.
</p>
@@ -272,7 +272,7 @@ Test.Example</pre>
<p>
All directive files go through a rigorous validation process
through <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/ConfigSchema/">
through <a href="http://repo.or.cz/w/htmlpurifier.git?a=blob;hb=HEAD;f=library/HTMLPurifier/ConfigSchema/Validator.php">
library/HTMLPurifier/ConfigSchema/Validator.php</a>, as well
as some basic checks during building. While
listing every error out here is out-of-scope for this document, we
@@ -339,7 +339,7 @@ Test.Example</pre>
The most difficult part is translating the Interchange member variable (valueAliases)
into a directive file key (VALUE-ALIASES), but there's a one-to-one
correspondence currently. If the two formats diverge, any discrepancies
will be described in <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php">
will be described in <a href="http://repo.or.cz/w/htmlpurifier.git?a=blob;hb=HEAD;f=library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php">
library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php</a>.
</p>
@@ -370,7 +370,5 @@ Test.Example</pre>
data. There is also an XML serializer, which is used to build documentation.
</p>
<div id="version">$Id$</div>
</body>
</html>

View File

@@ -62,6 +62,4 @@
do.
</p>
<div id="version">$Id$</div>
</body></html>

View File

@@ -77,6 +77,4 @@ help you find the correct functionality more quickly. Here they are:</p>
</dl>
<div id="version">$Id$</div>
</body></html>

View File

@@ -27,6 +27,4 @@ that itch, put it here!</p>
<li>Parallelize strategies</li>
</ul>
<div id="version">$Id$</div>
</body></html>

View File

@@ -303,6 +303,4 @@ Mozilla on inside and needs -moz-outline, no IE support.</td></tr>
</table>
<div id="version">$Id$</div>
</body></html>

View File

@@ -213,7 +213,7 @@ $def = $config->getHTMLDefinition(true);</pre>
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
<strong>$config->set('Core', 'DefinitionCache', null); // remove this later!</strong>
<strong>$config->set('Cache', 'DefinitionImpl', null); // remove this later!</strong>
$def = $config->getHTMLDefinition(true);</pre>
<p>
@@ -269,7 +269,7 @@ $def = $config->getHTMLDefinition(true);</pre>
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
$config->set('Core', 'DefinitionCache', null); // remove this later!
$config->set('Cache', 'DefinitionImpl', null); // remove this later!
$def = $config->getHTMLDefinition(true);
<strong>$def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');</strong></pre>
@@ -372,10 +372,10 @@ $def = $config->getHTMLDefinition(true);
<p>
For a complete list, consult
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/AttrTypes.php"><code>library/HTMLPurifier/AttrTypes.php</code></a>;
<a href="http://repo.or.cz/w/htmlpurifier.git?a=blob;hb=HEAD;f=library/HTMLPurifier/AttrTypes.php"><code>library/HTMLPurifier/AttrTypes.php</code></a>;
more information on attributes that accept parameters can be found on their
respective includes in
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/AttrDef/"><code>library/HTMLPurifier/AttrDef</code></a>.
<a href="http://repo.or.cz/w/htmlpurifier.git?a=tree;hb=HEAD;f=library/HTMLPurifier/AttrDef"><code>library/HTMLPurifier/AttrDef</code></a>.
</p>
<p>
@@ -387,7 +387,7 @@ $def = $config->getHTMLDefinition(true);
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
$config->set('Core', 'DefinitionCache', null); // remove this later!
$config->set('Cache', 'DefinitionImpl', null); // remove this later!
$def = $config->getHTMLDefinition(true);
<strong>$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
array('_blank','_self','_target','_top')
@@ -734,7 +734,7 @@ $def = $config->getHTMLDefinition(true);
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
$config->set('Core', 'DefinitionCache', null); // remove this later!
$config->set('Cache', 'DefinitionImpl', null); // remove this later!
$def = $config->getHTMLDefinition(true);
$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
array('_blank','_self','_target','_top')
@@ -764,7 +764,7 @@ $form->excludes = array('form' => true);</strong></pre>
<p>
And that's all there is to it! Implementing the rest of the form
module is left as an exercise to the user; to see more examples
check the <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/HTMLModule/"><code>library/HTMLPurifier/HTMLModule/</code></a> directory
check the <a href="http://repo.or.cz/w/htmlpurifier.git?a=tree;hb=HEAD;f=library/HTMLPurifier/HTMLModule"><code>library/HTMLPurifier/HTMLModule/</code></a> directory
in your local HTML Purifier installation.
</p>
@@ -789,10 +789,8 @@ $form->excludes = array('form' => true);</strong></pre>
</p>
<ul>
<li><a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/HTMLModule.php"><code>library/HTMLPurifier/HTMLModule.php</code></a></li>
<li><a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/ElementDef.php"><code>library/HTMLPurifier/ElementDef.php</code></a></li>
<li><a href="http://repo.or.cz/w/htmlpurifier.git?a=blob;hb=HEAD;f=library/HTMLPurifier/HTMLModule.php"><code>library/HTMLPurifier/HTMLModule.php</code></a></li>
<li><a href="http://repo.or.cz/w/htmlpurifier.git?a=blob;hb=HEAD;f=library/HTMLPurifier/ElementDef.php"><code>library/HTMLPurifier/ElementDef.php</code></a></li>
</ul>
<div id="version">$Id: enduser-tidy.html 1158 2007-06-18 19:26:29Z Edward $</div>
</body></html>

View File

@@ -141,7 +141,5 @@ anchors is beyond me.</p>
<p>Don't come crying to me when your page mysteriously stops validating, though.</p>
<div id="version">$Id$</div>
</body>
</html>

View File

@@ -225,6 +225,4 @@ and if that still doesn't satisfy your appetite, do some fine-tuning.
Other than that, don't worry about it: this all works silently and
effectively in the background.</p>
<div id="version">$Id$</div>
</body></html>

View File

@@ -130,30 +130,26 @@
</p>
<p>
Let's suppose I wanted to write a filter that de-internationalized domain
names by converting them to <a href="http://en.wikipedia.org/wiki/Punycode">Punycode</a>.
Assuming that <code>punycode_encode($input)</code> converts <code>$input</code> to
Punycode and returns <code>false</code> on failure:
Let's suppose I wanted to write a filter that converted links with a
custom <code>image</code> scheme to its corresponding real path on
our website:
</p>
<pre>class HTMLPurifier_URIFilter_ConvertIDNToPunycode extends HTMLPurifier_URIFilter
<pre>class HTMLPurifier_URIFilter_TransformImageScheme extends HTMLPurifier_URIFilter
{
public $name = 'ConvertIDNToPunycode';
public $name = 'TransformImageScheme';
public function filter(&$uri, $config, $context) {
if (is_null($uri->host)) return true;
if ($uri->host == utf8_decode($uri->host)) {
// is ASCII, abort
return true;
}
$host = punycode_encode($uri->host);
if ($host === false) return false;
$uri->host = $host;
if ($uri->scheme !== 'image') return true;
$img_name = $uri->path;
// Overwrite the previous URI object
$uri = new HTMLPurifier_URI('http', null, null, null, '/img/' . $img_name . '.png', null, null);
return true;
}
}</pre>
<p>
Notice I did not <code>return $uri;</code>.
Notice I did not <code>return $uri;</code>. This filter would turn
<code>image:Foo</code> into <code>/img/Foo.png</code>.
</p>
<h2>Activating your filter</h2>
@@ -186,16 +182,33 @@ $uri->registerFilter(new HTMLPurifier_URIFilter_<strong>NameOfFilter</strong>())
is set to true.
</p>
<h2>Post-filter</h2>
<p>
Remember our TransformImageScheme filter? That filter acted before we had
performed scheme validation; otherwise, the URI would have been filtered
out when it was discovered that there was no image scheme. Well, a post-filter
is run after scheme specific validation, so it's ideal for bulk
post-processing of URIs, including munging. To specify a URI as a post-filter,
set the <code>$post</code> member variable to TRUE.
</p>
<pre>class HTMLPurifier_URIFilter_MyPostFilter extends HTMLPurifier_URIFilter
{
public $name = 'MyPostFilter';
public $post = true;
// ... extra code here
}
</pre>
<h2>Examples</h2>
<p>
Check the
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/URIFilter/">URIFilter</a>
directory for more implementation examples, and see <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/docs/proposal-new-directives.txt">the
<a href="http://repo.or.cz/w/htmlpurifier.git?a=tree;hb=HEAD;f=library/HTMLPurifier/URIFilter">URIFilter</a>
directory for more implementation examples, and see <a href="proposal-new-directives.txt">the
new directives proposal document</a> for ideas on what could be implemented
as a filter.
</p>
<div id="version">$Id$</div>
</body></html>

View File

@@ -118,9 +118,8 @@ there are now many character encodings floating around.</p>
see a page on the web, chances are it's encoded in one
of these encodings.</li>
<li><strong>Unicode-based encodings</strong> implement the
Unicode standard and include UTF-8, UCS-2 and UTF-16.
They go beyond 8-bits (the first two are variable length,
while the second one uses 16-bits), and support almost
Unicode standard and include UTF-8, UTF-16 and UTF-32/UCS-4.
They go beyond 8-bits and support almost
every language in the world. UTF-8 is gaining traction
as the dominant international encoding of the web.</li>
</ul>
@@ -590,8 +589,10 @@ looks something like: <code>%C3%86</code>. There is no official way of
determining the character encoding of such a request, since the percent
encoding operates on a byte level, so it is usually assumed that it
is the same as the encoding the page containing the form was submitted
in. You'll run into very few problems if you only use characters in
the character encoding you chose.</p>
in. (<a href="http://tools.ietf.org/html/rfc3986#section-2.5">RFC 3986</a>
recommends that textual identifiers be translated to UTF-8; however, browser
compliance is spotty.) You'll run into very few problems
if you only use characters in the character encoding you chose.</p>
<p>However, once you start adding characters outside of your encoding
(and this is a lot more common than you may think: take curly

View File

@@ -70,7 +70,7 @@ into your documents. YouTube's code goes like this:</p>
class=&quot;embed-youtube&quot;&gt;AyPzM5WK8ys&lt;/span&gt;</code> your
application can reconstruct the full object from this small snippet that
passes through HTML Purifier <em>unharmed</em>.
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/Filter/YouTube.php">Show me the code!</a></p>
<a href="http://repo.or.cz/w/htmlpurifier.git?a=blob;hb=HEAD;f=library/HTMLPurifier/Filter/YouTube.php">Show me the code!</a></p>
<p>And the corresponding usage:</p>

View File

@@ -98,8 +98,8 @@ the code. They may be upgraded to HTML files or stay as TXT scratchpads.</p>
<table class="table">
<thead><tr>
<th width="10%">Type</th>
<th width="20%">Name</th>
<th style="width:10%">Type</th>
<th style="width:20%">Name</th>
<th>Description</th>
</tr></thead>
@@ -175,6 +175,5 @@ the code. They may be upgraded to HTML files or stay as TXT scratchpads.</p>
</table>
<div id="version">$Id$</div>
</body>
</html>

View File

@@ -42,7 +42,5 @@ into the mix.</li>
something like that?</li>
</ol>
<div id="version">$Id$</div>
</body>
</html>

209
docs/proposal-errors.txt Normal file
View File

@@ -0,0 +1,209 @@
Considerations for ErrorCollection
Presently, HTML Purifier takes a code-execution centric approach to handling
errors. Errors are organized and grouped according to which segment of the
code triggers them, not necessarily the portion of the input document that
triggered the error. This means that errors are pseudo-sorted by category,
rather than location in the document.
One easy way to "fix" this problem would be to re-sort according to line number.
However, the "category" style information we derive from naively following
program execution is still useful. After all, each of the strategies which
can report errors still process the document mostly linearly. Furthermore,
not only do they process linearly, but the way they pass off operations to
sub-systems mirrors that of the document. For example, AttrValidator will
linearly proceed through elements, and on each element will use AttrDef to
validate those contents. From there, the attribute might have more
sub-components, which have execution passed off accordingly.
In fact, each strategy handles a very specific class of "error."
RemoveForeignElements - element tokens
MakeWellFormed - element token ordering
FixNesting - element token ordering
ValidateAttributes - attributes of elements
The crucial point is that while we care about the hierarchy governing these
different errors, we *don't* care about any other information about what actually
happens to the elements. This brings up another point: if HTML Purifier fixes
something, this is not really a notice/warning/error; it's really a suggestion
of a way to fix the aforementioned defects.
In short, the refactoring to take this into account kinda sucks.
Errors should not be recorded in order that they are reported. Instead, they
should be bound to the line (and preferably element) in which they were found.
This means we need some way to uniquely identify every element in the document,
which doesn't presently exist. An easy way of adding this would be to track
line columns. An important ramification of this is that we *must* use the
DirectLex implementation.
1. Implement column numbers for DirectLex [DONE!]
2. Disable error collection when not using DirectLex [DONE!]
Next, we need to re-orient all of the error declarations to place CurrentToken
at utmost important. Since this is passed via Context, it's not always clear
if that's available. ErrorCollector should complain HARD if it isn't available.
There are some locations when we don't have a token available. These include:
* Lexing - this can actually have a row and column, but NOT correspond to
a token
* End of document errors - bump this to the end
Actually, we *don't* have to complain if CurrentToken isn't available; we just
set it as a document-wide error. And actually, nothing needs to be done here.
Something interesting to consider is whether or not we care about the locations
of attributes and CSS properties, i.e. the sub-objects that compose these things.
In terms of consistency, at the very least attributes should have column/line
numbers attached to them. However, this may be overkill, as attributes are
uniquely identifiable. You could go even further, with CSS, but they are also
uniquely identifiable.
Bottom-line is, however, this information must be available, in form of the
CurrentAttribute and CurrentCssProperty (theoretical) context variables, and
it must be used to organize the errors that the sub-processes may throw.
There is also a hierarchy of sorts that may make merging this into one context
variable more sense, if it hadn't been for HTML's reasonably rigid structure.
A CSS property will never contain an HTML attribute. So we won't ever get
recursive relations, and having multiple depths won't ever make sense. Leave
this be.
We already have this information, and consequently, using start and end is
*unnecessary*, so long as the context variables are set appropriately. We don't
care if an error was thrown by an attribute transform or an attribute definition;
to the end user these are the same (for a developer, they are different, but
they're better off with a stack trace (which we should add support for) in such
cases).
3. Remove start()/end() code. Don't get rid of recursion, though [DONE]
4. Setup ErrorCollector to use context information to setup hierarchies.
This may require a different internal format. Use objects if it gets
complex. [DONE]
ASIDE
More on this topic: since we are now binding errors to lines
and columns, a particular error can have three relationships to that
specific location:
1. The token at that location directly
RemoveForeignElements
AttrValidator (transforms)
MakeWellFormed
2. A "component" of that token (i.e. attribute)
AttrValidator (removals)
3. A modification to that node (i.e. contents from start to end
token) as a whole
FixNesting
This needs to be marked accordingly. In the presentation, it might
make sense keep (3) separate, have (2) a sublist of (1). (1) can
be a closing tag, in which case (3) makes no sense at all, OR it
should be related with its opening tag (this may not necessarily
be possible before MakeWellFormed is run).
So, the line and column counts as our identifier, so:
$errors[$line][$col] = ...
Then, we need to identify case 1, 2 or 3. They are identified as
such:
1. Need some sort of semaphore in RemoveForeignElements, etc.
2. If CurrentAttr/CurrentCssProperty is non-null
3. Default (FixNesting, MakeWellFormed)
One consideration about (1) is that it usually is actually a
(3) modification, but we have no way of knowing about that because
of various optimizations. However, they can probably be treated
the same. The other difficulty is that (3) is never a line and
column; rather, it is a range (i.e. a duple) and telling the user
the very start of the range may confuse them. For example,
<b>Foo<div>bar</div></b>
^ ^
The node being operated on is <b>, so the error would be assigned
to the first caret, with a "node reorganized" error. Then, the
ChildDef would have submitted its own suggestions and errors with
regard to what's going in the internals. So I suppose this is
ok. :-)
Now, the structure of the earlier mentioned ... would be something
like this:
object {
type = (token|attr|property),
value, // appropriate for type
errors => array(),
sub-errors = [recursive],
}
This helps us keep things agnostic. It is also sufficiently complex
enough to warrant an object.
So, more wanking about the object format is in order. The way HTML Purifier is
currently setup, the only possible hierarchy is:
token -> attr -> css property
These relations do not exist all of the time; a comment or end token would not
ever have any attributes, and non-style attributes would never have CSS properties
associated with them.
I believe that it is worth supporting multiple paths. At some point, we might
have a hierarchy like:
* -> syntax
-> token -> attr -> css property
-> url
-> css stylesheet <style>
et cetera. Now, one of the practical implications of this is that every "node"
on our tree is well-defined, so in theory it should be possible to either 1.
create a separate class for each error struct, or 2. embed this information
directly into HTML Purifier's token stream. Embedding the information in the
token stream is not a terribly good idea, since tokens can be removed, etc.
So that leaves us with 1... and if we use a generic interface we can cut down
on a lot of code we might need. So let's leave it like this.
~~~~
Then we setup suggestions.
5. Setup a separate error class which tells the user any modifications
HTML Purifier made.
Some information about this:
Our current paradigm is to tell the user what HTML Purifier did to the HTML.
This is the most natural mode of operation, since that's what HTML Purifier
is all about; it was not meant to be a validator.
However, most other people have experience dealing with a validator. In cases
where HTML Purifier unambiguously does the right thing, simply giving the user
the correct version isn't a bad idea, but problems arise when:
- The user has such bad HTML we do something odd, when we should have just
flagged the HTML as an error. Such examples are when we do things like
remove text from directly inside a <table> tag. It was probably meant to
be in a <td> tag or be outside the table, but we're not smart enough to
realize this so we just remove it. In such a case, we should tell the user
that there was foreign data in the table, but then we shouldn't "demand"
the user remove the data; it's more of a "here's a possible way of
rectifying the problem"
- Giving line context for input is hard enough, but feasible; giving output
line context will be extremely difficult due to shifting lines; we'd probably
have to track what the tokens are and then find the appropriate out context
and it's not guaranteed to work etc etc etc.
````````````
Don't forget to spruce up output.
6. Output needs to automatically give line and column numbers, basically
"at line" on steroids. Look at W3C's output; it's ok. [PARTIALLY DONE]
- We need a standard CSS to apply (check demo.css for some starting
styling; some buttons would also be hip)

View File

@@ -40,6 +40,5 @@ the development of this library in these forum threads:</p>
<p>...as well as any I may have forgotten.</p>
<div id="version">$Id$</div>
</body>
</html>

View File

@@ -0,0 +1,129 @@
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=us-ascii">
<meta name=Generator content="Microsoft Word 12 (filtered medium)">
<!--[if !mso]>
<style>
v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
..shape {behavior:url(#default#VML);}
</style>
<![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;}
@font-face
{font-family:Verdana;
panose-1:2 11 6 4 3 5 4 4 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
margin-bottom:.0001pt;
font-size:10.0pt;
font-family:"Verdana","sans-serif";}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:purple;
text-decoration:underline;}
p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
{mso-style-priority:99;
mso-style-link:"Balloon Text Char";
margin:0cm;
margin-bottom:.0001pt;
font-size:8.0pt;
font-family:"Tahoma","sans-serif";}
span.EmailStyle17
{mso-style-type:personal-compose;
font-family:"Verdana","sans-serif";
color:windowtext;}
span.BalloonTextChar
{mso-style-name:"Balloon Text Char";
mso-style-priority:99;
mso-style-link:"Balloon Text";
font-family:"Tahoma","sans-serif";}
..MsoChpDefault
{mso-style-type:export-only;}
@page Section1
{size:612.0pt 792.0pt;
margin:70.85pt 70.85pt 70.85pt 70.85pt;}
div.Section1
{page:Section1;}
-->
</style>
<!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="2050" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang=NL link=blue vlink=purple>
<div class=Section1>
<p class=MsoNormal><img width=1277 height=994 id="Picture_x0020_1"
src="cid:image001.png@01C8CBDF.5D1BAEE0"><o:p></o:p></p>
<p class=MsoNormal><o:p>&nbsp;</o:p></p>
<p class=MsoNormal><b>Name<o:p></o:p></b></p>
<p class=MsoNormal>E-mail : <a href="mailto:mail@example.com"><span
style='color:windowtext'>mail@example.com</span></a><o:p></o:p></p>
<p class=MsoNormal><o:p>&nbsp;</o:p></p>
<p class=MsoNormal><b>Company<o:p></o:p></b></p>
<p class=MsoNormal>Address 1<o:p></o:p></p>
<p class=MsoNormal>Address 2<o:p></o:p></p>
<p class=MsoNormal><o:p>&nbsp;</o:p></p>
<p class=MsoNormal>Telefoon&nbsp; : +xx xx xxx xxx xx <span style='color:black'><o:p></o:p></span></p>
<p class=MsoNormal><span lang=EN-US style='color:black'>Fax&nbsp; : +xx xx xxx xx xx<o:p></o:p></span></p>
<p class=MsoNormal><span lang=EN-US style='color:black'>Internet : </span><span
style='color:black'><a href="http://www.example.com/"><span lang=EN-US
style='color:black'>http://www.example.com</span></a></span><span
lang=EN-US style='color:black'><o:p></o:p></span></p>
<p class=MsoNormal><span lang=EN-US style='color:black'>Kamer van koophandel
xxxxxxxxx<o:p></o:p></span></p>
<p class=MsoNormal><span lang=EN-US style='color:black'><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal><span lang=EN-US style='font-size:7.5pt;color:black'>Op deze
e-mail is een disclaimer van toepassing, ga naar </span><span lang=EN-US
style='font-size:7.5pt'><a
href="http://www.example.com/disclaimer"><span
style='color:black'>www.example.com/disclaimer</span></a><br>
<span style='color:black'>A disclaimer is applicable to this email, please
refer to </span><a href="http://www.example.com/disclaimer"><span
style='color:black'>www.example.com/disclaimer</span></a><o:p></o:p></span></p>
<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>
</div>
</body>
</html>

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.1.0
* @version 3.2.0
*
* @warning
* You must *not* include any other HTML Purifier files before this file,
@@ -29,7 +29,6 @@ require 'HTMLPurifier/Definition.php';
require 'HTMLPurifier/CSSDefinition.php';
require 'HTMLPurifier/ChildDef.php';
require 'HTMLPurifier/Config.php';
require 'HTMLPurifier/ConfigDef.php';
require 'HTMLPurifier/ConfigSchema.php';
require 'HTMLPurifier/ContentSets.php';
require 'HTMLPurifier/Context.php';
@@ -42,6 +41,7 @@ require 'HTMLPurifier/Encoder.php';
require 'HTMLPurifier/EntityLookup.php';
require 'HTMLPurifier/EntityParser.php';
require 'HTMLPurifier/ErrorCollector.php';
require 'HTMLPurifier/ErrorStruct.php';
require 'HTMLPurifier/Exception.php';
require 'HTMLPurifier/Filter.php';
require 'HTMLPurifier/Generator.php';
@@ -52,6 +52,7 @@ require 'HTMLPurifier/IDAccumulator.php';
require 'HTMLPurifier/Injector.php';
require 'HTMLPurifier/Language.php';
require 'HTMLPurifier/LanguageFactory.php';
require 'HTMLPurifier/Length.php';
require 'HTMLPurifier/Lexer.php';
require 'HTMLPurifier/PercentEncoder.php';
require 'HTMLPurifier/Strategy.php';
@@ -66,12 +67,14 @@ require 'HTMLPurifier/URIFilter.php';
require 'HTMLPurifier/URIParser.php';
require 'HTMLPurifier/URIScheme.php';
require 'HTMLPurifier/URISchemeRegistry.php';
require 'HTMLPurifier/UnitConverter.php';
require 'HTMLPurifier/VarParser.php';
require 'HTMLPurifier/VarParserException.php';
require 'HTMLPurifier/AttrDef/CSS.php';
require 'HTMLPurifier/AttrDef/Enum.php';
require 'HTMLPurifier/AttrDef/Integer.php';
require 'HTMLPurifier/AttrDef/Lang.php';
require 'HTMLPurifier/AttrDef/Switch.php';
require 'HTMLPurifier/AttrDef/Text.php';
require 'HTMLPurifier/AttrDef/URI.php';
require 'HTMLPurifier/AttrDef/CSS/Number.php';
@@ -106,6 +109,7 @@ require 'HTMLPurifier/AttrDef/URI/Host.php';
require 'HTMLPurifier/AttrDef/URI/IPv4.php';
require 'HTMLPurifier/AttrDef/URI/IPv6.php';
require 'HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php';
require 'HTMLPurifier/AttrTransform/Background.php';
require 'HTMLPurifier/AttrTransform/BdoDir.php';
require 'HTMLPurifier/AttrTransform/BgColor.php';
require 'HTMLPurifier/AttrTransform/BoolToCSS.php';
@@ -113,10 +117,15 @@ require 'HTMLPurifier/AttrTransform/Border.php';
require 'HTMLPurifier/AttrTransform/EnumToCSS.php';
require 'HTMLPurifier/AttrTransform/ImgRequired.php';
require 'HTMLPurifier/AttrTransform/ImgSpace.php';
require 'HTMLPurifier/AttrTransform/Input.php';
require 'HTMLPurifier/AttrTransform/Lang.php';
require 'HTMLPurifier/AttrTransform/Length.php';
require 'HTMLPurifier/AttrTransform/Name.php';
require 'HTMLPurifier/AttrTransform/SafeEmbed.php';
require 'HTMLPurifier/AttrTransform/SafeObject.php';
require 'HTMLPurifier/AttrTransform/SafeParam.php';
require 'HTMLPurifier/AttrTransform/ScriptRequired.php';
require 'HTMLPurifier/AttrTransform/Textarea.php';
require 'HTMLPurifier/ChildDef/Chameleon.php';
require 'HTMLPurifier/ChildDef/Custom.php';
require 'HTMLPurifier/ChildDef/Empty.php';
@@ -124,9 +133,6 @@ require 'HTMLPurifier/ChildDef/Required.php';
require 'HTMLPurifier/ChildDef/Optional.php';
require 'HTMLPurifier/ChildDef/StrictBlockquote.php';
require 'HTMLPurifier/ChildDef/Table.php';
require 'HTMLPurifier/ConfigDef/Directive.php';
require 'HTMLPurifier/ConfigDef/DirectiveAlias.php';
require 'HTMLPurifier/ConfigDef/Namespace.php';
require 'HTMLPurifier/DefinitionCache/Decorator.php';
require 'HTMLPurifier/DefinitionCache/Null.php';
require 'HTMLPurifier/DefinitionCache/Serializer.php';
@@ -135,15 +141,19 @@ require 'HTMLPurifier/DefinitionCache/Decorator/Memory.php';
require 'HTMLPurifier/HTMLModule/Bdo.php';
require 'HTMLPurifier/HTMLModule/CommonAttributes.php';
require 'HTMLPurifier/HTMLModule/Edit.php';
require 'HTMLPurifier/HTMLModule/Forms.php';
require 'HTMLPurifier/HTMLModule/Hypertext.php';
require 'HTMLPurifier/HTMLModule/Image.php';
require 'HTMLPurifier/HTMLModule/Legacy.php';
require 'HTMLPurifier/HTMLModule/List.php';
require 'HTMLPurifier/HTMLModule/Name.php';
require 'HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
require 'HTMLPurifier/HTMLModule/Object.php';
require 'HTMLPurifier/HTMLModule/Presentation.php';
require 'HTMLPurifier/HTMLModule/Proprietary.php';
require 'HTMLPurifier/HTMLModule/Ruby.php';
require 'HTMLPurifier/HTMLModule/SafeEmbed.php';
require 'HTMLPurifier/HTMLModule/SafeObject.php';
require 'HTMLPurifier/HTMLModule/Scripting.php';
require 'HTMLPurifier/HTMLModule/StyleAttribute.php';
require 'HTMLPurifier/HTMLModule/Tables.php';
@@ -151,14 +161,18 @@ require 'HTMLPurifier/HTMLModule/Target.php';
require 'HTMLPurifier/HTMLModule/Text.php';
require 'HTMLPurifier/HTMLModule/Tidy.php';
require 'HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
require 'HTMLPurifier/HTMLModule/Tidy/Name.php';
require 'HTMLPurifier/HTMLModule/Tidy/Proprietary.php';
require 'HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php';
require 'HTMLPurifier/HTMLModule/Tidy/Strict.php';
require 'HTMLPurifier/HTMLModule/Tidy/Transitional.php';
require 'HTMLPurifier/HTMLModule/Tidy/XHTML.php';
require 'HTMLPurifier/Injector/AutoParagraph.php';
require 'HTMLPurifier/Injector/DisplayLinkURI.php';
require 'HTMLPurifier/Injector/Linkify.php';
require 'HTMLPurifier/Injector/PurifierLinkify.php';
require 'HTMLPurifier/Injector/RemoveEmpty.php';
require 'HTMLPurifier/Injector/SafeObject.php';
require 'HTMLPurifier/Lexer/DOMLex.php';
require 'HTMLPurifier/Lexer/DirectLex.php';
require 'HTMLPurifier/Strategy/Composite.php';
@@ -179,6 +193,7 @@ require 'HTMLPurifier/URIFilter/DisableExternal.php';
require 'HTMLPurifier/URIFilter/DisableExternalResources.php';
require 'HTMLPurifier/URIFilter/HostBlacklist.php';
require 'HTMLPurifier/URIFilter/MakeAbsolute.php';
require 'HTMLPurifier/URIFilter/Munge.php';
require 'HTMLPurifier/URIScheme/ftp.php';
require 'HTMLPurifier/URIScheme/http.php';
require 'HTMLPurifier/URIScheme/https.php';

View File

@@ -19,7 +19,7 @@
*/
/*
HTML Purifier 3.1.0 - Standards Compliant HTML Filtering
HTML Purifier 3.2.0 - Standards Compliant HTML Filtering
Copyright (C) 2006-2008 Edward Z. Yang
This library is free software; you can redistribute it and/or
@@ -55,10 +55,10 @@ class HTMLPurifier
{
/** Version of HTML Purifier */
public $version = '3.1.0';
public $version = '3.2.0';
/** Constant with version of HTML Purifier */
const VERSION = '3.1.0';
const VERSION = '3.2.0';
/** Global configuration object */
public $config;

View File

@@ -23,7 +23,6 @@ require_once $__dir . '/HTMLPurifier/Definition.php';
require_once $__dir . '/HTMLPurifier/CSSDefinition.php';
require_once $__dir . '/HTMLPurifier/ChildDef.php';
require_once $__dir . '/HTMLPurifier/Config.php';
require_once $__dir . '/HTMLPurifier/ConfigDef.php';
require_once $__dir . '/HTMLPurifier/ConfigSchema.php';
require_once $__dir . '/HTMLPurifier/ContentSets.php';
require_once $__dir . '/HTMLPurifier/Context.php';
@@ -36,6 +35,7 @@ require_once $__dir . '/HTMLPurifier/Encoder.php';
require_once $__dir . '/HTMLPurifier/EntityLookup.php';
require_once $__dir . '/HTMLPurifier/EntityParser.php';
require_once $__dir . '/HTMLPurifier/ErrorCollector.php';
require_once $__dir . '/HTMLPurifier/ErrorStruct.php';
require_once $__dir . '/HTMLPurifier/Exception.php';
require_once $__dir . '/HTMLPurifier/Filter.php';
require_once $__dir . '/HTMLPurifier/Generator.php';
@@ -46,6 +46,7 @@ require_once $__dir . '/HTMLPurifier/IDAccumulator.php';
require_once $__dir . '/HTMLPurifier/Injector.php';
require_once $__dir . '/HTMLPurifier/Language.php';
require_once $__dir . '/HTMLPurifier/LanguageFactory.php';
require_once $__dir . '/HTMLPurifier/Length.php';
require_once $__dir . '/HTMLPurifier/Lexer.php';
require_once $__dir . '/HTMLPurifier/PercentEncoder.php';
require_once $__dir . '/HTMLPurifier/Strategy.php';
@@ -60,12 +61,14 @@ require_once $__dir . '/HTMLPurifier/URIFilter.php';
require_once $__dir . '/HTMLPurifier/URIParser.php';
require_once $__dir . '/HTMLPurifier/URIScheme.php';
require_once $__dir . '/HTMLPurifier/URISchemeRegistry.php';
require_once $__dir . '/HTMLPurifier/UnitConverter.php';
require_once $__dir . '/HTMLPurifier/VarParser.php';
require_once $__dir . '/HTMLPurifier/VarParserException.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Integer.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Lang.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Switch.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Text.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Number.php';
@@ -100,6 +103,7 @@ require_once $__dir . '/HTMLPurifier/AttrDef/URI/Host.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI/IPv4.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI/IPv6.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Background.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/BdoDir.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/BgColor.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/BoolToCSS.php';
@@ -107,10 +111,15 @@ require_once $__dir . '/HTMLPurifier/AttrTransform/Border.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/EnumToCSS.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ImgRequired.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ImgSpace.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Input.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/SafeEmbed.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeObject.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Textarea.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Custom.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Empty.php';
@@ -118,9 +127,6 @@ require_once $__dir . '/HTMLPurifier/ChildDef/Required.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Optional.php';
require_once $__dir . '/HTMLPurifier/ChildDef/StrictBlockquote.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Table.php';
require_once $__dir . '/HTMLPurifier/ConfigDef/Directive.php';
require_once $__dir . '/HTMLPurifier/ConfigDef/DirectiveAlias.php';
require_once $__dir . '/HTMLPurifier/ConfigDef/Namespace.php';
require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator.php';
require_once $__dir . '/HTMLPurifier/DefinitionCache/Null.php';
require_once $__dir . '/HTMLPurifier/DefinitionCache/Serializer.php';
@@ -129,15 +135,19 @@ require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator/Memory.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Bdo.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/CommonAttributes.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Edit.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Forms.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Hypertext.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Image.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Legacy.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/List.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Name.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Object.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Presentation.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Proprietary.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Ruby.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeEmbed.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeObject.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Scripting.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/StyleAttribute.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tables.php';
@@ -145,14 +155,18 @@ require_once $__dir . '/HTMLPurifier/HTMLModule/Target.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Text.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Name.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Proprietary.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Strict.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Transitional.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/XHTML.php';
require_once $__dir . '/HTMLPurifier/Injector/AutoParagraph.php';
require_once $__dir . '/HTMLPurifier/Injector/DisplayLinkURI.php';
require_once $__dir . '/HTMLPurifier/Injector/Linkify.php';
require_once $__dir . '/HTMLPurifier/Injector/PurifierLinkify.php';
require_once $__dir . '/HTMLPurifier/Injector/RemoveEmpty.php';
require_once $__dir . '/HTMLPurifier/Injector/SafeObject.php';
require_once $__dir . '/HTMLPurifier/Lexer/DOMLex.php';
require_once $__dir . '/HTMLPurifier/Lexer/DirectLex.php';
require_once $__dir . '/HTMLPurifier/Strategy/Composite.php';
@@ -173,6 +187,7 @@ require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternal.php';
require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternalResources.php';
require_once $__dir . '/HTMLPurifier/URIFilter/HostBlacklist.php';
require_once $__dir . '/HTMLPurifier/URIFilter/MakeAbsolute.php';
require_once $__dir . '/HTMLPurifier/URIFilter/Munge.php';
require_once $__dir . '/HTMLPurifier/URIScheme/ftp.php';
require_once $__dir . '/HTMLPurifier/URIScheme/http.php';
require_once $__dir . '/HTMLPurifier/URIScheme/https.php';

View File

@@ -51,16 +51,13 @@ abstract class HTMLPurifier_AttrDef
*
* @warning This processing is inconsistent with XML's whitespace handling
* as specified by section 3.3.3 and referenced XHTML 1.0 section
* 4.7. Compliant processing requires all line breaks normalized
* to "\n", so the fix is not as simple as fixing it in this
* function. Trim and whitespace collapsing are supposed to only
* occur in NMTOKENs. However, note that we are NOT necessarily
* parsing XML, thus, this behavior may still be correct.
* 4.7. However, note that we are NOT necessarily
* parsing XML, thus, this behavior may still be correct. We
* assume that newlines have been normalized.
*/
public function parseCDATA($string) {
$string = trim($string);
$string = str_replace("\n", '', $string);
$string = str_replace(array("\r", "\t"), ' ', $string);
$string = str_replace(array("\n", "\t", "\r"), ' ', $string);
return $string;
}

View File

@@ -29,6 +29,12 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
$declarations = explode(';', $css);
$propvalues = array();
/**
* Name of the current CSS property being validated.
*/
$property = false;
$context->register('CurrentCSSProperty', $property);
foreach ($declarations as $declaration) {
if (!$declaration) continue;
if (!strpos($declaration, ':')) continue;
@@ -61,6 +67,8 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
$propvalues[$property] = $result;
}
$context->destroy('CurrentCSSProperty');
// procedure does not write the new CSS simultaneously, so it's
// slightly inefficient, but it's the only way of getting rid of
// duplicates. Perhaps config to optimize it, but not now.

View File

@@ -16,7 +16,6 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
'cursive' => true
);
$string = $this->parseCDATA($string);
// assume that no font names contain commas in them
$fonts = explode(',', $string);
$final = '';
@@ -35,13 +34,40 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
$quote = $font[0];
if ($font[$length - 1] !== $quote) continue;
$font = substr($font, 1, $length - 2);
// double-backslash processing is buggy
$font = str_replace("\\$quote", $quote, $font); // de-escape quote
$font = str_replace("\\\n", "\n", $font); // de-escape newlines
$new_font = '';
for ($i = 0, $c = strlen($font); $i < $c; $i++) {
if ($font[$i] === '\\') {
$i++;
if ($i >= $c) {
$new_font .= '\\';
break;
}
if (ctype_xdigit($font[$i])) {
$code = $font[$i];
for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) {
if (!ctype_xdigit($font[$i])) break;
$code .= $font[$i];
}
// We have to be extremely careful when adding
// new characters, to make sure we're not breaking
// the encoding.
$char = HTMLPurifier_Encoder::unichr(hexdec($code));
if (HTMLPurifier_Encoder::cleanUTF8($char) === '') continue;
$new_font .= $char;
if ($i < $c && trim($font[$i]) !== '') $i--;
continue;
}
if ($font[$i] === "\n") continue;
}
$new_font .= $font[$i];
}
$font = $new_font;
}
// $font is a pure representation of the font name
if (ctype_alnum($font)) {
if (ctype_alnum($font) && $font !== '') {
// very simple font, allow it in unharmed
$final .= $font . ', ';
continue;
@@ -50,8 +76,8 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
// complicated font, requires quoting
// armor single quotes and new lines
$font = str_replace("\\", "\\\\", $font);
$font = str_replace("'", "\\'", $font);
$font = str_replace("\n", "\\\n", $font);
$final .= "'$font', ";
}
$final = rtrim($final, ', ');

View File

@@ -6,46 +6,40 @@
class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef
{
/**
* Valid unit lookup table.
* @warning The code assumes all units are two characters long. Be careful
* if we have to change this behavior!
*/
protected $units = array('em' => true, 'ex' => true, 'px' => true, 'in' => true,
'cm' => true, 'mm' => true, 'pt' => true, 'pc' => true);
/**
* Instance of HTMLPurifier_AttrDef_Number to defer number validation to
*/
protected $number_def;
protected $min, $max;
/**
* @param $non_negative Bool indication whether or not negative values are
* allowed.
* @param HTMLPurifier_Length $max Minimum length, or null for no bound. String is also acceptable.
* @param HTMLPurifier_Length $max Maximum length, or null for no bound. String is also acceptable.
*/
public function __construct($non_negative = false) {
$this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative);
public function __construct($min = null, $max = null) {
$this->min = $min !== null ? HTMLPurifier_Length::make($min) : null;
$this->max = $max !== null ? HTMLPurifier_Length::make($max) : null;
}
public function validate($length, $config, $context) {
public function validate($string, $config, $context) {
$string = $this->parseCDATA($string);
$length = $this->parseCDATA($length);
if ($length === '') return false;
if ($length === '0') return '0';
$strlen = strlen($length);
if ($strlen === 1) return false; // impossible!
// Optimizations
if ($string === '') return false;
if ($string === '0') return '0';
if (strlen($string) === 1) return false;
// we assume all units are two characters
$unit = substr($length, $strlen - 2);
if (!ctype_lower($unit)) $unit = strtolower($unit);
$number = substr($length, 0, $strlen - 2);
$length = HTMLPurifier_Length::make($string);
if (!$length->isValid()) return false;
if (!isset($this->units[$unit])) return false;
$number = $this->number_def->validate($number, $config, $context);
if ($number === false) return false;
return $number . $unit;
if ($this->min) {
$c = $length->compareTo($this->min);
if ($c === false) return false;
if ($c < 0) return false;
}
if ($this->max) {
$c = $length->compareTo($this->max);
if ($c === false) return false;
if ($c > 0) return false;
}
return $length->toString();
}
}

View File

@@ -18,6 +18,10 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
$this->non_negative = $non_negative;
}
/**
* @warning Some contexts do not pass $config, $context. These
* variables should not be used without checking HTMLPurifier_Length
*/
public function validate($number, $config, $context) {
$number = $this->parseCDATA($number);

View File

@@ -13,10 +13,13 @@ class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
static $allowed_values = array(
'line-through' => true,
'overline' => true,
'underline' => true
'underline' => true,
);
$string = strtolower($this->parseCDATA($string));
if ($string === 'none') return $string;
$parts = explode(' ', $string);
$final = '';
foreach ($parts as $part) {

View File

@@ -42,10 +42,7 @@ class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
}
if (empty($ret_lookup)) return false;
$ret_array = array();
foreach ($ret_lookup as $part => $bool) $ret_array[] = $part;
$string = implode(' ', $ret_array);
$string = implode(' ', array_keys($ret_lookup));
return $string;

View File

@@ -6,6 +6,12 @@
class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef
{
protected $max;
public function __construct($max = null) {
$this->max = $max;
}
public function validate($string, $config, $context) {
$string = trim($string);
@@ -24,11 +30,18 @@ class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef
// crash operating systems, see <http://ha.ckers.org/imagecrash.html>
// WARNING, above link WILL crash you if you're using Windows
if ($int > 1200) return '1200';
if ($this->max !== null && $int > $this->max) return (string) $this->max;
return (string) $int;
}
public function make($string) {
if ($string === '') $max = null;
else $max = (int) $string;
$class = get_class($this);
return new $class($max);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* Decorator that, depending on a token, switches between two definitions.
*/
class HTMLPurifier_AttrDef_Switch
{
protected $tag;
protected $withTag, $withoutTag;
/**
* @param string $tag Tag name to switch upon
* @param HTMLPurifier_AttrDef $with_tag Call if token matches tag
* @param HTMLPurifier_AttrDef $without_tag Call if token doesn't match, or there is no token
*/
public function __construct($tag, $with_tag, $without_tag) {
$this->tag = $tag;
$this->withTag = $with_tag;
$this->withoutTag = $without_tag;
}
public function validate($string, $config, $context) {
$token = $context->get('CurrentToken', true);
if (!$token || $token->name !== $this->tag) {
return $this->withoutTag->validate($string, $config, $context);
} else {
return $this->withTag->validate($string, $config, $context);
}
}
}

View File

@@ -18,6 +18,11 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
$this->embedsResource = (bool) $embeds_resource;
}
public function make($string) {
$embeds = (bool) $string;
return new HTMLPurifier_AttrDef_URI($embeds);
}
public function validate($uri, $config, $context) {
if ($config->get('URI', 'Disable')) return false;
@@ -50,6 +55,10 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
$result = $scheme_obj->validate($uri, $config, $context);
if (!$result) break;
// Post chained filtering
$result = $uri_def->postFilter($uri, $config, $context);
if (!$result) break;
// survived gauntlet
$ok = true;
@@ -59,18 +68,7 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
if (!$ok) return false;
// back to string
$result = $uri->toString();
// munge entire URI if necessary
if (
!is_null($uri->host) && // indicator for authority
!empty($scheme_obj->browsable) &&
!is_null($munge = $config->get('URI', 'Munge'))
) {
$result = str_replace('%s', rawurlencode($result), $munge);
}
return $result;
return $uri->toString();
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* Pre-transform that changes proprietary background attribute to CSS.
*/
class HTMLPurifier_AttrTransform_Background extends HTMLPurifier_AttrTransform {
public function transform($attr, $config, $context) {
if (!isset($attr['background'])) return $attr;
$background = $this->confiscateAttr($attr, 'background');
// some validation should happen here
$this->prependCSS($attr, "background-image:url($background);");
return $attr;
}
}

View File

@@ -22,7 +22,12 @@ class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
if (!isset($attr['alt'])) {
if ($src) {
$alt = $config->get('Attr', 'DefaultImageAlt');
if ($alt === null) {
$attr['alt'] = basename($attr['src']);
} else {
$attr['alt'] = $alt;
}
} else {
$attr['alt'] = $config->get('Attr', 'DefaultInvalidImageAlt');
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Performs miscellaneous cross attribute validation and filtering for
* input elements. This is meant to be a post-transform.
*/
class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform {
protected $pixels;
public function __construct() {
$this->pixels = new HTMLPurifier_AttrDef_HTML_Pixels();
}
public function transform($attr, $config, $context) {
if (!isset($attr['type'])) $t = 'text';
else $t = strtolower($attr['type']);
if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') {
unset($attr['checked']);
}
if (isset($attr['maxlength']) && $t !== 'text' && $t !== 'password') {
unset($attr['maxlength']);
}
if (isset($attr['size']) && $t !== 'text' && $t !== 'password') {
$result = $this->pixels->validate($attr['size'], $config, $context);
if ($result === false) unset($attr['size']);
else $attr['size'] = $result;
}
if (isset($attr['src']) && $t !== 'image') {
unset($attr['src']);
}
if (!isset($attr['value']) && ($t === 'radio' || $t === 'checkbox')) {
$attr['value'] = '';
}
return $attr;
}
}

View File

@@ -0,0 +1,13 @@
<?php
class HTMLPurifier_AttrTransform_SafeEmbed extends HTMLPurifier_AttrTransform
{
public $name = "SafeEmbed";
public function transform($attr, $config, $context) {
$attr['allowscriptaccess'] = 'never';
$attr['allownetworking'] = 'internal';
$attr['type'] = 'application/x-shockwave-flash';
return $attr;
}
}

View File

@@ -0,0 +1,14 @@
<?php
/**
* Writes default type for all objects. Currently only supports flash.
*/
class HTMLPurifier_AttrTransform_SafeObject extends HTMLPurifier_AttrTransform
{
public $name = "SafeObject";
function transform($attr, $config, $context) {
if (!isset($attr['type'])) $attr['type'] = 'application/x-shockwave-flash';
return $attr;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/**
* Validates name/value pairs in param tags to be used in safe objects. This
* will only allow name values it recognizes, and pre-fill certain attributes
* with required values.
*
* @note
* This class only supports Flash. In the future, Quicktime support
* may be added.
*
* @warning
* This class expects an injector to add the necessary parameters tags.
*/
class HTMLPurifier_AttrTransform_SafeParam extends HTMLPurifier_AttrTransform
{
public $name = "SafeParam";
private $uri;
public function __construct() {
$this->uri = new HTMLPurifier_AttrDef_URI(true); // embedded
}
public function transform($attr, $config, $context) {
// If we add support for other objects, we'll need to alter the
// transforms.
switch ($attr['name']) {
// application/x-shockwave-flash
// Keep this synchronized with Injector/SafeObject.php
case 'allowScriptAccess':
$attr['value'] = 'never';
break;
case 'allowNetworking':
$attr['value'] = 'internal';
break;
case 'wmode':
$attr['value'] = 'window';
break;
case 'movie':
$attr['value'] = $this->uri->validate($attr['value'], $config, $context);
break;
// add other cases to support other param name/value pairs
default:
$attr['name'] = $attr['value'] = null;
}
return $attr;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Sets height/width defaults for <textarea>
*/
class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) {
// Calculated from Firefox
if (!isset($attr['cols'])) $attr['cols'] = '22';
if (!isset($attr['rows'])) $attr['rows'] = '3';
return $attr;
}
}

View File

@@ -32,6 +32,9 @@ class HTMLPurifier_AttrTypes
// unimplemented aliases
$this->info['ContentType'] = new HTMLPurifier_AttrDef_Text();
$this->info['ContentTypes'] = new HTMLPurifier_AttrDef_Text();
$this->info['Charsets'] = new HTMLPurifier_AttrDef_Text();
$this->info['Character'] = new HTMLPurifier_AttrDef_Text();
// number is really a positive integer (one or more digits)
// FIXME: ^^ not always, see start and value of list items

View File

@@ -43,21 +43,25 @@ class HTMLPurifier_AttrValidator
// DEFINITION CALL
$d_defs = $definition->info_global_attr;
// reference attributes for easy manipulation
$attr =& $token->attr;
// don't update token until the very end, to ensure an atomic update
$attr = $token->attr;
// do global transformations (pre)
// nothing currently utilizes this
foreach ($definition->info_attr_transform_pre as $transform) {
$attr = $transform->transform($o = $attr, $config, $context);
if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
if ($e) {
if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
}
}
// do local transformations only applicable to this element (pre)
// ex. <p align="right"> to <p style="text-align:right;">
foreach ($definition->info[$token->name]->attr_transform_pre as $transform) {
$attr = $transform->transform($o = $attr, $config, $context);
if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
if ($e) {
if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
}
}
// create alias to this element's attribute definition array, see
@@ -114,6 +118,8 @@ class HTMLPurifier_AttrValidator
// simple substitution
$attr[$attr_key] = $result;
} else {
// nothing happens
}
// we'd also want slightly more complicated substitution
@@ -130,14 +136,20 @@ class HTMLPurifier_AttrValidator
// global (error reporting untested)
foreach ($definition->info_attr_transform_post as $transform) {
$attr = $transform->transform($o = $attr, $config, $context);
if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
if ($e) {
if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
}
}
// local (error reporting untested)
foreach ($definition->info[$token->name]->attr_transform_post as $transform) {
$attr = $transform->transform($o = $attr, $config, $context);
if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
if ($e) {
if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
}
}
$token->attr = $attr;
// destroy CurrentToken if we made it ourselves
if (!$current_token) $context->destroy('CurrentToken');

View File

@@ -90,7 +90,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['border-left-width'] =
$this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')),
new HTMLPurifier_AttrDef_CSS_Length(true) //disallow negative
new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative
));
$this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width);
@@ -116,7 +116,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
new HTMLPurifier_AttrDef_Enum(array('normal')),
new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives
new HTMLPurifier_AttrDef_CSS_Length(true),
new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true)
));
@@ -138,7 +138,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['padding-bottom'] =
$this->info['padding-left'] =
$this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
new HTMLPurifier_AttrDef_CSS_Length(true),
new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true)
));
@@ -149,14 +149,26 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
new HTMLPurifier_AttrDef_CSS_Percentage()
));
$this->info['width'] =
$this->info['height'] =
new HTMLPurifier_AttrDef_CSS_DenyElementDecorator(
new HTMLPurifier_AttrDef_CSS_Composite(array(
new HTMLPurifier_AttrDef_CSS_Length(true),
$trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(array(
new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true),
new HTMLPurifier_AttrDef_Enum(array('auto'))
)), 'img');
));
$max = $config->get('CSS', 'MaxImgLength');
$this->info['width'] =
$this->info['height'] =
$max === null ?
$trusted_wh :
new HTMLPurifier_AttrDef_Switch('img',
// For img tags:
new HTMLPurifier_AttrDef_CSS_Composite(array(
new HTMLPurifier_AttrDef_CSS_Length('0', $max),
new HTMLPurifier_AttrDef_Enum(array('auto'))
)),
// For everyone else:
$trusted_wh
);
$this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();

View File

@@ -24,6 +24,14 @@ abstract class HTMLPurifier_ChildDef
*/
public $elements = array();
/**
* Get lookup of tag names that should not close this element automatically.
* All other elements will do so.
*/
public function getNonAutoCloseElements($config) {
return $this->elements;
}
/**
* Validates nodes according to definition and returns modification.
*

View File

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

View File

@@ -55,10 +55,7 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
$escape_invalid_children = $config->get('Core', 'EscapeInvalidChildren');
// generator
static $gen = null;
if ($gen === null) {
$gen = new HTMLPurifier_Generator();
}
$gen = new HTMLPurifier_Generator($config, $context);
foreach ($tokens_of_children as $token) {
if (!empty($token->is_whitespace)) {
@@ -83,7 +80,7 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
$result[] = $token;
} elseif ($pcdata_allowed && $escape_invalid_children) {
$result[] = new HTMLPurifier_Token_Text(
$gen->generateFromToken($token, $config)
$gen->generateFromToken($token)
);
}
continue;
@@ -94,7 +91,7 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
} elseif ($pcdata_allowed && $escape_invalid_children) {
$result[] =
new HTMLPurifier_Token_Text(
$gen->generateFromToken( $token, $config )
$gen->generateFromToken($token)
);
} else {
// drop silently

View File

@@ -10,16 +10,19 @@ class HTMLPurifier_ChildDef_StrictBlockquote extends HTMLPurifier_ChildDef_Requi
public $allow_empty = true;
public $type = 'strictblockquote';
protected $init = false;
/**
* @note We don't want MakeWellFormed to auto-close inline elements since
* they might be allowed.
*/
public function getNonAutoCloseElements($config) {
$this->init($config);
return $this->fake_elements;
}
public function validateChildren($tokens_of_children, $config, $context) {
$def = $config->getHTMLDefinition();
if (!$this->init) {
// allow all inline elements
$this->real_elements = $this->elements;
$this->fake_elements = $def->info_content_sets['Flow'];
$this->fake_elements['#PCDATA'] = true;
$this->init = true;
}
$this->init($config);
// trick the parent class into thinking it allows more
$this->elements = $this->fake_elements;
@@ -29,6 +32,7 @@ class HTMLPurifier_ChildDef_StrictBlockquote extends HTMLPurifier_ChildDef_Requi
if ($result === false) return array();
if ($result === true) $result = $tokens_of_children;
$def = $config->getHTMLDefinition();
$block_wrap_start = new HTMLPurifier_Token_Start($def->info_block_wrapper);
$block_wrap_end = new HTMLPurifier_Token_End( $def->info_block_wrapper);
$is_inline = false;
@@ -68,5 +72,16 @@ class HTMLPurifier_ChildDef_StrictBlockquote extends HTMLPurifier_ChildDef_Requi
if ($is_inline) $ret[] = $block_wrap_end;
return $ret;
}
private function init($config) {
if (!$this->init) {
$def = $config->getHTMLDefinition();
// allow all inline elements
$this->real_elements = $this->elements;
$this->fake_elements = $def->info_content_sets['Flow'];
$this->fake_elements['#PCDATA'] = true;
$this->init = true;
}
}
}

View File

@@ -20,7 +20,7 @@ class HTMLPurifier_Config
/**
* HTML Purifier's version
*/
public $version = '3.1.0';
public $version = '3.2.0';
/**
* Bool indicator whether or not to automatically finalize
@@ -125,7 +125,7 @@ class HTMLPurifier_Config
E_USER_WARNING);
return;
}
if ($this->def->info[$namespace][$key]->class == 'alias') {
if (isset($this->def->info[$namespace][$key]->isAlias)) {
$d = $this->def->info[$namespace][$key];
trigger_error('Cannot get value from aliased directive, use real name ' . $d->namespace . '.' . $d->name,
E_USER_ERROR);
@@ -196,42 +196,50 @@ class HTMLPurifier_Config
E_USER_WARNING);
return;
}
if ($this->def->info[$namespace][$key]->class == 'alias') {
$def = $this->def->info[$namespace][$key];
if (isset($def->isAlias)) {
if ($from_alias) {
trigger_error('Double-aliases not allowed, please fix '.
'ConfigSchema bug with' . "$namespace.$key", E_USER_ERROR);
return;
}
$this->set($new_ns = $this->def->info[$namespace][$key]->namespace,
$new_dir = $this->def->info[$namespace][$key]->name,
$this->set($new_ns = $def->namespace,
$new_dir = $def->name,
$value, true);
trigger_error("$namespace.$key is an alias, preferred directive name is $new_ns.$new_dir", E_USER_NOTICE);
return;
}
// Raw type might be negative when using the fully optimized form
// of stdclass, which indicates allow_null == true
$rtype = is_int($def) ? $def : $def->type;
if ($rtype < 0) {
$type = -$rtype;
$allow_null = true;
} else {
$type = $rtype;
$allow_null = isset($def->allow_null);
}
try {
$value = $this->parser->parse(
$value,
$type = $this->def->info[$namespace][$key]->type,
$this->def->info[$namespace][$key]->allow_null
);
$value = $this->parser->parse($value, $type, $allow_null);
} catch (HTMLPurifier_VarParserException $e) {
trigger_error('Value for ' . "$namespace.$key" . ' is of invalid type, should be ' . $type, E_USER_WARNING);
trigger_error('Value for ' . "$namespace.$key" . ' is of invalid type, should be ' . HTMLPurifier_VarParser::getTypeName($type), E_USER_WARNING);
return;
}
if (is_string($value)) {
if (is_string($value) && is_object($def)) {
// resolve value alias if defined
if (isset($this->def->info[$namespace][$key]->aliases[$value])) {
$value = $this->def->info[$namespace][$key]->aliases[$value];
if (isset($def->aliases[$value])) {
$value = $def->aliases[$value];
}
if ($this->def->info[$namespace][$key]->allowed !== true) {
// check to see if the value is allowed
if (!isset($this->def->info[$namespace][$key]->allowed[$value])) {
if (isset($def->allowed) && !isset($def->allowed[$value])) {
trigger_error('Value not supported, valid values are: ' .
$this->_listify($this->def->info[$namespace][$key]->allowed), E_USER_WARNING);
$this->_listify($def->allowed), E_USER_WARNING);
return;
}
}
}
$this->conf[$namespace][$key] = $value;
// reset definitions if the directives they depend on changed
@@ -386,7 +394,7 @@ class HTMLPurifier_Config
if (isset($blacklisted_directives["$ns.$directive"])) continue;
if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue;
}
if ($def->class == 'alias') continue;
if (isset($def->isAlias)) continue;
if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue;
$ret[] = array($ns, $directive);
}

View File

@@ -1,9 +0,0 @@
<?php
/**
* Base class for configuration entity
*/
abstract class HTMLPurifier_ConfigDef {
public $class = false;
}

View File

@@ -1,55 +0,0 @@
<?php
/**
* Structure object containing definition of a directive.
* @note This structure does not contain default values
*/
class HTMLPurifier_ConfigDef_Directive extends HTMLPurifier_ConfigDef
{
public $class = 'directive';
public function __construct(
$type = null,
$allow_null = null,
$allowed = null,
$aliases = null
) {
if ( $type !== null) $this->type = $type;
if ( $allow_null !== null) $this->allow_null = $allow_null;
if ( $allowed !== null) $this->allowed = $allowed;
if ( $aliases !== null) $this->aliases = $aliases;
}
/**
* Allowed type of the directive. Values are:
* - string
* - istring (case insensitive string)
* - int
* - float
* - bool
* - lookup (array of value => true)
* - list (regular numbered index array)
* - hash (array of key => value)
* - mixed (anything goes)
*/
public $type = 'mixed';
/**
* Is null allowed? Has no effect for mixed type.
* @bool
*/
public $allow_null = false;
/**
* Lookup table of allowed values of the element, bool true if all allowed.
*/
public $allowed = true;
/**
* Hash of value aliases, i.e. values that are equivalent.
*/
public $aliases = array();
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Structure object describing a directive alias
*/
class HTMLPurifier_ConfigDef_DirectiveAlias extends HTMLPurifier_ConfigDef
{
public $class = 'alias';
/**
* Namespace being aliased to
*/
public $namespace;
/**
* Directive being aliased to
*/
public $name;
public function __construct($namespace, $name) {
$this->namespace = $namespace;
$this->name = $name;
}
}

View File

@@ -1,10 +0,0 @@
<?php
/**
* Structure object describing of a namespace
*/
class HTMLPurifier_ConfigDef_Namespace extends HTMLPurifier_ConfigDef
{
public $class = 'namespace';
}

View File

@@ -12,7 +12,33 @@ class HTMLPurifier_ConfigSchema {
public $defaults = array();
/**
* Definition of the directives.
* Definition of the directives. The structure of this is:
*
* array(
* 'Namespace' => array(
* 'Directive' => new stdclass(),
* )
* )
*
* The stdclass may have the following properties:
*
* - If isAlias isn't set:
* - type: Integer type of directive, see HTMLPurifier_VarParser for definitions
* - allow_null: If set, this directive allows null values
* - aliases: If set, an associative array of value aliases to real values
* - allowed: If set, a lookup array of allowed (string) values
* - If isAlias is set:
* - namespace: Namespace this directive aliases to
* - name: Directive name this directive aliases to
*
* In certain degenerate cases, stdclass will actually be an integer. In
* that case, the value is equivalent to an stdclass with the type
* property set to the integer. If the integer is negative, type is
* equal to the absolute value of integer, and allow_null is true.
*
* This class is friendly with HTMLPurifier_Config. If you need introspection
* about the schema, you're better of using the ConfigSchema_Interchange,
* which uses more memory but has much richer information.
*/
public $info = array();
@@ -21,15 +47,6 @@ class HTMLPurifier_ConfigSchema {
*/
static protected $singleton;
/**
* Variable parser.
*/
protected $parser;
public function __construct() {
$this->parser = new HTMLPurifier_VarParser_Flexible();
}
/**
* Unserializes the default ConfigSchema.
*/
@@ -62,10 +79,10 @@ class HTMLPurifier_ConfigSchema {
* @param $allow_null Whether or not to allow null values
*/
public function add($namespace, $name, $default, $type, $allow_null) {
$default = $this->parser->parse($default, $type, $allow_null);
$this->info[$namespace][$name] = new HTMLPurifier_ConfigDef_Directive();
$this->info[$namespace][$name]->type = $type;
$this->info[$namespace][$name]->allow_null = $allow_null;
$obj = new stdclass();
$obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type];
if ($allow_null) $obj->allow_null = true;
$this->info[$namespace][$name] = $obj;
$this->defaults[$namespace][$name] = $default;
}
@@ -90,6 +107,9 @@ class HTMLPurifier_ConfigSchema {
* @param $aliases Hash of aliased values to the real alias
*/
public function addValueAliases($namespace, $name, $aliases) {
if (!isset($this->info[$namespace][$name]->aliases)) {
$this->info[$namespace][$name]->aliases = array();
}
foreach ($aliases as $alias => $real) {
$this->info[$namespace][$name]->aliases[$alias] = $real;
}
@@ -104,7 +124,6 @@ class HTMLPurifier_ConfigSchema {
* @param $allowed Lookup array of allowed values
*/
public function addAllowedValues($namespace, $name, $allowed) {
$type = $this->info[$namespace][$name]->type;
$this->info[$namespace][$name]->allowed = $allowed;
}
@@ -116,7 +135,26 @@ class HTMLPurifier_ConfigSchema {
* @param $new_name Directive that the alias will be to
*/
public function addAlias($namespace, $name, $new_namespace, $new_name) {
$this->info[$namespace][$name] = new HTMLPurifier_ConfigDef_DirectiveAlias($new_namespace, $new_name);
$obj = new stdclass;
$obj->namespace = $new_namespace;
$obj->name = $new_name;
$obj->isAlias = true;
$this->info[$namespace][$name] = $obj;
}
/**
* Replaces any stdclass that only has the type property with type integer.
*/
public function postProcess() {
foreach ($this->info as $namespace => $info) {
foreach ($info as $directive => $v) {
if (count((array) $v) == 1) {
$this->info[$namespace][$directive] = $v->type;
} elseif (count((array) $v) == 2 && isset($v->allow_null)) {
$this->info[$namespace][$directive] = -$v->type;
}
}
}
}
// DEPRECATED METHODS
@@ -124,7 +162,6 @@ class HTMLPurifier_ConfigSchema {
/** @see HTMLPurifier_ConfigSchema->set() */
public static function define($namespace, $name, $default, $type, $description) {
HTMLPurifier_ConfigSchema::deprecated(__METHOD__);
// process modifiers (OPTIMIZE!)
$type_values = explode('/', $type, 2);
$type = $type_values[0];
$modifier = isset($type_values[1]) ? $type_values[1] : false;
@@ -168,7 +205,8 @@ class HTMLPurifier_ConfigSchema {
/** @deprecated, use HTMLPurifier_VarParser->parse() */
public function validate($a, $b, $c = false) {
trigger_error("HTMLPurifier_ConfigSchema->validate deprecated, use HTMLPurifier_VarParser->parse instead", E_USER_NOTICE);
return $this->parser->parse($a, $b, $c);
$parser = new HTMLPurifier_VarParser();
return $parser->parse($a, $b, $c);
}
/**

View File

@@ -43,6 +43,7 @@ class HTMLPurifier_ConfigSchema_Builder_ConfigSchema
);
}
}
$schema->postProcess();
return $schema;
}

View File

@@ -111,7 +111,8 @@ class HTMLPurifier_ConfigSchema_Validator
if (!is_null($d->allowed) || !empty($d->valueAliases)) {
// allowed and valueAliases require that we be dealing with
// strings, so check for that early.
if (!isset(HTMLPurifier_VarParser::$stringTypes[$d->type])) {
$d_int = HTMLPurifier_VarParser::$types[$d->type];
if (!isset(HTMLPurifier_VarParser::$stringTypes[$d_int])) {
$this->error('type', 'must be a string type when used with allowed or value aliases');
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
Attr.DefaultImageAlt
TYPE: string/null
DEFAULT: null
--DESCRIPTION--
This is the content of the alt tag of an image if the user had not
previously specified an alt attribute. This applies to all images without
a valid alt attribute, as opposed to %Attr.DefaultInvalidImageAlt, which
only applies to invalid images, and overrides in the case of an invalid image.
Default behavior with null is to use the basename of the src tag for the alt.

View File

@@ -0,0 +1,10 @@
AutoFormat.DisplayLinkURI
TYPE: bool
VERSION: 3.2.0
DEFAULT: false
--DESCRIPTION--
<p>
This directive turns on the in-text display of URIs in &lt;a&gt; tags, and disables
those links. For example, <a href="http://example.com">example</a> becomes
example (<a>http://example.com</a>).
</p>

View File

@@ -0,0 +1,44 @@
AutoFormat.RemoveEmpty
TYPE: bool
VERSION: 3.2.0
DEFAULT: false
--DESCRIPTION--
<p>
When enabled, HTML Purifier will attempt to remove empty elements that
contribute no semantic information to the document. The following types
of nodes will be removed:
</p>
<ul><li>
Tags with no attributes and no content, and that are not empty
elements (remove <code>&lt;a&gt;&lt;/a&gt;</code> but not
<code>&lt;br /&gt;</code>), and
</li>
<li>
Tags with no content, except for:<ul>
<li>The <code>colgroup</code> element, or</li>
<li>
Elements with the <code>id</code> or <code>name</code> attribute,
when those attributes are permitted on those elements.
</li>
</ul></li>
</ul>
<p>
Please be very careful when using this functionality; while it may not
seem that empty elements contain useful information, they can alter the
layout of a document given appropriate styling. This directive is most
useful when you are processing machine-generated HTML, please avoid using
it on regular user HTML.
</p>
<p>
Elements that contain only whitespace will be treated as empty. Non-breaking
spaces, however, do not count as whitespace.
</p>
<p>
This algorithm is not perfect; you may still notice some empty tags,
particularly if a node had elements, but those elements were later removed
because they were not permitted in that context, or tags that, after
being auto-closed by another tag, where empty. This is for safety reasons
to prevent clever code from breaking validation. The general rule of thumb:
if a tag looked empty on the way end, it will get removed; if HTML Purifier
made it empty, it will stay.
</p>

View File

@@ -0,0 +1,15 @@
CSS.MaxImgLength
TYPE: string/null
DEFAULT: '1200px'
VERSION: 3.1.1
--DESCRIPTION--
<p>
This parameter sets the maximum allowed length on <code>img</code> tags,
effectively the <code>width</code> and <code>height</code> properties.
Only absolute units of measurement (in, pt, pc, mm, cm) and pixels (px) are allowed. This is
in place to prevent imagecrash attacks, disable with null at your own risk.
This directive is similar to %HTML.MaxImgLength, and both should be
concurrently edited, although there are
subtle differences in the input format (the CSS max is a number with
a unit).
</p>

View File

@@ -1,13 +1,17 @@
Core.AggressivelyFixLt
TYPE: bool
VERSION: 2.1.0
DEFAULT: false
DEFAULT: true
--DESCRIPTION--
<p>
This directive enables aggressive pre-filter fixes HTML Purifier can
perform in order to ensure that open angled-brackets do not get killed
during parsing stage. Enabling this will result in two preg_replace_callback
calls and one preg_replace call for every bit of HTML passed through here.
It is not necessary and will have no effect for PHP 4.
calls and at least two preg_replace calls for every HTML document parsed;
if your users make very well-formed HTML, you can set this directive false.
This has no effect when DirectLex is used.
</p>
<p>
<strong>Notice:</strong> This directive's default turned from false to true
in HTML Purifier 3.2.0.
</p>

View File

@@ -14,13 +14,49 @@ EXTERNAL: CSSTidy
<p>
Sample usage:
</p>
<pre><![CDATA[$config = HTMLPurifier_Config::createDefault();
<pre><![CDATA[
<?php
header('Content-type: text/html; charset=utf-8');
echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Filter.ExtractStyleBlocks</title>
<?php
require_once '/path/to/library/HTMLPurifier.auto.php';
require_once '/path/to/csstidy.class.php';
$dirty = '<style>body {color:#F00;}</style> Some text';
$config = HTMLPurifier_Config::createDefault();
$config->set('Filter', 'ExtractStyleBlocks', true);
$purifier = new HTMLPurifier($config);
$html = $purifier->purify($dirty);
// This implementation writes the stylesheets to the styles/ directory.
// You can also echo the styles inside the document, but it's a bit
// more difficult to make sure they get interpreted properly by
// browsers; try the usual CSS armoring techniques.
$styles = $purifier->context->get('StyleBlocks');
foreach ($styles as $style) {
echo '<style type="text/css">' . $style . "</style>\n";
}]]></pre>
$dir = 'styles/';
if (!is_dir($dir)) mkdir($dir);
$hash = sha1($_GET['html']);
foreach ($styles as $i => $style) {
file_put_contents($name = $dir . $hash . "_$i");
echo '<link rel="stylesheet" type="text/css" href="'.$name.'" />';
}
?>
</head>
<body>
<div>
<?php echo $html; ?>
</div>
</b]]><![CDATA[ody>
</html>
]]></pre>
<p>
<strong>Warning:</strong> It is possible for a user to mount an
imagecrash attack using this CSS. Counter-measures are difficult;

View File

@@ -0,0 +1,13 @@
HTML.MaxImgLength
TYPE: int/null
DEFAULT: 1200
VERSION: 3.1.1
--DESCRIPTION--
<p>
This directive controls the maximum number of pixels in the width and
height attributes in <code>img</code> tags. This is
in place to prevent imagecrash attacks, disable with null at your own risk.
This directive is similar to %CSS.MaxImgLength, and both should be
concurrently edited, although there are
subtle differences in the input format (the HTML max is an integer).
</p>

View File

@@ -0,0 +1,13 @@
HTML.SafeEmbed
TYPE: bool
VERSION: 3.1.1
DEFAULT: false
--DESCRIPTION--
<p>
Whether or not to permit embed tags in documents, with a number of extra
security features added to prevent script execution. This is similar to
what websites like MySpace do to embed tags. Embed is a proprietary
element and will cause your website to stop validating. You probably want
to enable this with %HTML.SafeObject.
<strong>Highly experimental.</strong>
</p>

View File

@@ -0,0 +1,13 @@
HTML.SafeObject
TYPE: bool
VERSION: 3.1.1
DEFAULT: false
--DESCRIPTION--
<p>
Whether or not to permit object tags in documents, with a number of extra
security features added to prevent script execution. This is similar to
what websites like MySpace do to object tags. You may also want to
enable %HTML.SafeEmbed for maximum interoperability with Internet Explorer,
although embed tags will cause your website to stop validating.
<strong>Highly experimental.</strong>
</p>

View File

@@ -0,0 +1,13 @@
Output.SortAttr
TYPE: bool
VERSION: 3.2.0
DEFAULT: false
--DESCRIPTION--
<p>
If true, HTML Purifier will sort attributes by name before writing them back
to the document, converting a tag like: <code>&lt;el b="" a="" c="" /&gt;</code>
to <code>&lt;el a="" b="" c="" /&gt;</code>. This is a workaround for
a bug in FCKeditor which causes it to swap attributes order, adding noise
to text diffs. If you're not seeing this bug, chances are, you don't need
this directive.
</p>

View File

@@ -6,7 +6,7 @@ DEFAULT: NULL
<p>
Munges all browsable (usually http, https and ftp)
absolute URI's into another URI, usually a URI redirection service.
absolute URIs into another URI, usually a URI redirection service.
This directive accepts a URI, formatted with a <code>%s</code> where
the url-encoded original URI should be inserted (sample:
<code>http://www.google.com/url?q=%s</code>).
@@ -19,13 +19,64 @@ DEFAULT: NULL
Prevent PageRank leaks, while being fairly transparent
to users (you may also want to add some client side JavaScript to
override the text in the statusbar). <strong>Notice</strong>:
Many security experts believe that this form of protection does
not deter spam-bots.
Many security experts believe that this form of protection does not deter spam-bots.
</li>
<li>
Redirect users to a splash page telling them they are leaving your
website. While this is poor usability practice, it is often
mandated
website. While this is poor usability practice, it is often mandated
in corporate environments.
</li>
</ul>
<p>
Prior to HTML Purifier 3.1.1, this directive also enabled the munging
of browsable external resources, which could break things if your redirection
script was a splash page or used <code>meta</code> tags. To revert to
previous behavior, please use %URI.MungeResources.
</p>
<p>
You may want to also use %URI.MungeSecretKey along with this directive
in order to enforce what URIs your redirector script allows. Open
redirector scripts can be a security risk and negatively affect the
reputation of your domain name.
</p>
<p>
Starting with HTML Purifier 3.1.1, there is also these substitutions:
</p>
<table>
<thead>
<tr>
<th>Key</th>
<th>Description</th>
<th>Example <code>&lt;a href=""&gt;</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>%r</td>
<td>1 - The URI embeds a resource<br />(blank) - The URI is merely a link</td>
<td></td>
</tr>
<tr>
<td>%n</td>
<td>The name of the tag this URI came from</td>
<td>a</td>
</tr>
<tr>
<td>%m</td>
<td>The name of the attribute this URI came from</td>
<td>href</td>
</tr>
<tr>
<td>%p</td>
<td>The name of the CSS property this URI came from, or blank if irrelevant</td>
<td></td>
</tr>
</tbody>
</table>
<p>
Admittedly, these letters are somewhat arbitrary; the only stipulation
was that they couldn't be a through f. r is for resource (I would have preferred
e, but you take what you can get), n is for name, m
was picked because it came after n (and I couldn't use a), p is for
property.
</p>

View File

@@ -0,0 +1,16 @@
URI.MungeResources
TYPE: bool
VERSION: 3.1.1
DEFAULT: false
--DESCRIPTION--
<p>
If true, any URI munging directives like %URI.Munge
will also apply to embedded resources, such as <code>&lt;img src=""&gt;</code>.
Be careful enabling this directive if you have a redirector script
that does not use the <code>Location</code> HTTP header; all of your images
and other embedded resources will break.
</p>
<p>
<strong>Warning:</strong> It is strongly advised you use this in conjunction
%URI.MungeSecretKey to mitigate the security risk of an open redirector.
</p>

View File

@@ -0,0 +1,29 @@
URI.MungeSecretKey
TYPE: string/null
VERSION: 3.1.1
DEFAULT: NULL
--DESCRIPTION--
<p>
This directive enables secure checksum generation along with %URI.Munge.
It should be set to a secure key that is not shared with anyone else.
The checksum can be placed in the URI using %t. Use of this checksum
affords an additional level of protection by allowing a redirector
to check if a URI has passed through HTML Purifier with this line:
</p>
<pre>$checksum === sha1($secret_key . ':' . $url)</pre>
<p>
If the output is TRUE, the redirector script should accept the URI.
</p>
<p>
Please note that it would still be possible for an attacker to procure
secure hashes en-mass by abusing your website's Preview feature or the
like, but this service affords an additional level of protection
that should be combined with website blacklisting.
</p>
<p>
Remember this has no effect if %URI.Munge is not on.
</p>

View File

@@ -37,33 +37,35 @@ class HTMLPurifier_ContentSets
// sorry, no way of overloading
foreach ($modules as $module_i => $module) {
foreach ($module->content_sets as $key => $value) {
if (isset($this->info[$key])) {
$temp = $this->convertToLookup($value);
if (isset($this->lookup[$key])) {
// add it into the existing content set
$this->info[$key] = $this->info[$key] . ' | ' . $value;
$this->lookup[$key] = array_merge($this->lookup[$key], $temp);
} else {
$this->info[$key] = $value;
$this->lookup[$key] = $temp;
}
}
}
// perform content_set expansions
$this->keys = array_keys($this->info);
foreach ($this->info as $i => $set) {
// only performed once, so infinite recursion is not
// a problem
$this->info[$i] =
str_replace(
$this->keys,
// must be recalculated each time due to
// changing substitutions
array_values($this->info),
$set);
$old_lookup = false;
while ($old_lookup !== $this->lookup) {
$old_lookup = $this->lookup;
foreach ($this->lookup as $i => $set) {
$add = array();
foreach ($set as $element => $x) {
if (isset($this->lookup[$element])) {
$add += $this->lookup[$element];
unset($this->lookup[$i][$element]);
}
}
$this->lookup[$i] += $add;
}
}
$this->values = array_values($this->info);
// generate lookup tables
foreach ($this->info as $name => $set) {
$this->lookup[$name] = $this->convertToLookup($set);
foreach ($this->lookup as $key => $lookup) {
$this->info[$key] = implode(' | ', array_keys($lookup));
}
$this->keys = array_keys($this->info);
$this->values = array_values($this->info);
}
/**
@@ -75,12 +77,22 @@ class HTMLPurifier_ContentSets
if (!empty($def->child)) return; // already done!
$content_model = $def->content_model;
if (is_string($content_model)) {
$def->content_model = str_replace(
$this->keys, $this->values, $content_model);
// Assume that $this->keys is alphanumeric
$def->content_model = preg_replace_callback(
'/\b(' . implode('|', $this->keys) . ')\b/',
array($this, 'generateChildDefCallback'),
$content_model
);
//$def->content_model = str_replace(
// $this->keys, $this->values, $content_model);
}
$def->child = $this->getChildDef($def, $module);
}
public function generateChildDefCallback($matches) {
return $this->info[$matches[0]];
}
/**
* Instantiates a ChildDef based on content_model and content_model_type
* member variables in HTMLPurifier_ElementDef

View File

@@ -0,0 +1 @@
This is a dummy file to prevent Git from ignoring this empty directory.

View File

@@ -46,35 +46,13 @@ class HTMLPurifier_Encoder
*/
public static function cleanUTF8($str, $force_php = false) {
static $non_sgml_chars = array();
if (empty($non_sgml_chars)) {
for ($i = 0; $i <= 31; $i++) {
// non-SGML ASCII chars
// save \r, \t and \n
if ($i == 9 || $i == 13 || $i == 10) continue;
$non_sgml_chars[chr($i)] = '';
}
for ($i = 127; $i <= 159; $i++) {
$non_sgml_chars[HTMLPurifier_Encoder::unichr($i)] = '';
}
}
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
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
$str = iconv('UTF-8', 'UTF-8//IGNORE', $str);
restore_error_handler();
return strtr($str, $non_sgml_chars);
// need to do PHP stuff. 99% of the time, this will be the case.
// The regexp matches the XML char production, as well as well as excluding
// non-SGML codepoints U+007F to U+009F
if (preg_match('/^[\x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]*$/Du', $str)) {
return $str;
}
$mState = 0; // cached expected number of octets after the current octet
@@ -185,7 +163,17 @@ class HTMLPurifier_Encoder
) {
} elseif (0xFEFF != $mUcs4 && // omit BOM
!($mUcs4 >= 128 && $mUcs4 <= 159) // omit non-SGML
// check for valid Char unicode codepoints
(
0x9 == $mUcs4 ||
0xA == $mUcs4 ||
0xD == $mUcs4 ||
(0x20 <= $mUcs4 && 0x7E >= $mUcs4) ||
// 7F-9F is not strictly prohibited by XML,
// but it is non-SGML, and thus we don't allow it
(0xA0 <= $mUcs4 && 0xD7FF >= $mUcs4) ||
(0x10000 <= $mUcs4 && 0x10FFFF >= $mUcs4)
)
) {
$out .= $char;
}
@@ -276,22 +264,31 @@ class HTMLPurifier_Encoder
* Converts a string to UTF-8 based on configuration.
*/
public static function convertToUTF8($str, $config, $context) {
static $iconv = null;
if ($iconv === null) $iconv = function_exists('iconv');
$encoding = $config->get('Core', 'Encoding');
if ($encoding === 'utf-8') return $str;
if ($iconv && !$config->get('Test', 'ForceNoIconv')) {
static $iconv = null;
if ($iconv === null) $iconv = function_exists('iconv');
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
if ($iconv && !$config->get('Test', 'ForceNoIconv')) {
$str = iconv($encoding, 'utf-8//IGNORE', $str);
if ($str === false) {
// $encoding is not a valid encoding
restore_error_handler();
trigger_error('Invalid encoding ' . $encoding, E_USER_ERROR);
return '';
}
// If the string is bjorked by Shift_JIS or a similar encoding
// that doesn't support all of ASCII, convert the naughty
// characters to their true byte-wise ASCII/UTF-8 equivalents.
$str = strtr($str, HTMLPurifier_Encoder::testEncodingSupportsASCII($encoding));
restore_error_handler();
return $str;
} elseif ($encoding === 'iso-8859-1') {
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
$str = utf8_encode($str);
restore_error_handler();
return $str;
}
trigger_error('Encoding not supported', E_USER_ERROR);
trigger_error('Encoding not supported, please install iconv', E_USER_ERROR);
}
/**
@@ -300,20 +297,28 @@ class HTMLPurifier_Encoder
* characters being omitted.
*/
public static function convertFromUTF8($str, $config, $context) {
static $iconv = null;
if ($iconv === null) $iconv = function_exists('iconv');
$encoding = $config->get('Core', 'Encoding');
if ($encoding === 'utf-8') return $str;
if ($config->get('Core', 'EscapeNonASCIICharacters')) {
static $iconv = null;
if ($iconv === null) $iconv = function_exists('iconv');
if ($escape = $config->get('Core', 'EscapeNonASCIICharacters')) {
$str = HTMLPurifier_Encoder::convertToASCIIDumbLossless($str);
}
if ($iconv && !$config->get('Test', 'ForceNoIconv')) {
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
if ($iconv && !$config->get('Test', 'ForceNoIconv')) {
// Undo our previous fix in convertToUTF8, otherwise iconv will barf
$ascii_fix = HTMLPurifier_Encoder::testEncodingSupportsASCII($encoding);
if (!$escape && !empty($ascii_fix)) {
$clear_fix = array();
foreach ($ascii_fix as $utf8 => $native) $clear_fix[$utf8] = '';
$str = strtr($str, $clear_fix);
}
$str = strtr($str, array_flip($ascii_fix));
// Normal stuff
$str = iconv('utf-8', $encoding . '//IGNORE', $str);
restore_error_handler();
return $str;
} elseif ($encoding === 'iso-8859-1') {
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
$str = utf8_decode($str);
restore_error_handler();
return $str;
@@ -368,6 +373,47 @@ class HTMLPurifier_Encoder
return $result;
}
/**
* This expensive function tests whether or not a given character
* encoding supports ASCII. 7/8-bit encodings like Shift_JIS will
* fail this test, and require special processing. Variable width
* encodings shouldn't ever fail.
*
* @param string $encoding Encoding name to test, as per iconv format
* @param bool $bypass Whether or not to bypass the precompiled arrays.
* @return Array of UTF-8 characters to their corresponding ASCII,
* which can be used to "undo" any overzealous iconv action.
*/
public static function testEncodingSupportsASCII($encoding, $bypass = false) {
static $encodings = array();
if (!$bypass) {
if (isset($encodings[$encoding])) return $encodings[$encoding];
$lenc = strtolower($encoding);
switch ($lenc) {
case 'shift_jis':
return array("\xC2\xA5" => '\\', "\xE2\x80\xBE" => '~');
case 'johab':
return array("\xE2\x82\xA9" => '\\');
}
if (strpos($lenc, 'iso-8859-') === 0) return array();
}
$ret = array();
set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
if (iconv('UTF-8', $encoding, 'a') === false) return false;
for ($i = 0x20; $i <= 0x7E; $i++) { // all printable ASCII chars
$c = chr($i);
if (iconv('UTF-8', "$encoding//IGNORE", $c) === '') {
// Reverse engineer: what's the UTF-8 equiv of this byte
// sequence? This assumes that there's no variable width
// encoding that doesn't support ASCII.
$ret[iconv($encoding, 'UTF-8//IGNORE', $c)] = $c;
}
}
restore_error_handler();
$encodings[$encoding] = $ret;
return $ret;
}
}

View File

@@ -7,22 +7,37 @@
class HTMLPurifier_ErrorCollector
{
protected $errors = array();
/**
* Identifiers for the returned error array. These are purposely numeric
* so list() can be used.
*/
const LINENO = 0;
const SEVERITY = 1;
const MESSAGE = 2;
const CHILDREN = 3;
protected $errors;
protected $_current;
protected $_stacks = array(array());
protected $locale;
protected $generator;
protected $context;
protected $lines = array();
public function __construct($context) {
$this->locale =& $context->get('Locale');
$this->generator =& $context->get('Generator');
$this->context = $context;
$this->_current =& $this->_stacks[0];
$this->errors =& $this->_stacks[0];
}
/**
* Sends an error message to the collector for later use
* @param $line Integer line number, or HTMLPurifier_Token that caused error
* @param $severity int Error severity, PHP error style (don't use E_USER_)
* @param $msg string Error message text
* @param $subst1 string First substitution for $msg
* @param $subst2 string ...
*/
public function send($severity, $msg) {
@@ -35,6 +50,7 @@ class HTMLPurifier_ErrorCollector
$token = $this->context->get('CurrentToken', true);
$line = $token ? $token->line : $this->context->get('CurrentLine', true);
$col = $token ? $token->col : $this->context->get('CurrentCol', true);
$attr = $this->context->get('CurrentAttr', true);
// perform special substitutions, also add custom parameters
@@ -55,13 +71,66 @@ class HTMLPurifier_ErrorCollector
if (!empty($subst)) $msg = strtr($msg, $subst);
$this->errors[] = array($line, $severity, $msg);
// (numerically indexed)
$error = array(
self::LINENO => $line,
self::SEVERITY => $severity,
self::MESSAGE => $msg,
self::CHILDREN => array()
);
$this->_current[] = $error;
// NEW CODE BELOW ...
$struct = null;
// Top-level errors are either:
// TOKEN type, if $value is set appropriately, or
// "syntax" type, if $value is null
$new_struct = new HTMLPurifier_ErrorStruct();
$new_struct->type = HTMLPurifier_ErrorStruct::TOKEN;
if ($token) $new_struct->value = clone $token;
if (is_int($line) && is_int($col)) {
if (isset($this->lines[$line][$col])) {
$struct = $this->lines[$line][$col];
} else {
$struct = $this->lines[$line][$col] = $new_struct;
}
// These ksorts may present a performance problem
ksort($this->lines[$line], SORT_NUMERIC);
} else {
if (isset($this->lines[-1])) {
$struct = $this->lines[-1];
} else {
$struct = $this->lines[-1] = $new_struct;
}
}
ksort($this->lines, SORT_NUMERIC);
// Now, check if we need to operate on a lower structure
if (!empty($attr)) {
$struct = $struct->getChild(HTMLPurifier_ErrorStruct::ATTR, $attr);
if (!$struct->value) {
$struct->value = array($attr, 'PUT VALUE HERE');
}
}
if (!empty($cssprop)) {
$struct = $struct->getChild(HTMLPurifier_ErrorStruct::CSSPROP, $cssprop);
if (!$struct->value) {
// if we tokenize CSS this might be a little more difficult to do
$struct->value = array($cssprop, 'PUT VALUE HERE');
}
}
// Ok, structs are all setup, now time to register the error
$struct->addError($severity, $msg);
}
/**
* Retrieves raw error data for custom formatter to use
* @param List of arrays in format of array(Error message text,
* token that caused error, tokens surrounding token)
* @param List of arrays in format of array(line of error,
* error severity, error message,
* recursive sub-errors array)
*/
public function getRaw() {
return $this->errors;
@@ -70,38 +139,25 @@ class HTMLPurifier_ErrorCollector
/**
* Default HTML formatting implementation for error messages
* @param $config Configuration array, vital for HTML output nature
* @param $errors Errors array to display; used for recursion.
*/
public function getHTMLFormatted($config) {
public function getHTMLFormatted($config, $errors = null) {
$ret = array();
$errors = $this->errors;
$this->generator = new HTMLPurifier_Generator($config, $this->context);
if ($errors === null) $errors = $this->errors;
// sort error array by line
// line numbers are enabled if they aren't explicitly disabled
if ($config->get('Core', 'MaintainLineNumbers') !== false) {
$has_line = array();
$lines = array();
$original_order = array();
foreach ($errors as $i => $error) {
$has_line[] = (int) (bool) $error[0];
$lines[] = $error[0];
$original_order[] = $i;
}
array_multisort($has_line, SORT_DESC, $lines, SORT_ASC, $original_order, SORT_ASC, $errors);
}
// 'At line' message needs to be removed
foreach ($errors as $error) {
list($line, $severity, $msg) = $error;
$string = '';
$string .= '<strong>' . $this->locale->getErrorName($severity) . '</strong>: ';
$string .= $this->generator->escape($msg);
if ($line) {
// have javascript link generation that causes
// textarea to skip to the specified line
$string .= $this->locale->formatMessage(
'ErrorCollector: At line', array('line' => $line));
// generation code for new structure goes here. It needs to be recursive.
foreach ($this->lines as $line => $col_array) {
if ($line == -1) continue;
foreach ($col_array as $col => $struct) {
$this->_renderStruct($ret, $struct, $line, $col);
}
$ret[] = $string;
}
if (isset($this->lines[-1])) {
$this->_renderStruct($ret, $this->lines[-1]);
}
if (empty($errors)) {
@@ -112,5 +168,41 @@ class HTMLPurifier_ErrorCollector
}
private function _renderStruct(&$ret, $struct, $line = null, $col = null) {
$stack = array($struct);
$context_stack = array(array());
while ($current = array_pop($stack)) {
$context = array_pop($context_stack);
foreach ($current->errors as $error) {
list($severity, $msg) = $error;
$string = '';
$string .= '<div>';
// W3C uses an icon to indicate the severity of the error.
$error = $this->locale->getErrorName($severity);
$string .= "<span class=\"error e$severity\"><strong>$error</strong></span> ";
if (!is_null($line) && !is_null($col)) {
$string .= "<em class=\"location\">Line $line, Column $col: </em> ";
} else {
$string .= '<em class="location">End of Document: </em> ';
}
$string .= '<strong class="description">' . $this->generator->escape($msg) . '</strong> ';
$string .= '</div>';
// Here, have a marker for the character on the column appropriate.
// Be sure to clip extremely long lines.
//$string .= '<pre>';
//$string .= '';
//$string .= '</pre>';
$ret[] = $string;
}
foreach ($current->children as $type => $array) {
$context[] = $current;
$stack = array_merge($stack, array_reverse($array, true));
for ($i = count($array); $i > 0; $i--) {
$context_stack[] = $context;
}
}
}
}
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* Records errors for particular segments of an HTML document such as tokens,
* attributes or CSS properties. They can contain error structs (which apply
* to components of what they represent), but their main purpose is to hold
* errors applying to whatever struct is being used.
*/
class HTMLPurifier_ErrorStruct
{
/**
* Possible values for $children first-key. Note that top-level structures
* are automatically token-level.
*/
const TOKEN = 0;
const ATTR = 1;
const CSSPROP = 2;
/**
* Type of this struct.
*/
public $type;
/**
* Value of the struct we are recording errors for. There are various
* values for this:
* - TOKEN: Instance of HTMLPurifier_Token
* - ATTR: array('attr-name', 'value')
* - CSSPROP: array('prop-name', 'value')
*/
public $value;
/**
* Errors registered for this structure.
*/
public $errors = array();
/**
* Child ErrorStructs that are from this structure. For example, a TOKEN
* ErrorStruct would contain ATTR ErrorStructs. This is a multi-dimensional
* array in structure: [TYPE]['identifier']
*/
public $children = array();
public function getChild($type, $id) {
if (!isset($this->children[$type][$id])) {
$this->children[$type][$id] = new HTMLPurifier_ErrorStruct();
$this->children[$type][$id]->type = $type;
}
return $this->children[$type][$id];
}
public function addError($severity, $message) {
$this->errors[] = array($severity, $message);
}
}

View File

@@ -26,6 +26,11 @@ class HTMLPurifier_Generator
*/
private $_def;
/**
* Cache of %Output.SortAttr
*/
private $_sortAttr;
/**
* Configuration for the generator
*/
@@ -35,10 +40,10 @@ class HTMLPurifier_Generator
* @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();
public function __construct($config, $context) {
$this->config = $config;
$this->_scriptFix = $config->get('Output', 'CommentScriptContents');
$this->_sortAttr = $config->get('Output', 'SortAttr');
$this->_def = $config->getHTMLDefinition();
$this->_xhtml = $this->_def->doctype->xml;
}
@@ -143,6 +148,7 @@ class HTMLPurifier_Generator
*/
public function generateAttributes($assoc_array_of_attributes, $element = false) {
$html = '';
if ($this->_sortAttr) ksort($assoc_array_of_attributes);
foreach ($assoc_array_of_attributes as $key => $value) {
if (!$this->_xhtml) {
// Remove namespaced attributes

View File

@@ -76,6 +76,11 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
*/
public $info_content_sets = array();
/**
* Indexed list of HTMLPurifier_Injector to be used.
*/
public $info_injector = array();
/**
* Doctype object
*/
@@ -198,6 +203,10 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
if ($v === false) unset($this->info_attr_transform_post[$k]);
else $this->info_attr_transform_post[$k] = $v;
}
foreach ($module->info_injector as $k => $v) {
if ($v === false) unset($this->info_injector[$k]);
else $this->info_injector[$k] = $v;
}
}
$this->info = $this->manager->getElements();
@@ -356,6 +365,14 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
}
}
// setup injectors -----------------------------------------------------
foreach ($this->info_injector as $i => $injector) {
if ($injector->checkNeeded($config) !== false) {
// remove injector that does not have it's required
// elements/attributes present, and is thus not needed.
unset($this->info_injector[$i]);
}
}
}
/**

View File

@@ -71,6 +71,14 @@ class HTMLPurifier_HTMLModule
*/
public $info_attr_transform_post = array();
/**
* List of HTMLPurifier_Injector to be performed during well-formedness fixing.
* An injector will only be invoked if all of it's pre-requisites are met;
* if an injector fails setup, there will be no error; it will simply be
* silently disabled.
*/
public $info_injector = array();
/**
* Boolean flag that indicates whether or not getChildDef is implemented.
* For optimization reasons: may save a call to a function. Be sure
@@ -222,5 +230,14 @@ class HTMLPurifier_HTMLModule
}
return $ret;
}
/**
* Lazy load construction of the module after determining whether
* or not it's needed, and also when a finalized configuration object
* is available.
* @param $config Instance of HTMLPurifier_Config
*/
public function setup($config) {}
}

View File

@@ -12,7 +12,7 @@ class HTMLPurifier_HTMLModule_Bdo extends HTMLPurifier_HTMLModule
'I18N' => array('dir' => false)
);
public function __construct() {
public function setup($config) {
$bdo = $this->addElement(
'bdo', 'Inline', 'Inline', array('Core', 'Lang'),
array(

View File

@@ -9,7 +9,7 @@ class HTMLPurifier_HTMLModule_Edit extends HTMLPurifier_HTMLModule
public $name = 'Edit';
public function __construct() {
public function setup($config) {
$contents = 'Chameleon: #PCDATA | Inline ! #PCDATA | Flow';
$attr = array(
'cite' => 'URI',

View File

@@ -0,0 +1,117 @@
<?php
/**
* XHTML 1.1 Forms module, defines all form-related elements found in HTML 4.
*/
class HTMLPurifier_HTMLModule_Forms extends HTMLPurifier_HTMLModule
{
public $name = 'Forms';
public $safe = false;
public $content_sets = array(
'Block' => 'Form',
'Inline' => 'Formctrl',
);
public function setup($config) {
$form = $this->addElement('form', 'Form',
'Required: Heading | List | Block | fieldset', 'Common', array(
'accept' => 'ContentTypes',
'accept-charset' => 'Charsets',
'action*' => 'URI',
'method' => 'Enum#get,post',
// really ContentType, but these two are the only ones used today
'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data',
));
$form->excludes = array('form' => true);
$input = $this->addElement('input', 'Formctrl', 'Empty', 'Common', array(
'accept' => 'ContentTypes',
'accesskey' => 'Character',
'alt' => 'Text',
'checked' => 'Bool#checked',
'disabled' => 'Bool#disabled',
'maxlength' => 'Number',
'name' => 'CDATA',
'readonly' => 'Bool#readonly',
'size' => 'Number',
'src' => 'URI#embeds',
'tabindex' => 'Number',
'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image',
'value' => 'CDATA',
));
$input->attr_transform_post[] = new HTMLPurifier_AttrTransform_Input();
$this->addElement('select', 'Formctrl', 'Required: optgroup | option', 'Common', array(
'disabled' => 'Bool#disabled',
'multiple' => 'Bool#multiple',
'name' => 'CDATA',
'size' => 'Number',
'tabindex' => 'Number',
));
$this->addElement('option', false, 'Optional: #PCDATA', 'Common', array(
'disabled' => 'Bool#disabled',
'label' => 'Text',
'selected' => 'Bool#selected',
'value' => 'CDATA',
));
// It's illegal for there to be more than one selected, but not
// be multiple. Also, no selected means undefined behavior. This might
// be difficult to implement; perhaps an injector, or a context variable.
$textarea = $this->addElement('textarea', 'Formctrl', 'Optional: #PCDATA', 'Common', array(
'accesskey' => 'Character',
'cols*' => 'Number',
'disabled' => 'Bool#disabled',
'name' => 'CDATA',
'readonly' => 'Bool#readonly',
'rows*' => 'Number',
'tabindex' => 'Number',
));
$textarea->attr_transform_pre[] = new HTMLPurifier_AttrTransform_Textarea();
$button = $this->addElement('button', 'Formctrl', 'Optional: #PCDATA | Heading | List | Block | Inline', 'Common', array(
'accesskey' => 'Character',
'disabled' => 'Bool#disabled',
'name' => 'CDATA',
'tabindex' => 'Number',
'type' => 'Enum#button,submit,reset',
'value' => 'CDATA',
));
// For exclusions, ideally we'd specify content sets, not literal elements
$button->excludes = $this->makeLookup(
'form', 'fieldset', // Form
'input', 'select', 'textarea', 'label', 'button', // Formctrl
'a' // as per HTML 4.01 spec, this is omitted by modularization
);
// Extra exclusion: img usemap="" is not permitted within this element.
// We'll omit this for now, since we don't have any good way of
// indicating it yet.
// This is HIGHLY user-unfriendly; we need a custom child-def for this
$this->addElement('fieldset', 'Form', 'Custom: (#WS?,legend,(Flow|#PCDATA)*)', 'Common');
$label = $this->addElement('label', 'Formctrl', 'Optional: #PCDATA | Inline', 'Common', array(
'accesskey' => 'Character',
// 'for' => 'IDREF', // IDREF not implemented, cannot allow
));
$label->excludes = array('label' => true);
$this->addElement('legend', false, 'Optional: #PCDATA | Inline', 'Common', array(
'accesskey' => 'Character',
));
$this->addElement('optgroup', false, 'Required: option', 'Common', array(
'disabled' => 'Bool#disabled',
'label*' => 'Text',
));
// Don't forget an injector for <isindex>. This one's a little complex
// because it maps to multiple elements.
}
}

View File

@@ -8,7 +8,7 @@ class HTMLPurifier_HTMLModule_Hypertext extends HTMLPurifier_HTMLModule
public $name = 'Hypertext';
public function __construct() {
public function setup($config) {
$a = $this->addElement(
'a', 'Inline', 'Inline', 'Common',
array(

View File

@@ -10,17 +10,25 @@ class HTMLPurifier_HTMLModule_Image extends HTMLPurifier_HTMLModule
public $name = 'Image';
public function __construct() {
public function setup($config) {
$max = $config->get('HTML', 'MaxImgLength');
$img = $this->addElement(
'img', 'Inline', 'Empty', 'Common',
array(
'alt*' => 'Text',
'height' => 'Length',
// According to the spec, it's Length, but percents can
// be abused, so we allow only Pixels.
'height' => 'Pixels#' . $max,
'width' => 'Pixels#' . $max,
'longdesc' => 'URI',
'src*' => new HTMLPurifier_AttrDef_URI(true), // embedded
'width' => 'Length'
)
);
if ($max === null || $config->get('HTML', 'Trusted')) {
$img->attr['height'] =
$img->attr['width'] = 'Length';
}
// kind of strange, but splitting things up would be inefficient
$img->attr_transform_pre[] =
$img->attr_transform_post[] =

View File

@@ -21,7 +21,7 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
public $name = 'Legacy';
public function __construct() {
public function setup($config) {
$this->addElement('basefont', 'Inline', 'Empty', false, array(
'color' => 'Color',

View File

@@ -19,7 +19,7 @@ class HTMLPurifier_HTMLModule_List extends HTMLPurifier_HTMLModule
public $content_sets = array('Flow' => 'List');
public function __construct() {
public function setup($config) {
$this->addElement('ol', 'List', 'Required: li', 'Common');
$this->addElement('ul', 'List', 'Required: li', 'Common');
$this->addElement('dl', 'List', 'Required: dt | dd', 'Common');

View File

@@ -0,0 +1,16 @@
<?php
class HTMLPurifier_HTMLModule_Name extends HTMLPurifier_HTMLModule
{
public $name = 'Name';
public function setup($config) {
$elements = array('a', 'applet', 'form', 'frame', 'iframe', 'img', 'map');
foreach ($elements as $name) {
$element = $this->addBlankElement($name);
$element->attr['name'] = 'ID';
}
}
}

View File

@@ -11,7 +11,7 @@ class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule
public $name = 'Object';
public $safe = false;
public function __construct() {
public function setup($config) {
$this->addElement('object', 'Inline', 'Optional: #PCDATA | Flow | param', 'Common',
array(

View File

@@ -15,7 +15,7 @@ class HTMLPurifier_HTMLModule_Presentation extends HTMLPurifier_HTMLModule
public $name = 'Presentation';
public function __construct() {
public function setup($config) {
$this->addElement('b', 'Inline', 'Inline', 'Common');
$this->addElement('big', 'Inline', 'Inline', 'Common');
$this->addElement('hr', 'Block', 'Empty', 'Common');

View File

@@ -9,7 +9,7 @@ class HTMLPurifier_HTMLModule_Proprietary extends HTMLPurifier_HTMLModule
public $name = 'Proprietary';
public function __construct() {
public function setup($config) {
$this->addElement('marquee', 'Inline', 'Flow', 'Common',
array(

View File

@@ -9,7 +9,7 @@ class HTMLPurifier_HTMLModule_Ruby extends HTMLPurifier_HTMLModule
public $name = 'Ruby';
public function __construct() {
public function setup($config) {
$this->addElement('ruby', 'Inline',
'Custom: ((rb, (rt | (rp, rt, rp))) | (rbc, rtc, rtc?))',
'Common');

View File

@@ -0,0 +1,31 @@
<?php
/**
* A "safe" embed module. See SafeObject. This is a proprietary element.
*/
class HTMLPurifier_HTMLModule_SafeEmbed extends HTMLPurifier_HTMLModule
{
public $name = 'SafeEmbed';
public function setup($config) {
$max = $config->get('HTML', 'MaxImgLength');
$embed = $this->addElement(
'embed', 'Inline', 'Empty', 'Common',
array(
'src*' => 'URI#embedded',
'type' => 'Enum#application/x-shockwave-flash',
'width' => 'Pixels#' . $max,
'height' => 'Pixels#' . $max,
'allowscriptaccess' => 'Enum#never',
'allownetworking' => 'Enum#internal',
'wmode' => 'Enum#window',
'name' => 'ID',
)
);
$embed->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeEmbed();
}
}

View File

@@ -0,0 +1,48 @@
<?php
/**
* A "safe" object module. In theory, objects permitted by this module will
* be safe, and untrusted users can be allowed to embed arbitrary flash objects
* (maybe other types too, but only Flash is supported as of right now).
* Highly experimental.
*/
class HTMLPurifier_HTMLModule_SafeObject extends HTMLPurifier_HTMLModule
{
public $name = 'SafeObject';
public function setup($config) {
// These definitions are not intrinsically safe: the attribute transforms
// are a vital part of ensuring safety.
$max = $config->get('HTML', 'MaxImgLength');
$object = $this->addElement(
'object',
'Inline',
'Optional: param | Flow | #PCDATA',
'Common',
array(
// While technically not required by the spec, we're forcing
// it to this value.
'type' => 'Enum#application/x-shockwave-flash',
'width' => 'Pixels#' . $max,
'height' => 'Pixels#' . $max,
'data' => 'URI#embedded'
)
);
$object->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeObject();
$param = $this->addElement('param', false, 'Empty', false,
array(
'id' => 'ID',
'name*' => 'Text',
'value' => 'Text'
)
);
$param->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeParam();
$this->info_injector[] = 'SafeObject';
}
}

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