如何使用PHP将所有字符转换为它们的HTML实体等价物

16

我想将这个hello@domain.com转换成

hello@domain.com

我尝试过:

url_encode($string)

这提供了我输入的相同字符串,其中@符号转换为%40

也尝试过:

htmlentities($string)

这将直接返回相同的字符串。

我正在使用UTF8字符集,不确定这是否有所区别...


我删除了我的回答,因为我意识到它不好。 (感谢Artefacto)然而,这并不是真正防止垃圾邮件机器人的足够保护... - Pekka
我知道这并不是完全可靠的,但是过去使用在线服务对我的电子邮件地址进行编码时,效果还不错。现在我正在尝试将这个功能集成到我正在构建的内容管理系统中。 - Mazatec
3个回答

41

以下是代码示例(假设使用 UTF-8 编码,但更改编码方式很容易):

function encode($str) {
    $str = mb_convert_encoding($str , 'UTF-32', 'UTF-8'); //big endian
    $split = str_split($str, 4);

    $res = "";
    foreach ($split as $c) {
        $cur = 0;
        for ($i = 0; $i < 4; $i++) {
            $cur |= ord($c[$i]) << (8*(3 - $i));
        }
        $res .= "&#" . $cur . ";";
    }
    return $res;
}

编辑 推荐使用unpack作为替代方案:

function encode2($str) {
    $str = mb_convert_encoding($str , 'UTF-32', 'UTF-8');
    $t = unpack("N*", $str);
    $t = array_map(function($n) { return "&#$n;"; }, $t);
    return implode("", $t);
}

$res .= "&#" . $cur . ";" 转换为字符串时,不必将 $cur 打印为无符号数,因为 Unicode 字符的范围并不那么广。但是,如果您有一个无效的 UTF-8 序列,这可能会产生负值(我不知道 mb_convert_encoding 是否验证范围)。 - Artefacto
这是一个出色的答案,原因有三:1.我自己想不到。2.它优雅而且运行良好。3.我从中学到了很多好东西。谢谢。 - Mazatec
你的第二个版本中使用了闭包,需要 PHP 5.3 及以上版本支持。对于低于 5.3 的版本,你可以传递一个字符串,例如 'encoded_str',然后编写一个函数来实现闭包的功能:function encoded_str($n) { return "&#$n;"; }。虽然不够优雅,但是向后兼容。 - CWSpear
Artefacto,你能用pack将它转换回原始字符串吗? - Mike Garcia
@Artefacto 很好的回答。它也帮助了我。谢谢。 - Satish Sharma
for($i=0;$i<mb_strlen($in);$i++) @$out.='&#'.mb_ord(mb_substr($in,$i,1),'UTF-8').';'; return $out;for($i=0;$i<strlen($in);$i++) @$o.='&#'.ord(substr($in,$i,1)).';'; return $o; - a55

11

有更简单的方法:

function convertToNumericEntities($string) {
    $convmap = array(0x80, 0x10ffff, 0, 0xffffff);
    return mb_encode_numericentity($string, $convmap, "UTF-8");
}

如果您使用的是其他编码方式,可以更改编码。

  • 修复了地图范围。感谢 Artefacto。

不错,虽然我还没有测试过,但我认为您还需要更改映射以涵盖所有Unicode字符。 - Artefacto
可能是这样的 $convmap = array(0x000000, 0x10ffff, 0, 0xffffff);(未经测试) - Artefacto
这个评论中的convmap是有效的:http://www.php.net/manual/en/function.mb-encode-numericentity.php#88586 - koen
这个答案非常简单,对我的应用程序很有效。为了回答这个问题,$convmap 应该包括普通的字母数字字符,但不包括空格或换行符,因此 $convmap = array( 0x21, 0x10ffff, 0, 0xffffff, ); 可能更适用。通过 html_entity_decode 函数调用传递字符串也可能是有益的,以防止实体的意外双重编码。 - Shaun Cockerill
由于某些原因,此解决方案仅输出非编码字符。@Artefacto的答案可以正常工作。 - Gavin

1
function uniord($char) {

     $k=mb_convert_encoding($char , 'UTF-32', 'UTF-8');

     $k1=ord(substr($k,0,1));

     $k2=ord(substr($k,1,1));

     $value=(string)($k2*256+$k1);

     return $value;

}

上述函数适用于单个字符,但如果您有一个字符串,可以使用以下方法:
$string="anytext";

$arr=preg_split(//u,$string,-1,PREG_SPLIT_NO_EMPTY);

$temp=" ";

foreach($arr as $v){

    $temp="&#".uniord($v);//prints the equivalent html entity of string

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接