嗯,如题 是个蛋疼物
目前QQ的聊天记录导出功能很让人郁闷
三种聊天记录格式的导出
1 TXT 没图
2 BAK 只能再导入QQ使用
3 MHT 有图有字,缺点是一旦聊天记录很多,文件体积就会很大,几乎所有的工具都不能正常打开
单纯的把MHT转换成HTML也不行,因为HTML也很大,加上图片之类的资源 也会卡死
于是只能切开显示,处理思路很简单,就是超大的文本文件,按行顺序处理,把图片解码存入文件,然后分割HTML内容
代码如下 只支持单个QQ群导出记录
<?php ini_set(\'pcre.backtrack_limit\',1000000); $is_table_end = false ; $page = 0 ;$contents = \'\'; $output_zip = \'./test.zip\'; #判断输入文件 if(!file_exists($argv[1])) { echo \'There isn\\'t have this file.\'; exit; } #建立归档文件 默认为 make_output_target($output_zip); $handle = fopen($argv[1], "rb"); #分段处理 do { $contents .=fread($handle,124416);#wtf $contents = mht_process($contents,$output_zip); } while (!feof($handle)); #主体数据处理 function mht_process($contents,$output_zip){ Global $is_table_end; Global $page; $zip = new ZipArchive; if ($zip->open($output_zip,ZIPARCHIVE::CREATE) !== TRUE) { echo \'create image failed\'; exit; } #判断非图片消息部分是否处理完毕 if(false === $is_table_end) { $html_head = \'<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>QQ Message</title><style type="text/css">body{font-size:12px; line-height:22px; margin:2px;}td{font-size:12px; line-height:22px;}</style></head><body><table width=100% cellspacing=0>\'; $html_foot = \'</table></body></html>\'; #判断消息部分是否完毕 只处理图片部分 if(false !== strpos($contents,$html_foot)) { $is_table_end = true; } $r = preg_match_all (\'|<tr.*?\</tr\>|ims\', $contents , $matches ,PREG_OFFSET_CAPTURE); if($r) { $matches = array_chunk($matches[0],200); foreach($matches as $key=>$val) { $arr = array_column($val,0); array_walk( $arr , function(&$v, $k) use ($zip) { $v = preg_replace(\'|<IMG src="{(\S)(\S)(\S+).dat|ims\',\'<IMG src="../images/$1/$2/{$1$2$3.dat\',$v); }); $zip->addFromString(\'messages/\'.sprintf("%08d", $page+$key).\'.html\' ,$html_head . implode(\'\',$arr).\'<td> <H1><a href="./\'.sprintf("%08d", $page+$key-1).\'.html">Prev page</a></h1> <H1><a href="./\'.sprintf("%08d", $page+$key+1).\'.html">Next page</a></h1></td>\'.$html_foot); } $page += $key; $pos = end($val); $contents = substr($contents,bcadd($pos[1],strlen($pos[0]),0)); } else { $contents = \'\'; } } #处理图片部分 if(true === $is_table_end) { #图片数据匹配 $r = preg_match_all (\'|Content-Type:image.*?:base64.*?Content-Location:(.*?)\.dat(.*?)(?:------=_)|ims\', $contents , $matches ,PREG_OFFSET_CAPTURE | PREG_SET_ORDER); if($r) { //$matches = array_chunk($matches[0],200); $result = array(); foreach($matches as $key=>$val){ $result = array(\'name\'=>$val[1][0],\'contents\'=>$val[2][0]); $dir = \'images/\'. substr($result[\'name\'],1,1) .\'/\' . substr($result[\'name\'],2,1) .\'/\'.$result[\'name\'] . \'.dat\'; #写入图片表情文件到硬盘 $zip->addFromString($dir,base64_decode(trim($result[\'contents\']))); $result = array(); } $result = array(); $contents = substr($contents,$val[0][1]); } else { $contents = \'\'; } } $zip->close(); #剩余部分返回 下一次处理拼接数据 return $contents; } #建立保存目标 function make_output_target($output=\'./test.zip\') { $zip = new ZipArchive; if ($zip->open($output,ZIPARCHIVE::CREATE) !== TRUE) { echo \'create images directory failed\'; exit; } $zip->addEmptyDir(\'images\'); $tmp = array(\'0\',\'1\',\'2\',\'3\',\'4\',\'5\',\'6\',\'7\',\'8\',\'9\',\'A\',\'B\',\'C\',\'D\',\'E\',\'F\',\'G\',\'H\',\'I\',\'J\',\'K\',\'L\',\'M\',\'N\',\'O\',\'P\',\'Q\',\'R\',\'S\',\'T\',\'U\',\'V\',\'W\',\'X\',\'Y\',\'Z\'); array_walk($tmp,function($val,$key) use ($tmp,$zip) { $base_path = \'images/\'.$val; $zip->addEmptyDir($base_path); array_walk($tmp,function($val,$key) use ($tmp,$zip,$base_path) { $zip->addEmptyDir($base_path.\'/\'.$val); }); }); $zip->addEmptyDir(\'messages\'); $zip->close(); return 0; }
使用方法
1 "php.exe" cli.php input.mht > log.txt 2 pause
生成ZIP之后 可以用winmount来挂载查看 无需解压很方便