PHP конвертировать строку в htmlentities

Как я могу преобразовать код внутри тегов <code> и <pre> в объекты html?

<code class="php"> <div> a div.. </div> </code>

<pre class="php">
<div> a div.. </div>
</pre>

<div> this should be ignored </div>

person Alex    schedule 02.04.2011    source источник
comment
Зависит от контекста. Где находится код? Внутри строки?   -  person Lightness Races in Orbit    schedule 03.04.2011
comment
да, это строковая переменная php   -  person Alex    schedule 03.04.2011
comment
@ Александра, это сложно, потому что вам нужно сначала проанализировать структуру, чтобы отличить части, которые вам нужны, от тех, которые вам не нужны. Почему это смешано таким образом в первую очередь? Можете ли вы повлиять на то, как это генерируется?   -  person Pekka    schedule 03.04.2011
comment
я не могу .. это вывод, когда посетитель публикует комментарий, и я хочу, чтобы они тоже могли публиковать html   -  person Alex    schedule 03.04.2011
comment
@Alexandra Вы не можете просто позволить посетителям публиковать HTML на вашем сайте — это позволяет атакам XSS и позволяет ботам публиковать действительно неприятный спам, невидимый для обычных посетителей, но видимый для ботов поисковых систем.   -  person Kornel    schedule 03.04.2011
comment
Я уверен, что это ОН.. уверен, что он может, он изменит его, как только его взломают.   -  person Dejan Marjanović    schedule 03.04.2011
comment
@webarto: я не он. как меня взломать, если код конвертируется в сущности, а после этого я обдираю тэги из всего комментария (кроме нескольких вроде <a>, <b> и т.д.)?   -  person Alex    schedule 03.04.2011
comment
После того, как вы закончите, не стесняйтесь опубликовать ссылку. Вы можете использовать <php></php>, а затем преобразовать его в тег <code><pre></pre></code>, он короче. Извинения за него, не мое дело.   -  person Dejan Marjanović    schedule 03.04.2011
comment
@Alexandra: Проблема в том, что вы перечисляете теги, которые нельзя использовать, а не теги, которые можно использовать.   -  person Lightness Races in Orbit    schedule 03.04.2011
comment
@Tomalak, но я запускаю функцию тега полосы для всего комментария (после htmlentity), которая удалит любые теги, которых нет в переменной $allowed (которых всего несколько)   -  person Alex    schedule 03.04.2011


Ответы (4)


Хорошо, я играл с этим некоторое время. Результат может быть не самым лучшим или самым прямым решением (и, честно говоря, я полностью не согласен с вашим подходом, если произвольные пользователи собираются отправлять входные данные), но, похоже, он «работает». И, самое главное, он не использует регулярные выражения для разбора XML. :)

Фальсификация ввода

<?php

$str = <<<EOF
<code class="php"> <div> a div.. </div> </code>

<pre class="php">
<div> a div.. </div>
</pre>

<div> this should be ignored </div>
EOF;

?>

Код

<?php

function recurse(&$doc, &$parent) {
   if (!$parent->hasChildNodes())
      return;

   foreach ($parent->childNodes as $elm) {

      if ($elm->nodeName == "code" || $elm->nodeName == "pre") {
         $content = '';
         while ($elm->hasChildNodes()) { // `for` breaks the `removeChild`
             $child = $elm->childNodes->item(0);
             $content .= $doc->saveXML($child);
             $elm->removeChild($child);
         }
         $elm->appendChild($doc->createTextNode($content));
      }
      else {
         recurse($doc, $elm);
      }
   }
}

// Load in the DOM (remembering that XML requires one root node)
$doc = new DOMDocument();
$doc->loadXML("<document>" . $str . "</document>");

// Iterate the DOM, finding <code /> and <pre /> tags:
recurse($doc, $doc->documentElement);

// Output the result
foreach ($doc->childNodes->item(0)->childNodes as $node) {
   echo $doc->saveXML($node);
}

?>

Вывод

<code class="php"> &lt;div&gt; a div.. &lt;/div&gt; </code>

<pre class="php">
&lt;div&gt; a div.. &lt;/div&gt;
</pre>

<div> this should be ignored </div>

Доказательство

Вы можете увидеть, как это работает здесь.

Обратите внимание, что он не вызывает явно htmlspecialchars; объект DOMDocument сам обрабатывает экранирование.

Я надеюсь, что это помогает. :)

person Lightness Races in Orbit    schedule 03.04.2011
comment
Мой код тоже работает... Ваш легко ломается, как и мой. PS Я потратил на 16 минут меньше, чем ты. - person Dejan Marjanović; 03.04.2011
comment
@webarto: Спасибо за ваш неконструктивный комментарий. Не могли бы вы привести пример ввода, который ломает мой код, чтобы я мог его исправить? PS это не пустая трата времени, если вы используете Stack Overflow, чтобы помогать людям. И это 12 минут. - person Lightness Races in Orbit; 03.04.2011
comment
Я только что заметил, что HTML дважды экранируется. Теперь это исправлено. - person Lightness Races in Orbit; 03.04.2011
comment
Это не является неконструктивным (codepad.org/FulWwCbC), это приведет к фатальной ошибке, если вы добавите всего один закрывающий тег, который все равно не открывается, код у тебя красивый, но в реальных ситуациях бесполезен, как и мой. - person Dejan Marjanović; 03.04.2011
comment
@webarto: Конечно, требуется действительный XML. Это предварительное условие, которое, я полагаю, я должен упомянуть в ответе. - person Lightness Races in Orbit; 03.04.2011

Вы можете использовать jQuery. Это будет кодировать что-либо внутри любых тегов с классом code.

$(".code").each(
    function () {
        $(this).text($(this).html()).html();
    }
);

Скрипка: http://jsfiddle.net/mazzzzz/qnbLL/

person Ben    schedule 02.04.2011
comment
+1 Я бы рекомендовал этот подход, если полученный HTML не является небезопасным. - person Christian; 03.04.2011
comment
Этот вопрос касается PHP, а не Javascript. - person Lightness Races in Orbit; 03.04.2011
comment
но как вас могут взломать, если код экранирован? stackoverflow делает то же самое.... - person Alex; 03.04.2011
comment
@Александра: Нет, это не так. Stack Overflow принимает строгое подмножество HTML. Вы отвергаете строгое подмножество HTML. - person Lightness Races in Orbit; 03.04.2011
comment
@Tomalak, но я делаю это только с вещами внутри CODE. в остальной части комментария я удаляю теги так же, как ТАК - person Alex; 03.04.2011
comment
@Tomalak: и к тому, что внутри кода я делаю с сущностью html, так что HTML-тег никак не может пройти, верно? ps: вот что id сделал в конце: заголовок stackoverflow.com/questions/5527574/ - person Alex; 03.04.2011

PHP

if(preg_match_all('#\<(code|pre) class\=\"php\"\>(.*?)\</(code|pre)\>#is', $html, $code)){
    unset($code[0]);
    foreach($code as $array){
        foreach($array as $value){
            $html = str_replace($value, htmlentities($value, ENT_QUOTES), $html);
        }
    }
}

HTML

<code class="php"> &lt;div&gt; a div.. &lt;/div&gt; </code>

<pre class="php">
&lt;div&gt; a div.. &lt;/div&gt;
</pre>

<div> this should be ignored </div>

Вы когда-нибудь слышали о BB-коде? http://en.wikipedia.org/wiki/BBCode

person Dejan Marjanović    schedule 02.04.2011
comment
Это не очень гибко. Вы требуете, чтобы теги имели очень строгое расположение текста. - person Lightness Races in Orbit; 03.04.2011
comment
Я не понимаю, Он так же легко ломается, как и ваш, нестрогая раскладка - это просто попытка взлома. - person Dejan Marjanović; 03.04.2011
comment
@webarto: Нет, его легче сломать. Мой требует действительный XML; ваш требует точного совпадения текста. Пользователь не мог написать больше пробелов внутри тега (что в остальном допустимо) или добавить дополнительные параметры в тег (что также допустимо в остальном). Ваш также соответствует <code>...</pre>. - person Lightness Races in Orbit; 03.04.2011
comment
Под точным соответствием вы подразумеваете <code class="php"></code>? да. Но он должен быть строгим. Могу ли я вставить встроенный CSS или JS в ваш тег code или pre? (что в любом случае не имеет смысла, потому что в этом случае вы можете использовать HTML снаружи). Да, это соответствует <code>...</pre>. Но действительный XML является обязательным условием :) - person Dejan Marjanović; 03.04.2011
comment
@webarto: <code class="php"><pre class="php">A</pre>B</code> является допустимым XML, но ваш код (я полагаю) не сможет экранировать B в нем. - person Lightness Races in Orbit; 03.04.2011
comment
@webarto: Кстати, я получаю сообщение об ошибке в этом примере (действительный XML, точное совпадение текста): codepad.org/oEcMEg9K - person Lightness Races in Orbit; 03.04.2011
comment
Это правильно, но рекурсивно. Мой пример не работает на парсере codepad.org. - person Dejan Marjanović; 03.04.2011
comment
@webarto: Итак, для этого требуется минимальная версия PHP, или менее строгая среда, или что? - person Lightness Races in Orbit; 03.04.2011
comment
@webarto: PHP 5.2.5 против 5.2.11, возможно. - person Lightness Races in Orbit; 03.04.2011

Это несколько связано, вам не нужно использовать Geshi, но я написал немного кода здесь Советы по реализации простого регулярного выражения (для разбора bbcode/geshi), которые помогут вам решить проблему.

Его можно настроить, чтобы не использовать GeSHi, просто потребуется немного повозиться. Надеюсь, это поможет тебе.

person Jimithus    schedule 02.04.2011