首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 字符串转 HTML 实体编码类实现:非 ASCII 字符安全转换

     編輯:PHP 綜合知識

字符实体化:防 XSS、解决编码兼容、存储特殊字符的通用方案

将字符串中非 ASCII 字符(中文、表情符、特殊符号)转为 HTML 数字实体引用(&#xxxx;),可在不指定字符集的环境下安全传输、存储、显示。本文实现一个高性能、支持多编码源的静态工具类。

核心实现:HtmlEncode 类

<?php
class HtmlEncode {
    // 默认源编码
    private static $_srcEncoding = 'UTF-8';

    /**
     * 将非 ASCII 字符转为 HTML 实体
     * @param string $s 待转换字符串
     * @param string $srcEncoding 源字符串编码 (UTF-8, GB2312, GBK 等)
     * @return string HTML 实体字符串
     * @example HtmlEncode::encode("我信了") → "我信了"
     */
    public static function encode($s, $srcEncoding = 'UTF-8') {
        self::$_srcEncoding = $srcEncoding;
        
        // 正则匹配非 ASCII 字节序列 (连续非 0x00-0x7F)
        return preg_replace_callback(
            '|[^\x00-\x7F]+|', 
            [__CLASS__, '_convertToHtmlEntities'], 
            $s
        );
    }

    /**
     * 回调处理:将匹配的多字节序列转为实体
     * @param array|string $data 匹配结果 (PREG_OFFSET_CAPTURE 时为数组)
     * @return string 实体字符串
     */
    private static function _convertToHtmlEntities($data) {
        // 兼容 preg_replace_callback 传入数组或字符串
        $str = is_array($data) ? $data[0] : $data;
        
        // 1. 转为 UCS-2BE (大端序,每字符 2 字节)
        $ucs2 = iconv(self::$_srcEncoding, "UCS-2BE", $str);
        
        // 2. 按 2 字节分割
        $chars = str_split($ucs2, 2);
        
        // 3. 每字符转为十进制实体
        $entities = array_map(function($char) {
            // 高字节在前,低字节在后
            $code = (ord($char[0]) << 8) | ord($char[1]);
            return "&#{$code};";
        }, $chars);
        
        return implode('', $entities);
    }
}
?>

使用示例

<?php
require 'HtmlEncode.php';

// 1. UTF-8 中文转实体
echo HtmlEncode::encode("你好世界"); 
// 输出: 你好世界

// 2. GB2312 源编码转实体
$gbStr = iconv("UTF-8", "GB2312", "测试");
echo HtmlEncode::encode($gbStr, "GB2312");
// 输出: 测试

// 3. 混合内容
echo HtmlEncode::encode("Hello 世界! 😀");
// 输出: Hello 世界! 😀

// 4. 数据库存储场景
$safeTitle = HtmlEncode::encode($userInput); // 存入 latin1 表也能正确显示中文
?>

核心逻辑解析

  1. 正则 [^\x00-\x7F]+:匹配连续非 ASCII 字节,避免逐字符回调开销
  2. iconv 转 UCS-2BE:统一到固定 2 字节/字符编码,便于计算码点
  3. 位运算 (ord($c[0]) << 8) | ord($c[1]):大端序合成 Unicode 码点
  4. 数字实体 &#code;:浏览器通用支持,无需实体名映射表

性能优化版:预编译正则 + 批量转换

<?php
class HtmlEncodeFast {
    private static $pattern = '|[^\x00-\x7F]+|';
    
    public static function encode($s, $srcEncoding = 'UTF-8') {
        // 预转整个字符串为 UCS-2BE,避免回调中重复 iconv
        $ucs2 = iconv($srcEncoding, "UCS-2BE", $s);
        $len = strlen($ucs2);
        $result = '';
        $asciiStart = 0;
        
        for ($i = 0; $i < $len; $i += 2) {
            $high = ord($ucs2[$i]);
            if ($high < 0x80) { // ASCII 字符 (高字节为 0)
                continue;
            }
            // 非 ASCII:输出前面的 ASCII 部分
            if ($i > $asciiStart) {
                $result .= substr($s, $asciiStart, ($i - $asciiStart) / 2);
            }
            // 转换当前字符
            $code = ($high << 8) | ord($ucs2[$i + 1]);
            $result .= "&#{$code};";
            $asciiStart = $i + 2;
        }
        // 尾部 ASCII
        if ($asciiStart < strlen($s)) {
            $result .= substr($s, $asciiStart);
        }
        return $result;
    }
}
?>

对比:htmlentities vs HtmlEncode

特性htmlentitiesHtmlEncode::encode
转换范围所有特殊字符 (& < > " ' 等)仅非 ASCII 字符
输出格式命名实体 (©) + 数字实体仅十进制数字实体
编码依赖需指定 charset 参数需指定源编码
数据库存储增加体积 2-4 倍仅非 ASCII 增加,体积较小
反向解码html_entity_decodehtml_entity_decode 通用

反向解码:实体还原字符串

<?php
function htmlEntitiesToString($html) {
    return html_entity_decode($html, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}

// 测试
$encoded = "你好世界";
echo htmlEntitiesToString($encoded); // 输出: 你好世界
?>

应用场景

  1. 旧系统 latin1 存中文:转实体存入,前端直接渲染
  2. 跨编码系统集成:统一用数字实体交换,避免编码转换错误
  3. 邮件模板安全:防止特殊字符破坏 HTML 结构
  4. 日志存储:统一编码存储,查看器无需切换编码
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved