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

Compare commits

..

176 Commits

Author SHA1 Message Date
Edward Z. Yang
f4e4c1556d Release 1.6.1.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1025 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 20:26:42 +00:00
Edward Z. Yang
c5e33416d3 [1.6.1] Unit tests now use exclusively assertIdentical
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1024 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 20:17:04 +00:00
Edward Z. Yang
6c08ca4c16 [1.6.1] Fix bug (== v. ===) that caused merged in attribute definitions to be messed up
- Make our modified class_exists() check to work in both PHP 4 and 5
(todo: we need some unit tests for ElementDef)

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1023 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 20:04:34 +00:00
Edward Z. Yang
b1822bb04f [1.6.1] Implement AttrTransform for type in ul, ol and li
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1022 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 19:13:52 +00:00
Edward Z. Yang
893e962890 [1.6.1] Update unit tests for font transformation
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1021 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 18:59:24 +00:00
Edward Z. Yang
bd6071cb3b [1.6.1] Transformation of font's size attribute now handles super-large numbers
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1020 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 18:56:45 +00:00
Edward Z. Yang
92ea74cba2 [1.6.1] Add attribute transformation smoketests
- Repair broken noshade implementation
- Add lots of advisory comments to TransformToStrict.php

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1019 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 18:41:53 +00:00
Edward Z. Yang
a01459c87a [1.6.1] Implement clear in br and align in caption, table, img and hr
- Refactored ValidateAttributesTest.php

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1018 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 16:18:04 +00:00
Edward Z. Yang
fd35c43643 [1.6.1] Implement generic EnumToCSS attribute transformation, migrate text alignment to it
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1017 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 15:48:41 +00:00
Edward Z. Yang
0426985c81 [1.6.1] Refactor AttrTransform to reduce duplication.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1016 48356398-32a2-884e-a903-53898d9a118a
2007-05-05 02:25:55 +00:00
Edward Z. Yang
bbea02f55c Rewrite docs on align attribute, complete with smoketest-case and licensing info.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1014 48356398-32a2-884e-a903-53898d9a118a
2007-05-04 01:29:06 +00:00
Edward Z. Yang
4e77a1adbd [1.6.1] Fix fatal error with XHTML 1.1 validation.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1013 48356398-32a2-884e-a903-53898d9a118a
2007-05-04 01:17:00 +00:00
Edward Z. Yang
bd58a7ba77 [1.6.1] Implement BoolToCSS attribute transformations for td,th.nowrap and hr.noshade
- Implement CSS property white-space:nowrap;
- Update TODO with more ambitious goal: all transforms by 1.6.1

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1012 48356398-32a2-884e-a903-53898d9a118a
2007-05-03 04:07:47 +00:00
Edward Z. Yang
a3ed9196b9 Downgrade code-quality back to a txt scratchpad, add more items for AttrDef
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1010 48356398-32a2-884e-a903-53898d9a118a
2007-05-03 03:15:29 +00:00
Edward Z. Yang
2646f5ea57 Add experimental and dangerous Scripting module. This is NOT mentioned in the NEWS items, and will be officially released with 1.7.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1008 48356398-32a2-884e-a903-53898d9a118a
2007-05-01 21:43:24 +00:00
Edward Z. Yang
424c7ad2e3 Update target milestones, add Windows live mail specimen.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1007 48356398-32a2-884e-a903-53898d9a118a
2007-05-01 21:37:35 +00:00
Edward Z. Yang
234b3085d7 [1.6.1] Activate transform for hr.size
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1006 48356398-32a2-884e-a903-53898d9a118a
2007-05-01 21:36:19 +00:00
Edward Z. Yang
3d978c961d [1.6.1] Implement target module/attribute.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1002 48356398-32a2-884e-a903-53898d9a118a
2007-04-30 21:19:15 +00:00
Edward Z. Yang
72254cd77a [1.6.1] Implement vspace and hspace transformations in img.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1001 48356398-32a2-884e-a903-53898d9a118a
2007-04-30 19:39:42 +00:00
Edward Z. Yang
d8a6361244 [1.6.1] Empty strings get converted to empty arrays instead of arrays with an empty string in them.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1000 48356398-32a2-884e-a903-53898d9a118a
2007-04-30 01:14:21 +00:00
Edward Z. Yang
968dfa2feb [1.6.1] Fix broken configuration directive %Core.RemoveInvalidImg, also make basic demo operational out-of-the-box
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@999 48356398-32a2-884e-a903-53898d9a118a
2007-04-30 00:53:13 +00:00
Edward Z. Yang
114d6841ab Update TODO: rename release and add HTML configuration interface
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@998 48356398-32a2-884e-a903-53898d9a118a
2007-04-30 00:48:22 +00:00
Edward Z. Yang
1c68d769b5 Fix bug in packager: force all files to be "php"
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@996 48356398-32a2-884e-a903-53898d9a118a
2007-04-29 04:06:40 +00:00
Edward Z. Yang
ac0ca3f15c Miscellaneous URL updates.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@993 48356398-32a2-884e-a903-53898d9a118a
2007-04-22 22:26:20 +00:00
Edward Z. Yang
2d5498b8aa Update URLs from hp.jpsband.org to htmlpurifier.org
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@992 48356398-32a2-884e-a903-53898d9a118a
2007-04-22 22:22:48 +00:00
Edward Z. Yang
71ccae1a3a [1.6.0] Add news item on how demo script was removed
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@991 48356398-32a2-884e-a903-53898d9a118a
2007-04-22 22:11:35 +00:00
Edward Z. Yang
cb186dddc4 Compactify HTML Purifier library inclusion
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@987 48356398-32a2-884e-a903-53898d9a118a
2007-04-22 21:01:48 +00:00
Edward Z. Yang
2ceccc0969 Moved remotely to website.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@984 48356398-32a2-884e-a903-53898d9a118a
2007-04-22 20:55:52 +00:00
Edward Z. Yang
93aa98ad01 Update package.php with new URLs from migration.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@979 48356398-32a2-884e-a903-53898d9a118a
2007-04-22 02:56:05 +00:00
Edward Z. Yang
c0b38bab85 [1.6.1] Invert HTMLModuleManager->addModule() processing order to check prefixes first and then the literal module
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@971 48356398-32a2-884e-a903-53898d9a118a
2007-04-21 02:31:38 +00:00
Edward Z. Yang
d6c4473a12 [1.6.1] Possibly fatal bug with __autoload() fixed in module manager
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@969 48356398-32a2-884e-a903-53898d9a118a
2007-04-21 02:19:18 +00:00
Edward Z. Yang
fc06f221d5 Remove redundant $info member variable.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@960 48356398-32a2-884e-a903-53898d9a118a
2007-04-11 21:44:26 +00:00
Edward Z. Yang
ac3ab2a556 [1.6.1] DirectLex now preserves text in which a < bracket is followed by a non-alphanumeric character. This means that certain emoticons are now preserved.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@939 48356398-32a2-884e-a903-53898d9a118a
2007-04-04 02:22:27 +00:00
Edward Z. Yang
2c330cac73 Add 1.6.1 TODO stuff.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@937 48356398-32a2-884e-a903-53898d9a118a
2007-04-02 13:28:49 +00:00
Edward Z. Yang
a0d6543b84 Some packaging fixes:
- Add VERSION file, which contains just the version number of the release
- Add WHATSNEW, which is a short summary of the new release
- Add release.php which bumps all the necessary version numbers in files
- Update package.php so that the version numbers aren't hardcoded
- Add news entry for 1.7.0

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@935 48356398-32a2-884e-a903-53898d9a118a
2007-04-02 03:58:59 +00:00
Edward Z. Yang
e223490a78 Release 1.6.0.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@930 48356398-32a2-884e-a903-53898d9a118a
2007-04-01 22:31:16 +00:00
Edward Z. Yang
2666f067cc Add partial French install file.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@929 48356398-32a2-884e-a903-53898d9a118a
2007-04-01 21:38:10 +00:00
Edward Z. Yang
826a57a04a Update Advanced API with various edits and Customization section.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@928 48356398-32a2-884e-a903-53898d9a118a
2007-04-01 18:21:43 +00:00
Edward Z. Yang
e08b5aaa70 [1.6.0] Add error messages for when user attempts to "allow" elements or attributes HTML Purifier does not support.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@927 48356398-32a2-884e-a903-53898d9a118a
2007-03-31 03:41:22 +00:00
Edward Z. Yang
b15e8c344e [1.6.0] Implement ID regexp matching.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@926 48356398-32a2-884e-a903-53898d9a118a
2007-03-31 03:25:10 +00:00
Edward Z. Yang
2c9e041b4c Update TODO and progress document.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@925 48356398-32a2-884e-a903-53898d9a118a
2007-03-31 03:09:46 +00:00
Edward Z. Yang
e2c3394d70 [1.6.0] Add support for LinkTypes, used for rel and rev attributes.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@924 48356398-32a2-884e-a903-53898d9a118a
2007-03-31 02:58:16 +00:00
Edward Z. Yang
1532fe703a Update docs:
- Progress hr.size was changed from width to height
- UTF-8 rules of thumb were clarified to make clear this is only necessary for UTF-8 text.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@923 48356398-32a2-884e-a903-53898d9a118a
2007-03-30 00:01:35 +00:00
Edward Z. Yang
058f1eba7d [1.6.0] Implement width/height attribute transforms with Length.php
- Also, enabled 'height' CSS attribute

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@922 48356398-32a2-884e-a903-53898d9a118a
2007-03-29 23:48:54 +00:00
Edward Z. Yang
1102dc6e27 [1.6.0] Add support for name transformation to id
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@921 48356398-32a2-884e-a903-53898d9a118a
2007-03-29 23:19:53 +00:00
Edward Z. Yang
85374d330f [1.6.0] Add support for border attribute transform
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@920 48356398-32a2-884e-a903-53898d9a118a
2007-03-29 21:41:17 +00:00
Edward Z. Yang
a16d6c4342 [1.6.0] Add support for bgcolor attribute transform.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@919 48356398-32a2-884e-a903-53898d9a118a
2007-03-29 21:20:44 +00:00
Edward Z. Yang
9b5e2978ad Add ID regexps to the TODO list.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@913 48356398-32a2-884e-a903-53898d9a118a
2007-03-29 00:13:12 +00:00
Edward Z. Yang
06468a4157 [1.5.1] Add segfault fix to news log.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@912 48356398-32a2-884e-a903-53898d9a118a
2007-03-27 23:29:10 +00:00
Edward Z. Yang
0167f8aa84 [1.5.1] Try separating out declarations, might stop segfaulting.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@911 48356398-32a2-884e-a903-53898d9a118a
2007-03-27 23:15:01 +00:00
Edward Z. Yang
f1a90e684b [1.5.1] Separate out trouble area that's having segfaults. (note: this commit actually inadvertently let us discover a fix for the segfault, applied in the next revision).
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@910 48356398-32a2-884e-a903-53898d9a118a
2007-03-27 23:07:21 +00:00
Edward Z. Yang
14d98413fd Update advanced API with more details on selection interface.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@908 48356398-32a2-884e-a903-53898d9a118a
2007-03-27 01:26:26 +00:00
Edward Z. Yang
97a4ec7598 Add in terracc's suggestions to TODO file.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@886 48356398-32a2-884e-a903-53898d9a118a
2007-03-25 00:40:13 +00:00
Edward Z. Yang
71ed725c5c Complete PEAR packager that actually works!
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@885 48356398-32a2-884e-a903-53898d9a118a
2007-03-25 00:23:35 +00:00
Edward Z. Yang
d4bf41288a Add package2.xml
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@884 48356398-32a2-884e-a903-53898d9a118a
2007-03-24 20:43:16 +00:00
Edward Z. Yang
365bd78c20 Commit PEAR package stuffs.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@883 48356398-32a2-884e-a903-53898d9a118a
2007-03-24 20:39:00 +00:00
Edward Z. Yang
52fa958fb2 Release 1.5.0 (bumped HTMLPurifier.php version number).
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@874 48356398-32a2-884e-a903-53898d9a118a
2007-03-24 02:10:33 +00:00
Edward Z. Yang
17d32bac7f Almost release 1.5.0. Merged in a few strict changes.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@870 48356398-32a2-884e-a903-53898d9a118a
2007-03-24 01:24:38 +00:00
Edward Z. Yang
e2babe5308 Almost release 1.5.0.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@867 48356398-32a2-884e-a903-53898d9a118a
2007-03-24 00:35:53 +00:00
Edward Z. Yang
5f1a6b883f Update NEWS with a few old items I missed. We may yet have a 1.4.2 interim release.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@811 48356398-32a2-884e-a903-53898d9a118a
2007-03-14 21:34:37 +00:00
Edward Z. Yang
c5e3796202 Update advanced API docs, link to it from index.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@808 48356398-32a2-884e-a903-53898d9a118a
2007-03-14 04:56:44 +00:00
Edward Z. Yang
72f1984229 Add notes on "mode" to advanced API.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@801 48356398-32a2-884e-a903-53898d9a118a
2007-03-12 03:53:09 +00:00
Edward Z. Yang
918081b372 [1.4.x?] Make regex multiline.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@794 48356398-32a2-884e-a903-53898d9a118a
2007-03-04 02:55:44 +00:00
Edward Z. Yang
6c56dd070f Updated Advanced API docs.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@769 48356398-32a2-884e-a903-53898d9a118a
2007-03-01 03:56:08 +00:00
Edward Z. Yang
299f93f8f0 Add initial version of advanced API specification, also add <q> tag fix.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@768 48356398-32a2-884e-a903-53898d9a118a
2007-02-28 04:42:08 +00:00
Edward Z. Yang
4169846c57 Modules are not passed by reference, so in PHP 4 we cannot guarantee same module that went in will be used.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@767 48356398-32a2-884e-a903-53898d9a118a
2007-02-27 23:57:54 +00:00
Edward Z. Yang
aff4957531 [1.4.x?] Alright, have both PHP5 and DOMDocument requirements for DOMLex checked.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@766 48356398-32a2-884e-a903-53898d9a118a
2007-02-27 23:54:29 +00:00
Edward Z. Yang
e4bdf472a6 Fix typo.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@764 48356398-32a2-884e-a903-53898d9a118a
2007-02-20 03:05:03 +00:00
Edward Z. Yang
9a99750474 - Setup doctypes, auto properties, and work on making the interface more user-friendly
- Yet even more unit test for HTMLModuleManager
- Sample code in printDefinition for defining a new element
- Downgraded importances of HTMLModule->elements

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@762 48356398-32a2-884e-a903-53898d9a118a
2007-02-18 05:29:19 +00:00
Edward Z. Yang
7eb751b5f5 More refactoring: for interest of unit testing, default doctypes were moved to an initialize() method which could optionally be omitted. Disable collection aliases in favor of doctype aliases.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@761 48356398-32a2-884e-a903-53898d9a118a
2007-02-17 22:17:14 +00:00
Edward Z. Yang
0d0173eb6e Implement unit tests for very public interfaces of HTMLModuleManager, also added lots of error checking. tally_errors now requires unit test to be passed in as parameter.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@760 48356398-32a2-884e-a903-53898d9a118a
2007-02-17 19:37:48 +00:00
Edward Z. Yang
556ed4ea90 - Shuffle around includes to the right places
- Fix error in unit test

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@759 48356398-32a2-884e-a903-53898d9a118a
2007-02-17 17:43:44 +00:00
Edward Z. Yang
cf445a6107 - Revamp ordering scheme: onus in on collections, conflict resolution based on module load order.
- Miscellaneous refactoring and documentation

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@758 48356398-32a2-884e-a903-53898d9a118a
2007-02-17 17:10:28 +00:00
Edward Z. Yang
243ad45e59 Add some clarifying comments on what belongs in activeModules and validModules.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@757 48356398-32a2-884e-a903-53898d9a118a
2007-02-16 03:48:25 +00:00
Edward Z. Yang
31d0c621f5 Create two more module sets: activeModules and validModules to supplant the getModules() method.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@756 48356398-32a2-884e-a903-53898d9a118a
2007-02-16 03:33:29 +00:00
Edward Z. Yang
0870974a25 Have processCollections() perform name to instance indexing at the get-go.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@755 48356398-32a2-884e-a903-53898d9a118a
2007-02-16 03:16:17 +00:00
Edward Z. Yang
5c4a0a6785 Migrate default attribute collections to their own module, do late-loading of the attribute collection.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@754 48356398-32a2-884e-a903-53898d9a118a
2007-02-16 03:07:47 +00:00
Edward Z. Yang
e55babdc53 Move order to module itself, as member variable type.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@753 48356398-32a2-884e-a903-53898d9a118a
2007-02-16 03:01:23 +00:00
Edward Z. Yang
6e1b540d99 Remove missing include.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@752 48356398-32a2-884e-a903-53898d9a118a
2007-02-15 14:02:01 +00:00
Edward Z. Yang
edf20018f0 Add an HTMLModuleManager.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@751 48356398-32a2-884e-a903-53898d9a118a
2007-02-15 14:00:18 +00:00
Edward Z. Yang
c09432e171 Add command line support for loading a single test file.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@750 48356398-32a2-884e-a903-53898d9a118a
2007-02-15 00:17:23 +00:00
Edward Z. Yang
9c031b5c1e Add name class member variable to modules.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@749 48356398-32a2-884e-a903-53898d9a118a
2007-02-14 22:30:17 +00:00
Edward Z. Yang
a827cbc3ba Slight formatting change.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@748 48356398-32a2-884e-a903-53898d9a118a
2007-02-14 22:21:07 +00:00
Edward Z. Yang
c05eebee15 [1.5.0] AttrDef partitioned into HTML, CSS and URI segments. Also, some minor bugs with MultiLength fixed.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@747 48356398-32a2-884e-a903-53898d9a118a
2007-02-14 20:38:51 +00:00
Edward Z. Yang
93a69d020a Fix typo.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@746 48356398-32a2-884e-a903-53898d9a118a
2007-02-14 16:22:28 +00:00
Edward Z. Yang
f3fa9c01ba Add IDREF support to TODO list.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@744 48356398-32a2-884e-a903-53898d9a118a
2007-02-14 03:59:25 +00:00
Edward Z. Yang
bae5b0c022 Move out SetParent and TweakSubtractiveWhitelist. Move out some other configurations, disable ID references.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@743 48356398-32a2-884e-a903-53898d9a118a
2007-02-14 02:54:41 +00:00
Edward Z. Yang
67befbc8a8 [1.5.0] Rename %Attr.DisableURI to %URI.Disable and move it over to the AttrDef.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@742 48356398-32a2-884e-a903-53898d9a118a
2007-02-14 01:57:06 +00:00
Edward Z. Yang
cac22f01cf [1.5.0]
- More framework work (modules now are treated first class)
- Config will regenerate definitions when appropriate entries are set
- Add HTMLModule->setup for pre-processing stuff
- Constructor receives $definition not $config
- Config rolled inside $definition->config until end of setup()

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@741 48356398-32a2-884e-a903-53898d9a118a
2007-02-14 01:44:06 +00:00
Edward Z. Yang
94d2dbaa74 Fix broken benchmark code.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@739 48356398-32a2-884e-a903-53898d9a118a
2007-02-13 20:51:47 +00:00
Edward Z. Yang
6add828bc8 Update UTF-8 title.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@735 48356398-32a2-884e-a903-53898d9a118a
2007-02-13 03:09:34 +00:00
Edward Z. Yang
800b67ed65 Add preProcess and postProcess infrastructure to HTMLModule and HTMLDefinition so that almost all functionality that does not involve merging the modules together can be factored into modules.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@733 48356398-32a2-884e-a903-53898d9a118a
2007-02-12 03:02:26 +00:00
Edward Z. Yang
71e4ddd222 [1.5.0] Implement Legacy module.
- Yet another test EnableAttrID
- ElementDef now is mindful of attr inclusion merges

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@732 48356398-32a2-884e-a903-53898d9a118a
2007-02-11 01:52:56 +00:00
Edward Z. Yang
54a68a1713 [1.5.0] Implement TransformToStrict proprietary module
- Factored out strictblockquote from the common definition
- Text module now follows "strict" rules by default
- attr_transform_* now are indexed with string keys, to allow overloading
- Implement ElementDef mergin, and add standalone class variable to ElementDef to prevent half-baked element definitions from masquerading as full ones
- Implement merging global attributes from modules, namely info_attr_transform_post, info_attr_transform_pre and info_tag_transform
- Rename setupInfo() to processModules()
- Fix typo in HTMLModule/Bdo.php

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@731 48356398-32a2-884e-a903-53898d9a118a
2007-02-10 23:35:21 +00:00
Edward Z. Yang
bd544ad038 Formatting and documentation fixes.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@730 48356398-32a2-884e-a903-53898d9a118a
2007-02-09 03:19:43 +00:00
Edward Z. Yang
d5491da77f [1.5.0] Rewrite XHTML 1.1 document to describe HTMLDefinition's modularization
- Use ElementDef->child to define a literal ChildDef object, rather than ElementDef->content_model.
- Add notes on transforms, HTMLModule will be able to write those too
- Fix some misc typos.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@729 48356398-32a2-884e-a903-53898d9a118a
2007-02-08 23:10:49 +00:00
Edward Z. Yang
591fc0ae28 Divvy up TagTransform library files into their own separate files. Similar action needs to be taken for the tests.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@728 48356398-32a2-884e-a903-53898d9a118a
2007-02-06 01:33:28 +00:00
Edward Z. Yang
dac7ac1eae Add documentation.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@727 48356398-32a2-884e-a903-53898d9a118a
2007-02-05 05:23:20 +00:00
Edward Z. Yang
64ee756b7a Rename ConfigEntity to ConfigDef and factor into its own classes.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@726 48356398-32a2-884e-a903-53898d9a118a
2007-02-05 03:22:32 +00:00
Edward Z. Yang
e2103ce0f2 Factor out content set and childdef functionality to ContentSets. Remove redundant info suffix from attr_collections.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@725 48356398-32a2-884e-a903-53898d9a118a
2007-02-05 03:05:46 +00:00
Edward Z. Yang
219902ebff Revert back to pre XHTMLDefinition testing state.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@724 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 23:18:53 +00:00
Edward Z. Yang
21116373a7 [1.5.0] Implemented new HTMLDefinition based on XHTML 1.1 Modularization
- Well, not really, but it's now official. Some gunky prototype code left, but it's pretty much all done.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@723 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 23:17:13 +00:00
Edward Z. Yang
5ed88809f3 Add a bunch of compatibility gunk to XHTMLDefinition for modules we've not implemented yet and replace HTMLDefinition with it.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@722 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 23:10:10 +00:00
Edward Z. Yang
bb8b38b1e0 Rename attr_collection to attr_collections, which is more accurate. HTMLModule now has attr_collections_info rather than attr_collections which implied an object. Further clarified naming conventions.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@721 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 22:26:56 +00:00
Edward Z. Yang
236159242f Enforce info_ prefix convention for data that is accessed by HTML Purifier internals.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@720 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 22:08:51 +00:00
Edward Z. Yang
9d8f839bf2 Add empty template HTMLModule for legacy-related processing.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@719 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 21:58:38 +00:00
Edward Z. Yang
882148f9ad Add nested test for del/ins inline support.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@718 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 21:02:35 +00:00
Edward Z. Yang
a863f62489 Add full documentation. Implement deferred ChildDef to HTMLModule. Add missing attributes for table, switched some to Number. Add necessary includes to module files. Add pre exclusions. Printer now ksorts arrays before output. Exclude ins/del from descendants_are_inline flagging.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@717 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 20:09:35 +00:00
Edward Z. Yang
6478c7c2df Implement Style Attribute Module, cleanup some attribute collections and add some documentation.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@716 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 18:27:59 +00:00
Edward Z. Yang
129a4ea506 Implement Image Module.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@715 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 16:35:40 +00:00
Edward Z. Yang
a122243a89 Implement Tables Module.
- Fix HTMLDefinition rendering of table children

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@714 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 16:23:26 +00:00
Edward Z. Yang
315c55eeb1 Implement Bdo module. Also added some documentation and missing values, as well as support for attr_collection additions.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@713 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 15:28:47 +00:00
Edward Z. Yang
cfe50ff8ae Implement Edit module.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@712 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 14:56:55 +00:00
Edward Z. Yang
d0018a2696 Implement Presentation module.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@711 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 04:41:34 +00:00
Edward Z. Yang
77d9e05a07 [1.5.0] Massive refactoring for Blockquote and Chameleon to be more extensible and accommodating of XHTMLDefinition.
- Fixed buggy chameleon-support for ins and del
. Removed context variable ParentType, replaced with IsInline, which
  is false when you're not inline and an integer of the parent that
  caused you to become inline when you are (so possibly zero)
. Removed ElementDef->type in favor of ElementDef->descendants_are_inline
  and HTMLDefinition->content_sets
. StrictBlockquote now reports what elements its supposed to allow,
  rather than what it does allow
. Removed HTMLDefinition->info_flow_elements in favor of
  HTMLDefinition->content_sets['Flow']
. Removed redundant "exclusionary" definitions from DTD roster
. StrictBlockquote now requires a construction parameter as if it
  were an Required ChildDef, this is the "real" set of allowed elements

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@710 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 03:53:57 +00:00
Edward Z. Yang
80243f377c Implement List module.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@709 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 01:52:13 +00:00
Edward Z. Yang
43b157cf4d Add Hypertext module.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@708 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 01:01:27 +00:00
Edward Z. Yang
f6b50d4bfd Initial implementation of XHTMLDefinition, you can see it in action at the smoketest printDefinition.php?x (add the x at the end).
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@707 48356398-32a2-884e-a903-53898d9a118a
2007-02-04 00:07:52 +00:00
Edward Z. Yang
806901cfd2 [1.5.0] Rename Class to Nmtokens (more accurate)
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@706 48356398-32a2-884e-a903-53898d9a118a
2007-02-03 20:15:33 +00:00
Edward Z. Yang
f90eef7f1f Update docs. Delineate XHTML 1.1 revamping of HTMLDefinition.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@705 48356398-32a2-884e-a903-53898d9a118a
2007-02-03 17:03:04 +00:00
Edward Z. Yang
06867e14b6 Increase child definition sets to all elements to facilitate later expansion. Currently has no perceptible effect.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@704 48356398-32a2-884e-a903-53898d9a118a
2007-02-03 03:45:13 +00:00
Edward Z. Yang
bda2615b30 [1.5.0] Add support for IDREF
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@703 48356398-32a2-884e-a903-53898d9a118a
2007-02-02 22:03:09 +00:00
Edward Z. Yang
e1a5d10e75 Fix typo in comment.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@702 48356398-32a2-884e-a903-53898d9a118a
2007-01-30 00:34:23 +00:00
Edward Z. Yang
98fd6b7d82 [1.5.0] Add rudimentary I18N and L10N support based off MediaWiki
- Also: allow 'x' subtag in language codes

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@701 48356398-32a2-884e-a903-53898d9a118a
2007-01-29 20:11:00 +00:00
Edward Z. Yang
be264a4b20 Update docs.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@700 48356398-32a2-884e-a903-53898d9a118a
2007-01-29 17:53:54 +00:00
Edward Z. Yang
01c85b71d2 Fix minor typo.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@699 48356398-32a2-884e-a903-53898d9a118a
2007-01-28 22:19:05 +00:00
Edward Z. Yang
2d22c0aa55 [1.4.x?] Completed enduser-utf8.html
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@697 48356398-32a2-884e-a903-53898d9a118a
2007-01-24 23:48:35 +00:00
Edward Z. Yang
6e061f5184 I18N -> International/internationalization
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@696 48356398-32a2-884e-a903-53898d9a118a
2007-01-24 21:24:54 +00:00
Edward Z. Yang
44b988f1f6 Fix some editing mistakes.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@695 48356398-32a2-884e-a903-53898d9a118a
2007-01-24 03:00:48 +00:00
Edward Z. Yang
0ead9558b4 Finish up to BOM.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@694 48356398-32a2-884e-a903-53898d9a118a
2007-01-24 01:29:25 +00:00
Edward Z. Yang
159a1cced1 Complete HTML Purifier segment.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@693 48356398-32a2-884e-a903-53898d9a118a
2007-01-23 03:27:10 +00:00
Edward Z. Yang
6871a54d64 Release 1.4.1.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@687 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 21:47:18 +00:00
Edward Z. Yang
96ac7e8797 [1.4.1] docs/enduser-youtube.html updated according to new functionality and YouTube IDs can have underscores and dashes
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@686 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 21:45:14 +00:00
Edward Z. Yang
2d49299621 Release 1.4.0.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@680 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 17:24:18 +00:00
Edward Z. Yang
ab5c782c77 Actually fix it.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@679 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 17:12:45 +00:00
Edward Z. Yang
8893b87e04 Fix call-time pass-by-reference.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@678 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 17:10:24 +00:00
Edward Z. Yang
aeef746060 Add 1000 passes image.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@677 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 16:45:01 +00:00
Edward Z. Yang
da13c6ac87 Further update TODO.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@676 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 16:17:34 +00:00
Edward Z. Yang
ccae73c25a Update TODO, remove caching: it won't help our memory usage or speed.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@674 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 15:23:42 +00:00
Edward Z. Yang
8d6bfa4037 [1.4.0] YouTube preservation code added to the core by adding HTMLPurifier_Filter hierarchy.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@673 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 15:09:07 +00:00
Edward Z. Yang
712d81ebea [1.4.0] Config object can now be instantiated from ini files. Also updated TODO.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@672 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 14:29:46 +00:00
Edward Z. Yang
f7f6fed86a [1.4.0] Revamp ConfigTest.php. Factor out tallyErrors() to its own function.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@671 48356398-32a2-884e-a903-53898d9a118a
2007-01-21 04:37:02 +00:00
Edward Z. Yang
2293c67eec [1.4.0] Revamp ConfigSchema tests, add more error checking.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@670 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 22:59:20 +00:00
Edward Z. Yang
108df87824 Migrate from assertError to expectError, removed all assertNoErrors()
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@669 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 19:22:55 +00:00
Edward Z. Yang
5e366b25f8 [1.4.0] Support for configuration directive aliases added.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@668 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 18:43:58 +00:00
Edward Z. Yang
2e16c4a968 Replaced version check with functionality check for DOM
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@667 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 15:07:48 +00:00
Edward Z. Yang
a8db22dfff Update docs, esp in context of soon to be added tag transforms.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@666 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 03:59:07 +00:00
Edward Z. Yang
fbe2c25f8a Update progress doc with more info. Fix some comments.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@665 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 03:48:39 +00:00
Edward Z. Yang
158be61def Update TODO.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@664 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 02:28:51 +00:00
Edward Z. Yang
d693c4ea09 [1.4.0] Implement 'background' shorthand CSS property.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@663 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 02:21:43 +00:00
Edward Z. Yang
c24916e1d6 Update progress doc.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@662 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 01:46:37 +00:00
Edward Z. Yang
a68b6afda1 [1.4.0] CSS property background-position implemented. Also:
- Fixed some misinformation in Percentage
- Add support for lowercase CSS length units

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@661 48356398-32a2-884e-a903-53898d9a118a
2007-01-20 01:40:56 +00:00
Edward Z. Yang
78cf7db82e Refactor index.php test runner, it was getting too big.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@660 48356398-32a2-884e-a903-53898d9a118a
2007-01-19 23:26:15 +00:00
Edward Z. Yang
9b375fdfb8 [1.4.0] Added convenient single test selector form on test runner
- Also fixed includes in test files
- Updated TODO with CSS plans

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@659 48356398-32a2-884e-a903-53898d9a118a
2007-01-19 23:02:28 +00:00
Edward Z. Yang
0dd866cc15 [1.4.0]
- Added %Core.EscapeNonASCIICharacters to workaround %Core.Encoding misbehavior
- Add "All Tests" to test runner title and reorder subfile names
- Specific file is now called with ?f=
- Link to UTF-8 docs, even though they're not done
- 1000th unit test passed! W00t! (that's a third as many as SimpleTest has for itself.)

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@658 48356398-32a2-884e-a903-53898d9a118a
2007-01-19 03:54:55 +00:00
Edward Z. Yang
ad1169c711 [1.4.0] Make all functions in Encoder static. Affects branches/strict
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@656 48356398-32a2-884e-a903-53898d9a118a
2007-01-18 22:55:44 +00:00
Edward Z. Yang
2816ae535f Link docs back to HTML Purifier home page.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@655 48356398-32a2-884e-a903-53898d9a118a
2007-01-18 22:38:40 +00:00
Edward Z. Yang
462d3ab72f [1.4.0] Add some nicer styling to the configuration documentation. Also update NEWS.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@654 48356398-32a2-884e-a903-53898d9a118a
2007-01-18 02:52:20 +00:00
Edward Z. Yang
cf1d868782 [1.4.0] Add some docs to printDefinition smoketest.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@653 48356398-32a2-884e-a903-53898d9a118a
2007-01-18 02:05:39 +00:00
Edward Z. Yang
c705e17a58 + Well Supported
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@652 48356398-32a2-884e-a903-53898d9a118a
2007-01-17 03:07:51 +00:00
Edward Z. Yang
1cce367950 [1.4.0] Add all smoketest file using iframes.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@651 48356398-32a2-884e-a903-53898d9a118a
2007-01-16 22:29:11 +00:00
Edward Z. Yang
61f852d429 Merge in PHP5 strict changes that are applicable to PHP4.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@650 48356398-32a2-884e-a903-53898d9a118a
2007-01-16 22:22:08 +00:00
Edward Z. Yang
3a73c2cf04 Fix some XHTML 1.0 conformance issues.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@646 48356398-32a2-884e-a903-53898d9a118a
2007-01-15 20:06:35 +00:00
Edward Z. Yang
e75b676656 Done up to Forms.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@645 48356398-32a2-884e-a903-53898d9a118a
2007-01-15 19:18:17 +00:00
Edward Z. Yang
b53370efbf Update progress doc.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@644 48356398-32a2-884e-a903-53898d9a118a
2007-01-15 01:16:25 +00:00
Edward Z. Yang
d60f345cab [1.4.0] Implemented background-image, background-repeat and background-attachment CSS properties. background shorthand property HAS NOT been extended to allow these, and background-position IS NOT implemented yet.
- Also: fixed up some flaky behavior in list-style shorthand, introduced uri_or_none

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@643 48356398-32a2-884e-a903-53898d9a118a
2007-01-15 01:14:24 +00:00
Edward Z. Yang
aefda60696 [1.4.0] Refactored ListStyle, since list-style-image was sort of tacked on and didn't really conform with the standard. Implementation is still a little flaky but conforms with W3C's validation service.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@642 48356398-32a2-884e-a903-53898d9a118a
2007-01-15 00:48:54 +00:00
Edward Z. Yang
2ffa5d3135 Update progress doc.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@641 48356398-32a2-884e-a903-53898d9a118a
2007-01-14 16:26:47 +00:00
Edward Z. Yang
23d3490d49 [1.4.0] Implemented list-style-image, URIs now allowed in list-style
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@640 48356398-32a2-884e-a903-53898d9a118a
2007-01-14 16:24:02 +00:00
Edward Z. Yang
582ffc4143 [1.4.0] Implemented AttrDef_CSSURI for url(http://google.com) style declarations
- 1.3.3 release downgraded to "not likely"

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@639 48356398-32a2-884e-a903-53898d9a118a
2007-01-14 15:54:05 +00:00
Edward Z. Yang
d52189a19d Complete info on fixing embedded encodings. Will discuss UTF-8 next.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@638 48356398-32a2-884e-a903-53898d9a118a
2007-01-14 02:31:54 +00:00
Edward Z. Yang
02006d6e64 Commit initial draft of UTF-8 document. Incomplete.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@637 48356398-32a2-884e-a903-53898d9a118a
2007-01-13 03:58:02 +00:00
Edward Z. Yang
dcaa374dae [1.3.3] Random miscellaneous housekeeping
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@636 48356398-32a2-884e-a903-53898d9a118a
2007-01-11 22:37:54 +00:00
Edward Z. Yang
e2cc37724b [1.3.3]
- Move SLOW to docs/enduser-slow.html and add code examples
- Update README and WYSIWYG
- Add warning to HTMLPurifier.func.php about naming similarities

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@635 48356398-32a2-884e-a903-53898d9a118a
2007-01-11 22:28:44 +00:00
Edward Z. Yang
3ad6239dc3 Remove useless $init assignment.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@634 48356398-32a2-884e-a903-53898d9a118a
2007-01-07 23:55:55 +00:00
Edward Z. Yang
663fb4e1b2 Add TODO item to INSTALL for new array syntax for configuration.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@627 48356398-32a2-884e-a903-53898d9a118a
2006-12-26 17:40:05 +00:00
396 changed files with 4936 additions and 26054 deletions

1100
Doxyfile

File diff suppressed because it is too large Load Diff

203
INSTALL
View File

@@ -2,55 +2,63 @@
Install Install
How to install HTML Purifier How to install HTML Purifier
HTML Purifier is designed to run out of the box, so actually using the HTML Purifier is designed to run out of the box, so actually using the library
library is extremely easy. (Although... if you were looking for a is extremely easy. (Although, if you were looking for a step-by-step
step-by-step installation GUI, you've downloaded the wrong software!) installation GUI, you've come to the wrong place!) The impatient can scroll
down to the bottom of this INSTALL document to see the code, but you really
should make sure a few things are properly done.
While the impatient can get going immediately with some of the sample Todo: Convert to using the array syntax for configuration.
code at the bottom of this library, it's well worth performing some
basic sanity checks to get the most out of this library.
---------------------------------------------------------------------------
1. Compatibility 1. Compatibility
HTML Purifier works in both PHP 4 and PHP 5, and is actively tested from HTML Purifier works in both PHP 4 and PHP 5, from PHP 4.3.9 and up. It has no
PHP 4.3.7 and up (see tests/multitest.php for specific versions). It has core dependencies with other libraries. (Whoopee!)
no core dependencies with other libraries. PHP 4 support will be
deprecated on December 31, 2007, at which time only essential security
fixes will be issued for the PHP 4 version until August 8, 2008.
These optional extensions can enhance the capabilities of HTML Purifier: Optional extensions are iconv (usually installed) and tidy (also common).
If you use UTF-8 and don't plan on pretty-printing HTML, you can get away with
* iconv : Converts text to and from non-UTF-8 encodings not having either of these extensions.
* tidy : Used for pretty-printing HTML
---------------------------------------------------------------------------
2. Reconnaissance
A big plus of HTML Purifier is its inerrant support of standards, so 2. Including the library
your web-pages should be standards-compliant. (They should also use
semantic markup, but that's another issue altogether, one HTML Purifier
cannot fix without reading your mind.)
HTML Purifier can process these doctypes: Simply use:
require_once '/path/to/library/HTMLPurifier.auto.php';
...and you're good to go. Since HTML Purifier's codebase is fairly
large, I recommend only including HTML Purifier when you need it.
If you don't like your include_path to be fiddled around with, simply set
HTML Purifier's library/ directory to the include path yourself and then:
require_once 'HTMLPurifier.php';
Only the contents in the library/ folder are necessary, so you can remove
everything else when using HTML Purifier in a production environment.
3. Preparing the proper output environment
HTML Purifier is all about web-standards, so accordingly your webpages should
be standards compliant. HTML Purifier can deal with these doctypes:
* XHTML 1.0 Transitional (default) * XHTML 1.0 Transitional (default)
* XHTML 1.0 Strict * XHTML 1.0 Strict
* HTML 4.01 Transitional * HTML 4.01 Transitional
* HTML 4.01 Strict * HTML 4.01 Strict
* XHTML 1.1
...and these character encodings: ...and these character encodings:
* UTF-8 (default) * UTF-8 (default)
* Any encoding iconv supports (with crippled internationalization support) * Any encoding iconv supports (support is crippled for i18n though)
These defaults reflect what my choices where be if I were authoring an The defaults are there for a reason: they are best-practice choices that
HTML document, however, what you choose depends on the nature of your should not be changed lightly. For those of you in the dark, you can determine
codebase. If you don't know what doctype you are using, you can determine the doctype from this code in your HTML documents:
the doctype from this identifier at the top of your source code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
@@ -59,34 +67,18 @@ the doctype from this identifier at the top of your source code:
<meta http-equiv="Content-type" content="text/html;charset=ENCODING"> <meta http-equiv="Content-type" content="text/html;charset=ENCODING">
If the character encoding declaration is missing, STOP NOW, and For legacy codebases these declarations may be missing. If that is the case,
read 'docs/enduser-utf8.html' (web accessible at STOP, and read up on character encodings and doctypes (in that order). Here
http://htmlpurifier.org/docs/enduser-utf8.html). In fact, even if it is are some links:
present, read this document anyway, as most websites specify character
encoding incorrectly. * http://www.joelonsoftware.com/articles/Unicode.html
* http://alistapart.com/stories/doctype/
You may currently be vulnerable to XSS and other security threats, and HTML
Purifier won't be able to fix that.
---------------------------------------------------------------------------
3. Including the library
The procedure is quite simple:
require_once '/path/to/library/HTMLPurifier.auto.php';
I recommend only including HTML Purifier when you need it, because that
call represents the inclusion of a lot of PHP files which constitute
the bulk of HTML Purifier's memory usage.
If you don't like your include_path to be fiddled around with, simply set
HTML Purifier's library/ directory to the include path yourself and then:
require_once 'HTMLPurifier.php';
Only the contents in the library/ folder are necessary, so you can remove
everything else when using HTML Purifier in a production environment.
---------------------------------------------------------------------------
4. Configuration 4. Configuration
HTML Purifier is designed to run out-of-the-box, but occasionally HTML HTML Purifier is designed to run out-of-the-box, but occasionally HTML
@@ -103,6 +95,7 @@ object and read on:
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();
4.1. Setting a different character encoding 4.1. Setting a different character encoding
You really shouldn't use any other encoding except UTF-8, especially if you You really shouldn't use any other encoding except UTF-8, especially if you
@@ -123,26 +116,28 @@ websites):
Note that HTML Purifier's support for non-Unicode encodings is crippled by the Note that HTML Purifier's support for non-Unicode encodings is crippled by the
fact that any character not supported by that encoding will be silently fact that any character not supported by that encoding will be silently
dropped, EVEN if it is ampersand escaped. If you want to work around dropped, EVEN if it is ampersand escaped. This is a current limitation of
this, you are welcome to read docs/enduser-utf8.html for a fix, HTML Purifier that we are NOT actively working to fix. Patches are welcome,
but please be cognizant of the issues the "solution" creates (for this but there are so many other gotchas and problems in I18N for non-Unicode
reason, I do not include the solution in this document). encodings that this functionality is low priority. See
<http://ppewww.ph.gla.ac.uk/~flavell/charset/form-i18n.html> for a more
detailed lowdown on the topic.
4.2. Setting a different doctype 4.2. Setting a different doctype
For those of you using HTML 4.01 Transitional, you can disable For those of you stuck using HTML 4.01 Transitional, you can disable
XHTML output like this: XHTML output like this:
$config->set('HTML', 'Doctype', 'HTML 4.01 Transitional'); $config->set('Core', 'XHTML', false);
Other supported doctypes include: I recommend that you use XHTML, although not as much as I recommend UTF-8. If
your HTML 4.01 page validates, good for you!
Currently, we can only guarantee transitional-complaint output, future
versions will also allow strict-compliant output.
* HTML 4.01 Strict
* HTML 4.01 Transitional
* XHTML 1.0 Strict
* XHTML 1.0 Transitional
* XHTML 1.1
4.3. Other settings 4.3. Other settings
@@ -150,66 +145,11 @@ Other supported doctypes include:
There are more configuration directives which can be read about There are more configuration directives which can be read about
here: <http://htmlpurifier.org/live/configdoc/plain.html> They're a bit boring, here: <http://htmlpurifier.org/live/configdoc/plain.html> They're a bit boring,
but they can help out for those of you who like to exert maximum control over but they can help out for those of you who like to exert maximum control over
your code. Some of the more interesting ones are configurable at the your code.
demo <http://htmlpurifier.org/demo.php> and are well worth looking into
for your own system.
For example, you can fine tune allowed elements and attributes, convert
relative URLs to absolute ones, and even autoparagraph input text! These
are, respectively, %HTML.Allowed, %URI.MakeAbsolute and %URI.Base, and
%AutoFormat.AutoParagraph. The %Namespace.Directive naming convention
translates to:
$config->set('Namespace', 'Directive', $value);
E.g.
$config->set('HTML', 'Allowed', 'p,b,a[href],i');
$config->set('URI', 'Base', 'http://www.example.com');
$config->set('URI', 'MakeAbsolute', true);
$config->set('AutoFormat', 'AutoParagraph', true);
---------------------------------------------------------------------------
5. Caching
HTML Purifier generates some cache files (generally one or two) to speed up 5. Using the code
its execution. For maximum performance, make sure that
library/HTMLPurifier/DefinitionCache/Serializer is writeable by the webserver.
If you are in the library/ folder of HTML Purifier, you can set the
appropriate permissions using:
chmod -R 0755 HTMLPurifier/DefinitionCache/Serializer
If the above command doesn't work, you may need to assign write permissions
to all. This may be necessary if your webserver runs as nobody, but is
not recommended since it means any other user can write files in the
directory. Use:
chmod -R 0777 HTMLPurifier/DefinitionCache/Serializer
You can also chmod files via your FTP client; this option
is usually accessible by right clicking the corresponding directory and
then selecting "chmod" or "file permissions".
Starting with 2.0.1, HTML Purifier will generate friendly error messages
that will tell you exactly what you have to chmod the directory to, if in doubt,
follow its advice.
If you are unable or unwilling to give write permissions to the cache
directory, you can either disable the cache (and suffer a performance
hit):
$config->set('Core', 'DefinitionCache', null);
Or move the cache directory somewhere else (no trailing slash):
$config->set('Cache', 'SerializerPath', '/home/user/absolute/path');
---------------------------------------------------------------------------
6. Using the code
The interface is mind-numbingly simple: The interface is mind-numbingly simple:
@@ -222,15 +162,13 @@ The interface is mind-numbingly simple:
$clean_html = $purifier->purify( $dirty_html ); $clean_html = $purifier->purify( $dirty_html );
That's it! For more examples, check out docs/examples/ (they aren't very That's it! For more examples, check out docs/examples/ (they aren't very
different though). Also, docs/enduser-slow.html gives advice on what to different though). Also, SLOW gives advice on what to do if HTML Purifier
do if HTML Purifier is slowing down your application. is slowing down your application.
---------------------------------------------------------------------------
7. Quick install
First, make sure library/HTMLPurifier/DefinitionCache/Serializer is 6. Quick install
writable by the webserver (see Section 5: Caching above for details).
If your website is in UTF-8 and XHTML Transitional, use this code: If your website is in UTF-8 and XHTML Transitional, use this code:
<?php <?php
@@ -246,10 +184,9 @@ If your website is in a different encoding or doctype, use this code:
require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php'; require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();
$config->set('Core', 'Encoding', 'ISO-8859-1'); // replace with your encoding $config->set('Core', 'Encoding', 'ISO-8859-1'); //replace with your encoding
$config->set('HTML', 'Doctype', 'HTML 4.01 Transitional'); // replace with your doctype $config->set('Core', 'XHTML', true); //replace with false if HTML 4.01
$purifier = new HTMLPurifier($config); $purifier = new HTMLPurifier($config);
$clean_html = $purifier->purify($dirty_html); $clean_html = $purifier->purify($dirty_html);
?> ?>

View File

@@ -17,7 +17,7 @@ ce document pour quelques choses.
1. Compatibilité 1. Compatibilité
HTML Purifier fonctionne dans PHP 4 et PHP 5. PHP 4.3.2 est le dernier HTML Purifier fonctionne dans PHP 4 et PHP 5. PHP 4.3.9 est le dernier
version que je le testais. Il ne dépend de les autre librairies. version que je le testais. Il ne dépend de les autre librairies.
Les extensions optionnel est iconv (en général déjà installer) et Les extensions optionnel est iconv (en général déjà installer) et

244
NEWS
View File

@@ -9,245 +9,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
. Internal change . Internal change
========================== ==========================
2.1.3, released 2007-11-05 1.7.0, unknown release date
! tests/multitest.php allows you to test multiple versions by running
tests/index.php through multiple interpreters using `phpv` shell
script (you must provide this script!)
- Fixed poor include ordering for Email URI AttrDefs, causes fatal errors
on some systems.
- Injector algorithm further refined: off-by-one error regarding skip
counts for dormant injectors fixed
- Corrective blockquote definition now enabled for HTML 4.01 Strict
- Fatal error when <img> tag (or any other element with required attributes)
has 'id' attribute fixed, thanks NykO18 for reporting
- Fix warning emitted when a non-supported URI scheme is passed to the
MakeAbsolute URIFilter, thanks NykO18 (again)
- Further refine AutoParagraph injector. Behavior inside of elements
allowing paragraph tags clarified: only inline content delimeted by
double newlines (not block elements) are paragraphed.
- Buggy treatment of end tags of elements that have required attributes
fixed (does not manifest on default tag-set)
- Spurious internal content reorganization error suppressed
- HTMLDefinition->addElement now returns a reference to the created
element object, as implied by the documentation
- Phorum mod's HTML Purifier help message expanded (unreleased elsewhere)
- Fix a theoretical class of infinite loops from DirectLex reported
by Nate Abele
- Work around unnecessary DOMElement type-cast in PH5P that caused errors
in PHP 5.1
- Work around PHP 4 SimpleTest lack-of-error complaining for one-time-only
HTMLDefinition errors, this may indicate problems with error-collecting
facilities in PHP 5
- Make ErrorCollectorEMock work in both PHP 4 and PHP 5
- Make PH5P work with PHP 5.0 by removing unnecessary array parameter typedef
. %Core.AcceptFullDocuments renamed to %Core.ConvertDocumentToFragment
to better communicate its purpose
. Error unit tests can now specify the expectation of no errors. Future
iterations of the harness will be extremely strict about what errors
are allowed
. Extend Injector hooks to allow for more powerful injector routines
. HTMLDefinition->addBlankElement created, as according to the HTMLModule
method
. Doxygen configuration file updated, with minor improvements
. Test runner now checks for similarly named files in conf/ directory too.
. Minor cosmetic change to flush-definition-cache.php: trailing newline is
outputted
. Maintenance script for generating PH5P patch added, original PH5P source
file also added under version control
. Full unit test runner script title made more descriptive with PHP version
. Updated INSTALL file to state that 4.3.7 is the earliest version we
are actively testing
2.1.2, released 2007-09-03
! Implemented Object module for trusted users
! Implemented experimental HTML5 parsing mode using PH5P. To use, add
this to your code:
require_once 'HTMLPurifier/Lexer/PH5P.php';
$config->set('Core', 'LexerImpl', 'PH5P');
Note that this Lexer introduces some classes not in the HTMLPurifier
namespace. Also, this is PHP5 only.
! CSS property border-spacing implemented
- Fix non-visible parsing error in DirectLex with empty tags that have
slashes inside attribute values.
- Fix typo in CSS definition: border-collapse:seperate; was incorrectly
accepted as valid CSS. Usually non-visible, because this styling is the
default for tables in most browsers. Thanks Brett Zamir for pointing
this out.
- Fix validation errors in configuration form
- Hammer out a bunch of edge-case bugs in the standalone distribution
- Inclusion reflection removed from URISchemeRegistry; you must manually
include any new schema files you wish to use
- Numerous typo fixes in documentation thanks to Brett Zamir
. Unit test refactoring for one logical test per test function
. Config and context parameters in ComplexHarness deprecated: instead, edit
the $config and $context member variables
. HTML wrapper in DOMLex now takes DTD identifiers into account; doesn't
really make a difference, but is good for completeness sake
. merge-library.php script refactored for greater code reusability and
PHP4 compatibility
2.1.1, released 2007-08-04
- Fix show-stopper bug in %URI.MakeAbsolute functionality
- Fix PHP4 syntax error in standalone version
. Add prefix directory to include path for standalone, this prevents
other installations from clobbering the standalone's URI schemes
. Single test methods can be invoked by prefixing with __only
2.1.0, released 2007-08-02
# flush-htmldefinition-cache.php superseded in favor of a generic
flush-definition-cache.php script, you can clear a specific cache
by passing its name as a parameter to the script
! Phorum mod implemented for HTML Purifier
! With %Core.AggressivelyFixLt, <3 and similar emoticons no longer
trigger HTML removal in PHP5 (DOMLex). This directive is not necessary
for PHP4 (DirectLex).
! Standalone file now available, which greatly reduces the amount of
includes (although there are still a few files that reside in the
standalone folder)
! Relative URIs can now be transformed into their absolute equivalents
using %URI.Base and %URI.MakeAbsolute
! Ruby implemented for XHTML 1.1
! You can now define custom URI filtering behavior, see enduser-uri-filter.html
for more details
! UTF-8 font names now supported in CSS
- AutoFormatters emit friendly error messages if tags or attributes they
need are not allowed
- ConfigForm's compactification of directive names is now configurable
- AutoParagraph autoformatter algorithm refined after field-testing
- XHTML 1.1 now applies XHTML 1.0 Strict cleanup routines, namely
blockquote wrapping
- Contents of <style> tags removed by default when tags are removed
. HTMLPurifier_Config->getSerial() implemented, this is extremely useful
for output cache invalidation
. ConfigForm printer now can retrieve CSS and JS files as strings, in
case HTML Purifier's directory is not publically accessible
. Introduce new text/itext configuration directive values: these represent
longer strings that would be more appropriately edited with a textarea
. Allow newlines to act as separators for lists, hashes, lookups and
%HTML.Allowed
. ConfigForm generates textareas instead of text inputs for lists, hashes,
lookups, text and itext fields
. Hidden element content removal genericized: %Core.HiddenElements can
be used to customize this behavior, by default <script> and <style> are
hidden
. Added HTMLPURIFIER_PREFIX constant, should be used instead of dirname(__FILE__)
. Custom ChildDef added to default include list
. URIScheme reflection improved: will not attempt to include file if class
already exists. May clobber autoload, so I need to keep an eye on it
. ConfigSchema heavily optimized, will only collect information and validate
definitions when HTMLPURIFIER_SCHEMA_STRICT is true.
. AttrDef_URI unit tests and implementation refactored
. benchmarks/ directory now protected from public view with .htaccess file;
run the tests via command line
. URI scheme is munged off if there is no authority and the scheme is the
default one
. All unit tests inherit from HTMLPurifier_Harness, not UnitTestCase
. Interface for URIScheme changed
. Generic URI object to hold components of URI added, most systems involved
in URI validation have been migrated to use it
. Custom filtering for URIs factored out to URIDefinition interface for
maximum extensibility
2.0.1, released 2007-06-27
! Tag auto-closing now based on a ChildDef heuristic rather than a
manually set auto_close array; some behavior may change
! Experimental AutoFormat functionality added: auto-paragraph and
linkify your HTML input by setting %AutoFormat.AutoParagraph and
%AutoFormat.Linkify to true
! Newlines normalized internally, and then converted back to the
value of PHP_EOL. If this is not desired, set your newline format
using %Output.Newline.
! Beta error collection, messages are implemented for the most generic
cases involving Lexing or Strategies
- Clean up special case code for <script> tags
- Reorder includes for DefinitionCache decorators, fixes a possible
missing class error
- Fixed bug where manually modified definitions were not saved via cache
(mostly harmless, except for the fact that it would be a little slower)
- Configuration objects with different serials do not clobber each
others when revision numbers are unequal
- Improve Serializer DefinitionCache directory permissions checks
- DefinitionCache no longer throws errors when it encounters old
serial files that do not conform to the current style
- Stray xmlns attributes removed from configuration documentation
- configForm.php smoketest no longer has XSS vulnerability due to
unescaped print_r output
- Printer adheres to configuration's directives on output format
- Fix improperly named form field in ConfigForm printer
. Rewire some test-cases to swallow errors rather than expect them
. HTMLDefinition printer updated with some of the new attributes
. DefinitionCache keys reordered to reflect precedence: version number,
hash, then revision number
. %Core.DefinitionCache renamed to %Cache.DefinitionImpl
. Interlinking in configuration documentation added using
Injector_PurifierLinkify
. Directives now keep track of aliases to themselves
. Error collector now requires a severity to be passed, use PHP's internal
error constants for this
. HTMLPurifier_Config::getAllowedDirectivesForForm implemented, allows
much easier selective embedding of configuration values
. Doctype objects now accept public and system DTD identifiers
. %HTML.Doctype is now constrained by specific values, to specify a custom
doctype use new %HTML.CustomDoctype
. ConfigForm truncates long directives to keep the form small, and does
not re-output namespaces
2.0.0, released 2007-06-20
# Completely refactored HTMLModuleManager, decentralizing safety
information
# Transform modules changed to Tidy modules, which offer more flexibility
and better modularization
# Configuration object now finalizes itself when a read operation is
performed on it, ensuring that its internal state stays consistent.
To revert this behavior, you can set the $autoFinalize member variable
off, but it's not recommended.
# New compact syntax for AttrDef objects that can be used to instantiate
new objects via make()
# Definitions (esp. HTMLDefinition) are now cached for a significant
performance boost. You can disable caching by setting %Core.DefinitionCache
to null. You CANNOT edit raw definitions without setting the corresponding
DefinitionID directive (%HTML.DefinitionID for HTMLDefinition).
# Contents between <script> tags are now completely removed if <script>
is not allowed
# Prototype-declarations for Lexer removed in favor of configuration
determination of Lexer implementations.
! HTML Purifier now works in PHP 4.3.2.
! Configuration form-editing API makes tweaking HTMLPurifier_Config a
breeze!
! Configuration directives that accept hashes now allow new string
format: key1:value1,key2:value2
! ConfigDoc now factored into OOP design
! All deprecated elements now natively supported
! Implement TinyMCE styled whitelist specification format in
%HTML.Allowed
! Config object gives more friendly error messages when things go wrong
! Advanced API implemented: easy functions for creating elements (addElement)
and attributes (addAttribute) on HTMLDefinition
! Add native support for required attributes
- Deprecated and removed EnableRedundantUTF8Cleaning. It didn't even work!
- DOMLex will not emit errors when a custom error handler that does not
honor error_reporting is used
- StrictBlockquote child definition refrains from wrapping whitespace
in tags now.
- Bug resulting from tag transforms to non-allowed elements fixed
- ChildDef_Custom's regex generation has been improved, removing several
false positives
. Unit test for ElementDef created, ElementDef behavior modified to
be more flexible
. Added convenience functions for HTMLModule constructors
. AttrTypes now has accessor functions that should be used instead
of directly manipulating info
. TagTransform_Center deprecated in favor of generic TagTransform_Simple
. Add extra protection in AttrDef_URI against phantom Schemes
. Doctype object added to HTMLDefinition which describes certain aspects
of the operational document type
. Lexer is now pre-emptively included, with a conditional include for the
PHP5 only version.
. HTMLDefinition and CSSDefinition have a common parent class: Definition.
. DirectLex can now track line-numbers
. Preliminary error collector is in place, although no code actually reports
errors yet
. Factor out most of ValidateAttributes to new AttrValidator class
1.6.1, released 2007-05-05 1.6.1, released 2007-05-05
! Support for more deprecated attributes via transformations: ! Support for more deprecated attributes via transformations:
@@ -299,7 +61,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
- Error messages are emitted when you attempt to "allow" elements or - Error messages are emitted when you attempt to "allow" elements or
attributes that HTML Purifier does not support attributes that HTML Purifier does not support
1.5.1, unknown release date
- Fix segfault in unit test. The problem is not very reproduceable and - Fix segfault in unit test. The problem is not very reproduceable and
I don't know what causes it, but a six line patch fixed it. I don't know what causes it, but a six line patch fixed it.
@@ -498,4 +260,4 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
! First public release, most functionality implemented. Notable omissions are: ! First public release, most functionality implemented. Notable omissions are:
+ Shorthand CSS properties + Shorthand CSS properties
+ Table CSS properties + Table CSS properties
+ Deprecated attribute transformations + Deprecated attribute transformations

81
TODO
View File

@@ -1,3 +1,4 @@
TODO List TODO List
= KEY ==================== = KEY ====================
@@ -6,15 +7,33 @@ TODO List
? Maybe I'll Do It ? Maybe I'll Do It
========================== ==========================
If no interest is expressed for a feature that may required a considerable 1.7 release [Advanced API]
amount of effort to implement, it may get endlessly delayed. Do not be # Complete advanced API, and fully document it
afraid to cast your vote for the next feature to be implemented! # Implement all edge-case attribute transforms
# Implement all deprecated tags and attributes
- Parse TinyMCE-style whitelist into our %HTML.Allow* whitelists (possibly
do this earlier)
? HTML interface for tweaking configuration to see changes
2.2 release [Error'ed] 1.8 release [Refactor, refactor!]
# URI validation routines tighter (see docs/dev-code-quality.html) (COMPLEX)
# Advanced URI filtering schemes (see docs/proposal-new-directives.txt)
- Configuration profiles: predefined directives set with one func call
- Implement IDREF support (harder than it seems, since you cannot have
IDREFs to non-existent IDs)
- Allow non-ASCII characters in font names
1.9 release [Error'ed]
# Error logging for filtering/cleanup procedures # Error logging for filtering/cleanup procedures
- Requires I18N facilities to be created first (COMPLEX)
- XSS-attempt detection - XSS-attempt detection
- More fine-grained control over escaping behavior
- Silently drop content inbetween SCRIPT tags (can be generalized to allow
specification of elements that, when detected as foreign, trigger removal
of children, although unbalanced tags could wreck havoc (or at least
delete the rest of the document)).
2.3 release [Do What I Mean, Not What I Say] 1.10 release [Do What I Mean, Not What I Say]
# Additional support for poorly written HTML # Additional support for poorly written HTML
- Microsoft Word HTML cleaning (i.e. MsoNormal, but research essential!) - Microsoft Word HTML cleaning (i.e. MsoNormal, but research essential!)
- Friendly strict handling of <address> (block -> <br>) - Friendly strict handling of <address> (block -> <br>)
@@ -28,61 +47,49 @@ afraid to cast your vote for the next feature to be implemented!
- Remove empty inline tags<i></i> - Remove empty inline tags<i></i>
- Append something to duplicate IDs so they're still usable (impl. note: the - Append something to duplicate IDs so they're still usable (impl. note: the
dupe detector would also need to detect the suffix as well) dupe detector would also need to detect the suffix as well)
- Externalize inline CSS to promote clean HTML
2.4 release [It's All About Trust] (floating) 2.0 release [Beyond HTML]
# Implement untrusted, dangerous elements/attributes
# 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
3.0 release [Beyond HTML]
# Legit token based CSS parsing (will require revamping almost every # Legit token based CSS parsing (will require revamping almost every
AttrDef class). Probably will use CSSTidy class AttrDef class)
# More control over allowed CSS properties (maybe modularize it in the # Formatters for plaintext (COMPLEX)
same fashion!) - Auto-paragraphing (be sure to leverage fact that we know when things
# Formatters for plaintext shouldn't be paragraphed, such as lists and tables).
- Linkify URLs
- Smileys - Smileys
- Standardize token armor for all areas of processing - Linkification for HTML Purifier docs: notably configuration and classes
- Allow tags to be "armored", an internal flag that protects them
from validation and passes them out unharmed
- Fixes for Firefox's inability to handle COL alignment props (Bug 915)
- Automatically add non-breaking spaces to empty table cells when
empty-cells:show is applied to have compatibility with Internet Explorer
- Convert RTL/LTR override characters to <bdo> tags, or vice versa on demand. - Convert RTL/LTR override characters to <bdo> tags, or vice versa on demand.
Also, enable disabling of directionality Also, enable disabling of directionality
4.0 release [To XML and Beyond] 3.0 release [To XML and Beyond]
- Extended HTML capabilities based on namespacing and tag transforms (COMPLEX) - Extended HTML capabilities based on namespacing and tag transforms (COMPLEX)
- Hooks for adding custom processors to custom namespaced tags and - Hooks for adding custom processors to custom namespaced tags and
attributes, offer default implementation attributes, offer default implementation
- Lots of documentation and samples - Lots of documentation and samples
- XHTML 1.1 support
Ongoing Ongoing
- Lots of profiling, make it faster! - Lots of profiling, make it faster!
- Plugins for major CMSes (COMPLEX) - Plugins for major CMSes (COMPLEX)
- phpBB - WordPress (mostly written, needs beta-testing)
- eFiction - eFiction
- more! (look for ones that use WYSIWYGs) - more! (look for ones that use WYSIWYGs)
- Complete basic smoketests
Unknown release (on a scratch-an-itch basis) Unknown release (on a scratch-an-itch basis)
# CHMOD install script for PEAR installs ? Semi-lossy dumb alternate character encoding transfor
? Have 'lang' attribute be checked against official lists, achieved by ? Have 'lang' attribute be checked against official lists, achieved by
encoding all characters that have string entity equivalents encoding all characters that have string entity equivalents
- Abstract ChildDef_BlockQuote to work with all elements that only - Explain how to use HTML Purifier in non-PHP languages
allow blocks in them, required or optional
- Reorganize Unit Tests
- Reorganize configuration directives (Create more namespaces! Get messy!)
- Advanced URI filtering schemes (see docs/proposal-new-directives.txt)
- Implement lenient <ruby> child validation
- Explain how to use HTML Purifier in non-PHP languages / create
a simple command line stub (or complicated?)
- Fixes for Firefox's inability to handle COL alignment props (Bug 915)
- Automatically add non-breaking spaces to empty table cells when
empty-cells:show is applied to have compatibility with Internet Explorer
Requested Requested
? Native content compression, whitespace stripping (don't rely on Tidy, make
sure we don't remove from <pre> or related tags)
Wontfix Wontfix
- Non-lossy smart alternate character encoding transformations (unless - Non-lossy smart alternate character encoding transformations (unless
patch provided) patch provided)
- Pretty-printing HTML: users can use Tidy on the output on entire page - Pretty-printing HTML, users can use Tidy on the output on entire page
- Native content compression, whitespace stripping (don't rely on Tidy, make
sure we don't remove from <pre> or related tags): use gzip if this is
really important

View File

@@ -1 +1 @@
2.1.3 1.6.1

View File

@@ -1,6 +1,7 @@
Stability release 2.1.3 fixes a slew of minor bugs found in HTML Purifier, The 1.6.1 release, code-named 'Ach! We missed something! Run!', completes
and also includes some internal code enhancements and refactorings. HTML Purifier's roster of attribute transformations. It also implements
Notably, tests/multitest.php automates testing in multiple versions, a number of minor features (such as better font transformations, smarter
fatal AttrDef_URI_Email error fixed, blockquote contents are more lenient HTML parsing, the CSS property 'white-space' and XHTML 1.1), a few bug
in HTML 4.01 Strict and fatal errors involving ID tags in img tags were fixes (most notably fixed __autoload compatibility issues) and a ton
fixed. of refactoring. 1.6 was for things that absolutely could not wait: this
release, developed in a more leisurely pace, fills in the gaps.

View File

@@ -16,3 +16,7 @@ trouble. Therein lies the solution:
HTML Purifier is perfect for filtering pure-HTML input from WYSIWYG editors. HTML Purifier is perfect for filtering pure-HTML input from WYSIWYG editors.
Enough said. Enough said.
There is a proof-of-concept integration of HTML Purifier with the Mantis
bugtracker at http://hp.jpsband.org/mantis/ You can see notes on how
this integration was acheived at http://hp.jpsband.org/mantis_notes.txt

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1 +0,0 @@
Deny from all

View File

@@ -165,4 +165,4 @@ echo '<div>Random input was: ' .
?> ?>
</body></html> </body></html>

View File

@@ -15,3 +15,5 @@ $context = new HTMLPurifier_Context();
for ($i = 0; $i < 10; $i++) { for ($i = 0; $i < 10; $i++) {
$tokens = $lexer->tokenizeHTML($input, $config, $context); $tokens = $lexer->tokenizeHTML($input, $config, $context);
} }
?>

View File

@@ -1,12 +0,0 @@
<?php
ini_set('xdebug.trace_format', 1);
ini_set('xdebug.show_mem_delta', true);
xdebug_start_trace(dirname(__FILE__) . '/Trace');
require_once '../library/HTMLPurifier.auto.php';
$purifier = new HTMLPurifier();
$data = $purifier->purify(file_get_contents('samples/Lexer/4.html'));
xdebug_stop_trace();

View File

@@ -2,44 +2,218 @@
/** /**
* Generates XML and HTML documents describing configuration. * Generates XML and HTML documents describing configuration.
* @note PHP 5 only!
*/ */
/* /*
TODO: TODO:
- make XML format richer (see XMLSerializer_ConfigSchema) - make XML format richer (see below)
- extend XSLT transformation (see the corresponding XSLT file) - extend XSLT transformation (see the corresponding XSLT file)
- allow generation of packaged docs that can be easily moved - allow generation of packaged docs that can be easily moved
- multipage documentation - multipage documentation
- determine how to multilingualize - determine how to multilingualize
- add blurbs to ToC - factor out code into classes
*/ */
// ---------------------------------------------------------------------------
// Check and configure environment
if (version_compare('5', PHP_VERSION, '>')) exit('Requires PHP 5 or higher.'); if (version_compare('5', PHP_VERSION, '>')) exit('Requires PHP 5 or higher.');
error_reporting(E_ALL); // probably not possible to use E_STRICT error_reporting(E_ALL);
define('HTMLPURIFIER_SCHEMA_STRICT', true); // description data needs to be collected
// load dual-libraries // ---------------------------------------------------------------------------
// Include HTML Purifier library
require_once '../library/HTMLPurifier.auto.php'; require_once '../library/HTMLPurifier.auto.php';
require_once 'library/ConfigDoc.auto.php';
$purifier = HTMLPurifier::getInstance(array(
'AutoFormat.PurifierLinkify' => true // ---------------------------------------------------------------------------
)); // Setup convenience functions
function appendHTMLDiv($document, $node, $html) {
global $purifier;
$html = $purifier->purify($html);
$dom_html = $document->createDocumentFragment();
$dom_html->appendXML($html);
$dom_div = $document->createElement('div');
$dom_div->setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
$dom_div->appendChild($dom_html);
$node->appendChild($dom_div);
}
// ---------------------------------------------------------------------------
// Load copies of HTMLPurifier_ConfigDef and HTMLPurifier
$schema = HTMLPurifier_ConfigSchema::instance(); $schema = HTMLPurifier_ConfigSchema::instance();
$style = 'plain'; // use $_GET in the future $purifier = new HTMLPurifier();
$configdoc = new ConfigDoc();
$output = $configdoc->generate($schema, $style);
// write out
file_put_contents("$style.html", $output); // ---------------------------------------------------------------------------
// Generate types.xml, a document describing the constraint "type"
$types_document = new DOMDocument('1.0', 'UTF-8');
$types_root = $types_document->createElement('types');
$types_document->appendChild($types_root);
$types_document->formatOutput = true;
foreach ($schema->types as $name => $expanded_name) {
$types_type = $types_document->createElement('type', $expanded_name);
$types_type->setAttribute('id', $name);
$types_root->appendChild($types_type);
}
$types_document->save('types.xml');
// ---------------------------------------------------------------------------
// Generate configdoc.xml, a document documenting configuration directives
$dom_document = new DOMDocument('1.0', 'UTF-8');
$dom_root = $dom_document->createElement('configdoc');
$dom_document->appendChild($dom_root);
$dom_document->formatOutput = true;
// add the name of the application
$dom_root->appendChild($dom_document->createElement('title', 'HTML Purifier'));
/*
TODO for XML format:
- create a definition (DTD or other) once interface stabilizes
*/
foreach($schema->info as $namespace_name => $namespace_info) {
$dom_namespace = $dom_document->createElement('namespace');
$dom_root->appendChild($dom_namespace);
$dom_namespace->setAttribute('id', $namespace_name);
$dom_namespace->appendChild(
$dom_document->createElement('name', $namespace_name)
);
$dom_namespace_description = $dom_document->createElement('description');
$dom_namespace->appendChild($dom_namespace_description);
appendHTMLDiv($dom_document, $dom_namespace_description,
$schema->info_namespace[$namespace_name]->description);
foreach ($namespace_info as $name => $info) {
if ($info->class == 'alias') continue;
$dom_directive = $dom_document->createElement('directive');
$dom_namespace->appendChild($dom_directive);
$dom_directive->setAttribute('id', $namespace_name . '.' . $name);
$dom_directive->appendChild(
$dom_document->createElement('name', $name)
);
$dom_constraints = $dom_document->createElement('constraints');
$dom_directive->appendChild($dom_constraints);
$dom_type = $dom_document->createElement('type', $info->type);
if ($info->allow_null) {
$dom_type->setAttribute('allow-null', 'yes');
}
$dom_constraints->appendChild($dom_type);
if ($info->allowed !== true) {
$dom_allowed = $dom_document->createElement('allowed');
$dom_constraints->appendChild($dom_allowed);
foreach ($info->allowed as $allowed => $bool) {
$dom_allowed->appendChild(
$dom_document->createElement('value', $allowed)
);
}
}
$raw_default = $schema->defaults[$namespace_name][$name];
if (is_bool($raw_default)) {
$default = $raw_default ? 'true' : 'false';
} elseif (is_string($raw_default)) {
$default = "\"$raw_default\"";
} elseif (is_null($raw_default)) {
$default = 'null';
} else {
$default = print_r(
$schema->defaults[$namespace_name][$name], true
);
}
$dom_default = $dom_document->createElement('default', $default);
// remove this once we get a DTD
$dom_default->setAttribute('xml:space', 'preserve');
$dom_constraints->appendChild($dom_default);
$dom_descriptions = $dom_document->createElement('descriptions');
$dom_directive->appendChild($dom_descriptions);
foreach ($info->descriptions as $file => $file_descriptions) {
foreach ($file_descriptions as $line => $description) {
$dom_description = $dom_document->createElement('description');
$dom_description->setAttribute('file', $file);
$dom_description->setAttribute('line', $line);
appendHTMLDiv($dom_document, $dom_description, $description);
$dom_descriptions->appendChild($dom_description);
}
}
}
}
// print_r($dom_document->saveXML());
// save a copy of the raw XML
$dom_document->save('configdoc.xml');
// ---------------------------------------------------------------------------
// Generate final output using XSLT
// load the stylesheet
$xsl_stylesheet_name = 'plain';
$xsl_stylesheet = "styles/$xsl_stylesheet_name.xsl";
$xsl_dom_stylesheet = new DOMDocument();
$xsl_dom_stylesheet->load($xsl_stylesheet);
// setup the XSLT processor
$xsl_processor = new XSLTProcessor();
// perform the transformation
$xsl_processor->importStylesheet($xsl_dom_stylesheet);
$html_output = $xsl_processor->transformToXML($dom_document);
// some slight fudges to preserve backwards compatibility
$html_output = str_replace('/>', ' />', $html_output); // <br /> not <br/>
$html_output = str_replace(' xmlns=""', '', $html_output); // rm unnecessary xmlns
if (class_exists('Tidy')) {
// cleanup output
$config = array(
'indent' => true,
'output-xhtml' => true,
'wrap' => 80
);
$tidy = new Tidy;
$tidy->parseString($html_output, $config, 'utf8');
$tidy->cleanRepair();
$html_output = (string) $tidy;
}
// write it to a file (todo: parse into seperate pages)
file_put_contents("$xsl_stylesheet_name.html", $html_output);
// ---------------------------------------------------------------------------
// Output for instant feedback
if (php_sapi_name() != 'cli') { if (php_sapi_name() != 'cli') {
// output = instant feedback echo $html_output;
echo $output;
} else { } else {
echo 'Files generated successfully.'; echo 'Files generated successfully.';
} }
?>

View File

@@ -1,9 +0,0 @@
<?php
/**
* This is a stub include that automatically configures the include path.
*/
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() );
require_once 'ConfigDoc.php';

View File

@@ -1,38 +0,0 @@
<?php
require_once 'ConfigDoc/HTMLXSLTProcessor.php';
require_once 'ConfigDoc/XMLSerializer/Types.php';
require_once 'ConfigDoc/XMLSerializer/ConfigSchema.php';
class ConfigDoc
{
function generate($schema, $xsl_stylesheet_name = 'plain', $parameters = array()) {
// generate types document, describing type constraints
$types_serializer = new ConfigDoc_XMLSerializer_Types();
$types_document = $types_serializer->serialize($schema);
$types_document->save(dirname(__FILE__) . '/../types.xml'); // only ONE
// generate configdoc.xml, documents configuration directives
$schema_serializer = new ConfigDoc_XMLSerializer_ConfigSchema();
$schema_document = $schema_serializer->serialize($schema);
$schema_document->save('configdoc.xml');
// setup transformation
$xsl_stylesheet = dirname(__FILE__) . "/../styles/$xsl_stylesheet_name.xsl";
$xslt_processor = new ConfigDoc_HTMLXSLTProcessor();
$xslt_processor->setParameters($parameters);
$xslt_processor->importStylesheet($xsl_stylesheet);
return $xslt_processor->transformToHTML($schema_document);
}
/**
* Remove any generated files
*/
function cleanup() {
unlink('configdoc.xml');
}
}

View File

@@ -1,62 +0,0 @@
<?php
/**
* Special XSLTProcessor specifically for HTML documents. Loosely
* based off of XSLTProcessor, but not really
*/
class ConfigDoc_HTMLXSLTProcessor
{
protected $xsltProcessor;
public function __construct() {
$this->xsltProcessor = new XSLTProcessor();
}
/**
* Imports stylesheet for processor to use
* @param $xsl XSLT DOM tree, or filename of the XSL transformation
*/
public function importStylesheet($xsl) {
if (is_string($xsl)) {
$xsl_file = $xsl;
$xsl = new DOMDocument();
$xsl->load($xsl_file);
}
return $this->xsltProcessor->importStylesheet($xsl);
}
/**
* Transforms an XML file into HTML based on the stylesheet
* @param $xml XML DOM tree
*/
public function transformToHTML($xml) {
$out = $this->xsltProcessor->transformToXML($xml);
// fudges for HTML backwards compatibility
$out = str_replace('/>', ' />', $out); // <br /> not <br/>
$out = str_replace(' xmlns=""', '', $out); // rm unnecessary xmlns
$out = str_replace(' xmlns="http://www.w3.org/1999/xhtml"', '', $out); // rm unnecessary xmlns
if (class_exists('Tidy')) {
// cleanup output
$config = array(
'indent' => true,
'output-xhtml' => true,
'wrap' => 80
);
$tidy = new Tidy;
$tidy->parseString($out, $config, 'utf8');
$tidy->cleanRepair();
$out = (string) $tidy;
}
return $out;
}
public function setParameters($options) {
foreach ($options as $name => $value) {
$this->xsltProcessor->setParameter('', $name, $value);
}
}
}

View File

@@ -1,25 +0,0 @@
<?php
/**
* The XMLSerializer hierarchy of classes consist of classes that take
* objects and serialize them into XML, specifically DOM, form; this
* super-class contains convenience functions for those classes.
*/
class ConfigDoc_XMLSerializer
{
protected function appendHTMLDiv($document, $node, $html) {
$purifier = HTMLPurifier::getInstance();
$html = $purifier->purify($html);
$dom_html = $document->createDocumentFragment();
$dom_html->appendXML($html);
$dom_div = $document->createElement('div');
$dom_div->setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
$dom_div->appendChild($dom_html);
$node->appendChild($dom_div);
}
}

View File

@@ -1,123 +0,0 @@
<?php
require_once 'ConfigDoc/XMLSerializer.php';
class ConfigDoc_XMLSerializer_ConfigSchema extends ConfigDoc_XMLSerializer
{
/**
* Serializes a schema into DOM form
* @todo Split into sub-serializers
* @param $schema HTMLPurifier_ConfigSchema to serialize
*/
public function serialize($schema) {
$dom_document = new DOMDocument('1.0', 'UTF-8');
$dom_root = $dom_document->createElement('configdoc');
$dom_document->appendChild($dom_root);
$dom_document->formatOutput = true;
// add the name of the application
$dom_root->appendChild($dom_document->createElement('title', 'HTML Purifier'));
/*
TODO for XML format:
- create a definition (DTD or other) once interface stabilizes
*/
foreach($schema->info as $namespace_name => $namespace_info) {
$dom_namespace = $dom_document->createElement('namespace');
$dom_root->appendChild($dom_namespace);
$dom_namespace->setAttribute('id', $namespace_name);
$dom_namespace->appendChild(
$dom_document->createElement('name', $namespace_name)
);
$dom_namespace_description = $dom_document->createElement('description');
$dom_namespace->appendChild($dom_namespace_description);
$this->appendHTMLDiv($dom_document, $dom_namespace_description,
$schema->info_namespace[$namespace_name]->description);
foreach ($namespace_info as $name => $info) {
if ($info->class == 'alias') continue;
$dom_directive = $dom_document->createElement('directive');
$dom_namespace->appendChild($dom_directive);
$dom_directive->setAttribute('id', $namespace_name . '.' . $name);
$dom_directive->appendChild(
$dom_document->createElement('name', $name)
);
$dom_aliases = $dom_document->createElement('aliases');
$dom_directive->appendChild($dom_aliases);
foreach ($info->directiveAliases as $alias) {
$dom_aliases->appendChild($dom_document->createElement('alias', $alias));
}
$dom_constraints = $dom_document->createElement('constraints');
$dom_directive->appendChild($dom_constraints);
$dom_type = $dom_document->createElement('type', $info->type);
if ($info->allow_null) {
$dom_type->setAttribute('allow-null', 'yes');
}
$dom_constraints->appendChild($dom_type);
if ($info->allowed !== true) {
$dom_allowed = $dom_document->createElement('allowed');
$dom_constraints->appendChild($dom_allowed);
foreach ($info->allowed as $allowed => $bool) {
$dom_allowed->appendChild(
$dom_document->createElement('value', $allowed)
);
}
}
$raw_default = $schema->defaults[$namespace_name][$name];
if (is_bool($raw_default)) {
$default = $raw_default ? 'true' : 'false';
} elseif (is_string($raw_default)) {
$default = "\"$raw_default\"";
} elseif (is_null($raw_default)) {
$default = 'null';
} else {
$default = print_r(
$schema->defaults[$namespace_name][$name], true
);
}
$dom_default = $dom_document->createElement('default', $default);
// remove this once we get a DTD
$dom_default->setAttribute('xml:space', 'preserve');
$dom_constraints->appendChild($dom_default);
$dom_descriptions = $dom_document->createElement('descriptions');
$dom_directive->appendChild($dom_descriptions);
foreach ($info->descriptions as $file => $file_descriptions) {
foreach ($file_descriptions as $line => $description) {
$dom_description = $dom_document->createElement('description');
// refuse to write $file if it's a full path
if (str_replace('\\', '/', realpath($file)) != $file) {
$dom_description->setAttribute('file', $file);
$dom_description->setAttribute('line', $line);
}
$this->appendHTMLDiv($dom_document, $dom_description, $description);
$dom_descriptions->appendChild($dom_description);
}
}
}
}
return $dom_document;
}
}

View File

@@ -1,26 +0,0 @@
<?php
require_once 'ConfigDoc/XMLSerializer.php';
class ConfigDoc_XMLSerializer_Types extends ConfigDoc_XMLSerializer
{
/**
* Serializes the types in a schema into DOM form
* @param $schema HTMLPurifier_ConfigSchema owner of types to serialize
*/
public function serialize($schema) {
$types_document = new DOMDocument('1.0', 'UTF-8');
$types_root = $types_document->createElement('types');
$types_document->appendChild($types_root);
$types_document->formatOutput = true;
foreach ($schema->types as $name => $expanded_name) {
$types_type = $types_document->createElement('type', $expanded_name);
$types_type->setAttribute('id', $name);
$types_root->appendChild($types_type);
}
return $types_document;
}
}

View File

@@ -12,21 +12,19 @@
indent = "no" indent = "no"
media-type = "text/html" media-type = "text/html"
/> />
<xsl:param name="css" select="'styles/plain.css'"/>
<xsl:param name="title" select="'Configuration Documentation'"/>
<xsl:variable name="typeLookup" select="document('../types.xml')" /> <xsl:variable name="typeLookup" select="document('../types.xml')" />
<xsl:template match="/"> <xsl:template match="/">
<html lang="en" xml:lang="en"> <html lang="en" xml:lang="en">
<head> <head>
<title><xsl:value-of select="$title" /> - <xsl:value-of select="/configdoc/title" /></title> <title>Configuration Documentation - <xsl:value-of select="/configdoc/title" /></title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="{$css}" /> <link rel="stylesheet" type="text/css" href="styles/plain.css" />
</head> </head>
<body> <body>
<div id="library"><xsl:value-of select="/configdoc/title" /></div> <div id="library"><xsl:value-of select="/configdoc/title" /></div>
<h1><xsl:value-of select="$title" /></h1> <h1>Configuration Documentation</h1>
<h2>Table of Contents</h2> <h2>Table of Contents</h2>
<ul id="toc"> <ul id="toc">
<xsl:apply-templates mode="toc" /> <xsl:apply-templates mode="toc" />
@@ -72,45 +70,23 @@
<xsl:apply-templates /> <xsl:apply-templates />
</xsl:template> </xsl:template>
<xsl:template match="directive/name"> <xsl:template match="directive/name">
<xsl:apply-templates select="../aliases/alias" mode="anchor" />
<h3 id="{../@id}"><xsl:value-of select="../@id" /></h3> <h3 id="{../@id}"><xsl:value-of select="../@id" /></h3>
</xsl:template> </xsl:template>
<xsl:template match="alias" mode="anchor">
<a id="{.}"></a>
</xsl:template>
<!-- Do not pass through -->
<xsl:template match="alias"></xsl:template>
<xsl:template match="directive/constraints"> <xsl:template match="directive/constraints">
<table class="constraints"> <table class="constraints">
<xsl:apply-templates /> <xsl:apply-templates />
<!-- Calculated other values --> <!-- Calculated other values -->
<xsl:if test="../descriptions/description[@file]"> <tr>
<tr> <th>Used by:</th>
<th>Used by:</th> <td>
<td> <xsl:for-each select="../descriptions/description">
<xsl:for-each select="../descriptions/description"> <xsl:if test="position()&gt;1">, </xsl:if>
<xsl:if test="position()&gt;1">, </xsl:if> <xsl:value-of select="@file" />
<xsl:value-of select="@file" /> </xsl:for-each>
</xsl:for-each> </td>
</td> </tr>
</tr>
</xsl:if>
<xsl:if test="../aliases/alias">
<xsl:apply-templates select="../aliases" mode="constraints" />
</xsl:if>
</table> </table>
</xsl:template> </xsl:template>
<xsl:template match="directive/aliases" mode="constraints">
<th>Aliases:</th>
<td>
<xsl:for-each select="alias">
<xsl:if test="position()&gt;1">, </xsl:if>
<xsl:value-of select="." />
</xsl:for-each>
</td>
</xsl:template>
<xsl:template match="directive//description"> <xsl:template match="directive//description">
<div class="description"> <div class="description">
<xsl:copy-of select="div/node()" /> <xsl:copy-of select="div/node()" />
@@ -148,4 +124,4 @@
</tr> </tr>
</xsl:template> </xsl:template>
</xsl:stylesheet> </xsl:stylesheet>

View File

@@ -17,12 +17,9 @@
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div> <div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>HTML Purifier currently natively supports only a subset of HTML's <p>HTML Purifier currently natively supports only a subset of HTML's
allowed elements, attributes, and behavior; specifically, this subset allowed elements, attributes, and behavior. This is by design,
is the set of elements that are safe for untrusted users to use. but as the user is always right, they'll need some method to overload
However, HTML Purifier is often utilized to ensure standards-compliance these behaviors.</p>
from input that is trusted (making it a sort of Tidy substitute),
and often users need to define new elements or attributes. The
advanced API is oriented specifically for these use-cases.</p>
<p>Our goals are to let the user:</p> <p>Our goals are to let the user:</p>
@@ -30,15 +27,20 @@ advanced API is oriented specifically for these use-cases.</p>
<dt>Select</dt> <dt>Select</dt>
<dd><ul> <dd><ul>
<li>Doctype</li> <li>Doctype</li>
<!-- <li>Filterset</li> --> <li>Mode: Lenient / Correctional</li>
<li>Elements / Attributes / Modules</li> <li>Elements / Attributes / Modules</li>
<li>Tidy</li> <li>Filterset</li>
</ul></dd> </ul></dd>
<dt>Customize</dt> <dt>Customize</dt>
<dd><ul> <dd><ul>
<li>Attributes</li> <li>Attributes</li>
<li>Elements</li> <li>Elements</li>
<!--<li>Doctypes</li>--> </ul></dd>
<dt>Internals</dt>
<dd><ul>
<li>Modules / Elements / Attributes / Attribute Types</li>
<li>Filtersets</li>
<li>Doctype</li>
</ul></dd> </ul></dd>
</dl> </dl>
@@ -66,64 +68,136 @@ Transitional, however, we really shouldn't be guessing what the user's
doctype is. Fortunantely, people who can't be bothered to set this won't doctype is. Fortunantely, people who can't be bothered to set this won't
be bothered when their pages stop validating.</p> be bothered when their pages stop validating.</p>
<h3>Selecting Mode</h3>
<p>Within doctypes, there are various <strong>modes</strong> of operation.
These indicate variant behaviors that, while not strictly changing the
allowed set of elements and attributes, definitely affect the output.
Currently, we have two modes, which may be used together:</p>
<dl>
<dt>Lenient</dt>
<dd>
<p>Deprecated elements and attributes will be transformed into
standards-compliant alternatives when explicitly disallowed.</p>
<p>For example, in the XHTML 1.0 Strict doctype, a <code>center</code>
element would be turned into a <code>div</code> with the CSS property
<code>text-align:center;</code>, but in XHTML 1.0 Transitional
the element would be preserved.</p>
<p>This mode is on by default.</p>
</dd>
<dt>Correctional[items to correct]</dt>
<dd>
<p>Deprecated elements and attributes will be transformed into
standards-compliant alternatives whenever possible.
It may have various levels of operation.</p>
<p>Referring back to the previous example, the <code>center</code> element would
be transformed in both cases. However, elements without a
reasonable standards-compliant alternative will be preserved
in their form.</p>
<p>A user may want to correct certain deprecated attributes, but
not others. For example, the <code>bgcolor</code> attribute may be
acceptable, but the <code>center</code> element not; also, possibly,
an HTML Purifier transformation may be buggy, so the user wants
to forgo it. Thus, correctional accepts an array defining which
elements and attributes to cleanup, or no parameter at all, which
means everything gets corrected. This also means that each
correction needs to be given a unique ID that can be referenced
in this manner. (We may also allow globbing, like *.name or a.*
for mass-enabling correction, and subtractive mode, where things
specified stop correction.) This array gets passed into the
constructor of the mode's module.</p>
<p>This mode is on by default.</p>
</dd>
</dl>
<p>A possible call to select modes would be:</p>
<pre>$config->set('HTML', 'Mode', array('correctional', 'lenient'));</pre>
<p>If modes have extra parameters, a hash is necessary:</p>
<pre>$config->set('HTML', 'Mode', array(
'correctional' => 'center,a.name',
'lenient' => true // this one's just boolean
));</pre>
<p>Modes may be specified along with the doctype declaration (we may want
to get a better set of separator characters):</p>
<pre>$config->setDoctype('XHTML Transitional 1.0', '+correctional[center,a.name] -lenient');</pre>
<p>
With regards to the various levels of operation conjectured in the
Correctional mode, this is prompted by the fact that a user may want to
correct certain problems but not others, for example, fix the <code>center</code>
element but not the <code>u</code> element, both of which are deprecated.
Having an integer <q>level</q> will not work very well for such fine
grained tweaking, but an array of specific settings might.</p>
<h3>Selecting Elements / Attributes / Modules</h3> <h3>Selecting Elements / Attributes / Modules</h3>
<p>HTML Purifier will, by default, allow as many elements and attributes <p></p>
as possible. However, a user may decide to roll their own filterset by
selecting modules, elements and attributes to allow for their own
specific use-case. This can be done using %HTML.Allowed:</p>
<pre>$config->set('HTML', 'Allowed', 'a[href|title],em,p,blockquote');</pre> <p>If this cookie cutter approach doesn't appeal to a user, they may
decide to roll their own filterset by selecting modules, elements and
attributes to allow.</p>
<p class="technical">The directive %HTML.Allowed is a convenience feature <p class="technical">This would make use of the same facilities
that may be fully expressed with the legacy interface.</p> as a filterset author would use, except that it would go under an
<q>anonymous</q> filterset that would be auto-selected if any of the
relevant module/elements/attribute selection configuration directives were
non-null.</p>
<p>We currently support another interface from older versions:</p> <p>In practice, this is the most commonly demanded feature. Most users are
perfectly happy defining a filterset that looks like:</p>
<pre>$config->setAllowedHTML('a[href,title];em;p;blockquote');</pre>
<p class="technical">The directive %HTML.Allowed is a convenience function
that may be fully expressed with the legacy interface, and thus is
given its own setter.</p>
<p>We currently support a separated interface, which also must be preserved:</p>
<pre>$config->set('HTML', 'AllowedElements', 'a,em,p,blockquote'); <pre>$config->set('HTML', 'AllowedElements', 'a,em,p,blockquote');
$config->set('HTML', 'AllowedAttributes', 'a.href,a.title');</pre> $config->set('HTML', 'AllowedAttributes', 'a.href,a.title');</pre>
<p>A user may also choose to allow modules using a specialized <p>A user may also choose to allow modules:</p>
directive:</p>
<pre>$config->set('HTML', 'AllowedModules', 'Hypertext,Text,Lists');</pre> <pre>$config->set('HTML', 'AllowedModules', 'Hypertext,Text,Lists'); // or
$config->setAllowedHTML('Hypertext,Text,Lists');</pre>
<p>But it is not expected that this feature will be widely used.</p> <p>But it is not expected that this feature will be widely used.</p>
<p class="technical">Module selection will work slightly differently <p class="fixme">The granularity of these modules is too coarse for
from the other AllowedElements and AllowedAttributes directives by the average user (for example, the core module loads everything from
directly modifying the doctype you are operating in, in the spirit of the essential <code>p</code> element to the not-so-safe <code>h1</code>
XHTML 1.1's modularization. We stop users from shooting themselves in the element). How do we make this still a viable solution? Possible answers
foot by mandating the modules in %HTML.CoreModules be used.</p> may be sub-modules or module parameters. This may not even be a problem,
considering that most people won't be selecting modules.</p>
<p class="technical">Modules are distinguished from regular elements by the <p class="technical">Modules are distinguished from regular elements by the
case of their first letter. While XML distinguishes between and allows case of their first letter. While XML distinguishes between and allows
lower and uppercase letters in element names, XHTML uses only lower-case lower and uppercase letters in element names, most well-known XML
languages use only lower-case
element names for sake of consistency.</p> element names for sake of consistency.</p>
<h3>Selecting Tidy</h3> <p class="technical">Considering that, internally speaking, as mandated by
the XHTML 1.1 Modularization specification, we have organized our
elements around modules, considerable gymnastics will be needed to
get this sort of functionality working.</p>
<p>The name of this segment of functionality is inspired off of Dave
Ragget's program HTML Tidy, which purported to help clean up HTML. In
HTML Purifier, Tidy functionality involves turning unsupported and
deprecated elements into standards-compliant ones, maintaining
backwards compatibility, and enforcing best practices.</p>
<p>This is a complicated feature, and is explained more in depth at
<a href="enduser-tidy.html">the Tidy documentation page</a>.</p>
<!--
<h3>Unified selector</h3> <h3>Unified selector</h3>
<p>Because selecting each and every one of these configuration options <p>Because selecting each and every one of these configuration options
is a chore, we may wish to offer a specialized configuration method is a chore, we may wish to offer a specialized configuration method
for selecting a filterset. Possibility:</p> for selecting a filterset. Possibility:</p>
<pre>function selectFilter($doctype, $filterset, $tidy)</pre> <pre>function selectFilter($doctype, $filterset, $mode)</pre>
<p>...which is simply a light wrapper over the individual configuration <p>...which is simply a light wrapper over the individual configuration
calls. A custom config file format or text format could also be adopted.</p> calls. A custom config file format or text format could also be adopted.</p>
-->
<h2>Customize</h2> <h2>Customize</h2>
@@ -135,34 +209,38 @@ use-cases.</p>
<p>Note that the functions described here are only available if <p>Note that the functions described here are only available if
a raw copy of <code>HTMLPurifier_HTMLDefinition</code> was retrieved. a raw copy of <code>HTMLPurifier_HTMLDefinition</code> was retrieved.
Furthermore, caching may prevent your changes from immediately <code>addAttribute</code> may work on a processed copy, but for
being seen: consult <a href="enduser-customize.html">enduser-customize.html</a> on how consistency's sake we will mandate this for everything.</p>
to work around this.</p>
<h3>Attributes</h3> <h3>Attributes</h3>
<p>An attribute is bound to an element by a name and has a specific <p>An attribute is bound to an element by a name and has a specific
<code>AttrDef</code> that validates it. The interface is therefore:</p> <code>AttrDef</code> that validates it. Thus, the interface should
be:</p>
<pre>function addAttribute($element, $attribute, $attribute_def);</pre> <pre>function addAttribute($element, $attribute, $attribute_def);</pre>
<p>Example of the functionality in action:</p> <p>With a use-case that looks like:</p>
<pre>$def->addAttribute('a', 'rel', 'Enum#nofollow');</pre> <pre>$def->addAttribute('a', 'rel', new HTMLPurifier_AttrDef_Enum(array('nofollow')));</pre>
<p>The <code>$attribute_def</code> value is flexible, <p>The <code>$attribute_def</code> value can be a little flexible,
to make things simpler. It can be a literal object or:</p> to make things simpler. We'll let it also be:</p>
<ul> <ul>
<!--<li>Class name: We'll instantiate it for you</li> <li>Class name: We'll instantiate it for you</li>
<li>Function name: We'll create an <code>HTMLPurifier_AttrDef_Anonymous</code> <li>Function name: We'll create an <code>HTMLPurifier_AttrDef_Anonymous</code>
class with that function registered as a callback.</li>--> class with that function registered as a callback.</li>
<li>String attribute type: We'll use <code>HTMLPurifier_AttrTypes</code> <li>String attribute type: We'll use <code>HTMLPurifier_AttrTypes</code>
to resolve it for you. Any data that follows a hash mark (#) will </li>
be used to customize the attribute type: in the example above, <li>String starting with <code>enum(</code>: We'll explode it and stuff it in an
we specify which values for Enum to allow.</li> <code>HTMLPurifier_AttrDef_Enum</code> for you.</li>
</ul> </ul>
<p>Making the previous example written as:</p>
<pre>$def->addAttribute('a', 'rel', 'enum(nofollow)');</pre>
<h3>Elements</h3> <h3>Elements</h3>
<p>An element requires certain information as specified by <p>An element requires certain information as specified by
@@ -177,8 +255,7 @@ the usual things required are:</p>
<p>This suggests an API like this:</p> <p>This suggests an API like this:</p>
<pre>function addElement($element, $type, $contents, <pre>function addElement($element, $type, $content_model, $attributes = array());</pre>
$attr_collections = array(); $attributes = array());</pre>
<p>Each parameter explained in depth:</p> <p>Each parameter explained in depth:</p>
@@ -187,15 +264,11 @@ the usual things required are:</p>
<dd>Element name, ex. 'label'</dd> <dd>Element name, ex. 'label'</dd>
<dt><code>$type</code></dt> <dt><code>$type</code></dt>
<dd>Content set to register in, ex. 'Inline' or 'Flow'</dd> <dd>Content set to register in, ex. 'Inline' or 'Flow'</dd>
<dt><code>$contents</code></dt> <dt><code>$content_model</code></dt>
<dd>Description of allowed children. This is a merged form of <dd>Description of allowed children. This is a merged form of
<code>HTMLPurifier_ElementDef</code>'s member variables <code>HTMLPurifier_ElementDef</code>'s member variables
<code>$content_model</code> and <code>$content_model_type</code>, <code>$content_model</code> and <code>$content_model_type</code>,
where the form is <q>Type: Model</q>, ex. 'Optional: Inline'. where the form is <q>Type: Model</q>, ex. 'Optional: Inline'.</dd>
There are also a number of predefined templates one may use.</dd>
<dt><code>$attr_collections</code></dt>
<dd>Array (or string if only one) of attribute collection(s) to
merge into the attributes array.</dd>
<dt><code>$attributes</code></dt> <dt><code>$attributes</code></dt>
<dd>Array of attribute names to attribute definitions, much like <dd>Array of attribute names to attribute definitions, much like
the above-described attribute customization.</dd> the above-described attribute customization.</dd>
@@ -203,11 +276,12 @@ the usual things required are:</p>
<p>A possible usage:</p> <p>A possible usage:</p>
<pre>$def->addElement('font', 'Inline', 'Optional: Inline', 'Common', <pre>$def->addElement('font', 'Inline', 'Optional: Inline',
array('color' => 'Color'));</pre> array(0 => array('Common'), 'color' => 'Color'));</pre>
<p>See <code>HTMLPurifier/HTMLModule.php</code> for details.</p> <p>We may want to Common attribute collection inclusion to be added
by default.</p>
<div id="version">$Id$</div> <div id="version">$Id$</div>
</body></html> </body></html>

View File

@@ -11,7 +11,8 @@ docs/examples/demo.php - ad hoc HTML/PHP soup to the extreme
AttrDef - a lot of duplication, more generic classes need to be created; AttrDef - a lot of duplication, more generic classes need to be created;
a lot of strtolower() calls, no legit casing a lot of strtolower() calls, no legit casing
Class - doesn't support Unicode characters (fringe); uses regular expressions Class - doesn't support Unicode characters (fringe); uses regular
expressions
Lang - code duplication; premature optimization Lang - code duplication; premature optimization
Length - easily mistaken for CSSLength Length - easily mistaken for CSSLength
URI - multiple regular expressions; missing validation for parts (?) URI - multiple regular expressions; missing validation for parts (?)
@@ -21,6 +22,9 @@ ConfigSchema - redefinition is a mess
Strategy Strategy
FixNesting - cannot bubble nodes out of structures, duplicated checks FixNesting - cannot bubble nodes out of structures, duplicated checks
for special-case parent node for special-case parent node
MakeWellFormed - insufficient automatic closing definitions (check HTML
spec for optional end tags, also, closing based on type (block/inline)
might be efficient).
RemoveForeignElements - should be run in parallel with MakeWellFormed RemoveForeignElements - should be run in parallel with MakeWellFormed
URIScheme - needs to have callable generic checks URIScheme - needs to have callable generic checks
mailto - doesn't validate emails, doesn't validate querystring mailto - doesn't validate emails, doesn't validate querystring

View File

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

View File

@@ -30,4 +30,4 @@ that itch, put it here!</p>
<div id="version">$Id$</div> <div id="version">$Id$</div>
</body></html> </body></html>

View File

@@ -39,7 +39,7 @@ thead th {text-align:left;padding:0.1em;background-color:#EEE;}
<table cellspacing="0"><tbody> <table cellspacing="0"><tbody>
<tr><td class="impl-yes">Implemented</td></tr> <tr><td class="impl-yes">Implemented</td></tr>
<tr><td class="impl-partial">Partially implemented</td></tr> <tr><td class="impl-partial">Partially implemented</td></tr>
<tr><td class="impl-no">Not priority to implement</td></tr> <tr><td class="impl-no">Will not implement</td></tr>
<tr><td class="danger">Dangerous attribute/property</td></tr> <tr><td class="danger">Dangerous attribute/property</td></tr>
<tr><td class="css1">Present in CSS1</td></tr> <tr><td class="css1">Present in CSS1</td></tr>
<tr><td class="feature">Feature, requires extra work</td></tr> <tr><td class="feature">Feature, requires extra work</td></tr>
@@ -118,7 +118,6 @@ thead th {text-align:left;padding:0.1em;background-color:#EEE;}
<tbody> <tbody>
<tr><th colspan="2">Table</th></tr> <tr><th colspan="2">Table</th></tr>
<tr class="impl-yes"><td>border-collapse</td><td>ENUM(collapse, seperate)</td></tr> <tr class="impl-yes"><td>border-collapse</td><td>ENUM(collapse, seperate)</td></tr>
<tr class="impl-yes"><td>border-space</td><td>MULTIPLE</td></tr>
<tr class="impl-yes"><td>caption-side</td><td>ENUM(top, bottom)</td></tr> <tr class="impl-yes"><td>caption-side</td><td>ENUM(top, bottom)</td></tr>
<tr class="feature"><td>empty-cells</td><td>ENUM(show, hide), No IE support makes this useless, <tr class="feature"><td>empty-cells</td><td>ENUM(show, hide), No IE support makes this useless,
possible fix with &amp;nbsp;? Unknown release milestone.</td></tr> possible fix with &amp;nbsp;? Unknown release milestone.</td></tr>
@@ -300,4 +299,4 @@ Mozilla on inside and needs -moz-outline, no IE support.</td></tr>
<div id="version">$Id$</div> <div id="version">$Id$</div>
</body></html> </body></html>

View File

@@ -1,798 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="description" content="Tutorial for customizing HTML Purifier's tag and attribute sets." />
<link rel="stylesheet" type="text/css" href="style.css" />
<title>Customize - HTML Purifier</title>
</head><body>
<h1 class="subtitled">Customize!</h1>
<div class="subtitle">HTML Purifier is a Swiss-Army Knife</div>
<div id="filing">Filed under End-User</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>
You may have heard of the <a href="dev-advanced-api.html">Advanced API</a>.
If you're interested in reading dry prose and boring functional
specifications, feel free to click that link to get a no-nonsense overview
on the Advanced API. For the rest of us, there's this tutorial. By the time
you're finished reading this, you should have a pretty good idea on
how to implement custom tags and attributes that HTML Purifier may not have.
</p>
<h2>Is it necessary?</h2>
<p>
Before we even write any code, it is paramount to consider whether or
not the code we're writing is necessary or not. HTML Purifier, by default,
contains a large set of elements and attributes: large enough so that
<em>any</em> element or attribute in XHTML 1.0 or 1.1 (and its HTML variants)
that can be safely used by the general public is implemented.
</p>
<p>
So what needs to be implemented? (Feel free to skip this section if
you know what you want).
</p>
<h3>XHTML 1.0</h3>
<p>
All of the modules listed below are based off of the
<a href="http://www.w3.org/TR/2001/REC-xhtml-modularization-20010410/abstract_modules.html#sec_5.2.">modularization of
XHTML</a>, which, while technically for XHTML 1.1, is quite a useful
resource.
</p>
<ul>
<li>Structure</li>
<li>Frames</li>
<li>Applets (deprecated)</li>
<li>Forms</li>
<li>Image maps</li>
<li>Objects</li>
<li>Frames</li>
<li>Events</li>
<li>Meta-information</li>
<li>Style sheets</li>
<li>Link (not hypertext)</li>
<li>Base</li>
<li>Name</li>
</ul>
<p>
If you don't recognize it, you probably don't need it. But the curious
can look all of these modules up in the above-mentioned document. Note
that inline scripting comes packaged with HTML Purifier (more on this
later).
</p>
<h3>XHTML 1.1</h3>
<p>
As of HTMLPurifier 2.1.0, we have implemented the
<a href="http://www.w3.org/TR/2001/REC-ruby-20010531/">Ruby module</a>,
which defines a set of tags
for publishing short annotations for text, used mostly in Japanese
and Chinese school texts, but applicable for positioning any text (not
limited to translations) above or below other corresponding text.
</p>
<h3>XHTML 2.0</h3>
<p>
<a href="http://www.w3.org/TR/xhtml2/">XHTML 2.0</a> is still a
working draft, so any elements introduced in the
specification have not been implemented and will not be implemented
until we get a recommendation or proposal. Because XHTML 2.0 is
an entirely new markup language, implementing rules for it will be
no easy task.
</p>
<h3>HTML 5</h3>
<p>
<a href="http://www.whatwg.org/specs/web-apps/current-work/">HTML 5</a>
is a fork of HTML 4.01 by WHATWG, who believed that XHTML 2.0 was headed
in the wrong direction. It too is a working draft, and may change
drastically before publication, but it should be noted that the
<code>canvas</code> tag has been implemented by many browser vendors.
</p>
<h3>Proprietary</h3>
<p>
There are a number of proprietary tags still in the wild. Many of them
have been documented in <a href="ref-proprietary-tags.txt">ref-proprietary-tags.txt</a>,
but there is currently no implementation for any of them.
</p>
<h3>Extensions</h3>
<p>
There are also a number of other XML languages out there that can
be embedded in HTML documents: two of the most popular are MathML and
SVG, and I frequently get requests to implement these. But they are
expansive, comprehensive specifications, and it would take far too long
to implement them <em>correctly</em> (most systems I've seen go as far
as whitelisting tags and no further; come on, what about nesting!)
</p>
<p>
Word of warning: HTML Purifier is currently <em>not</em> namespace
aware.
</p>
<h2>Giving back</h2>
<p>
As you may imagine from the details above (don't be abashed if you didn't
read it all: a glance over would have done), there's quite a bit that
HTML Purifier doesn't implement. Recent architectural changes have
allowed HTML Purifier to implement elements and attributes that are not
safe! Don't worry, they won't be activated unless you set %HTML.Trusted
to true, but they certainly help out users who need to put, say, forms
on their page and don't want to go through the trouble of reading this
and implementing it themself.
</p>
<p>
So any of the above that you implement for your own application could
help out some other poor sap on the other side of the globe. Help us
out, and send back code so that it can be hammered into a module and
released with the core. Any code would be greatly appreciated!
</p>
<h2>And now...</h2>
<p>
Enough philosophical talk, time for some code:
</p>
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
$def =& $config->getHTMLDefinition(true);</pre>
<p>
Assuming that HTML Purifier has already been properly loaded (hint:
include <code>HTMLPurifier.auto.php</code>), this code will set up
the environment that you need to start customizing the HTML definition.
What's going on?
</p>
<ul>
<li>
The first three lines are regular configuration code:
<ul>
<li>
%HTML.DefinitionID is set to a unique identifier for your
custom HTML definition. This prevents it from clobbering
other custom definitions on the same installation.
</li>
<li>
%HTML.DefinitionRev is a revision integer of your HTML
definition. Because HTML definitions are cached, you'll need
to increment this whenever you make a change in order to flush
the cache.
</li>
</ul>
</li>
<li>
The fourth line retrieves a raw <code>HTMLPurifier_HTMLDefinition</code>
object that we will be tweaking. If the parameter was removed, we
would be retrieving a fully formed definition object, which is somewhat
useless for customization purposes.
</li>
</ul>
<h3>Broken backwards-compatibility</h3>
<p>
Those of you who have already been twiddling around with the raw
HTML definition object, you'll be noticing that you're getting an error
when you attempt to retrieve the raw definition object without specifying
a DefinitionID. It is vital to caching (see below) that you make a unique
name for your customized definition, so make up something right now and
things will operate again.
</p>
<h2>Turn off caching</h2>
<p>
To make development easier, we're going to temporarily turn off
definition caching:
</p>
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
<strong>$config->set('Core', 'DefinitionCache', null); // remove this later!</strong>
$def =& $config->getHTMLDefinition(true);</pre>
<p>
A few things should be mentioned about the caching mechanism before
we move on. For performance reasons, HTML Purifier caches generated
<code>HTMLPurifier_Definition</code> objects in serialized files
stored (by default) in <code>library/HTMLPurifier/DefinitionCache/Serializer</code>.
A lot of processing is done in order to create these objects, so it
makes little sense to repeat the same processing over and over again
whenever HTML Purifier is called.
</p>
<p>
In order to identify a cache entry, HTML Purifier uses three variables:
the library's version number, the value of %HTML.DefinitionRev and
a serial of relevant configuration. Whenever any of these changes,
a new HTML definition is generated. Notice that there is no way
for the definition object to track changes to customizations: here, it
is up to you to supply appropriate information to DefinitionID and
DefinitionRev.
</p>
<h2 id="addAttribute">Add an attribute</h2>
<p>
For this example, we're going to implement the <code>target</code> attribute found
on <code>a</code> elements. To implement an attribute, we have to
ask a few questions:
</p>
<ol>
<li>What element is it found on?</li>
<li>What is its name?</li>
<li>Is it required or optional?</li>
<li>What are valid values for it?</li>
</ol>
<p>
The first three are easy: the element is <code>a</code>, the attribute
is <code>target</code>, and it is not a required attribute. (If it
was required, we'd need to append an asterisk to the attribute name,
you'll see an example of this in the addElement() example).
</p>
<p>
The last question is a little trickier.
Lets allow the special values: _blank, _self, _target and _top.
The form of this is called an <strong>enumeration</strong>, a list of
valid values, although only one can be used at a time. To translate
this into code form, we write:
</p>
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
$config->set('Core', 'DefinitionCache', null); // remove this later!
$def =& $config->getHTMLDefinition(true);
<strong>$def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');</strong></pre>
<p>
The <code>Enum#_blank,_self,_target,_top</code> does all the magic.
The string is split into two parts, separated by a hash mark (#):
</p>
<ol>
<li>The first part is the name of what we call an <code>AttrDef</code></li>
<li>The second part is the parameter of the above-mentioned <code>AttrDef</code></li>
</ol>
<p>
If that sounds vague and generic, it's because it is! HTML Purifier defines
an assortment of different attribute types one can use, and each of these
has their own specialized parameter format. Here are some of the more useful
ones:
</p>
<table class="table">
<thead>
<tr>
<th>Type</th>
<th>Format</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<th>Enum</th>
<td><em>[s:]</em>value1,value2,...</td>
<td>
Attribute with a number of valid values, one of which may be used. When
s: is present, the enumeration is case sensitive.
</td>
</tr>
<tr>
<th>Bool</th>
<td>attribute_name</td>
<td>
Boolean attribute, with only one valid value: the name
of the attribute.
</td>
</tr>
<tr>
<th>CDATA</th>
<td></td>
<td>
Attribute of arbitrary text. Can also be referred to as <strong>Text</strong>
(the specification makes a semantic distinction between the two).
</td>
</tr>
<tr>
<th>ID</th>
<td></td>
<td>
Attribute that specifies a unique ID
</td>
</tr>
<tr>
<th>Pixels</th>
<td></td>
<td>
Attribute that specifies an integer pixel length
</td>
</tr>
<tr>
<th>Length</th>
<td></td>
<td>
Attribute that specifies a pixel or percentage length
</td>
</tr>
<tr>
<th>NMTOKENS</th>
<td></td>
<td>
Attribute that specifies a number of name tokens, example: the
<code>class</code> attribute
</td>
</tr>
<tr>
<th>URI</th>
<td></td>
<td>
Attribute that specifies a URI, example: the <code>href</code>
attribute
</td>
</tr>
<tr>
<th>Number</th>
<td></td>
<td>
Attribute that specifies an positive integer number
</td>
</tr>
</tbody>
</table>
<p>
For a complete list, consult
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/AttrTypes.php"><code>library/HTMLPurifier/AttrTypes.php</code></a>;
more information on attributes that accept parameters can be found on their
respective includes in
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/AttrDef/"><code>library/HTMLPurifier/AttrDef</code></a>.
</p>
<p>
Sometimes, the restrictive list in AttrTypes just doesn't cut it. Don't
sweat: you can also use a fully instantiated object as the value. The
equivalent, verbose form of the above example is:
</p>
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
$config->set('Core', 'DefinitionCache', null); // remove this later!
$def =& $config->getHTMLDefinition(true);
<strong>$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
array('_blank','_self','_target','_top')
));</strong></pre>
<p>
Trust me, you'll learn to love the shorthand.
</p>
<h2>Add an element</h2>
<p>
Adding attributes is really small-fry stuff, though, and it was possible
to add them (albeit a bit more wordy) prior to 2.0. The real gem of
the Advanced API is adding elements. There are five questions to
ask when adding a new element:
</p>
<ol>
<li>What is the element's name?</li>
<li>What content set does this element belong to?</li>
<li>What are the allowed children of this element?</li>
<li>What attributes does the element allow that are general?</li>
<li>What attributes does the element allow that are specific to this element?</li>
</ol>
<p>
It's a mouthful, and you'll be slightly lost if your not familiar with
the HTML specification, so let's explain them step by step.
</p>
<h3>Content set</h3>
<p>
The HTML specification defines two major content sets: Inline
and Block. Each of these
content sets contain a list of elements: Inline contains things like
<code>span</code> and <code>b</code> while Block contains things like
<code>div</code> and <code>blockquote</code>.
</p>
<p>
These content sets amount to a macro mechanism for HTML definition. Most
elements in HTML are organized into one of these two sets, and most
elements in HTML allow elements from one of these sets. If we had
to write each element verbatim into each other element's allowed
children, we would have ridiculously large lists; instead we use
content sets to compactify the declaration.
</p>
<p>
Practically speaking, there are several useful values you can use here:
</p>
<table class="table">
<thead>
<tr>
<th>Content set</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<th>Inline</th>
<td>Character level elements, text</td>
</tr>
<tr>
<th>Block</th>
<td>Block-like elements, like paragraphs and lists</td>
</tr>
<tr>
<th><em>false</em></th>
<td>
Any element that doesn't fit into the mold, for example <code>li</code>
or <code>tr</code>
</td>
</tr>
</tbody>
</table>
<p>
By specifying a valid value here, all other elements that use that
content set will also allow your element, without you having to do
anything. If you specify <em>false</em>, you'll have to register
your element manually.
</p>
<h3>Allowed children</h3>
<p>
Allowed children defines the elements that this element can contain.
The allowed values may range from none to a complex regexp depending on
your element.
</p>
<p>
If you've ever taken a look at the HTML DTD's before, you may have
noticed declarations like this:
</p>
<pre>&lt;!ELEMENT LI - O (%flow;)* -- list item --&gt;</pre>
<p>
The <code>(%flow;)*</code> indicates the allowed children of the
<code>li</code> tag: <code>li</code> allows any number of flow
elements as its children. (The <code>- O</code> allows the closing tag to be
omitted, though in XML this is not allowed.) In HTML Purifier,
we'd write it like <code>Flow</code> (here's where the content sets
we were discussing earlier come into play). There are three shorthand
content models you can specify:
</p>
<table class="table">
<thead>
<tr>
<th>Content model</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<th>Empty</th>
<td>No children allowed, like <code>br</code> or <code>hr</code></td>
</tr>
<tr>
<th>Inline</th>
<td>Any number of inline elements and text, like <code>span</code></td>
</tr>
<tr>
<th>Flow</th>
<td>Any number of inline elements, block elements and text, like <code>div</code></td>
</tr>
</tbody>
</table>
<p>
This covers 90% of all the cases out there, but what about elements that
break the mold like <code>ul</code>? This guy requires at least one
child, and the only valid children for it are <code>li</code>. The
content model is: <code>Required: li</code>. There are two parts: the
first type determines what <code>ChildDef</code> will be used to validate
content models. The most common values are:
</p>
<table class="table">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<th>Required</th>
<td>Children must be one or more of the valid elements</td>
</tr>
<tr>
<th>Optional</th>
<td>Children can be any number of the valid elements</td>
</tr>
<tr>
<th>Custom</th>
<td>Children must follow the DTD-style regex</td>
</tr>
</tbody>
</table>
<p>
You can also implement your own <code>ChildDef</code>: this was done
for a few special cases in HTML Purifier such as <code>Chameleon</code>
(for <code>ins</code> and <code>del</code>), <code>StrictBlockquote</code>
and <code>Table</code>.
</p>
<p>
The second part specifies either valid elements or a regular expression.
Valid elements are separated with horizontal bars (|), i.e.
"<code>a | b | c</code>". Use #PCDATA to represent plain text.
Regular expressions are based off of DTD's style:
</p>
<ul>
<li>Parentheses () are used for grouping</li>
<li>Commas (,) separate elements that should come one after another</li>
<li>Horizontal bars (|) indicate one or the other elements should be used</li>
<li>Plus signs (+) are used for a one or more match</li>
<li>Asterisks (*) are used for a zero or more match</li>
<li>Question marks (?) are used for a zero or one match</li>
</ul>
<p>
For example, "<code>a, b?, (c | d), e+, f*</code>" means "In this order,
one <code>a</code> element, at most one <code>b</code> element,
one <code>c</code> or <code>d</code> element (but not both), one or more
<code>e</code> elements, and any number of <code>f</code> elements."
Regex veterans should be able to jump right in, and those not so savvy
can always copy-paste W3C's content model definitions into HTML Purifier
and hope for the best.
</p>
<p>
A word of warning: while the regex format is extremely flexible on
the developer's side, it is
quite unforgiving on the user's side. If the user input does not <em>exactly</em>
match the specification, the entire contents of the element will
be nuked. This is why there is are specific content model types like
Optional and Required: while they could be implemented as <code>Custom:
(valid | elements)*</code>, the custom classes contain special recovery
measures that make sure as much of the user's original content gets
through. HTML Purifier's core, as a rule, does not use Custom.
</p>
<p>
One final note: you can also use Content Sets inside your valid elements
lists or regular expressions. In fact, the three shorthand content models
mentioned above are just that: abbreviations:
</p>
<table class="table">
<thead>
<tr>
<th>Content model</th>
<th>Implementation</th>
</tr>
</thead>
<tbody>
<tr>
<th>Inline</th>
<td>Optional: Inline | #PCDATA</td>
</tr>
<tr>
<th>Flow</th>
<td>Optional: Flow | #PCDATA</td>
</tr>
</tbody>
</table>
<p>
When the definition is compiled, Inline will be replaced with a
horizontal-bar separated list of inline elements. Also, notice that
it does not contain text: you have to specify that yourself.
</p>
<h3>Common attributes</h3>
<p>
Congratulations: you have just gotten over the proverbial hump (Allowed
children). Common attributes is much simpler, and boils down to
one question: does your element have the <code>id</code>, <code>style</code>,
<code>class</code>, <code>title</code> and <code>lang</code> attributes?
If so, you'll want to specify the <code>Common</code> attribute collection,
which contains these five attributes that are found on almost every
HTML element in the specification.
</p>
<p>
There are a few more collections, but they're really edge cases:
</p>
<table class="table">
<thead>
<tr>
<th>Collection</th>
<th>Attributes</th>
</tr>
</thead>
<tbody>
<tr>
<th>I18N</th>
<td><code>lang</code>, possibly <code>xml:lang</code></td>
</tr>
<tr>
<th>Core</th>
<td><code>style</code>, <code>class</code>, <code>id</code> and <code>title</code></td>
</tr>
</tbody>
</table>
<p>
Common is a combination of the above-mentioned collections.
</p>
<p class="aside">
Readers familiar with the modularization may have noticed that the Core
attribute collection differs from that specified by the <a
href="http://www.w3.org/TR/xhtml-modularization/abstract_modules.html#s_commonatts">abstract
modules of the XHTML Modularization 1.1</a>. We believe this section
to be in error, as <code>br</code> permits the use of the <code>style</code>
attribute even though it uses the <code>Core</code> collection, and
the DTD and XML Schemas supplied by W3C support our interpretation.
</p>
<h3>Attributes</h3>
<p>
If you didn't read the <a href="#addAttribute">earlier section on
adding attributes</a>, read it now. The last parameter is simply
an array of attribute names to attribute implementations, in the exact
same format as <code>addAttribute()</code>.
</p>
<h3>Putting it all together</h3>
<p>
We're going to implement <code>form</code>. Before we embark, lets
grab a reference implementation from over at the
<a href="http://www.w3.org/TR/html4/sgml/loosedtd.html">transitional DTD</a>:
</p>
<pre>&lt;!ELEMENT FORM - - (%flow;)* -(FORM) -- interactive form --&gt;
&lt;!ATTLIST FORM
%attrs; -- %coreattrs, %i18n, %events --
action %URI; #REQUIRED -- server-side form handler --
method (GET|POST) GET -- HTTP method used to submit the form--
enctype %ContentType; &quot;application/x-www-form-urlencoded&quot;
accept %ContentTypes; #IMPLIED -- list of MIME types for file upload --
name CDATA #IMPLIED -- name of form for scripting --
onsubmit %Script; #IMPLIED -- the form was submitted --
onreset %Script; #IMPLIED -- the form was reset --
target %FrameTarget; #IMPLIED -- render in this frame --
accept-charset %Charsets; #IMPLIED -- list of supported charsets --
&gt;</pre>
<p>
Juicy! With just this, we can answer four of our five questions:
</p>
<ol>
<li>What is the element's name? <strong>form</strong></li>
<li>What content set does this element belong to? <strong>Block</strong>
(this needs a little sleuthing, I find the easiest way is to search
the DTD for <code>FORM</code> and determine which set it is in.)</li>
<li>What are the allowed children of this element? <strong>One
or more flow elements, but no nested <code>form</code>s</strong></li>
<li>What attributes does the element allow that are general? <strong>Common</strong></li>
<li>What attributes does the element allow that are specific to this element? <strong>A whole bunch, see ATTLIST;
we're going to the vital ones: <code>action</code>, <code>method</code> and <code>name</code></strong></li>
</ol>
<p>
Time for some code:
</p>
<pre>$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'DefinitionID', 'enduser-customize.html tutorial');
$config->set('HTML', 'DefinitionRev', 1);
$config->set('Core', 'DefinitionCache', null); // remove this later!
$def =& $config->getHTMLDefinition(true);
$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
array('_blank','_self','_target','_top')
));
<strong>$form =& $def->addElement(
'form', // name
'Block', // content set
'Flow', // allowed children
'Common', // attribute collection
array( // attributes
'action*' => 'URI',
'method' => 'Enum#get|post',
'name' => 'ID'
)
);
$form->excludes = array('form' => true);</strong></pre>
<p>
Each of the parameters corresponds to one of the questions we asked.
Notice that we added an asterisk to the end of the <code>action</code>
attribute to indicate that it is required. If someone specifies a
<code>form</code> without that attribute, the tag will be axed.
Also, the extra line at the end is a special extra declaration that
prevents forms from being nested within each other.
</p>
<p>
And that's all there is to it! Implementing the rest of the form
module is left as an exercise to the user; to see more examples
check the <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/HTMLModule/"><code>library/HTMLPurifier/HTMLModule/</code></a> directory
in your local HTML Purifier installation.
</p>
<h2>And beyond...</h2>
<p>
Perceptive users may have realized that, to a certain extent, we
have simply re-implemented the facilities of XML Schema or the
Document Type Definition. What you are seeing here, however, is
not just an XML Schema or Document Type Definition: it is a fully
expressive method of specifying the definition of HTML that is
a portable superset of the capabilities of the two above-mentioned schema
languages. What makes HTMLDefinition so powerful is the fact that
if we don't have an implementation for a content model or an attribute
definition, you can supply it yourself by writing a PHP class.
</p>
<p>
There are many facets of HTMLDefinition beyond the Advanced API I have
walked you through today. To find out more about these, you can
check out these source files:
</p>
<ul>
<li><a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/HTMLModule.php"><code>library/HTMLPurifier/HTMLModule.php</code></a></li>
<li><a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/ElementDef.php"><code>library/HTMLPurifier/ElementDef.php</code></a></li>
</ul>
<div id="version">$Id: enduser-tidy.html 1158 2007-06-18 19:26:29Z Edward $</div>
</body></html>

View File

@@ -58,7 +58,7 @@ appear elsewhere on the document. The method is simple:</p>
<pre>$config->set('HTML', 'EnableAttrID', true); <pre>$config->set('HTML', 'EnableAttrID', true);
$config->set('Attr', 'IDBlacklist' array( $config->set('Attr', 'IDBlacklist' array(
'list', 'of', 'attribute', 'values', 'that', 'are', 'forbidden' 'list', 'of', 'attributes', 'that', 'are', 'forbidden'
));</pre> ));</pre>
<p>That being said, there are some notable drawbacks. First of all, you have to <p>That being said, there are some notable drawbacks. First of all, you have to
@@ -71,9 +71,9 @@ to possible standards-compliance issues.</p>
<p>Furthermore, this position becomes untenable when a single web page must hold <p>Furthermore, this position becomes untenable when a single web page must hold
multiple portions of user-submitted content. Since there's obviously no way multiple portions of user-submitted content. Since there's obviously no way
to find out before-hand what IDs users will use, the blacklist is helpless. to find out before-hand what IDs users will use, the blacklist is helpless.
And since HTML Purifier validates each segment separately, perhaps doing And even since HTML Purifier validates each segment seperately, perhaps doing
so at different times, it would be extremely difficult to dynamically update so at different times, it would be extremely difficult to dynamically update
the blacklist in between runs.</p> the blacklist inbetween runs.</p>
<p>Finally, simply destroying the ID is extremely un-userfriendly behavior: after <p>Finally, simply destroying the ID is extremely un-userfriendly behavior: after
all, they might have simply specified a duplicate ID by accident.</p> all, they might have simply specified a duplicate ID by accident.</p>
@@ -144,4 +144,4 @@ anchors is beyond me.</p>
<div id="version">$Id$</div> <div id="version">$Id$</div>
</body> </body>
</html> </html>

View File

@@ -8,9 +8,15 @@ to be effective. Things to remember:
1. Character Encoding: see enduser-utf8.html for more info. 1. Character Encoding: see enduser-utf8.html for more info.
2. IDs: see enduser-id.html for more info 2. Doctype: document pending feature completion
Not strictly necessary, actually. More in-depth discussion once we figure
out how to get strict loose mode working.
3. URIs: see enduser-uri-filter.html 3. IDs: see enduser-id.html for more info
4. CSS: document pending 4. Links: document pending feature completion
Rudimentary blacklisting, we should also allow only relative URIs. We
need a doc to explain the stuff.
5. CSS: document pending
Explain which CSS styles we blocked and why. Explain which CSS styles we blocked and why.

View File

@@ -114,4 +114,4 @@ if you decide to do that! Especially if you port HTML Purifier to C++.
<tt>;-)</tt></p> <tt>;-)</tt></p>
</body> </body>
</html> </html>

View File

@@ -1,230 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="description" content="Tutorial for tweaking HTML Purifier's Tidy-like behavior." />
<link rel="stylesheet" type="text/css" href="style.css" />
<title>Tidy - HTML Purifier</title>
</head><body>
<h1>Tidy</h1>
<div id="filing">Filed under Development</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>You've probably heard of HTML Tidy, Dave Raggett's little piece
of software that cleans up poorly written HTML. Let me say it straight
out:</p>
<p class="emphasis">This ain't HTML Tidy!</p>
<p>Rather, Tidy stands for a cool set of Tidy-inspired features in HTML Purifier
that allows users to submit deprecated elements and attributes and get
valid strict markup back. For example:</p>
<pre>&lt;center&gt;Centered&lt;/center&gt;</pre>
<p>...becomes:</p>
<pre>&lt;div style=&quot;text-align:center;&quot;&gt;Centered&lt;/div&gt;</pre>
<p>...when this particular fix is run on the HTML. This tutorial will give
you the lowdown of what exactly HTML Purifier will do when Tidy
is on, and how to fine-tune this behavior. Once again, <strong>you do
not need Tidy installed on your PHP to use these features!</strong></p>
<h2>What does it do?</h2>
<p>Tidy will do several things to your HTML:</p>
<ul>
<li>Convert deprecated elements and attributes to standards-compliant
alternatives</li>
<li>Enforce XHTML compatibility guidelines and other best practices</li>
<li>Preserve data that would normally be removed as per W3C</li>
</ul>
<h2>What are levels?</h2>
<p>Levels describe how aggressive the Tidy module should be when
cleaning up HTML. There are four levels to pick: none, light, medium
and heavy. Each of these levels has a well-defined set of behavior
associated with it, although it may change depending on your doctype.</p>
<dl>
<dt>light</dt>
<dd>This is the <strong>lenient</strong> level. If a tag or attribute
is about to be removed because it isn't supported by the
doctype, Tidy will step in and change into an alternative that
is supported.</dd>
<dt>medium</dt>
<dd>This is the <strong>correctional</strong> level. At this level,
all the functions of light are performed, as well as some extra,
non-essential best practices enforcement. Changes made on this
level are very benign and are unlikely to cause problems.</dd>
<dt>heavy</dt>
<dd>This is the <strong>aggressive</strong> level. If a tag or
attribute is deprecated, it will be converted into a non-deprecated
version, no ifs ands or buts.</dd>
</dl>
<p>By default, Tidy operates on the <strong>medium</strong> level. You can
change the level of cleaning by setting the %HTML.TidyLevel configuration
directive:</p>
<pre>$config->set('HTML', 'TidyLevel', 'heavy'); // burn baby burn!</pre>
<h2>Is the light level really light?</h2>
<p>It depends on what doctype you're using. If your documents are HTML
4.01 <em>Transitional</em>, HTML Purifier will be lazy
and won't clean up your <code>center</code>
or <code>font</code> tags. But if you're using HTML 4.01 <em>Strict</em>,
HTML Purifier has no choice: it has to convert them, or they will
be nuked out of existence. So while light on Transitional will result
in little to no changes, light on Strict will still result in quite
a lot of fixes.</p>
<p>This is different behavior from 1.6 or before, where deprecated
tags in transitional documents would
always be cleaned up regardless. This is also better behavior.</p>
<h2>My pages look different!</h2>
<p>HTML Purifier is tasked with converting deprecated tags and
attributes to standards-compliant alternatives, which usually
need copious amounts of CSS. It's also not foolproof: sometimes
things do get lost in the translation. This is why when HTML Purifier
can get away with not doing cleaning, it won't; this is why
the default value is <strong>medium</strong> and not heavy.</p>
<p>Fortunately, only a few attributes have problems with the switch
over. They are described below:</p>
<table class="table">
<thead><tr>
<th>Element@Attr</th>
<th>Changes</th>
</tr></thead>
<tbody>
<tr>
<td>caption@align</td>
<td>Firefox supports stuffing the caption on the
left and right side of the table, a feature that
Internet Explorer, understandably, does not have.
When align equals right or left, the text will simply
be aligned on the left or right side.</td>
</tr>
<tr>
<td>img@align</td>
<td>The implementation for align bottom is good, but not
perfect. There are a few pixel differences.</td>
</tr>
<tr>
<td>br@clear</td>
<td>Clear both gets a little wonky in Internet Explorer. Haven't
really been able to figure out why.</td>
</tr>
<tr>
<td>hr@noshade</td>
<td>All browsers implement this slightly differently: we've
chosen to make noshade horizontal rules gray.</td>
</tr>
</tbody>
</table>
<p>There are a few more minor, although irritating, bugs.
Some older browsers support deprecated attributes,
but not CSS. Transformed elements and attributes will look unstyled
to said browsers. Also, CSS precedence is slightly different for
inline styles versus presentational markup. In increasing precedence:</p>
<ol>
<li>Presentational attributes</li>
<li>External style sheets</li>
<li>Inline styling</li>
</ol>
<p>This means that styling that may have been masked by external CSS
declarations will start showing up (a good thing, perhaps). Finally,
if you've turned off the style attribute, almost all of
these transformations will not work. Sorry mates.</p>
<p>You can review the rendering before and after of these transformations
by consulting the <a
href="http://htmlpurifier.org/live/smoketests/attrTransform.php">attrTransform.php
smoketest</a>.</p>
<h2>I like the general idea, but the specifics bug me!</h2>
<p>So you want HTML Purifier to clean up your HTML, but you're not
so happy about the br@clear implementation. That's perfectly fine!
HTML Purifier will make accomodations:</p>
<pre>$config->set('HTML', 'Doctype', 'XHTML 1.0 Transitional');
$config->set('HTML', 'TidyLevel', 'heavy'); // all changes, minus...
<strong>$config->set('HTML', 'TidyRemove', 'br@clear');</strong></pre>
<p>That third line does the magic, removing the br@clear fix
from the module, ensuring that <code>&lt;br clear="both" /&gt;</code>
will pass through unharmed. The reverse is possible too:</p>
<pre>$config->set('HTML', 'Doctype', 'XHTML 1.0 Transitional');
$config->set('HTML', 'TidyLevel', 'none'); // no changes, plus...
<strong>$config->set('HTML', 'TidyAdd', 'p@align');</strong></pre>
<p>In this case, all transformations are shut off, except for the p@align
one, which you found handy.</p>
<p>To find out what the names of fixes you want to turn on or off are,
you'll have to consult the source code, specifically the files in
<code>HTMLPurifier/HTMLModule/Tidy/</code>. There is, however, a
general syntax:</p>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Example</th>
<th>Interpretation</th>
</tr>
</thead>
<tbody>
<tr>
<td>element</td>
<td>font</td>
<td>Tag transform for <em>element</em></td>
</tr>
<tr>
<td>element@attr</td>
<td>br@clear</td>
<td>Attribute transform for <em>attr</em> on <em>element</em></td>
</tr>
<tr>
<td>@attr</td>
<td>@lang</td>
<td>Global attribute transform for <em>attr</em></td>
</tr>
<tr>
<td>e#content_model_type</td>
<td>blockquote#content_model_type</td>
<td>Change of child processing implementation for <em>e</em></td>
</tr>
</tbody>
</table>
<h2>So... what's the lowdown?</h2>
<p>The lowdown is, quite frankly, HTML Purifier's default settings are
probably good enough. The next step is to bump the level up to heavy,
and if that still doesn't satisfy your appetite, do some fine-tuning.
Other than that, don't worry about it: this all works silently and
effectively in the background.</p>
<div id="version">$Id$</div>
</body></html>

View File

@@ -1,201 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="description" content="Tutorial for creating custom URI filters." />
<link rel="stylesheet" type="text/css" href="style.css" />
<title>URI Filters - HTML Purifier</title>
</head><body>
<h1>URI Filters</h1>
<div id="filing">Filed under End-User</div>
<div id="index">Return to the <a href="index.html">index</a>.</div>
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
<p>
This is a quick and dirty document to get you on your way to writing
custom URI filters for your own URL filtering needs. Why would you
want to write a URI filter? If you need URIs your users put into
HTML to magically change into a different URI, this is
exactly what you need!
</p>
<h2>Creating the class</h2>
<p>
Any URI filter you make will be a subclass of <code>HTMLPurifier_URIFilter</code>.
The scaffolding is thus:
</p>
<pre>class HTMLPurifier_URIFilter_<strong>NameOfFilter</strong> extends HTMLPurifier_URIFilter
{
var $name = '<strong>NameOfFilter</strong>';
function prepare($config) {}
function filter(&$uri, $config, &$context) {}
}</pre>
<p>
Fill in the variable <code>$name</code> with the name of your filter, and
take a look at the two methods. <code>prepare()</code> is an initialization
method that is called only once, before any filtering has been done of the
HTML. Use it to perform any costly setup work that only needs to be done
once. <code>filter()</code> is the guts and innards of our filter:
it takes the URI and does whatever needs to be done to it.
</p>
<p>
If you've worked with HTML Purifier, you'll recognize the <code>$config</code>
and <code>$context</code> parameters. On the other hand, <code>$uri</code>
is something unique to this section of the application: it's a
<code>HTMLPurifier_URI</code> object. The interface is thus:
</p>
<pre>class HTMLPurifier_URI
{
var $scheme, $userinfo, $host, $port, $path, $query, $fragment;
function HTMLPurifier_URI($scheme, $userinfo, $host, $port, $path, $query, $fragment);
function toString();
function copy();
function getSchemeObj($config, &$context);
function validate($config, &$context);
}</pre>
<p>
The first three methods are fairly self-explanatory: you have a constructor,
a serializer, and a cloner. Generally, you won't be using them when
you are manipulating the URI objects themselves.
<code>getSchemeObj()</code> is a special purpose method that returns
a <code>HTMLPurifier_URIScheme</code> object corresponding to the specific
URI at hand. <code>validate()</code> performs general-purpose validation
on the internal components of a URI. Once again, you don't need to
worry about these: they've already been handled for you.
</p>
<h2>URI format</h2>
<p>
As a URIFilter, we're interested in the member variables of the URI object.
</p>
<table class="quick"><tbody>
<tr><th>Scheme</th> <td>The protocol for identifying (and possibly locating) a resource (http, ftp, https)</td></tr>
<tr><th>Userinfo</th> <td>User information such as a username (bob)</td></tr>
<tr><th>Host</th> <td>Domain name or IP address of the server (example.com, 127.0.0.1)</td></tr>
<tr><th>Port</th> <td>Network port number for the server (80, 12345)</td></tr>
<tr><th>Path</th> <td>Data that identifies the resource, possibly hierarchical (/path/to, ed@example.com)</td></tr>
<tr><th>Query</th> <td>String of information to be interpreted by the resource (?q=search-term)</td></tr>
<tr><th>Fragment</th> <td>Additional information for the resource after retrieval (#bookmark)</td></tr>
</tbody></table>
<p>
Because the URI is presented to us in this form, and not
<code>http://bob@example.com:8080/foo.php?q=string#hash</code>, it saves us
a lot of trouble in having to parse the URI every time we want to filter
it. For the record, the above URI has the following components:
</p>
<table class="quick"><tbody>
<tr><th>Scheme</th> <td>http</td></tr>
<tr><th>Userinfo</th> <td>bob</td></tr>
<tr><th>Host</th> <td>example.com</td></tr>
<tr><th>Port</th> <td>8080</td></tr>
<tr><th>Path</th> <td>/foo.php</td></tr>
<tr><th>Query</th> <td>q=string</td></tr>
<tr><th>Fragment</th> <td>hash</td></tr>
</tbody></table>
<p>
Note that there is no question mark or octothorpe in the query or
fragment: these get removed during parsing.
</p>
<p>
With this information, you can get straight to implementing your
<code>filter()</code> method. But one more thing...
</p>
<h2>Return value: Boolean, not URI</h2>
<p>
You may have noticed that the URI is being passed in by reference.
This means that whatever changes you make to it, those changes will
be reflected in the URI object the callee had. <strong>Do not
return the URI object: it is unnecessary and will cause bugs.</strong>
Instead, return a boolean value, true if the filtering was successful,
or false if the URI is beyond repair and needs to be axed.
</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:
</p>
<pre>class HTMLPurifier_URIFilter_ConvertIDNToPunycode extends HTMLPurifier_URIFilter
{
var $name = 'ConvertIDNToPunycode';
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;
return true;
}
}</pre>
<p>
Notice I did not <code>return $uri;</code>.
</p>
<h2>Activating your filter</h2>
<p>
Having a filter is all well and good, but you need to tell HTML Purifier
to use it. Fortunately, this part's simple:
</p>
<pre>$uri =& $config->getDefinition('URI');
$uri->addFilter(new HTMLPurifier_URIFilter_<strong>NameOfFilter</strong>());</pre>
<p>
If you want to be really fancy, you can define a configuration directive
for your filter and have HTML Purifier automatically manage whether or
not your filter gets loaded or not (this is how internal filters manage
things):
</p>
<pre>HTMLPurifier_ConfigSchema::define(
'URI', '<strong>NameOfFilter</strong>', false, 'bool',
'<strong>What your filter does.</strong>'
);
$uri =& $config->getDefinition('URI', true);
$uri->registerFilter(new HTMLPurifier_URIFilter_<strong>NameOfFilter</strong>());
</pre>
<p>
Now, your filter will only be called when %URI.<strong>NameOfFilter</strong>
is set to true.
</p>
<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
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

@@ -96,7 +96,7 @@ which can be a rewarding (but difficult) task.</p>
<h2 id="findcharset">Finding the real encoding</h2> <h2 id="findcharset">Finding the real encoding</h2>
<p>In the beginning, there was ASCII, and things were simple. But they <p>In the beginning, there was ASCII, and things were simple. But they
weren't good, for no one could write in Cyrillic or Thai. So there weren't good, for no one could write in Cryllic or Thai. So there
exploded a proliferation of character encodings to remedy the problem exploded a proliferation of character encodings to remedy the problem
by extending the characters ASCII could express. This ridiculously by extending the characters ASCII could express. This ridiculously
simplified version of the history of character encodings shows us that simplified version of the history of character encodings shows us that
@@ -138,7 +138,7 @@ browser:</p>
<dd>View &gt; Encoding: bulleted item is unofficial name</dd> <dd>View &gt; Encoding: bulleted item is unofficial name</dd>
</dl> </dl>
<p>Internet Explorer won't give you the MIME (i.e. useful/real) name of the <p>Internet Explorer won't give you the mime (i.e. useful/real) name of the
character encoding, so you'll have to look it up using their description. character encoding, so you'll have to look it up using their description.
Some common ones:</p> Some common ones:</p>
@@ -216,12 +216,6 @@ if your <code>META</code> tag claims that either:</p>
<h2 id="fixcharset">Fixing the encoding</h2> <h2 id="fixcharset">Fixing the encoding</h2>
<p class="aside">The advice given here is for pages being served as
vanilla <code>text/html</code>. Different practices must be used
for <code>application/xml</code> or <code>application/xml+xhtml</code>, see
<a href="http://www.w3.org/TR/2002/NOTE-xhtml-media-types-20020430/">W3C's
document on XHTML media types</a> for more information.</p>
<p>If your <code>META</code> encoding and your real encoding match, <p>If your <code>META</code> encoding and your real encoding match,
savvy! You can skip this section. If they don't...</p> savvy! You can skip this section. If they don't...</p>
@@ -237,7 +231,7 @@ of your real encoding.</p>
why the character encoding should be explicitly stated. When the why the character encoding should be explicitly stated. When the
browser isn't told what the character encoding of a text is, it browser isn't told what the character encoding of a text is, it
has to guess: and sometimes the guess is wrong. Hackers can manipulate has to guess: and sometimes the guess is wrong. Hackers can manipulate
this guess in order to slip XSS past filters and then fool the this guess in order to slip XSS pass filters and then fool the
browser into executing it as active code. A great example of this browser into executing it as active code. A great example of this
is the <a href="http://shiflett.org/archive/177">Google UTF-7 is the <a href="http://shiflett.org/archive/177">Google UTF-7
exploit</a>.</p> exploit</a>.</p>
@@ -308,8 +302,7 @@ languages</a>. The appropriate code is:</p>
<p>...replacing UTF-8 with whatever your embedded encoding is. <p>...replacing UTF-8 with whatever your embedded encoding is.
This code must come before any output, so be careful about This code must come before any output, so be careful about
stray whitespace in your application (i.e., any whitespace before stray whitespace in your application.</p>
output excluding whitespace within &lt;?php ?&gt; tags).</p>
<h4 id="fixcharset-server-phpini">PHP ini directive</h4> <h4 id="fixcharset-server-phpini">PHP ini directive</h4>
@@ -320,8 +313,8 @@ header call: <code><a href="http://php.net/ini.core#ini.default-charset">default
<p>...will also do the trick. If PHP is running as an Apache module (and <p>...will also do the trick. If PHP is running as an Apache module (and
not as FastCGI, consult not as FastCGI, consult
<a href="http://php.net/phpinfo">phpinfo</a>() for details), you can even use htaccess to apply this property <a href="http://php.net/phpinfo">phpinfo</a>() for details), you can even use htaccess do apply this property
across many PHP files:</p> globally:</p>
<pre><a href="http://php.net/configuration.changes#configuration.changes.apache">php_value</a> default_charset &quot;UTF-8&quot;</pre> <pre><a href="http://php.net/configuration.changes#configuration.changes.apache">php_value</a> default_charset &quot;UTF-8&quot;</pre>
@@ -367,11 +360,10 @@ to send anything at all:</p>
<pre><a href="http://httpd.apache.org/docs/1.3/mod/core.html#adddefaultcharset">AddDefaultCharset</a> Off</pre> <pre><a href="http://httpd.apache.org/docs/1.3/mod/core.html#adddefaultcharset">AddDefaultCharset</a> Off</pre>
<p>...making your internal charset declaration (usually the <code>META</code> tags) <p>...making your <code>META</code> tags the sole source of
the sole source of character encoding character encoding information. In these cases, it is
information. In these cases, it is <em>especially</em> important to make <em>especially</em> important to make sure you have valid <code>META</code>
sure you have valid <code>META</code> tags on your pages and all the tags on your pages and all the text before them is ASCII.</p>
text before them is ASCII.</p>
<blockquote class="aside"><p>These directives can also be <blockquote class="aside"><p>These directives can also be
placed in httpd.conf file for Apache, but placed in httpd.conf file for Apache, but
@@ -436,30 +428,28 @@ IIS to change character encodings, I'd be grateful.</p>
<p><code>META</code> tags are the most common source of embedded <p><code>META</code> tags are the most common source of embedded
encodings, but they can also come from somewhere else: XML encodings, but they can also come from somewhere else: XML
Declarations. They look like:</p> processing instructions. They look like:</p>
<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</pre> <pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</pre>
<p>...and are most often found in XML documents (including XHTML).</p> <p>...and are most often found in XML documents (including XHTML).</p>
<p>For XHTML, this XML Declaration theoretically <p>For XHTML, this processing instruction theoretically
overrides the <code>META</code> tag. In reality, this happens only when the overrides the <code>META</code> tag. In reality, this happens only when the
XHTML is actually served as legit XML and not HTML, which is almost always XHTML is actually served as legit XML and not HTML, which is almost always
never due to Internet Explorer's lack of support for never due to Internet Explorer's lack of support for
<code>application/xhtml+xml</code> (even though doing so is often <code>application/xhtml+xml</code> (even though doing so is often
argued to be <a href="http://www.hixie.ch/advocacy/xhtml">good argued to be <a href="http://www.hixie.ch/advocacy/xhtml">good practice</a>).</p>
practice</a> and is required by the XHTML 1.1 specification).</p>
<p>For XML, however, this XML Declaration is extremely important. <p>For XML, however, this processing instruction is extremely important.
Since most webservers are not configured to send charsets for .xml files, Since most webservers are not configured to send charsets for .xml files,
this is the only thing a parser has to go on. Furthermore, the default this is the only thing a parser has to go on. Furthermore, the default
for XML files is UTF-8, which often butts heads with more common for XML files is UTF-8, which often butts heads with more common
ISO-8859-1 encoding (you see this in garbled RSS feeds).</p> ISO-8859-1 encoding (you see this in garbled RSS feeds).</p>
<p>In short, if you use XHTML and have gone through the <p>In short, if you use XHTML and have gone through the
trouble of adding the XML Declaration, make sure it jives trouble of adding the XML header, make sure it jives
with your <code>META</code> tags (which should only be present with your <code>META</code> tags and HTTP headers.</p>
if served in text/html) and HTTP headers.</p>
<h3 id="fixcharset-internals">Inside the process</h3> <h3 id="fixcharset-internals">Inside the process</h3>
@@ -516,7 +506,7 @@ usage in one language sometimes requires the occasional special character
that, without surprise, is not available in your character set. Sometimes that, without surprise, is not available in your character set. Sometimes
developers get around this by adding support for multiple encodings: when developers get around this by adding support for multiple encodings: when
using Chinese, use Big5, when using Japanese, use Shift-JIS, when using Chinese, use Big5, when using Japanese, use Shift-JIS, when
using Greek, etc. Other times, they use character references with great using Greek, etc. Other times, they use character entities with great
zeal.</p> zeal.</p>
<p>UTF-8, however, obviates the need for any of these complicated <p>UTF-8, however, obviates the need for any of these complicated
@@ -530,14 +520,14 @@ you don't have to use those user-unfriendly entities.</p>
<p>Websites encoded in Latin-1 (ISO-8859-1) which ocassionally need <p>Websites encoded in Latin-1 (ISO-8859-1) which ocassionally need
a special character outside of their scope often will use a character a special character outside of their scope often will use a character
entity reference to achieve the desired effect. For instance, &theta; can be entity to achieve the desired effect. For instance, &theta; can be
written <code>&amp;theta;</code>, regardless of the character encoding's written <code>&amp;theta;</code>, regardless of the character encoding's
support of Greek letters.</p> support of Greek letters.</p>
<p>This works nicely for limited use of special characters, but <p>This works nicely for limited use of special characters, but
say you wanted this sentence of Chinese text: &#28608;&#20809;, say you wanted this sentence of Chinese text: &#28608;&#20809;,
&#36889;&#20841;&#20491;&#23383;&#26159;&#29978;&#40636;&#24847;&#24605;. &#36889;&#20841;&#20491;&#23383;&#26159;&#29978;&#40636;&#24847;&#24605;.
The ampersand encoded version would look like this:</p> The entity-ized version would look like this:</p>
<pre>&amp;#28608;&amp;#20809;, &amp;#36889;&amp;#20841;&amp;#20491;&amp;#23383;&amp;#26159;&amp;#29978;&amp;#40636;&amp;#24847;&amp;#24605;</pre> <pre>&amp;#28608;&amp;#20809;, &amp;#36889;&amp;#20841;&amp;#20491;&amp;#23383;&amp;#26159;&amp;#29978;&amp;#40636;&amp;#24847;&amp;#24605;</pre>
@@ -555,7 +545,7 @@ an application that originally used ISO-8859-1 but switched to UTF-8
when it became far to cumbersome to support foreign languages. Bots when it became far to cumbersome to support foreign languages. Bots
will now actually go through articles and convert character entities will now actually go through articles and convert character entities
to their corresponding real characters for the sake of user-friendliness to their corresponding real characters for the sake of user-friendliness
and searchability. See and searcheability. See
<a href="http://meta.wikimedia.org/wiki/Help:Special_characters">Meta's <a href="http://meta.wikimedia.org/wiki/Help:Special_characters">Meta's
page on special characters</a> for more details. page on special characters</a> for more details.
</p></blockquote> </p></blockquote>
@@ -577,11 +567,10 @@ which may be used by POST, and is required when you want to upload
files.</p> files.</p>
<p>The following is a summarization of notes from <p>The following is a summarization of notes from
<a href="http://web.archive.org/web/20060427015200/ppewww.ph.gla.ac.uk/~flavell/charset/form-i18n.html"> <a href="http://ppewww.physics.gla.ac.uk/~flavell/charset/form-i18n.html">
<code>FORM</code> submission and i18n</a>. That document contains lots <code>FORM</code> submission and i18n</a>. That document contains lots
of useful information, but is written in a rambly manner, so of useful information, but is written in a rambly manner, so
here I try to get right to the point. (Note: the original has here I try to get right to the point.</p>
disappeared off the web, so I am linking to the Web Archive copy.)</p>
<h4 id="whyutf8-forms-urlencoded"><code>application/x-www-form-urlencoded</code></h4> <h4 id="whyutf8-forms-urlencoded"><code>application/x-www-form-urlencoded</code></h4>
@@ -603,7 +592,7 @@ browser you're using, they might:</p>
<ul> <ul>
<li>Replace the unsupported characters with useless question marks,</li> <li>Replace the unsupported characters with useless question marks,</li>
<li>Attempt to fix the characters (example: smart quotes to regular quotes),</li> <li>Attempt to fix the characters (example: smart quotes to regular quotes),</li>
<li>Replace the character with a character entity reference, or</li> <li>Replace the character with a character entity, or</li>
<li>Send it anyway as a different character encoding mixed in <li>Send it anyway as a different character encoding mixed in
with the original encoding (usually Windows-1252 rather than with the original encoding (usually Windows-1252 rather than
iso-8859-1 or UTF-8 interspersed in 8-bit)</li> iso-8859-1 or UTF-8 interspersed in 8-bit)</li>
@@ -619,7 +608,7 @@ since UTF-8 supports every character.</p>
<h4 id="whyutf8-forms-multipart"><code>multipart/form-data</code></h4> <h4 id="whyutf8-forms-multipart"><code>multipart/form-data</code></h4>
<p>Multipart form submission takes away a lot of the ambiguity <p>Multipart form submission takes a way a lot of the ambiguity
that percent-encoding had: the server now can explicitly ask for that percent-encoding had: the server now can explicitly ask for
certain encodings, and the client can explicitly tell the server certain encodings, and the client can explicitly tell the server
during the form submission what encoding the fields are in.</p> during the form submission what encoding the fields are in.</p>
@@ -632,9 +621,9 @@ Each method has deficiencies, especially the former.</p>
<p>If you tell the browser to send the form in the same encoding as <p>If you tell the browser to send the form in the same encoding as
the page, you still have the trouble of what to do with characters the page, you still have the trouble of what to do with characters
that are outside of the character encoding's range. The behavior, once that are outside of the character encoding's range. The behavior, once
again, varies: Firefox 2.0 converts them to character entity references again, varies: Firefox 2.0 entity-izes them while Internet Explorer
while Internet Explorer 7.0 mangles them beyond intelligibility. For 7.0 mangles them beyond intelligibility. For serious internationalization purposes,
serious internationalization purposes, this is not an option.</p> this is not an option.</p>
<p>The other possibility is to set Accept-Encoding to UTF-8, which <p>The other possibility is to set Accept-Encoding to UTF-8, which
begs the question: Why aren't you using UTF-8 for everything then? begs the question: Why aren't you using UTF-8 for everything then?
@@ -674,12 +663,12 @@ it up to the module iconv to do the dirty work.</p>
<p>This approach, however, is not perfect. iconv is blithely unaware <p>This approach, however, is not perfect. iconv is blithely unaware
of HTML character entities. HTML Purifier, in order to of HTML character entities. HTML Purifier, in order to
protect against sophisticated escaping schemes, normalizes all character protect against sophisticated escaping schemes, normalizes all character
and numeric entitie references before processing the text. This leads to and numeric entities before processing the text. This leads to
one important ramification:</p> one important ramification:</p>
<p><strong>Any character that is not supported by the target character <p><strong>Any character that is not supported by the target character
set, regardless of whether or not it is in the form of a character set, regardless of whether or not it is in the form of a character
entity reference or a raw character, will be silently ignored.</strong></p> entity or a raw character, will be silently ignored.</strong></p>
<p>Example of this principle at work: say you have <code>&amp;theta;</code> <p>Example of this principle at work: say you have <code>&amp;theta;</code>
in your HTML, but the output is in Latin-1 (which, understandably, in your HTML, but the output is in Latin-1 (which, understandably,
@@ -688,7 +677,7 @@ set the encoding correctly using %Core.Encoding):</p>
<ul> <ul>
<li>The <code>Encoder</code> will transform the text from ISO 8859-1 to UTF-8 <li>The <code>Encoder</code> will transform the text from ISO 8859-1 to UTF-8
(note that theta is preserved here since it doesn't actually use (note that theta is preserved since it doesn't actually use
any non-ASCII characters): <code>&amp;theta;</code></li> any non-ASCII characters): <code>&amp;theta;</code></li>
<li>The <code>EntityParser</code> will transform all named and numeric <li>The <code>EntityParser</code> will transform all named and numeric
character entities to their corresponding raw UTF-8 equivalents: character entities to their corresponding raw UTF-8 equivalents:
@@ -711,7 +700,7 @@ Purifier has provided a slightly more palatable workaround using
<li>The <code>EntityParser</code> transforms entities: <code>&theta;</code></li> <li>The <code>EntityParser</code> transforms entities: <code>&theta;</code></li>
<li>HTML Purifier processes the code: <code>&theta;</code></li> <li>HTML Purifier processes the code: <code>&theta;</code></li>
<li>The <code>Encoder</code> replaces all non-ASCII characters <li>The <code>Encoder</code> replaces all non-ASCII characters
with numeric entity reference: <code>&amp;#952;</code></li> with numeric entities: <code>&amp;#952;</code></li>
<li>For good measure, <code>Encoder</code> transforms encoding back to <li>For good measure, <code>Encoder</code> transforms encoding back to
original (which is strictly unnecessary for 99% of encodings original (which is strictly unnecessary for 99% of encodings
out there): <code>&amp;#952;</code> (remember, it's all ASCII!)</li> out there): <code>&amp;#952;</code> (remember, it's all ASCII!)</li>
@@ -721,19 +710,19 @@ Purifier has provided a slightly more palatable workaround using
the land of Unicode characters, and is totally unacceptable for Chinese the land of Unicode characters, and is totally unacceptable for Chinese
or Japanese texts. The even bigger kicker is that, supposing the or Japanese texts. The even bigger kicker is that, supposing the
input encoding was actually ISO-8859-7, which <em>does</em> support input encoding was actually ISO-8859-7, which <em>does</em> support
theta, the character would get converted into a character entity reference theta, the character would get entity-ized anyway! (The Encoder does
anyway! (The Encoder does not discriminate).</p> not discriminate).</p>
<p>The current functionality is about where HTML Purifier will be for <p>The current functionality is about where HTML Purifier will be for
the rest of eternity. HTML Purifier could attempt to preserve the original the rest of eternity. HTML Purifier could attempt to preserve the original
form of the character references so that they could be substituted back in, only the form of the entities so that they could be substituted back in, only the
DOM extension kills them off irreversibly. HTML Purifier could also attempt DOM extension kills them off irreversibly. HTML Purifier could also attempt
to be smart and only convert non-ASCII characters that weren't supported to be smart and only convert non-ASCII characters that weren't supported
by the target encoding, but that would require reimplementing iconv by the target encoding, but that would require reimplementing iconv
with HTML awareness, something I will not do.</p> with HTML awareness, something I will not do.</p>
<p>So there: either it's UTF-8 or crippled international support. Your pick! (and I'm <p>So there: either it's UTF-8 or crippled international support. Your pick! (and I'm
not being sarcastic here: some people could care less about other languages).</p> not being sarcastic here: some people could care less about other languages)</p>
<h2 id="migrate">Migrate to UTF-8</h2> <h2 id="migrate">Migrate to UTF-8</h2>
@@ -995,7 +984,7 @@ and yes, it is variable width. Other traits:</p>
in different ways. It is beyond the scope of this document to explain in different ways. It is beyond the scope of this document to explain
what precisely these implications are. PHPWact provides what precisely these implications are. PHPWact provides
a very good <a href="http://www.phpwact.org/php/i18n/utf-8">reference document</a> a very good <a href="http://www.phpwact.org/php/i18n/utf-8">reference document</a>
on what to expect from each function, although coverage is spotty in on what to expect from each functions, although coverage is spotty in
some areas. Their more general notes on some areas. Their more general notes on
<a href="http://www.phpwact.org/php/i18n/charsets">character sets</a> <a href="http://www.phpwact.org/php/i18n/charsets">character sets</a>
are also worth looking at for information on UTF-8. Some rules of thumb are also worth looking at for information on UTF-8. Some rules of thumb
@@ -1009,7 +998,7 @@ when dealing with Unicode text:</p>
<li>Think twice before using functions that:<ul> <li>Think twice before using functions that:<ul>
<li>...count characters (strlen will return bytes, not characters; <li>...count characters (strlen will return bytes, not characters;
str_split and word_wrap may corrupt)</li> str_split and word_wrap may corrupt)</li>
<li>...convert characters to entity references (UTF-8 doesn't need entities)</li> <li>...entity-ize things (UTF-8 doesn't need entities)</li>
<li>...do very complex string processing (*printf)</li> <li>...do very complex string processing (*printf)</li>
</ul></li> </ul></li>
</ul> </ul>
@@ -1054,4 +1043,4 @@ a more in-depth look into character sets and encodings.</p>
</ul> </ul>
</body> </body>
</html> </html>

View File

@@ -149,4 +149,4 @@ like that, for that matter), send it over and it might get included
with the core!</p> with the core!</p>
</body> </body>
</html> </html>

View File

@@ -8,8 +8,8 @@ require_once '../../library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();
// configuration goes here: // configuration goes here:
$config->set('Core', 'Encoding', 'UTF-8'); // replace with your encoding $config->set('Core', 'Encoding', 'ISO-8859-1'); //replace with your encoding
$config->set('HTML', 'Doctype', 'XHTML 1.0 Transitional'); // replace with your doctype $config->set('Core', 'XHTML', true); // set to false if HTML 4.01
$purifier = new HTMLPurifier($config); $purifier = new HTMLPurifier($config);
@@ -20,3 +20,4 @@ $pure_html = $purifier->purify($html);
echo '<pre>' . htmlspecialchars($pure_html) . '</pre>'; echo '<pre>' . htmlspecialchars($pure_html) . '</pre>';
?>

View File

@@ -34,15 +34,6 @@ information for casual developers using HTML Purifier.</p>
<dt><a href="enduser-utf8.html">UTF-8: The Secret of Character Encoding</a></dt> <dt><a href="enduser-utf8.html">UTF-8: The Secret of Character Encoding</a></dt>
<dd>Describes the rationale for using UTF-8, the ramifications otherwise, and how to make the switch.</dd> <dd>Describes the rationale for using UTF-8, the ramifications otherwise, and how to make the switch.</dd>
<dt><a href="enduser-tidy.html">Tidy</a></dt>
<dd>Tutorial for tweaking HTML Purifier's Tidy-like behavior.</dd>
<dt><a href="enduser-customize.html">Customize</a></dt>
<dd>Tutorial for customizing HTML Purifier's tag and attribute sets.</dd>
<dt><a href="enduser-uri-filter.html">URI Filters</a></dt>
<dd>Tutorial for creating custom URI filters.</dd>
</dl> </dl>
<h2>Development</h2> <h2>Development</h2>
@@ -137,8 +128,8 @@ the code. They may be upgraded to HTML files or stay as TXT scratchpads.</p>
<tr> <tr>
<td>Reference</td> <td>Reference</td>
<td><a href="ref-content-models.txt">Handling Content Model Changes</a></td> <td><a href="ref-loose-vs-strict.txt">Loose vs.Strict</a></td>
<td>Discusses how to tidy up content model changes using custom ChildDef classes.</td> <td>Differences between HTML Strict and Transitional versions.</td>
</tr> </tr>
<tr> <tr>
@@ -149,8 +140,14 @@ the code. They may be upgraded to HTML files or stay as TXT scratchpads.</p>
<tr> <tr>
<td>Reference</td> <td>Reference</td>
<td><a href="ref-html-modularization.txt">Modularization of HTMLDefinition</a></td> <td><a href="ref-strictness.txt">Strictness</a></td>
<td>Provides a high-level overview of the concepts behind HTMLModules.</td> <td>Short essay on how loose definition isn't really loose.</td>
</tr>
<tr>
<td>Reference</td>
<td><a href="ref-xhtml-1.1.txt">XHTML 1.1</a></td>
<td>What we'd have to do to support XHTML 1.1.</td>
</tr> </tr>
<tr> <tr>
@@ -165,4 +162,4 @@ the code. They may be upgraded to HTML files or stay as TXT scratchpads.</p>
<div id="version">$Id$</div> <div id="version">$Id$</div>
</body> </body>
</html> </html>

View File

@@ -12,10 +12,29 @@ the documentation in ConfigDef for more information on these namespaces.
Since configuration is dependant on context, internal classes require a Since configuration is dependant on context, internal classes require a
configuration object to be passed as a parameter. (They also require a configuration object to be passed as a parameter. (They also require a
Context object). A majority of classes do not need the config object, Context object).
but for those who do, it is a lifesaver.
Definition objects are complex datatypes influenced by their respective In relation to HTMLDefinition and CSSDefinition, there could be a special class
directive namespaces (HTMLDefinition with HTML and CSSDefinition with CSS). of directives that influence the *construction* of the Definition object.
If any of these directives is updated, HTML Purifier forces the definition A theoretical call pattern would look like:
to be regenerated.
1. Client calls Config->getHTMLDefinition()
2. Config calls HTMLDefinition->createNew(this)
3. HTMLDefinition constructs itself with base configuration
4. HTMLDefinition calls Config->get('HTML')
5. Config returns array of directives
6. HTMLDefinition performs operations and changes specified by directives
7. HTMLPurifier returns constructed definition
8. Config caches definition so it doesn't have to be generated again
9. Config returns definition
You could also override Config's copy of the definition with your own
custom copy, which OVERRIDES all directives. Only the base, vanilla copy
is the Singleton, the object actually interfaced with is a operated-upon
clone of that object. Also, if an update to the directives would update
the definition, you'd have to force reconstruction.
In practice, the pulling directives from the config object are
solely need-based, and the flex points are littered throughout the
setup() function. Some sort of refactoring is likely in order. See
ref-xhtml-1.1.txt for more info.

View File

@@ -2,16 +2,23 @@
Filter Levels Filter Levels
When one size *does not* fit all When one size *does not* fit all
It makes little sense to constrain users to one set of HTML elements and The more I think about it, the less sense it makes for maintaining one huge
attributes and tell them that they are not allowed to mold this in monolithic HTMLDefinition class. There's simply so much variation that
any fashion. Many users demand to be able to custom-select which elements could go into this definition: the set of HTML good for blog entries is
and attributes they want. This is fine: because HTML Purifier keeps close definitely too large for HTML that would be allowed in blog comments. Going
track of what elements are safe to use, there is no way for them to from Transitional to Strict requires changes to the definition.
accidently allow an XSS-able tag.
However, combing through the HTML spec to make your own whitelist can Allowing users to specify their own whitelists is one step (implemented, btw),
be a daunting task. HTML Purifier ought to offer pre-canned filter levels but I have doubts on only doing this. Simply put, the typical programmer is too
that amateur users can select based on what they think is their use-case. lazy to actually go through the trouble of investigating which tags, attributes
and properties to allow. HTMLDefinition makes a big part of what HTMLPurifier
is.
The idea, then, is to setup fundamentally different set of definitions, which
can further be customized using simpler configuration options. Alternatively,
they could be implemented as configuration profiles, which simply load
a set of recommended directives to acheive a desired affect (no simpler
config options though).
Here are some fuzzy levels you could set: Here are some fuzzy levels you could set:
@@ -32,17 +39,13 @@ Here are some fuzzy levels you could set:
One final note: when you start axing tags that are more commonly used, you One final note: when you start axing tags that are more commonly used, you
run the risk of accidentally destroying user data, especially if the data run the risk of accidentally destroying user data, especially if the data
is incoming from a WYSIWYG editor that hasn't been synced accordingly. This may is incoming from a WYSIWYG eidtor that hasn't been synced accordingly. This may
make forbidden element to text transformations desirable (for example, images). make forbidden element to text transformations desirable (for example, images).
== Element Risk Analysis == == Element Risk Analysis ==
Although none of the currently supported elements presents a security
threat per-say, some can cause problems for page layouts or be
extremely complicated.
Legend: Legend:
[danger level] - regular tags / uncommon tags ~ deprecated tags [danger level] - regular tags / uncommon tags ~ deprecated tags
[danger level]* - rare tags [danger level]* - rare tags
@@ -111,10 +114,6 @@ Partially presentational - table.cellpadding, table.cellspacing,
== CSS Risk Analysis == == CSS Risk Analysis ==
Currently, there is no support for fine-grained "allowed CSS" specification,
mainly because I'm lazy, partially because no one has asked for it. However,
this will be added eventually.
There are certain CSS elements that are extremely useful inline, but then There are certain CSS elements that are extremely useful inline, but then
as you get to more presentation oriented styling it may not always be as you get to more presentation oriented styling it may not always be
appropriate to inline them. appropriate to inline them.
@@ -127,7 +126,6 @@ any CSS properties that are not currently implemented (such as position).
Dangerous, can go outside container - float Dangerous, can go outside container - float
Easy to abuse - font-size, font-family (font), width Easy to abuse - font-size, font-family (font), width
Colored - background-color (background), border-color (border), color Colored - background-color (background), border-color (border), color
(see proposal-colors.html)
Dramatic - border, list-style-position (list-style), margin, padding, Dramatic - border, list-style-position (list-style), margin, padding,
text-align, text-indent, text-transform, vertical-align, line-height text-align, text-indent, text-transform, vertical-align, line-height

View File

@@ -2,8 +2,7 @@
Configuration Ideas Configuration Ideas
Here are some theoretical configuration ideas that we could implement some Here are some theoretical configuration ideas that we could implement some
time. Note the naming convention: %Namespace.Directive. If you want one time. Note the naming convention: %Namespace.Directive
implemented, give us a ring, and we'll move it up the priority chain.
%Attr.RewriteFragments - if there's %Attr.IDPrefix we may want to transparently %Attr.RewriteFragments - if there's %Attr.IDPrefix we may want to transparently
rewrite the URLs we parse too. However, we can only do it when it's a pure rewrite the URLs we parse too. However, we can only do it when it's a pure
@@ -23,6 +22,8 @@ implemented, give us a ring, and we'll move it up the priority chain.
%URI.AddRelNofollow - will add rel="nofollow" to all links, preventing the %URI.AddRelNofollow - will add rel="nofollow" to all links, preventing the
spread of ill-gotten pagerank spread of ill-gotten pagerank
%URI.RelativeToAbsolute - transforms all relative URIs to absolute form
%URI.HostBlacklistRegex - regexes that if matching the host are disallowed %URI.HostBlacklistRegex - regexes that if matching the host are disallowed
%URI.HostWhitelist - domain names that are excluded from the host blacklist %URI.HostWhitelist - domain names that are excluded from the host blacklist
%URI.HostPolicy - determines whether or not its reject all and then whitelist %URI.HostPolicy - determines whether or not its reject all and then whitelist

View File

@@ -1,48 +0,0 @@
Handling Content Model Changes
1. Context
The distinction between Transitional and Strict document types is somewhat
of an anomaly in the lineage of XHTML document types (following 1.0, no
doctypes do not have flavors: instead, modularization is used to let
document authors vary their elements). This transition is usually quite
straight-forward, as W3C usually deprecates attributes or elements, which
are quite easily handled using tag and attribute transforms.
However, for two elements, <blockquote>, <body> and <address>, W3C elected
to also change the content model. <blockquote> and <body> originally
accepted both inline and block elements, but in the strict doctype they
only allow block elements. With <address>, the situation is inverted:
<p> tags were now forbidden from appearing within this tag.
2. Current situation
Currently, HTML Purifier treats <blockquote> specially during Tidy mode
using a custom ChildDef class StrictBlockquote. StrictBlockquote
operates similarly to Required, except that when it encounters an inline
element, it will wrap it in a block tag (as specified by
%HTML.BlockWrapper, the default is <p>). The naming suggests it can
only be used for <blockquote>s, although it may be possible to
genericize it to work on other cases of this nature (this would be of
little practical application, as no other element in XHTML 1.1 or earlier
has a block-only content model).
Tidy currently contains no custom, lenient implementation for <address>.
If one were to be written, it would likely operate on the principle that,
when a <p> tag were to be encountered, it would be replaced with a
leading and trailing <br /> tag (the contents of <p>, being inline, are
not an issue). There is no prior work with this sort of operation.
3. Outside applicability
There are a number of other elements that contain restrictive content
models, such as <ul> or <span> (the latter is restrictive in that it
does not allow block elements). In the former case, an errant node
is eliminated completely, in the latter case, the text of the node
would is preserved (as the parent node does allow PCDATA). Custom
content model implementations probably are not the best way of handling
these cases, instead, node bubbling should be implemented instead.

View File

@@ -1,28 +0,0 @@
CSS Length Reference
To bound, or not to bound, that is the question
It's quite a reasonable request, really, and it's already been implemented
for HTML. That is, length bounding. It makes little sense to let users
define text blocks that have a font-size of 63,360 inches (that's a mile,
by the way) or a width of forty-fold the parent container.
But it's a little more complicated then that. There are multiple units
one can use, and we have to a little unit conversion to get things working.
Here's what we have:
Absolute:
1 in ~= 2.54 cm
1 cm = 10 mm
1 pt = 1/72 in
1 pc = 12 pt
Relative:
1 em ~= 10.0667 px
1 ex ~= 0.5 em, though Mozilla Firefox says 1 ex = 6px
1 px ~= 1 pt
Watch out: font-sizes can also be nested to get successively larger
(although I do not relish having to keep track of context font-sizes,
this may be necessary, especially for some of the more advanced features
for preventing things like white on white).

View File

@@ -42,4 +42,4 @@ the development of this library in these forum threads:</p>
<div id="version">$Id$</div> <div id="version">$Id$</div>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,37 @@
Loose versus Strict
Changes from one doctype to another
There are changes. Wow, how insightful. Not everything changed is relevant
to HTML Purifier, though, so let's take a look:
== Major incompatibilities ==
[done] BLOCKQUOTE changes from 'flow' to 'block'
current behavior: inline inner contents should not be nuked, block-ify as necessary
[partially-done] U, S, STRIKE cut
current behavior: removed completely
projected behavior: replace with appropriate inline span + CSS
[done] ADDRESS from potpourri to Inline (removes p tags)
current behavior: block tags silently dropped
ideal behavior: replace tags with something like <br>. (not high priority)
== Things we can loosen up ==
Tags DIR, MENU, CENTER, ISINDEX, FONT, BASEFONT? allowed in loose
current behavior: transform to strict-valid forms
Attributes allowed in loose (see attribute transforms in 'dev-progress.html')
current behavior: projected to transform into strict-valid forms
== Periphery issues ==
A tag's attribute 'target' (for selecting frames) cut
current behavior: not allowed at all
projected behavior: use loose doctype if needed, needs valid values
[done] OL/LI tag's attribute 'start'/'value' (for renumbering lists) cut
current behavior: no substitute, just delete when in strict, allow in loose
Attribute 'name' deprecated in favor of 'id'
current behavior: dropped silently
projected behavior: create proper AttrTransform
[done] PRE tag allows SUB/SUP? (strict dtd comment vs syntax, loose disallows)
current behavior: disallow as usual

View File

@@ -18,7 +18,5 @@ HTML Purifier context.
<listing>, monospace pre-variant (extremely rare) <listing>, monospace pre-variant (extremely rare)
<plaintext>, escapes all tags to the end of document <plaintext>, escapes all tags to the end of document
<ruby> and friends, (more research needed, appears to be XHTML 1.1 markup)
<xmp>, monospace, replace with pre <xmp>, monospace, replace with pre
These should be put into their own Tidy module, not loaded by default(?). These
all qualify as "lenient" transforms.

37
docs/ref-strictness.txt Normal file
View File

@@ -0,0 +1,37 @@
Is HTML Purifier Strict or Transitional?
A little bit of helpful guidance
Despite the fact that HTML Purifier professes to support both transitional and
strict HTML, it rejects a lot of attributes and elements that are actually, indeed,
valid. You can investigate progress.html to find out precisely what we
are doing to these *deprecated* attributes.
However, users have found that Strict HTML imposes some quite unreasonable
restrictions on certain things. The start and value attributes in ol and
li (respectively) perhaps are the most contested. There's is currently no
widely supported browser method short of JavaScript that can replace these
two deprecated elements. It behooves us to allow these deprecated
attributes when the output is transitional.
Fortunantely, that's the only real bugger case. The others have near-perfect
CSS equivalents, and were presentational anyway. However, the other question
pops up: should we always convert these to the CSS forms when 1. the spec
allows them anyway and 2. older browsers support them better? After all, the
whole point about CSS is to seperate styling from content, so inline styling
doesn't solve that problem.
It's an icky question, and we'll have to deal with it as more and more
transforms get implemented. As of right now, however, we currently support
these loose-only constructs in loose mode:
- <ul start="1">, <li value="1"> attributes
- <u>, <strike>, <s> tags
- flow children in <blockquote>
- mixed children in <address>
The changed child definitions as well as the ul.start li.value are the most
compelling reasons why loose should be used. We may want offer disabling <u>,
<strike> and <s> by themselves. We may also want to offer no pre-emptive
deprecated conversions. This all must be unified.

View File

@@ -2,23 +2,8 @@
Web Hypertext Application Technology Working Group Web Hypertext Application Technology Working Group
WHATWG WHATWG
== HTML 5 == I don't think we need to worry about them. Untrusted users shouldn't be
submitting applications, eh? But if some interesting attribute pops up in
their spec, and might be worth supporting, stick it here.
URL: http://www.whatwg.org/specs/web-apps/current-work/ (none so far, as you can see)
HTML 5 defines a kaboodle of new elements and attributes, as well as
some well-defined, "quirks mode" HTML parsing. Although WHATWG professes
to be targeted towards web applications, many of their semantic additions
would be quite useful in regular documents. Eventually, HTML
Purifier will need to audit their lists and figure out what changes need
to be made. This process is complicated by the fact that the WHATWG
doesn't buy into W3C's modularization of XHTML 1.1: we may need
to remodularize HTML 5 (probably done by section name). No sense in
committing ourselves till the spec stabilizes, though.
More immediately speaking though, however, is the well-defined parsing
behavior that HTML 5 adds. While I have little interest in writing
another DirectLex parser, other parsers like ph5p
<http://jero.net/lab/ph5p/> can be adapted to DOMLex to support much more
flexible HTML parsing (a cool feature I've seen is how they resolve
<b>bold<i>both</b>italic</i>).

View File

@@ -1,8 +1,10 @@
The Modularization of HTMLDefinition in HTML Purifier XHTML 1.1 and HTML Purifier
Todo for XHTML 1.1 support <http://www.w3.org/TR/xhtml11/changes.html> Todo for XHTML 1.1 support <http://www.w3.org/TR/xhtml11/changes.html>
1. Support Ruby <http://www.w3.org/TR/2001/REC-ruby-20010531/> 1. Scratch lang entirely in favor of xml:lang
2. Scratch name entirely in favor of id (partially-done)
3. Support Ruby <http://www.w3.org/TR/2001/REC-ruby-20010531/>
HTML Purifier uses the modularization of XHTML HTML Purifier uses the modularization of XHTML
<http://www.w3.org/TR/xhtml-modularization/> to organize the internals <http://www.w3.org/TR/xhtml-modularization/> to organize the internals
@@ -10,10 +12,25 @@ of HTMLDefinition into a more manageable and extensible fashion. Rather
than have one super-object, HTMLDefinition is split into HTMLModules, than have one super-object, HTMLDefinition is split into HTMLModules,
each of which are responsible for defining elements, their attributes, each of which are responsible for defining elements, their attributes,
and other properties (for a more indepth coverage, see and other properties (for a more indepth coverage, see
/library/HTMLPurifier/HTMLModule.php's docblock comments). These modules /library/HTMLPurifier/HTMLModule.php's docblock comments).
are managed by HTMLModuleManager.
Modules that we don't support but could support are: The modules that W3C defines and we support are:
* 5.1. Attribute Collections (technically not a module
* 5.2. Core Modules
o 5.2.2. Text Module
o 5.2.3. Hypertext Module
o 5.2.4. List Module
* 5.4. Text Extension Modules
o 5.4.1. Presentation Module
o 5.4.2. Edit Module
o 5.4.3. Bi-directional Text Module
* 5.6. Table Modules
o 5.6.2. Tables Module
* 5.7. Image Module
* 5.18. Style Attribute Module
Modules that we don't support but coul support are:
* 5.6. Table Modules * 5.6. Table Modules
o 5.6.1. Basic Tables Module [?] o 5.6.1. Basic Tables Module [?]
@@ -21,8 +38,10 @@ Modules that we don't support but could support are:
* 5.9. Server-side Image Map Module [?] * 5.9. Server-side Image Map Module [?]
* 5.12. Target Module [?] * 5.12. Target Module [?]
* 5.21. Name Identification Module [deprecated] * 5.21. Name Identification Module [deprecated]
* 5.22. Legacy Module [deprecated]
These modules would be implemented as "unsafe": These modules will not be implemented due to their dangerousness or
inapplicability as an XHTML fragment:
* 5.2. Core Modules * 5.2. Core Modules
o 5.2.1. Structure Module o 5.2.1. Structure Module
@@ -45,7 +64,11 @@ of robust tools for handling them (the main problem is that all the
current parsers are usually PHP 5 only and solely-validating, not current parsers are usually PHP 5 only and solely-validating, not
correcting). correcting).
This system may be generalized and ported over for CSS. The abstraction of the HTMLDefinition creation process will also
contribute to a need for a caching system. Cache invalidation would be
difficult, but could be done by comparing the HTML and Attr config
namespaces with a copy that was packaged along with the serialized
HTMLDefinition object.
== General Use-Case == == General Use-Case ==
@@ -68,7 +91,7 @@ like this:
<?php <?php
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();
$def =& $config->getHTMLDefinition(true); // reference to raw $def =& $config->getHTMLDefinition(true); // reference to raw
$def->addElement('marquee', 'Block', 'Flow', 'Common'); unset($def->modules['Hypertext']); // rm ''a'' link
$purifier = new HTMLPurifier($config); $purifier = new HTMLPurifier($config);
$purifier->purify($html); // now the definition is finalized $purifier->purify($html); // now the definition is finalized
?> ?>
@@ -161,4 +184,4 @@ Content sets can be altered using HTMLModule->content_sets, an associative
array of content set names to content set contents. If the content set array of content set names to content set contents. If the content set
already exists, your values are appended on to it (great for, say, already exists, your values are appended on to it (great for, say,
registering the font tag as an inline element), otherwise it is registering the font tag as an inline element), otherwise it is
created. They are substituted into content_model. created. They are substituted into content_model.

View File

@@ -25,7 +25,6 @@ h4 {font-family:sans-serif; font-size:0.9em; font-weight:bold; }
.aside {margin-left:2em; font-family:sans-serif; font-size:0.9em; } .aside {margin-left:2em; font-family:sans-serif; font-size:0.9em; }
blockquote .label {font-weight:bold; font-size:1em; margin:0 0 .1em; blockquote .label {font-weight:bold; font-size:1em; margin:0 0 .1em;
border-bottom:1px solid #CCC;} border-bottom:1px solid #CCC;}
.emphasis {font-weight:bold; text-align:center; font-size:1.3em;}
/* A regular table */ /* A regular table */
.table {border-collapse:collapse; border-bottom:2px solid #888; margin-left:2em; } .table {border-collapse:collapse; border-bottom:2px solid #888; margin-left:2em; }
@@ -33,9 +32,6 @@ blockquote .label {font-weight:bold; font-size:1em; margin:0 0 .1em;
.table thead th:first-child {-moz-border-radius-topleft:1em;} .table thead th:first-child {-moz-border-radius-topleft:1em;}
.table tbody td {border-bottom:1px solid #CCC; padding-right:0.6em;padding-left:0.6em;} .table tbody td {border-bottom:1px solid #CCC; padding-right:0.6em;padding-left:0.6em;}
/* A quick table*/
table.quick tbody th {text-align:right; padding-right:1em;}
/* Category of the file */ /* Category of the file */
#filing {font-weight:bold; font-size:smaller; } #filing {font-weight:bold; font-size:smaller; }
@@ -70,5 +66,3 @@ q:after {
/* Marks off sections that are lacking. */ /* Marks off sections that are lacking. */
.fixme {margin-left:2em; } .fixme {margin-left:2em; }
.fixme:before {content:"Fix me: "; font-weight:bold; color:#C00; } .fixme:before {content:"Fix me: "; font-weight:bold; color:#C00; }
#applicability {margin: 1em 5%; font-style:italic;}

View File

@@ -7,3 +7,4 @@
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() ); set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() );
require_once 'HTMLPurifier.php'; require_once 'HTMLPurifier.php';
?>

View File

@@ -18,3 +18,4 @@ function HTMLPurifier($html, $config = null) {
return $purifier->purify($html, $config); return $purifier->purify($html, $config);
} }
?>

View File

@@ -22,8 +22,8 @@
*/ */
/* /*
HTML Purifier 2.1.3 - Standards Compliant HTML Filtering HTML Purifier 1.6.1 - Standards Compliant HTML Filtering
Copyright (C) 2006-2007 Edward Z. Yang Copyright (C) 2006 Edward Z. Yang
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@@ -40,11 +40,9 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
// constants are slow, but we'll make one exception // almost every class has an undocumented dependency to these, so make sure
define('HTMLPURIFIER_PREFIX', dirname(__FILE__)); // they get included
require_once 'HTMLPurifier/ConfigSchema.php';
// every class has an undocumented dependency to these, must be included!
require_once 'HTMLPurifier/ConfigSchema.php'; // fatal errors if not included
require_once 'HTMLPurifier/Config.php'; require_once 'HTMLPurifier/Config.php';
require_once 'HTMLPurifier/Context.php'; require_once 'HTMLPurifier/Context.php';
@@ -53,29 +51,12 @@ require_once 'HTMLPurifier/Generator.php';
require_once 'HTMLPurifier/Strategy/Core.php'; require_once 'HTMLPurifier/Strategy/Core.php';
require_once 'HTMLPurifier/Encoder.php'; require_once 'HTMLPurifier/Encoder.php';
require_once 'HTMLPurifier/ErrorCollector.php';
require_once 'HTMLPurifier/LanguageFactory.php';
HTMLPurifier_ConfigSchema::define(
'Core', 'CollectErrors', false, 'bool', '
Whether or not to collect errors found while filtering the document. This
is a useful way to give feedback to your users. <strong>Warning:</strong>
Currently this feature is very patchy and experimental, with lots of
possible error messages not yet implemented. It will not cause any problems,
but it may not help your users either. This directive has been available
since 2.0.0.
');
/** /**
* Facade that coordinates HTML Purifier's subsystems in order to purify HTML. * Main library execution class.
* *
* @note There are several points in which configuration can be specified * Facade that performs calls to the HTMLPurifier_Lexer,
* for HTML Purifier. The precedence of these (from lowest to * HTMLPurifier_Strategy and HTMLPurifier_Generator subsystems in order to
* highest) is as follows: * purify HTML.
* -# Instance: new HTMLPurifier($config)
* -# Invocation: purify($html, $config)
* These configurations are entirely independent of each other and
* are *not* merged.
* *
* @todo We need an easier way to inject strategies, it'll probably end * @todo We need an easier way to inject strategies, it'll probably end
* up getting done through config though. * up getting done through config though.
@@ -83,16 +64,15 @@ since 2.0.0.
class HTMLPurifier class HTMLPurifier
{ {
var $version = '2.1.3'; var $version = '1.6.1';
var $config; var $config;
var $filters = array(); var $filters;
var $strategy, $generator; var $lexer, $strategy, $generator;
/** /**
* Resultant HTMLPurifier_Context of last run purification. Is an array * Final HTMLPurifier_Context of last run purification. Might be an array.
* of contexts if the last called method was purifyArray().
* @public * @public
*/ */
var $context; var $context;
@@ -109,6 +89,7 @@ class HTMLPurifier
$this->config = HTMLPurifier_Config::create($config); $this->config = HTMLPurifier_Config::create($config);
$this->lexer = HTMLPurifier_Lexer::create();
$this->strategy = new HTMLPurifier_Strategy_Core(); $this->strategy = new HTMLPurifier_Strategy_Core();
$this->generator = new HTMLPurifier_Generator(); $this->generator = new HTMLPurifier_Generator();
@@ -136,32 +117,7 @@ class HTMLPurifier
$config = $config ? HTMLPurifier_Config::create($config) : $this->config; $config = $config ? HTMLPurifier_Config::create($config) : $this->config;
// implementation is partially environment dependant, partially
// configuration dependant
$lexer = HTMLPurifier_Lexer::create($config);
$context = new HTMLPurifier_Context(); $context = new HTMLPurifier_Context();
// our friendly neighborhood generator, all primed with configuration too!
$this->generator->generateFromTokens(array(), $config, $context);
$context->register('Generator', $this->generator);
// set up global context variables
if ($config->get('Core', 'CollectErrors')) {
// may get moved out if other facilities use it
$language_factory = HTMLPurifier_LanguageFactory::instance();
$language = $language_factory->create($config, $context);
$context->register('Locale', $language);
$error_collector = new HTMLPurifier_ErrorCollector($context);
$context->register('ErrorCollector', $error_collector);
}
// setup id_accumulator context, necessary due to the fact that
// AttrValidator can be called from many places
$id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
$context->register('IDAccumulator', $id_accumulator);
$html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context); $html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context);
for ($i = 0, $size = count($this->filters); $i < $size; $i++) { for ($i = 0, $size = count($this->filters); $i < $size; $i++) {
@@ -174,7 +130,7 @@ class HTMLPurifier
// list of tokens // list of tokens
$this->strategy->execute( $this->strategy->execute(
// list of un-purified tokens // list of un-purified tokens
$lexer->tokenizeHTML( $this->lexer->tokenizeHTML(
// un-purified HTML // un-purified HTML
$html, $config, $context $html, $config, $context
), ),
@@ -208,25 +164,7 @@ class HTMLPurifier
return $array_of_html; return $array_of_html;
} }
/**
* Singleton for enforcing just one HTML Purifier in your system
* @param $prototype Optional prototype HTMLPurifier instance to
* overload singleton with.
*/
static function &getInstance($prototype = null) {
static $htmlpurifier;
if (!$htmlpurifier || $prototype) {
if ($prototype instanceof HTMLPurifier) {
$htmlpurifier = $prototype;
} elseif ($prototype) {
$htmlpurifier = new HTMLPurifier($prototype);
} else {
$htmlpurifier = new HTMLPurifier();
}
}
return $htmlpurifier;
}
} }
?>

View File

@@ -1,6 +1,7 @@
<?php <?php
require_once 'HTMLPurifier/AttrTypes.php'; require_once 'HTMLPurifier/AttrTypes.php';
require_once 'HTMLPurifier/AttrDef/Lang.php';
/** /**
* Defines common attribute collections that modules reference * Defines common attribute collections that modules reference
@@ -11,6 +12,8 @@ class HTMLPurifier_AttrCollections
/** /**
* Associative array of attribute collections, indexed by name * Associative array of attribute collections, indexed by name
* @note Technically, the composition of these is more complicated,
* but we bypass it using our own excludes property
*/ */
var $info = array(); var $info = array();
@@ -22,29 +25,27 @@ class HTMLPurifier_AttrCollections
* @param $modules Hash array of HTMLPurifier_HTMLModule members * @param $modules Hash array of HTMLPurifier_HTMLModule members
*/ */
function HTMLPurifier_AttrCollections($attr_types, $modules) { function HTMLPurifier_AttrCollections($attr_types, $modules) {
$info =& $this->info;
// load extensions from the modules // load extensions from the modules
foreach ($modules as $module) { foreach ($modules as $module) {
foreach ($module->attr_collections as $coll_i => $coll) { foreach ($module->attr_collections as $coll_i => $coll) {
if (!isset($this->info[$coll_i])) {
$this->info[$coll_i] = array();
}
foreach ($coll as $attr_i => $attr) { foreach ($coll as $attr_i => $attr) {
if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) { if ($attr_i === 0 && isset($info[$coll_i][$attr_i])) {
// merge in includes // merge in includes
$this->info[$coll_i][$attr_i] = array_merge( $info[$coll_i][$attr_i] = array_merge(
$this->info[$coll_i][$attr_i], $attr); $info[$coll_i][$attr_i], $attr);
continue; continue;
} }
$this->info[$coll_i][$attr_i] = $attr; $info[$coll_i][$attr_i] = $attr;
} }
} }
} }
// perform internal expansions and inclusions // perform internal expansions and inclusions
foreach ($this->info as $name => $attr) { foreach ($info as $name => $attr) {
// merge attribute collections that include others // merge attribute collections that include others
$this->performInclusions($this->info[$name]); $this->performInclusions($info[$name]);
// replace string identifiers with actual attribute objects // replace string identifiers with actual attribute objects
$this->expandIdentifiers($this->info[$name], $attr_types); $this->expandIdentifiers($info[$name], $attr_types);
} }
} }
@@ -56,20 +57,16 @@ class HTMLPurifier_AttrCollections
function performInclusions(&$attr) { function performInclusions(&$attr) {
if (!isset($attr[0])) return; if (!isset($attr[0])) return;
$merge = $attr[0]; $merge = $attr[0];
$seen = array(); // recursion guard
// loop through all the inclusions // loop through all the inclusions
for ($i = 0; isset($merge[$i]); $i++) { for ($i = 0; isset($merge[$i]); $i++) {
if (isset($seen[$merge[$i]])) continue;
$seen[$merge[$i]] = true;
// foreach attribute of the inclusion, copy it over // foreach attribute of the inclusion, copy it over
if (!isset($this->info[$merge[$i]])) continue;
foreach ($this->info[$merge[$i]] as $key => $value) { foreach ($this->info[$merge[$i]] as $key => $value) {
if (isset($attr[$key])) continue; // also catches more inclusions if (isset($attr[$key])) continue; // also catches more inclusions
$attr[$key] = $value; $attr[$key] = $value;
} }
if (isset($this->info[$merge[$i]][0])) { if (isset($info[$merge[$i]][0])) {
// recursion // recursion
$merge = array_merge($merge, $this->info[$merge[$i]][0]); $merge = array_merge($merge, isset($info[$merge[$i]][0]));
} }
} }
unset($attr[0]); unset($attr[0]);
@@ -82,48 +79,22 @@ class HTMLPurifier_AttrCollections
* @param $attr_types HTMLPurifier_AttrTypes instance * @param $attr_types HTMLPurifier_AttrTypes instance
*/ */
function expandIdentifiers(&$attr, $attr_types) { function expandIdentifiers(&$attr, $attr_types) {
// because foreach will process new elements we add, make sure we
// skip duplicates
$processed = array();
foreach ($attr as $def_i => $def) { foreach ($attr as $def_i => $def) {
// skip inclusions
if ($def_i === 0) continue; if ($def_i === 0) continue;
if (!is_string($def)) continue;
if (isset($processed[$def_i])) continue;
// determine whether or not attribute is required
if ($required = (strpos($def_i, '*') !== false)) {
// rename the definition
unset($attr[$def_i]);
$def_i = trim($def_i, '*');
$attr[$def_i] = $def;
}
$processed[$def_i] = true;
// if we've already got a literal object, move on
if (is_object($def)) {
// preserve previous required
$attr[$def_i]->required = ($required || $attr[$def_i]->required);
continue;
}
if ($def === false) { if ($def === false) {
unset($attr[$def_i]); unset($attr[$def_i]);
continue; continue;
} }
if (isset($attr_types->info[$def])) {
if ($t = $attr_types->get($def)) { $attr[$def_i] = $attr_types->info[$def];
$attr[$def_i] = $t;
$attr[$def_i]->required = $required;
} else { } else {
trigger_error('Attempted to reference undefined attribute type', E_USER_ERROR);
unset($attr[$def_i]); unset($attr[$def_i]);
} }
} }
} }
} }
?>

View File

@@ -14,17 +14,11 @@ class HTMLPurifier_AttrDef
{ {
/** /**
* Tells us whether or not an HTML attribute is minimized. Has no * Tells us whether or not an HTML attribute is minimized. Only the
* meaning in other contexts. * boolean attribute vapourware would use this.
*/ */
var $minimized = false; var $minimized = false;
/**
* Tells us whether or not an HTML attribute is required. Has no
* meaning in other contexts
*/
var $required = false;
/** /**
* Validates and cleans passed string according to a definition. * Validates and cleans passed string according to a definition.
* *
@@ -68,19 +62,6 @@ class HTMLPurifier_AttrDef
$string = str_replace(array("\r", "\t"), ' ', $string); $string = str_replace(array("\r", "\t"), ' ', $string);
return $string; return $string;
} }
/**
* Factory method for creating this class from a string.
* @param $string String construction info
* @return Created AttrDef object corresponding to $string
* @public
*/
function make($string) {
// default implementation, return flyweight of this object
// if overloaded, it is *necessary* for you to clone the
// object (usually by instantiating a new copy) and return that
return $this;
}
} }
?>

View File

@@ -66,3 +66,4 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -84,3 +84,4 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -127,3 +127,4 @@ class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -42,3 +42,4 @@ class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -2,47 +2,43 @@
require_once 'HTMLPurifier/AttrDef.php'; require_once 'HTMLPurifier/AttrDef.php';
HTMLPurifier_ConfigSchema::define(
'Core', 'ColorKeywords', array(
'maroon' => '#800000',
'red' => '#FF0000',
'orange' => '#FFA500',
'yellow' => '#FFFF00',
'olive' => '#808000',
'purple' => '#800080',
'fuchsia' => '#FF00FF',
'white' => '#FFFFFF',
'lime' => '#00FF00',
'green' => '#008000',
'navy' => '#000080',
'blue' => '#0000FF',
'aqua' => '#00FFFF',
'teal' => '#008080',
'black' => '#000000',
'silver' => '#C0C0C0',
'gray' => '#808080'
), 'hash', '
Lookup array of color names to six digit hexadecimal number corresponding
to color, with preceding hash mark. Used when parsing colors.
This directive has been available since 2.0.0.
');
/** /**
* Validates Color as defined by CSS. * Validates Color as defined by CSS.
*/ */
class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
{ {
/**
* Color keyword lookup table.
* @todo Extend it to include all usually allowed colors.
*/
var $colors = array(
'maroon' => '#800000',
'red' => '#F00',
'orange' => '#FFA500',
'yellow' => '#FF0',
'olive' => '#808000',
'purple' => '#800080',
'fuchsia' => '#F0F',
'white' => '#FFF',
'lime' => '#0F0',
'green' => '#008000',
'navy' => '#000080',
'blue' => '#00F',
'aqua' => '#0FF',
'teal' => '#008080',
'black' => '#000',
'silver' => '#C0C0C0',
'gray' => '#808080'
);
function validate($color, $config, &$context) { function validate($color, $config, &$context) {
static $colors = null;
if ($colors === null) $colors = $config->get('Core', 'ColorKeywords');
$color = trim($color); $color = trim($color);
if (!$color) return false; if (!$color) return false;
$lower = strtolower($color); $lower = strtolower($color);
if (isset($colors[$lower])) return $colors[$lower]; if (isset($this->colors[$lower])) return $this->colors[$lower];
if ($color[0] === '#') { if ($color[0] === '#') {
// hexadecimal handling // hexadecimal handling
@@ -98,3 +94,4 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -35,3 +35,4 @@ class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -18,6 +18,18 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
*/ */
var $info = array(); var $info = array();
/**
* System font keywords.
*/
var $system_fonts = array(
'caption' => true,
'icon' => true,
'menu' => true,
'message-box' => true,
'small-caption' => true,
'status-bar' => true
);
function HTMLPurifier_AttrDef_CSS_Font($config) { function HTMLPurifier_AttrDef_CSS_Font($config) {
$def = $config->getCSSDefinition(); $def = $config->getCSSDefinition();
$this->info['font-style'] = $def->info['font-style']; $this->info['font-style'] = $def->info['font-style'];
@@ -30,22 +42,13 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
function validate($string, $config, &$context) { function validate($string, $config, &$context) {
static $system_fonts = array(
'caption' => true,
'icon' => true,
'menu' => true,
'message-box' => true,
'small-caption' => true,
'status-bar' => true
);
// regular pre-processing // regular pre-processing
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
if ($string === '') return false; if ($string === '') return false;
// check if it's one of the keywords // check if it's one of the keywords
$lowercase_string = strtolower($string); $lowercase_string = strtolower($string);
if (isset($system_fonts[$lowercase_string])) { if (isset($this->system_fonts[$lowercase_string])) {
return $lowercase_string; return $lowercase_string;
} }
@@ -148,3 +151,4 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -10,15 +10,19 @@ require_once 'HTMLPurifier/AttrDef.php';
class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
{ {
/**
* Generic font family keywords.
* @protected
*/
var $generic_names = array(
'serif' => true,
'sans-serif' => true,
'monospace' => true,
'fantasy' => true,
'cursive' => true
);
function validate($string, $config, &$context) { function validate($string, $config, &$context) {
static $generic_names = array(
'serif' => true,
'sans-serif' => true,
'monospace' => true,
'fantasy' => true,
'cursive' => true
);
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
// assume that no font names contain commas in them // assume that no font names contain commas in them
$fonts = explode(',', $string); $fonts = explode(',', $string);
@@ -27,7 +31,7 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
$font = trim($font); $font = trim($font);
if ($font === '') continue; if ($font === '') continue;
// match a generic name // match a generic name
if (isset($generic_names[$font])) { if (isset($this->generic_names[$font])) {
$final .= $font . ', '; $final .= $font . ', ';
continue; continue;
} }
@@ -38,24 +42,19 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
$quote = $font[0]; $quote = $font[0];
if ($font[$length - 1] !== $quote) continue; if ($font[$length - 1] !== $quote) continue;
$font = substr($font, 1, $length - 2); $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
} }
// $font is a pure representation of the font name // process font
if (ctype_alnum($font)) { if (ctype_alnum($font)) {
// very simple font, allow it in unharmed // very simple font, allow it in unharmed
$final .= $font . ', '; $final .= $font . ', ';
continue; continue;
} }
$nospace = str_replace(array(' ', '.', '!'), '', $font);
// complicated font, requires quoting if (ctype_alnum($nospace)) {
// font with spaces in it
// armor single quotes and new lines $final .= "'$font', ";
$font = str_replace("'", "\\'", $font); continue;
$font = str_replace("\n", "\\\n", $font); }
$final .= "'$font', ";
} }
$final = rtrim($final, ', '); $final = rtrim($final, ', ');
if ($final === '') return false; if ($final === '') return false;
@@ -64,3 +63,4 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -53,3 +53,4 @@ class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -77,3 +77,4 @@ class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -55,3 +55,4 @@ class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -58,3 +58,4 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -40,3 +40,4 @@ class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -10,19 +10,23 @@ require_once 'HTMLPurifier/AttrDef.php';
class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
{ {
/**
* Lookup table of allowed values.
* @protected
*/
var $allowed_values = array(
'line-through' => true,
'overline' => true,
'underline' => true
);
function validate($string, $config, &$context) { function validate($string, $config, &$context) {
static $allowed_values = array(
'line-through' => true,
'overline' => true,
'underline' => true
);
$string = strtolower($this->parseCDATA($string)); $string = strtolower($this->parseCDATA($string));
$parts = explode(' ', $string); $parts = explode(' ', $string);
$final = ''; $final = '';
foreach ($parts as $part) { foreach ($parts as $part) {
if (isset($allowed_values[$part])) { if (isset($this->allowed_values[$part])) {
$final .= $part . ' '; $final .= $part . ' ';
} }
} }
@@ -34,3 +38,4 @@ class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -15,7 +15,7 @@ class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
{ {
function HTMLPurifier_AttrDef_CSS_URI() { function HTMLPurifier_AttrDef_CSS_URI() {
parent::HTMLPurifier_AttrDef_URI(true); // always embedded $this->HTMLPurifier_AttrDef_URI(true); // always embedded
} }
function validate($uri_string, $config, &$context) { function validate($uri_string, $config, &$context) {
@@ -29,7 +29,7 @@ class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
if ($uri_string[$new_length] != ')') return false; if ($uri_string[$new_length] != ')') return false;
$uri = trim(substr($uri_string, 0, $new_length)); $uri = trim(substr($uri_string, 0, $new_length));
if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) { if (isset($uri[0]) && ($uri[0] == "'" || $uri[0] == '"')) {
$quote = $uri[0]; $quote = $uri[0];
$new_length = strlen($uri) - 1; $new_length = strlen($uri) - 1;
if ($uri[$new_length] !== $quote) return false; if ($uri[$new_length] !== $quote) return false;
@@ -55,3 +55,4 @@ class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
} }
?>

View File

@@ -45,21 +45,6 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
return $result ? $string : false; return $result ? $string : false;
} }
/**
* @param $string In form of comma-delimited list of case-insensitive
* valid values. Example: "foo,bar,baz". Prepend "s:" to make
* case sensitive
*/
function make($string) {
if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') {
$string = substr($string, 2);
$sensitive = true;
} else {
$sensitive = false;
}
$values = explode(',', $string);
return new HTMLPurifier_AttrDef_Enum($values, $sensitive);
}
} }
?>

View File

@@ -1,29 +0,0 @@
<?php
require_once 'HTMLPurifier/AttrDef.php';
/**
* Validates a boolean attribute
*/
class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef
{
var $name;
var $minimized = true;
function HTMLPurifier_AttrDef_HTML_Bool($name = false) {$this->name = $name;}
function validate($string, $config, &$context) {
if (empty($string)) return false;
return $this->name;
}
/**
* @param $string Name of attribute
*/
function make($string) {
return new HTMLPurifier_AttrDef_HTML_Bool($string);
}
}

View File

@@ -1,34 +0,0 @@
<?php
require_once 'HTMLPurifier/AttrDef.php';
require_once 'HTMLPurifier/AttrDef/CSS/Color.php'; // for %Core.ColorKeywords
/**
* Validates a color according to the HTML spec.
*/
class HTMLPurifier_AttrDef_HTML_Color extends HTMLPurifier_AttrDef
{
function validate($string, $config, &$context) {
static $colors = null;
if ($colors === null) $colors = $config->get('Core', 'ColorKeywords');
$string = trim($string);
if (empty($string)) return false;
if (isset($colors[$string])) return $colors[$string];
if ($string[0] === '#') $hex = substr($string, 1);
else $hex = $string;
$length = strlen($hex);
if ($length !== 3 && $length !== 6) return false;
if (!ctype_xdigit($hex)) return false;
if ($length === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
return "#$hex";
}
}

View File

@@ -31,3 +31,4 @@ class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum
} }
?>

View File

@@ -118,3 +118,4 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -41,3 +41,4 @@ class HTMLPurifier_AttrDef_HTML_Length extends HTMLPurifier_AttrDef_HTML_Pixels
} }
?>

View File

@@ -26,20 +26,22 @@ HTMLPurifier_ConfigSchema::define(
class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
{ {
/** Lookup array of attribute names to configuration name */
var $configLookup = array(
'rel' => 'AllowedRel',
'rev' => 'AllowedRev'
);
/** Name config attribute to pull. */ /** Name config attribute to pull. */
var $name; var $name;
function HTMLPurifier_AttrDef_HTML_LinkTypes($name) { function HTMLPurifier_AttrDef_HTML_LinkTypes($name) {
$configLookup = array( if (!isset($this->configLookup[$name])) {
'rel' => 'AllowedRel',
'rev' => 'AllowedRev'
);
if (!isset($configLookup[$name])) {
trigger_error('Unrecognized attribute name for link '. trigger_error('Unrecognized attribute name for link '.
'relationship.', E_USER_ERROR); 'relationship.', E_USER_ERROR);
return; return;
} }
$this->name = $configLookup[$name]; $this->name = $this->configLookup[$name];
} }
function validate($string, $config, &$context) { function validate($string, $config, &$context) {
@@ -70,3 +72,4 @@ class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -41,3 +41,4 @@ class HTMLPurifier_AttrDef_HTML_MultiLength extends HTMLPurifier_AttrDef_HTML_Le
} }
?>

View File

@@ -48,3 +48,4 @@ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -34,3 +34,4 @@ class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -72,3 +72,4 @@ class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -72,3 +72,4 @@ class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -14,3 +14,4 @@ class HTMLPurifier_AttrDef_Text extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -1,66 +1,90 @@
<?php <?php
require_once 'HTMLPurifier/AttrDef.php'; require_once 'HTMLPurifier/AttrDef.php';
require_once 'HTMLPurifier/URIParser.php';
require_once 'HTMLPurifier/URIScheme.php'; require_once 'HTMLPurifier/URIScheme.php';
require_once 'HTMLPurifier/URISchemeRegistry.php'; require_once 'HTMLPurifier/URISchemeRegistry.php';
require_once 'HTMLPurifier/AttrDef/URI/Host.php'; require_once 'HTMLPurifier/AttrDef/URI/Host.php';
require_once 'HTMLPurifier/PercentEncoder.php'; require_once 'HTMLPurifier/PercentEncoder.php';
require_once 'HTMLPurifier/AttrDef/URI/Email.php';
// special case filtering directives
HTMLPurifier_ConfigSchema::define( HTMLPurifier_ConfigSchema::define(
'URI', 'Munge', null, 'string/null', ' 'URI', 'DefaultScheme', 'http', 'string',
<p> 'Defines through what scheme the output will be served, in order to '.
Munges all browsable (usually http, https and ftp) 'select the proper object validator when no scheme information is present.'
absolute URI\'s 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>).
</p>
<p>
Uses for this directive:
</p>
<ul>
<li>
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.
</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
in corporate environments.
</li>
</ul>
<p>
This directive has been available since 1.3.0.
</p>
');
// disabling directives
HTMLPurifier_ConfigSchema::define( HTMLPurifier_ConfigSchema::define(
'URI', 'Disable', false, 'bool', ' 'URI', 'Host', null, 'string/null',
<p> 'Defines the domain name of the server, so we can determine whether or '.
Disables all URIs in all forms. Not sure why you\'d want to do that 'an absolute URI is from your website or not. Not strictly necessary, '.
(after all, the Internet\'s founded on the notion of a hyperlink). 'as users should be using relative URIs to reference resources on your '.
This directive has been available since 1.3.0. 'website. It will, however, let you use absolute URIs to link to '.
</p> 'subdomains of the domain you post here: i.e. example.com will allow '.
'); 'sub.example.com. However, higher up domains will still be excluded: '.
'if you set %URI.Host to sub.example.com, example.com will be blocked. '.
'This directive has been available since 1.2.0.'
);
HTMLPurifier_ConfigSchema::define(
'URI', 'DisableExternal', false, 'bool',
'Disables links to external websites. This is a highly effective '.
'anti-spam and anti-pagerank-leech measure, but comes at a hefty price: no'.
'links or images outside of your domain will be allowed. Non-linkified '.
'URIs will still be preserved. If you want to be able to link to '.
'subdomains or use absolute URIs, specify %URI.Host for your website. '.
'This directive has been available since 1.2.0.'
);
HTMLPurifier_ConfigSchema::define(
'URI', 'DisableExternalResources', false, 'bool',
'Disables the embedding of external resources, preventing users from '.
'embedding things like images from other hosts. This prevents '.
'access tracking (good for email viewers), bandwidth leeching, '.
'cross-site request forging, goatse.cx posting, and '.
'other nasties, but also results in '.
'a loss of end-user functionality (they can\'t directly post a pic '.
'they posted from Flickr anymore). Use it if you don\'t have a '.
'robust user-content moderation team. This directive has been '.
'available since 1.3.0.'
);
HTMLPurifier_ConfigSchema::define(
'URI', 'DisableResources', false, 'bool',
'Disables embedding resources, essentially meaning no pictures. You can '.
'still link to them though. See %URI.DisableExternalResources for why '.
'this might be a good idea. This directive has been available since 1.3.0.'
);
HTMLPurifier_ConfigSchema::define(
'URI', 'Munge', null, 'string/null',
'Munges all browsable (usually http, https and ftp) URI\'s into some URL '.
'redirection service. Pass this directive a URI, with %s inserted where '.
'the url-encoded original URI should be inserted (sample: '.
'<code>http://www.google.com/url?q=%s</code>). '.
'This prevents PageRank leaks, while being as transparent as possible '.
'to users (you may also want to add some client side JavaScript to '.
'override the text in the statusbar). Warning: many security experts '.
'believe that this form of protection does not deter spam-bots. '.
'You can also use this directive to redirect users to a splash page '.
'telling them they are leaving your website. '.
'This directive has been available since 1.3.0.'
);
HTMLPurifier_ConfigSchema::define(
'URI', 'HostBlacklist', array(), 'list',
'List of strings that are forbidden in the host of any URI. Use it to '.
'kill domain names of spam, etc. Note that it will catch anything in '.
'the domain, so <tt>moo.com</tt> will catch <tt>moo.com.example.com</tt>. '.
'This directive has been available since 1.3.0.'
);
HTMLPurifier_ConfigSchema::define(
'URI', 'Disable', false, 'bool',
'Disables all URIs in all forms. Not sure why you\'d want to do that '.
'(after all, the Internet\'s founded on the notion of a hyperlink). '.
'This directive has been available since 1.3.0.'
);
HTMLPurifier_ConfigSchema::defineAlias('Attr', 'DisableURI', 'URI', 'Disable'); HTMLPurifier_ConfigSchema::defineAlias('Attr', 'DisableURI', 'URI', 'Disable');
HTMLPurifier_ConfigSchema::define(
'URI', 'DisableResources', false, 'bool', '
<p>
Disables embedding resources, essentially meaning no pictures. You can
still link to them though. See %URI.DisableExternalResources for why
this might be a good idea. This directive has been available since 1.3.0.
</p>
');
/** /**
* Validates a URI as defined by RFC 3986. * Validates a URI as defined by RFC 3986.
* @note Scheme-specific mechanics deferred to HTMLPurifier_URIScheme * @note Scheme-specific mechanics deferred to HTMLPurifier_URIScheme
@@ -68,83 +92,205 @@ HTMLPurifier_ConfigSchema::define(
class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
{ {
var $parser, $percentEncoder; var $host;
var $embedsResource; var $PercentEncoder;
var $embeds_resource;
/** /**
* @param $embeds_resource_resource Does the URI here result in an extra HTTP request? * @param $embeds_resource_resource Does the URI here result in an extra HTTP request?
*/ */
function HTMLPurifier_AttrDef_URI($embeds_resource = false) { function HTMLPurifier_AttrDef_URI($embeds_resource = false) {
$this->parser = new HTMLPurifier_URIParser(); $this->host = new HTMLPurifier_AttrDef_URI_Host();
$this->percentEncoder = new HTMLPurifier_PercentEncoder(); $this->PercentEncoder = new HTMLPurifier_PercentEncoder();
$this->embedsResource = (bool) $embeds_resource; $this->embeds_resource = (bool) $embeds_resource;
} }
function validate($uri, $config, &$context) { function validate($uri, $config, &$context) {
// We'll write stack-based parsers later, for now, use regexps to
// get things working as fast as possible (irony)
if ($config->get('URI', 'Disable')) return false; if ($config->get('URI', 'Disable')) return false;
// initial operations // parse as CDATA
$uri = $this->parseCDATA($uri); $uri = $this->parseCDATA($uri);
$uri = $this->percentEncoder->normalize($uri);
// parse the URI // fix up percent-encoding
$uri = $this->parser->parse($uri); $uri = $this->PercentEncoder->normalize($uri);
if ($uri === false) return false;
// add embedded flag to context for validators // while it would be nice to use parse_url(), that's specifically
$context->register('EmbeddedURI', $this->embedsResource); // for HTTP and thus won't work for our generic URI parsing
$ok = false; // according to the RFC... (but this cuts corners, i.e. non-validating)
do { $r_URI = '!'.
'(([^:/?#<>\'"]+):)?'. // 2. Scheme
// generic validation '(//([^/?#<>\'"]*))?'. // 4. Authority
$result = $uri->validate($config, $context); '([^?#<>\'"]*)'. // 5. Path
if (!$result) break; '(\?([^#<>\'"]*))?'. // 7. Query
'(#([^<>\'"]*))?'. // 8. Fragment
// chained filtering '!';
$uri_def =& $config->getDefinition('URI');
$result = $uri_def->filter($uri, $config, $context);
if (!$result) break;
// scheme-specific validation
$scheme_obj = $uri->getSchemeObj($config, $context);
if (!$scheme_obj) break;
if ($this->embedsResource && !$scheme_obj->browsable) break;
$result = $scheme_obj->validate($uri, $config, $context);
if (!$result) break;
// survived gauntlet
$ok = true;
} while (false);
$context->destroy('EmbeddedURI'); $matches = array();
if (!$ok) return false; $result = preg_match($r_URI, $uri, $matches);
// munge scheme off if necessary (this must be last) if (!$result) return false; // invalid URI
if (!is_null($uri->scheme) && is_null($uri->host)) {
if ($uri_def->defaultScheme == $uri->scheme) { // seperate out parts
$uri->scheme = null; $scheme = !empty($matches[1]) ? $matches[2] : null;
} $authority = !empty($matches[3]) ? $matches[4] : null;
$path = $matches[5]; // always present, can be empty
$query = !empty($matches[6]) ? $matches[7] : null;
$fragment = !empty($matches[8]) ? $matches[9] : null;
$registry =& HTMLPurifier_URISchemeRegistry::instance();
if ($scheme !== null) {
// no need to validate the scheme's fmt since we do that when we
// retrieve the specific scheme object from the registry
$scheme = ctype_lower($scheme) ? $scheme : strtolower($scheme);
$scheme_obj = $registry->getScheme($scheme, $config, $context);
if (!$scheme_obj) return false; // invalid scheme, clean it out
} else {
$scheme_obj = $registry->getScheme(
$config->get('URI', 'DefaultScheme'), $config, $context
);
} }
// back to string
$result = $uri->toString();
// munge entire URI if necessary // the URI we're processing embeds_resource a resource in the page, but the URI
if ( // it references cannot be located
!is_null($uri->host) && // indicator for authority if ($this->embeds_resource && !$scheme_obj->browsable) {
!empty($scheme_obj->browsable) && return false;
!is_null($munge = $config->get('URI', 'Munge')) }
) {
$result = str_replace('%s', rawurlencode($result), $munge);
if ($authority !== null) {
// remove URI if it's absolute and we disabled externals or
// if it's absolute and embedded and we disabled external resources
unset($our_host);
if (
$config->get('URI', 'DisableExternal') ||
(
$config->get('URI', 'DisableExternalResources') &&
$this->embeds_resource
)
) {
$our_host = $config->get('URI', 'Host');
if ($our_host === null) return false;
}
$HEXDIG = '[A-Fa-f0-9]';
$unreserved = 'A-Za-z0-9-._~'; // make sure you wrap with []
$sub_delims = '!$&\'()'; // needs []
$pct_encoded = "%$HEXDIG$HEXDIG";
$r_userinfo = "(?:[$unreserved$sub_delims:]|$pct_encoded)*";
$r_authority = "/^(($r_userinfo)@)?(\[[^\]]+\]|[^:]*)(:(\d*))?/";
$matches = array();
preg_match($r_authority, $authority, $matches);
// overloads regexp!
$userinfo = !empty($matches[1]) ? $matches[2] : null;
$host = !empty($matches[3]) ? $matches[3] : null;
$port = !empty($matches[4]) ? $matches[5] : null;
// validate port
if ($port !== null) {
$port = (int) $port;
if ($port < 1 || $port > 65535) $port = null;
}
$host = $this->host->validate($host, $config, $context);
if ($host === false) $host = null;
if ($this->checkBlacklist($host, $config, $context)) return false;
// more lenient absolute checking
if (isset($our_host)) {
$host_parts = array_reverse(explode('.', $host));
// could be cached
$our_host_parts = array_reverse(explode('.', $our_host));
foreach ($our_host_parts as $i => $discard) {
if (!isset($host_parts[$i])) return false;
if ($host_parts[$i] != $our_host_parts[$i]) return false;
}
}
// userinfo and host are validated within the regexp
} else {
$port = $host = $userinfo = null;
}
// query and fragment are quite simple in terms of definition:
// *( pchar / "/" / "?" ), so define their validation routines
// when we start fixing percent encoding
// path gets to be validated against a hodge-podge of rules depending
// on the status of authority and scheme, but it's not that important,
// esp. since it won't be applicable to everyone
// okay, now we defer execution to the subobject for more processing
// note that $fragment is omitted
list($userinfo, $host, $port, $path, $query) =
$scheme_obj->validateComponents(
$userinfo, $host, $port, $path, $query, $config, $context
);
// reconstruct authority
$authority = null;
if (!is_null($userinfo) || !is_null($host) || !is_null($port)) {
$authority = '';
if($userinfo !== null) $authority .= $userinfo . '@';
$authority .= $host;
if($port !== null) $authority .= ':' . $port;
}
// reconstruct the result
$result = '';
if ($scheme !== null) $result .= "$scheme:";
if ($authority !== null) $result .= "//$authority";
$result .= $path;
if ($query !== null) $result .= "?$query";
if ($fragment !== null) $result .= "#$fragment";
// munge if necessary
$munge = $config->get('URI', 'Munge');
if (!empty($scheme_obj->browsable) && $munge !== null) {
if ($authority !== null) {
$result = str_replace('%s', rawurlencode($result), $munge);
}
} }
return $result; return $result;
} }
/**
* Checks a host against an array blacklist
* @param $host Host to check
* @param $config HTMLPurifier_Config instance
* @param $context HTMLPurifier_Context instance
* @return bool Is spam?
*/
function checkBlacklist($host, &$config, &$context) {
$blacklist = $config->get('URI', 'HostBlacklist');
if (!empty($blacklist)) {
foreach($blacklist as $blacklisted_host_fragment) {
if (strpos($host, $blacklisted_host_fragment) !== false) {
return true;
}
}
}
return false;
}
} }
?>

View File

@@ -14,5 +14,4 @@ class HTMLPurifier_AttrDef_URI_Email extends HTMLPurifier_AttrDef
} }
// sub-implementations ?>
require_once 'HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php';

View File

@@ -20,3 +20,4 @@ class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_UR
} }
?>

View File

@@ -51,3 +51,4 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
} }
?>

View File

@@ -15,10 +15,13 @@ class HTMLPurifier_AttrDef_URI_IPv4 extends HTMLPurifier_AttrDef
*/ */
var $ip4; var $ip4;
function HTMLPurifier_AttrDef_URI_IPv4() {
$oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255
$this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})";
}
function validate($aIP, $config, &$context) { function validate($aIP, $config, &$context) {
if (!$this->ip4) $this->_loadRegex();
if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) if (preg_match('#^' . $this->ip4 . '$#s', $aIP))
{ {
return $aIP; return $aIP;
@@ -28,14 +31,6 @@ class HTMLPurifier_AttrDef_URI_IPv4 extends HTMLPurifier_AttrDef
} }
/**
* Lazy load function to prevent regex from being stuffed in
* cache.
*/
function _loadRegex() {
$oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255
$this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})";
}
} }
?>

View File

@@ -13,8 +13,6 @@ class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4
function validate($aIP, $config, &$context) { function validate($aIP, $config, &$context) {
if (!$this->ip4) $this->_loadRegex();
$original = $aIP; $original = $aIP;
$hex = '[0-9a-fA-F]'; $hex = '[0-9a-fA-F]';
@@ -98,3 +96,4 @@ class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4
} }
?>

View File

@@ -55,3 +55,4 @@ class HTMLPurifier_AttrTransform
} }
?>

View File

@@ -28,3 +28,4 @@ class HTMLPurifier_AttrTransform_BdoDir extends HTMLPurifier_AttrTransform
} }
?>

View File

@@ -23,3 +23,4 @@ extends HTMLPurifier_AttrTransform {
} }
?>

View File

@@ -36,3 +36,4 @@ extends HTMLPurifier_AttrTransform {
} }
?>

View File

@@ -17,3 +17,4 @@ class HTMLPurifier_AttrTransform_Border extends HTMLPurifier_AttrTransform {
} }
?>

View File

@@ -57,3 +57,4 @@ class HTMLPurifier_AttrTransform_EnumToCSS extends HTMLPurifier_AttrTransform {
} }
?>

View File

@@ -20,10 +20,7 @@ HTMLPurifier_ConfigSchema::define(
); );
/** /**
* Transform that supplies default values for the src and alt attributes * Post-transform that ensures the required attrs of img (alt and src) are set
* in img tags, as well as prevents the img tag from being removed
* because of a missing alt tag. This needs to be registered as both
* a pre and post attribute transform.
*/ */
class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
{ {
@@ -32,7 +29,6 @@ class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
$src = true; $src = true;
if (!isset($attr['src'])) { if (!isset($attr['src'])) {
if ($config->get('Core', 'RemoveInvalidImg')) return $attr;
$attr['src'] = $config->get('Attr', 'DefaultInvalidImage'); $attr['src'] = $config->get('Attr', 'DefaultInvalidImage');
$src = false; $src = false;
} }
@@ -51,3 +47,4 @@ class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
} }
?>

View File

@@ -44,3 +44,4 @@ extends HTMLPurifier_AttrTransform {
} }
?>

View File

@@ -27,3 +27,4 @@ class HTMLPurifier_AttrTransform_Lang extends HTMLPurifier_AttrTransform
} }
?>

View File

@@ -26,3 +26,4 @@ class HTMLPurifier_AttrTransform_Length extends HTMLPurifier_AttrTransform
} }
?>

View File

@@ -18,3 +18,4 @@ class HTMLPurifier_AttrTransform_Name extends HTMLPurifier_AttrTransform
} }
?>

View File

@@ -1,14 +1,10 @@
<?php <?php
require_once 'HTMLPurifier/AttrDef/Lang.php';
require_once 'HTMLPurifier/AttrDef/Enum.php';
require_once 'HTMLPurifier/AttrDef/HTML/Bool.php';
require_once 'HTMLPurifier/AttrDef/HTML/ID.php'; require_once 'HTMLPurifier/AttrDef/HTML/ID.php';
require_once 'HTMLPurifier/AttrDef/HTML/Length.php'; require_once 'HTMLPurifier/AttrDef/HTML/Length.php';
require_once 'HTMLPurifier/AttrDef/HTML/MultiLength.php'; require_once 'HTMLPurifier/AttrDef/HTML/MultiLength.php';
require_once 'HTMLPurifier/AttrDef/HTML/Nmtokens.php'; require_once 'HTMLPurifier/AttrDef/HTML/Nmtokens.php';
require_once 'HTMLPurifier/AttrDef/HTML/Pixels.php'; require_once 'HTMLPurifier/AttrDef/HTML/Pixels.php';
require_once 'HTMLPurifier/AttrDef/HTML/Color.php';
require_once 'HTMLPurifier/AttrDef/Integer.php'; require_once 'HTMLPurifier/AttrDef/Integer.php';
require_once 'HTMLPurifier/AttrDef/Text.php'; require_once 'HTMLPurifier/AttrDef/Text.php';
require_once 'HTMLPurifier/AttrDef/URI.php'; require_once 'HTMLPurifier/AttrDef/URI.php';
@@ -20,19 +16,14 @@ class HTMLPurifier_AttrTypes
{ {
/** /**
* Lookup array of attribute string identifiers to concrete implementations * Lookup array of attribute string identifiers to concrete implementations
* @protected * @public
*/ */
var $info = array(); var $info = array();
/** /**
* Constructs the info array, supplying default implementations for attribute * Constructs the info array
* types.
*/ */
function HTMLPurifier_AttrTypes() { function HTMLPurifier_AttrTypes() {
// pseudo-types, must be instantiated via shorthand
$this->info['Enum'] = new HTMLPurifier_AttrDef_Enum();
$this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool();
$this->info['CDATA'] = new HTMLPurifier_AttrDef_Text(); $this->info['CDATA'] = new HTMLPurifier_AttrDef_Text();
$this->info['ID'] = new HTMLPurifier_AttrDef_HTML_ID(); $this->info['ID'] = new HTMLPurifier_AttrDef_HTML_ID();
$this->info['Length'] = new HTMLPurifier_AttrDef_HTML_Length(); $this->info['Length'] = new HTMLPurifier_AttrDef_HTML_Length();
@@ -41,45 +32,10 @@ class HTMLPurifier_AttrTypes
$this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels(); $this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels();
$this->info['Text'] = new HTMLPurifier_AttrDef_Text(); $this->info['Text'] = new HTMLPurifier_AttrDef_Text();
$this->info['URI'] = new HTMLPurifier_AttrDef_URI(); $this->info['URI'] = new HTMLPurifier_AttrDef_URI();
$this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang();
$this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color();
// unimplemented aliases
$this->info['ContentType'] = new HTMLPurifier_AttrDef_Text();
// number is really a positive integer (one or more digits) // number is really a positive integer (one or more digits)
// FIXME: ^^ not always, see start and value of list items
$this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
} }
/**
* Retrieves a type
* @param $type String type name
* @return Object AttrDef for type
*/
function get($type) {
// determine if there is any extra info tacked on
if (strpos($type, '#') !== false) list($type, $string) = explode('#', $type, 2);
else $string = '';
if (!isset($this->info[$type])) {
trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR);
return;
}
return $this->info[$type]->make($string);
}
/**
* Sets a new implementation for a type
* @param $type String type name
* @param $impl Object AttrDef for type
*/
function set($type, $impl) {
$this->info[$type] = $impl;
}
} }
?>

View File

@@ -1,146 +0,0 @@
<?php
/**
* Validates the attributes of a token. Doesn't manage required attributes
* very well. The only reason we factored this out was because RemoveForeignElements
* also needed it besides ValidateAttributes.
*/
class HTMLPurifier_AttrValidator
{
/**
* Validates the attributes of a token, returning a modified token
* that has valid tokens
* @param $token Reference to token to validate. We require a reference
* because the operation this class performs on the token are
* not atomic, so the context CurrentToken to be updated
* throughout
* @param $config Instance of HTMLPurifier_Config
* @param $context Instance of HTMLPurifier_Context
*/
function validateToken(&$token, &$config, &$context) {
$definition = $config->getHTMLDefinition();
$e =& $context->get('ErrorCollector', true);
// initialize IDAccumulator if necessary
$ok =& $context->get('IDAccumulator', true);
if (!$ok) {
$id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
$context->register('IDAccumulator', $id_accumulator);
}
// initialize CurrentToken if necessary
$current_token =& $context->get('CurrentToken', true);
if (!$current_token) $context->register('CurrentToken', $token);
if ($token->type !== 'start' && $token->type !== 'empty') return $token;
// create alias to global definition array, see also $defs
// DEFINITION CALL
$d_defs = $definition->info_global_attr;
// reference attributes for easy manipulation
$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);
}
// 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);
}
// create alias to this element's attribute definition array, see
// also $d_defs (global attribute definition array)
// DEFINITION CALL
$defs = $definition->info[$token->name]->attr;
$attr_key = false;
$context->register('CurrentAttr', $attr_key);
// iterate through all the attribute keypairs
// Watch out for name collisions: $key has previously been used
foreach ($attr as $attr_key => $value) {
// call the definition
if ( isset($defs[$attr_key]) ) {
// there is a local definition defined
if ($defs[$attr_key] === false) {
// We've explicitly been told not to allow this element.
// This is usually when there's a global definition
// that must be overridden.
// Theoretically speaking, we could have a
// AttrDef_DenyAll, but this is faster!
$result = false;
} else {
// validate according to the element's definition
$result = $defs[$attr_key]->validate(
$value, $config, $context
);
}
} elseif ( isset($d_defs[$attr_key]) ) {
// there is a global definition defined, validate according
// to the global definition
$result = $d_defs[$attr_key]->validate(
$value, $config, $context
);
} else {
// system never heard of the attribute? DELETE!
$result = false;
}
// put the results into effect
if ($result === false || $result === null) {
// this is a generic error message that should replaced
// with more specific ones when possible
if ($e) $e->send(E_ERROR, 'AttrValidator: Attribute removed');
// remove the attribute
unset($attr[$attr_key]);
} elseif (is_string($result)) {
// generally, if a substitution is happening, there
// was some sort of implicit correction going on. We'll
// delegate it to the attribute classes to say exactly what.
// simple substitution
$attr[$attr_key] = $result;
}
// we'd also want slightly more complicated substitution
// involving an array as the return value,
// although we're not sure how colliding attributes would
// resolve (certain ones would be completely overriden,
// others would prepend themselves).
}
$context->destroy('CurrentAttr');
// post transforms
// 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);
}
// 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);
}
// destroy CurrentToken if we made it ourselves
if (!$current_token) $context->destroy('CurrentToken');
}
}

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