PHP压缩HTML-使用正则安全的压缩
程序员文章站
2022-04-30 14:05:29
...
分析HTML代码
HTML一般包括以下的部分:
标签,以<>包裹
文档声明、注释等<!...>格式
半开标签<..../>
闭合标签</..>
内容,非以<>包裹,这一部分内容中多空格是无效果的
PHP正则分解html代码
html代码是以标签为界限的,所以,只要按标签分解就可以了。在PHP中使用preg_split:
$segments = preg_split("/(<[^>]+?>)/si",$html, null,PREG_SPLIT_NO_EMPTY| PREG_SPLIT_DELIM_CAPTURE);
例如,以下的代码
$html = <<<HTML <!doctype html> <html> <head> <title>狼魂博客</title> <meta charset="utf-8"> <meta name="description" content="关注WEB,体悟生活;珍惜生命,远离代码。"> </head> <body> <div class="wrap"> <a class="rss" href="http://pjiaxu.com/rss.xml">文章RSS</a> <a class="rss" href="http://pjiaxu.com/map.html">网站地图</a> <a class="rss" href="http://pjiaxu.com/archives.html">日期归档</a> <a class="rss" href="http://pjiaxu.com/tags.html">标签归档</a> <h2 id="logo"><a href="http://pjiaxu.com/" title="狼魂博客">狼魂博客</a></h2> <p id="webdesc">关注WEB,体悟生活;珍惜生命,远离代码。</p> <div class="clear"></div> </div> </body> </html> HTML; print_r(preg_split("/(<[^>]+?>)/si",$html, -1,PREG_SPLIT_NO_EMPTY| PREG_SPLIT_DELIM_CAPTURE));
会产生如下的输出:
Array ( [0] => <!doctype html> [1] => [2] => <html> [3] => [4] => <head> [5] => [6] => <title> [7] => 狼魂博客 [8] => </title> [9] => [10] => <meta charset="utf-8"> [11] => [12] => <meta name="description" content="关注WEB,体悟生活;珍惜生命,远离代码。"> [13] => [14] => </head> [15] => [16] => <body> [17] => [18] => <div class="wrap"> [19] => [20] => <a class="rss" href="http://pjiaxu.com/rss.xml"> [21] => 文章RSS [22] => </a> [23] => [24] => <a class="rss" href="http://pjiaxu.com/map.html"> [25] => 网站地图 [26] => </a> [27] => [28] => <a class="rss" href="http://pjiaxu.com/archives.html"> [29] => 日期归档 [30] => </a> [31] => [32] => <a class="rss" href="http://pjiaxu.com/tags.html"> [33] => 标签归档 [34] => </a> [35] => [36] => <h2 id="logo"> [37] => <a href="http://pjiaxu.com/" title="狼魂博客"> [38] => 狼魂博客 [39] => </a> [40] => </h2> [41] => [42] => <p id="webdesc"> [43] => 关注WEB,体悟生活;珍惜生命,远离代码。 [44] => </p> [45] => [46] => <div class="clear"> [47] => </div> [48] => [49] => </div> [50] => [51] => </body> [52] => [53] => </html> )
最简单但有损的PHP压缩
最简单的压缩就是直接连接所有的非空项,同时非标签去掉所有的空白:
$compressed = array(); foreach($segments as $seg) { $seg = trim($seg); if($seg) { //非标签中的空白是无效的字符 $compressed[] = $seg[0] === '<' ? $seg : preg_replace('!\s!','',$seg); } } return join('',$compress);
如以上的HTML通过这样的压缩生成的代码是(为了方便显示,我手动将它们断行了):
<!doctype html><html><head><title>狼魂博客</title><meta charset="utf-8"> <meta name="description" content="关注WEB,体悟生活;珍惜生命,远离代码。"></head> <body><div class="wrap"><a class="rss" href="http://pjiaxu.com/rss.xml">文章RSS</a> <a class="rss" href="http://pjiaxu.com/map.html">网站地图</a> <a class="rss" href="http://pjiaxu.com/archives.html">日期归档</a> <a class="rss" href="http://pjiaxu.com/tags.html">标签归档</a><h2 id="logo"> <a href="http://pjiaxu.com/" title="狼魂博客">狼魂博客</a></h2> <p id="webdesc">关注WEB,体悟生活;珍惜生命,远离代码。</p><div class="clear"> </div></div></body></html>
正常情况下这没错,但是也有“不正常”的情况:遇到不能去掉空白的内容时。比如script、code、pre、style是不可以去掉空白的,这时,就要使用栈进行压缩了:
使用栈进行安全压缩html
使用栈的规则是:<..>标签入栈,</..>标签出栈,<!..>和<../>不理,但有一种可能的情况是,<../>不一定有结尾的反斜杠如:
<meta> <meta/>
都是可以的,这时就要特殊的处理这种情况:
<?php $html = <<<HTML <body> <div class="wrap"> <a class="rss" href="http://pjiaxu.com/rss.xml">文章RSS</a> <a class="rss" href="http://pjiaxu.com/map.html">网站地图</a> <a class="rss" href="http://pjiaxu.com/archives.html">日期归档</a> <a class="rss" href="http://pjiaxu.com/tags.html">标签归档</a> <h2 id="logo"><a href="http://pjiaxu.com/" title="狼魂博客">狼魂博客</a></h2> <p id="webdesc">关注WEB,体悟生活;珍惜生命,远离代码。</p> <div class="clear"></div> </div> <pre> var say = "Hello world!"; print say; </pre> </body> HTML; $segments = preg_split("/(<[^>]+?>)/si",$html, -1,PREG_SPLIT_NO_EMPTY| PREG_SPLIT_DELIM_CAPTURE); $compressed = array(); $stack = array(); $tag = ''; $half_open = array('meta','input','link','img','br'); $cannot_compress = array('pre','code','script','style'); foreach($segments as $seg) { if(trim($seg) === '') { continue; } //<.../> if(preg_match("!<([a-z0-9]+)[^>]*?/>!si",$seg, $match)) { //$tag = self::format_tag($match[1]); format_tag($match[1]); $compressed[] = $seg; } else if(preg_match("!</([a-z0-9]+)[^>]*?>!si",$seg,$match))//</..> { $tag = format_tag($match[1]); if(count($stack) > 0 && $stack[count($stack)-1] == $tag) { array_pop($stack); $compressed[] = $seg; } //这里再最好加一段判断,可以用于修复错误的html //... } else if(preg_match("!<([a-z0-9]+)[^>]*?>!si",$seg,$match))//<> { $tag = format_tag($match[1]); //半闭合标签不需要入栈,如<br/>,<img/> if(!in_array($tag, $half_open)) { array_push($stack,$tag); } $compressed[] = $seg; } else if(preg_match("~<![^>]*>~", $seg)) { //文档声明和注释,注释也不能删除,如<!--ie条件--> $compressed[] = $seg; } else { $compressed[] = in_array($tag, $cannot_compress) ? $seg : preg_replace('!\s!', '', $seg); } } function format_tag($tag) { return trim(strtolower($tag)); } echo join('',$compressed);
以上的代码产生如下的输出(为了方便显示,我手工断行了):
<body><div class="wrap"><a class="rss" href="http://pjiaxu.com/rss.xml">文章RSS</a> <a class="rss" href="http://pjiaxu.com/map.html">网站地图</a> <a class="rss" href="http://pjiaxu.com/archives.html">日期归档</a> <a class="rss" href="http://pjiaxu.com/tags.html">标签归档</a><h2 id="logo"> <a href="http://pjiaxu.com/" title="狼魂博客">狼魂博客</a></h2><p id="webdesc"> 关注WEB,体悟生活;珍惜生命,远离代码。</p><div class="clear"></div></div><pre> var say = "Hello world!"; print say; </pre></body>
最安全的HTML压缩
当然,以上的代码正确运行的基础是:HTML都是正确合法的,没有出现如<a><b></a></b>等,但是在普通应用是没有问题的,如果需要安全的压缩HTML代码,可以使用HTML解析库进行修复并进行压缩
推荐阅读
-
使用php的zlib压缩和解压缩swf文件_PHP教程
-
php使用pclzip类实现文件压缩的方法(附pclzip类下载地址)
-
php文件打包 下载之使用PHP自带的ZipArchive压缩文件并下载打包好的文件
-
php使用gzip压缩传输js和css文件的方法
-
php的zip解压缩类pclzip使用示例
-
php文件打包 下载之使用PHP自带的ZipArchive压缩文件并下载打包好的文件
-
php使用gzip压缩传输js和css文件的方法
-
php使用ZipArchive函数实现文件的压缩与解压缩
-
PHP使用zlib扩展实现GZIP压缩输出的方法详解
-
php使用curl获取header检测开启GZip压缩的方法