如何在<code></code>标记内转义所有代码以允许人们发布代码?

时间:2012-03-01 01:37:29

标签: php escaping

我想要做的是允许用户在需要时发布代码,因此它是可见的并且不会呈现。例如:

<span>
<div id="hkhsdfhu"></div>
</span>
<h1>Hello</h1>

应该变成:

&lt;span&gt;
&lt;div id="hkhsdfhu"&gt;&lt;/div&gt;
&lt;/span&gt;
&lt;h1&gt;Hello&lt;/h1&gt;

仅当它包含在<code></code>标记中时。现在我使用以下函数只允许某些HTML标记并转义任何其他标记:

function allowedHtml($str) {
$allowed_tags = array("b", "strong", "i", "em");
$sans_tags = str_replace(array("<", ">"), array("&lt;","&gt;"), $str);
$regex = sprintf("~&lt;(/)?(%s)&gt;~", implode("|",$allowed_tags));
$with_allowed = preg_replace($regex, "<\\1\\2>", $sans_tags);
return $with_allowed;
}

但是,如果用户将代码包装在<code></code>标记中并且它包含上述函数中的任何允许的标记,那么这些标记将呈现而不是被转义。如何将<code></code>标记中的任何内容转义(或仅<>转换为&lt;&gt;)?我知道htmlentities(),但我不想对整个帖子这样做,只有<code></code>个标签内的内容。

提前致谢!

4 个答案:

答案 0 :(得分:3)

只需使用preg_replace()一个htmlenteties()函数就<code>代码中找到的所有内容执行function allowedHtml($str) { $str = htmlentities($str, ENT_QUOTES, "UTF-8"); $allowed_tags = array("b", "strong", "i", "em", "code"); foreach ($allowed_tags as $tag) { $str = preg_replace("#&lt;" . $tag . "&gt;(.*?)&lt;/" . $tag . "&gt;#i", "<" . $tag . ">$1</" . $tag . ">", $str); } return $str; } $reply = allowedHtml($_POST['reply']); $reply = preg_replace("#\<code\>(.+?)\</code\>#e", "'<code>'.htmlentities('$1', ENT_QUOTES, 'UTF-8').'</code>'", $reply); $reply = str_replace("&amp;", "&", $reply); 函数

EDITED

allowedHtml()

重写了您的str_replace()功能并在最后添加了function convertHtml($reply, $revert = false) { $specials = array("**", "*", "_", "-"); $tags = array("b", "i", "u", "s"); foreach ($tags as $key => $tag) { $open = "<" . $tag . ">"; $close = "</" . $tag . ">"; if ($revert == true) { $special = $specials[$key]; $reply = preg_replace("#" . $open . "(.+?)" . $close . "#i", $special . "$1" . $special, $reply); } else { $special = str_replace("*", "\*", $specials[$key]); $reply = preg_replace("#" . $special . "(.+?)" . $special . "#i", $open . "$1" . $close, $reply); } } return $reply; } $reply = htmlentities($reply, ENT_QUOTES, "UTF-8"); $reply = convertHtml($reply); $reply = preg_replace("#[^\S\r\n]{4}(.+?)(?!.+)#i", "<pre><code>$1</code></pre>", $reply); $reply = preg_replace("#\</code\>\</pre\>(\s*)\<pre\>\<code\>#i", "$1", $reply); $reply = nl2br($reply); $reply = preg_replace("#\<pre\>\<code\>(.*?)\</code\>\</pre\>#se", "'<pre><code>'.convertHtml(str_replace('<br />', '', '$1'), true).'</code></pre>'", $reply);

它已经过测试,现在应该可以完美运行:)

更新 - 新解决方案

{{1}}

讨论了另一个解决方案,上面的代码将解决这个问题。它就像Stack Overflow html转换一样,这意味着**变为粗体,*变为斜体,_变为下划线, - 是“删除线”。最重要的是,所有以4个或更多空格开头的行将作为代码输出

答案 1 :(得分:2)

我认为你最好直接使用dom而不是使用正则表达式来解析允许的标签。例如,要遍历dom并转义<code>标签中的内容,您可以执行以下操作:

$doc = new DOMDocument();
$doc->loadHTML($postHtml);
$codeNode = $doc->getElementsByTagName('code')->item(0);
$escapedCode = htmlspecialchars($codeNode->nodeValue);

答案 2 :(得分:1)

您可以使用preg_replace()进行此操作。只需确保在调用allowedHtml函数之前调用此函数,以便标记已被替换。

<?php

$post = <<<EOD
I am a person writing a post
How can I write this code?

Example:

<code>
<span>
<div id="hkhsdfhu"></div>
</span>
<h1>Hello</h1>
</code>

Pls help me...
EOD;

$post = preg_replace('/<code>(.*?)<\/code>/ise',
                     "'<code>' . htmlspecialchars('$1') . '</code>'",
                      $post);

var_dump($post);

结果:

string(201) "I am a person writing a post
How can I write this code?

Example:

<code>
&lt;span&gt;
&lt;div id=\&quot;hkhsdfhu\&quot;&gt;&lt;/div&gt;
&lt;/span&gt;
&lt;h1&gt;Hello&lt;/h1&gt;
</code>

Pls help me..."

答案 3 :(得分:1)

这是一个。

$str = preg_replace_callback('/(?<=<code>)(.*?)(?=<\/code>)/si','escape_code',$str);

function escape_code($matches) {

    $tags = array('b','strong','i','em');
    // declare the tags in this array

    $allowed = implode('|',$tags);
    $match = htmlentities($matches[0],ENT_NOQUOTES,'UTF-8');
    return preg_replace('~&lt;(/)?('.$allowed.')(\s*/)?&gt;~i','<$1$2$3>',$match);
}