You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
6.0KB

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  3. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  4. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  6. <meta name="description" content="Explains various methods for allowing IDs in documents safely in HTML Purifier." />
  7. <link rel="stylesheet" type="text/css" href="./style.css" />
  8. <title>IDs - HTML Purifier</title>
  9. </head><body>
  10. <h1 class="subtitled">IDs</h1>
  11. <div class="subtitle">What they are, why you should(n't) wear them, and how to deal with it</div>
  12. <div id="filing">Filed under End-User</div>
  13. <div id="index">Return to the <a href="index.html">index</a>.</div>
  14. <div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
  15. <p>Prior to HTML Purifier 1.2.0, this library blithely accepted user input that
  16. looked like this:</p>
  17. <pre>&lt;a id=&quot;fragment&quot;&gt;Anchor&lt;/a&gt;</pre>
  18. <p>...presenting an attractive vector for those that would destroy standards
  19. compliance: simply set the ID to one that is already used elsewhere in the
  20. document and voila: validation breaks. There was a half-hearted attempt to
  21. prevent this by allowing users to blacklist IDs, but I suspect that no one
  22. really bothered, and thus, with the release of 1.2.0, IDs are now <em>removed</em>
  23. by default.</p>
  24. <p>IDs, however, are quite useful functionality to have, so if users start
  25. complaining about broken anchors you'll probably want to turn them back on
  26. with %Attr.EnableID. But before you go mucking around with the config
  27. object, it's probably worth to take some precautions to keep your page
  28. validating. Why?</p>
  29. <ol>
  30. <li>Standards-compliant pages are good</li>
  31. <li>Duplicated IDs interfere with anchors. If there are two id="foobar"s in a
  32. document, which spot does a browser presented with the fragment #foobar go
  33. to? Most browsers opt for the first appearing ID, making it impossible
  34. to references the second section. Similarly, duplicated IDs can hijack
  35. client-side scripting that relies on the IDs of elements.</li>
  36. </ol>
  37. <p>You have (currently) four ways of dealing with the problem.</p>
  38. <h2 class="subtitled">Blacklisting IDs</h2>
  39. <div class="subsubtitle">Good for pages with single content source and stable templates</div>
  40. <p>Keeping in terms with the
  41. <acronym title="Keep It Simple, Stupid">KISS</acronym> principle, let us
  42. deal with the most obvious solution: preventing users from using any IDs that
  43. appear elsewhere on the document. The method is simple:</p>
  44. <pre>$config-&gt;set('Attr.EnableID', true);
  45. $config-&gt;set('Attr.IDBlacklist' array(
  46. 'list', 'of', 'attribute', 'values', 'that', 'are', 'forbidden'
  47. ));</pre>
  48. <p>That being said, there are some notable drawbacks. First of all, you have to
  49. know precisely which IDs are being used by the HTML surrounding the user code.
  50. This is easier said than done: quite often the page designer and the system
  51. coder work separately, so the designer has to constantly be talking with the
  52. coder whenever he decides to add a new anchor. Miss one and you open yourself
  53. to possible standards-compliance issues.</p>
  54. <p>Furthermore, this position becomes untenable when a single web page must hold
  55. multiple portions of user-submitted content. Since there's obviously no way
  56. to find out before-hand what IDs users will use, the blacklist is helpless.
  57. And since HTML Purifier validates each segment separately, perhaps doing
  58. so at different times, it would be extremely difficult to dynamically update
  59. the blacklist in between runs.</p>
  60. <p>Finally, simply destroying the ID is extremely un-userfriendly behavior: after
  61. all, they might have simply specified a duplicate ID by accident.</p>
  62. <p>Thus, we get to our second method.</p>
  63. <h2 class="subtitled">Namespacing IDs</h2>
  64. <div class="subsubtitle">Lazy developer's way, but needs user education</div>
  65. <p>This method, too, is quite simple: add a prefix to all user IDs. With this
  66. code:</p>
  67. <pre>$config-&gt;set('Attr.EnableID', true);
  68. $config-&gt;set('Attr.IDPrefix', 'user_');</pre>
  69. <p>...this:</p>
  70. <pre>&lt;a id=&quot;foobar&quot;&gt;Anchor!&lt;/a&gt;</pre>
  71. <p>...turns into:</p>
  72. <pre>&lt;a id=&quot;user_foobar&quot;&gt;Anchor!&lt;/a&gt;</pre>
  73. <p>As long as you don't have any IDs that start with user_, collisions are
  74. guaranteed not to happen. The drawback is obvious: if a user submits
  75. id=&quot;foobar&quot;, they probably expect to be able to reference their page with
  76. #foobar. You'll have to tell them, &quot;No, that doesn't work, you have to add
  77. user_ to the beginning.&quot;</p>
  78. <p>And yes, things get hairier. Even with a nice prefix, we still have done
  79. nothing about multiple HTML Purifier outputs on one page. Thus, we have
  80. a second configuration value to piggy-back off of: %Attr.IDPrefixLocal:</p>
  81. <pre>$config-&gt;set('Attr.IDPrefixLocal', 'comment' . $id . '_');</pre>
  82. <p>This new attributes does nothing but append on to regular IDPrefix, but is
  83. special in that it is volatile: it's value is determined at run-time and
  84. cannot possibly be cordoned into, say, a .ini config file. As for what to
  85. put into the directive, is up to you, but I would recommend the ID number
  86. the text has been assigned in the database. Whatever you pick, however, it
  87. has to be unique and stable for the text you are validating. Note, however,
  88. that we require that %Attr.IDPrefix be set before you use this directive.</p>
  89. <p>And also remember: the user has to know what this prefix is too!</p>
  90. <h2>Abstinence</h2>
  91. <p>You may not want to bother. That's okay too, just don't enable IDs.</p>
  92. <p>Personally, I would take this road whenever user-submitted content would be
  93. possibly be shown together on one page. Why a blog comment would need to use
  94. anchors is beyond me.</p>
  95. <h2>Denial</h2>
  96. <p>To revert back to pre-1.2.0 behavior, simply:</p>
  97. <pre>$config-&gt;set('Attr.EnableID', true);</pre>
  98. <p>Don't come crying to me when your page mysteriously stops validating, though.</p>
  99. </body>
  100. </html>
  101. <!-- vim: et sw=4 sts=4
  102. -->