title: HTML Purifier: Removing an element conditionally based on its attributes
body: <p>As per <a href="http://htmlpurifier.org/live/smoketests/xssAttacks.php" rel="nofollow noreferrer">the HTML Purifier smoketest</a>, 'malformed' URIs are occasionally discarded to leave behind an attribute-less anchor tag, e.g.</p>
  
  <p><code>&lt;a href="javascript:document.location='http://www.google.com/'"&gt;XSS&lt;/a&gt;</code> becomes <code>&lt;a&gt;XSS&lt;/a&gt;</code></p>
  
  <p>...as well as occasionally being stripped down to the protocol, e.g.</p>
  
  <p><code>&lt;a href="http://1113982867/"&gt;XSS&lt;/a&gt;</code> becomes <code>&lt;a href="http:/"&gt;XSS&lt;/a&gt;</code></p>
  
  <p>While that's unproblematic, per se, it's a bit ugly. Instead of trying to strip these out with regular expressions, I was hoping to use HTML Purifier's own library capabilities / injectors / plug-ins / whathaveyou.</p>
  
  <h2>Point of reference: Handling attributes</h2>
  
  <p>Conditionally removing an <strong>attribute</strong> in HTMLPurifier is easy. Here the library offers the class <code>HTMLPurifier_AttrTransform</code> with the method <strong><code>confiscateAttr()</code></strong>.</p>
  
  <p>While I don't personally use the functionality of <strong><code>confiscateAttr()</code></strong>, I do use an <code>HTMLPurifier_AttrTransform</code> as per <a href="http://htmlpurifier.org/phorum/read.php?3,4254" rel="nofollow noreferrer">this thread</a> to add <code>target="_blank"</code> to all anchors.</p>
  
  <pre><code>// more configuration stuff up here
  $htmlDef = $htmlPurifierConfiguration-&gt;getHTMLDefinition(true);
  $anchor  = $htmlDef-&gt;addBlankElement('a');
  $anchor-&gt;attr_transform_post[] = new HTMLPurifier_AttrTransform_Target();
  // purify down here
  </code></pre>
  
  <p><code>HTMLPurifier_AttrTransform_Target</code> is a very simple class, of course.</p>
  
  <pre><code>class HTMLPurifier_AttrTransform_Target extends HTMLPurifier_AttrTransform
  {
      public function transform($attr, $config, $context) {
          // I could call $this-&gt;confiscateAttr() here to throw away an
          // undesired attribute
          $attr['target'] = '_blank';
          return $attr;
      }
  }
  </code></pre>
  
  <p>That part works like a charm, naturally.</p>
  
  <h2>Handling elements</h2>
  
  <p>Perhaps I'm not squinting hard enough at <code>HTMLPurifier_TagTransform</code>, or am looking in the wrong place(s), or generally amn't understanding it, but I can't seem to figure out a way to conditionally remove <strong>elements</strong>.</p>
  
  <p>Say, something to the effect of:</p>
  
  <pre><code>// more configuration stuff up here
  $htmlDef = $htmlPurifierConfiguration-&gt;getHTMLDefinition(true);
  $anchor  = $htmlDef-&gt;addElementHandler('a');
  $anchor-&gt;elem_transform_post[] = new HTMLPurifier_ElementTransform_Cull();
  // add target as per 'point of reference' here
  // purify down here
  </code></pre>
  
  <p>With the Cull class extending something that has a <strong><code>confiscateElement()</code></strong> ability, or comparable, wherein I could check for a missing <code>href</code> attribute or a <code>href</code> attribute with the content <code>http:/</code>.</p>
  
  <h2>HTMLPurifier_Filter</h2>
  
  <p>I understand I could create a filter, but the examples (Youtube.php and ExtractStyleBlocks.php) suggest I'd be using regular expressions in that, which I'd really rather avoid, <em>if it is at all possible</em>. I'm hoping for an onboard or quasi-onboard solution that makes use of HTML Purifier's excellent parsing capabilities.</p>
  
  <p>Returning <code>null</code> in a child-class of <code>HTMLPurifier_AttrTransform</code> unfortunately doesn't cut it.</p>
  
  <p>Anyone have any smart ideas, or am I stuck with regexes? :)</p>