toumingbai

 嗯,如题 是个蛋疼物
目前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来挂载查看 无需解压很方便 

分类:

技术点:

相关文章: