Smarty常用自定义函数扩展实现:中文截取、UBB转HTML与Unescape解码
在使用 Smarty 进行 Web 开发时,经常需要处理中文字符截断保持完整、UBB 标签转 HTML 显示以及 URL 编码解码等问题。通过编写自定义修饰符(Modifier)函数,可以显著提升模板页面的整洁度和数据处理能力。本文将逐一解析这三个核心扩展功能的实现原理与代码结构。
实现中文字符串安全截断
在展示摘要或列表内容时,直接截断字符串容易导致乱码,尤其是涉及多字节字符集(如 GBK 或 UTF-8)时。以下函数 smarty_modifier_cn_truncate 能够智能识别字符边界,确保截取后的字符串不乱码,同时支持保留首尾样式参数。
- 初始化与长度计算:输入字符串
$string和目标长度$strlen。为了兼容不同编码下的字节数,先将目标长度乘以 2(针对部分双字节逻辑进行调整),并去除首尾空格。 - 短文本直接返回:如果原字符串长度小于等于设定的最大长度,则直接返回原文,无需截取。
- 提取纯文本内容:使用
strip_tags()去除原有 HTML 标签,得到纯净文本$str。 - 字节边界检测:遍历指定长度的字节,利用
ord()检查 ASCII 值是否大于 0xa0(通常是多字节字符标识)。若发现单数值的字节被切断,自动调整截取长度以保证完整性。 - 执行截取与追加省略号:根据调整后的长度截取子串,并在末尾添加省略号
$etc。 - 可选:保留原始样式:当
$keep_first_style为真且包含包裹标签时,尝试定位起始和结束位置,重新拼接包含样式的最终字符串。注意此处使用了正则匹配,需确保源字符串符合预期结构。
代码如下:
function smarty_modifier_cn_truncate($string, $strlen = 20, $etc = '...',
$keep_first_style = false)
{
$strlen = $strlen*2;
$string = trim($string);
if ( strlen($string) <= $strlen ) {
return $string;
}
$str = strip_tags($string);
$j = 0;
for($i=0;$i<$strlen;$i++) {
if(ord(substr($str,$i,1))>0xa0) $j++;
}
if($j%2!=0) $strlen++;
$rstr=substr($str,0,$strlen);
if (strlen($str)>$strlen ) {$rstr .= $etc;}
// 可选:尝试保留外部样式标签
if ( $keep_first_style == true && ereg('^<(.*)>$',$string) ) {
if ( strlen($str) <= $strlen ) {
return $string;
}
$start_pos = strpos($string,substr($str,0,4));
$end_pos = strpos($string,substr($str,-4));
$end_pos = $end_pos+4;
$rstr = substr($string,0,$start_pos) . $rstr . substr($string,$end_pos,strlen($string));
}
return $rstr;
}
将 UBB 代码转换为 HTML 标签
许多旧式论坛系统使用 UBB 标签(如 [b], [img])存储用户输入。该扩展函数 smarty_modifier_ubb 定义了一系列映射规则,将这些自定义标签批量替换为标准 HTML 元素,便于现代浏览器渲染和 CSS 控制。
- 定义映射数组:构建二维关联数组
$ubbs,键名为标签类型(如 quote, b, img, url 等),值为正则表达式模式及其对应的 HTML 替换字符串。 - 特殊符号处理:优先将通用列表符号
[*]替换为<li>,以便统一后续的列表处理逻辑。 - 循环替换执行:遍历所有定义的规则,调用辅助函数
ubb_replace对正文进行全局正则替换。此过程会持续运行直到某次替换没有产生变化为止,以应对嵌套或复杂情况。
代码如下:
function smarty_modifier_ubb($str) {
// 定义各类 UBB 标签到 HTML 的映射规则
$ubbs['quote'][0] = '/\[quote\](.*?)\[\/quote\]/s';
$ubbs['quote'][1] = '<blockquote>引用:<hr size=1>\1<hr size=1></blockquote>';
$ubbs['b'][0] = '/\[b\](.*?)\[\/b\]/s';
$ubbs['b'][1] = '<b>\1</b>';
$ubbs['i'][0] = '/\[i\](.*?)\[\/i\]/s';
$ubbs['i'][1] = '<i>\1</i>';
// ... (此处省略其他常见标签如u, li, color等映射定义) ...
$ubbs['img'][0] = '/\[img\](.*?)\[\/img\]/s';
$ubbs['img'][1] = '<img border="0" src="\1">';
$ubbs['url'][0] = '/\[url\](.*?)\[\/url\]/s';
$ubbs['url'][1] = '<a href="\1" target="_blank">\1</a>';
$ubbs['email'][0] = '/\[email=([^\]]+)\](.*?)\[\/email\]/s';
$ubbs['email'][1] = '<a href="mailto:\2">\2</a>';
// ... (更多图片、颜色、字体大小等高级映射逻辑) ...
// 处理通用列表项符号
$str = str_replace('[*]','<li>',$str);
// 依次应用所有正则替换
foreach ($ubbs as $ubb){
$str = ubb_replace($ubb[0],$ubb[1],$str);
}
return $str;
}
// 辅助函数:执行多次替换直至稳定
function ubb_replace($pattern,$replacement,$str){
do {
$str_ret = $str;
$str = preg_replace($pattern,$replacement,$str);
}while($$str); // 注意:此处原代码写法可能存在变量语法歧义,建议在实际生产环境中确认变量作用域
return $str_ret;
}
解析 URL 编码字符串 (Unescape)
在前端向后端传输数据时,中文字符常被编码为 Unicode 形式(如 %uXXXX)。此函数 smarty_modifier_unescape 专门用于将这类经过双重编码或特定格式的字符串还原为可读文本,主要适配 GB2312 等旧式编码环境,但在处理 UCS-2 序列时同样有效。
- 初步解码:首先使用
rawurldecode()进行标准的 URL 解码,消除百分号转义符。 - 正则分离:使用正则可以区分出普通的非百分号字符块和特殊的 Unicode 编码块
(?:%u.{4})。 - 逐个转换 Unicode:遍历拆分后的数组,若发现以
%u开头且长度为 6 的片段,提取后四位十六进制数,使用pack("H4")打包成二进制,再通过iconv("UCS-2","GB2312",...)转换为目标编码的汉字。 - 重组输出:将所有解码后的片段重新连接为完整字符串并返回。
代码如下:
function smarty_modifier_unescape($str)
{
$str = rawurldecode($str);
// 匹配 %uXXXX 格式的 Unicode 或普通字符块
preg_match_all("/(?:%u.{4})|[^%]+/",$str,$r);
$ar = $r[0];
foreach($ar as $k=>$v) {
// 判断是否为 %u 开头的 6 位字符
if(substr($v,0,2) == "%u" && strlen($v) == 6)
// 提取最后4位 hex,打包为 UCS-2 字节流并转为 GB2312
$ar[$k] = iconv("UCS-2","GB2312",@pack("H4",substr($v,-4)));
}
return join("",$ar);
}
以上就是 PHP Smarty 自定义函数扩展中关于中文截取、UBB转HTML及Unescape解析的详细内容,更多关于 Smarty 优化技巧的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









