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

Compare commits

...

27 Commits

Author SHA1 Message Date
Edward Z. Yang
6f389f0f25 Release 4.6.0.
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
2013-11-30 00:25:19 -08:00
Edward Z. Yang
8cd08620dc Conditionalize hash_hmac tests for 5.0
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-11-29 22:27:01 -08:00
Edward Z. Yang
0beecad78a Add Twitter handle to release notes.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-11-29 22:26:57 -08:00
Edward Z. Yang
54477c172b Fix infinite loop in Lexer.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-27 21:41:08 -07:00
Edward Z. Yang
e52d1fe310 Fix < PHP 5.4 compatibility break. Thanks GromNaN for submitting the patch.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-22 14:17:41 -07:00
Edward Z. Yang
0767bbc12d Rewrite FixNesting implementation to be tree-based.
This mega-patch rips out the FixNesting implementation and the related
ChildDef components.  The primary algorithmic change is to convert from
use of tokens to tree nodes, which are far more amenable to the style
of processing that FixNesting uses.  Additionally, FixNesting has been
changed to go bottom-up rather than top-down, in order to avoid needing
to implement backtracking.

This patch simplifies a good deal of the relevant logic, since we no
longer need to continually recalculate the nesting structure when
processing things.  However, the conversion to the alternate format
incurs some overhead, so for small inputs these changes are not a win.
One possibility to greatly reduce the constant factors here is to switch
to entirely using libxml's representation, and never serializing tokens;
this would require one to rewrite injectors, however.

The iterative post-order traversal in FixNesting is a bit subtle, but
we have essentially reified the stack and continuations.

We've removed support for %Core.EscapeInvalidChildren.

Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-20 22:37:01 -07:00
Edward Z. Yang
b3640e1af6 Add conversion functions for our own tree format.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-20 15:05:11 -07:00
Edward Z. Yang
be5769804a Make the Token class abstract.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-17 16:13:04 -07:00
Edward Z. Yang
d6fbd7df22 Remove some unnecessary pass-by-reference.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-16 18:55:23 -07:00
Edward Z. Yang
804a06f01e Remove PHP 4 compatibility hack.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-16 18:36:44 -07:00
Edward Z. Yang
8f401f769e Use a Zipper to process MakeWellFormed, removing quadratic behavior.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-13 13:21:02 -07:00
Edward Z. Yang
82bcc62058 Properly handle context variables that are NULL.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-13 13:21:02 -07:00
Edward Z. Yang
f17490f009 Implementation of a Zipper, for efficient splice.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-13 01:16:32 -07:00
Edward Z. Yang
a5fc37d8c3 Improve gitignore.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-10-13 00:18:11 -07:00
Edward Z. Yang
412bae13b5 Fix quadratic behavior in DOMLex due to array_shift.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-09-17 00:48:42 -07:00
Edward Z. Yang
cf44f399f8 Properly use HMAC for secure munging.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-09-13 21:16:50 -07:00
Marcus Bointon
fac747bdbd PSR-2 reformatting PHPDoc corrections
With minor corrections.

Signed-off-by: Marcus Bointon <marcus@synchromedia.co.uk>
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-08-17 22:27:26 -04:00
Edward Z. Yang
19eee14899 Tighten up invariants.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-07-26 21:54:53 -07:00
Edward Z. Yang
25d49f4ec0 Explicitly specify decorator name.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-07-26 21:37:33 -07:00
Edward Z. Yang
53c2907706 New directive %Core.AllowHostnameUnderscore
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-07-26 21:33:39 -07:00
Edward Z. Yang
af7107e830 Add note fall through is intentional.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-07-18 10:22:45 -07:00
Marcus Bointon
107b3055a1 Fix var name conflict in loadArray 2013-07-16 21:56:29 -07:00
Synchro
29a3c70370 A bunch of PHPdoc and php codesniffer corrections - no functional code changes 2013-07-16 21:53:17 -07:00
Edward Z. Yang
75bd7abcc7 Make list nesting test more sensitive.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-06-06 13:08:13 -07:00
Edward Z. Yang
0680832d41 Use info_parent_def to get parent information, since it may not be present in info array.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-05-21 17:19:59 -07:00
Edward Z. Yang
19360ddb36 Ignore commas and nbsps for linkification. Thanks nAS for contributing.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-05-21 16:43:59 -07:00
Edward Z. Yang
3c903b7463 Doc fix.
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
2013-05-18 08:48:47 -07:00
460 changed files with 14822 additions and 7677 deletions

4
.gitignore vendored
View File

@@ -22,3 +22,7 @@ docs/doxygen*
/*.php /*.php
vendor vendor
composer.lock composer.lock
*.rej
*.orig
*.bak
core

View File

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

2
FOCUS
View File

@@ -1,4 +1,4 @@
4 - Minor feature enhancements 9 - Major security fixes
[ Appendix A: Release focus IDs ] [ Appendix A: Release focus IDs ]
0 - N/A 0 - N/A

19
NEWS
View File

@@ -9,10 +9,27 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
. Internal change . Internal change
========================== ==========================
4.6.0, unknown release date 4.6.0, released 2013-11-30
# Secure URI munge hashing algorithm has changed to hash_hmac("sha256", $url, $secret).
Please update any verification scripts you may have.
# URI parsing algorithm was made more strict, so only prefixes which # URI parsing algorithm was made more strict, so only prefixes which
looks like schemes will actually be schemes. Thanks looks like schemes will actually be schemes. Thanks
Michael Gusev <mgusev@sugarcrm.com> for fixing. Michael Gusev <mgusev@sugarcrm.com> for fixing.
# %Core.EscapeInvalidChildren is no longer supported, and no longer does
anything.
! New directive %Core.AllowHostnameUnderscore which allows underscores
in hostnames.
- Eliminate quadratic behavior in DOMLex by using a proper queue.
Thanks Ole Laursen for noticing this.
- Rewritten MakeWellFormed/FixNesting implementation eliminates quadratic
behavior in the rest of the purificaiton pipeline. Thanks Chedburn
Networks for sponsoring this work.
- Made Linkify URL parser a bit less permissive, so that non-breaking
spaces and commas are not included as part of URL. Thanks nAS for fixing.
- Fix some bad interactions with %HTML.Allowed and injectors. Thanks
David Hirtz for reporting.
- Fix infinite loop in DirectLex. Thanks Ashar Javed (@soaj1664ashar)
for reporting.
4.5.0, released 2013-02-17 4.5.0, released 2013-02-17
# Fix bug where stacked attribute transforms clobber each other; # Fix bug where stacked attribute transforms clobber each other;

View File

@@ -1 +1 @@
4.5.0 4.6.0

View File

@@ -1,6 +1,5 @@
HTML Purifier 4.5.0 is a minor bugfix and feature release, containing an HTML Purifier 4.6.0 is a major security release, fixing numerous bad
accumulation of changes over a year. CSS support has been extended to quadratic asymptotics in HTML Purifier's core algorithms. Most users will
support display:inline-block, white-space, underscores in font families, see a decent speedup on large inputs, although small inputs may take
page-break-* CSS3 properties (when proprietary is enabled.) We now use longer. Additionally, the secure URI munging algorithm has changed to
SHA-1 to identify cached definitions, and the semantics of stacked do a proper HMAC. There are some other miscellaneous bugfixes as well.
attribute transforms has changed slightly.

View File

@@ -23,15 +23,16 @@ if (version_compare(PHP_VERSION, '5', '>=')) {
class RowTimer extends Benchmark_Timer class RowTimer extends Benchmark_Timer
{ {
var $name; public $name;
function RowTimer($name, $auto = false) { public function RowTimer($name, $auto = false)
{
$this->name = htmlentities($name); $this->name = htmlentities($name);
$this->Benchmark_Timer($auto); $this->Benchmark_Timer($auto);
} }
function getOutput() { public function getOutput()
{
$total = $this->TimeElapsed(); $total = $this->TimeElapsed();
$result = $this->getProfiling(); $result = $this->getProfiling();
$dashes = ''; $dashes = '';
@@ -68,7 +69,8 @@ class RowTimer extends Benchmark_Timer
} }
} }
function print_lexers() { function print_lexers()
{
global $LEXERS; global $LEXERS;
$first = true; $first = true;
foreach ($LEXERS as $key => $value) { foreach ($LEXERS as $key => $value) {
@@ -78,7 +80,8 @@ function print_lexers() {
} }
} }
function do_benchmark($name, $document) { function do_benchmark($name, $document)
{
global $LEXERS, $RUNS; global $LEXERS, $RUNS;
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();

View File

@@ -2,546 +2,546 @@
<usage> <usage>
<directive id="Core.CollectErrors"> <directive id="Core.CollectErrors">
<file name="HTMLPurifier.php"> <file name="HTMLPurifier.php">
<line>131</line> <line>162</line>
</file> </file>
<file name="HTMLPurifier/Lexer.php"> <file name="HTMLPurifier/Lexer.php">
<line>81</line> <line>85</line>
<line>284</line> <line>315</line>
</file> </file>
<file name="HTMLPurifier/Lexer/DirectLex.php"> <file name="HTMLPurifier/Lexer/DirectLex.php">
<line>53</line> <line>67</line>
<line>73</line> <line>87</line>
<line>348</line> <line>385</line>
</file> </file>
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php"> <file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>50</line> <line>57</line>
</file> </file>
</directive> </directive>
<directive id="CSS.MaxImgLength"> <directive id="CSS.MaxImgLength">
<file name="HTMLPurifier/CSSDefinition.php"> <file name="HTMLPurifier/CSSDefinition.php">
<line>157</line> <line>226</line>
</file> </file>
</directive> </directive>
<directive id="CSS.Proprietary"> <directive id="CSS.Proprietary">
<file name="HTMLPurifier/CSSDefinition.php"> <file name="HTMLPurifier/CSSDefinition.php">
<line>215</line> <line>319</line>
</file> </file>
</directive> </directive>
<directive id="CSS.AllowTricky"> <directive id="CSS.AllowTricky">
<file name="HTMLPurifier/CSSDefinition.php"> <file name="HTMLPurifier/CSSDefinition.php">
<line>219</line> <line>323</line>
</file> </file>
</directive> </directive>
<directive id="CSS.Trusted"> <directive id="CSS.Trusted">
<file name="HTMLPurifier/CSSDefinition.php"> <file name="HTMLPurifier/CSSDefinition.php">
<line>223</line> <line>327</line>
</file> </file>
</directive> </directive>
<directive id="CSS.AllowImportant"> <directive id="CSS.AllowImportant">
<file name="HTMLPurifier/CSSDefinition.php"> <file name="HTMLPurifier/CSSDefinition.php">
<line>227</line> <line>331</line>
</file> </file>
</directive> </directive>
<directive id="CSS.AllowedProperties"> <directive id="CSS.AllowedProperties">
<file name="HTMLPurifier/CSSDefinition.php"> <file name="HTMLPurifier/CSSDefinition.php">
<line>302</line> <line>447</line>
</file> </file>
</directive> </directive>
<directive id="CSS.ForbiddenProperties"> <directive id="CSS.ForbiddenProperties">
<file name="HTMLPurifier/CSSDefinition.php"> <file name="HTMLPurifier/CSSDefinition.php">
<line>316</line> <line>463</line>
</file> </file>
</directive> </directive>
<directive id="Cache.DefinitionImpl"> <directive id="Cache.DefinitionImpl">
<file name="HTMLPurifier/DefinitionCacheFactory.php"> <file name="HTMLPurifier/DefinitionCacheFactory.php">
<line>49</line> <line>66</line>
</file> </file>
</directive> </directive>
<directive id="HTML.Doctype"> <directive id="HTML.Doctype">
<file name="HTMLPurifier/DoctypeRegistry.php"> <file name="HTMLPurifier/DoctypeRegistry.php">
<line>83</line> <line>119</line>
</file> </file>
</directive> </directive>
<directive id="HTML.CustomDoctype"> <directive id="HTML.CustomDoctype">
<file name="HTMLPurifier/DoctypeRegistry.php"> <file name="HTMLPurifier/DoctypeRegistry.php">
<line>85</line> <line>123</line>
</file> </file>
</directive> </directive>
<directive id="HTML.XHTML"> <directive id="HTML.XHTML">
<file name="HTMLPurifier/DoctypeRegistry.php"> <file name="HTMLPurifier/DoctypeRegistry.php">
<line>88</line> <line>128</line>
</file> </file>
</directive> </directive>
<directive id="HTML.Strict"> <directive id="HTML.Strict">
<file name="HTMLPurifier/DoctypeRegistry.php"> <file name="HTMLPurifier/DoctypeRegistry.php">
<line>93</line> <line>133</line>
</file> </file>
</directive> </directive>
<directive id="Core.Encoding"> <directive id="Core.Encoding">
<file name="HTMLPurifier/Encoder.php"> <file name="HTMLPurifier/Encoder.php">
<line>337</line> <line>374</line>
<line>372</line> <line>422</line>
</file> </file>
</directive> </directive>
<directive id="Test.ForceNoIconv"> <directive id="Test.ForceNoIconv">
<file name="HTMLPurifier/Encoder.php"> <file name="HTMLPurifier/Encoder.php">
<line>341</line> <line>382</line>
<line>379</line> <line>433</line>
</file> </file>
</directive> </directive>
<directive id="Core.EscapeNonASCIICharacters"> <directive id="Core.EscapeNonASCIICharacters">
<file name="HTMLPurifier/Encoder.php"> <file name="HTMLPurifier/Encoder.php">
<line>373</line> <line>423</line>
</file> </file>
</directive> </directive>
<directive id="Output.CommentScriptContents"> <directive id="Output.CommentScriptContents">
<file name="HTMLPurifier/Generator.php"> <file name="HTMLPurifier/Generator.php">
<line>61</line> <line>70</line>
</file> </file>
</directive> </directive>
<directive id="Output.FixInnerHTML"> <directive id="Output.FixInnerHTML">
<file name="HTMLPurifier/Generator.php"> <file name="HTMLPurifier/Generator.php">
<line>62</line> <line>71</line>
</file> </file>
</directive> </directive>
<directive id="Output.SortAttr"> <directive id="Output.SortAttr">
<file name="HTMLPurifier/Generator.php"> <file name="HTMLPurifier/Generator.php">
<line>63</line> <line>72</line>
</file> </file>
</directive> </directive>
<directive id="Output.FlashCompat"> <directive id="Output.FlashCompat">
<file name="HTMLPurifier/Generator.php"> <file name="HTMLPurifier/Generator.php">
<line>64</line> <line>73</line>
</file> </file>
</directive> </directive>
<directive id="Output.TidyFormat"> <directive id="Output.TidyFormat">
<file name="HTMLPurifier/Generator.php"> <file name="HTMLPurifier/Generator.php">
<line>93</line> <line>104</line>
</file> </file>
</directive> </directive>
<directive id="Core.NormalizeNewlines"> <directive id="Core.NormalizeNewlines">
<file name="HTMLPurifier/Generator.php"> <file name="HTMLPurifier/Generator.php">
<line>107</line> <line>122</line>
</file> </file>
<file name="HTMLPurifier/Lexer.php"> <file name="HTMLPurifier/Lexer.php">
<line>266</line> <line>297</line>
</file> </file>
</directive> </directive>
<directive id="Output.Newline"> <directive id="Output.Newline">
<file name="HTMLPurifier/Generator.php"> <file name="HTMLPurifier/Generator.php">
<line>108</line> <line>123</line>
</file> </file>
</directive> </directive>
<directive id="HTML.BlockWrapper"> <directive id="HTML.BlockWrapper">
<file name="HTMLPurifier/HTMLDefinition.php"> <file name="HTMLPurifier/HTMLDefinition.php">
<line>222</line> <line>263</line>
</file> </file>
</directive> </directive>
<directive id="HTML.Parent"> <directive id="HTML.Parent">
<file name="HTMLPurifier/HTMLDefinition.php"> <file name="HTMLPurifier/HTMLDefinition.php">
<line>230</line> <line>273</line>
</file> </file>
</directive> </directive>
<directive id="HTML.AllowedElements"> <directive id="HTML.AllowedElements">
<file name="HTMLPurifier/HTMLDefinition.php"> <file name="HTMLPurifier/HTMLDefinition.php">
<line>247</line> <line>291</line>
</file> </file>
</directive> </directive>
<directive id="HTML.AllowedAttributes"> <directive id="HTML.AllowedAttributes">
<file name="HTMLPurifier/HTMLDefinition.php"> <file name="HTMLPurifier/HTMLDefinition.php">
<line>248</line> <line>292</line>
</file> </file>
</directive> </directive>
<directive id="HTML.Allowed"> <directive id="HTML.Allowed">
<file name="HTMLPurifier/HTMLDefinition.php"> <file name="HTMLPurifier/HTMLDefinition.php">
<line>251</line> <line>295</line>
</file> </file>
</directive> </directive>
<directive id="HTML.ForbiddenElements"> <directive id="HTML.ForbiddenElements">
<file name="HTMLPurifier/HTMLDefinition.php"> <file name="HTMLPurifier/HTMLDefinition.php">
<line>342</line> <line>399</line>
</file> </file>
</directive> </directive>
<directive id="HTML.ForbiddenAttributes"> <directive id="HTML.ForbiddenAttributes">
<file name="HTMLPurifier/HTMLDefinition.php"> <file name="HTMLPurifier/HTMLDefinition.php">
<line>343</line> <line>400</line>
</file> </file>
</directive> </directive>
<directive id="HTML.Trusted"> <directive id="HTML.Trusted">
<file name="HTMLPurifier/HTMLModuleManager.php"> <file name="HTMLPurifier/HTMLModuleManager.php">
<line>204</line> <line>234</line>
</file> </file>
<file name="HTMLPurifier/Lexer.php"> <file name="HTMLPurifier/Lexer.php">
<line>271</line> <line>302</line>
</file> </file>
<file name="HTMLPurifier/HTMLModule/Image.php"> <file name="HTMLPurifier/HTMLModule/Image.php">
<line>27</line> <line>37</line>
</file> </file>
<file name="HTMLPurifier/Lexer/DirectLex.php"> <file name="HTMLPurifier/Lexer/DirectLex.php">
<line>36</line> <line>47</line>
</file> </file>
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php"> <file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>23</line> <line>30</line>
</file> </file>
</directive> </directive>
<directive id="HTML.AllowedModules"> <directive id="HTML.AllowedModules">
<file name="HTMLPurifier/HTMLModuleManager.php"> <file name="HTMLPurifier/HTMLModuleManager.php">
<line>211</line> <line>241</line>
</file> </file>
</directive> </directive>
<directive id="HTML.CoreModules"> <directive id="HTML.CoreModules">
<file name="HTMLPurifier/HTMLModuleManager.php"> <file name="HTMLPurifier/HTMLModuleManager.php">
<line>212</line> <line>242</line>
</file> </file>
</directive> </directive>
<directive id="HTML.Proprietary"> <directive id="HTML.Proprietary">
<file name="HTMLPurifier/HTMLModuleManager.php"> <file name="HTMLPurifier/HTMLModuleManager.php">
<line>222</line> <line>256</line>
</file> </file>
</directive> </directive>
<directive id="HTML.SafeObject"> <directive id="HTML.SafeObject">
<file name="HTMLPurifier/HTMLModuleManager.php"> <file name="HTMLPurifier/HTMLModuleManager.php">
<line>225</line> <line>259</line>
</file> </file>
</directive> </directive>
<directive id="HTML.SafeEmbed"> <directive id="HTML.SafeEmbed">
<file name="HTMLPurifier/HTMLModuleManager.php"> <file name="HTMLPurifier/HTMLModuleManager.php">
<line>228</line> <line>262</line>
</file> </file>
</directive> </directive>
<directive id="HTML.SafeScripting"> <directive id="HTML.SafeScripting">
<file name="HTMLPurifier/HTMLModuleManager.php"> <file name="HTMLPurifier/HTMLModuleManager.php">
<line>231</line> <line>265</line>
</file> </file>
<file name="HTMLPurifier/HTMLModule/SafeScripting.php"> <file name="HTMLPurifier/HTMLModule/SafeScripting.php">
<line>17</line> <line>22</line>
</file> </file>
</directive> </directive>
<directive id="HTML.Nofollow"> <directive id="HTML.Nofollow">
<file name="HTMLPurifier/HTMLModuleManager.php"> <file name="HTMLPurifier/HTMLModuleManager.php">
<line>234</line> <line>268</line>
</file> </file>
</directive> </directive>
<directive id="HTML.TargetBlank"> <directive id="HTML.TargetBlank">
<file name="HTMLPurifier/HTMLModuleManager.php"> <file name="HTMLPurifier/HTMLModuleManager.php">
<line>237</line> <line>271</line>
</file> </file>
</directive> </directive>
<directive id="Attr.IDBlacklist"> <directive id="Attr.IDBlacklist">
<file name="HTMLPurifier/IDAccumulator.php"> <file name="HTMLPurifier/IDAccumulator.php">
<line>26</line> <line>27</line>
</file> </file>
</directive> </directive>
<directive id="Core.Language"> <directive id="Core.Language">
<file name="HTMLPurifier/LanguageFactory.php"> <file name="HTMLPurifier/LanguageFactory.php">
<line>88</line> <line>93</line>
</file> </file>
</directive> </directive>
<directive id="Core.LexerImpl"> <directive id="Core.LexerImpl">
<file name="HTMLPurifier/Lexer.php"> <file name="HTMLPurifier/Lexer.php">
<line>76</line> <line>80</line>
</file> </file>
</directive> </directive>
<directive id="Core.MaintainLineNumbers"> <directive id="Core.MaintainLineNumbers">
<file name="HTMLPurifier/Lexer.php"> <file name="HTMLPurifier/Lexer.php">
<line>80</line> <line>84</line>
</file> </file>
<file name="HTMLPurifier/Lexer/DirectLex.php"> <file name="HTMLPurifier/Lexer/DirectLex.php">
<line>48</line> <line>62</line>
</file> </file>
</directive> </directive>
<directive id="Core.ConvertDocumentToFragment"> <directive id="Core.ConvertDocumentToFragment">
<file name="HTMLPurifier/Lexer.php"> <file name="HTMLPurifier/Lexer.php">
<line>282</line> <line>313</line>
</file> </file>
</directive> </directive>
<directive id="Core.RemoveProcessingInstructions"> <directive id="Core.RemoveProcessingInstructions">
<file name="HTMLPurifier/Lexer.php"> <file name="HTMLPurifier/Lexer.php">
<line>303</line> <line>334</line>
</file> </file>
</directive> </directive>
<directive id="URI."> <directive id="URI.">
<file name="HTMLPurifier/URIDefinition.php"> <file name="HTMLPurifier/URIDefinition.php">
<line>60</line> <line>65</line>
</file> </file>
<file name="HTMLPurifier/URIFilter/Munge.php"> <file name="HTMLPurifier/URIFilter/Munge.php">
<line>12</line> <line>46</line>
</file> </file>
</directive> </directive>
<directive id="URI.Host"> <directive id="URI.Host">
<file name="HTMLPurifier/URIDefinition.php"> <file name="HTMLPurifier/URIDefinition.php">
<line>70</line> <line>76</line>
</file> </file>
<file name="HTMLPurifier/URIScheme.php"> <file name="HTMLPurifier/URIScheme.php">
<line>81</line> <line>89</line>
</file> </file>
</directive> </directive>
<directive id="URI.Base"> <directive id="URI.Base">
<file name="HTMLPurifier/URIDefinition.php"> <file name="HTMLPurifier/URIDefinition.php">
<line>71</line> <line>77</line>
</file> </file>
</directive> </directive>
<directive id="URI.DefaultScheme"> <directive id="URI.DefaultScheme">
<file name="HTMLPurifier/URIDefinition.php"> <file name="HTMLPurifier/URIDefinition.php">
<line>78</line> <line>84</line>
</file> </file>
</directive> </directive>
<directive id="URI.AllowedSchemes"> <directive id="URI.AllowedSchemes">
<file name="HTMLPurifier/URISchemeRegistry.php"> <file name="HTMLPurifier/URISchemeRegistry.php">
<line>41</line> <line>48</line>
</file> </file>
</directive> </directive>
<directive id="URI.OverrideAllowedSchemes"> <directive id="URI.OverrideAllowedSchemes">
<file name="HTMLPurifier/URISchemeRegistry.php"> <file name="HTMLPurifier/URISchemeRegistry.php">
<line>42</line> <line>49</line>
</file> </file>
</directive> </directive>
<directive id="URI.Disable"> <directive id="URI.Disable">
<file name="HTMLPurifier/AttrDef/URI.php"> <file name="HTMLPurifier/AttrDef/URI.php">
<line>28</line> <line>47</line>
</file> </file>
</directive> </directive>
<directive id="Core.ColorKeywords"> <directive id="Core.ColorKeywords">
<file name="HTMLPurifier/AttrDef/CSS/Color.php"> <file name="HTMLPurifier/AttrDef/CSS/Color.php">
<line>12</line> <line>19</line>
</file> </file>
<file name="HTMLPurifier/AttrDef/HTML/Color.php"> <file name="HTMLPurifier/AttrDef/HTML/Color.php">
<line>12</line> <line>19</line>
</file> </file>
</directive> </directive>
<directive id="CSS.AllowedFonts"> <directive id="CSS.AllowedFonts">
<file name="HTMLPurifier/AttrDef/CSS/FontFamily.php"> <file name="HTMLPurifier/AttrDef/CSS/FontFamily.php">
<line>50</line> <line>64</line>
</file> </file>
</directive> </directive>
<directive id="Attr.AllowedClasses"> <directive id="Attr.AllowedClasses">
<file name="HTMLPurifier/AttrDef/HTML/Class.php"> <file name="HTMLPurifier/AttrDef/HTML/Class.php">
<line>18</line> <line>33</line>
</file> </file>
</directive> </directive>
<directive id="Attr.ForbiddenClasses"> <directive id="Attr.ForbiddenClasses">
<file name="HTMLPurifier/AttrDef/HTML/Class.php"> <file name="HTMLPurifier/AttrDef/HTML/Class.php">
<line>19</line> <line>34</line>
</file> </file>
</directive> </directive>
<directive id="Attr.AllowedFrameTargets"> <directive id="Attr.AllowedFrameTargets">
<file name="HTMLPurifier/AttrDef/HTML/FrameTarget.php"> <file name="HTMLPurifier/AttrDef/HTML/FrameTarget.php">
<line>15</line> <line>32</line>
</file> </file>
</directive> </directive>
<directive id="Attr.EnableID"> <directive id="Attr.EnableID">
<file name="HTMLPurifier/AttrDef/HTML/ID.php"> <file name="HTMLPurifier/AttrDef/HTML/ID.php">
<line>30</line> <line>41</line>
</file> </file>
</directive> </directive>
<directive id="Attr.IDPrefix"> <directive id="Attr.IDPrefix">
<file name="HTMLPurifier/AttrDef/HTML/ID.php"> <file name="HTMLPurifier/AttrDef/HTML/ID.php">
<line>36</line> <line>51</line>
</file> </file>
</directive> </directive>
<directive id="Attr.IDPrefixLocal"> <directive id="Attr.IDPrefixLocal">
<file name="HTMLPurifier/AttrDef/HTML/ID.php"> <file name="HTMLPurifier/AttrDef/HTML/ID.php">
<line>38</line> <line>53</line>
<line>41</line> <line>58</line>
</file> </file>
</directive> </directive>
<directive id="Attr.IDBlacklistRegexp"> <directive id="Attr.IDBlacklistRegexp">
<file name="HTMLPurifier/AttrDef/HTML/ID.php"> <file name="HTMLPurifier/AttrDef/HTML/ID.php">
<line>64</line> <line>89</line>
</file> </file>
</directive> </directive>
<directive id="Attr."> <directive id="Attr.">
<file name="HTMLPurifier/AttrDef/HTML/LinkTypes.php"> <file name="HTMLPurifier/AttrDef/HTML/LinkTypes.php">
<line>30</line> <line>46</line>
</file>
</directive>
<directive id="Core.AllowHostnameUnderscore">
<file name="HTMLPurifier/AttrDef/URI/Host.php">
<line>77</line>
</file> </file>
</directive> </directive>
<directive id="Core.EnableIDNA"> <directive id="Core.EnableIDNA">
<file name="HTMLPurifier/AttrDef/URI/Host.php"> <file name="HTMLPurifier/AttrDef/URI/Host.php">
<line>67</line> <line>96</line>
</file> </file>
</directive> </directive>
<directive id="Attr.DefaultTextDir"> <directive id="Attr.DefaultTextDir">
<file name="HTMLPurifier/AttrTransform/BdoDir.php"> <file name="HTMLPurifier/AttrTransform/BdoDir.php">
<line>13</line> <line>22</line>
</file> </file>
</directive> </directive>
<directive id="Core.RemoveInvalidImg"> <directive id="Core.RemoveInvalidImg">
<file name="HTMLPurifier/AttrTransform/ImgRequired.php"> <file name="HTMLPurifier/AttrTransform/ImgRequired.php">
<line>18</line> <line>24</line>
</file> </file>
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php"> <file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>20</line> <line>27</line>
</file> </file>
</directive> </directive>
<directive id="Attr.DefaultInvalidImage"> <directive id="Attr.DefaultInvalidImage">
<file name="HTMLPurifier/AttrTransform/ImgRequired.php"> <file name="HTMLPurifier/AttrTransform/ImgRequired.php">
<line>19</line> <line>27</line>
</file> </file>
</directive> </directive>
<directive id="Attr.DefaultImageAlt"> <directive id="Attr.DefaultImageAlt">
<file name="HTMLPurifier/AttrTransform/ImgRequired.php"> <file name="HTMLPurifier/AttrTransform/ImgRequired.php">
<line>25</line> <line>33</line>
</file> </file>
</directive> </directive>
<directive id="Attr.DefaultInvalidImageAlt"> <directive id="Attr.DefaultInvalidImageAlt">
<file name="HTMLPurifier/AttrTransform/ImgRequired.php"> <file name="HTMLPurifier/AttrTransform/ImgRequired.php">
<line>33</line> <line>41</line>
</file> </file>
</directive> </directive>
<directive id="HTML.Attr.Name.UseCDATA"> <directive id="HTML.Attr.Name.UseCDATA">
<file name="HTMLPurifier/AttrTransform/Name.php"> <file name="HTMLPurifier/AttrTransform/Name.php">
<line>11</line> <line>18</line>
</file> </file>
<file name="HTMLPurifier/HTMLModule/Name.php"> <file name="HTMLPurifier/HTMLModule/Name.php">
<line>13</line> <line>19</line>
</file> </file>
</directive> </directive>
<directive id="HTML.FlashAllowFullScreen"> <directive id="HTML.FlashAllowFullScreen">
<file name="HTMLPurifier/AttrTransform/SafeParam.php"> <file name="HTMLPurifier/AttrTransform/SafeParam.php">
<line>38</line> <line>53</line>
</file>
</directive>
<directive id="Core.EscapeInvalidChildren">
<file name="HTMLPurifier/ChildDef/Required.php">
<line>62</line>
</file> </file>
</directive> </directive>
<directive id="Cache.SerializerPath"> <directive id="Cache.SerializerPath">
<file name="HTMLPurifier/DefinitionCache/Serializer.php"> <file name="HTMLPurifier/DefinitionCache/Serializer.php">
<line>91</line> <line>171</line>
</file> </file>
</directive> </directive>
<directive id="Cache.SerializerPermissions"> <directive id="Cache.SerializerPermissions">
<file name="HTMLPurifier/DefinitionCache/Serializer.php"> <file name="HTMLPurifier/DefinitionCache/Serializer.php">
<line>107</line> <line>188</line>
<line>124</line> <line>206</line>
</file> </file>
</directive> </directive>
<directive id="Filter.ExtractStyleBlocks.TidyImpl"> <directive id="Filter.ExtractStyleBlocks.TidyImpl">
<file name="HTMLPurifier/Filter/ExtractStyleBlocks.php"> <file name="HTMLPurifier/Filter/ExtractStyleBlocks.php">
<line>55</line> <line>94</line>
</file> </file>
</directive> </directive>
<directive id="Filter.ExtractStyleBlocks.Scope"> <directive id="Filter.ExtractStyleBlocks.Scope">
<file name="HTMLPurifier/Filter/ExtractStyleBlocks.php"> <file name="HTMLPurifier/Filter/ExtractStyleBlocks.php">
<line>79</line> <line>122</line>
</file> </file>
</directive> </directive>
<directive id="Filter.ExtractStyleBlocks.Escaping"> <directive id="Filter.ExtractStyleBlocks.Escaping">
<file name="HTMLPurifier/Filter/ExtractStyleBlocks.php"> <file name="HTMLPurifier/Filter/ExtractStyleBlocks.php">
<line>277</line> <line>327</line>
</file> </file>
</directive> </directive>
<directive id="HTML.SafeIframe"> <directive id="HTML.SafeIframe">
<file name="HTMLPurifier/HTMLModule/Iframe.php"> <file name="HTMLPurifier/HTMLModule/Iframe.php">
<line>17</line> <line>28</line>
</file> </file>
<file name="HTMLPurifier/URIFilter/SafeIframe.php"> <file name="HTMLPurifier/URIFilter/SafeIframe.php">
<line>23</line> <line>48</line>
</file> </file>
</directive> </directive>
<directive id="HTML.MaxImgLength"> <directive id="HTML.MaxImgLength">
<file name="HTMLPurifier/HTMLModule/Image.php"> <file name="HTMLPurifier/HTMLModule/Image.php">
<line>14</line> <line>21</line>
</file> </file>
<file name="HTMLPurifier/HTMLModule/SafeEmbed.php"> <file name="HTMLPurifier/HTMLModule/SafeEmbed.php">
<line>13</line> <line>18</line>
</file> </file>
<file name="HTMLPurifier/HTMLModule/SafeObject.php"> <file name="HTMLPurifier/HTMLModule/SafeObject.php">
<line>19</line> <line>24</line>
</file> </file>
</directive> </directive>
<directive id="HTML.TidyLevel"> <directive id="HTML.TidyLevel">
<file name="HTMLPurifier/HTMLModule/Tidy.php"> <file name="HTMLPurifier/HTMLModule/Tidy.php">
<line>45</line> <line>50</line>
</file> </file>
</directive> </directive>
<directive id="HTML.TidyAdd"> <directive id="HTML.TidyAdd">
<file name="HTMLPurifier/HTMLModule/Tidy.php"> <file name="HTMLPurifier/HTMLModule/Tidy.php">
<line>49</line> <line>54</line>
</file> </file>
</directive> </directive>
<directive id="HTML.TidyRemove"> <directive id="HTML.TidyRemove">
<file name="HTMLPurifier/HTMLModule/Tidy.php"> <file name="HTMLPurifier/HTMLModule/Tidy.php">
<line>50</line> <line>55</line>
</file> </file>
</directive> </directive>
<directive id="AutoFormat.PurifierLinkify.DocURL"> <directive id="AutoFormat.PurifierLinkify.DocURL">
<file name="HTMLPurifier/Injector/PurifierLinkify.php"> <file name="HTMLPurifier/Injector/PurifierLinkify.php">
<line>15</line> <line>31</line>
</file> </file>
</directive> </directive>
<directive id="AutoFormat.RemoveEmpty.RemoveNbsp"> <directive id="AutoFormat.RemoveEmpty.RemoveNbsp">
<file name="HTMLPurifier/Injector/RemoveEmpty.php"> <file name="HTMLPurifier/Injector/RemoveEmpty.php">
<line>15</line> <line>46</line>
</file> </file>
</directive> </directive>
<directive id="AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions"> <directive id="AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions">
<file name="HTMLPurifier/Injector/RemoveEmpty.php"> <file name="HTMLPurifier/Injector/RemoveEmpty.php">
<line>16</line> <line>47</line>
</file> </file>
</directive> </directive>
<directive id="Core.AggressivelyFixLt"> <directive id="Core.AggressivelyFixLt">
<file name="HTMLPurifier/Lexer/DOMLex.php"> <file name="HTMLPurifier/Lexer/DOMLex.php">
<line>44</line> <line>54</line>
</file> </file>
</directive> </directive>
<directive id="Core.DirectLexLineNumberSyncInterval"> <directive id="Core.DirectLexLineNumberSyncInterval">
<file name="HTMLPurifier/Lexer/DirectLex.php"> <file name="HTMLPurifier/Lexer/DirectLex.php">
<line>70</line> <line>84</line>
</file> </file>
</directive> </directive>
<directive id="Core.DisableExcludes"> <directive id="Core.DisableExcludes">
<file name="HTMLPurifier/Strategy/FixNesting.php"> <file name="HTMLPurifier/Strategy/FixNesting.php">
<line>57</line> <line>54</line>
</file> </file>
</directive> </directive>
<directive id="Core.EscapeInvalidTags"> <directive id="Core.EscapeInvalidTags">
<file name="HTMLPurifier/Strategy/MakeWellFormed.php"> <file name="HTMLPurifier/Strategy/MakeWellFormed.php">
<line>53</line> <line>72</line>
</file> </file>
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php"> <file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>19</line> <line>26</line>
</file> </file>
</directive> </directive>
<directive id="HTML.AllowedComments"> <directive id="HTML.AllowedComments">
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php"> <file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>24</line> <line>31</line>
</file> </file>
</directive> </directive>
<directive id="HTML.AllowedCommentsRegexp"> <directive id="HTML.AllowedCommentsRegexp">
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php"> <file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>25</line> <line>32</line>
</file> </file>
</directive> </directive>
<directive id="Core.RemoveScriptContents"> <directive id="Core.RemoveScriptContents">
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php"> <file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>28</line> <line>35</line>
</file> </file>
</directive> </directive>
<directive id="Core.HiddenElements"> <directive id="Core.HiddenElements">
<file name="HTMLPurifier/Strategy/RemoveForeignElements.php"> <file name="HTMLPurifier/Strategy/RemoveForeignElements.php">
<line>29</line> <line>36</line>
</file> </file>
</directive> </directive>
<directive id="URI.HostBlacklist"> <directive id="URI.HostBlacklist">
<file name="HTMLPurifier/URIFilter/HostBlacklist.php"> <file name="HTMLPurifier/URIFilter/HostBlacklist.php">
<line>12</line> <line>25</line>
</file> </file>
</directive> </directive>
<directive id="URI.MungeResources"> <directive id="URI.MungeResources">
<file name="HTMLPurifier/URIFilter/Munge.php"> <file name="HTMLPurifier/URIFilter/Munge.php">
<line>14</line> <line>48</line>
</file> </file>
</directive> </directive>
<directive id="URI.MungeSecretKey"> <directive id="URI.MungeSecretKey">
<file name="HTMLPurifier/URIFilter/Munge.php"> <file name="HTMLPurifier/URIFilter/Munge.php">
<line>15</line> <line>49</line>
</file> </file>
</directive> </directive>
<directive id="URI.SafeIframeRegexp"> <directive id="URI.SafeIframeRegexp">
<file name="HTMLPurifier/URIFilter/SafeIframe.php"> <file name="HTMLPurifier/URIFilter/SafeIframe.php">
<line>18</line> <line>35</line>
</file> </file>
</directive> </directive>
</usage> </usage>

View File

@@ -11,7 +11,8 @@ class ConfigDoc_HTMLXSLTProcessor
*/ */
protected $xsltProcessor; protected $xsltProcessor;
public function __construct($proc = false) { public function __construct($proc = false)
{
if ($proc === false) $proc = new XSLTProcessor(); if ($proc === false) $proc = new XSLTProcessor();
$this->xsltProcessor = $proc; $this->xsltProcessor = $proc;
} }
@@ -19,7 +20,8 @@ class ConfigDoc_HTMLXSLTProcessor
/** /**
* @note Allows a string $xsl filename to be passed * @note Allows a string $xsl filename to be passed
*/ */
public function importStylesheet($xsl) { public function importStylesheet($xsl)
{
if (is_string($xsl)) { if (is_string($xsl)) {
$xsl_file = $xsl; $xsl_file = $xsl;
$xsl = new DOMDocument(); $xsl = new DOMDocument();
@@ -34,7 +36,8 @@ class ConfigDoc_HTMLXSLTProcessor
* @return string HTML output * @return string HTML output
* @todo Rename to transformToXHTML, as transformToHTML is misleading * @todo Rename to transformToXHTML, as transformToHTML is misleading
*/ */
public function transformToHTML($xml) { public function transformToHTML($xml)
{
if (is_string($xml)) { if (is_string($xml)) {
$dom = new DOMDocument(); $dom = new DOMDocument();
$dom->load($xml); $dom->load($xml);
@@ -68,7 +71,8 @@ class ConfigDoc_HTMLXSLTProcessor
* Bulk sets parameters for the XSL stylesheet * Bulk sets parameters for the XSL stylesheet
* @param array $options Associative array of options to set * @param array $options Associative array of options to set
*/ */
public function setParameters($options) { public function setParameters($options)
{
foreach ($options as $name => $value) { foreach ($options as $name => $value) {
$this->xsltProcessor->setParameter('', $name, $value); $this->xsltProcessor->setParameter('', $name, $value);
} }
@@ -77,7 +81,8 @@ class ConfigDoc_HTMLXSLTProcessor
/** /**
* Forward any other calls to the XSLT processor * Forward any other calls to the XSLT processor
*/ */
public function __call($name, $arguments) { public function __call($name, $arguments)
{
call_user_func_array(array($this->xsltProcessor, $name), $arguments); call_user_func_array(array($this->xsltProcessor, $name), $arguments);
} }

View File

@@ -15,7 +15,8 @@ class FSTools
/** /**
* Returns a global instance of FSTools * Returns a global instance of FSTools
*/ */
static public function singleton() { public static function singleton()
{
if (empty(FSTools::$singleton)) FSTools::$singleton = new FSTools(); if (empty(FSTools::$singleton)) FSTools::$singleton = new FSTools();
return FSTools::$singleton; return FSTools::$singleton;
} }
@@ -24,7 +25,8 @@ class FSTools
* Sets our global singleton to something else; useful for overloading * Sets our global singleton to something else; useful for overloading
* functions. * functions.
*/ */
static public function setSingleton($singleton) { public static function setSingleton($singleton)
{
FSTools::$singleton = $singleton; FSTools::$singleton = $singleton;
} }
@@ -33,7 +35,8 @@ class FSTools
* @param string $folder Name of folder to create * @param string $folder Name of folder to create
* @note Adapted from the PHP manual comment 76612 * @note Adapted from the PHP manual comment 76612
*/ */
public function mkdirr($folder) { public function mkdirr($folder)
{
$folders = preg_split("#[\\\\/]#", $folder); $folders = preg_split("#[\\\\/]#", $folder);
$base = ''; $base = '';
for($i = 0, $c = count($folders); $i < $c; $i++) { for($i = 0, $c = count($folders); $i < $c; $i++) {
@@ -57,7 +60,8 @@ class FSTools
* so that copied files, if PHP, have includes removed * so that copied files, if PHP, have includes removed
* @note Adapted from http://aidanlister.com/repos/v/function.copyr.php * @note Adapted from http://aidanlister.com/repos/v/function.copyr.php
*/ */
public function copyr($source, $dest) { public function copyr($source, $dest)
{
// Simple copy for a file // Simple copy for a file
if (is_file($source)) { if (is_file($source)) {
return $this->copy($source, $dest); return $this->copy($source, $dest);
@@ -92,7 +96,8 @@ class FSTools
* ignore hidden files, unreadable files, etc. This function * ignore hidden files, unreadable files, etc. This function
* applies to copyr(). * applies to copyr().
*/ */
public function copyable($file) { public function copyable($file)
{
return true; return true;
} }
@@ -131,7 +136,8 @@ class FSTools
/** /**
* Recursively globs a directory. * Recursively globs a directory.
*/ */
public function globr($dir, $pattern, $flags = NULL) { public function globr($dir, $pattern, $flags = NULL)
{
$files = $this->glob("$dir/$pattern", $flags); $files = $this->glob("$dir/$pattern", $flags);
if ($files === false) $files = array(); if ($files === false) $files = array();
$sub_dirs = $this->glob("$dir/*", GLOB_ONLYDIR); $sub_dirs = $this->glob("$dir/*", GLOB_ONLYDIR);
@@ -148,7 +154,8 @@ class FSTools
* @warning This function will not work for functions that need * @warning This function will not work for functions that need
* to pass references; manually define a stub function for those. * to pass references; manually define a stub function for those.
*/ */
public function __call($name, $args) { public function __call($name, $args)
{
return call_user_func_array($name, $args); return call_user_func_array($name, $args);
} }

View File

@@ -23,7 +23,8 @@ class FSTools_File
* Filename of file you wish to instantiate. * Filename of file you wish to instantiate.
* @note This file need not exist * @note This file need not exist
*/ */
public function __construct($name, $fs = false) { public function __construct($name, $fs = false)
{
$this->name = $name; $this->name = $name;
$this->fs = $fs ? $fs : FSTools::singleton(); $this->fs = $fs ? $fs : FSTools::singleton();
} }
@@ -38,27 +39,32 @@ class FSTools_File
* Retrieves the contents of a file * Retrieves the contents of a file
* @todo Throw an exception if file doesn't exist * @todo Throw an exception if file doesn't exist
*/ */
public function get() { public function get()
{
return $this->fs->file_get_contents($this->name); return $this->fs->file_get_contents($this->name);
} }
/** Writes contents to a file, creates new file if necessary */ /** Writes contents to a file, creates new file if necessary */
public function write($contents) { public function write($contents)
{
return $this->fs->file_put_contents($this->name, $contents); return $this->fs->file_put_contents($this->name, $contents);
} }
/** Deletes the file */ /** Deletes the file */
public function delete() { public function delete()
{
return $this->fs->unlink($this->name); return $this->fs->unlink($this->name);
} }
/** Returns true if file exists and is a file. */ /** Returns true if file exists and is a file. */
public function exists() { public function exists()
{
return $this->fs->is_file($this->name); return $this->fs->is_file($this->name);
} }
/** Returns last file modification time */ /** Returns last file modification time */
public function getMTime() { public function getMTime()
{
return $this->fs->filemtime($this->name); return $this->fs->filemtime($this->name);
} }
@@ -67,19 +73,22 @@ class FSTools_File
* @note We ignore errors because of some weird owner trickery due * @note We ignore errors because of some weird owner trickery due
* to SVN duality * to SVN duality
*/ */
public function chmod($octal_code) { public function chmod($octal_code)
{
return @$this->fs->chmod($this->name, $octal_code); return @$this->fs->chmod($this->name, $octal_code);
} }
/** Opens file's handle */ /** Opens file's handle */
public function open($mode) { public function open($mode)
{
if ($this->handle) $this->close(); if ($this->handle) $this->close();
$this->handle = $this->fs->fopen($this->name, $mode); $this->handle = $this->fs->fopen($this->name, $mode);
return true; return true;
} }
/** Closes file's handle */ /** Closes file's handle */
public function close() { public function close()
{
if (!$this->handle) return false; if (!$this->handle) return false;
$status = $this->fs->fclose($this->handle); $status = $this->fs->fclose($this->handle);
$this->handle = false; $this->handle = false;
@@ -87,37 +96,43 @@ class FSTools_File
} }
/** Retrieves a line from an open file, with optional max length $length */ /** Retrieves a line from an open file, with optional max length $length */
public function getLine($length = null) { public function getLine($length = null)
{
if (!$this->handle) $this->open('r'); if (!$this->handle) $this->open('r');
if ($length === null) return $this->fs->fgets($this->handle); if ($length === null) return $this->fs->fgets($this->handle);
else return $this->fs->fgets($this->handle, $length); else return $this->fs->fgets($this->handle, $length);
} }
/** Retrieves a character from an open file */ /** Retrieves a character from an open file */
public function getChar() { public function getChar()
{
if (!$this->handle) $this->open('r'); if (!$this->handle) $this->open('r');
return $this->fs->fgetc($this->handle); return $this->fs->fgetc($this->handle);
} }
/** Retrieves an $length bytes of data from an open data */ /** Retrieves an $length bytes of data from an open data */
public function read($length) { public function read($length)
{
if (!$this->handle) $this->open('r'); if (!$this->handle) $this->open('r');
return $this->fs->fread($this->handle, $length); return $this->fs->fread($this->handle, $length);
} }
/** Writes to an open file */ /** Writes to an open file */
public function put($string) { public function put($string)
{
if (!$this->handle) $this->open('a'); if (!$this->handle) $this->open('a');
return $this->fs->fwrite($this->handle, $string); return $this->fs->fwrite($this->handle, $string);
} }
/** Returns TRUE if the end of the file has been reached */ /** Returns TRUE if the end of the file has been reached */
public function eof() { public function eof()
{
if (!$this->handle) return true; if (!$this->handle) return true;
return $this->fs->feof($this->handle); return $this->fs->feof($this->handle);
} }
public function __destruct() { public function __destruct()
{
if ($this->handle) $this->close(); if ($this->handle) $this->close();
} }

View File

@@ -17,7 +17,8 @@ if (function_exists('spl_autoload_register')) {
spl_autoload_register('__autoload'); spl_autoload_register('__autoload');
} }
} elseif (!function_exists('__autoload')) { } elseif (!function_exists('__autoload')) {
function __autoload($class) { function __autoload($class)
{
return HTMLPurifierExtras::autoload($class); return HTMLPurifierExtras::autoload($class);
} }
} }

View File

@@ -7,14 +7,16 @@
class HTMLPurifierExtras class HTMLPurifierExtras
{ {
public static function autoload($class) { public static function autoload($class)
{
$path = HTMLPurifierExtras::getPath($class); $path = HTMLPurifierExtras::getPath($class);
if (!$path) return false; if (!$path) return false;
require $path; require $path;
return true; return true;
} }
public static function getPath($class) { public static function getPath($class)
{
if ( if (
strncmp('FSTools', $class, 7) !== 0 && strncmp('FSTools', $class, 7) !== 0 &&
strncmp('ConfigDoc', $class, 9) !== 0 strncmp('ConfigDoc', $class, 9) !== 0

View File

@@ -14,7 +14,8 @@ if (function_exists('spl_autoload_register') && function_exists('spl_autoload_un
spl_autoload_register('__autoload'); spl_autoload_register('__autoload');
} }
} elseif (!function_exists('__autoload')) { } elseif (!function_exists('__autoload')) {
function __autoload($class) { function __autoload($class)
{
return HTMLPurifier_Bootstrap::autoload($class); return HTMLPurifier_Bootstrap::autoload($class);
} }
} }

View File

@@ -8,11 +8,13 @@
/** /**
* Purify HTML. * Purify HTML.
* @param $html String HTML to purify * @param string $html String HTML to purify
* @param $config Configuration to use, can be any value accepted by * @param mixed $config Configuration to use, can be any value accepted by
* HTMLPurifier_Config::create() * HTMLPurifier_Config::create()
* @return string
*/ */
function HTMLPurifier($html, $config = null) { function HTMLPurifier($html, $config = null)
{
static $purifier = false; static $purifier = false;
if (!$purifier) { if (!$purifier) {
$purifier = new HTMLPurifier(); $purifier = new HTMLPurifier();

View File

@@ -7,7 +7,7 @@
* primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS * primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
* FILE, changes will be overwritten the next time the script is run. * FILE, changes will be overwritten the next time the script is run.
* *
* @version 4.5.0 * @version 4.6.0
* *
* @warning * @warning
* You must *not* include any other HTML Purifier files before this file, * You must *not* include any other HTML Purifier files before this file,
@@ -19,6 +19,7 @@
*/ */
require 'HTMLPurifier.php'; require 'HTMLPurifier.php';
require 'HTMLPurifier/Arborize.php';
require 'HTMLPurifier/AttrCollections.php'; require 'HTMLPurifier/AttrCollections.php';
require 'HTMLPurifier/AttrDef.php'; require 'HTMLPurifier/AttrDef.php';
require 'HTMLPurifier/AttrTransform.php'; require 'HTMLPurifier/AttrTransform.php';
@@ -54,9 +55,11 @@ require 'HTMLPurifier/Language.php';
require 'HTMLPurifier/LanguageFactory.php'; require 'HTMLPurifier/LanguageFactory.php';
require 'HTMLPurifier/Length.php'; require 'HTMLPurifier/Length.php';
require 'HTMLPurifier/Lexer.php'; require 'HTMLPurifier/Lexer.php';
require 'HTMLPurifier/Node.php';
require 'HTMLPurifier/PercentEncoder.php'; require 'HTMLPurifier/PercentEncoder.php';
require 'HTMLPurifier/PropertyList.php'; require 'HTMLPurifier/PropertyList.php';
require 'HTMLPurifier/PropertyListIterator.php'; require 'HTMLPurifier/PropertyListIterator.php';
require 'HTMLPurifier/Queue.php';
require 'HTMLPurifier/Strategy.php'; require 'HTMLPurifier/Strategy.php';
require 'HTMLPurifier/StringHash.php'; require 'HTMLPurifier/StringHash.php';
require 'HTMLPurifier/StringHashParser.php'; require 'HTMLPurifier/StringHashParser.php';
@@ -72,6 +75,7 @@ require 'HTMLPurifier/URISchemeRegistry.php';
require 'HTMLPurifier/UnitConverter.php'; require 'HTMLPurifier/UnitConverter.php';
require 'HTMLPurifier/VarParser.php'; require 'HTMLPurifier/VarParser.php';
require 'HTMLPurifier/VarParserException.php'; require 'HTMLPurifier/VarParserException.php';
require 'HTMLPurifier/Zipper.php';
require 'HTMLPurifier/AttrDef/CSS.php'; require 'HTMLPurifier/AttrDef/CSS.php';
require 'HTMLPurifier/AttrDef/Clone.php'; require 'HTMLPurifier/AttrDef/Clone.php';
require 'HTMLPurifier/AttrDef/Enum.php'; require 'HTMLPurifier/AttrDef/Enum.php';
@@ -189,6 +193,9 @@ require 'HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php';
require 'HTMLPurifier/Injector/SafeObject.php'; require 'HTMLPurifier/Injector/SafeObject.php';
require 'HTMLPurifier/Lexer/DOMLex.php'; require 'HTMLPurifier/Lexer/DOMLex.php';
require 'HTMLPurifier/Lexer/DirectLex.php'; require 'HTMLPurifier/Lexer/DirectLex.php';
require 'HTMLPurifier/Node/Comment.php';
require 'HTMLPurifier/Node/Element.php';
require 'HTMLPurifier/Node/Text.php';
require 'HTMLPurifier/Strategy/Composite.php'; require 'HTMLPurifier/Strategy/Composite.php';
require 'HTMLPurifier/Strategy/Core.php'; require 'HTMLPurifier/Strategy/Core.php';
require 'HTMLPurifier/Strategy/FixNesting.php'; require 'HTMLPurifier/Strategy/FixNesting.php';

View File

@@ -7,7 +7,8 @@
require_once dirname(__FILE__) . '/HTMLPurifier.auto.php'; require_once dirname(__FILE__) . '/HTMLPurifier.auto.php';
function kses($string, $allowed_html, $allowed_protocols = null) { function kses($string, $allowed_html, $allowed_protocols = null)
{
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();
$allowed_elements = array(); $allowed_elements = array();
$allowed_attributes = array(); $allowed_attributes = array();
@@ -19,7 +20,6 @@ function kses($string, $allowed_html, $allowed_protocols = null) {
} }
$config->set('HTML.AllowedElements', $allowed_elements); $config->set('HTML.AllowedElements', $allowed_elements);
$config->set('HTML.AllowedAttributes', $allowed_attributes); $config->set('HTML.AllowedAttributes', $allowed_attributes);
$allowed_schemes = array();
if ($allowed_protocols !== null) { if ($allowed_protocols !== null) {
$config->set('URI.AllowedSchemes', $allowed_protocols); $config->set('URI.AllowedSchemes', $allowed_protocols);
} }

View File

@@ -19,7 +19,7 @@
*/ */
/* /*
HTML Purifier 4.5.0 - Standards Compliant HTML Filtering HTML Purifier 4.6.0 - Standards Compliant HTML Filtering
Copyright (C) 2006-2008 Edward Z. Yang Copyright (C) 2006-2008 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
@@ -54,66 +54,97 @@
class HTMLPurifier class HTMLPurifier
{ {
/** Version of HTML Purifier */ /**
public $version = '4.5.0'; * Version of HTML Purifier.
* @type string
/** Constant with version of HTML Purifier */ */
const VERSION = '4.5.0'; public $version = '4.6.0';
/** Global configuration object */
public $config;
/** Array of extra HTMLPurifier_Filter objects to run on HTML, for backwards compatibility */
private $filters = array();
/** Single instance of HTML Purifier */
private static $instance;
protected $strategy, $generator;
/** /**
* Resultant HTMLPurifier_Context of last run purification. Is an array * Constant with version of HTML Purifier.
* of contexts if the last called method was purifyArray(). */
const VERSION = '4.6.0';
/**
* Global configuration object.
* @type HTMLPurifier_Config
*/
public $config;
/**
* Array of extra filter objects to run on HTML,
* for backwards compatibility.
* @type HTMLPurifier_Filter[]
*/
private $filters = array();
/**
* Single instance of HTML Purifier.
* @type HTMLPurifier
*/
private static $instance;
/**
* @type HTMLPurifier_Strategy_Core
*/
protected $strategy;
/**
* @type HTMLPurifier_Generator
*/
protected $generator;
/**
* Resultant context of last run purification.
* Is an array of contexts if the last called method was purifyArray().
* @type HTMLPurifier_Context
*/ */
public $context; public $context;
/** /**
* Initializes the purifier. * Initializes the purifier.
* @param $config Optional HTMLPurifier_Config object for all instances of *
* the purifier, if omitted, a default configuration is * @param HTMLPurifier_Config $config Optional HTMLPurifier_Config object
* supplied (which can be overridden on a per-use basis). * for all instances of the purifier, if omitted, a default
* configuration is supplied (which can be overridden on a
* per-use basis).
* The parameter can also be any type that * The parameter can also be any type that
* HTMLPurifier_Config::create() supports. * HTMLPurifier_Config::create() supports.
*/ */
public function __construct($config = null) { public function __construct($config = null)
{
$this->config = HTMLPurifier_Config::create($config); $this->config = HTMLPurifier_Config::create($config);
$this->strategy = new HTMLPurifier_Strategy_Core();
$this->strategy = new HTMLPurifier_Strategy_Core();
} }
/** /**
* Adds a filter to process the output. First come first serve * Adds a filter to process the output. First come first serve
* @param $filter HTMLPurifier_Filter object *
* @param HTMLPurifier_Filter $filter HTMLPurifier_Filter object
*/ */
public function addFilter($filter) { public function addFilter($filter)
trigger_error('HTMLPurifier->addFilter() is deprecated, use configuration directives in the Filter namespace or Filter.Custom', E_USER_WARNING); {
trigger_error(
'HTMLPurifier->addFilter() is deprecated, use configuration directives' .
' in the Filter namespace or Filter.Custom',
E_USER_WARNING
);
$this->filters[] = $filter; $this->filters[] = $filter;
} }
/** /**
* Filters an HTML snippet/document to be XSS-free and standards-compliant. * Filters an HTML snippet/document to be XSS-free and standards-compliant.
* *
* @param $html String of HTML to purify * @param string $html String of HTML to purify
* @param $config HTMLPurifier_Config object for this operation, if omitted, * @param HTMLPurifier_Config $config Config object for this operation,
* defaults to the config object specified during this * if omitted, defaults to the config object specified during this
* object's construction. The parameter can also be any type * object's construction. The parameter can also be any type
* that HTMLPurifier_Config::create() supports. * that HTMLPurifier_Config::create() supports.
* @return Purified HTML *
* @return string Purified HTML
*/ */
public function purify($html, $config = null) { public function purify($html, $config = null)
{
// :TODO: make the config merge in, instead of replace // :TODO: make the config merge in, instead of replace
$config = $config ? HTMLPurifier_Config::create($config) : $this->config; $config = $config ? HTMLPurifier_Config::create($config) : $this->config;
@@ -151,8 +182,12 @@ class HTMLPurifier
unset($filter_flags['Custom']); unset($filter_flags['Custom']);
$filters = array(); $filters = array();
foreach ($filter_flags as $filter => $flag) { foreach ($filter_flags as $filter => $flag) {
if (!$flag) continue; if (!$flag) {
if (strpos($filter, '.') !== false) continue; continue;
}
if (strpos($filter, '.') !== false) {
continue;
}
$class = "HTMLPurifier_Filter_$filter"; $class = "HTMLPurifier_Filter_$filter";
$filters[] = new $class; $filters[] = new $class;
} }
@@ -175,9 +210,12 @@ class HTMLPurifier
// list of un-purified tokens // list of un-purified tokens
$lexer->tokenizeHTML( $lexer->tokenizeHTML(
// un-purified HTML // un-purified HTML
$html, $config, $context $html,
$config,
$context
), ),
$config, $context $config,
$context
) )
); );
@@ -192,11 +230,15 @@ class HTMLPurifier
/** /**
* Filters an array of HTML snippets * Filters an array of HTML snippets
* @param $config Optional HTMLPurifier_Config object for this operation. *
* @param string[] $array_of_html Array of html snippets
* @param HTMLPurifier_Config $config Optional config object for this operation.
* See HTMLPurifier::purify() for more details. * See HTMLPurifier::purify() for more details.
* @return Array of purified HTML *
* @return string[] Array of purified HTML
*/ */
public function purifyArray($array_of_html, $config = null) { public function purifyArray($array_of_html, $config = null)
{
$context_array = array(); $context_array = array();
foreach ($array_of_html as $key => $html) { foreach ($array_of_html as $key => $html) {
$array_of_html[$key] = $this->purify($html, $config); $array_of_html[$key] = $this->purify($html, $config);
@@ -208,11 +250,16 @@ class HTMLPurifier
/** /**
* Singleton for enforcing just one HTML Purifier in your system * Singleton for enforcing just one HTML Purifier in your system
* @param $prototype Optional prototype HTMLPurifier instance to *
* overload singleton with, or HTMLPurifier_Config * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype
* instance to configure the generated version with. * HTMLPurifier instance to overload singleton with,
* or HTMLPurifier_Config instance to configure the
* generated version with.
*
* @return HTMLPurifier
*/ */
public static function instance($prototype = null) { public static function instance($prototype = null)
{
if (!self::$instance || $prototype) { if (!self::$instance || $prototype) {
if ($prototype instanceof HTMLPurifier) { if ($prototype instanceof HTMLPurifier) {
self::$instance = $prototype; self::$instance = $prototype;
@@ -226,12 +273,20 @@ class HTMLPurifier
} }
/** /**
* Singleton for enforcing just one HTML Purifier in your system
*
* @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype
* HTMLPurifier instance to overload singleton with,
* or HTMLPurifier_Config instance to configure the
* generated version with.
*
* @return HTMLPurifier
* @note Backwards compatibility, see instance() * @note Backwards compatibility, see instance()
*/ */
public static function getInstance($prototype = null) { public static function getInstance($prototype = null)
{
return HTMLPurifier::instance($prototype); return HTMLPurifier::instance($prototype);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -13,6 +13,7 @@
$__dir = dirname(__FILE__); $__dir = dirname(__FILE__);
require_once $__dir . '/HTMLPurifier.php'; require_once $__dir . '/HTMLPurifier.php';
require_once $__dir . '/HTMLPurifier/Arborize.php';
require_once $__dir . '/HTMLPurifier/AttrCollections.php'; require_once $__dir . '/HTMLPurifier/AttrCollections.php';
require_once $__dir . '/HTMLPurifier/AttrDef.php'; require_once $__dir . '/HTMLPurifier/AttrDef.php';
require_once $__dir . '/HTMLPurifier/AttrTransform.php'; require_once $__dir . '/HTMLPurifier/AttrTransform.php';
@@ -48,9 +49,11 @@ require_once $__dir . '/HTMLPurifier/Language.php';
require_once $__dir . '/HTMLPurifier/LanguageFactory.php'; require_once $__dir . '/HTMLPurifier/LanguageFactory.php';
require_once $__dir . '/HTMLPurifier/Length.php'; require_once $__dir . '/HTMLPurifier/Length.php';
require_once $__dir . '/HTMLPurifier/Lexer.php'; require_once $__dir . '/HTMLPurifier/Lexer.php';
require_once $__dir . '/HTMLPurifier/Node.php';
require_once $__dir . '/HTMLPurifier/PercentEncoder.php'; require_once $__dir . '/HTMLPurifier/PercentEncoder.php';
require_once $__dir . '/HTMLPurifier/PropertyList.php'; require_once $__dir . '/HTMLPurifier/PropertyList.php';
require_once $__dir . '/HTMLPurifier/PropertyListIterator.php'; require_once $__dir . '/HTMLPurifier/PropertyListIterator.php';
require_once $__dir . '/HTMLPurifier/Queue.php';
require_once $__dir . '/HTMLPurifier/Strategy.php'; require_once $__dir . '/HTMLPurifier/Strategy.php';
require_once $__dir . '/HTMLPurifier/StringHash.php'; require_once $__dir . '/HTMLPurifier/StringHash.php';
require_once $__dir . '/HTMLPurifier/StringHashParser.php'; require_once $__dir . '/HTMLPurifier/StringHashParser.php';
@@ -66,6 +69,7 @@ require_once $__dir . '/HTMLPurifier/URISchemeRegistry.php';
require_once $__dir . '/HTMLPurifier/UnitConverter.php'; require_once $__dir . '/HTMLPurifier/UnitConverter.php';
require_once $__dir . '/HTMLPurifier/VarParser.php'; require_once $__dir . '/HTMLPurifier/VarParser.php';
require_once $__dir . '/HTMLPurifier/VarParserException.php'; require_once $__dir . '/HTMLPurifier/VarParserException.php';
require_once $__dir . '/HTMLPurifier/Zipper.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php'; require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Clone.php'; require_once $__dir . '/HTMLPurifier/AttrDef/Clone.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php'; require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php';
@@ -183,6 +187,9 @@ require_once $__dir . '/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php';
require_once $__dir . '/HTMLPurifier/Injector/SafeObject.php'; require_once $__dir . '/HTMLPurifier/Injector/SafeObject.php';
require_once $__dir . '/HTMLPurifier/Lexer/DOMLex.php'; require_once $__dir . '/HTMLPurifier/Lexer/DOMLex.php';
require_once $__dir . '/HTMLPurifier/Lexer/DirectLex.php'; require_once $__dir . '/HTMLPurifier/Lexer/DirectLex.php';
require_once $__dir . '/HTMLPurifier/Node/Comment.php';
require_once $__dir . '/HTMLPurifier/Node/Element.php';
require_once $__dir . '/HTMLPurifier/Node/Text.php';
require_once $__dir . '/HTMLPurifier/Strategy/Composite.php'; require_once $__dir . '/HTMLPurifier/Strategy/Composite.php';
require_once $__dir . '/HTMLPurifier/Strategy/Core.php'; require_once $__dir . '/HTMLPurifier/Strategy/Core.php';
require_once $__dir . '/HTMLPurifier/Strategy/FixNesting.php'; require_once $__dir . '/HTMLPurifier/Strategy/FixNesting.php';

View File

@@ -0,0 +1,71 @@
<?php
/**
* Converts a stream of HTMLPurifier_Token into an HTMLPurifier_Node,
* and back again.
*
* @note This transformation is not an equivalence. We mutate the input
* token stream to make it so; see all [MUT] markers in code.
*/
class HTMLPurifier_Arborize
{
public static function arborize($tokens, $config, $context) {
$definition = $config->getHTMLDefinition();
$parent = new HTMLPurifier_Token_Start($definition->info_parent);
$stack = array($parent->toNode());
foreach ($tokens as $token) {
$token->skip = null; // [MUT]
$token->carryover = null; // [MUT]
if ($token instanceof HTMLPurifier_Token_End) {
$token->start = null; // [MUT]
$r = array_pop($stack);
assert($r->name === $token->name);
assert(empty($token->attr));
$r->endCol = $token->col;
$r->endLine = $token->line;
$r->endArmor = $token->armor;
continue;
}
$node = $token->toNode();
$stack[count($stack)-1]->children[] = $node;
if ($token instanceof HTMLPurifier_Token_Start) {
$stack[] = $node;
}
}
assert(count($stack) == 1);
return $stack[0];
}
public static function flatten($node, $config, $context) {
$level = 0;
$nodes = array($level => new HTMLPurifier_Queue(array($node)));
$closingTokens = array();
$tokens = array();
do {
while (!$nodes[$level]->isEmpty()) {
$node = $nodes[$level]->shift(); // FIFO
list($start, $end) = $node->toTokenPair();
if ($level > 0) {
$tokens[] = $start;
}
if ($end !== NULL) {
$closingTokens[$level][] = $end;
}
if ($node instanceof HTMLPurifier_Node_Element) {
$level++;
$nodes[$level] = new HTMLPurifier_Queue();
foreach ($node->children as $childNode) {
$nodes[$level]->push($childNode);
}
}
}
$level--;
if ($level && isset($closingTokens[$level])) {
while ($token = array_pop($closingTokens[$level])) {
$tokens[] = $token;
}
}
} while ($level > 0);
return $tokens;
}
}

View File

@@ -8,7 +8,8 @@ class HTMLPurifier_AttrCollections
{ {
/** /**
* Associative array of attribute collections, indexed by name * Associative array of attribute collections, indexed by name.
* @type array
*/ */
public $info = array(); public $info = array();
@@ -16,10 +17,11 @@ class HTMLPurifier_AttrCollections
* Performs all expansions on internal data for use by other inclusions * Performs all expansions on internal data for use by other inclusions
* It also collects all attribute collection extensions from * It also collects all attribute collection extensions from
* modules * modules
* @param $attr_types HTMLPurifier_AttrTypes instance * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
* @param $modules Hash array of HTMLPurifier_HTMLModule members * @param HTMLPurifier_HTMLModule[] $modules Hash array of HTMLPurifier_HTMLModule members
*/ */
public function __construct($attr_types, $modules) { public function __construct($attr_types, $modules)
{
// 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) {
@@ -30,7 +32,9 @@ class HTMLPurifier_AttrCollections
if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) { if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
// merge in includes // merge in includes
$this->info[$coll_i][$attr_i] = array_merge( $this->info[$coll_i][$attr_i] = array_merge(
$this->info[$coll_i][$attr_i], $attr); $this->info[$coll_i][$attr_i],
$attr
);
continue; continue;
} }
$this->info[$coll_i][$attr_i] = $attr; $this->info[$coll_i][$attr_i] = $attr;
@@ -49,20 +53,29 @@ class HTMLPurifier_AttrCollections
/** /**
* Takes a reference to an attribute associative array and performs * Takes a reference to an attribute associative array and performs
* all inclusions specified by the zero index. * all inclusions specified by the zero index.
* @param &$attr Reference to attribute array * @param array &$attr Reference to attribute array
*/ */
public function performInclusions(&$attr) { public function performInclusions(&$attr)
if (!isset($attr[0])) return; {
if (!isset($attr[0])) {
return;
}
$merge = $attr[0]; $merge = $attr[0];
$seen = array(); // recursion guard $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; if (isset($seen[$merge[$i]])) {
continue;
}
$seen[$merge[$i]] = true; $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; 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($this->info[$merge[$i]][0])) {
@@ -76,20 +89,24 @@ class HTMLPurifier_AttrCollections
/** /**
* Expands all string identifiers in an attribute array by replacing * Expands all string identifiers in an attribute array by replacing
* them with the appropriate values inside HTMLPurifier_AttrTypes * them with the appropriate values inside HTMLPurifier_AttrTypes
* @param &$attr Reference to attribute array * @param array &$attr Reference to attribute array
* @param $attr_types HTMLPurifier_AttrTypes instance * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
*/ */
public function expandIdentifiers(&$attr, $attr_types) { public function expandIdentifiers(&$attr, $attr_types)
{
// because foreach will process new elements we add, make sure we // because foreach will process new elements we add, make sure we
// skip duplicates // skip duplicates
$processed = array(); $processed = array();
foreach ($attr as $def_i => $def) { foreach ($attr as $def_i => $def) {
// skip inclusions // skip inclusions
if ($def_i === 0) continue; if ($def_i === 0) {
continue;
}
if (isset($processed[$def_i])) continue; if (isset($processed[$def_i])) {
continue;
}
// determine whether or not attribute is required // determine whether or not attribute is required
if ($required = (strpos($def_i, '*') !== false)) { if ($required = (strpos($def_i, '*') !== false)) {
@@ -120,9 +137,7 @@ class HTMLPurifier_AttrCollections
unset($attr[$def_i]); unset($attr[$def_i]);
} }
} }
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -14,23 +14,25 @@ abstract 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.
* meaning in other contexts. * Has no meaning in other contexts.
* @type bool
*/ */
public $minimized = false; public $minimized = false;
/** /**
* Tells us whether or not an HTML attribute is required. Has no * Tells us whether or not an HTML attribute is required.
* meaning in other contexts * Has no meaning in other contexts
* @type bool
*/ */
public $required = false; public $required = false;
/** /**
* Validates and cleans passed string according to a definition. * Validates and cleans passed string according to a definition.
* *
* @param $string String to be validated and cleaned. * @param string $string String to be validated and cleaned.
* @param $config Mandatory HTMLPurifier_Config object. * @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object.
* @param $context Mandatory HTMLPurifier_AttrContext object. * @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object.
*/ */
abstract public function validate($string, $config, $context); abstract public function validate($string, $config, $context);
@@ -55,7 +57,8 @@ abstract class HTMLPurifier_AttrDef
* parsing XML, thus, this behavior may still be correct. We * parsing XML, thus, this behavior may still be correct. We
* assume that newlines have been normalized. * assume that newlines have been normalized.
*/ */
public function parseCDATA($string) { public function parseCDATA($string)
{
$string = trim($string); $string = trim($string);
$string = str_replace(array("\n", "\t", "\r"), ' ', $string); $string = str_replace(array("\n", "\t", "\r"), ' ', $string);
return $string; return $string;
@@ -63,10 +66,11 @@ abstract class HTMLPurifier_AttrDef
/** /**
* Factory method for creating this class from a string. * Factory method for creating this class from a string.
* @param $string String construction info * @param string $string String construction info
* @return Created AttrDef object corresponding to $string * @return HTMLPurifier_AttrDef Created AttrDef object corresponding to $string
*/ */
public function make($string) { public function make($string)
{
// default implementation, return a flyweight of this object. // default implementation, return a flyweight of this object.
// If $string has an effect on the returned object (i.e. you // If $string has an effect on the returned object (i.e. you
// need to overload this method), it is best // need to overload this method), it is best
@@ -77,16 +81,20 @@ abstract class HTMLPurifier_AttrDef
/** /**
* Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work * Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work
* properly. THIS IS A HACK! * properly. THIS IS A HACK!
* @param string $string a CSS colour definition
* @return string
*/ */
protected function mungeRgb($string) { protected function mungeRgb($string)
{
return preg_replace('/rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)/', 'rgb(\1,\2,\3)', $string); return preg_replace('/rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)/', 'rgb(\1,\2,\3)', $string);
} }
/** /**
* Parses a possibly escaped CSS string and returns the "pure" * Parses a possibly escaped CSS string and returns the "pure"
* version of it. * version of it.
*/ */
protected function expandCSSEscape($string) { protected function expandCSSEscape($string)
{
// flexibly parse it // flexibly parse it
$ret = ''; $ret = '';
for ($i = 0, $c = strlen($string); $i < $c; $i++) { for ($i = 0, $c = strlen($string); $i < $c; $i++) {
@@ -99,25 +107,32 @@ abstract class HTMLPurifier_AttrDef
if (ctype_xdigit($string[$i])) { if (ctype_xdigit($string[$i])) {
$code = $string[$i]; $code = $string[$i];
for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) { for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) {
if (!ctype_xdigit($string[$i])) break; if (!ctype_xdigit($string[$i])) {
break;
}
$code .= $string[$i]; $code .= $string[$i];
} }
// We have to be extremely careful when adding // We have to be extremely careful when adding
// new characters, to make sure we're not breaking // new characters, to make sure we're not breaking
// the encoding. // the encoding.
$char = HTMLPurifier_Encoder::unichr(hexdec($code)); $char = HTMLPurifier_Encoder::unichr(hexdec($code));
if (HTMLPurifier_Encoder::cleanUTF8($char) === '') continue; if (HTMLPurifier_Encoder::cleanUTF8($char) === '') {
continue;
}
$ret .= $char; $ret .= $char;
if ($i < $c && trim($string[$i]) !== '') $i--; if ($i < $c && trim($string[$i]) !== '') {
$i--;
}
continue;
}
if ($string[$i] === "\n") {
continue; continue;
} }
if ($string[$i] === "\n") continue;
} }
$ret .= $string[$i]; $ret .= $string[$i];
} }
return $ret; return $ret;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -14,8 +14,14 @@
class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
{ {
public function validate($css, $config, $context) { /**
* @param string $css
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($css, $config, $context)
{
$css = $this->parseCDATA($css); $css = $this->parseCDATA($css);
$definition = $config->getCSSDefinition(); $definition = $config->getCSSDefinition();
@@ -36,34 +42,47 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
$context->register('CurrentCSSProperty', $property); $context->register('CurrentCSSProperty', $property);
foreach ($declarations as $declaration) { foreach ($declarations as $declaration) {
if (!$declaration) continue; if (!$declaration) {
if (!strpos($declaration, ':')) continue; continue;
}
if (!strpos($declaration, ':')) {
continue;
}
list($property, $value) = explode(':', $declaration, 2); list($property, $value) = explode(':', $declaration, 2);
$property = trim($property); $property = trim($property);
$value = trim($value); $value = trim($value);
$ok = false; $ok = false;
do { do {
if (isset($definition->info[$property])) { if (isset($definition->info[$property])) {
$ok = true; $ok = true;
break; break;
} }
if (ctype_lower($property)) break; if (ctype_lower($property)) {
break;
}
$property = strtolower($property); $property = strtolower($property);
if (isset($definition->info[$property])) { if (isset($definition->info[$property])) {
$ok = true; $ok = true;
break; break;
} }
} while(0); } while (0);
if (!$ok) continue; if (!$ok) {
continue;
}
// inefficient call, since the validator will do this again // inefficient call, since the validator will do this again
if (strtolower(trim($value)) !== 'inherit') { if (strtolower(trim($value)) !== 'inherit') {
// inherit works for everything (but only on the base property) // inherit works for everything (but only on the base property)
$result = $definition->info[$property]->validate( $result = $definition->info[$property]->validate(
$value, $config, $context ); $value,
$config,
$context
);
} else { } else {
$result = 'inherit'; $result = 'inherit';
} }
if ($result === false) continue; if ($result === false) {
continue;
}
$propvalues[$property] = $result; $propvalues[$property] = $result;
} }

View File

@@ -3,19 +3,32 @@
class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number
{ {
public function __construct() { public function __construct()
{
parent::__construct(false); // opacity is non-negative, but we will clamp it parent::__construct(false); // opacity is non-negative, but we will clamp it
} }
public function validate($number, $config, $context) { /**
* @param string $number
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return string
*/
public function validate($number, $config, $context)
{
$result = parent::validate($number, $config, $context); $result = parent::validate($number, $config, $context);
if ($result === false) return $result; if ($result === false) {
$float = (float) $result; return $result;
if ($float < 0.0) $result = '0'; }
if ($float > 1.0) $result = '1'; $float = (float)$result;
if ($float < 0.0) {
$result = '0';
}
if ($float > 1.0) {
$result = '1';
}
return $result; return $result;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -9,11 +9,16 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
/** /**
* Local copy of component validators. * Local copy of component validators.
* @type HTMLPurifier_AttrDef[]
* @note See HTMLPurifier_AttrDef_Font::$info for a similar impl. * @note See HTMLPurifier_AttrDef_Font::$info for a similar impl.
*/ */
protected $info; protected $info;
public function __construct($config) { /**
* @param HTMLPurifier_Config $config
*/
public function __construct($config)
{
$def = $config->getCSSDefinition(); $def = $config->getCSSDefinition();
$this->info['background-color'] = $def->info['background-color']; $this->info['background-color'] = $def->info['background-color'];
$this->info['background-image'] = $def->info['background-image']; $this->info['background-image'] = $def->info['background-image'];
@@ -22,11 +27,19 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
$this->info['background-position'] = $def->info['background-position']; $this->info['background-position'] = $def->info['background-position'];
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
// regular pre-processing // regular pre-processing
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
if ($string === '') return false; if ($string === '') {
return false;
}
// munge rgb() decl if necessary // munge rgb() decl if necessary
$string = $this->mungeRgb($string); $string = $this->mungeRgb($string);
@@ -35,27 +48,34 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
$bits = explode(' ', $string); // bits to process $bits = explode(' ', $string); // bits to process
$caught = array(); $caught = array();
$caught['color'] = false; $caught['color'] = false;
$caught['image'] = false; $caught['image'] = false;
$caught['repeat'] = false; $caught['repeat'] = false;
$caught['attachment'] = false; $caught['attachment'] = false;
$caught['position'] = false; $caught['position'] = false;
$i = 0; // number of catches $i = 0; // number of catches
$none = false;
foreach ($bits as $bit) { foreach ($bits as $bit) {
if ($bit === '') continue; if ($bit === '') {
continue;
}
foreach ($caught as $key => $status) { foreach ($caught as $key => $status) {
if ($key != 'position') { if ($key != 'position') {
if ($status !== false) continue; if ($status !== false) {
continue;
}
$r = $this->info['background-' . $key]->validate($bit, $config, $context); $r = $this->info['background-' . $key]->validate($bit, $config, $context);
} else { } else {
$r = $bit; $r = $bit;
} }
if ($r === false) continue; if ($r === false) {
continue;
}
if ($key == 'position') { if ($key == 'position') {
if ($caught[$key] === false) $caught[$key] = ''; if ($caught[$key] === false) {
$caught[$key] = '';
}
$caught[$key] .= $r . ' '; $caught[$key] .= $r . ' ';
} else { } else {
$caught[$key] = $r; $caught[$key] = $r;
@@ -65,7 +85,9 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
} }
} }
if (!$i) return false; if (!$i) {
return false;
}
if ($caught['position'] !== false) { if ($caught['position'] !== false) {
$caught['position'] = $this->info['background-position']-> $caught['position'] = $this->info['background-position']->
validate($caught['position'], $config, $context); validate($caught['position'], $config, $context);
@@ -73,15 +95,17 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
$ret = array(); $ret = array();
foreach ($caught as $value) { foreach ($caught as $value) {
if ($value === false) continue; if ($value === false) {
continue;
}
$ret[] = $value; $ret[] = $value;
} }
if (empty($ret)) return false; if (empty($ret)) {
return false;
}
return implode(' ', $ret); return implode(' ', $ret);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -44,15 +44,30 @@
class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
{ {
/**
* @type HTMLPurifier_AttrDef_CSS_Length
*/
protected $length; protected $length;
/**
* @type HTMLPurifier_AttrDef_CSS_Percentage
*/
protected $percentage; protected $percentage;
public function __construct() { public function __construct()
$this->length = new HTMLPurifier_AttrDef_CSS_Length(); {
$this->length = new HTMLPurifier_AttrDef_CSS_Length();
$this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage(); $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage();
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
$bits = explode(' ', $string); $bits = explode(' ', $string);
@@ -74,7 +89,9 @@ class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
); );
foreach ($bits as $bit) { foreach ($bits as $bit) {
if ($bit === '') continue; if ($bit === '') {
continue;
}
// test for keyword // test for keyword
$lbit = ctype_lower($bit) ? $bit : strtolower($bit); $lbit = ctype_lower($bit) ? $bit : strtolower($bit);
@@ -104,30 +121,37 @@ class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
$measures[] = $r; $measures[] = $r;
$i++; $i++;
} }
} }
if (!$i) return false; // no valid values were caught if (!$i) {
return false;
} // no valid values were caught
$ret = array(); $ret = array();
// first keyword // first keyword
if ($keywords['h']) $ret[] = $keywords['h']; if ($keywords['h']) {
elseif ($keywords['ch']) { $ret[] = $keywords['h'];
} elseif ($keywords['ch']) {
$ret[] = $keywords['ch']; $ret[] = $keywords['ch'];
$keywords['cv'] = false; // prevent re-use: center = center center $keywords['cv'] = false; // prevent re-use: center = center center
} elseif (count($measures)) {
$ret[] = array_shift($measures);
} }
elseif (count($measures)) $ret[] = array_shift($measures);
if ($keywords['v']) $ret[] = $keywords['v']; if ($keywords['v']) {
elseif ($keywords['cv']) $ret[] = $keywords['cv']; $ret[] = $keywords['v'];
elseif (count($measures)) $ret[] = array_shift($measures); } elseif ($keywords['cv']) {
$ret[] = $keywords['cv'];
} elseif (count($measures)) {
$ret[] = array_shift($measures);
}
if (empty($ret)) return false; if (empty($ret)) {
return false;
}
return implode(' ', $ret); return implode(' ', $ret);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -8,17 +8,29 @@ class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
/** /**
* Local copy of properties this property is shorthand for. * Local copy of properties this property is shorthand for.
* @type HTMLPurifier_AttrDef[]
*/ */
protected $info = array(); protected $info = array();
public function __construct($config) { /**
* @param HTMLPurifier_Config $config
*/
public function __construct($config)
{
$def = $config->getCSSDefinition(); $def = $config->getCSSDefinition();
$this->info['border-width'] = $def->info['border-width']; $this->info['border-width'] = $def->info['border-width'];
$this->info['border-style'] = $def->info['border-style']; $this->info['border-style'] = $def->info['border-style'];
$this->info['border-top-color'] = $def->info['border-top-color']; $this->info['border-top-color'] = $def->info['border-top-color'];
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
$string = $this->mungeRgb($string); $string = $this->mungeRgb($string);
$bits = explode(' ', $string); $bits = explode(' ', $string);
@@ -26,7 +38,9 @@ class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
$ret = ''; // return value $ret = ''; // return value
foreach ($bits as $bit) { foreach ($bits as $bit) {
foreach ($this->info as $propname => $validator) { foreach ($this->info as $propname => $validator) {
if (isset($done[$propname])) continue; if (isset($done[$propname])) {
continue;
}
$r = $validator->validate($bit, $config, $context); $r = $validator->validate($bit, $config, $context);
if ($r !== false) { if ($r !== false) {
$ret .= $r . ' '; $ret .= $r . ' ';
@@ -37,7 +51,6 @@ class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
} }
return rtrim($ret); return rtrim($ret);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,29 +6,47 @@
class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
{ {
public function validate($color, $config, $context) { /**
* @param string $color
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($color, $config, $context)
{
static $colors = null; static $colors = null;
if ($colors === null) $colors = $config->get('Core.ColorKeywords'); 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($colors[$lower])) {
return $colors[$lower];
}
if (strpos($color, 'rgb(') !== false) { if (strpos($color, 'rgb(') !== false) {
// rgb literal handling // rgb literal handling
$length = strlen($color); $length = strlen($color);
if (strpos($color, ')') !== $length - 1) return false; if (strpos($color, ')') !== $length - 1) {
return false;
}
$triad = substr($color, 4, $length - 4 - 1); $triad = substr($color, 4, $length - 4 - 1);
$parts = explode(',', $triad); $parts = explode(',', $triad);
if (count($parts) !== 3) return false; if (count($parts) !== 3) {
return false;
}
$type = false; // to ensure that they're all the same type $type = false; // to ensure that they're all the same type
$new_parts = array(); $new_parts = array();
foreach ($parts as $part) { foreach ($parts as $part) {
$part = trim($part); $part = trim($part);
if ($part === '') return false; if ($part === '') {
return false;
}
$length = strlen($part); $length = strlen($part);
if ($part[$length - 1] === '%') { if ($part[$length - 1] === '%') {
// handle percents // handle percents
@@ -37,9 +55,13 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
} elseif ($type !== 'percentage') { } elseif ($type !== 'percentage') {
return false; return false;
} }
$num = (float) substr($part, 0, $length - 1); $num = (float)substr($part, 0, $length - 1);
if ($num < 0) $num = 0; if ($num < 0) {
if ($num > 100) $num = 100; $num = 0;
}
if ($num > 100) {
$num = 100;
}
$new_parts[] = "$num%"; $new_parts[] = "$num%";
} else { } else {
// handle integers // handle integers
@@ -48,10 +70,14 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
} elseif ($type !== 'integer') { } elseif ($type !== 'integer') {
return false; return false;
} }
$num = (int) $part; $num = (int)$part;
if ($num < 0) $num = 0; if ($num < 0) {
if ($num > 255) $num = 255; $num = 0;
$new_parts[] = (string) $num; }
if ($num > 255) {
$num = 255;
}
$new_parts[] = (string)$num;
} }
} }
$new_triad = implode(',', $new_parts); $new_triad = implode(',', $new_parts);
@@ -65,14 +91,15 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
$color = '#' . $color; $color = '#' . $color;
} }
$length = strlen($hex); $length = strlen($hex);
if ($length !== 3 && $length !== 6) return false; if ($length !== 3 && $length !== 6) {
if (!ctype_xdigit($hex)) return false; return false;
}
if (!ctype_xdigit($hex)) {
return false;
}
} }
return $color; return $color;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -13,26 +13,36 @@ class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef
{ {
/** /**
* List of HTMLPurifier_AttrDef objects that may process strings * List of objects that may process strings.
* @type HTMLPurifier_AttrDef[]
* @todo Make protected * @todo Make protected
*/ */
public $defs; public $defs;
/** /**
* @param $defs List of HTMLPurifier_AttrDef objects * @param HTMLPurifier_AttrDef[] $defs List of HTMLPurifier_AttrDef objects
*/ */
public function __construct($defs) { public function __construct($defs)
{
$this->defs = $defs; $this->defs = $defs;
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
foreach ($this->defs as $i => $def) { foreach ($this->defs as $i => $def) {
$result = $this->defs[$i]->validate($string, $config, $context); $result = $this->defs[$i]->validate($string, $config, $context);
if ($result !== false) return $result; if ($result !== false) {
return $result;
}
} }
return false; return false;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -5,22 +5,38 @@
*/ */
class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef
{ {
public $def, $element; /**
* @type HTMLPurifier_AttrDef
*/
public $def;
/**
* @type string
*/
public $element;
/** /**
* @param $def Definition to wrap * @param HTMLPurifier_AttrDef $def Definition to wrap
* @param $element Element to deny * @param string $element Element to deny
*/ */
public function __construct($def, $element) { public function __construct($def, $element)
{
$this->def = $def; $this->def = $def;
$this->element = $element; $this->element = $element;
} }
/** /**
* Checks if CurrentToken is set and equal to $this->element * Checks if CurrentToken is set and equal to $this->element
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/ */
public function validate($string, $config, $context) { public function validate($string, $config, $context)
{
$token = $context->get('CurrentToken', true); $token = $context->get('CurrentToken', true);
if ($token && $token->name == $this->element) return false; if ($token && $token->name == $this->element) {
return false;
}
return $this->def->validate($string, $config, $context); return $this->def->validate($string, $config, $context);
} }
} }

View File

@@ -7,23 +7,37 @@
*/ */
class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
{ {
/**
* @type HTMLPurifier_AttrDef_Integer
*/
protected $intValidator; protected $intValidator;
public function __construct() { public function __construct()
{
$this->intValidator = new HTMLPurifier_AttrDef_Integer(); $this->intValidator = new HTMLPurifier_AttrDef_Integer();
} }
public function validate($value, $config, $context) { /**
* @param string $value
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($value, $config, $context)
{
$value = $this->parseCDATA($value); $value = $this->parseCDATA($value);
if ($value === 'none') return $value; if ($value === 'none') {
return $value;
}
// if we looped this we could support multiple filters // if we looped this we could support multiple filters
$function_length = strcspn($value, '('); $function_length = strcspn($value, '(');
$function = trim(substr($value, 0, $function_length)); $function = trim(substr($value, 0, $function_length));
if ($function !== 'alpha' && if ($function !== 'alpha' &&
$function !== 'Alpha' && $function !== 'Alpha' &&
$function !== 'progid:DXImageTransform.Microsoft.Alpha' $function !== 'progid:DXImageTransform.Microsoft.Alpha'
) return false; ) {
return false;
}
$cursor = $function_length + 1; $cursor = $function_length + 1;
$parameters_length = strcspn($value, ')', $cursor); $parameters_length = strcspn($value, ')', $cursor);
$parameters = substr($value, $cursor, $parameters_length); $parameters = substr($value, $cursor, $parameters_length);
@@ -32,15 +46,25 @@ class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
$lookup = array(); $lookup = array();
foreach ($params as $param) { foreach ($params as $param) {
list($key, $value) = explode('=', $param); list($key, $value) = explode('=', $param);
$key = trim($key); $key = trim($key);
$value = trim($value); $value = trim($value);
if (isset($lookup[$key])) continue; if (isset($lookup[$key])) {
if ($key !== 'opacity') continue; continue;
}
if ($key !== 'opacity') {
continue;
}
$value = $this->intValidator->validate($value, $config, $context); $value = $this->intValidator->validate($value, $config, $context);
if ($value === false) continue; if ($value === false) {
$int = (int) $value; continue;
if ($int > 100) $value = '100'; }
if ($int < 0) $value = '0'; $int = (int)$value;
if ($int > 100) {
$value = '100';
}
if ($int < 0) {
$value = '0';
}
$ret_params[] = "$key=$value"; $ret_params[] = "$key=$value";
$lookup[$key] = true; $lookup[$key] = true;
} }
@@ -48,7 +72,6 @@ class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
$ret_function = "$function($ret_parameters)"; $ret_function = "$function($ret_parameters)";
return $ret_function; return $ret_function;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -7,8 +7,8 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
{ {
/** /**
* Local copy of component validators. * Local copy of validators
* * @type HTMLPurifier_AttrDef[]
* @note If we moved specific CSS property definitions to their own * @note If we moved specific CSS property definitions to their own
* classes instead of having them be assembled at run time by * classes instead of having them be assembled at run time by
* CSSDefinition, this wouldn't be necessary. We'd instantiate * CSSDefinition, this wouldn't be necessary. We'd instantiate
@@ -16,18 +16,28 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
*/ */
protected $info = array(); protected $info = array();
public function __construct($config) { /**
* @param HTMLPurifier_Config $config
*/
public function __construct($config)
{
$def = $config->getCSSDefinition(); $def = $config->getCSSDefinition();
$this->info['font-style'] = $def->info['font-style']; $this->info['font-style'] = $def->info['font-style'];
$this->info['font-variant'] = $def->info['font-variant']; $this->info['font-variant'] = $def->info['font-variant'];
$this->info['font-weight'] = $def->info['font-weight']; $this->info['font-weight'] = $def->info['font-weight'];
$this->info['font-size'] = $def->info['font-size']; $this->info['font-size'] = $def->info['font-size'];
$this->info['line-height'] = $def->info['line-height']; $this->info['line-height'] = $def->info['line-height'];
$this->info['font-family'] = $def->info['font-family']; $this->info['font-family'] = $def->info['font-family'];
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
static $system_fonts = array( static $system_fonts = array(
'caption' => true, 'caption' => true,
'icon' => true, 'icon' => true,
@@ -39,7 +49,9 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
// 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);
@@ -54,15 +66,20 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
$final = ''; // output $final = ''; // output
for ($i = 0, $size = count($bits); $i < $size; $i++) { for ($i = 0, $size = count($bits); $i < $size; $i++) {
if ($bits[$i] === '') continue; if ($bits[$i] === '') {
continue;
}
switch ($stage) { switch ($stage) {
case 0: // attempting to catch font-style, font-variant or font-weight
// attempting to catch font-style, font-variant or font-weight
case 0:
foreach ($stage_1 as $validator_name) { foreach ($stage_1 as $validator_name) {
if (isset($caught[$validator_name])) continue; if (isset($caught[$validator_name])) {
continue;
}
$r = $this->info[$validator_name]->validate( $r = $this->info[$validator_name]->validate(
$bits[$i], $config, $context); $bits[$i],
$config,
$context
);
if ($r !== false) { if ($r !== false) {
$final .= $r . ' '; $final .= $r . ' ';
$caught[$validator_name] = true; $caught[$validator_name] = true;
@@ -70,15 +87,17 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
} }
} }
// all three caught, continue on // all three caught, continue on
if (count($caught) >= 3) $stage = 1; if (count($caught) >= 3) {
if ($r !== false) break; $stage = 1;
}
// attempting to catch font-size and perhaps line-height if ($r !== false) {
case 1: break;
}
case 1: // attempting to catch font-size and perhaps line-height
$found_slash = false; $found_slash = false;
if (strpos($bits[$i], '/') !== false) { if (strpos($bits[$i], '/') !== false) {
list($font_size, $line_height) = list($font_size, $line_height) =
explode('/', $bits[$i]); explode('/', $bits[$i]);
if ($line_height === '') { if ($line_height === '') {
// ooh, there's a space after the slash! // ooh, there's a space after the slash!
$line_height = false; $line_height = false;
@@ -89,14 +108,19 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
$line_height = false; $line_height = false;
} }
$r = $this->info['font-size']->validate( $r = $this->info['font-size']->validate(
$font_size, $config, $context); $font_size,
$config,
$context
);
if ($r !== false) { if ($r !== false) {
$final .= $r; $final .= $r;
// attempt to catch line-height // attempt to catch line-height
if ($line_height === false) { if ($line_height === false) {
// we need to scroll forward // we need to scroll forward
for ($j = $i + 1; $j < $size; $j++) { for ($j = $i + 1; $j < $size; $j++) {
if ($bits[$j] === '') continue; if ($bits[$j] === '') {
continue;
}
if ($bits[$j] === '/') { if ($bits[$j] === '/') {
if ($found_slash) { if ($found_slash) {
return false; return false;
@@ -116,7 +140,10 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
if ($found_slash) { if ($found_slash) {
$i = $j; $i = $j;
$r = $this->info['line-height']->validate( $r = $this->info['line-height']->validate(
$line_height, $config, $context); $line_height,
$config,
$context
);
if ($r !== false) { if ($r !== false) {
$final .= '/' . $r; $final .= '/' . $r;
} }
@@ -126,13 +153,14 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
break; break;
} }
return false; return false;
case 2: // attempting to catch font-family
// attempting to catch font-family
case 2:
$font_family = $font_family =
implode(' ', array_slice($bits, $i, $size - $i)); implode(' ', array_slice($bits, $i, $size - $i));
$r = $this->info['font-family']->validate( $r = $this->info['font-family']->validate(
$font_family, $config, $context); $font_family,
$config,
$context
);
if ($r !== false) { if ($r !== false) {
$final .= $r . ' '; $final .= $r . ' ';
// processing completed successfully // processing completed successfully
@@ -143,7 +171,6 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
} }
return false; return false;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -8,11 +8,18 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
protected $mask = null; protected $mask = null;
public function __construct() { public function __construct()
{
$this->mask = '_- '; $this->mask = '_- ';
for ($c = 'a'; $c <= 'z'; $c++) $this->mask .= $c; for ($c = 'a'; $c <= 'z'; $c++) {
for ($c = 'A'; $c <= 'Z'; $c++) $this->mask .= $c; $this->mask .= $c;
for ($c = '0'; $c <= '9'; $c++) $this->mask .= $c; // cast-y, but should be fine }
for ($c = 'A'; $c <= 'Z'; $c++) {
$this->mask .= $c;
}
for ($c = '0'; $c <= '9'; $c++) {
$this->mask .= $c;
} // cast-y, but should be fine
// special bytes used by UTF-8 // special bytes used by UTF-8
for ($i = 0x80; $i <= 0xFF; $i++) { for ($i = 0x80; $i <= 0xFF; $i++) {
// We don't bother excluding invalid bytes in this range, // We don't bother excluding invalid bytes in this range,
@@ -39,7 +46,14 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
// possible optimization: invert the mask. // possible optimization: invert the mask.
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
static $generic_names = array( static $generic_names = array(
'serif' => true, 'serif' => true,
'sans-serif' => true, 'sans-serif' => true,
@@ -52,9 +66,11 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
// assume that no font names contain commas in them // assume that no font names contain commas in them
$fonts = explode(',', $string); $fonts = explode(',', $string);
$final = ''; $final = '';
foreach($fonts as $font) { foreach ($fonts as $font) {
$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($generic_names[$font])) {
if ($allowed_fonts === null || isset($allowed_fonts[$font])) { if ($allowed_fonts === null || isset($allowed_fonts[$font])) {
@@ -65,9 +81,13 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
// match a quoted name // match a quoted name
if ($font[0] === '"' || $font[0] === "'") { if ($font[0] === '"' || $font[0] === "'") {
$length = strlen($font); $length = strlen($font);
if ($length <= 2) continue; if ($length <= 2) {
continue;
}
$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);
} }
@@ -188,7 +208,9 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
$final .= "'$font', "; $final .= "'$font', ";
} }
$final = rtrim($final, ', '); $final = rtrim($final, ', ');
if ($final === '') return false; if ($final === '') {
return false;
}
return $final; return $final;
} }

View File

@@ -6,19 +6,27 @@
class HTMLPurifier_AttrDef_CSS_Ident extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_Ident extends HTMLPurifier_AttrDef
{ {
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string); $string = trim($string);
// early abort: '' and '0' (strings that convert to false) are invalid // early abort: '' and '0' (strings that convert to false) are invalid
if (!$string) return false; if (!$string) {
return false;
}
$pattern = '/^(-?[A-Za-z_][A-Za-z_\-0-9]*)$/'; $pattern = '/^(-?[A-Za-z_][A-Za-z_\-0-9]*)$/';
if (!preg_match($pattern, $string)) return false; if (!preg_match($pattern, $string)) {
return false;
}
return $string; return $string;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -5,20 +5,34 @@
*/ */
class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef
{ {
public $def, $allow; /**
* @type HTMLPurifier_AttrDef
*/
public $def;
/**
* @type bool
*/
public $allow;
/** /**
* @param $def Definition to wrap * @param HTMLPurifier_AttrDef $def Definition to wrap
* @param $allow Whether or not to allow !important * @param bool $allow Whether or not to allow !important
*/ */
public function __construct($def, $allow = false) { public function __construct($def, $allow = false)
{
$this->def = $def; $this->def = $def;
$this->allow = $allow; $this->allow = $allow;
} }
/** /**
* Intercepts and removes !important if necessary * Intercepts and removes !important if necessary
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/ */
public function validate($string, $config, $context) { public function validate($string, $config, $context)
{
// test for ! and important tokens // test for ! and important tokens
$string = trim($string); $string = trim($string);
$is_important = false; $is_important = false;
@@ -32,7 +46,9 @@ class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef
} }
} }
$string = $this->def->validate($string, $config, $context); $string = $this->def->validate($string, $config, $context);
if ($this->allow && $is_important) $string .= ' !important'; if ($this->allow && $is_important) {
$string .= ' !important';
}
return $string; return $string;
} }
} }

View File

@@ -6,42 +6,72 @@
class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef
{ {
protected $min, $max; /**
* @type HTMLPurifier_Length|string
*/
protected $min;
/** /**
* @param HTMLPurifier_Length $max Minimum length, or null for no bound. String is also acceptable. * @type HTMLPurifier_Length|string
* @param HTMLPurifier_Length $max Maximum length, or null for no bound. String is also acceptable.
*/ */
public function __construct($min = null, $max = null) { protected $max;
/**
* @param HTMLPurifier_Length|string $min Minimum length, or null for no bound. String is also acceptable.
* @param HTMLPurifier_Length|string $max Maximum length, or null for no bound. String is also acceptable.
*/
public function __construct($min = null, $max = null)
{
$this->min = $min !== null ? HTMLPurifier_Length::make($min) : null; $this->min = $min !== null ? HTMLPurifier_Length::make($min) : null;
$this->max = $max !== null ? HTMLPurifier_Length::make($max) : null; $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null;
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
// Optimizations // Optimizations
if ($string === '') return false; if ($string === '') {
if ($string === '0') return '0'; return false;
if (strlen($string) === 1) return false; }
if ($string === '0') {
return '0';
}
if (strlen($string) === 1) {
return false;
}
$length = HTMLPurifier_Length::make($string); $length = HTMLPurifier_Length::make($string);
if (!$length->isValid()) return false; if (!$length->isValid()) {
return false;
}
if ($this->min) { if ($this->min) {
$c = $length->compareTo($this->min); $c = $length->compareTo($this->min);
if ($c === false) return false; if ($c === false) {
if ($c < 0) return false; return false;
}
if ($c < 0) {
return false;
}
} }
if ($this->max) { if ($this->max) {
$c = $length->compareTo($this->max); $c = $length->compareTo($this->max);
if ($c === false) return false; if ($c === false) {
if ($c > 0) return false; return false;
}
if ($c > 0) {
return false;
}
} }
return $length->toString(); return $length->toString();
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -8,46 +8,72 @@ class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef
{ {
/** /**
* Local copy of component validators. * Local copy of validators.
* @type HTMLPurifier_AttrDef[]
* @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl. * @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl.
*/ */
protected $info; protected $info;
public function __construct($config) { /**
* @param HTMLPurifier_Config $config
*/
public function __construct($config)
{
$def = $config->getCSSDefinition(); $def = $config->getCSSDefinition();
$this->info['list-style-type'] = $def->info['list-style-type']; $this->info['list-style-type'] = $def->info['list-style-type'];
$this->info['list-style-position'] = $def->info['list-style-position']; $this->info['list-style-position'] = $def->info['list-style-position'];
$this->info['list-style-image'] = $def->info['list-style-image']; $this->info['list-style-image'] = $def->info['list-style-image'];
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
// regular pre-processing // regular pre-processing
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
if ($string === '') return false; if ($string === '') {
return false;
}
// assumes URI doesn't have spaces in it // assumes URI doesn't have spaces in it
$bits = explode(' ', strtolower($string)); // bits to process $bits = explode(' ', strtolower($string)); // bits to process
$caught = array(); $caught = array();
$caught['type'] = false; $caught['type'] = false;
$caught['position'] = false; $caught['position'] = false;
$caught['image'] = false; $caught['image'] = false;
$i = 0; // number of catches $i = 0; // number of catches
$none = false; $none = false;
foreach ($bits as $bit) { foreach ($bits as $bit) {
if ($i >= 3) return; // optimization bit if ($i >= 3) {
if ($bit === '') continue; return;
} // optimization bit
if ($bit === '') {
continue;
}
foreach ($caught as $key => $status) { foreach ($caught as $key => $status) {
if ($status !== false) continue; if ($status !== false) {
continue;
}
$r = $this->info['list-style-' . $key]->validate($bit, $config, $context); $r = $this->info['list-style-' . $key]->validate($bit, $config, $context);
if ($r === false) continue; if ($r === false) {
continue;
}
if ($r === 'none') { if ($r === 'none') {
if ($none) continue; if ($none) {
else $none = true; continue;
if ($key == 'image') continue; } else {
$none = true;
}
if ($key == 'image') {
continue;
}
} }
$caught[$key] = $r; $caught[$key] = $r;
$i++; $i++;
@@ -55,24 +81,32 @@ class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef
} }
} }
if (!$i) return false; if (!$i) {
return false;
}
$ret = array(); $ret = array();
// construct type // construct type
if ($caught['type']) $ret[] = $caught['type']; if ($caught['type']) {
$ret[] = $caught['type'];
}
// construct image // construct image
if ($caught['image']) $ret[] = $caught['image']; if ($caught['image']) {
$ret[] = $caught['image'];
}
// construct position // construct position
if ($caught['position']) $ret[] = $caught['position']; if ($caught['position']) {
$ret[] = $caught['position'];
}
if (empty($ret)) return false; if (empty($ret)) {
return false;
}
return implode(' ', $ret); return implode(' ', $ret);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -13,9 +13,9 @@
*/ */
class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
{ {
/** /**
* Instance of component definition to defer validation to. * Instance of component definition to defer validation to.
* @type HTMLPurifier_AttrDef
* @todo Make protected * @todo Make protected
*/ */
public $single; public $single;
@@ -27,32 +27,45 @@ class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
public $max; public $max;
/** /**
* @param $single HTMLPurifier_AttrDef to multiply * @param HTMLPurifier_AttrDef $single HTMLPurifier_AttrDef to multiply
* @param $max Max number of values allowed (usually four) * @param int $max Max number of values allowed (usually four)
*/ */
public function __construct($single, $max = 4) { public function __construct($single, $max = 4)
{
$this->single = $single; $this->single = $single;
$this->max = $max; $this->max = $max;
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
if ($string === '') return false; if ($string === '') {
return false;
}
$parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n $parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n
$length = count($parts); $length = count($parts);
$final = ''; $final = '';
for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) { for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) {
if (ctype_space($parts[$i])) continue; if (ctype_space($parts[$i])) {
continue;
}
$result = $this->single->validate($parts[$i], $config, $context); $result = $this->single->validate($parts[$i], $config, $context);
if ($result !== false) { if ($result !== false) {
$final .= $result . ' '; $final .= $result . ' ';
$num++; $num++;
} }
} }
if ($final === '') return false; if ($final === '') {
return false;
}
return rtrim($final); return rtrim($final);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -7,32 +7,44 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
{ {
/** /**
* Bool indicating whether or not only positive values allowed. * Indicates whether or not only positive values are allowed.
* @type bool
*/ */
protected $non_negative = false; protected $non_negative = false;
/** /**
* @param $non_negative Bool indicating whether negatives are forbidden * @param bool $non_negative indicates whether negatives are forbidden
*/ */
public function __construct($non_negative = false) { public function __construct($non_negative = false)
{
$this->non_negative = $non_negative; $this->non_negative = $non_negative;
} }
/** /**
* @param string $number
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return string|bool
* @warning Some contexts do not pass $config, $context. These * @warning Some contexts do not pass $config, $context. These
* variables should not be used without checking HTMLPurifier_Length * variables should not be used without checking HTMLPurifier_Length
*/ */
public function validate($number, $config, $context) { public function validate($number, $config, $context)
{
$number = $this->parseCDATA($number); $number = $this->parseCDATA($number);
if ($number === '') return false; if ($number === '') {
if ($number === '0') return '0'; return false;
}
if ($number === '0') {
return '0';
}
$sign = ''; $sign = '';
switch ($number[0]) { switch ($number[0]) {
case '-': case '-':
if ($this->non_negative) return false; if ($this->non_negative) {
return false;
}
$sign = '-'; $sign = '-';
case '+': case '+':
$number = substr($number, 1); $number = substr($number, 1);
@@ -44,14 +56,20 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
} }
// Period is the only non-numeric character allowed // Period is the only non-numeric character allowed
if (strpos($number, '.') === false) return false; if (strpos($number, '.') === false) {
return false;
}
list($left, $right) = explode('.', $number, 2); list($left, $right) = explode('.', $number, 2);
if ($left === '' && $right === '') return false; if ($left === '' && $right === '') {
if ($left !== '' && !ctype_digit($left)) return false; return false;
}
if ($left !== '' && !ctype_digit($left)) {
return false;
}
$left = ltrim($left, '0'); $left = ltrim($left, '0');
$right = rtrim($right, '0'); $right = rtrim($right, '0');
if ($right === '') { if ($right === '') {
@@ -59,11 +77,8 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
} elseif (!ctype_digit($right)) { } elseif (!ctype_digit($right)) {
return false; return false;
} }
return $sign . $left . '.' . $right; return $sign . $left . '.' . $right;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -7,34 +7,48 @@ class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef
{ {
/** /**
* Instance of HTMLPurifier_AttrDef_CSS_Number to defer number validation * Instance to defer number validation to.
* @type HTMLPurifier_AttrDef_CSS_Number
*/ */
protected $number_def; protected $number_def;
/** /**
* @param Bool indicating whether to forbid negative values * @param bool $non_negative Whether to forbid negative values
*/ */
public function __construct($non_negative = false) { public function __construct($non_negative = false)
{
$this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative); $this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative);
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
if ($string === '') return false; if ($string === '') {
return false;
}
$length = strlen($string); $length = strlen($string);
if ($length === 1) return false; if ($length === 1) {
if ($string[$length - 1] !== '%') return false; return false;
}
if ($string[$length - 1] !== '%') {
return false;
}
$number = substr($string, 0, $length - 1); $number = substr($string, 0, $length - 1);
$number = $this->number_def->validate($number, $config, $context); $number = $this->number_def->validate($number, $config, $context);
if ($number === false) return false; if ($number === false) {
return false;
}
return "$number%"; return "$number%";
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -8,8 +8,14 @@
class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
{ {
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
static $allowed_values = array( static $allowed_values = array(
'line-through' => true, 'line-through' => true,
'overline' => true, 'overline' => true,
@@ -18,7 +24,9 @@ class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
$string = strtolower($this->parseCDATA($string)); $string = strtolower($this->parseCDATA($string));
if ($string === 'none') return $string; if ($string === 'none') {
return $string;
}
$parts = explode(' ', $string); $parts = explode(' ', $string);
$final = ''; $final = '';
@@ -28,11 +36,11 @@ class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
} }
} }
$final = rtrim($final); $final = rtrim($final);
if ($final === '') return false; if ($final === '') {
return false;
}
return $final; return $final;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -12,25 +12,39 @@
class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
{ {
public function __construct() { public function __construct()
{
parent::__construct(true); // always embedded parent::__construct(true); // always embedded
} }
public function validate($uri_string, $config, $context) { /**
* @param string $uri_string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($uri_string, $config, $context)
{
// parse the URI out of the string and then pass it onto // parse the URI out of the string and then pass it onto
// the parent object // the parent object
$uri_string = $this->parseCDATA($uri_string); $uri_string = $this->parseCDATA($uri_string);
if (strpos($uri_string, 'url(') !== 0) return false; if (strpos($uri_string, 'url(') !== 0) {
return false;
}
$uri_string = substr($uri_string, 4); $uri_string = substr($uri_string, 4);
$new_length = strlen($uri_string) - 1; $new_length = strlen($uri_string) - 1;
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 (!empty($uri) && ($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;
}
$uri = substr($uri, 1, $new_length - 1); $uri = substr($uri, 1, $new_length - 1);
} }
@@ -38,7 +52,9 @@ class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
$result = parent::validate($uri, $config, $context); $result = parent::validate($uri, $config, $context);
if ($result === false) return false; if ($result === false) {
return false;
}
// extra sanity check; should have been done by URI // extra sanity check; should have been done by URI
$result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result); $result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result);
@@ -51,11 +67,8 @@ class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
// an innerHTML cycle, so a very unlucky query parameter could // an innerHTML cycle, so a very unlucky query parameter could
// then change the meaning of the URL. Unfortunately, there's // then change the meaning of the URL. Unfortunately, there's
// not much we can do about that... // not much we can do about that...
return "url(\"$result\")"; return "url(\"$result\")";
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -7,22 +7,38 @@
class HTMLPurifier_AttrDef_Clone extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_Clone extends HTMLPurifier_AttrDef
{ {
/** /**
* What we're cloning * What we're cloning.
* @type HTMLPurifier_AttrDef
*/ */
protected $clone; protected $clone;
public function __construct($clone) { /**
* @param HTMLPurifier_AttrDef $clone
*/
public function __construct($clone)
{
$this->clone = $clone; $this->clone = $clone;
} }
public function validate($v, $config, $context) { /**
* @param string $v
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($v, $config, $context)
{
return $this->clone->validate($v, $config, $context); return $this->clone->validate($v, $config, $context);
} }
public function make($string) { /**
* @param string $string
* @return HTMLPurifier_AttrDef
*/
public function make($string)
{
return clone $this->clone; return clone $this->clone;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -12,9 +12,10 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
/** /**
* Lookup table of valid values. * Lookup table of valid values.
* @type array
* @todo Make protected * @todo Make protected
*/ */
public $valid_values = array(); public $valid_values = array();
/** /**
* Bool indicating whether or not enumeration is case sensitive. * Bool indicating whether or not enumeration is case sensitive.
@@ -23,17 +24,23 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
protected $case_sensitive = false; // values according to W3C spec protected $case_sensitive = false; // values according to W3C spec
/** /**
* @param $valid_values List of valid values * @param array $valid_values List of valid values
* @param $case_sensitive Bool indicating whether or not case sensitive * @param bool $case_sensitive Whether or not case sensitive
*/ */
public function __construct( public function __construct($valid_values = array(), $case_sensitive = false)
$valid_values = array(), $case_sensitive = false {
) {
$this->valid_values = array_flip($valid_values); $this->valid_values = array_flip($valid_values);
$this->case_sensitive = $case_sensitive; $this->case_sensitive = $case_sensitive;
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string); $string = trim($string);
if (!$this->case_sensitive) { if (!$this->case_sensitive) {
// we may want to do full case-insensitive libraries // we may want to do full case-insensitive libraries
@@ -45,11 +52,13 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
} }
/** /**
* @param $string In form of comma-delimited list of case-insensitive * @param string $string In form of comma-delimited list of case-insensitive
* valid values. Example: "foo,bar,baz". Prepend "s:" to make * valid values. Example: "foo,bar,baz". Prepend "s:" to make
* case sensitive * case sensitive
* @return HTMLPurifier_AttrDef_Enum
*/ */
public function make($string) { public function make($string)
{
if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') { if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') {
$string = substr($string, 2); $string = substr($string, 2);
$sensitive = true; $sensitive = true;
@@ -59,7 +68,6 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
$values = explode(',', $string); $values = explode(',', $string);
return new HTMLPurifier_AttrDef_Enum($values, $sensitive); return new HTMLPurifier_AttrDef_Enum($values, $sensitive);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,23 +6,46 @@
class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef
{ {
/**
* @type bool
*/
protected $name; protected $name;
/**
* @type bool
*/
public $minimized = true; public $minimized = true;
public function __construct($name = false) {$this->name = $name;} /**
* @param bool $name
*/
public function __construct($name = false)
{
$this->name = $name;
}
public function validate($string, $config, $context) { /**
if (empty($string)) return false; * @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
if (empty($string)) {
return false;
}
return $this->name; return $this->name;
} }
/** /**
* @param $string Name of attribute * @param string $string Name of attribute
* @return HTMLPurifier_AttrDef_HTML_Bool
*/ */
public function make($string) { public function make($string)
{
return new HTMLPurifier_AttrDef_HTML_Bool($string); return new HTMLPurifier_AttrDef_HTML_Bool($string);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -5,7 +5,14 @@
*/ */
class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens
{ {
protected function split($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
protected function split($string, $config, $context)
{
// really, this twiddle should be lazy loaded // really, this twiddle should be lazy loaded
$name = $config->getDefinition('HTML')->doctype->name; $name = $config->getDefinition('HTML')->doctype->name;
if ($name == "XHTML 1.1" || $name == "XHTML 2.0") { if ($name == "XHTML 1.1" || $name == "XHTML 2.0") {
@@ -14,13 +21,20 @@ class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens
return preg_split('/\s+/', $string); return preg_split('/\s+/', $string);
} }
} }
protected function filter($tokens, $config, $context) {
/**
* @param array $tokens
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
protected function filter($tokens, $config, $context)
{
$allowed = $config->get('Attr.AllowedClasses'); $allowed = $config->get('Attr.AllowedClasses');
$forbidden = $config->get('Attr.ForbiddenClasses'); $forbidden = $config->get('Attr.ForbiddenClasses');
$ret = array(); $ret = array();
foreach ($tokens as $token) { foreach ($tokens as $token) {
if ( if (($allowed === null || isset($allowed[$token])) &&
($allowed === null || isset($allowed[$token])) &&
!isset($forbidden[$token]) && !isset($forbidden[$token]) &&
// We need this O(n) check because of PHP's array // We need this O(n) check because of PHP's array
// implementation that casts -0 to 0. // implementation that casts -0 to 0.

View File

@@ -6,28 +6,46 @@
class HTMLPurifier_AttrDef_HTML_Color extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_HTML_Color extends HTMLPurifier_AttrDef
{ {
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
static $colors = null; static $colors = null;
if ($colors === null) $colors = $config->get('Core.ColorKeywords'); if ($colors === null) {
$colors = $config->get('Core.ColorKeywords');
}
$string = trim($string); $string = trim($string);
if (empty($string)) return false; if (empty($string)) {
return false;
}
$lower = strtolower($string); $lower = strtolower($string);
if (isset($colors[$lower])) return $colors[$lower]; if (isset($colors[$lower])) {
if ($string[0] === '#') $hex = substr($string, 1); return $colors[$lower];
else $hex = $string; }
if ($string[0] === '#') {
$hex = substr($string, 1);
} else {
$hex = $string;
}
$length = strlen($hex); $length = strlen($hex);
if ($length !== 3 && $length !== 6) return false; if ($length !== 3 && $length !== 6) {
if (!ctype_xdigit($hex)) return false; return false;
if ($length === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2]; }
if (!ctype_xdigit($hex)) {
return false;
}
if ($length === 3) {
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
}
return "#$hex"; return "#$hex";
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,16 +6,33 @@
class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum
{ {
/**
* @type array
*/
public $valid_values = false; // uninitialized value public $valid_values = false; // uninitialized value
/**
* @type bool
*/
protected $case_sensitive = false; protected $case_sensitive = false;
public function __construct() {} public function __construct()
{
public function validate($string, $config, $context) {
if ($this->valid_values === false) $this->valid_values = $config->get('Attr.AllowedFrameTargets');
return parent::validate($string, $config, $context);
} }
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
if ($this->valid_values === false) {
$this->valid_values = $config->get('Attr.AllowedFrameTargets');
}
return parent::validate($string, $config, $context);
}
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -18,34 +18,56 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
/** /**
* Determines whether or not we're validating an ID in a CSS * Determines whether or not we're validating an ID in a CSS
* selector context. * selector context.
* @type bool
*/ */
protected $selector; protected $selector;
public function __construct($selector = false) { /**
* @param bool $selector
*/
public function __construct($selector = false)
{
$this->selector = $selector; $this->selector = $selector;
} }
public function validate($id, $config, $context) { /**
* @param string $id
if (!$this->selector && !$config->get('Attr.EnableID')) return false; * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($id, $config, $context)
{
if (!$this->selector && !$config->get('Attr.EnableID')) {
return false;
}
$id = trim($id); // trim it first $id = trim($id); // trim it first
if ($id === '') return false; if ($id === '') {
return false;
}
$prefix = $config->get('Attr.IDPrefix'); $prefix = $config->get('Attr.IDPrefix');
if ($prefix !== '') { if ($prefix !== '') {
$prefix .= $config->get('Attr.IDPrefixLocal'); $prefix .= $config->get('Attr.IDPrefixLocal');
// prevent re-appending the prefix // prevent re-appending the prefix
if (strpos($id, $prefix) !== 0) $id = $prefix . $id; if (strpos($id, $prefix) !== 0) {
$id = $prefix . $id;
}
} elseif ($config->get('Attr.IDPrefixLocal') !== '') { } elseif ($config->get('Attr.IDPrefixLocal') !== '') {
trigger_error('%Attr.IDPrefixLocal cannot be used unless '. trigger_error(
'%Attr.IDPrefix is set', E_USER_WARNING); '%Attr.IDPrefixLocal cannot be used unless ' .
'%Attr.IDPrefix is set',
E_USER_WARNING
);
} }
if (!$this->selector) { if (!$this->selector) {
$id_accumulator =& $context->get('IDAccumulator'); $id_accumulator =& $context->get('IDAccumulator');
if (isset($id_accumulator->ids[$id])) return false; if (isset($id_accumulator->ids[$id])) {
return false;
}
} }
// we purposely avoid using regex, hopefully this is faster // we purposely avoid using regex, hopefully this is faster
@@ -53,11 +75,14 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
if (ctype_alpha($id)) { if (ctype_alpha($id)) {
$result = true; $result = true;
} else { } else {
if (!ctype_alpha(@$id[0])) return false; if (!ctype_alpha(@$id[0])) {
$trim = trim( // primitive style of regexps, I suppose return false;
}
// primitive style of regexps, I suppose
$trim = trim(
$id, $id,
'A..Za..z0..9:-._' 'A..Za..z0..9:-._'
); );
$result = ($trim === ''); $result = ($trim === '');
} }
@@ -66,15 +91,15 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
return false; return false;
} }
if (!$this->selector && $result) $id_accumulator->add($id); if (!$this->selector && $result) {
$id_accumulator->add($id);
}
// if no change was made to the ID, return the result // if no change was made to the ID, return the result
// else, return the new id if stripping whitespace made it // else, return the new id if stripping whitespace made it
// valid, or return false. // valid, or return false.
return $result ? $id : false; return $result ? $id : false;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -10,32 +10,47 @@
class HTMLPurifier_AttrDef_HTML_Length extends HTMLPurifier_AttrDef_HTML_Pixels class HTMLPurifier_AttrDef_HTML_Length extends HTMLPurifier_AttrDef_HTML_Pixels
{ {
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string); $string = trim($string);
if ($string === '') return false; if ($string === '') {
return false;
}
$parent_result = parent::validate($string, $config, $context); $parent_result = parent::validate($string, $config, $context);
if ($parent_result !== false) return $parent_result; if ($parent_result !== false) {
return $parent_result;
}
$length = strlen($string); $length = strlen($string);
$last_char = $string[$length - 1]; $last_char = $string[$length - 1];
if ($last_char !== '%') return false; if ($last_char !== '%') {
return false;
}
$points = substr($string, 0, $length - 1); $points = substr($string, 0, $length - 1);
if (!is_numeric($points)) return false; if (!is_numeric($points)) {
return false;
}
$points = (int) $points; $points = (int)$points;
if ($points < 0) return '0%';
if ($points > 100) return '100%';
return ((string) $points) . '%';
if ($points < 0) {
return '0%';
}
if ($points > 100) {
return '100%';
}
return ((string)$points) . '%';
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -9,26 +9,44 @@
class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
{ {
/** Name config attribute to pull. */ /**
* Name config attribute to pull.
* @type string
*/
protected $name; protected $name;
public function __construct($name) { /**
* @param string $name
*/
public function __construct($name)
{
$configLookup = array( $configLookup = array(
'rel' => 'AllowedRel', 'rel' => 'AllowedRel',
'rev' => 'AllowedRev' 'rev' => 'AllowedRev'
); );
if (!isset($configLookup[$name])) { if (!isset($configLookup[$name])) {
trigger_error('Unrecognized attribute name for link '. trigger_error(
'relationship.', E_USER_ERROR); 'Unrecognized attribute name for link ' .
'relationship.',
E_USER_ERROR
);
return; return;
} }
$this->name = $configLookup[$name]; $this->name = $configLookup[$name];
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$allowed = $config->get('Attr.' . $this->name); $allowed = $config->get('Attr.' . $this->name);
if (empty($allowed)) return false; if (empty($allowed)) {
return false;
}
$string = $this->parseCDATA($string); $string = $this->parseCDATA($string);
$parts = explode(' ', $string); $parts = explode(' ', $string);
@@ -37,17 +55,18 @@ class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
$ret_lookup = array(); $ret_lookup = array();
foreach ($parts as $part) { foreach ($parts as $part) {
$part = strtolower(trim($part)); $part = strtolower(trim($part));
if (!isset($allowed[$part])) continue; if (!isset($allowed[$part])) {
continue;
}
$ret_lookup[$part] = true; $ret_lookup[$part] = true;
} }
if (empty($ret_lookup)) return false; if (empty($ret_lookup)) {
return false;
}
$string = implode(' ', array_keys($ret_lookup)); $string = implode(' ', array_keys($ret_lookup));
return $string; return $string;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -9,33 +9,52 @@
class HTMLPurifier_AttrDef_HTML_MultiLength extends HTMLPurifier_AttrDef_HTML_Length class HTMLPurifier_AttrDef_HTML_MultiLength extends HTMLPurifier_AttrDef_HTML_Length
{ {
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string); $string = trim($string);
if ($string === '') return false; if ($string === '') {
return false;
}
$parent_result = parent::validate($string, $config, $context); $parent_result = parent::validate($string, $config, $context);
if ($parent_result !== false) return $parent_result; if ($parent_result !== false) {
return $parent_result;
}
$length = strlen($string); $length = strlen($string);
$last_char = $string[$length - 1]; $last_char = $string[$length - 1];
if ($last_char !== '*') return false; if ($last_char !== '*') {
return false;
}
$int = substr($string, 0, $length - 1); $int = substr($string, 0, $length - 1);
if ($int == '') return '*'; if ($int == '') {
if (!is_numeric($int)) return false; return '*';
}
$int = (int) $int; if (!is_numeric($int)) {
return false;
if ($int < 0) return false; }
if ($int == 0) return '0';
if ($int == 1) return '*';
return ((string) $int) . '*';
$int = (int)$int;
if ($int < 0) {
return false;
}
if ($int == 0) {
return '0';
}
if ($int == 1) {
return '*';
}
return ((string)$int) . '*';
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,24 +6,38 @@
class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
{ {
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string); $string = trim($string);
// early abort: '' and '0' (strings that convert to false) are invalid // early abort: '' and '0' (strings that convert to false) are invalid
if (!$string) return false; if (!$string) {
return false;
}
$tokens = $this->split($string, $config, $context); $tokens = $this->split($string, $config, $context);
$tokens = $this->filter($tokens, $config, $context); $tokens = $this->filter($tokens, $config, $context);
if (empty($tokens)) return false; if (empty($tokens)) {
return false;
}
return implode(' ', $tokens); return implode(' ', $tokens);
} }
/** /**
* Splits a space separated list of tokens into its constituent parts. * Splits a space separated list of tokens into its constituent parts.
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/ */
protected function split($string, $config, $context) { protected function split($string, $config, $context)
{
// OPTIMIZABLE! // OPTIMIZABLE!
// do the preg_match, capture all subpatterns for reformulation // do the preg_match, capture all subpatterns for reformulation
@@ -31,9 +45,9 @@ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
// escaping because I don't know how to do that with regexps // escaping because I don't know how to do that with regexps
// and plus it would complicate optimization efforts (you never // and plus it would complicate optimization efforts (you never
// see that anyway). // see that anyway).
$pattern = '/(?:(?<=\s)|\A)'. // look behind for space or string start $pattern = '/(?:(?<=\s)|\A)' . // look behind for space or string start
'((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)'. '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)' .
'(?:(?=\s)|\z)/'; // look ahead for space or string end '(?:(?=\s)|\z)/'; // look ahead for space or string end
preg_match_all($pattern, $string, $matches); preg_match_all($pattern, $string, $matches);
return $matches[1]; return $matches[1];
} }
@@ -42,11 +56,15 @@ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
* Template method for removing certain tokens based on arbitrary criteria. * Template method for removing certain tokens based on arbitrary criteria.
* @note If we wanted to be really functional, we'd do an array_filter * @note If we wanted to be really functional, we'd do an array_filter
* with a callback. But... we're not. * with a callback. But... we're not.
* @param array $tokens
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/ */
protected function filter($tokens, $config, $context) { protected function filter($tokens, $config, $context)
{
return $tokens; return $tokens;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,43 +6,71 @@
class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef
{ {
/**
* @type int
*/
protected $max; protected $max;
public function __construct($max = null) { /**
* @param int $max
*/
public function __construct($max = null)
{
$this->max = $max; $this->max = $max;
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string); $string = trim($string);
if ($string === '0') return $string; if ($string === '0') {
if ($string === '') return false; return $string;
}
if ($string === '') {
return false;
}
$length = strlen($string); $length = strlen($string);
if (substr($string, $length - 2) == 'px') { if (substr($string, $length - 2) == 'px') {
$string = substr($string, 0, $length - 2); $string = substr($string, 0, $length - 2);
} }
if (!is_numeric($string)) return false; if (!is_numeric($string)) {
$int = (int) $string; return false;
}
$int = (int)$string;
if ($int < 0) return '0'; if ($int < 0) {
return '0';
}
// upper-bound value, extremely high values can // upper-bound value, extremely high values can
// crash operating systems, see <http://ha.ckers.org/imagecrash.html> // crash operating systems, see <http://ha.ckers.org/imagecrash.html>
// WARNING, above link WILL crash you if you're using Windows // WARNING, above link WILL crash you if you're using Windows
if ($this->max !== null && $int > $this->max) return (string) $this->max; if ($this->max !== null && $int > $this->max) {
return (string)$this->max;
return (string) $int; }
return (string)$int;
} }
public function make($string) { /**
if ($string === '') $max = null; * @param string $string
else $max = (int) $string; * @return HTMLPurifier_AttrDef
*/
public function make($string)
{
if ($string === '') {
$max = null;
} else {
$max = (int)$string;
}
$class = get_class($this); $class = get_class($this);
return new $class($max); return new $class($max);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -11,17 +11,20 @@ class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef
{ {
/** /**
* Bool indicating whether or not negative values are allowed * Whether or not negative values are allowed.
* @type bool
*/ */
protected $negative = true; protected $negative = true;
/** /**
* Bool indicating whether or not zero is allowed * Whether or not zero is allowed.
* @type bool
*/ */
protected $zero = true; protected $zero = true;
/** /**
* Bool indicating whether or not positive values are allowed * Whether or not positive values are allowed.
* @type bool
*/ */
protected $positive = true; protected $positive = true;
@@ -30,44 +33,59 @@ class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef
* @param $zero Bool indicating whether or not zero is allowed * @param $zero Bool indicating whether or not zero is allowed
* @param $positive Bool indicating whether or not positive values are allowed * @param $positive Bool indicating whether or not positive values are allowed
*/ */
public function __construct( public function __construct($negative = true, $zero = true, $positive = true)
$negative = true, $zero = true, $positive = true {
) {
$this->negative = $negative; $this->negative = $negative;
$this->zero = $zero; $this->zero = $zero;
$this->positive = $positive; $this->positive = $positive;
} }
public function validate($integer, $config, $context) { /**
* @param string $integer
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($integer, $config, $context)
{
$integer = $this->parseCDATA($integer); $integer = $this->parseCDATA($integer);
if ($integer === '') return false; if ($integer === '') {
return false;
}
// we could possibly simply typecast it to integer, but there are // we could possibly simply typecast it to integer, but there are
// certain fringe cases that must not return an integer. // certain fringe cases that must not return an integer.
// clip leading sign // clip leading sign
if ( $this->negative && $integer[0] === '-' ) { if ($this->negative && $integer[0] === '-') {
$digits = substr($integer, 1); $digits = substr($integer, 1);
if ($digits === '0') $integer = '0'; // rm minus sign for zero if ($digits === '0') {
} elseif( $this->positive && $integer[0] === '+' ) { $integer = '0';
} // rm minus sign for zero
} elseif ($this->positive && $integer[0] === '+') {
$digits = $integer = substr($integer, 1); // rm unnecessary plus $digits = $integer = substr($integer, 1); // rm unnecessary plus
} else { } else {
$digits = $integer; $digits = $integer;
} }
// test if it's numeric // test if it's numeric
if (!ctype_digit($digits)) return false; if (!ctype_digit($digits)) {
return false;
}
// perform scope tests // perform scope tests
if (!$this->zero && $integer == 0) return false; if (!$this->zero && $integer == 0) {
if (!$this->positive && $integer > 0) return false; return false;
if (!$this->negative && $integer < 0) return false; }
if (!$this->positive && $integer > 0) {
return false;
}
if (!$this->negative && $integer < 0) {
return false;
}
return $integer; return $integer;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -7,15 +7,25 @@
class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
{ {
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string); $string = trim($string);
if (!$string) return false; if (!$string) {
return false;
}
$subtags = explode('-', $string); $subtags = explode('-', $string);
$num_subtags = count($subtags); $num_subtags = count($subtags);
if ($num_subtags == 0) return false; // sanity check if ($num_subtags == 0) { // sanity check
return false;
}
// process primary subtag : $subtags[0] // process primary subtag : $subtags[0]
$length = strlen($subtags[0]); $length = strlen($subtags[0]);
@@ -23,15 +33,15 @@ class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
case 0: case 0:
return false; return false;
case 1: case 1:
if (! ($subtags[0] == 'x' || $subtags[0] == 'i') ) { if (!($subtags[0] == 'x' || $subtags[0] == 'i')) {
return false; return false;
} }
break; break;
case 2: case 2:
case 3: case 3:
if (! ctype_alpha($subtags[0]) ) { if (!ctype_alpha($subtags[0])) {
return false; return false;
} elseif (! ctype_lower($subtags[0]) ) { } elseif (!ctype_lower($subtags[0])) {
$subtags[0] = strtolower($subtags[0]); $subtags[0] = strtolower($subtags[0]);
} }
break; break;
@@ -40,17 +50,23 @@ class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
} }
$new_string = $subtags[0]; $new_string = $subtags[0];
if ($num_subtags == 1) return $new_string; if ($num_subtags == 1) {
return $new_string;
}
// process second subtag : $subtags[1] // process second subtag : $subtags[1]
$length = strlen($subtags[1]); $length = strlen($subtags[1]);
if ($length == 0 || ($length == 1 && $subtags[1] != 'x') || $length > 8 || !ctype_alnum($subtags[1])) { if ($length == 0 || ($length == 1 && $subtags[1] != 'x') || $length > 8 || !ctype_alnum($subtags[1])) {
return $new_string; return $new_string;
} }
if (!ctype_lower($subtags[1])) $subtags[1] = strtolower($subtags[1]); if (!ctype_lower($subtags[1])) {
$subtags[1] = strtolower($subtags[1]);
}
$new_string .= '-' . $subtags[1]; $new_string .= '-' . $subtags[1];
if ($num_subtags == 2) return $new_string; if ($num_subtags == 2) {
return $new_string;
}
// process all other subtags, index 2 and up // process all other subtags, index 2 and up
for ($i = 2; $i < $num_subtags; $i++) { for ($i = 2; $i < $num_subtags; $i++) {
@@ -63,11 +79,8 @@ class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
} }
$new_string .= '-' . $subtags[$i]; $new_string .= '-' . $subtags[$i];
} }
return $new_string; return $new_string;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,21 +6,41 @@
class HTMLPurifier_AttrDef_Switch class HTMLPurifier_AttrDef_Switch
{ {
/**
* @type string
*/
protected $tag; protected $tag;
protected $withTag, $withoutTag;
/**
* @type HTMLPurifier_AttrDef
*/
protected $withTag;
/**
* @type HTMLPurifier_AttrDef
*/
protected $withoutTag;
/** /**
* @param string $tag Tag name to switch upon * @param string $tag Tag name to switch upon
* @param HTMLPurifier_AttrDef $with_tag Call if token matches tag * @param HTMLPurifier_AttrDef $with_tag Call if token matches tag
* @param HTMLPurifier_AttrDef $without_tag Call if token doesn't match, or there is no token * @param HTMLPurifier_AttrDef $without_tag Call if token doesn't match, or there is no token
*/ */
public function __construct($tag, $with_tag, $without_tag) { public function __construct($tag, $with_tag, $without_tag)
{
$this->tag = $tag; $this->tag = $tag;
$this->withTag = $with_tag; $this->withTag = $with_tag;
$this->withoutTag = $without_tag; $this->withoutTag = $without_tag;
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$token = $context->get('CurrentToken', true); $token = $context->get('CurrentToken', true);
if (!$token || $token->name !== $this->tag) { if (!$token || $token->name !== $this->tag) {
return $this->withoutTag->validate($string, $config, $context); return $this->withoutTag->validate($string, $config, $context);
@@ -28,7 +48,6 @@ class HTMLPurifier_AttrDef_Switch
return $this->withTag->validate($string, $config, $context); return $this->withTag->validate($string, $config, $context);
} }
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,10 +6,16 @@
class HTMLPurifier_AttrDef_Text extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_Text extends HTMLPurifier_AttrDef
{ {
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
return $this->parseCDATA($string); return $this->parseCDATA($string);
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -7,31 +7,54 @@
class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
{ {
/**
* @type HTMLPurifier_URIParser
*/
protected $parser; protected $parser;
/**
* @type bool
*/
protected $embedsResource; protected $embedsResource;
/** /**
* @param $embeds_resource_resource Does the URI here result in an extra HTTP request? * @param bool $embeds_resource Does the URI here result in an extra HTTP request?
*/ */
public function __construct($embeds_resource = false) { public function __construct($embeds_resource = false)
{
$this->parser = new HTMLPurifier_URIParser(); $this->parser = new HTMLPurifier_URIParser();
$this->embedsResource = (bool) $embeds_resource; $this->embedsResource = (bool)$embeds_resource;
} }
public function make($string) { /**
* @param string $string
* @return HTMLPurifier_AttrDef_URI
*/
public function make($string)
{
$embeds = ($string === 'embedded'); $embeds = ($string === 'embedded');
return new HTMLPurifier_AttrDef_URI($embeds); return new HTMLPurifier_AttrDef_URI($embeds);
} }
public function validate($uri, $config, $context) { /**
* @param string $uri
if ($config->get('URI.Disable')) return false; * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($uri, $config, $context)
{
if ($config->get('URI.Disable')) {
return false;
}
$uri = $this->parseCDATA($uri); $uri = $this->parseCDATA($uri);
// parse the URI // parse the URI
$uri = $this->parser->parse($uri); $uri = $this->parser->parse($uri);
if ($uri === false) return false; if ($uri === false) {
return false;
}
// add embedded flag to context for validators // add embedded flag to context for validators
$context->register('EmbeddedURI', $this->embedsResource); $context->register('EmbeddedURI', $this->embedsResource);
@@ -41,23 +64,35 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
// generic validation // generic validation
$result = $uri->validate($config, $context); $result = $uri->validate($config, $context);
if (!$result) break; if (!$result) {
break;
}
// chained filtering // chained filtering
$uri_def = $config->getDefinition('URI'); $uri_def = $config->getDefinition('URI');
$result = $uri_def->filter($uri, $config, $context); $result = $uri_def->filter($uri, $config, $context);
if (!$result) break; if (!$result) {
break;
}
// scheme-specific validation // scheme-specific validation
$scheme_obj = $uri->getSchemeObj($config, $context); $scheme_obj = $uri->getSchemeObj($config, $context);
if (!$scheme_obj) break; if (!$scheme_obj) {
if ($this->embedsResource && !$scheme_obj->browsable) break; break;
}
if ($this->embedsResource && !$scheme_obj->browsable) {
break;
}
$result = $scheme_obj->validate($uri, $config, $context); $result = $scheme_obj->validate($uri, $config, $context);
if (!$result) break; if (!$result) {
break;
}
// Post chained filtering // Post chained filtering
$result = $uri_def->postFilter($uri, $config, $context); $result = $uri_def->postFilter($uri, $config, $context);
if (!$result) break; if (!$result) {
break;
}
// survived gauntlet // survived gauntlet
$ok = true; $ok = true;
@@ -65,13 +100,12 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
} while (false); } while (false);
$context->destroy('EmbeddedURI'); $context->destroy('EmbeddedURI');
if (!$ok) return false; if (!$ok) {
return false;
}
// back to string // back to string
return $uri->toString(); return $uri->toString();
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -5,8 +5,11 @@ abstract class HTMLPurifier_AttrDef_URI_Email extends HTMLPurifier_AttrDef
/** /**
* Unpacks a mailbox into its display-name and address * Unpacks a mailbox into its display-name and address
* @param string $string
* @return mixed
*/ */
function unpack($string) { public function unpack($string)
{
// needs to be implemented // needs to be implemented
} }

View File

@@ -7,15 +7,23 @@
class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_URI_Email class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_URI_Email
{ {
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
// no support for named mailboxes i.e. "Bob <bob@example.com>" // no support for named mailboxes i.e. "Bob <bob@example.com>"
// that needs more percent encoding to be done // that needs more percent encoding to be done
if ($string == '') return false; if ($string == '') {
return false;
}
$string = trim($string); $string = trim($string);
$result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string); $result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string);
return $result ? $string : false; return $result ? $string : false;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -7,21 +7,31 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
{ {
/** /**
* Instance of HTMLPurifier_AttrDef_URI_IPv4 sub-validator * IPv4 sub-validator.
* @type HTMLPurifier_AttrDef_URI_IPv4
*/ */
protected $ipv4; protected $ipv4;
/** /**
* Instance of HTMLPurifier_AttrDef_URI_IPv6 sub-validator * IPv6 sub-validator.
* @type HTMLPurifier_AttrDef_URI_IPv6
*/ */
protected $ipv6; protected $ipv6;
public function __construct() { public function __construct()
{
$this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4(); $this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4();
$this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6(); $this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6();
} }
public function validate($string, $config, $context) { /**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$length = strlen($string); $length = strlen($string);
// empty hostname is OK; it's usually semantically equivalent: // empty hostname is OK; it's usually semantically equivalent:
// the default host as defined by a URI scheme is used: // the default host as defined by a URI scheme is used:
@@ -29,32 +39,51 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
// If the URI scheme defines a default for host, then that // If the URI scheme defines a default for host, then that
// default applies when the host subcomponent is undefined // default applies when the host subcomponent is undefined
// or when the registered name is empty (zero length). // or when the registered name is empty (zero length).
if ($string === '') return ''; if ($string === '') {
if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') { return '';
}
if ($length > 1 && $string[0] === '[' && $string[$length - 1] === ']') {
//IPv6 //IPv6
$ip = substr($string, 1, $length - 2); $ip = substr($string, 1, $length - 2);
$valid = $this->ipv6->validate($ip, $config, $context); $valid = $this->ipv6->validate($ip, $config, $context);
if ($valid === false) return false; if ($valid === false) {
return '['. $valid . ']'; return false;
}
return '[' . $valid . ']';
} }
// need to do checks on unusual encodings too // need to do checks on unusual encodings too
$ipv4 = $this->ipv4->validate($string, $config, $context); $ipv4 = $this->ipv4->validate($string, $config, $context);
if ($ipv4 !== false) return $ipv4; if ($ipv4 !== false) {
return $ipv4;
}
// A regular domain name. // A regular domain name.
// This doesn't match I18N domain names, but we don't have proper IRI support, // This doesn't match I18N domain names, but we don't have proper IRI support,
// so force users to insert Punycode. // so force users to insert Punycode.
// There is not a good sense in which underscores should be
// allowed, since it's technically not! (And if you go as
// far to allow everything as specified by the DNS spec...
// well, that's literally everything, modulo some space limits
// for the components and the overall name (which, by the way,
// we are NOT checking!). So we (arbitrarily) decide this:
// let's allow underscores wherever we would have allowed
// hyphens, if they are enabled. This is a pretty good match
// for browser behavior, for example, a large number of browsers
// cannot handle foo_.example.com, but foo_bar.example.com is
// fairly well supported.
$underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : '';
// The productions describing this are: // The productions describing this are:
$a = '[a-z]'; // alpha $a = '[a-z]'; // alpha
$an = '[a-z0-9]'; // alphanum $an = '[a-z0-9]'; // alphanum
$and = '[a-z0-9-]'; // alphanum | "-" $and = "[a-z0-9-$underscore]"; // alphanum | "-"
// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
$domainlabel = "$an($and*$an)?"; $domainlabel = "$an($and*$an)?";
// toplabel = alpha | alpha *( alphanum | "-" ) alphanum // toplabel = alpha | alpha *( alphanum | "-" ) alphanum
$toplabel = "$a($and*$an)?"; $toplabel = "$a($and*$an)?";
// hostname = *( domainlabel "." ) toplabel [ "." ] // hostname = *( domainlabel "." ) toplabel [ "." ]
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) { if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
return $string; return $string;
@@ -92,10 +121,8 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
// XXX error reporting // XXX error reporting
} }
} }
return false; return false;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -8,32 +8,38 @@ class HTMLPurifier_AttrDef_URI_IPv4 extends HTMLPurifier_AttrDef
{ {
/** /**
* IPv4 regex, protected so that IPv6 can reuse it * IPv4 regex, protected so that IPv6 can reuse it.
* @type string
*/ */
protected $ip4; protected $ip4;
public function validate($aIP, $config, $context) { /**
* @param string $aIP
if (!$this->ip4) $this->_loadRegex(); * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) * @return bool|string
{ */
return $aIP; public function validate($aIP, $config, $context)
{
if (!$this->ip4) {
$this->_loadRegex();
} }
if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) {
return $aIP;
}
return false; return false;
} }
/** /**
* Lazy load function to prevent regex from being stuffed in * Lazy load function to prevent regex from being stuffed in
* cache. * cache.
*/ */
protected function _loadRegex() { protected function _loadRegex()
{
$oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255 $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})"; $this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})";
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -9,91 +9,81 @@
class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4 class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4
{ {
public function validate($aIP, $config, $context) { /**
* @param string $aIP
if (!$this->ip4) $this->_loadRegex(); * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($aIP, $config, $context)
{
if (!$this->ip4) {
$this->_loadRegex();
}
$original = $aIP; $original = $aIP;
$hex = '[0-9a-fA-F]'; $hex = '[0-9a-fA-F]';
$blk = '(?:' . $hex . '{1,4})'; $blk = '(?:' . $hex . '{1,4})';
$pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128 $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128
// prefix check // prefix check
if (strpos($aIP, '/') !== false) if (strpos($aIP, '/') !== false) {
{ if (preg_match('#' . $pre . '$#s', $aIP, $find)) {
if (preg_match('#' . $pre . '$#s', $aIP, $find)) $aIP = substr($aIP, 0, 0 - strlen($find[0]));
{ unset($find);
$aIP = substr($aIP, 0, 0-strlen($find[0])); } else {
unset($find); return false;
} }
else
{
return false;
}
} }
// IPv4-compatiblity check // IPv4-compatiblity check
if (preg_match('#(?<=:'.')' . $this->ip4 . '$#s', $aIP, $find)) if (preg_match('#(?<=:' . ')' . $this->ip4 . '$#s', $aIP, $find)) {
{ $aIP = substr($aIP, 0, 0 - strlen($find[0]));
$aIP = substr($aIP, 0, 0-strlen($find[0])); $ip = explode('.', $find[0]);
$ip = explode('.', $find[0]); $ip = array_map('dechex', $ip);
$ip = array_map('dechex', $ip); $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3];
$aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3]; unset($find, $ip);
unset($find, $ip);
} }
// compression check // compression check
$aIP = explode('::', $aIP); $aIP = explode('::', $aIP);
$c = count($aIP); $c = count($aIP);
if ($c > 2) if ($c > 2) {
{ return false;
} elseif ($c == 2) {
list($first, $second) = $aIP;
$first = explode(':', $first);
$second = explode(':', $second);
if (count($first) + count($second) > 8) {
return false; return false;
} }
elseif ($c == 2)
{
list($first, $second) = $aIP;
$first = explode(':', $first);
$second = explode(':', $second);
if (count($first) + count($second) > 8) while (count($first) < 8) {
{ array_push($first, '0');
return false; }
}
while(count($first) < 8) array_splice($first, 8 - count($second), 8, $second);
{ $aIP = $first;
array_push($first, '0'); unset($first, $second);
} } else {
$aIP = explode(':', $aIP[0]);
array_splice($first, 8 - count($second), 8, $second);
$aIP = $first;
unset($first,$second);
}
else
{
$aIP = explode(':', $aIP[0]);
} }
$c = count($aIP); $c = count($aIP);
if ($c != 8) if ($c != 8) {
{ return false;
return false;
} }
// All the pieces should be 16-bit hex strings. Are they? // All the pieces should be 16-bit hex strings. Are they?
foreach ($aIP as $piece) foreach ($aIP as $piece) {
{ if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) {
if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) return false;
{ }
return false;
}
} }
return $original; return $original;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -20,37 +20,41 @@ abstract class HTMLPurifier_AttrTransform
/** /**
* Abstract: makes changes to the attributes dependent on multiple values. * Abstract: makes changes to the attributes dependent on multiple values.
* *
* @param $attr Assoc array of attributes, usually from * @param array $attr Assoc array of attributes, usually from
* HTMLPurifier_Token_Tag::$attr * HTMLPurifier_Token_Tag::$attr
* @param $config Mandatory HTMLPurifier_Config object. * @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object.
* @param $context Mandatory HTMLPurifier_Context object * @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object
* @returns Processed attribute array. * @return array Processed attribute array.
*/ */
abstract public function transform($attr, $config, $context); abstract public function transform($attr, $config, $context);
/** /**
* Prepends CSS properties to the style attribute, creating the * Prepends CSS properties to the style attribute, creating the
* attribute if it doesn't exist. * attribute if it doesn't exist.
* @param $attr Attribute array to process (passed by reference) * @param array &$attr Attribute array to process (passed by reference)
* @param $css CSS to prepend * @param string $css CSS to prepend
*/ */
public function prependCSS(&$attr, $css) { public function prependCSS(&$attr, $css)
{
$attr['style'] = isset($attr['style']) ? $attr['style'] : ''; $attr['style'] = isset($attr['style']) ? $attr['style'] : '';
$attr['style'] = $css . $attr['style']; $attr['style'] = $css . $attr['style'];
} }
/** /**
* Retrieves and removes an attribute * Retrieves and removes an attribute
* @param $attr Attribute array to process (passed by reference) * @param array &$attr Attribute array to process (passed by reference)
* @param $key Key of attribute to confiscate * @param mixed $key Key of attribute to confiscate
* @return mixed
*/ */
public function confiscateAttr(&$attr, $key) { public function confiscateAttr(&$attr, $key)
if (!isset($attr[$key])) return null; {
if (!isset($attr[$key])) {
return null;
}
$value = $attr[$key]; $value = $attr[$key];
unset($attr[$key]); unset($attr[$key]);
return $value; return $value;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -3,21 +3,26 @@
/** /**
* Pre-transform that changes proprietary background attribute to CSS. * Pre-transform that changes proprietary background attribute to CSS.
*/ */
class HTMLPurifier_AttrTransform_Background extends HTMLPurifier_AttrTransform { class HTMLPurifier_AttrTransform_Background extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) { /**
* @param array $attr
if (!isset($attr['background'])) return $attr; * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['background'])) {
return $attr;
}
$background = $this->confiscateAttr($attr, 'background'); $background = $this->confiscateAttr($attr, 'background');
// some validation should happen here // some validation should happen here
$this->prependCSS($attr, "background-image:url($background);"); $this->prependCSS($attr, "background-image:url($background);");
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -8,12 +8,20 @@
class HTMLPurifier_AttrTransform_BdoDir extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_BdoDir extends HTMLPurifier_AttrTransform
{ {
public function transform($attr, $config, $context) { /**
if (isset($attr['dir'])) return $attr; * @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (isset($attr['dir'])) {
return $attr;
}
$attr['dir'] = $config->get('Attr.DefaultTextDir'); $attr['dir'] = $config->get('Attr.DefaultTextDir');
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -3,21 +3,26 @@
/** /**
* Pre-transform that changes deprecated bgcolor attribute to CSS. * Pre-transform that changes deprecated bgcolor attribute to CSS.
*/ */
class HTMLPurifier_AttrTransform_BgColor extends HTMLPurifier_AttrTransform { class HTMLPurifier_AttrTransform_BgColor extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) { /**
* @param array $attr
if (!isset($attr['bgcolor'])) return $attr; * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['bgcolor'])) {
return $attr;
}
$bgcolor = $this->confiscateAttr($attr, 'bgcolor'); $bgcolor = $this->confiscateAttr($attr, 'bgcolor');
// some validation should happen here // some validation should happen here
$this->prependCSS($attr, "background-color:$bgcolor;"); $this->prependCSS($attr, "background-color:$bgcolor;");
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -3,34 +3,45 @@
/** /**
* Pre-transform that changes converts a boolean attribute to fixed CSS * Pre-transform that changes converts a boolean attribute to fixed CSS
*/ */
class HTMLPurifier_AttrTransform_BoolToCSS extends HTMLPurifier_AttrTransform { class HTMLPurifier_AttrTransform_BoolToCSS extends HTMLPurifier_AttrTransform
{
/** /**
* Name of boolean attribute that is trigger * Name of boolean attribute that is trigger.
* @type string
*/ */
protected $attr; protected $attr;
/** /**
* CSS declarations to add to style, needs trailing semicolon * CSS declarations to add to style, needs trailing semicolon.
* @type string
*/ */
protected $css; protected $css;
/** /**
* @param $attr string attribute name to convert from * @param string $attr attribute name to convert from
* @param $css string CSS declarations to add to style (needs semicolon) * @param string $css CSS declarations to add to style (needs semicolon)
*/ */
public function __construct($attr, $css) { public function __construct($attr, $css)
{
$this->attr = $attr; $this->attr = $attr;
$this->css = $css; $this->css = $css;
} }
public function transform($attr, $config, $context) { /**
if (!isset($attr[$this->attr])) return $attr; * @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr[$this->attr])) {
return $attr;
}
unset($attr[$this->attr]); unset($attr[$this->attr]);
$this->prependCSS($attr, $this->css); $this->prependCSS($attr, $this->css);
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -3,16 +3,24 @@
/** /**
* Pre-transform that changes deprecated border attribute to CSS. * Pre-transform that changes deprecated border attribute to CSS.
*/ */
class HTMLPurifier_AttrTransform_Border extends HTMLPurifier_AttrTransform { class HTMLPurifier_AttrTransform_Border extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) { /**
if (!isset($attr['border'])) return $attr; * @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['border'])) {
return $attr;
}
$border_width = $this->confiscateAttr($attr, 'border'); $border_width = $this->confiscateAttr($attr, 'border');
// some validation should happen here // some validation should happen here
$this->prependCSS($attr, "border:{$border_width}px solid;"); $this->prependCSS($attr, "border:{$border_width}px solid;");
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -4,55 +4,65 @@
* Generic pre-transform that converts an attribute with a fixed number of * Generic pre-transform that converts an attribute with a fixed number of
* values (enumerated) to CSS. * values (enumerated) to CSS.
*/ */
class HTMLPurifier_AttrTransform_EnumToCSS extends HTMLPurifier_AttrTransform { class HTMLPurifier_AttrTransform_EnumToCSS extends HTMLPurifier_AttrTransform
{
/** /**
* Name of attribute to transform from * Name of attribute to transform from.
* @type string
*/ */
protected $attr; protected $attr;
/** /**
* Lookup array of attribute values to CSS * Lookup array of attribute values to CSS.
* @type array
*/ */
protected $enumToCSS = array(); protected $enumToCSS = array();
/** /**
* Case sensitivity of the matching * Case sensitivity of the matching.
* @type bool
* @warning Currently can only be guaranteed to work with ASCII * @warning Currently can only be guaranteed to work with ASCII
* values. * values.
*/ */
protected $caseSensitive = false; protected $caseSensitive = false;
/** /**
* @param $attr String attribute name to transform from * @param string $attr Attribute name to transform from
* @param $enumToCSS Lookup array of attribute values to CSS * @param array $enum_to_css Lookup array of attribute values to CSS
* @param $case_sensitive Boolean case sensitivity indicator, default false * @param bool $case_sensitive Case sensitivity indicator, default false
*/ */
public function __construct($attr, $enum_to_css, $case_sensitive = false) { public function __construct($attr, $enum_to_css, $case_sensitive = false)
{
$this->attr = $attr; $this->attr = $attr;
$this->enumToCSS = $enum_to_css; $this->enumToCSS = $enum_to_css;
$this->caseSensitive = (bool) $case_sensitive; $this->caseSensitive = (bool)$case_sensitive;
} }
public function transform($attr, $config, $context) { /**
* @param array $attr
if (!isset($attr[$this->attr])) return $attr; * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr[$this->attr])) {
return $attr;
}
$value = trim($attr[$this->attr]); $value = trim($attr[$this->attr]);
unset($attr[$this->attr]); unset($attr[$this->attr]);
if (!$this->caseSensitive) $value = strtolower($value); if (!$this->caseSensitive) {
$value = strtolower($value);
}
if (!isset($this->enumToCSS[$value])) { if (!isset($this->enumToCSS[$value])) {
return $attr; return $attr;
} }
$this->prependCSS($attr, $this->enumToCSS[$value]); $this->prependCSS($attr, $this->enumToCSS[$value]);
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -11,11 +11,19 @@
class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
{ {
public function transform($attr, $config, $context) { /**
* @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
$src = true; $src = true;
if (!isset($attr['src'])) { if (!isset($attr['src'])) {
if ($config->get('Core.RemoveInvalidImg')) return $attr; if ($config->get('Core.RemoveInvalidImg')) {
return $attr;
}
$attr['src'] = $config->get('Attr.DefaultInvalidImage'); $attr['src'] = $config->get('Attr.DefaultInvalidImage');
$src = false; $src = false;
} }
@@ -25,7 +33,7 @@ class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
$alt = $config->get('Attr.DefaultImageAlt'); $alt = $config->get('Attr.DefaultImageAlt');
if ($alt === null) { if ($alt === null) {
// truncate if the alt is too long // truncate if the alt is too long
$attr['alt'] = substr(basename($attr['src']),0,40); $attr['alt'] = substr(basename($attr['src']), 0, 40);
} else { } else {
$attr['alt'] = $alt; $attr['alt'] = $alt;
} }
@@ -33,11 +41,8 @@ class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
$attr['alt'] = $config->get('Attr.DefaultInvalidImageAlt'); $attr['alt'] = $config->get('Attr.DefaultInvalidImageAlt');
} }
} }
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -3,42 +3,59 @@
/** /**
* Pre-transform that changes deprecated hspace and vspace attributes to CSS * Pre-transform that changes deprecated hspace and vspace attributes to CSS
*/ */
class HTMLPurifier_AttrTransform_ImgSpace extends HTMLPurifier_AttrTransform { class HTMLPurifier_AttrTransform_ImgSpace extends HTMLPurifier_AttrTransform
{
/**
* @type string
*/
protected $attr; protected $attr;
/**
* @type array
*/
protected $css = array( protected $css = array(
'hspace' => array('left', 'right'), 'hspace' => array('left', 'right'),
'vspace' => array('top', 'bottom') 'vspace' => array('top', 'bottom')
); );
public function __construct($attr) { /**
* @param string $attr
*/
public function __construct($attr)
{
$this->attr = $attr; $this->attr = $attr;
if (!isset($this->css[$attr])) { if (!isset($this->css[$attr])) {
trigger_error(htmlspecialchars($attr) . ' is not valid space attribute'); trigger_error(htmlspecialchars($attr) . ' is not valid space attribute');
} }
} }
public function transform($attr, $config, $context) { /**
* @param array $attr
if (!isset($attr[$this->attr])) return $attr; * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr[$this->attr])) {
return $attr;
}
$width = $this->confiscateAttr($attr, $this->attr); $width = $this->confiscateAttr($attr, $this->attr);
// some validation could happen here // some validation could happen here
if (!isset($this->css[$this->attr])) return $attr; if (!isset($this->css[$this->attr])) {
return $attr;
}
$style = ''; $style = '';
foreach ($this->css[$this->attr] as $suffix) { foreach ($this->css[$this->attr] as $suffix) {
$property = "margin-$suffix"; $property = "margin-$suffix";
$style .= "$property:{$width}px;"; $style .= "$property:{$width}px;";
} }
$this->prependCSS($attr, $style); $this->prependCSS($attr, $style);
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -4,17 +4,31 @@
* Performs miscellaneous cross attribute validation and filtering for * Performs miscellaneous cross attribute validation and filtering for
* input elements. This is meant to be a post-transform. * input elements. This is meant to be a post-transform.
*/ */
class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform { class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform
{
/**
* @type HTMLPurifier_AttrDef_HTML_Pixels
*/
protected $pixels; protected $pixels;
public function __construct() { public function __construct()
{
$this->pixels = new HTMLPurifier_AttrDef_HTML_Pixels(); $this->pixels = new HTMLPurifier_AttrDef_HTML_Pixels();
} }
public function transform($attr, $config, $context) { /**
if (!isset($attr['type'])) $t = 'text'; * @param array $attr
else $t = strtolower($attr['type']); * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['type'])) {
$t = 'text';
} else {
$t = strtolower($attr['type']);
}
if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') { if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') {
unset($attr['checked']); unset($attr['checked']);
} }
@@ -23,8 +37,11 @@ class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform {
} }
if (isset($attr['size']) && $t !== 'text' && $t !== 'password') { if (isset($attr['size']) && $t !== 'text' && $t !== 'password') {
$result = $this->pixels->validate($attr['size'], $config, $context); $result = $this->pixels->validate($attr['size'], $config, $context);
if ($result === false) unset($attr['size']); if ($result === false) {
else $attr['size'] = $result; unset($attr['size']);
} else {
$attr['size'] = $result;
}
} }
if (isset($attr['src']) && $t !== 'image') { if (isset($attr['src']) && $t !== 'image') {
unset($attr['src']); unset($attr['src']);
@@ -34,7 +51,6 @@ class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform {
} }
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -8,9 +8,15 @@
class HTMLPurifier_AttrTransform_Lang extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_Lang extends HTMLPurifier_AttrTransform
{ {
public function transform($attr, $config, $context) { /**
* @param array $attr
$lang = isset($attr['lang']) ? $attr['lang'] : false; * @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
$lang = isset($attr['lang']) ? $attr['lang'] : false;
$xml_lang = isset($attr['xml:lang']) ? $attr['xml:lang'] : false; $xml_lang = isset($attr['xml:lang']) ? $attr['xml:lang'] : false;
if ($lang !== false && $xml_lang === false) { if ($lang !== false && $xml_lang === false) {
@@ -18,11 +24,8 @@ class HTMLPurifier_AttrTransform_Lang extends HTMLPurifier_AttrTransform
} elseif ($xml_lang !== false) { } elseif ($xml_lang !== false) {
$attr['lang'] = $xml_lang; $attr['lang'] = $xml_lang;
} }
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,22 +6,40 @@
class HTMLPurifier_AttrTransform_Length extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_Length extends HTMLPurifier_AttrTransform
{ {
/**
* @type string
*/
protected $name; protected $name;
/**
* @type string
*/
protected $cssName; protected $cssName;
public function __construct($name, $css_name = null) { public function __construct($name, $css_name = null)
{
$this->name = $name; $this->name = $name;
$this->cssName = $css_name ? $css_name : $name; $this->cssName = $css_name ? $css_name : $name;
} }
public function transform($attr, $config, $context) { /**
if (!isset($attr[$this->name])) return $attr; * @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr[$this->name])) {
return $attr;
}
$length = $this->confiscateAttr($attr, $this->name); $length = $this->confiscateAttr($attr, $this->name);
if(ctype_digit($length)) $length .= 'px'; if (ctype_digit($length)) {
$length .= 'px';
}
$this->prependCSS($attr, $this->cssName . ":$length;"); $this->prependCSS($attr, $this->cssName . ":$length;");
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,16 +6,28 @@
class HTMLPurifier_AttrTransform_Name extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_Name extends HTMLPurifier_AttrTransform
{ {
public function transform($attr, $config, $context) { /**
* @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
// Abort early if we're using relaxed definition of name // Abort early if we're using relaxed definition of name
if ($config->get('HTML.Attr.Name.UseCDATA')) return $attr; if ($config->get('HTML.Attr.Name.UseCDATA')) {
if (!isset($attr['name'])) return $attr; return $attr;
}
if (!isset($attr['name'])) {
return $attr;
}
$id = $this->confiscateAttr($attr, 'name'); $id = $this->confiscateAttr($attr, 'name');
if ( isset($attr['id'])) return $attr; if (isset($attr['id'])) {
return $attr;
}
$attr['id'] = $id; $attr['id'] = $id;
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -8,20 +8,34 @@
class HTMLPurifier_AttrTransform_NameSync extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_NameSync extends HTMLPurifier_AttrTransform
{ {
public function __construct() { public function __construct()
{
$this->idDef = new HTMLPurifier_AttrDef_HTML_ID(); $this->idDef = new HTMLPurifier_AttrDef_HTML_ID();
} }
public function transform($attr, $config, $context) { /**
if (!isset($attr['name'])) return $attr; * @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['name'])) {
return $attr;
}
$name = $attr['name']; $name = $attr['name'];
if (isset($attr['id']) && $attr['id'] === $name) return $attr; if (isset($attr['id']) && $attr['id'] === $name) {
return $attr;
}
$result = $this->idDef->validate($name, $config, $context); $result = $this->idDef->validate($name, $config, $context);
if ($result === false) unset($attr['name']); if ($result === false) {
else $attr['name'] = $result; unset($attr['name']);
} else {
$attr['name'] = $result;
}
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -8,14 +8,24 @@
*/ */
class HTMLPurifier_AttrTransform_Nofollow extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_Nofollow extends HTMLPurifier_AttrTransform
{ {
/**
* @type HTMLPurifier_URIParser
*/
private $parser; private $parser;
public function __construct() { public function __construct()
{
$this->parser = new HTMLPurifier_URIParser(); $this->parser = new HTMLPurifier_URIParser();
} }
public function transform($attr, $config, $context) { /**
* @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['href'])) { if (!isset($attr['href'])) {
return $attr; return $attr;
} }
@@ -35,11 +45,8 @@ class HTMLPurifier_AttrTransform_Nofollow extends HTMLPurifier_AttrTransform
$attr['rel'] = 'nofollow'; $attr['rel'] = 'nofollow';
} }
} }
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -2,9 +2,19 @@
class HTMLPurifier_AttrTransform_SafeEmbed extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_SafeEmbed extends HTMLPurifier_AttrTransform
{ {
/**
* @type string
*/
public $name = "SafeEmbed"; public $name = "SafeEmbed";
public function transform($attr, $config, $context) { /**
* @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
$attr['allowscriptaccess'] = 'never'; $attr['allowscriptaccess'] = 'never';
$attr['allownetworking'] = 'internal'; $attr['allownetworking'] = 'internal';
$attr['type'] = 'application/x-shockwave-flash'; $attr['type'] = 'application/x-shockwave-flash';

View File

@@ -5,10 +5,22 @@
*/ */
class HTMLPurifier_AttrTransform_SafeObject extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_SafeObject extends HTMLPurifier_AttrTransform
{ {
/**
* @type string
*/
public $name = "SafeObject"; public $name = "SafeObject";
function transform($attr, $config, $context) { /**
if (!isset($attr['type'])) $attr['type'] = 'application/x-shockwave-flash'; * @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['type'])) {
$attr['type'] = 'application/x-shockwave-flash';
}
return $attr; return $attr;
} }
} }

View File

@@ -14,15 +14,30 @@
*/ */
class HTMLPurifier_AttrTransform_SafeParam extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_SafeParam extends HTMLPurifier_AttrTransform
{ {
/**
* @type string
*/
public $name = "SafeParam"; public $name = "SafeParam";
/**
* @type HTMLPurifier_AttrDef_URI
*/
private $uri; private $uri;
public function __construct() { public function __construct()
{
$this->uri = new HTMLPurifier_AttrDef_URI(true); // embedded $this->uri = new HTMLPurifier_AttrDef_URI(true); // embedded
$this->wmode = new HTMLPurifier_AttrDef_Enum(array('window', 'opaque', 'transparent')); $this->wmode = new HTMLPurifier_AttrDef_Enum(array('window', 'opaque', 'transparent'));
} }
public function transform($attr, $config, $context) { /**
* @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
// If we add support for other objects, we'll need to alter the // If we add support for other objects, we'll need to alter the
// transforms. // transforms.
switch ($attr['name']) { switch ($attr['name']) {

View File

@@ -5,7 +5,14 @@
*/ */
class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform
{ {
public function transform($attr, $config, $context) { /**
* @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['type'])) { if (!isset($attr['type'])) {
$attr['type'] = 'text/javascript'; $attr['type'] = 'text/javascript';
} }

View File

@@ -9,14 +9,24 @@
*/ */
class HTMLPurifier_AttrTransform_TargetBlank extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_TargetBlank extends HTMLPurifier_AttrTransform
{ {
/**
* @type HTMLPurifier_URIParser
*/
private $parser; private $parser;
public function __construct() { public function __construct()
{
$this->parser = new HTMLPurifier_URIParser(); $this->parser = new HTMLPurifier_URIParser();
} }
public function transform($attr, $config, $context) { /**
* @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['href'])) { if (!isset($attr['href'])) {
return $attr; return $attr;
} }
@@ -28,11 +38,8 @@ class HTMLPurifier_AttrTransform_TargetBlank extends HTMLPurifier_AttrTransform
if ($scheme->browsable && !$url->isBenign($config, $context)) { if ($scheme->browsable && !$url->isBenign($config, $context)) {
$attr['target'] = '_blank'; $attr['target'] = '_blank';
} }
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -5,14 +5,23 @@
*/ */
class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform
{ {
/**
public function transform($attr, $config, $context) { * @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
// Calculated from Firefox // Calculated from Firefox
if (!isset($attr['cols'])) $attr['cols'] = '22'; if (!isset($attr['cols'])) {
if (!isset($attr['rows'])) $attr['rows'] = '3'; $attr['cols'] = '22';
}
if (!isset($attr['rows'])) {
$attr['rows'] = '3';
}
return $attr; return $attr;
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -6,7 +6,8 @@
class HTMLPurifier_AttrTypes class HTMLPurifier_AttrTypes
{ {
/** /**
* Lookup array of attribute string identifiers to concrete implementations * Lookup array of attribute string identifiers to concrete implementations.
* @type HTMLPurifier_AttrDef[]
*/ */
protected $info = array(); protected $info = array();
@@ -14,7 +15,8 @@ class HTMLPurifier_AttrTypes
* Constructs the info array, supplying default implementations for attribute * Constructs the info array, supplying default implementations for attribute
* types. * types.
*/ */
public function __construct() { public function __construct()
{
// XXX This is kind of poor, since we don't actually /clone/ // XXX This is kind of poor, since we don't actually /clone/
// instances; instead, we use the supplied make() attribute. So, // instances; instead, we use the supplied make() attribute. So,
// the underlying class must know how to deal with arguments. // the underlying class must know how to deal with arguments.
@@ -54,36 +56,39 @@ class HTMLPurifier_AttrTypes
$this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
} }
private static function makeEnum($in) { private static function makeEnum($in)
{
return new HTMLPurifier_AttrDef_Clone(new HTMLPurifier_AttrDef_Enum(explode(',', $in))); return new HTMLPurifier_AttrDef_Clone(new HTMLPurifier_AttrDef_Enum(explode(',', $in)));
} }
/** /**
* Retrieves a type * Retrieves a type
* @param $type String type name * @param string $type String type name
* @return Object AttrDef for type * @return HTMLPurifier_AttrDef Object AttrDef for type
*/ */
public function get($type) { public function get($type)
{
// determine if there is any extra info tacked on // determine if there is any extra info tacked on
if (strpos($type, '#') !== false) list($type, $string) = explode('#', $type, 2); if (strpos($type, '#') !== false) {
else $string = ''; list($type, $string) = explode('#', $type, 2);
} else {
$string = '';
}
if (!isset($this->info[$type])) { if (!isset($this->info[$type])) {
trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR); trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR);
return; return;
} }
return $this->info[$type]->make($string); return $this->info[$type]->make($string);
} }
/** /**
* Sets a new implementation for a type * Sets a new implementation for a type
* @param $type String type name * @param string $type String type name
* @param $impl Object AttrDef for type * @param HTMLPurifier_AttrDef $impl Object AttrDef for type
*/ */
public function set($type, $impl) { public function set($type, $impl)
{
$this->info[$type] = $impl; $this->info[$type] = $impl;
} }
} }

View File

@@ -9,17 +9,14 @@ class HTMLPurifier_AttrValidator
{ {
/** /**
* Validates the attributes of a token, returning a modified token * Validates the attributes of a token, mutating it as necessary.
* that has valid tokens * that has valid tokens
* @param $token Reference to token to validate. We require a reference * @param HTMLPurifier_Token $token Token to validate.
* because the operation this class performs on the token are * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config
* not atomic, so the context CurrentToken to be updated * @param HTMLPurifier_Context $context Instance of HTMLPurifier_Context
* throughout
* @param $config Instance of HTMLPurifier_Config
* @param $context Instance of HTMLPurifier_Context
*/ */
public function validateToken(&$token, &$config, $context) { public function validateToken($token, $config, $context)
{
$definition = $config->getHTMLDefinition(); $definition = $config->getHTMLDefinition();
$e =& $context->get('ErrorCollector', true); $e =& $context->get('ErrorCollector', true);
@@ -32,12 +29,15 @@ class HTMLPurifier_AttrValidator
// initialize CurrentToken if necessary // initialize CurrentToken if necessary
$current_token =& $context->get('CurrentToken', true); $current_token =& $context->get('CurrentToken', true);
if (!$current_token) $context->register('CurrentToken', $token); if (!$current_token) {
$context->register('CurrentToken', $token);
}
if ( if (!$token instanceof HTMLPurifier_Token_Start &&
!$token instanceof HTMLPurifier_Token_Start &&
!$token instanceof HTMLPurifier_Token_Empty !$token instanceof HTMLPurifier_Token_Empty
) return $token; ) {
return;
}
// create alias to global definition array, see also $defs // create alias to global definition array, see also $defs
// DEFINITION CALL // DEFINITION CALL
@@ -51,7 +51,9 @@ class HTMLPurifier_AttrValidator
foreach ($definition->info_attr_transform_pre as $transform) { foreach ($definition->info_attr_transform_pre as $transform) {
$attr = $transform->transform($o = $attr, $config, $context); $attr = $transform->transform($o = $attr, $config, $context);
if ($e) { if ($e) {
if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); if ($attr != $o) {
$e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
}
} }
} }
@@ -60,7 +62,9 @@ class HTMLPurifier_AttrValidator
foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { foreach ($definition->info[$token->name]->attr_transform_pre as $transform) {
$attr = $transform->transform($o = $attr, $config, $context); $attr = $transform->transform($o = $attr, $config, $context);
if ($e) { if ($e) {
if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); if ($attr != $o) {
$e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
}
} }
} }
@@ -77,7 +81,7 @@ class HTMLPurifier_AttrValidator
foreach ($attr as $attr_key => $value) { foreach ($attr as $attr_key => $value) {
// call the definition // call the definition
if ( isset($defs[$attr_key]) ) { if (isset($defs[$attr_key])) {
// there is a local definition defined // there is a local definition defined
if ($defs[$attr_key] === false) { if ($defs[$attr_key] === false) {
// We've explicitly been told not to allow this element. // We've explicitly been told not to allow this element.
@@ -89,15 +93,19 @@ class HTMLPurifier_AttrValidator
} else { } else {
// validate according to the element's definition // validate according to the element's definition
$result = $defs[$attr_key]->validate( $result = $defs[$attr_key]->validate(
$value, $config, $context $value,
); $config,
$context
);
} }
} elseif ( isset($d_defs[$attr_key]) ) { } elseif (isset($d_defs[$attr_key])) {
// there is a global definition defined, validate according // there is a global definition defined, validate according
// to the global definition // to the global definition
$result = $d_defs[$attr_key]->validate( $result = $d_defs[$attr_key]->validate(
$value, $config, $context $value,
); $config,
$context
);
} else { } else {
// system never heard of the attribute? DELETE! // system never heard of the attribute? DELETE!
$result = false; $result = false;
@@ -107,7 +115,9 @@ class HTMLPurifier_AttrValidator
if ($result === false || $result === null) { if ($result === false || $result === null) {
// this is a generic error message that should replaced // this is a generic error message that should replaced
// with more specific ones when possible // with more specific ones when possible
if ($e) $e->send(E_ERROR, 'AttrValidator: Attribute removed'); if ($e) {
$e->send(E_ERROR, 'AttrValidator: Attribute removed');
}
// remove the attribute // remove the attribute
unset($attr[$attr_key]); unset($attr[$attr_key]);
@@ -137,7 +147,9 @@ class HTMLPurifier_AttrValidator
foreach ($definition->info_attr_transform_post as $transform) { foreach ($definition->info_attr_transform_post as $transform) {
$attr = $transform->transform($o = $attr, $config, $context); $attr = $transform->transform($o = $attr, $config, $context);
if ($e) { if ($e) {
if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); if ($attr != $o) {
$e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
}
} }
} }
@@ -145,14 +157,18 @@ class HTMLPurifier_AttrValidator
foreach ($definition->info[$token->name]->attr_transform_post as $transform) { foreach ($definition->info[$token->name]->attr_transform_post as $transform) {
$attr = $transform->transform($o = $attr, $config, $context); $attr = $transform->transform($o = $attr, $config, $context);
if ($e) { if ($e) {
if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); if ($attr != $o) {
$e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
}
} }
} }
$token->attr = $attr; $token->attr = $attr;
// destroy CurrentToken if we made it ourselves // destroy CurrentToken if we made it ourselves
if (!$current_token) $context->destroy('CurrentToken'); if (!$current_token) {
$context->destroy('CurrentToken');
}
} }

View File

@@ -32,11 +32,15 @@ class HTMLPurifier_Bootstrap
/** /**
* Autoload function for HTML Purifier * Autoload function for HTML Purifier
* @param $class Class to load * @param string $class Class to load
* @return bool
*/ */
public static function autoload($class) { public static function autoload($class)
{
$file = HTMLPurifier_Bootstrap::getPath($class); $file = HTMLPurifier_Bootstrap::getPath($class);
if (!$file) return false; if (!$file) {
return false;
}
// Technically speaking, it should be ok and more efficient to // Technically speaking, it should be ok and more efficient to
// just do 'require', but Antonio Parraga reports that with // just do 'require', but Antonio Parraga reports that with
// Zend extensions such as Zend debugger and APC, this invariant // Zend extensions such as Zend debugger and APC, this invariant
@@ -48,9 +52,14 @@ class HTMLPurifier_Bootstrap
/** /**
* Returns the path for a specific class. * Returns the path for a specific class.
* @param string $class Class path to get
* @return string
*/ */
public static function getPath($class) { public static function getPath($class)
if (strncmp('HTMLPurifier', $class, 12) !== 0) return false; {
if (strncmp('HTMLPurifier', $class, 12) !== 0) {
return false;
}
// Custom implementations // Custom implementations
if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) { if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) {
$code = str_replace('_', '-', substr($class, 22)); $code = str_replace('_', '-', substr($class, 22));
@@ -58,16 +67,19 @@ class HTMLPurifier_Bootstrap
} else { } else {
$file = str_replace('_', '/', $class) . '.php'; $file = str_replace('_', '/', $class) . '.php';
} }
if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) return false; if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) {
return false;
}
return $file; return $file;
} }
/** /**
* "Pre-registers" our autoloader on the SPL stack. * "Pre-registers" our autoloader on the SPL stack.
*/ */
public static function registerAutoload() { public static function registerAutoload()
{
$autoload = array('HTMLPurifier_Bootstrap', 'autoload'); $autoload = array('HTMLPurifier_Bootstrap', 'autoload');
if ( ($funcs = spl_autoload_functions()) === false ) { if (($funcs = spl_autoload_functions()) === false) {
spl_autoload_register($autoload); spl_autoload_register($autoload);
} elseif (function_exists('spl_autoload_unregister')) { } elseif (function_exists('spl_autoload_unregister')) {
if (version_compare(PHP_VERSION, '5.3.0', '>=')) { if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
@@ -83,27 +95,30 @@ class HTMLPurifier_Bootstrap
// places where we need to error out // places where we need to error out
$reflector = new ReflectionMethod($func[0], $func[1]); $reflector = new ReflectionMethod($func[0], $func[1]);
if (!$reflector->isStatic()) { if (!$reflector->isStatic()) {
throw new Exception(' throw new Exception(
HTML Purifier autoloader registrar is not compatible 'HTML Purifier autoloader registrar is not compatible
with non-static object methods due to PHP Bug #44144; with non-static object methods due to PHP Bug #44144;
Please do not use HTMLPurifier.autoload.php (or any Please do not use HTMLPurifier.autoload.php (or any
file that includes this file); instead, place the code: file that includes this file); instead, place the code:
spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\')) spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\'))
after your own autoloaders. after your own autoloaders.'
'); );
} }
// Suprisingly, spl_autoload_register supports the // Suprisingly, spl_autoload_register supports the
// Class::staticMethod callback format, although call_user_func doesn't // Class::staticMethod callback format, although call_user_func doesn't
if ($compat) $func = implode('::', $func); if ($compat) {
$func = implode('::', $func);
}
} }
spl_autoload_unregister($func); spl_autoload_unregister($func);
} }
spl_autoload_register($autoload); spl_autoload_register($autoload);
foreach ($funcs as $func) spl_autoload_register($func); foreach ($funcs as $func) {
spl_autoload_register($func);
}
} }
} }
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -11,35 +11,59 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
/** /**
* Assoc array of attribute name to definition object. * Assoc array of attribute name to definition object.
* @type HTMLPurifier_AttrDef[]
*/ */
public $info = array(); public $info = array();
/** /**
* Constructs the info array. The meat of this class. * Constructs the info array. The meat of this class.
* @param HTMLPurifier_Config $config
*/ */
protected function doSetup($config) { protected function doSetup($config)
{
$this->info['text-align'] = new HTMLPurifier_AttrDef_Enum( $this->info['text-align'] = new HTMLPurifier_AttrDef_Enum(
array('left', 'right', 'center', 'justify'), false); array('left', 'right', 'center', 'justify'),
false
);
$border_style = $border_style =
$this->info['border-bottom-style'] = $this->info['border-bottom-style'] =
$this->info['border-right-style'] = $this->info['border-right-style'] =
$this->info['border-left-style'] = $this->info['border-left-style'] =
$this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum( $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum(
array('none', 'hidden', 'dotted', 'dashed', 'solid', 'double', array(
'groove', 'ridge', 'inset', 'outset'), false); 'none',
'hidden',
'dotted',
'dashed',
'solid',
'double',
'groove',
'ridge',
'inset',
'outset'
),
false
);
$this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style); $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style);
$this->info['clear'] = new HTMLPurifier_AttrDef_Enum( $this->info['clear'] = new HTMLPurifier_AttrDef_Enum(
array('none', 'left', 'right', 'both'), false); array('none', 'left', 'right', 'both'),
false
);
$this->info['float'] = new HTMLPurifier_AttrDef_Enum( $this->info['float'] = new HTMLPurifier_AttrDef_Enum(
array('none', 'left', 'right'), false); array('none', 'left', 'right'),
false
);
$this->info['font-style'] = new HTMLPurifier_AttrDef_Enum( $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum(
array('normal', 'italic', 'oblique'), false); array('normal', 'italic', 'oblique'),
false
);
$this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum( $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum(
array('normal', 'small-caps'), false); array('normal', 'small-caps'),
false
);
$uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite( $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite(
array( array(
@@ -49,16 +73,31 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
); );
$this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum( $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum(
array('inside', 'outside'), false); array('inside', 'outside'),
false
);
$this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum( $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum(
array('disc', 'circle', 'square', 'decimal', 'lower-roman', array(
'upper-roman', 'lower-alpha', 'upper-alpha', 'none'), false); 'disc',
'circle',
'square',
'decimal',
'lower-roman',
'upper-roman',
'lower-alpha',
'upper-alpha',
'none'
),
false
);
$this->info['list-style-image'] = $uri_or_none; $this->info['list-style-image'] = $uri_or_none;
$this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config); $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config);
$this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum(
array('capitalize', 'uppercase', 'lowercase', 'none'), false); array('capitalize', 'uppercase', 'lowercase', 'none'),
false
);
$this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color(); $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['background-image'] = $uri_or_none; $this->info['background-image'] = $uri_or_none;
@@ -71,104 +110,137 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition();
$border_color = $border_color =
$this->info['border-top-color'] = $this->info['border-top-color'] =
$this->info['border-bottom-color'] = $this->info['border-bottom-color'] =
$this->info['border-left-color'] = $this->info['border-left-color'] =
$this->info['border-right-color'] = $this->info['border-right-color'] =
$this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_Enum(array('transparent')), array(
new HTMLPurifier_AttrDef_CSS_Color() new HTMLPurifier_AttrDef_Enum(array('transparent')),
)); new HTMLPurifier_AttrDef_CSS_Color()
)
);
$this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config); $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config);
$this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color); $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color);
$border_width = $border_width =
$this->info['border-top-width'] = $this->info['border-top-width'] =
$this->info['border-bottom-width'] = $this->info['border-bottom-width'] =
$this->info['border-left-width'] = $this->info['border-left-width'] =
$this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')), array(
new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')),
)); new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative
)
);
$this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width); $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width);
$this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_Enum(array('normal')), array(
new HTMLPurifier_AttrDef_CSS_Length() new HTMLPurifier_AttrDef_Enum(array('normal')),
)); new HTMLPurifier_AttrDef_CSS_Length()
)
);
$this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_Enum(array('normal')), array(
new HTMLPurifier_AttrDef_CSS_Length() new HTMLPurifier_AttrDef_Enum(array('normal')),
)); new HTMLPurifier_AttrDef_CSS_Length()
)
);
$this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_Enum(array('xx-small', 'x-small', array(
'small', 'medium', 'large', 'x-large', 'xx-large', new HTMLPurifier_AttrDef_Enum(
'larger', 'smaller')), array(
new HTMLPurifier_AttrDef_CSS_Percentage(), 'xx-small',
new HTMLPurifier_AttrDef_CSS_Length() 'x-small',
)); 'small',
'medium',
'large',
'x-large',
'xx-large',
'larger',
'smaller'
)
),
new HTMLPurifier_AttrDef_CSS_Percentage(),
new HTMLPurifier_AttrDef_CSS_Length()
)
);
$this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_Enum(array('normal')), array(
new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives new HTMLPurifier_AttrDef_Enum(array('normal')),
new HTMLPurifier_AttrDef_CSS_Length('0'), new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives
new HTMLPurifier_AttrDef_CSS_Percentage(true) new HTMLPurifier_AttrDef_CSS_Length('0'),
)); new HTMLPurifier_AttrDef_CSS_Percentage(true)
)
);
$margin = $margin =
$this->info['margin-top'] = $this->info['margin-top'] =
$this->info['margin-bottom'] = $this->info['margin-bottom'] =
$this->info['margin-left'] = $this->info['margin-left'] =
$this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_CSS_Length(), array(
new HTMLPurifier_AttrDef_CSS_Percentage(), new HTMLPurifier_AttrDef_CSS_Length(),
new HTMLPurifier_AttrDef_Enum(array('auto')) new HTMLPurifier_AttrDef_CSS_Percentage(),
)); new HTMLPurifier_AttrDef_Enum(array('auto'))
)
);
$this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin); $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin);
// non-negative // non-negative
$padding = $padding =
$this->info['padding-top'] = $this->info['padding-top'] =
$this->info['padding-bottom'] = $this->info['padding-bottom'] =
$this->info['padding-left'] = $this->info['padding-left'] =
$this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_CSS_Length('0'), array(
new HTMLPurifier_AttrDef_CSS_Percentage(true) new HTMLPurifier_AttrDef_CSS_Length('0'),
)); new HTMLPurifier_AttrDef_CSS_Percentage(true)
)
);
$this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding); $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding);
$this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_CSS_Length(), array(
new HTMLPurifier_AttrDef_CSS_Percentage() new HTMLPurifier_AttrDef_CSS_Length(),
)); new HTMLPurifier_AttrDef_CSS_Percentage()
)
);
$trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(array( $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_CSS_Length('0'), array(
new HTMLPurifier_AttrDef_CSS_Percentage(true), new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_Enum(array('auto')) new HTMLPurifier_AttrDef_CSS_Percentage(true),
)); new HTMLPurifier_AttrDef_Enum(array('auto'))
)
);
$max = $config->get('CSS.MaxImgLength'); $max = $config->get('CSS.MaxImgLength');
$this->info['width'] = $this->info['width'] =
$this->info['height'] = $this->info['height'] =
$max === null ? $max === null ?
$trusted_wh : $trusted_wh :
new HTMLPurifier_AttrDef_Switch('img', new HTMLPurifier_AttrDef_Switch(
// For img tags: 'img',
new HTMLPurifier_AttrDef_CSS_Composite(array( // For img tags:
new HTMLPurifier_AttrDef_CSS_Length('0', $max), new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_Enum(array('auto')) array(
)), new HTMLPurifier_AttrDef_CSS_Length('0', $max),
// For everyone else: new HTMLPurifier_AttrDef_Enum(array('auto'))
$trusted_wh )
); ),
// For everyone else:
$trusted_wh
);
$this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();
@@ -176,8 +248,23 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
// this could use specialized code // this could use specialized code
$this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum( $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum(
array('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', array(
'400', '500', '600', '700', '800', '900'), false); 'normal',
'bold',
'bolder',
'lighter',
'100',
'200',
'300',
'400',
'500',
'600',
'700',
'800',
'900'
),
false
);
// MUST be called after other font properties, as it references // MUST be called after other font properties, as it references
// a CSSDefinition object // a CSSDefinition object
@@ -190,27 +277,44 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['border-left'] = $this->info['border-left'] =
$this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config); $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config);
$this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(array( $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(
'collapse', 'separate')); array('collapse', 'separate')
);
$this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(array( $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(
'top', 'bottom')); array('top', 'bottom')
);
$this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(array( $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(
'auto', 'fixed')); array('auto', 'fixed')
);
$this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_Enum(array('baseline', 'sub', 'super', array(
'top', 'text-top', 'middle', 'bottom', 'text-bottom')), new HTMLPurifier_AttrDef_Enum(
new HTMLPurifier_AttrDef_CSS_Length(), array(
new HTMLPurifier_AttrDef_CSS_Percentage() 'baseline',
)); 'sub',
'super',
'top',
'text-top',
'middle',
'bottom',
'text-bottom'
)
),
new HTMLPurifier_AttrDef_CSS_Length(),
new HTMLPurifier_AttrDef_CSS_Percentage()
)
);
$this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2); $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2);
// These CSS properties don't work on many browsers, but we live // These CSS properties don't work on many browsers, but we live
// in THE FUTURE! // in THE FUTURE!
$this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line')); $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(
array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line')
);
if ($config->get('CSS.Proprietary')) { if ($config->get('CSS.Proprietary')) {
$this->doSetupProprietary($config); $this->doSetupProprietary($config);
@@ -233,76 +337,119 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->setupConfigStuff($config); $this->setupConfigStuff($config);
} }
protected function doSetupProprietary($config) { /**
* @param HTMLPurifier_Config $config
*/
protected function doSetupProprietary($config)
{
// Internet Explorer only scrollbar colors // Internet Explorer only scrollbar colors
$this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color(); $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color(); $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color(); $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
// technically not proprietary, but CSS3, and no one supports it // technically not proprietary, but CSS3, and no one supports it
$this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
$this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
$this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
// only opacity, for now // only opacity, for now
$this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter(); $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter();
// more CSS3 // more CSS3
$this->info['page-break-after'] = $this->info['page-break-after'] =
$this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum(array('auto','always','avoid','left','right')); $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum(
$this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto','avoid')); array(
'auto',
'always',
'avoid',
'left',
'right'
)
);
$this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid'));
} }
protected function doSetupTricky($config) { /**
$this->info['display'] = new HTMLPurifier_AttrDef_Enum(array( * @param HTMLPurifier_Config $config
'inline', 'block', 'list-item', 'run-in', 'compact', */
'marker', 'table', 'inline-block', 'inline-table', 'table-row-group', protected function doSetupTricky($config)
'table-header-group', 'table-footer-group', 'table-row', {
'table-column-group', 'table-column', 'table-cell', 'table-caption', 'none' $this->info['display'] = new HTMLPurifier_AttrDef_Enum(
)); array(
$this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(array( 'inline',
'visible', 'hidden', 'collapse' 'block',
)); 'list-item',
'run-in',
'compact',
'marker',
'table',
'inline-block',
'inline-table',
'table-row-group',
'table-header-group',
'table-footer-group',
'table-row',
'table-column-group',
'table-column',
'table-cell',
'table-caption',
'none'
)
);
$this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(
array('visible', 'hidden', 'collapse')
);
$this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll')); $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll'));
} }
protected function doSetupTrusted($config) { /**
$this->info['position'] = new HTMLPurifier_AttrDef_Enum(array( * @param HTMLPurifier_Config $config
'static', 'relative', 'absolute', 'fixed' */
)); protected function doSetupTrusted($config)
{
$this->info['position'] = new HTMLPurifier_AttrDef_Enum(
array('static', 'relative', 'absolute', 'fixed')
);
$this->info['top'] = $this->info['top'] =
$this->info['left'] = $this->info['left'] =
$this->info['right'] = $this->info['right'] =
$this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite(array( $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite(
new HTMLPurifier_AttrDef_CSS_Length(), array(
new HTMLPurifier_AttrDef_CSS_Percentage(), new HTMLPurifier_AttrDef_CSS_Length(),
new HTMLPurifier_AttrDef_Enum(array('auto')), new HTMLPurifier_AttrDef_CSS_Percentage(),
)); new HTMLPurifier_AttrDef_Enum(array('auto')),
$this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite(array( )
new HTMLPurifier_AttrDef_Integer(), );
new HTMLPurifier_AttrDef_Enum(array('auto')), $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite(
)); array(
new HTMLPurifier_AttrDef_Integer(),
new HTMLPurifier_AttrDef_Enum(array('auto')),
)
);
} }
/** /**
* Performs extra config-based processing. Based off of * Performs extra config-based processing. Based off of
* HTMLPurifier_HTMLDefinition. * HTMLPurifier_HTMLDefinition.
* @param HTMLPurifier_Config $config
* @todo Refactor duplicate elements into common class (probably using * @todo Refactor duplicate elements into common class (probably using
* composition, not inheritance). * composition, not inheritance).
*/ */
protected function setupConfigStuff($config) { protected function setupConfigStuff($config)
{
// setup allowed elements // setup allowed elements
$support = "(for information on implementing this, see the ". $support = "(for information on implementing this, see the " .
"support forums) "; "support forums) ";
$allowed_properties = $config->get('CSS.AllowedProperties'); $allowed_properties = $config->get('CSS.AllowedProperties');
if ($allowed_properties !== null) { if ($allowed_properties !== null) {
foreach ($this->info as $name => $d) { foreach ($this->info as $name => $d) {
if(!isset($allowed_properties[$name])) unset($this->info[$name]); if (!isset($allowed_properties[$name])) {
unset($this->info[$name]);
}
unset($allowed_properties[$name]); unset($allowed_properties[$name]);
} }
// emit errors // emit errors
@@ -321,7 +468,6 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
} }
} }
} }
} }
} }

View File

@@ -1,48 +1,52 @@
<?php <?php
/** /**
* Defines allowed child nodes and validates tokens against it. * Defines allowed child nodes and validates nodes against it.
*/ */
abstract class HTMLPurifier_ChildDef abstract class HTMLPurifier_ChildDef
{ {
/** /**
* Type of child definition, usually right-most part of class name lowercase. * Type of child definition, usually right-most part of class name lowercase.
* Used occasionally in terms of context. * Used occasionally in terms of context.
* @type string
*/ */
public $type; public $type;
/** /**
* Bool that indicates whether or not an empty array of children is okay * Indicates whether or not an empty array of children is okay.
* *
* This is necessary for redundant checking when changes affecting * This is necessary for redundant checking when changes affecting
* a child node may cause a parent node to now be disallowed. * a child node may cause a parent node to now be disallowed.
* @type bool
*/ */
public $allow_empty; public $allow_empty;
/** /**
* Lookup array of all elements that this definition could possibly allow * Lookup array of all elements that this definition could possibly allow.
* @type array
*/ */
public $elements = array(); public $elements = array();
/** /**
* Get lookup of tag names that should not close this element automatically. * Get lookup of tag names that should not close this element automatically.
* All other elements will do so. * All other elements will do so.
* @param HTMLPurifier_Config $config HTMLPurifier_Config object
* @return array
*/ */
public function getAllowedElements($config) { public function getAllowedElements($config)
{
return $this->elements; return $this->elements;
} }
/** /**
* Validates nodes according to definition and returns modification. * Validates nodes according to definition and returns modification.
* *
* @param $tokens_of_children Array of HTMLPurifier_Token * @param HTMLPurifier_Node[] $children Array of HTMLPurifier_Node
* @param $config HTMLPurifier_Config object * @param HTMLPurifier_Config $config HTMLPurifier_Config object
* @param $context HTMLPurifier_Context object * @param HTMLPurifier_Context $context HTMLPurifier_Context object
* @return bool true to leave nodes as is * @return bool|array true to leave nodes as is, false to remove parent node, array of replacement children
* @return bool false to remove parent node
* @return array of replacement child tokens
*/ */
abstract public function validateChildren($tokens_of_children, $config, $context); abstract public function validateChildren($children, $config, $context);
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

View File

@@ -14,33 +14,52 @@ class HTMLPurifier_ChildDef_Chameleon extends HTMLPurifier_ChildDef
/** /**
* Instance of the definition object to use when inline. Usually stricter. * Instance of the definition object to use when inline. Usually stricter.
* @type HTMLPurifier_ChildDef_Optional
*/ */
public $inline; public $inline;
/** /**
* Instance of the definition object to use when block. * Instance of the definition object to use when block.
* @type HTMLPurifier_ChildDef_Optional
*/ */
public $block; public $block;
/**
* @type string
*/
public $type = 'chameleon'; public $type = 'chameleon';
/** /**
* @param $inline List of elements to allow when inline. * @param array $inline List of elements to allow when inline.
* @param $block List of elements to allow when block. * @param array $block List of elements to allow when block.
*/ */
public function __construct($inline, $block) { public function __construct($inline, $block)
{
$this->inline = new HTMLPurifier_ChildDef_Optional($inline); $this->inline = new HTMLPurifier_ChildDef_Optional($inline);
$this->block = new HTMLPurifier_ChildDef_Optional($block); $this->block = new HTMLPurifier_ChildDef_Optional($block);
$this->elements = $this->block->elements; $this->elements = $this->block->elements;
} }
public function validateChildren($tokens_of_children, $config, $context) { /**
* @param HTMLPurifier_Node[] $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool
*/
public function validateChildren($children, $config, $context)
{
if ($context->get('IsInline') === false) { if ($context->get('IsInline') === false) {
return $this->block->validateChildren( return $this->block->validateChildren(
$tokens_of_children, $config, $context); $children,
$config,
$context
);
} else { } else {
return $this->inline->validateChildren( return $this->inline->validateChildren(
$tokens_of_children, $config, $context); $children,
$config,
$context
);
} }
} }
} }

View File

@@ -8,28 +8,42 @@
*/ */
class HTMLPurifier_ChildDef_Custom extends HTMLPurifier_ChildDef class HTMLPurifier_ChildDef_Custom extends HTMLPurifier_ChildDef
{ {
public $type = 'custom';
public $allow_empty = false;
/** /**
* Allowed child pattern as defined by the DTD * @type string
*/
public $type = 'custom';
/**
* @type bool
*/
public $allow_empty = false;
/**
* Allowed child pattern as defined by the DTD.
* @type string
*/ */
public $dtd_regex; public $dtd_regex;
/** /**
* PCRE regex derived from $dtd_regex * PCRE regex derived from $dtd_regex.
* @private * @type string
*/ */
private $_pcre_regex; private $_pcre_regex;
/** /**
* @param $dtd_regex Allowed child pattern from the DTD * @param $dtd_regex Allowed child pattern from the DTD
*/ */
public function __construct($dtd_regex) { public function __construct($dtd_regex)
{
$this->dtd_regex = $dtd_regex; $this->dtd_regex = $dtd_regex;
$this->_compileRegex(); $this->_compileRegex();
} }
/** /**
* Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex) * Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex)
*/ */
protected function _compileRegex() { protected function _compileRegex()
{
$raw = str_replace(' ', '', $this->dtd_regex); $raw = str_replace(' ', '', $this->dtd_regex);
if ($raw{0} != '(') { if ($raw{0} != '(') {
$raw = "($raw)"; $raw = "($raw)";
@@ -57,33 +71,31 @@ class HTMLPurifier_ChildDef_Custom extends HTMLPurifier_ChildDef
$this->_pcre_regex = $reg; $this->_pcre_regex = $reg;
} }
public function validateChildren($tokens_of_children, $config, $context) {
/**
* @param HTMLPurifier_Node[] $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool
*/
public function validateChildren($children, $config, $context)
{
$list_of_children = ''; $list_of_children = '';
$nesting = 0; // depth into the nest $nesting = 0; // depth into the nest
foreach ($tokens_of_children as $token) { foreach ($children as $node) {
if (!empty($token->is_whitespace)) continue; if (!empty($node->is_whitespace)) {
continue;
$is_child = ($nesting == 0); // direct
if ($token instanceof HTMLPurifier_Token_Start) {
$nesting++;
} elseif ($token instanceof HTMLPurifier_Token_End) {
$nesting--;
}
if ($is_child) {
$list_of_children .= $token->name . ',';
} }
$list_of_children .= $node->name . ',';
} }
// add leading comma to deal with stray comma declarations // add leading comma to deal with stray comma declarations
$list_of_children = ',' . rtrim($list_of_children, ','); $list_of_children = ',' . rtrim($list_of_children, ',');
$okay = $okay =
preg_match( preg_match(
'/^,?'.$this->_pcre_regex.'$/', '/^,?' . $this->_pcre_regex . '$/',
$list_of_children $list_of_children
); );
return (bool)$okay;
return (bool) $okay;
} }
} }

View File

@@ -9,10 +9,28 @@
*/ */
class HTMLPurifier_ChildDef_Empty extends HTMLPurifier_ChildDef class HTMLPurifier_ChildDef_Empty extends HTMLPurifier_ChildDef
{ {
/**
* @type bool
*/
public $allow_empty = true; public $allow_empty = true;
/**
* @type string
*/
public $type = 'empty'; public $type = 'empty';
public function __construct() {}
public function validateChildren($tokens_of_children, $config, $context) { public function __construct()
{
}
/**
* @param HTMLPurifier_Node[] $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
return array(); return array();
} }
} }

View File

@@ -2,117 +2,83 @@
/** /**
* Definition for list containers ul and ol. * Definition for list containers ul and ol.
*
* What does this do? The big thing is to handle ol/ul at the top
* level of list nodes, which should be handled specially by /folding/
* them into the previous list node. We generally shouldn't ever
* see other disallowed elements, because the autoclose behavior
* in MakeWellFormed handles it.
*/ */
class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef
{ {
/**
* @type string
*/
public $type = 'list'; public $type = 'list';
/**
* @type array
*/
// lying a little bit, so that we can handle ul and ol ourselves // lying a little bit, so that we can handle ul and ol ourselves
// XXX: This whole business with 'wrap' is all a bit unsatisfactory // XXX: This whole business with 'wrap' is all a bit unsatisfactory
public $elements = array('li' => true, 'ul' => true, 'ol' => true); public $elements = array('li' => true, 'ul' => true, 'ol' => true);
public function validateChildren($tokens_of_children, $config, $context) {
/**
* @param array $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
// Flag for subclasses // Flag for subclasses
$this->whitespace = false; $this->whitespace = false;
// if there are no tokens, delete parent node // if there are no tokens, delete parent node
if (empty($tokens_of_children)) return false; if (empty($children)) {
return false;
}
// the new set of children // the new set of children
$result = array(); $result = array();
// current depth into the nest
$nesting = 0;
// a little sanity check to make sure it's not ALL whitespace // a little sanity check to make sure it's not ALL whitespace
$all_whitespace = true; $all_whitespace = true;
$seen_li = false; $current_li = false;
$need_close_li = false;
foreach ($tokens_of_children as $token) { foreach ($children as $node) {
if (!empty($token->is_whitespace)) { if (!empty($node->is_whitespace)) {
$result[] = $token; $result[] = $node;
continue; continue;
} }
$all_whitespace = false; // phew, we're not talking about whitespace $all_whitespace = false; // phew, we're not talking about whitespace
if ($nesting == 1 && $need_close_li) { if ($node->name === 'li') {
$result[] = new HTMLPurifier_Token_End('li'); // good
$nesting--; $current_li = $node;
$need_close_li = false; $result[] = $node;
} } else {
// we want to tuck this into the previous li
$is_child = ($nesting == 0); // Invariant: we expect the node to be ol/ul
// ToDo: Make this more robust in the case of not ol/ul
if ($token instanceof HTMLPurifier_Token_Start) { // by distinguishing between existing li and li created
$nesting++; // to handle non-list elements; non-list elements should
} elseif ($token instanceof HTMLPurifier_Token_End) { // not be appended to an existing li; only li created
$nesting--; // for non-list. This distinction is not currently made.
} if ($current_li === false) {
$current_li = new HTMLPurifier_Node_Element('li');
if ($is_child) { $result[] = $current_li;
if ($token->name === 'li') {
// good
$seen_li = true;
} elseif ($token->name === 'ul' || $token->name === 'ol') {
// we want to tuck this into the previous li
$need_close_li = true;
$nesting++;
if (!$seen_li) {
// create a new li element
$result[] = new HTMLPurifier_Token_Start('li');
} else {
// backtrack until </li> found
while(true) {
$t = array_pop($result);
if ($t instanceof HTMLPurifier_Token_End) {
// XXX actually, these invariants could very plausibly be violated
// if we are doing silly things with modifying the set of allowed elements.
// FORTUNATELY, it doesn't make a difference, since the allowed
// elements are hard-coded here!
if ($t->name !== 'li') {
trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR);
return false;
}
break;
} elseif ($t instanceof HTMLPurifier_Token_Empty) { // bleagh
if ($t->name !== 'li') {
trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR);
return false;
}
// XXX this should have a helper for it...
$result[] = new HTMLPurifier_Token_Start('li', $t->attr, $t->line, $t->col, $t->armor);
break;
} else {
if (!$t->is_whitespace) {
trigger_error("Only whitespace present invariant violated in List ChildDef", E_USER_ERROR);
return false;
}
}
}
}
} else {
// start wrapping (this doesn't precisely mimic
// browser behavior, but what browsers do is kind of
// hard to mimic in a standards compliant way
// XXX Actually, this has no impact in practice,
// because this gets handled earlier. Arguably,
// we should rip out all of that processing
$result[] = new HTMLPurifier_Token_Start('li');
$nesting++;
$seen_li = true;
$need_close_li = true;
} }
$current_li->children[] = $node;
$current_li->empty = false; // XXX fascinating! Check for this error elsewhere ToDo
} }
$result[] = $token;
} }
if ($need_close_li) { if (empty($result)) {
$result[] = new HTMLPurifier_Token_End('li'); return false;
} }
if (empty($result)) return false;
if ($all_whitespace) { if ($all_whitespace) {
return false; return false;
} }
if ($tokens_of_children == $result) return true;
return $result; return $result;
} }
} }

View File

@@ -9,15 +9,34 @@
*/ */
class HTMLPurifier_ChildDef_Optional extends HTMLPurifier_ChildDef_Required class HTMLPurifier_ChildDef_Optional extends HTMLPurifier_ChildDef_Required
{ {
/**
* @type bool
*/
public $allow_empty = true; public $allow_empty = true;
/**
* @type string
*/
public $type = 'optional'; public $type = 'optional';
public function validateChildren($tokens_of_children, $config, $context) {
$result = parent::validateChildren($tokens_of_children, $config, $context); /**
// we assume that $tokens_of_children is not modified * @param array $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
$result = parent::validateChildren($children, $config, $context);
// we assume that $children is not modified
if ($result === false) { if ($result === false) {
if (empty($tokens_of_children)) return true; if (empty($children)) {
elseif ($this->whitespace) return $tokens_of_children; return true;
else return array(); } elseif ($this->whitespace) {
return $children;
} else {
return array();
}
} }
return $result; return $result;
} }

View File

@@ -7,17 +7,21 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
{ {
/** /**
* Lookup table of allowed elements. * Lookup table of allowed elements.
* @public * @type array
*/ */
public $elements = array(); public $elements = array();
/** /**
* Whether or not the last passed node was all whitespace. * Whether or not the last passed node was all whitespace.
* @type bool
*/ */
protected $whitespace = false; protected $whitespace = false;
/** /**
* @param $elements List of allowed element names (lowercase). * @param array|string $elements List of allowed element names (lowercase).
*/ */
public function __construct($elements) { public function __construct($elements)
{
if (is_string($elements)) { if (is_string($elements)) {
$elements = str_replace(' ', '', $elements); $elements = str_replace(' ', '', $elements);
$elements = explode('|', $elements); $elements = explode('|', $elements);
@@ -27,29 +31,43 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
$elements = array_flip($elements); $elements = array_flip($elements);
foreach ($elements as $i => $x) { foreach ($elements as $i => $x) {
$elements[$i] = true; $elements[$i] = true;
if (empty($i)) unset($elements[$i]); // remove blank if (empty($i)) {
unset($elements[$i]);
} // remove blank
} }
} }
$this->elements = $elements; $this->elements = $elements;
} }
/**
* @type bool
*/
public $allow_empty = false; public $allow_empty = false;
/**
* @type string
*/
public $type = 'required'; public $type = 'required';
public function validateChildren($tokens_of_children, $config, $context) {
/**
* @param array $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
// Flag for subclasses // Flag for subclasses
$this->whitespace = false; $this->whitespace = false;
// if there are no tokens, delete parent node // if there are no tokens, delete parent node
if (empty($tokens_of_children)) return false; if (empty($children)) {
return false;
}
// the new set of children // the new set of children
$result = array(); $result = array();
// current depth into the nest
$nesting = 0;
// whether or not we're deleting a node
$is_deleting = false;
// whether or not parsed character data is allowed // whether or not parsed character data is allowed
// this controls whether or not we silently drop a tag // this controls whether or not we silently drop a tag
// or generate escaped HTML from it // or generate escaped HTML from it
@@ -58,58 +76,41 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
// a little sanity check to make sure it's not ALL whitespace // a little sanity check to make sure it's not ALL whitespace
$all_whitespace = true; $all_whitespace = true;
// some configuration $stack = array_reverse($children);
$escape_invalid_children = $config->get('Core.EscapeInvalidChildren'); while (!empty($stack)) {
$node = array_pop($stack);
// generator if (!empty($node->is_whitespace)) {
$gen = new HTMLPurifier_Generator($config, $context); $result[] = $node;
foreach ($tokens_of_children as $token) {
if (!empty($token->is_whitespace)) {
$result[] = $token;
continue; continue;
} }
$all_whitespace = false; // phew, we're not talking about whitespace $all_whitespace = false; // phew, we're not talking about whitespace
$is_child = ($nesting == 0); if (!isset($this->elements[$node->name])) {
// special case text
if ($token instanceof HTMLPurifier_Token_Start) { // XXX One of these ought to be redundant or something
$nesting++; if ($pcdata_allowed && $node instanceof HTMLPurifier_Node_Text) {
} elseif ($token instanceof HTMLPurifier_Token_End) { $result[] = $node;
$nesting--; continue;
} }
// spill the child contents in
if ($is_child) { // ToDo: Make configurable
$is_deleting = false; if ($node instanceof HTMLPurifier_Node_Element) {
if (!isset($this->elements[$token->name])) { for ($i = count($node->children) - 1; $i >= 0; $i--) {
$is_deleting = true; $stack[] = $node->children[$i];
if ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text) {
$result[] = $token;
} elseif ($pcdata_allowed && $escape_invalid_children) {
$result[] = new HTMLPurifier_Token_Text(
$gen->generateFromToken($token)
);
} }
continue; continue;
} }
continue;
} }
if (!$is_deleting || ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text)) { $result[] = $node;
$result[] = $token; }
} elseif ($pcdata_allowed && $escape_invalid_children) { if (empty($result)) {
$result[] = return false;
new HTMLPurifier_Token_Text(
$gen->generateFromToken($token)
);
} else {
// drop silently
}
} }
if (empty($result)) return false;
if ($all_whitespace) { if ($all_whitespace) {
$this->whitespace = true; $this->whitespace = true;
return false; return false;
} }
if ($tokens_of_children == $result) return true;
return $result; return $result;
} }
} }

View File

@@ -5,75 +5,97 @@
*/ */
class HTMLPurifier_ChildDef_StrictBlockquote extends HTMLPurifier_ChildDef_Required class HTMLPurifier_ChildDef_StrictBlockquote extends HTMLPurifier_ChildDef_Required
{ {
/**
* @type array
*/
protected $real_elements; protected $real_elements;
/**
* @type array
*/
protected $fake_elements; protected $fake_elements;
/**
* @type bool
*/
public $allow_empty = true; public $allow_empty = true;
/**
* @type string
*/
public $type = 'strictblockquote'; public $type = 'strictblockquote';
/**
* @type bool
*/
protected $init = false; protected $init = false;
/** /**
* @param HTMLPurifier_Config $config
* @return array
* @note We don't want MakeWellFormed to auto-close inline elements since * @note We don't want MakeWellFormed to auto-close inline elements since
* they might be allowed. * they might be allowed.
*/ */
public function getAllowedElements($config) { public function getAllowedElements($config)
{
$this->init($config); $this->init($config);
return $this->fake_elements; return $this->fake_elements;
} }
public function validateChildren($tokens_of_children, $config, $context) { /**
* @param array $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
$this->init($config); $this->init($config);
// trick the parent class into thinking it allows more // trick the parent class into thinking it allows more
$this->elements = $this->fake_elements; $this->elements = $this->fake_elements;
$result = parent::validateChildren($tokens_of_children, $config, $context); $result = parent::validateChildren($children, $config, $context);
$this->elements = $this->real_elements; $this->elements = $this->real_elements;
if ($result === false) return array(); if ($result === false) {
if ($result === true) $result = $tokens_of_children; return array();
}
if ($result === true) {
$result = $children;
}
$def = $config->getHTMLDefinition(); $def = $config->getHTMLDefinition();
$block_wrap_start = new HTMLPurifier_Token_Start($def->info_block_wrapper); $block_wrap_name = $def->info_block_wrapper;
$block_wrap_end = new HTMLPurifier_Token_End( $def->info_block_wrapper); $block_wrap = false;
$is_inline = false;
$depth = 0;
$ret = array(); $ret = array();
// assuming that there are no comment tokens foreach ($result as $node) {
foreach ($result as $i => $token) { if ($block_wrap === false) {
$token = $result[$i]; if (($node instanceof HTMLPurifier_Node_Text && !$node->is_whitespace) ||
// ifs are nested for readability ($node instanceof HTMLPurifier_Node_Element && !isset($this->elements[$node->name]))) {
if (!$is_inline) { $block_wrap = new HTMLPurifier_Node_Element($def->info_block_wrapper);
if (!$depth) { $ret[] = $block_wrap;
if (
($token instanceof HTMLPurifier_Token_Text && !$token->is_whitespace) ||
(!$token instanceof HTMLPurifier_Token_Text && !isset($this->elements[$token->name]))
) {
$is_inline = true;
$ret[] = $block_wrap_start;
}
} }
} else { } else {
if (!$depth) { if ($node instanceof HTMLPurifier_Node_Element && isset($this->elements[$node->name])) {
// starting tokens have been inline text / empty $block_wrap = false;
if ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) {
if (isset($this->elements[$token->name])) {
// ended
$ret[] = $block_wrap_end;
$is_inline = false;
}
}
} }
} }
$ret[] = $token; if ($block_wrap) {
if ($token instanceof HTMLPurifier_Token_Start) $depth++; $block_wrap->children[] = $node;
if ($token instanceof HTMLPurifier_Token_End) $depth--; } else {
$ret[] = $node;
}
} }
if ($is_inline) $ret[] = $block_wrap_end;
return $ret; return $ret;
} }
private function init($config) { /**
* @param HTMLPurifier_Config $config
*/
private function init($config)
{
if (!$this->init) { if (!$this->init) {
$def = $config->getHTMLDefinition(); $def = $config->getHTMLDefinition();
// allow all inline elements // allow all inline elements

View File

@@ -31,195 +31,192 @@
*/ */
class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef
{ {
/**
* @type bool
*/
public $allow_empty = false; public $allow_empty = false;
public $type = 'table';
public $elements = array('tr' => true, 'tbody' => true, 'thead' => true,
'tfoot' => true, 'caption' => true, 'colgroup' => true, 'col' => true);
public function __construct() {}
public function validateChildren($tokens_of_children, $config, $context) {
if (empty($tokens_of_children)) return false;
// this ensures that the loop gets run one last time before closing /**
// up. It's a little bit of a hack, but it works! Just make sure you * @type string
// get rid of the token later. */
$tokens_of_children[] = false; public $type = 'table';
/**
* @type array
*/
public $elements = array(
'tr' => true,
'tbody' => true,
'thead' => true,
'tfoot' => true,
'caption' => true,
'colgroup' => true,
'col' => true
);
public function __construct()
{
}
/**
* @param array $children
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function validateChildren($children, $config, $context)
{
if (empty($children)) {
return false;
}
// only one of these elements is allowed in a table // only one of these elements is allowed in a table
$caption = false; $caption = false;
$thead = false; $thead = false;
$tfoot = false; $tfoot = false;
// whitespace
$initial_ws = array();
$after_caption_ws = array();
$after_thead_ws = array();
$after_tfoot_ws = array();
// as many of these as you want // as many of these as you want
$cols = array(); $cols = array();
$content = array(); $content = array();
$nesting = 0; // current depth so we can determine nodes
$is_collecting = false; // are we globbing together tokens to package
// into one of the collectors?
$collection = array(); // collected nodes
$tag_index = 0; // the first node might be whitespace,
// so this tells us where the start tag is
$tbody_mode = false; // if true, then we need to wrap any stray $tbody_mode = false; // if true, then we need to wrap any stray
// <tr>s with a <tbody>. // <tr>s with a <tbody>.
foreach ($tokens_of_children as $token) { $ws_accum =& $initial_ws;
$is_child = ($nesting == 0);
if ($token === false) { foreach ($children as $node) {
// terminating sequence started if ($node instanceof HTMLPurifier_Node_Comment) {
} elseif ($token instanceof HTMLPurifier_Token_Start) { $ws_accum[] = $node;
$nesting++; continue;
} elseif ($token instanceof HTMLPurifier_Token_End) {
$nesting--;
} }
switch ($node->name) {
// handle node collection case 'tbody':
if ($is_collecting) { $tbody_mode = true;
if ($is_child) { // fall through
// okay, let's stash the tokens away case 'tr':
// first token tells us the type of the collection $content[] = $node;
switch ($collection[$tag_index]->name) { $ws_accum =& $content;
case 'tbody': break;
$tbody_mode = true; case 'caption':
case 'tr': // there can only be one caption!
$content[] = $collection; if ($caption !== false) break;
break; $caption = $node;
case 'caption': $ws_accum =& $after_caption_ws;
if ($caption !== false) break; break;
$caption = $collection; case 'thead':
break; $tbody_mode = true;
case 'thead': // XXX This breaks rendering properties with
case 'tfoot': // Firefox, which never floats a <thead> to
$tbody_mode = true; // the top. Ever. (Our scheme will float the
// XXX This breaks rendering properties with // first <thead> to the top.) So maybe
// Firefox, which never floats a <thead> to // <thead>s that are not first should be
// the top. Ever. (Our scheme will float the // turned into <tbody>? Very tricky, indeed.
// first <thead> to the top.) So maybe if ($thead === false) {
// <thead>s that are not first should be $thead = $node;
// turned into <tbody>? Very tricky, indeed. $ws_accum =& $after_thead_ws;
// access the appropriate variable, $thead or $tfoot
$var = $collection[$tag_index]->name;
if ($$var === false) {
$$var = $collection;
} else {
// Oops, there's a second one! What
// should we do? Current behavior is to
// transmutate the first and last entries into
// tbody tags, and then put into content.
// Maybe a better idea is to *attach
// it* to the existing thead or tfoot?
// We don't do this, because Firefox
// doesn't float an extra tfoot to the
// bottom like it does for the first one.
$collection[$tag_index]->name = 'tbody';
$collection[count($collection)-1]->name = 'tbody';
$content[] = $collection;
}
break;
case 'colgroup':
$cols[] = $collection;
break;
}
$collection = array();
$is_collecting = false;
$tag_index = 0;
} else { } else {
// add the node to the collection // Oops, there's a second one! What
$collection[] = $token; // should we do? Current behavior is to
// transmutate the first and last entries into
// tbody tags, and then put into content.
// Maybe a better idea is to *attach
// it* to the existing thead or tfoot?
// We don't do this, because Firefox
// doesn't float an extra tfoot to the
// bottom like it does for the first one.
$node->name = 'tbody';
$content[] = $node;
$ws_accum =& $content;
} }
} break;
case 'tfoot':
// terminate // see above for some aveats
if ($token === false) break; $tbody_mode = true;
if ($tfoot === false) {
if ($is_child) { $tfoot = $node;
// determine what we're dealing with $ws_accum =& $after_tfoot_ws;
if ($token->name == 'col') { } else {
// the only empty tag in the possie, we can handle it $node->name = 'tbody';
// immediately $content[] = $node;
$cols[] = array_merge($collection, array($token)); $ws_accum =& $content;
$collection = array();
$tag_index = 0;
continue;
} }
switch($token->name) { break;
case 'caption': case 'colgroup':
case 'colgroup': case 'col':
case 'thead': $cols[] = $node;
case 'tfoot': $ws_accum =& $cols;
case 'tbody': break;
case 'tr': case '#PCDATA':
$is_collecting = true; // How is whitespace handled? We treat is as sticky to
$collection[] = $token; // the *end* of the previous element. So all of the
continue; // nonsense we have worked on is to keep things
default: // together.
if (!empty($token->is_whitespace)) { if (!empty($node->is_whitespace)) {
$collection[] = $token; $ws_accum[] = $node;
$tag_index++;
}
continue;
} }
break;
} }
} }
if (empty($content)) return false; if (empty($content)) {
return false;
}
$ret = array(); $ret = $initial_ws;
if ($caption !== false) $ret = array_merge($ret, $caption); if ($caption !== false) {
if ($cols !== false) foreach ($cols as $token_array) $ret = array_merge($ret, $token_array); $ret[] = $caption;
if ($thead !== false) $ret = array_merge($ret, $thead); $ret = array_merge($ret, $after_caption_ws);
if ($tfoot !== false) $ret = array_merge($ret, $tfoot); }
if ($cols !== false) {
$ret = array_merge($ret, $cols);
}
if ($thead !== false) {
$ret[] = $thead;
$ret = array_merge($ret, $after_thead_ws);
}
if ($tfoot !== false) {
$ret[] = $tfoot;
$ret = array_merge($ret, $after_tfoot_ws);
}
if ($tbody_mode) { if ($tbody_mode) {
// a little tricky, since the start of the collection may be // we have to shuffle tr into tbody
// whitespace $current_tr_tbody = null;
$inside_tbody = false;
foreach ($content as $token_array) { foreach($content as $node) {
// find the starting token switch ($node->name) {
foreach ($token_array as $t) { case 'tbody':
if ($t->name === 'tr' || $t->name === 'tbody') { $current_tr_tbody = null;
break; $ret[] = $node;
break;
case 'tr':
if ($current_tr_tbody === null) {
$current_tr_tbody = new HTMLPurifier_Node_Element('tbody');
$ret[] = $current_tr_tbody;
} }
} // iterator variable carries over $current_tr_tbody->children[] = $node;
if ($t->name === 'tr') { break;
if ($inside_tbody) { case '#PCDATA':
$ret = array_merge($ret, $token_array); assert($node->is_whitespace);
if ($current_tr_tbody === null) {
$ret[] = $node;
} else { } else {
$ret[] = new HTMLPurifier_Token_Start('tbody'); $current_tr_tbody->children[] = $node;
$ret = array_merge($ret, $token_array);
$inside_tbody = true;
} }
} elseif ($t->name === 'tbody') { break;
if ($inside_tbody) {
$ret[] = new HTMLPurifier_Token_End('tbody');
$inside_tbody = false;
$ret = array_merge($ret, $token_array);
} else {
$ret = array_merge($ret, $token_array);
}
} else {
trigger_error("tr/tbody in content invariant failed in Table ChildDef", E_USER_ERROR);
} }
} }
if ($inside_tbody) {
$ret[] = new HTMLPurifier_Token_End('tbody');
}
} else { } else {
foreach ($content as $token_array) { $ret = array_merge($ret, $content);
// invariant: everything in here is <tr>s
$ret = array_merge($ret, $token_array);
}
} }
if (!empty($collection) && $is_collecting == false){ return $ret;
// grab the trailing space
$ret = array_merge($ret, $collection);
}
array_pop($tokens_of_children); // remove phantom token
return ($ret === $tokens_of_children) ? true : $ret;
} }
} }

View File

@@ -19,78 +19,92 @@ class HTMLPurifier_Config
/** /**
* HTML Purifier's version * HTML Purifier's version
* @type string
*/ */
public $version = '4.5.0'; public $version = '4.6.0';
/** /**
* Bool indicator whether or not to automatically finalize * Whether or not to automatically finalize
* the object if a read operation is done * the object if a read operation is done.
* @type bool
*/ */
public $autoFinalize = true; public $autoFinalize = true;
// protected member variables // protected member variables
/** /**
* Namespace indexed array of serials for specific namespaces (see * Namespace indexed array of serials for specific namespaces.
* getSerial() for more info). * @see getSerial() for more info.
* @type string[]
*/ */
protected $serials = array(); protected $serials = array();
/** /**
* Serial for entire configuration object * Serial for entire configuration object.
* @type string
*/ */
protected $serial; protected $serial;
/** /**
* Parser for variables * Parser for variables.
* @type HTMLPurifier_VarParser_Flexible
*/ */
protected $parser = null; protected $parser = null;
/** /**
* Reference HTMLPurifier_ConfigSchema for value checking * Reference HTMLPurifier_ConfigSchema for value checking.
* @type HTMLPurifier_ConfigSchema
* @note This is public for introspective purposes. Please don't * @note This is public for introspective purposes. Please don't
* abuse! * abuse!
*/ */
public $def; public $def;
/** /**
* Indexed array of definitions * Indexed array of definitions.
* @type HTMLPurifier_Definition[]
*/ */
protected $definitions; protected $definitions;
/** /**
* Bool indicator whether or not config is finalized * Whether or not config is finalized.
* @type bool
*/ */
protected $finalized = false; protected $finalized = false;
/** /**
* Property list containing configuration directives. * Property list containing configuration directives.
* @type array
*/ */
protected $plist; protected $plist;
/** /**
* Whether or not a set is taking place due to an * Whether or not a set is taking place due to an alias lookup.
* alias lookup. * @type bool
*/ */
private $aliasMode; private $aliasMode;
/** /**
* Set to false if you do not want line and file numbers in errors * Set to false if you do not want line and file numbers in errors.
* (useful when unit testing). This will also compress some errors * (useful when unit testing). This will also compress some errors
* and exceptions. * and exceptions.
* @type bool
*/ */
public $chatty = true; public $chatty = true;
/** /**
* Current lock; only gets to this namespace are allowed. * Current lock; only gets to this namespace are allowed.
* @type string
*/ */
private $lock; private $lock;
/** /**
* @param $definition HTMLPurifier_ConfigSchema that defines what directives * Constructor
* are allowed. * @param HTMLPurifier_ConfigSchema $definition ConfigSchema that defines
* what directives are allowed.
* @param HTMLPurifier_PropertyList $parent
*/ */
public function __construct($definition, $parent = null) { public function __construct($definition, $parent = null)
{
$parent = $parent ? $parent : $definition->defaultPlist; $parent = $parent ? $parent : $definition->defaultPlist;
$this->plist = new HTMLPurifier_PropertyList($parent); $this->plist = new HTMLPurifier_PropertyList($parent);
$this->def = $definition; // keep a copy around for checking $this->def = $definition; // keep a copy around for checking
@@ -103,10 +117,11 @@ class HTMLPurifier_Config
* object. Can be: a HTMLPurifier_Config() object, * object. Can be: a HTMLPurifier_Config() object,
* an array of directives based on loadArray(), * an array of directives based on loadArray(),
* or a string filename of an ini file. * or a string filename of an ini file.
* @param HTMLPurifier_ConfigSchema Schema object * @param HTMLPurifier_ConfigSchema $schema Schema object
* @return Configured HTMLPurifier_Config object * @return HTMLPurifier_Config Configured object
*/ */
public static function create($config, $schema = null) { public static function create($config, $schema = null)
{
if ($config instanceof HTMLPurifier_Config) { if ($config instanceof HTMLPurifier_Config) {
// pass-through // pass-through
return $config; return $config;
@@ -116,57 +131,79 @@ class HTMLPurifier_Config
} else { } else {
$ret = new HTMLPurifier_Config($schema); $ret = new HTMLPurifier_Config($schema);
} }
if (is_string($config)) $ret->loadIni($config); if (is_string($config)) {
elseif (is_array($config)) $ret->loadArray($config); $ret->loadIni($config);
} elseif (is_array($config)) $ret->loadArray($config);
return $ret; return $ret;
} }
/** /**
* Creates a new config object that inherits from a previous one. * Creates a new config object that inherits from a previous one.
* @param HTMLPurifier_Config $config Configuration object to inherit * @param HTMLPurifier_Config $config Configuration object to inherit from.
* from.
* @return HTMLPurifier_Config object with $config as its parent. * @return HTMLPurifier_Config object with $config as its parent.
*/ */
public static function inherit(HTMLPurifier_Config $config) { public static function inherit(HTMLPurifier_Config $config)
{
return new HTMLPurifier_Config($config->def, $config->plist); return new HTMLPurifier_Config($config->def, $config->plist);
} }
/** /**
* Convenience constructor that creates a default configuration object. * Convenience constructor that creates a default configuration object.
* @return Default HTMLPurifier_Config object. * @return HTMLPurifier_Config default object.
*/ */
public static function createDefault() { public static function createDefault()
{
$definition = HTMLPurifier_ConfigSchema::instance(); $definition = HTMLPurifier_ConfigSchema::instance();
$config = new HTMLPurifier_Config($definition); $config = new HTMLPurifier_Config($definition);
return $config; return $config;
} }
/** /**
* Retreives a value from the configuration. * Retrieves a value from the configuration.
* @param $key String key *
* @param string $key String key
* @param mixed $a
*
* @return mixed
*/ */
public function get($key, $a = null) { public function get($key, $a = null)
{
if ($a !== null) { if ($a !== null) {
$this->triggerError("Using deprecated API: use \$config->get('$key.$a') instead", E_USER_WARNING); $this->triggerError(
"Using deprecated API: use \$config->get('$key.$a') instead",
E_USER_WARNING
);
$key = "$key.$a"; $key = "$key.$a";
} }
if (!$this->finalized) $this->autoFinalize(); if (!$this->finalized) {
$this->autoFinalize();
}
if (!isset($this->def->info[$key])) { if (!isset($this->def->info[$key])) {
// can't add % due to SimpleTest bug // can't add % due to SimpleTest bug
$this->triggerError('Cannot retrieve value of undefined directive ' . htmlspecialchars($key), $this->triggerError(
E_USER_WARNING); 'Cannot retrieve value of undefined directive ' . htmlspecialchars($key),
E_USER_WARNING
);
return; return;
} }
if (isset($this->def->info[$key]->isAlias)) { if (isset($this->def->info[$key]->isAlias)) {
$d = $this->def->info[$key]; $d = $this->def->info[$key];
$this->triggerError('Cannot get value from aliased directive, use real name ' . $d->key, $this->triggerError(
E_USER_ERROR); 'Cannot get value from aliased directive, use real name ' . $d->key,
E_USER_ERROR
);
return; return;
} }
if ($this->lock) { if ($this->lock) {
list($ns) = explode('.', $key); list($ns) = explode('.', $key);
if ($ns !== $this->lock) { if ($ns !== $this->lock) {
$this->triggerError('Cannot get value of namespace ' . $ns . ' when lock for ' . $this->lock . ' is active, this probably indicates a Definition setup method is accessing directives that are not within its namespace', E_USER_ERROR); $this->triggerError(
'Cannot get value of namespace ' . $ns . ' when lock for ' .
$this->lock .
' is active, this probably indicates a Definition setup method ' .
'is accessing directives that are not within its namespace',
E_USER_ERROR
);
return; return;
} }
} }
@@ -174,15 +211,24 @@ class HTMLPurifier_Config
} }
/** /**
* Retreives an array of directives to values from a given namespace * Retrieves an array of directives to values from a given namespace
* @param $namespace String namespace *
* @param string $namespace String namespace
*
* @return array
*/ */
public function getBatch($namespace) { public function getBatch($namespace)
if (!$this->finalized) $this->autoFinalize(); {
if (!$this->finalized) {
$this->autoFinalize();
}
$full = $this->getAll(); $full = $this->getAll();
if (!isset($full[$namespace])) { if (!isset($full[$namespace])) {
$this->triggerError('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace), $this->triggerError(
E_USER_WARNING); 'Cannot retrieve undefined namespace ' .
htmlspecialchars($namespace),
E_USER_WARNING
);
return; return;
} }
return $full[$namespace]; return $full[$namespace];
@@ -191,11 +237,15 @@ class HTMLPurifier_Config
/** /**
* Returns a SHA-1 signature of a segment of the configuration object * Returns a SHA-1 signature of a segment of the configuration object
* that uniquely identifies that particular configuration * that uniquely identifies that particular configuration
*
* @param string $namespace Namespace to get serial for
*
* @return string
* @note Revision is handled specially and is removed from the batch * @note Revision is handled specially and is removed from the batch
* before processing! * before processing!
* @param $namespace Namespace to get serial for
*/ */
public function getBatchSerial($namespace) { public function getBatchSerial($namespace)
{
if (empty($this->serials[$namespace])) { if (empty($this->serials[$namespace])) {
$batch = $this->getBatch($namespace); $batch = $this->getBatch($namespace);
unset($batch['DefinitionRev']); unset($batch['DefinitionRev']);
@@ -207,8 +257,11 @@ class HTMLPurifier_Config
/** /**
* Returns a SHA-1 signature for the entire configuration object * Returns a SHA-1 signature for the entire configuration object
* that uniquely identifies that particular configuration * that uniquely identifies that particular configuration
*
* @return string
*/ */
public function getSerial() { public function getSerial()
{
if (empty($this->serial)) { if (empty($this->serial)) {
$this->serial = sha1(serialize($this->getAll())); $this->serial = sha1(serialize($this->getAll()));
} }
@@ -217,10 +270,14 @@ class HTMLPurifier_Config
/** /**
* Retrieves all directives, organized by namespace * Retrieves all directives, organized by namespace
*
* @warning This is a pretty inefficient function, avoid if you can * @warning This is a pretty inefficient function, avoid if you can
*/ */
public function getAll() { public function getAll()
if (!$this->finalized) $this->autoFinalize(); {
if (!$this->finalized) {
$this->autoFinalize();
}
$ret = array(); $ret = array();
foreach ($this->plist->squash() as $name => $value) { foreach ($this->plist->squash() as $name => $value) {
list($ns, $key) = explode('.', $name, 2); list($ns, $key) = explode('.', $name, 2);
@@ -231,10 +288,13 @@ class HTMLPurifier_Config
/** /**
* Sets a value to configuration. * Sets a value to configuration.
* @param $key String key *
* @param $value Mixed value * @param string $key key
* @param mixed $value value
* @param mixed $a
*/ */
public function set($key, $value, $a = null) { public function set($key, $value, $a = null)
{
if (strpos($key, '.') === false) { if (strpos($key, '.') === false) {
$namespace = $key; $namespace = $key;
$directive = $value; $directive = $value;
@@ -244,18 +304,25 @@ class HTMLPurifier_Config
} else { } else {
list($namespace) = explode('.', $key); list($namespace) = explode('.', $key);
} }
if ($this->isFinalized('Cannot set directive after finalization')) return; if ($this->isFinalized('Cannot set directive after finalization')) {
return;
}
if (!isset($this->def->info[$key])) { if (!isset($this->def->info[$key])) {
$this->triggerError('Cannot set undefined directive ' . htmlspecialchars($key) . ' to value', $this->triggerError(
E_USER_WARNING); 'Cannot set undefined directive ' . htmlspecialchars($key) . ' to value',
E_USER_WARNING
);
return; return;
} }
$def = $this->def->info[$key]; $def = $this->def->info[$key];
if (isset($def->isAlias)) { if (isset($def->isAlias)) {
if ($this->aliasMode) { if ($this->aliasMode) {
$this->triggerError('Double-aliases not allowed, please fix '. $this->triggerError(
'ConfigSchema bug with' . $key, E_USER_ERROR); 'Double-aliases not allowed, please fix '.
'ConfigSchema bug with' . $key,
E_USER_ERROR
);
return; return;
} }
$this->aliasMode = true; $this->aliasMode = true;
@@ -279,7 +346,11 @@ class HTMLPurifier_Config
try { try {
$value = $this->parser->parse($value, $type, $allow_null); $value = $this->parser->parse($value, $type, $allow_null);
} catch (HTMLPurifier_VarParserException $e) { } catch (HTMLPurifier_VarParserException $e) {
$this->triggerError('Value for ' . $key . ' is of invalid type, should be ' . HTMLPurifier_VarParser::getTypeName($type), E_USER_WARNING); $this->triggerError(
'Value for ' . $key . ' is of invalid type, should be ' .
HTMLPurifier_VarParser::getTypeName($type),
E_USER_WARNING
);
return; return;
} }
if (is_string($value) && is_object($def)) { if (is_string($value) && is_object($def)) {
@@ -289,8 +360,11 @@ class HTMLPurifier_Config
} }
// check to see if the value is allowed // check to see if the value is allowed
if (isset($def->allowed) && !isset($def->allowed[$value])) { if (isset($def->allowed) && !isset($def->allowed[$value])) {
$this->triggerError('Value not supported, valid values are: ' . $this->triggerError(
$this->_listify($def->allowed), E_USER_WARNING); 'Value not supported, valid values are: ' .
$this->_listify($def->allowed),
E_USER_WARNING
);
return; return;
} }
} }
@@ -308,63 +382,83 @@ class HTMLPurifier_Config
/** /**
* Convenience function for error reporting * Convenience function for error reporting
*
* @param array $lookup
*
* @return string
*/ */
private function _listify($lookup) { private function _listify($lookup)
{
$list = array(); $list = array();
foreach ($lookup as $name => $b) $list[] = $name; foreach ($lookup as $name => $b) {
$list[] = $name;
}
return implode(', ', $list); return implode(', ', $list);
} }
/** /**
* Retrieves object reference to the HTML definition. * Retrieves object reference to the HTML definition.
* @param $raw Return a copy that has not been setup yet. Must be *
* @param bool $raw Return a copy that has not been setup yet. Must be
* called before it's been setup, otherwise won't work. * called before it's been setup, otherwise won't work.
* @param $optimized If true, this method may return null, to * @param bool $optimized If true, this method may return null, to
* indicate that a cached version of the modified * indicate that a cached version of the modified
* definition object is available and no further edits * definition object is available and no further edits
* are necessary. Consider using * are necessary. Consider using
* maybeGetRawHTMLDefinition, which is more explicitly * maybeGetRawHTMLDefinition, which is more explicitly
* named, instead. * named, instead.
*
* @return HTMLPurifier_HTMLDefinition
*/ */
public function getHTMLDefinition($raw = false, $optimized = false) { public function getHTMLDefinition($raw = false, $optimized = false)
{
return $this->getDefinition('HTML', $raw, $optimized); return $this->getDefinition('HTML', $raw, $optimized);
} }
/** /**
* Retrieves object reference to the CSS definition * Retrieves object reference to the CSS definition
* @param $raw Return a copy that has not been setup yet. Must be *
* @param bool $raw Return a copy that has not been setup yet. Must be
* called before it's been setup, otherwise won't work. * called before it's been setup, otherwise won't work.
* @param $optimized If true, this method may return null, to * @param bool $optimized If true, this method may return null, to
* indicate that a cached version of the modified * indicate that a cached version of the modified
* definition object is available and no further edits * definition object is available and no further edits
* are necessary. Consider using * are necessary. Consider using
* maybeGetRawCSSDefinition, which is more explicitly * maybeGetRawCSSDefinition, which is more explicitly
* named, instead. * named, instead.
*
* @return HTMLPurifier_CSSDefinition
*/ */
public function getCSSDefinition($raw = false, $optimized = false) { public function getCSSDefinition($raw = false, $optimized = false)
{
return $this->getDefinition('CSS', $raw, $optimized); return $this->getDefinition('CSS', $raw, $optimized);
} }
/** /**
* Retrieves object reference to the URI definition * Retrieves object reference to the URI definition
* @param $raw Return a copy that has not been setup yet. Must be *
* @param bool $raw Return a copy that has not been setup yet. Must be
* called before it's been setup, otherwise won't work. * called before it's been setup, otherwise won't work.
* @param $optimized If true, this method may return null, to * @param bool $optimized If true, this method may return null, to
* indicate that a cached version of the modified * indicate that a cached version of the modified
* definition object is available and no further edits * definition object is available and no further edits
* are necessary. Consider using * are necessary. Consider using
* maybeGetRawURIDefinition, which is more explicitly * maybeGetRawURIDefinition, which is more explicitly
* named, instead. * named, instead.
*
* @return HTMLPurifier_URIDefinition
*/ */
public function getURIDefinition($raw = false, $optimized = false) { public function getURIDefinition($raw = false, $optimized = false)
{
return $this->getDefinition('URI', $raw, $optimized); return $this->getDefinition('URI', $raw, $optimized);
} }
/** /**
* Retrieves a definition * Retrieves a definition
* @param $type Type of definition: HTML, CSS, etc *
* @param $raw Whether or not definition should be returned raw * @param string $type Type of definition: HTML, CSS, etc
* @param $optimized Only has an effect when $raw is true. Whether * @param bool $raw Whether or not definition should be returned raw
* @param bool $optimized Only has an effect when $raw is true. Whether
* or not to return null if the result is already present in * or not to return null if the result is already present in
* the cache. This is off by default for backwards * the cache. This is off by default for backwards
* compatibility reasons, but you need to do things this * compatibility reasons, but you need to do things this
@@ -372,12 +466,18 @@ class HTMLPurifier_Config
* Check out enduser-customize.html for more details. * Check out enduser-customize.html for more details.
* We probably won't ever change this default, as much as the * We probably won't ever change this default, as much as the
* maybe semantics is the "right thing to do." * maybe semantics is the "right thing to do."
*
* @throws HTMLPurifier_Exception
* @return HTMLPurifier_Definition
*/ */
public function getDefinition($type, $raw = false, $optimized = false) { public function getDefinition($type, $raw = false, $optimized = false)
{
if ($optimized && !$raw) { if ($optimized && !$raw) {
throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false"); throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false");
} }
if (!$this->finalized) $this->autoFinalize(); if (!$this->finalized) {
$this->autoFinalize();
}
// temporarily suspend locks, so we can handle recursive definition calls // temporarily suspend locks, so we can handle recursive definition calls
$lock = $this->lock; $lock = $this->lock;
$this->lock = null; $this->lock = null;
@@ -395,7 +495,9 @@ class HTMLPurifier_Config
return $def; return $def;
} else { } else {
$def->setup($this); $def->setup($this);
if ($def->optimized) $cache->add($def, $this); if ($def->optimized) {
$cache->add($def, $this);
}
return $def; return $def;
} }
} }
@@ -424,23 +526,36 @@ class HTMLPurifier_Config
if ($optimized) { if ($optimized) {
if (is_null($this->get($type . '.DefinitionID'))) { if (is_null($this->get($type . '.DefinitionID'))) {
// fatally error out if definition ID not set // fatally error out if definition ID not set
throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID"); throw new HTMLPurifier_Exception(
"Cannot retrieve raw version without specifying %$type.DefinitionID"
);
} }
} }
if (!empty($this->definitions[$type])) { if (!empty($this->definitions[$type])) {
$def = $this->definitions[$type]; $def = $this->definitions[$type];
if ($def->setup && !$optimized) { if ($def->setup && !$optimized) {
$extra = $this->chatty ? " (try moving this code block earlier in your initialization)" : ""; $extra = $this->chatty ?
throw new HTMLPurifier_Exception("Cannot retrieve raw definition after it has already been setup" . $extra); " (try moving this code block earlier in your initialization)" :
"";
throw new HTMLPurifier_Exception(
"Cannot retrieve raw definition after it has already been setup" .
$extra
);
} }
if ($def->optimized === null) { if ($def->optimized === null) {
$extra = $this->chatty ? " (try flushing your cache)" : ""; $extra = $this->chatty ? " (try flushing your cache)" : "";
throw new HTMLPurifier_Exception("Optimization status of definition is unknown" . $extra); throw new HTMLPurifier_Exception(
"Optimization status of definition is unknown" . $extra
);
} }
if ($def->optimized !== $optimized) { if ($def->optimized !== $optimized) {
$msg = $optimized ? "optimized" : "unoptimized"; $msg = $optimized ? "optimized" : "unoptimized";
$extra = $this->chatty ? " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)" : ""; $extra = $this->chatty ?
throw new HTMLPurifier_Exception("Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra); " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)"
: "";
throw new HTMLPurifier_Exception(
"Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra
);
} }
} }
// check if definition was in memory // check if definition was in memory
@@ -473,9 +588,22 @@ class HTMLPurifier_Config
if (!$optimized) { if (!$optimized) {
if (!is_null($this->get($type . '.DefinitionID'))) { if (!is_null($this->get($type . '.DefinitionID'))) {
if ($this->chatty) { if ($this->chatty) {
$this->triggerError("Due to a documentation error in previous version of HTML Purifier, your definitions are not being cached. If this is OK, you can remove the %$type.DefinitionRev and %$type.DefinitionID declaration. Otherwise, modify your code to use maybeGetRawDefinition, and test if the returned value is null before making any edits (if it is null, that means that a cached version is available, and no raw operations are necessary). See <a href='http://htmlpurifier.org/docs/enduser-customize.html#optimized'>Customize</a> for more details", E_USER_WARNING); $this->triggerError(
'Due to a documentation error in previous version of HTML Purifier, your ' .
'definitions are not being cached. If this is OK, you can remove the ' .
'%$type.DefinitionRev and %$type.DefinitionID declaration. Otherwise, ' .
'modify your code to use maybeGetRawDefinition, and test if the returned ' .
'value is null before making any edits (if it is null, that means that a ' .
'cached version is available, and no raw operations are necessary). See ' .
'<a href="http://htmlpurifier.org/docs/enduser-customize.html#optimized">' .
'Customize</a> for more details',
E_USER_WARNING
);
} else { } else {
$this->triggerError("Useless DefinitionID declaration", E_USER_WARNING); $this->triggerError(
"Useless DefinitionID declaration",
E_USER_WARNING
);
} }
} }
} }
@@ -487,7 +615,16 @@ class HTMLPurifier_Config
throw new HTMLPurifier_Exception("The impossible happened!"); throw new HTMLPurifier_Exception("The impossible happened!");
} }
private function initDefinition($type) { /**
* Initialise definition
*
* @param string $type What type of definition to create
*
* @return HTMLPurifier_CSSDefinition|HTMLPurifier_HTMLDefinition|HTMLPurifier_URIDefinition
* @throws HTMLPurifier_Exception
*/
private function initDefinition($type)
{
// quick checks failed, let's create the object // quick checks failed, let's create the object
if ($type == 'HTML') { if ($type == 'HTML') {
$def = new HTMLPurifier_HTMLDefinition(); $def = new HTMLPurifier_HTMLDefinition();
@@ -496,35 +633,45 @@ class HTMLPurifier_Config
} elseif ($type == 'URI') { } elseif ($type == 'URI') {
$def = new HTMLPurifier_URIDefinition(); $def = new HTMLPurifier_URIDefinition();
} else { } else {
throw new HTMLPurifier_Exception("Definition of $type type not supported"); throw new HTMLPurifier_Exception(
"Definition of $type type not supported"
);
} }
$this->definitions[$type] = $def; $this->definitions[$type] = $def;
return $def; return $def;
} }
public function maybeGetRawDefinition($name) { public function maybeGetRawDefinition($name)
{
return $this->getDefinition($name, true, true); return $this->getDefinition($name, true, true);
} }
public function maybeGetRawHTMLDefinition() { public function maybeGetRawHTMLDefinition()
{
return $this->getDefinition('HTML', true, true); return $this->getDefinition('HTML', true, true);
} }
public function maybeGetRawCSSDefinition() { public function maybeGetRawCSSDefinition()
{
return $this->getDefinition('CSS', true, true); return $this->getDefinition('CSS', true, true);
} }
public function maybeGetRawURIDefinition() { public function maybeGetRawURIDefinition()
{
return $this->getDefinition('URI', true, true); return $this->getDefinition('URI', true, true);
} }
/** /**
* Loads configuration values from an array with the following structure: * Loads configuration values from an array with the following structure:
* Namespace.Directive => Value * Namespace.Directive => Value
* @param $config_array Configuration associative array *
* @param array $config_array Configuration associative array
*/ */
public function loadArray($config_array) { public function loadArray($config_array)
if ($this->isFinalized('Cannot load directives after finalization')) return; {
if ($this->isFinalized('Cannot load directives after finalization')) {
return;
}
foreach ($config_array as $key => $value) { foreach ($config_array as $key => $value) {
$key = str_replace('_', '.', $key); $key = str_replace('_', '.', $key);
if (strpos($key, '.') !== false) { if (strpos($key, '.') !== false) {
@@ -532,8 +679,8 @@ class HTMLPurifier_Config
} else { } else {
$namespace = $key; $namespace = $key;
$namespace_values = $value; $namespace_values = $value;
foreach ($namespace_values as $directive => $value) { foreach ($namespace_values as $directive => $value2) {
$this->set($namespace .'.'. $directive, $value); $this->set($namespace .'.'. $directive, $value2);
} }
} }
} }
@@ -543,40 +690,55 @@ class HTMLPurifier_Config
* Returns a list of array(namespace, directive) for all directives * Returns a list of array(namespace, directive) for all directives
* that are allowed in a web-form context as per an allowed * that are allowed in a web-form context as per an allowed
* namespaces/directives list. * namespaces/directives list.
* @param $allowed List of allowed namespaces/directives *
* @param array $allowed List of allowed namespaces/directives
* @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy
*
* @return array
*/ */
public static function getAllowedDirectivesForForm($allowed, $schema = null) { public static function getAllowedDirectivesForForm($allowed, $schema = null)
{
if (!$schema) { if (!$schema) {
$schema = HTMLPurifier_ConfigSchema::instance(); $schema = HTMLPurifier_ConfigSchema::instance();
} }
if ($allowed !== true) { if ($allowed !== true) {
if (is_string($allowed)) $allowed = array($allowed); if (is_string($allowed)) {
$allowed_ns = array(); $allowed = array($allowed);
$allowed_directives = array(); }
$blacklisted_directives = array(); $allowed_ns = array();
foreach ($allowed as $ns_or_directive) { $allowed_directives = array();
if (strpos($ns_or_directive, '.') !== false) { $blacklisted_directives = array();
// directive foreach ($allowed as $ns_or_directive) {
if ($ns_or_directive[0] == '-') { if (strpos($ns_or_directive, '.') !== false) {
$blacklisted_directives[substr($ns_or_directive, 1)] = true; // directive
} else { if ($ns_or_directive[0] == '-') {
$allowed_directives[$ns_or_directive] = true; $blacklisted_directives[substr($ns_or_directive, 1)] = true;
} } else {
} else { $allowed_directives[$ns_or_directive] = true;
// namespace }
$allowed_ns[$ns_or_directive] = true; } else {
} // namespace
} $allowed_ns[$ns_or_directive] = true;
}
}
} }
$ret = array(); $ret = array();
foreach ($schema->info as $key => $def) { foreach ($schema->info as $key => $def) {
list($ns, $directive) = explode('.', $key, 2); list($ns, $directive) = explode('.', $key, 2);
if ($allowed !== true) { if ($allowed !== true) {
if (isset($blacklisted_directives["$ns.$directive"])) continue; if (isset($blacklisted_directives["$ns.$directive"])) {
if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue; continue;
}
if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) {
continue;
}
}
if (isset($def->isAlias)) {
continue;
}
if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') {
continue;
} }
if (isset($def->isAlias)) continue;
if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue;
$ret[] = array($ns, $directive); $ret[] = array($ns, $directive);
} }
return $ret; return $ret;
@@ -585,13 +747,17 @@ class HTMLPurifier_Config
/** /**
* Loads configuration values from $_GET/$_POST that were posted * Loads configuration values from $_GET/$_POST that were posted
* via ConfigForm * via ConfigForm
* @param $array $_GET or $_POST array to import *
* @param $index Index/name that the config variables are in * @param array $array $_GET or $_POST array to import
* @param $allowed List of allowed namespaces/directives * @param string|bool $index Index/name that the config variables are in
* @param $mq_fix Boolean whether or not to enable magic quotes fix * @param array|bool $allowed List of allowed namespaces/directives
* @param $schema Instance of HTMLPurifier_ConfigSchema to use, if not global copy * @param bool $mq_fix Boolean whether or not to enable magic quotes fix
* @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy
*
* @return mixed
*/ */
public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) { public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null)
{
$ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema); $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema);
$config = HTMLPurifier_Config::create($ret, $schema); $config = HTMLPurifier_Config::create($ret, $schema);
return $config; return $config;
@@ -599,9 +765,14 @@ class HTMLPurifier_Config
/** /**
* Merges in configuration values from $_GET/$_POST to object. NOT STATIC. * Merges in configuration values from $_GET/$_POST to object. NOT STATIC.
* @note Same parameters as loadArrayFromForm *
* @param array $array $_GET or $_POST array to import
* @param string|bool $index Index/name that the config variables are in
* @param array|bool $allowed List of allowed namespaces/directives
* @param bool $mq_fix Boolean whether or not to enable magic quotes fix
*/ */
public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) { public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true)
{
$ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def); $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def);
$this->loadArray($ret); $this->loadArray($ret);
} }
@@ -609,9 +780,20 @@ class HTMLPurifier_Config
/** /**
* Prepares an array from a form into something usable for the more * Prepares an array from a form into something usable for the more
* strict parts of HTMLPurifier_Config * strict parts of HTMLPurifier_Config
*
* @param array $array $_GET or $_POST array to import
* @param string|bool $index Index/name that the config variables are in
* @param array|bool $allowed List of allowed namespaces/directives
* @param bool $mq_fix Boolean whether or not to enable magic quotes fix
* @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy
*
* @return array
*/ */
public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) { public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null)
if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); {
if ($index !== false) {
$array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
}
$mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc();
$allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema); $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema);
@@ -623,7 +805,9 @@ class HTMLPurifier_Config
$ret[$ns][$directive] = null; $ret[$ns][$directive] = null;
continue; continue;
} }
if (!isset($array[$skey])) continue; if (!isset($array[$skey])) {
continue;
}
$value = $mq ? stripslashes($array[$skey]) : $array[$skey]; $value = $mq ? stripslashes($array[$skey]) : $array[$skey];
$ret[$ns][$directive] = $value; $ret[$ns][$directive] = $value;
} }
@@ -632,19 +816,27 @@ class HTMLPurifier_Config
/** /**
* Loads configuration values from an ini file * Loads configuration values from an ini file
* @param $filename Name of ini file *
* @param string $filename Name of ini file
*/ */
public function loadIni($filename) { public function loadIni($filename)
if ($this->isFinalized('Cannot load directives after finalization')) return; {
if ($this->isFinalized('Cannot load directives after finalization')) {
return;
}
$array = parse_ini_file($filename, true); $array = parse_ini_file($filename, true);
$this->loadArray($array); $this->loadArray($array);
} }
/** /**
* Checks whether or not the configuration object is finalized. * Checks whether or not the configuration object is finalized.
* @param $error String error message, or false for no error *
* @param string|bool $error String error message, or false for no error
*
* @return bool
*/ */
public function isFinalized($error = false) { public function isFinalized($error = false)
{
if ($this->finalized && $error) { if ($this->finalized && $error) {
$this->triggerError($error, E_USER_ERROR); $this->triggerError($error, E_USER_ERROR);
} }
@@ -655,7 +847,8 @@ class HTMLPurifier_Config
* Finalizes configuration only if auto finalize is on and not * Finalizes configuration only if auto finalize is on and not
* already finalized * already finalized
*/ */
public function autoFinalize() { public function autoFinalize()
{
if ($this->autoFinalize) { if ($this->autoFinalize) {
$this->finalize(); $this->finalize();
} else { } else {
@@ -666,7 +859,8 @@ class HTMLPurifier_Config
/** /**
* Finalizes a configuration object, prohibiting further change * Finalizes a configuration object, prohibiting further change
*/ */
public function finalize() { public function finalize()
{
$this->finalized = true; $this->finalized = true;
$this->parser = null; $this->parser = null;
} }
@@ -674,8 +868,12 @@ class HTMLPurifier_Config
/** /**
* Produces a nicely formatted error message by supplying the * Produces a nicely formatted error message by supplying the
* stack frame information OUTSIDE of HTMLPurifier_Config. * stack frame information OUTSIDE of HTMLPurifier_Config.
*
* @param string $msg An error message
* @param int $no An error number
*/ */
protected function triggerError($msg, $no) { protected function triggerError($msg, $no)
{
// determine previous stack frame // determine previous stack frame
$extra = ''; $extra = '';
if ($this->chatty) { if ($this->chatty) {
@@ -697,8 +895,11 @@ class HTMLPurifier_Config
/** /**
* Returns a serialized form of the configuration object that can * Returns a serialized form of the configuration object that can
* be reconstituted. * be reconstituted.
*
* @return string
*/ */
public function serialize() { public function serialize()
{
$this->getDefinition('HTML'); $this->getDefinition('HTML');
$this->getDefinition('CSS'); $this->getDefinition('CSS');
$this->getDefinition('URI'); $this->getDefinition('URI');

View File

@@ -3,21 +3,24 @@
/** /**
* Configuration definition, defines directives and their defaults. * Configuration definition, defines directives and their defaults.
*/ */
class HTMLPurifier_ConfigSchema { class HTMLPurifier_ConfigSchema
{
/** /**
* Defaults of the directives and namespaces. * Defaults of the directives and namespaces.
* @type array
* @note This shares the exact same structure as HTMLPurifier_Config::$conf * @note This shares the exact same structure as HTMLPurifier_Config::$conf
*/ */
public $defaults = array(); public $defaults = array();
/** /**
* The default property list. Do not edit this property list. * The default property list. Do not edit this property list.
* @type array
*/ */
public $defaultPlist; public $defaultPlist;
/** /**
* Definition of the directives. The structure of this is: * Definition of the directives.
* The structure of this is:
* *
* array( * array(
* 'Namespace' => array( * 'Namespace' => array(
@@ -44,22 +47,27 @@ class HTMLPurifier_ConfigSchema {
* This class is friendly with HTMLPurifier_Config. If you need introspection * This class is friendly with HTMLPurifier_Config. If you need introspection
* about the schema, you're better of using the ConfigSchema_Interchange, * about the schema, you're better of using the ConfigSchema_Interchange,
* which uses more memory but has much richer information. * which uses more memory but has much richer information.
* @type array
*/ */
public $info = array(); public $info = array();
/** /**
* Application-wide singleton * Application-wide singleton
* @type HTMLPurifier_ConfigSchema
*/ */
static protected $singleton; protected static $singleton;
public function __construct() { public function __construct()
{
$this->defaultPlist = new HTMLPurifier_PropertyList(); $this->defaultPlist = new HTMLPurifier_PropertyList();
} }
/** /**
* Unserializes the default ConfigSchema. * Unserializes the default ConfigSchema.
* @return HTMLPurifier_ConfigSchema
*/ */
public static function makeFromSerial() { public static function makeFromSerial()
{
$contents = file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser'); $contents = file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser');
$r = unserialize($contents); $r = unserialize($contents);
if (!$r) { if (!$r) {
@@ -71,8 +79,11 @@ class HTMLPurifier_ConfigSchema {
/** /**
* Retrieves an instance of the application-wide configuration definition. * Retrieves an instance of the application-wide configuration definition.
* @param HTMLPurifier_ConfigSchema $prototype
* @return HTMLPurifier_ConfigSchema
*/ */
public static function instance($prototype = null) { public static function instance($prototype = null)
{
if ($prototype !== null) { if ($prototype !== null) {
HTMLPurifier_ConfigSchema::$singleton = $prototype; HTMLPurifier_ConfigSchema::$singleton = $prototype;
} elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) { } elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) {
@@ -86,17 +97,19 @@ class HTMLPurifier_ConfigSchema {
* @warning Will fail of directive's namespace is defined. * @warning Will fail of directive's namespace is defined.
* @warning This method's signature is slightly different from the legacy * @warning This method's signature is slightly different from the legacy
* define() static method! Beware! * define() static method! Beware!
* @param $namespace Namespace the directive is in * @param string $key Name of directive
* @param $name Key of directive * @param mixed $default Default value of directive
* @param $default Default value of directive * @param string $type Allowed type of the directive. See
* @param $type Allowed type of the directive. See
* HTMLPurifier_DirectiveDef::$type for allowed values * HTMLPurifier_DirectiveDef::$type for allowed values
* @param $allow_null Whether or not to allow null values * @param bool $allow_null Whether or not to allow null values
*/ */
public function add($key, $default, $type, $allow_null) { public function add($key, $default, $type, $allow_null)
{
$obj = new stdclass(); $obj = new stdclass();
$obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type]; $obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type];
if ($allow_null) $obj->allow_null = true; if ($allow_null) {
$obj->allow_null = true;
}
$this->info[$key] = $obj; $this->info[$key] = $obj;
$this->defaults[$key] = $default; $this->defaults[$key] = $default;
$this->defaultPlist->set($key, $default); $this->defaultPlist->set($key, $default);
@@ -107,11 +120,11 @@ class HTMLPurifier_ConfigSchema {
* *
* Directive value aliases are convenient for developers because it lets * Directive value aliases are convenient for developers because it lets
* them set a directive to several values and get the same result. * them set a directive to several values and get the same result.
* @param $namespace Directive's namespace * @param string $key Name of Directive
* @param $name Name of Directive * @param array $aliases Hash of aliased values to the real alias
* @param $aliases Hash of aliased values to the real alias
*/ */
public function addValueAliases($key, $aliases) { public function addValueAliases($key, $aliases)
{
if (!isset($this->info[$key]->aliases)) { if (!isset($this->info[$key]->aliases)) {
$this->info[$key]->aliases = array(); $this->info[$key]->aliases = array();
} }
@@ -124,22 +137,21 @@ class HTMLPurifier_ConfigSchema {
* Defines a set of allowed values for a directive. * Defines a set of allowed values for a directive.
* @warning This is slightly different from the corresponding static * @warning This is slightly different from the corresponding static
* method definition. * method definition.
* @param $namespace Namespace of directive * @param string $key Name of directive
* @param $name Name of directive * @param array $allowed Lookup array of allowed values
* @param $allowed Lookup array of allowed values
*/ */
public function addAllowedValues($key, $allowed) { public function addAllowedValues($key, $allowed)
{
$this->info[$key]->allowed = $allowed; $this->info[$key]->allowed = $allowed;
} }
/** /**
* Defines a directive alias for backwards compatibility * Defines a directive alias for backwards compatibility
* @param $namespace * @param string $key Directive that will be aliased
* @param $name Directive that will be aliased * @param string $new_key Directive that the alias will be to
* @param $new_namespace
* @param $new_name Directive that the alias will be to
*/ */
public function addAlias($key, $new_key) { public function addAlias($key, $new_key)
{
$obj = new stdclass; $obj = new stdclass;
$obj->key = $new_key; $obj->key = $new_key;
$obj->isAlias = true; $obj->isAlias = true;
@@ -149,7 +161,8 @@ class HTMLPurifier_ConfigSchema {
/** /**
* Replaces any stdclass that only has the type property with type integer. * Replaces any stdclass that only has the type property with type integer.
*/ */
public function postProcess() { public function postProcess()
{
foreach ($this->info as $key => $v) { foreach ($this->info as $key => $v) {
if (count((array) $v) == 1) { if (count((array) $v) == 1) {
$this->info[$key] = $v->type; $this->info[$key] = $v->type;
@@ -158,7 +171,6 @@ class HTMLPurifier_ConfigSchema {
} }
} }
} }
} }
// vim: et sw=4 sts=4 // vim: et sw=4 sts=4

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