听·时光

# 网站数据迁移之二:VSB9系统的数据导入MySQL数据库中

开发 Tags: 数据迁移 阅读: 422

项目情况:某单位网站原网站是基于VSB9系统开发的,改版后的网站采用的技术是PHP+MySQL。问题:如何将原网站系统的数据导入到新版网站?
一开始也想像上一篇文章提到思路那样处理,直接读取VSB9的数据库,然后插入到MySQL数据库中。但是研究发现VSB9是一款商业软件,没有提供直接访问数据库的接口。所以这个方法行不通。
后面发现VSB9后台提供了导出文章的功能(也只能一个栏目一个栏目地导出)。
VSB9系统导出文章示例图

导出后的文件解压后结构如下:
VSB9导出文章1.png
点开某篇文章目录,里面结构为:
VSB9导出文章2.png
其中Excel文件存储文章所属栏目,点击次数等信息;“内容”文件夹里面是一个txt文档,存储文章的内容;图片文件夹存储文章的图片文件,如果文章没有图片,那么“图片”这个文件夹就没有;如果文章还上传了附件,那么还有一个“附件”文件夹存储附件文档。
那么,现在处理的思路就是:在VSB9网站后台分别导出每个栏目的所有文章,然后遍历文件夹,读取相关内容插入到MySQL数据库中。
代码如下:

    //处理文件夹的函数
    function handleDir($dir,$level=1,$newFileDir,$newImgDir,$k=0){
        if(is_dir($dir)){
            if ($dh = opendir($dir)){
                while (($file = readdir($dh)) !== false){
                    if((is_dir($dir."/".$file)) && $file!="." && $file!="..") {
                        $k++;
                        echo '正在处理第'.$k.'个文件夹。<br />';
                        handleDir($dir."/".$file."/",$level+1,$newFileDir,$newImgDir,$k);
                    }else{
                        if($file!="." && $file!=".."){
                            if(($level-1)==1){
                                if(in_array('内容',getSubDirs($dir))){
                                    if(!copy(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'内容/正文.txt'),iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'正文.txt'))){
                                        echo '移动“正文.txt”位置失败!';
                                    }else{
                                        unlink(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'内容/正文.txt'));
                                    }
                                    $content = file_get_contents(iconv("UTF-8", "GBK", mb_convert_encoding($dir, "UTF-8", "GBK") . '正文.txt'));
                                   $content = str_replace("'","\'",$content);
                                    $fp=fopen(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'正文.txt'),  'w');
                                    fwrite ($fp,$content);
                                    fclose ($fp);
                                    rmdir(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'内容'));
                                }else if(in_array('附件',getSubDirs($dir))){
                                    $arr = getSubDirs(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'附件'));
                                    for($i=0;$i<count($arr);$i++) {
                                        $content = file_get_contents(iconv("UTF-8", "GBK", mb_convert_encoding($dir, "UTF-8", "GBK") . '正文.txt'));
                                        $content = $content . '<br /><p>附件:<a href="'.$newFileDir.$arr[$i].'" target="_blank">'.$arr[$i].'</a></p>';
                                        if(!copy(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'附件/'.$arr[$i]),iconv("UTF-8","GBK","../../$newFileDir".$arr[$i]))){
                                            echo '移动“附件”位置失败!';
                                        }else{
                                            unlink(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'附件/'.$arr[$i]));
                                        }
                                    }
                                    deldir(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'附件'));
                                    $fp=fopen(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'正文.txt'),  'w');
                                    fwrite ($fp,$content);
                                    fclose ($fp);
                                }else if(in_array('图片',getSubDirs($dir))){
                                    $arr = getSubDirs(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'图片'));
                                    $key = array_search('_thumb', $arr);
                                    if ($key !== false) {array_splice($arr, $key, 1);}
                                    $key = array_search('source', $arr);
                                    if ($key !== false) {array_splice($arr, $key, 1);}
                                    $content = file_get_contents(iconv("UTF-8", "GBK", mb_convert_encoding($dir, "UTF-8", "GBK") . '正文.txt'));
                                    for($i=0;$i<count($arr);$i++) {
                                        $content = str_replace($arr[$i], $newImgDir.$arr[$i], $content);
                                        if (!copy(iconv("UTF-8", "GBK", mb_convert_encoding($dir, "UTF-8", "GBK") . '图片/' . $arr[$i]), iconv("UTF-8", "GBK", "../../$newImgDir".$arr[$i]))) {
                                            echo '移动“图片”位置失败!';
                                        }else{
                                            unlink(iconv("UTF-8", "GBK", mb_convert_encoding($dir, "UTF-8", "GBK") . '图片/' . $arr[$i]));
                                        }
                                    }
                                    deldir(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'图片'));
                                    $fp=fopen(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'正文.txt'),  'w');
                                    fwrite ($fp,$content);
                                    fclose ($fp);
                                }
                            }
                        }
                    }
                }
                closedir($dh);
            }else{
                echo mb_convert_encoding($dir, "UTF-8", "GBK").'已经删除';
            }
            return true;
        }else{
            return false;
        }
    }
    //读取具体内容函数
    function handleFile($dir,$level=1,$k=0){
        if(is_dir($dir)){
            if ($dh = opendir($dir)){
                while (($file = readdir($dh)) !== false){
                    if((is_dir($dir."/".$file)) && $file!="." && $file!="..") {
                        $k++;
                        echo '正在处理第'.$k.'篇文章。<br />';
                        handleFile($dir."/".$file."/",$level+1,$k);
                    }else{
                        if($file!="." && $file!=".."){
                            if(($level-1)==1){
                                $objReader = PHPExcel_IOFactory::createReader('Excel5');
                                $objReader->setLoadSheetsOnly('基本信息');
                                $content = file_get_contents(iconv("UTF-8","GBK",mb_convert_encoding($dir, "UTF-8", "GBK").'正文.txt'));
                                            
                                $content = mb_convert_encoding($content,"GBK","UTF-8");
                                $content = str_replace("?","",$content);
                                $content = mb_convert_encoding($content,"UTF-8","GBK");
                                preg_match("/^.*\.(?:xls)$/","$file",$matches);
                                if(count($matches)>0){
                                    $objPHPExcel = $objReader->load($dir.$matches[0]);
                                    $sheetData1 = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true);
                                    $objReader->setLoadSheetsOnly('高级信息');
                                    $objPHPExcel = $objReader->load($dir.$matches[0]);
                                    $sheetData2 = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true);
                                    $arr[] = array('标题'=>$sheetData1[2]['C'],'作者'=>$sheetData1[6]['C'],'发布时间'=>$sheetData1[8]['C'],'副标题'=>$sheetData1[11]['C'],'点击数'=>$sheetData2[7]['C'],'修改时间'=>$sheetData2[17]['C'],'正文内容'=>$content);
                                }
                    $title = $arr[0]['标题'];
                    $author = $arr[0]['作者'];
                    $time = $arr[0]['发布时间'];
                    $hit = $arr[0]['点击数'];
                    $content = $arr[0]['正文内容'];
                    //为不泄露表的结果,用字段1,字段2取代真实字段信息
                    $sql = "INSERT INTO news('字段1','字段2','字段3','字段4',....) VALUES(12,'admin',85,'$title','$author','$content','$time','$hit',1,'','','','','','','','a',1,'','')";
                            }
                        }
                    }
                }
                if(isset($sql)){
                    if(mysql_query($sql)){
                        add_count('作者1',date('Y-m',strtotime($time)));//添加发稿记录
                        echo '成功导入第'.$k.'篇文章。<br />';
                    }else{
                        echo '导入出现问题。'.mysql_error().'<br />';
                    }
                }
                closedir($dh);
            }else{
                echo mb_convert_encoding($dir, "UTF-8", "GBK").'已经删除';
            }
        }
    }
    //删除文件夹函数
    function deldir($dir) {
        $dh=opendir($dir);
        while ($file=readdir($dh)) {
            if($file!="." && $file!="..") {
                $fullpath=$dir."/".$file;
                if(!is_dir($fullpath)) {
                    unlink($fullpath);
                } else {
                    deldir($fullpath);
                }
            }
        }
        closedir($dh);
        //删除当前文件夹:
        if(rmdir($dir)){
            return true;
        }else{
            return false;
        }
    }
    //取得文件夹子目录函数
    function getSubDirs($dir){
        $subdirs = array();
        if(!$dh = opendir($dir)){
            return $subdirs;
        }
        $i = 0;
        while ($f = readdir($dh)) {
            if($f =='.' || $f =='..')
                continue;
            //如果只要子目录名, path = $f;
            //$path = $dir.'/'.$f;
            $path = $f;
            $subdirs[$i] = mb_convert_encoding("$path", "UTF-8", "GBK");
            $i++;
        }
        return $subdirs;
    }
    //脚本消耗内存函数
    function memory_usage() {
        $memory     = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB';
        return $memory;
    }
    //增加发稿记录函数
    function add_count($source,$time){
        $sql = "SELECT * FROM a_count WHERE count_name='$source' AND count_addtime = '$time'";
        $result = mysql_query($sql);
        $num = mysql_num_rows($result);
        if($num==0){
            $result2 = mysql_query("INSERT INTO a_count(count_name,count_num,count_addtime) VALUES ('$source',1,'$time')");
            return TRUE;
        }else{
            $result2 = mysql_query("UPDATE a_count SET count_num = count_num+1 WHERE count_name='$source' AND count_addtime='$time'");
            return TRUE;
        }
        return FALSE;
    }
    //开始运行
    $time = microtime(true);
    header('Content-Type: text/html; charset=utf-8');
    define('FILENAME',iconv("UTF-8","GBK","./文件通知"));
    define('NEW_FILE_DIR',iconv("UTF-8","GBK","/fujian/file/"));
    define('NEW_IMG_DIR',iconv("UTF-8","GBK","/fujian/img/"));
    include './Classes/PHPExcel/IOFactory.php';//要读取excel文件,引用了PHPExcel库
    if(handleDir(FILENAME,1,NEW_FILE_DIR,NEW_IMG_DIR,0)){
        handleFile(FILENAME,1,0);
        $time2 = microtime(true);
        $total = $time2-$time;
        echo '数据导入处理成功!,导入此栏目全部文章共耗时'.$total.'秒。<br />';
    }else{
        echo '批处理导出文章(文件夹)出现错误!';
    }
    echo '导入此栏目全部文章消耗内存:'.memory_usage();

以上代码思路:
因为每篇文章对应的文件夹下还含有子目录,所以首先遍历文件夹,把子目录全部处理掉(调用handleDir()函数):把正文内容移到上一级目录、图片、附件文件移到网站对应的目录,并且删除掉“内容”,“图片”,“附件”文件夹。处理完了后的文件夹结构为:
处理后的文件结构.png
处理完后再次遍历,就不用考虑每个文件夹下面的子栏目了,因为里面只剩下一个excel文件和一个txt文件了。接下来再次遍历,读取excel文件里有关内容和txt的正文内容存入MySQL数据库中(调用handleFile()函数)。
经过实践验证发现,这个方法一次性能处理的文章数约为500左右,如果某个栏目下有1700篇文章,那么要分成3个批次进行处理,如果一次直接处理1700篇文章,那么程序运行后一段时间会挂掉(哪怕把PHP内存加到2G也还是会挂掉)。其原因是每次读取excel调用的类库执行起来比较耗内存。

附:VSB9是什么? (以下内容来自百度百科)
VSB9(全称Visual SiteBuilder 9)是博达软件独立开发拥有自主知识产权的高度产品化的站群管理软件,是一款功能完善的门户网站、站群建设和管理软件。VSB实现了基于纯浏览器界面的网站创建和编辑,VSB9具备强大的多站点(站群形式)管理功能,并提供企业级协作管理环境及多种安全服务体系,保证系统的正常运行,避免网络的非授权使用。
发表评论