Files
useds/app/common/utils/crawl/service/UnCodeFont.php
T
2026-02-05 19:25:56 +08:00

95 lines
2.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\common\utils\crawl\service;
use support\Db;
trait UnCodeFont{
/**
* 是否包含 PUA 字符(U+E000~U+F8FF)
*/
function needFontDecode(string $text): bool
{
if ($text === '') return false;
$chars = preg_split('//u', $text, -1, PREG_SPLIT_NO_EMPTY);
if (!$chars) return false;
foreach ($chars as $ch) {
$u = mb_convert_encoding($ch, 'UCS-4BE', 'UTF-8');
if ($u === false || strlen($u) !== 4) continue;
$cp = unpack('N', $u)[1];
if ($cp >= 0xE000 && $cp <= 0xF8FF) {
return true;
}
}
return false;
}
/**
* 读取某个 font_hash 的映射表,返回 [ 'e53d' => '中', ... ]
* code 表里存的是 '&#xE53D;' 或 '&#xe53d;'
*/
function loadFontMap(string $fontHash): array
{
$rows = Db::table('font_map')
->select('code', 'char')
->where('font_hash', $fontHash)
->get()
->toArray();
$rows = array_map(function($item) {
return (array) $item;
}, $rows);
$map = [];
foreach ($rows as $r) {
// 从 '&#xE53D;' 提取 e53d
if (preg_match('/&#x([0-9a-fA-F]+);/i', $r['code'], $m)) {
$map[strtolower($m[1])] = $r['char'];
}
}
return $map;
}
/**
* 将包含 PUA 字符的字符串,按 font_map 替换
*/
function decodeObfuscatedText(string $text, array $fontMap): string
{
$fontHash = '77fd388510a974babdf4837b26d2d33f'; // 你当前字体 md5(font_map.sql 里那一份)
$fontMap = $this->loadFontMap($fontHash);
// 按 Unicode 字符切分
$chars = preg_split('//u', $text, -1, PREG_SPLIT_NO_EMPTY);
if (!$chars) return $text;
$out = '';
foreach ($chars as $ch) {
// 获取码点(十六进制),如 e53d
$hex = $this->unicodeCodePointHex($ch);
if ($hex !== null) {
$key = strtolower($hex);
// 只替换命中的(一般就是 E***)
if (isset($fontMap[$key])) {
$out .= $fontMap[$key];
continue;
}
}
// 没命中:原样保留(比如 '.' 这种正常字符)
$out .= $ch;
}
return $out;
}
/**
* 获取单个 Unicode 字符的码点十六进制(不带 0x),失败返回 null
* 例:'' -> 'e53d'
*/
function unicodeCodePointHex(string $ch): ?string
{
if ($ch === '') return null;
$u = mb_convert_encoding($ch, 'UCS-4BE', 'UTF-8');
if ($u === false || strlen($u) !== 4) return null;
$code = unpack('N', $u)[1]; // 32-bit
return dechex($code);
}
}