HTML Purifier: удаление элемента условно на основе его атрибутов - PullRequest
4 голосов
/ 14 апреля 2010

В соответствии с тестом на очиститель HTML , «неправильно сформированные» URI иногда отбрасываются, оставляя после себя тег без привязки, например

<a href="javascript:document.location='http://www.google.com/'">XSS</a> становится <a>XSS</a>

... а также время от времени сокращаются до протокола, например

<a href="http://1113982867/">XSS</a> становится <a href="http:/">XSS</a>

Хотя это без проблем, само по себе это немного уродливо. Вместо того чтобы пытаться избавиться от них с помощью регулярных выражений, я надеялся использовать собственные возможности библиотеки HTML Purifier / injectors / plug-ins / whathaveyou.

Точка отсчета: Обработка атрибутов

Условное удаление атрибута в HTMLPurifier легко. Здесь библиотека предлагает класс HTMLPurifier_AttrTransform с методом confiscateAttr().

Хотя я лично не использую функциональность confiscateAttr(), я использую HTMLPurifier_AttrTransform согласно этой теме , чтобы добавить target="_blank" ко всем якорям.

// more configuration stuff up here
$htmlDef = $htmlPurifierConfiguration->getHTMLDefinition(true);
$anchor  = $htmlDef->addBlankElement('a');
$anchor->attr_transform_post[] = new HTMLPurifier_AttrTransform_Target();
// purify down here

HTMLPurifier_AttrTransform_Target очень простой класс, конечно.

class HTMLPurifier_AttrTransform_Target extends HTMLPurifier_AttrTransform
{
    public function transform($attr, $config, $context) {
        // I could call $this->confiscateAttr() here to throw away an
        // undesired attribute
        $attr['target'] = '_blank';
        return $attr;
    }
}

Эта часть, естественно, работает как шарм.

Элементы обработки

Возможно, я недостаточно щурился на HTMLPurifier_TagTransform, или смотрю не в том месте (ах), или вообще не понимаю, но я не могу найти способ условно удалить элементы .

Скажите, что-то с эффектом:

// more configuration stuff up here
$htmlDef = $htmlPurifierConfiguration->getHTMLDefinition(true);
$anchor  = $htmlDef->addElementHandler('a');
$anchor->elem_transform_post[] = new HTMLPurifier_ElementTransform_Cull();
// add target as per 'point of reference' here
// purify down here

С классом Cull, расширяющим что-то, обладающее способностью confiscateElement() или сопоставимым, в котором я мог бы проверить отсутствие атрибута href или атрибута href с содержимым http:/.

HTMLPurifier_Filter

Я понимаю, что мог бы создать фильтр, но примеры (Youtube.php и ExtractStyleBlocks.php) предполагают, что в этом я бы использовал регулярные выражения, которых я действительно предпочел бы избежать, , если это вообще так. возможно . Я надеюсь на встроенное или квази-встроенное решение, которое использует превосходные возможности парсинга HTML Purifier.

Возвращение null в дочернем классе HTMLPurifier_AttrTransform, к сожалению, не сокращает его.

У кого-нибудь есть какие-нибудь умные идеи, или я застрял в регулярных выражениях? :)

Ответы [ 3 ]

5 голосов
/ 19 апреля 2010

Успех! Благодаря Ambush Commander и mcgrailm в другом вопросе , теперь я использую очень простое решение:

// a bit of context
$htmlDef = $this->configuration->getHTMLDefinition(true);
$anchor  = $htmlDef->addBlankElement('a');

// HTMLPurifier_AttrTransform_RemoveLoneHttp strips 'href="http:/"' from
// all anchor tags (see first post for class detail)
$anchor->attr_transform_post[] = new HTMLPurifier_AttrTransform_RemoveLoneHttp();

// this is the magic! We're making 'href' a required attribute (note the
// asterisk) - now HTML Purifier removes <a></a>, as well as
// <a href="http:/"></a> after HTMLPurifier_AttrTransform_RemoveLoneHttp
// is through with it!
$htmlDef->addAttribute('a', 'href*', new HTMLPurifier_AttrDef_URI());

Это работает, это работает , bahahahaHAHAHAHAnhͥͤͫ̀ğͮ͑̆ͦó̓̉ͬ͋h́ͧ̆̈́̉ğ̈́͐̈a̾̈́̑ͨô̔̄̑̇g̀̄h̘̝͊̐ͩͥ̋ͤ͛g̦̣̙̙̒̀ͥ̐̔ͅo̤̣h͖̩̯̥͕͓̘̝͂̈̐ͮ̒̈͊̐ͩͥ̋ͤ͛͋̇̓́̆a͖̩̯̥͕͂̈̐ͮ̒o̶ͬ̽̀̍ͮ̾ͮ͢҉̩͉̘͓̙̦̩̹͍̹̠̕g̵̡͔̙͉̱̠̙̩͚͑ͥ̎̓͛̋͗̍̽͋͑̈́̚ ... ! * маниакальный смех, булькающие звуки * 101 * * * * * * * * * * * * 0

2 голосов
/ 14 апреля 2010

Тот факт, что вы не можете удалить элементы с помощью TagTransform, кажется, был деталью реализации. Классический механизм удаления узлов (более высокий уровень, чем просто теги) заключается в использовании инжектора.

Как бы то ни было, конкретный компонент, который вы ищете, уже реализован как% AutoFormat.RemoveEmpty

0 голосов
/ 15 апреля 2010

Для прочтения, это мое текущее решение. Это работает, но полностью обходит HTML Purifier.

/**
 * Removes <a></a> and <a href="http:/"></a> tags from the purified
 * HTML.
 * @todo solve this with an injector?
 * @param string $purified The purified HTML
 * @return string The purified HTML, sans pointless anchors.
 */
private function anchorCull($purified)
{
    if (empty($purified)) return '';
    // re-parse HTML
    $domTree = new DOMDocument();
    $domTree->loadHTML($purified);
    // find all anchors (even good ones)
    $anchors = $domTree->getElementsByTagName('a');
    // collect bad anchors (destroying them in this loop breaks the DOM)
    $destroyNodes = array();
    for ($i = 0; ($i < $anchors->length); $i++) {
        $anchor = $anchors->item($i);
        $href   = $anchor->attributes->getNamedItem('href');
        // <a></a>
        if (is_null($href)) {
            $destroyNodes[] = $anchor;
        // <a href="http:/"></a>
        } else if ($href->nodeValue == 'http:/') {
            $destroyNodes[] = $anchor;
        }
    }
    // destroy the collected nodes
    foreach ($destroyNodes as $node) {
        // preserve content
        $retain = $node->childNodes;
        for ($i = 0; ($i < $retain->length); $i++) {
            $rnode = $retain->item($i);
            $node->parentNode->insertBefore($rnode, $node);
        }
        // actually destroy the node
        $node->parentNode->removeChild($node);
    }
    // strip out HTML out of DOM structure string
    $html = $domTree->saveHTML();
    $begin = strpos($html, '<body>') + strlen('<body>');
    $end   = strpos($html, '</body>');
    return substr($html, $begin, $end - $begin);
}

Я бы все-таки предпочел хорошее решение для очистки HTML, поэтому ответ на этот вопрос не будет принят самостоятельно. Но в случае, если не найдется лучшего ответа, по крайней мере, он может помочь тем, у кого похожие проблемы. :)

...