PHP实现Unicode及Escape字符串的解码与编码
在处理来自不同来源的数据时,经常遇到非标准编码的字符串,例如由 JavaScript 生成的 %uXXXX 格式或 HTML 实体格式的 Unicode 字符串。本文将展示如何使用 PHP 编写自定义函数,统一解码这些复杂格式的字符串,并提供一种将中文转换为 Escape 编码的实现方案,以解决乱码和数据解析难题。
核心功能目标
主要解决两个问题:
1. 解码:将混合了 <number;> 和 %uXXXX 格式的字符串还原为可读的中文字符。
2. 编码:将普通 PHP 字符串转换为带有 %u 前缀的 Unicode 十六进制格式(常用于前端 JS 处理或特定加密场景)。
准备条件
- 支持 PHP 5.3 及以上版本的环境。
- 注意:部分旧版代码使用了已废弃的
/e修饰符(preg_replace中的执行模式),现代 PHP(7.0+)中建议改用preg_replace_callback以避免安全风险。下文代码基于兼容性与逻辑完整性进行了整理。
第1步:实现统一的 Unicode 解码函数
此函数旨在识别字符串中的两种常见 Unicode 表示法:
- HTML 数字实体:袪好,
- JS/JSON 转义:%u5927%u5BB6 或 \u5927\u5BB6
它将分别提取这些编码点,转换字符集,并替换回原字符串。
入口参数:$s - 待解码的原始字符串。
返回结果:string - 解码后的 UTF-8 字符串。
function uni_decode($s) {
// 1. 匹配 HTML 实体 <数字;>
preg_match_all('/\&\#([0-9]{2,5})\;/i', $s, $html_uni);
// 2. 匹配 %uXXXX 格式 (注意:实际应用中需确保正则能捕获全量)
// 这里简化匹配 %u + 4位十六进制
preg_match_all('/%u([0-9a-fA-F]{4})/', $s, $js_uni);
// 合并所有匹配的源字符串(用于替换)
// 注意:$html_uni[0] 是完整匹配如 <123;>
// $js_uni[0] 是完整匹配如 %u5927
$source = array_merge($html_uni[0], $js_uni[0]);
// 处理 JS 部分的数值
$js_numeric = array();
if (isset($js_uni[1])) {
foreach ($js_uni[1] as $hex) {
$js_numeric[] = hexdec($hex);
}
}
// 合并所有需要转换的 Unicode 码点值
// $html_uni[1] 是十进制数,$js_numeric 是十六进制转来的十进制数
$utf8_codes = array_merge((array)$html_uni[1], $js_numeric);
$code = $s;
// 遍历并替换
for ($j = 0; $j < count($utf8_codes); $j++) {
$target_code = $utf8_codes[$j];
if (isset($source[$j])) {
$unicode_char = unicode2utf8($target_code);
$code = str_replace($source[$j], $unicode_char, $code);
}
}
return $code;
}
// 辅助函数:将 Unicode 码点转换为 UTF-8 字节串
function unicode2utf8($c) {
$str = "";
if ($c < 0x80) {
$str .= chr($c);
} else if ($c < 0x800) {
$str .= chr(0xC0 | ($c >> 6));
$str .= chr(0x80 | ($c & 0x3F));
} else if ($c < 0x10000) {
$str .= chr(0xE0 | ($c >> 12));
$str .= chr(0x80 | (($c >> 6) & 0x3F));
$str .= chr(0x80 | ($c & 0x3F));
} else if ($c < 0x200000) {
$str .= chr(0xF0 | ($c >> 18));
$str .= chr(0x80 | (($c >> 12) & 0x3F));
$str .= chr(0x80 | (($c >> 6) & 0x3F));
$str .= chr(0x80 | ($c & 0x3F));
}
return $str;
}
可观察的完成状态:输入包含乱码的测试字符串后,输出应恢复为正常的中文文本。
第2步:实现 PHP Escape 编码函数
该函数用于将 PHP 字符串转换为 JS 常用的 %uXXXX 编码格式。这在某些老式系统或与 JS 强耦合的场景中较为常见。
风险提示:以下代码涉及字符集转换,请确保服务器环境支持 iconv 扩展,且源文件编码与转换目标一致(通常为 GBK/GB2312 转 UCS-2 再转 UTF-8 的过程,具体取决于系统字节序)。
function phpescape($str) {
// 匹配所有字节序列
preg_match_all("/[\x80-\xff].|[\x01-\x7f]+/", $str, $newstr);
$ar = $newstr[0];
$reString = "";
foreach ($ar as $k => $v) {
// 判断是否为非 ASCII 字符
if (ord($ar[$k]) >= 127) {
// 使用 iconv 转换为 UCS-2 (Java/JS 通常使用的内部编码)
// 注意:此处假设输入字符串符合当前 locale 编码,常见为 GBK
// 若输入已是 UTF-8,直接处理可能更简单,但为兼容原版逻辑保留此转换
$tmpString = bin2hex(iconv("UTF-8", "UCS-2", $v));
// 处理字节序 (Endianness)
// Windows/Linux 下 UCS-2 的字节序可能需要调整,以便 JS 正确读取
// 大多数情况下,直接使用 substr 调整字节顺序以适应 %uXXXX 格式
if (!eregi("WIN", PHP_OS)) {
// Linux/Mac 等小端或对半字节序敏感的修正逻辑
// 原逻辑中 eregi 已废弃,这里仅保留业务逻辑示意
// 实际生产中建议使用 mb_convert_encoding('UTF-8', 'UTF-16BE') 等方式
}
$reString .= "%u" . strtoupper($tmpString);
} else {
// ASCII 字符保持原样或使用 rawurlencode
$reString .= rawurlencode($v);
}
}
return $reString;
}
第3步:验证与测试
通过构造一个包含 Unicode 转义字符的变量来测试解码函数:
$str = '%u5927%u5BB6%u597D%uFF0C%E6%88%91%E6%98%AF%E5%AD%A4%E9%AD%82!
';
// 注意:上面的混合了 %u 和可能的 HTML 实体,实际测试需统一格式
// 使用纯 %u 格式测试 uni_decode:
$testStr = '%u5927%u5BB6%u597D';
echo uni_decode($testStr);
// 预期输出: "大家好"
原文有依据的排错
- Deprecated Functions:原文代码中使用了
ereg()(eregi) 和PREG_REPLACE_EVAL(/e 修饰符),这些在 PHP 7 中已被移除或严重限制。新版实现应转向preg_replace_callback或使用mb_系列函数进行更安全、高效的字符串处理。
- Encoding Assumptions:
phpescape函数中硬编码了iconv("GBK","ucs-2",...,这依赖于系统的默认编码环境。在现代 Web 开发中,绝大多数情况应全程使用UTF-8。如果需要生成 JS 可用的 Unicode,直接使用json_encode配合JSON_UNESCAPED_UNICODE可能是更标准的做法。
简要总结
上述即为利用 PHP 函数对 Unicode 及 Escape 加密字符串进行解码与编码的详细操作方法。通过 uni_decode 可以有效清理混杂的各种编码格式,而 phpescape 则提供特定的输出格式支持。建议在现代项目中优先考虑使用内置的 mb_convert_encoding 或 JSON 序列化来处理此类字符集转换问题,以确保跨平台兼容性。
以上就是PHP解密Unicode及Escape加密字符串的详细内容,更多关于PHP编码解密资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













