PHP 修复未正常关闭的HTML标签实现代码(支持嵌套和就近闭合)

fixHtmlTag
version 0.2
这个版本解决了上次遗留的问题,即就近闭合和嵌套闭合问题。具体可以看代码的注释。


代码如下:

<?php

/**
* fixHtmlTag
*
* HTML标签修复函数,此函数可以修复未正确闭合的 HTML 标签
*
* 由于不确定性因素太多,暂时提供两种模式“嵌套闭合模式”和
* “就近闭合模式”,应该够用了。
*
* 这两种模式是我为了解释清楚此函数的实现而创造的两个名词,
* 只需明白什么意思就行。
* 1,嵌套闭合模式,NEST,为默认的闭合方式。即 "<body><div>你好"
* 这样的 html 代码会被修改为 "<body><div>你好</div></body>"
* 2,就近闭合模式,CLOSE,这种模式会将形如 "<p>你好<p>为什么没有
* 闭合呢" 的代码修改为 "<p>你好</p><p>为什么没有闭合呢</p>"
*
* 在嵌套闭合模式(默认,无需特殊传参)下,可以传入需要就近闭合的
* 标签名,通过这种方式将类似 "<body><p>你好</p><p>我也好" 转换为
* "<body><p>你好</p><p>我也好</p></body>"的形式。
* 传参时索引需要按照如下方式写,不需要修改的设置可以省略
*
* $param = array(
* 'html' => '', //必填
* 'options' => array(
* 'tagArray' => array();
* 'type' => 'NEST',
* 'length' => null,
* 'lowerTag' => TRUE,
* 'XHtmlFix' => TRUE,
* )
* );
* fixHtmlTag($param);
*
* 上面索引对应的值含义如下
* string $html 需要修改的 html 代码
* array $tagArray 当为嵌套模式时,需要就近闭合的标签数组
* string $type 模式名,目前支持 NEST 和 CLOSE 两种模式,如果设置为 CLOSE,将会忽略参数 $tagArray 的设置,而全部就近闭合所有标签
* ini $length 如果希望截断一定长度,可以在此赋值,此长度指的是字符串长度
* bool $lowerTag 是否将代码中的标签全部转换为小写,默认为 TRUE
* bool $XHtmlFix 是否处理不符合 XHTML 规范的标签,即将 <br> 转换为 <br />
*
* @author IT不倒翁 <itbudaoweng@gmail.com>
* @version 0.2
* @link http://yungbo.com IT不倒翁
* @link http://enenba.com/?post=19 某某
* @param array $param 数组参数,需要赋予特定的索引
* @return string $result 经过处理后的 html 代码
* @since 2012-04-14
*/
function fixHtmlTag($param = array()) {
//参数的默认值
$html = '';
$tagArray = array();
$type = 'NEST';
$length = null;
$lowerTag = TRUE;
$XHtmlFix = TRUE;

//首先获取一维数组,即 $html 和 $options (如果提供了参数)
extract($param);

//如果存在 options,提取相关变量
if (isset($options)) {
extract($options);
}

$result = ''; //最终要返回的 html 代码
$tagStack = array(); //标签栈,用 array_push() 和 array_pop() 模拟实现
$contents = array(); //用来存放 html 标签
$len = 0; //字符串的初始长度

//设置闭合标记 $isClosed,默认为 TRUE, 如果需要就近闭合,成功匹配开始标签后其值为 false,成功闭合后为 true
$isClosed = true;

//将要处理的标签全部转为小写
$tagArray = array_map('strtolower', $tagArray);

//“合法”的单闭合标签
$singleTagArray = array(
'<meta',
'<link',
'<base',
'<br',
'<hr',
'<input',
'<img'
);

//校验匹配模式 $type,默认为 NEST 模式
$type = strtoupper($type);
if (!in_array($type, array('NEST', 'CLOSE'))) {
$type = 'NEST';
}

//以一对 < 和 > 为分隔符,将原 html 标签和标签内的字符串放到数组中
$contents = preg_split("/(<[^>]+?>)/si", $html, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

foreach ($contents as $tag) {
if ('' == trim($tag)) {
$result .= $tag;
continue;
}

//匹配标准的单闭合标签,如<br />
if (preg_match("/<(\w+)[^\/>]*?\/>/si", $tag)) {
$result .= $tag;
continue;
}

//匹配开始标签,如果是单标签则出栈
else if (preg_match("/<(\w+)[^\/>]*?>/si", $tag, $match)) {
//如果上一个标签没有闭合,并且上一个标签属于就近闭合类型
//则闭合之,上一个标签出栈

//如果标签未闭合
if (false === $isClosed) {
//就近闭合模式,直接就近闭合所有的标签
if ('CLOSE' == $type) {
$result .= '</' . end($tagStack) . '>';
array_pop($tagStack);
}
//默认的嵌套模式,就近闭合参数提供的标签
else {
if (in_array(end($tagStack), $tagArray)) {
$result .= '</' . end($tagStack) . '>';
array_pop($tagStack);
}
}
}

//如果参数 $lowerTag 为 TRUE 则将标签名转为小写
$matchLower = $lowerTag == TRUE ? strtolower($match[1]) : $match[1];

$tag = str_replace('<' . $match[1], '<' . $matchLower, $tag);
//开始新的标签组合
$result .= $tag;
array_push($tagStack, $matchLower);

//如果属于约定的的单标签,则闭合之并出栈
foreach ($singleTagArray as $singleTag) {
if (stripos($tag, $singleTag) !== false) {
if ($XHtmlFix == TRUE) {
$tag = str_replace('>', ' />', $tag);
}
array_pop($tagStack);
}
}

//就近闭合模式,状态变为未闭合
if ('CLOSE' == $type) {
$isClosed = false;
}
//默认的嵌套模式,如果标签位于提供的 $tagArray 里,状态改为未闭合
else {
if (in_array($matchLower, $tagArray)) {
$isClosed = false;
}
}
unset($matchLower);
}

//匹配闭合标签,如果合适则出栈
else if (preg_match("/<\/(\w+)[^\/>]*?>/si", $tag, $match)) {

//如果参数 $lowerTag 为 TRUE 则将标签名转为小写
$matchLower = $lowerTag == TRUE ? strtolower($match[1]) : $match[1];

if (end($tagStack) == $matchLower) {
$isClosed = true; //匹配完成,标签闭合
$tag = str_replace('</' . $match[1], '</' . $matchLower, $tag);
$result .= $tag;
array_pop($tagStack);
}
unset($matchLower);
}

//匹配注释,直接连接 $result
else if (preg_match("/<!--.*?-->/si", $tag)) {
$result .= $tag;
}

//将字符串放入 $result ,顺便做下截断操作
else {
if (is_null($length) || $len + mb_strlen($tag) < $length) {
$result .= $tag;
$len += mb_strlen($tag);
} else {
$str = mb_substr($tag, 0, $length - $len + 1);
$result .= $str;
break;
}
}
}

//如果还有将栈内的未闭合的标签连接到 $result
while (!empty($tagStack)) {
$result .= '</' . array_pop($tagStack) . '>';
}
return $result;
}

(0)

相关推荐

  • php 批量替换html标签的实例代码

    1.把html元素全部去掉,或者保留某几个html标签 复制代码 代码如下: <?php$text = '<p>Test paragraph.</p><!-- Comment --> <a href="#fragment">Other text</a>';echo strip_tags($text);echo "/n"; // Allow <p> and <a>echo str

  • php使HTML标签自动补全闭合函数代码

    简单解释一些代码: 第一个 ~(<[^>]+?>)~si 这个正则是匹配<--->中的内容.简单说是所有的<标签>. 第二个 ~<([a-z0-9]+)[^/>]*?/>~si 这个正则是匹配<--/>中的内容.是单闭合标签 如<br /> 第三个 ~</([a-z0-9]+)[^/>]*?>~si 这个正则是匹配</......>中的内容.也就是结束标签 如</a> 第四个 ~&

  • PHP转换文本框内容为HTML格式的方法

    本文实例讲述了PHP转换文本框内容为HTML格式的方法.分享给大家供大家参考,具体如下: 有时候我们将会用到将多行文本框中输入的内容以html格式显示出来,这样子可以保持原来的文本格式,如换行.回车等.可以通过下面的函数实现: function shtm($design_str) { $str=trim($design_str); // 取得字串同时去掉头尾空格和空回车 //$str=str_replace("<br>","",$str); // 去掉&

  • PHP将HTML转换成文本的实现代码

    核心代码: <?php // $document 应包含一个 HTML 文档. // 本例将去掉 HTML 标记,javascript 代码 // 和空白字符.还会将一些通用的 // HTML 实体转换成相应的文本. $search = array ("'<script[^>]*?>.*?</script>'si", // 去掉 javascript "'<[\/\!]*?[^<>]*?>'si", //

  • PHP删除HTMl标签的三种解决方法

    方法1:直接取出想要取出的标记 复制代码 代码如下: <?php    //取出br标记    function strip($str){$str=str_replace("<br>","",$str);//$str=htmlspecialchars($str);return strip_tags($str);}?> 方法2.PHP 中有个 strip_tags 函数可以方便地去除 HTML 标签.echo strip_tags("

  • PHP html标签正则替换并可自定义正则规则

    复制代码 代码如下: <?php function pregstring($str){ $strtemp = trim($str); $search = array( "|'|Uis", "|<script[^>].*?</script>|Uis", // 去掉 javascript "|\[字定义\].*\[/字定义\]|Uis", // 去掉缩略图 "|<[\/\!].*?[^<>]*

  • PHP中HTML标签过滤技巧

    在开发文章系统中正常需要用到HTML标签.JS脚本等其他脚本代码的过滤,稍微尝试了下,感觉简单的htmlspecialchars()函数的过滤效果始终不如strip_tags()函数的过滤效果好. 其中有人会说我就想还要显示点图片,那怎么办呢? 没关系,我们对文章内容进行二次处理,正则找出某个图片的地址,然后对整个布局动态调控下,将图片放到最后,其效果还有可能会达到微博或者是Q空间动态的那种效果,多一举两得啊!

  • php中将html中的br换行符转换为文本输入中的换行符

    下面这几个方法将能够帮你解决这个问题. PHP版将html中的<br />换行符转换为文本框中的换行符: 复制代码 代码如下: function br2nl($text){    return preg_replace('/<br\\s*?\/??>/i','',$text);} 或者: 复制代码 代码如下: function br2nl($text){    $text=preg_replace('/<br\\s*?\/??>/i',chr(13),$text); r

  • php自定义函数转换html标签示例

    本文实例讲述了php自定义函数转换html标签的方法.分享给大家供大家参考,具体如下: <?php /* * Created on 2016-9-29 * */ $orig = "I'll \"walk\" the <b>dog</b> now"; $a = htmlentities($orig); $b = html_entity_decode($a); echo $a; // I'll "walk" the &l

  • php去除HTML标签实例

    例1.php自带的函数可以去除/删除字符串中的HTML标签/代码.strip_tags(string,allow):函数剥去 HTML.XML 以及 PHP 的标签.参数:string,必填,规定要检查的字符串:allow,选填,规定允许存在的标签,这些标签不会被删除. 复制代码 代码如下: $str = '郭碗瓢盆-<span style="color:#f00;">PHP</span>'; $str1 = strip_tags($str);         

  • PHP实现HTML标签自动补全代码

    一般情况下先用PHP的 strip_tags 函数去掉所有html标签,再去掉空格等,然后再用substr或者自己实现的cn_substr函数来实现截取.因为如果不先去掉html标签,直接截取出来的字符串就会有没有闭合的标签出现,有时甚至会截取在标签上面比如 复制代码 代码如下: </di ... 今天遇到一个内容翻页截取问题: 正文是用富文本编辑器写入的,编辑器上有个分页按钮,点击之后就往当前光标位置插入一个蓝色的 复制代码 代码如下: <hr /> 横线.然后php直接存入数据库.显

  • php过滤HTML标签、属性等正则表达式汇总

    $str=preg_replace("/\s+/", " ", $str); //过滤多余回车 $str=preg_replace("/<[ ]+/si","<",$str); //过滤<__("<"号后面带空格)   $str=preg_replace("/<\!--.*?-->/si","",$str); //注释 $str=p

  • php实现过滤表单提交中html标签的方法

    本文实例讲述了php实现过滤表单提交中html标签的方法.分享给大家供大家参考.具体实现方法如下: 有时候我们做的简单评论功能会发现有提交很多的html标签,这些标签会导致页面有一些外连的情况,下面我们一起来看在php中过滤表单提交的html标签方法. 近评论中有一些机器人提交的post链接,都是一些垃圾评论.为了减少这种无谓的链接内容出现,其实是可以用php来删除表单POST提交的html标签,这样机器提交的信息也不会得到他们要的结果.而且可以减少来自seo/seo.html" target=

  • php获取网页标题和内容函数(不包含html标签)

    复制代码 代码如下: function getPageContent($url) { //$url='http://www.ttphp.com; $pageinfo = array();           $pageinfo[content_type] = '';           $pageinfo[charset] = '';           $pageinfo[title] = '';           $pageinfo[description] = '';          

随机推荐