PHP中的htmlentities但保留了html标签

时间:2009-09-01 22:19:33

标签: php html string replace html-entities

我想将字符串中的所有文本转换为html实体,但保留HTML标记,例如:

<p><font style="color:#FF0000">Camión español</font></p>

应该翻译成:

<p><font style="color:#FF0000">Cami&oacute;n espa&ntilde;ol</font></p>

任何想法?

7 个答案:

答案 0 :(得分:64)

您可以获取对应列表character =&gt; htmlentities使用的实体,函数get_html_translation_table;考虑这段代码:

$list = get_html_translation_table(HTML_ENTITIES);
var_dump($list);

(您可能需要在手册中检查该功能的第二个参数 - 也许您需要将其设置为与默认值不同的值)

它会让你得到这样的东西:

array
  ' ' => string '&nbsp;' (length=6)
  '¡' => string '&iexcl;' (length=7)
  '¢' => string '&cent;' (length=6)
  '£' => string '&pound;' (length=7)
  '¤' => string '&curren;' (length=8)
  ....
  ....
  ....
  'ÿ' => string '&yuml;' (length=6)
  '"' => string '&quot;' (length=6)
  '<' => string '&lt;' (length=4)
  '>' => string '&gt;' (length=4)
  '&' => string '&amp;' (length=5)

现在,删除你不想要的对应物:

unset($list['"']);
unset($list['<']);
unset($list['>']);
unset($list['&']);

您的列表现在具有所有对应字符=&gt; htmlentites使用的实体,除了你不想编码的几个字符。

现在,您只需要提取键和值列表:

$search = array_keys($list);
$values = array_values($list);

最后,您可以使用str_replace进行替换:

$str_in = '<p><font style="color:#FF0000">Camión español</font></p>';
$str_out = str_replace($search, $values, $str_in);
var_dump($str_out);

你得到:

string '<p><font style="color:#FF0000">Cami&Atilde;&sup3;n espa&Atilde;&plusmn;ol</font></p>' (length=84)

看起来像你想要的; - )


编辑:好吧,除了编码问题(该死的UTF-8,我想 - 我正试图为此找到解决方案,并将再次编辑) < / p>

第二次编辑几分钟后:在调用utf8_encode之前,您似乎必须在$search列表中使用str_replace: - (

这意味着使用这样的东西:

$search = array_map('utf8_encode', $search);

在致电array_keys和致电str_replace之间。

而且,这一次,你应该得到你想要的东西:

string '<p><font style="color:#FF0000">Cami&oacute;n espa&ntilde;ol</font></p>' (length=70)


以下是代码的完整部分:

$list = get_html_translation_table(HTML_ENTITIES);
unset($list['"']);
unset($list['<']);
unset($list['>']);
unset($list['&']);

$search = array_keys($list);
$values = array_values($list);
$search = array_map('utf8_encode', $search);

$str_in = '<p><font style="color:#FF0000">Camión español</font></p>';
$str_out = str_replace($search, $values, $str_in);
var_dump($str_in, $str_out);

完整输出:

string '<p><font style="color:#FF0000">Camión español</font></p>' (length=58)
string '<p><font style="color:#FF0000">Cami&oacute;n espa&ntilde;ol</font></p>' (length=70)

这一次,应该没问题^^
它并不真正适合一行,可能不是最优化的解决方案;但它应该工作正常,并且有一个优点,允许你添加/删除任何对应字符=&gt;你需要与否的实体。

玩得开心!

答案 1 :(得分:18)

可能不是非常有效,但它有效

$sample = '<p><font style="color:#FF0000">Camión español</font></p>';

echo htmlspecialchars_decode(
    htmlentities($sample, ENT_NOQUOTES, 'UTF-8', false)
  , ENT_NOQUOTES
);

答案 2 :(得分:7)

这是已接受答案的优化版本。

$list = get_html_translation_table(HTML_ENTITIES);
unset($list['"']);
unset($list['<']);
unset($list['>']);
unset($list['&']);

$string = strtr($string, $list);

答案 3 :(得分:5)

对于所有情况,没有解析器的解决方案是正确的。你的情况很好:

<p><font style="color:#FF0000">Camión español</font></p>

但是你也想支持:

<p><font>true if 5 < a && name == "joe"</font></p>

你希望它出现在:

<p><font>true if 5 &lt; a &amp;&amp; name == &quot;joe&quot;</font></p>

问题:您可以在构建HTML之前进行编码吗?换句话说,可以做类似的事情:

"<p><font>" + htmlentities(inner) + "</font></p>"
如果你能做到这一点,你会为自己节省很多悲伤。如果你不能,你需要一些方法来跳过编码&lt;,&gt;和“(如上所述),或者只是将其全部编码,然后撤消它(例如。replace('&lt;', '<')

答案 4 :(得分:3)

这是我刚刚编写的一个函数,它以非常优雅的方式解决了这个问题:

首先,将从字符串中提取HTML标记,然后对每个剩余的子字符串执行htmlentities(),之后将原始HTML标记插入其旧位置,从而不会更改HTML标记。 : - )

玩得开心:

function htmlentitiesOutsideHTMLTags ($htmlText)
{
    $matches = Array();
    $sep = '###HTMLTAG###';

    preg_match_all("@<[^>]*>@", $htmlText, $matches);   
    $tmp = preg_replace("@(<[^>]*>)@", $sep, $htmlText);
    $tmp = explode($sep, $tmp);

    for ($i=0; $i<count($tmp); $i++)
        $tmp[$i] = htmlentities($tmp[$i]);

    $tmp = join($sep, $tmp);

    for ($i=0; $i<count($matches[0]); $i++)
        $tmp = preg_replace("@$sep@", $matches[0][$i], $tmp, 1);

    return $tmp;
}

答案 5 :(得分:2)

根据bflesch的答案,我对管理包含less than signgreater than signsingle quotedouble quotes的字符串进行了一些更改。

function htmlentitiesOutsideHTMLTags ($htmlText, $ent)
{
    $matches = Array();
    $sep = '###HTMLTAG###';

    preg_match_all(":</{0,1}[a-z]+[^>]*>:i", $htmlText, $matches);

    $tmp = preg_replace(":</{0,1}[a-z]+[^>]*>:i", $sep, $htmlText);
    $tmp = explode($sep, $tmp);

    for ($i=0; $i<count($tmp); $i++)
        $tmp[$i] = htmlentities($tmp[$i], $ent, 'UTF-8', false);

    $tmp = join($sep, $tmp);

    for ($i=0; $i<count($matches[0]); $i++)
        $tmp = preg_replace(":$sep:", $matches[0][$i], $tmp, 1);

    return $tmp;
}



使用示例:

$string = '<b>Is 1 < 4?</b>è<br><i>"then"</i> <div style="some:style;"><p>gain some <strong>€</strong><img src="/some/path" /></p></div>';
$string_entities = htmlentitiesOutsideHTMLTags($string, ENT_QUOTES | ENT_HTML401);
var_dump( $string_entities );

输出是:

string '<b>Is 1 &lt; 4?</b>&egrave;<br><i>&quot;then&quot;</i> <div style="some:style;"><p>gain some <strong>&euro;</strong><img src="/some/path" /></p></div>' (length=150)



您可以根据htmlentities manual

传递任何ent flag

答案 6 :(得分:1)

无需转换表或自定义函数的单行解决方案:

我知道这是一个老问题,但我最近不得不将静态网站导入wordpress网站,并且必须克服这个问题:

这是我的解决方案,不需要摆弄翻译表:

htmlspecialchars_decode( htmlentities( html_entity_decode( $string ) ) );

应用于OP的字符串时:

<p><font style="color:#FF0000">Camión español</font></p>

输出:

<p><font style="color:#FF0000">Cami&oacute;n espa&ntilde;ol</font></p>

当应用于Luca的字符串时:

<b>Is 1 < 4?</b>è<br><i>"then"</i> <div style="some:style;"><p>gain some <strong>€</strong><img src="/some/path" /></p></div>

输出:

<b>Is 1 < 4?</b>&egrave;<br><i>"then"</i> <div style="some:style;"><p>gain some <strong>&euro;</strong><img src="/some/path" /></p></div>