总结ThinkPHP导出数据到表格的几种方法及代码,分享给大家,注释超详细。

我先具体介绍完这几种方法,然后在结尾会将几种办法进行优缺点的分析和比较,方便大家择优利用。

第一种:导出excel格式,这种方法适合数据量不太大的情况,比如下面这段代码是勾选导出。

public function excelExport(){
        $ids = substr($_REQUEST['ids'],0);//传到这个方法的数据id
        import("ORG.PHPExcel.PHPExcel");//引入PHPExcel引擎
        $objPHPExcel = new PHPExcel();    
        $objProps = $objPHPExcel->getProperties();
        $objProps->setCreator("smartcrm");//灰色的代码就是给导出的表格设置一些属性,无需变动
        $objProps->setLastModifiedBy("smartcrm"); 
        $objProps->setTitle("smartcrm");    
        $objProps->setSubject("smartcrm");    
        $objProps->setDescription("smartcrm");    
        $objProps->setKeywords("smartcrm");    
        $objProps->setCategory("smartcrm");
        $objPHPExcel->setActiveSheetIndex(0);     
        $objActSheet = $objPHPExcel->getActiveSheet(); 
        $objActSheet->setTitle('Sheet1');
        $row = 1;   //行坐标
        $col = "A"; //列坐标
        $field_list = M()->select();//查出要导出的数据的字段列表
        foreach($field_list as $field){
            $objActSheet->setCellValue($col.$row ,$field['name']);//将字段的名字循环放在第一行
            $col ++;
        }
        $list = M()->where('id in(%s)',$ids)->select();//查询要导出的数据
        foreach ($list as $k => $v) {//循环写入excel表格,先循环行,再循环列,一个单元格一个单元的写
            $row ++;//第一行写完,行累加
            $col = "A"; //列坐标 
            foreach($field_list as $field){//这里可以对导出数据按照字段进行处理,比如时间戳转化为日期格式等等等。
                 $objActSheet->setCellValue($col.$row, $v[$field['field']]);
                 $col++;//第一行第一列写完,列累加
            }
        }
        $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
        header("Content-Type: application/vnd.ms-excel;");
        header("Content-Disposition:attachment;filename=XXX.xls");//XXX定义导出Excel的名字
        header("Pragma:no-cache");
        header("Expires:0");

        $objWriter->save('php://output');
}

第二种:导出csv格式,这种方法适合数据量大的情况,比如一次性全部导出(兼容个别导出)等等,折后总导出方式的原理是分批次循环导出,防止查询压力过大导致的崩溃。

public function excelExportAll(){
        $ids = !!$_REQUEST['ids'] ? $_REQUEST['ids'] : false;
        $fileDir=(substr(dirname(__FILE__),0,strpos(dirname(__FILE__),'\App'))."/App/Runtime/Temp/");
        if(!is_dir($fileDir)) mkdir($fileDir);//设置文件生成的路径
        $fileName=substr(basename(__FILE__),0,strpos(basename(__FILE__),'.'));
        $fileTime=time();
        $fileType=".csv";
        $file=$fileDir.$fileName.'-'.$fileTime.$fileType;设置导出文件的名称,这么长是为了防止重复,保证生成文件的唯一性
        $fp=fopen($file,"w+");//以写入的方式打开文件
        $field_list = M()->select();//获取所有导出字段
        $title_name    = array();
        foreach($field_list as $column=>$detail) {//循环写入标题
            array_push($title_name,utf2gb($detail['name']));//这里注意设计汉字的需要转码,否则导出来你会看到火星文
        }
        fputcsv($fp,$title_name);
        $where =  'id in('.$ids.")";
        $count  = M()->where($where)->count();
        $once_c =1000; //手动分批次,这里根据服务器性能和内存情况适量定义
        $cur_s  = 0;
        $run_time=floor($count/$once_c);
        for($i=0;$i<=$run_time;$i++){
          $list = M()->limit($cur_s.",".$once_c)->select();//每次只查询$once_c条数据
          foreach ($list as $k => $row) {
               $array_column[$k] = $row;//把 数据都放在$array_column这个数组里
               foreach($row as $c=>$v) {   
                     //这里可进行一系列转化操作,如时间戳的字段转化为日期格式等,转化的字段和内容如果很多的话会使内存随着循环叠加上升,我利用任务管理器做过测试,下面我会详细介绍。
               } 
               fputcsv($fp,$array_column[$k]);//把$array_column数组循环写入到打开文件中
           }
           $cur_s += $once_c;//这个批次循环完,累加循环下一批
        }
        if(fclose($fp)){//写完关闭文件
            $down_name=$fileName;
            $content=file_get_contents($file);
            unlink($file);
            header("Content-Type: text/csv;charset=utf-8"); 
            header("Content-Type: application/force-download");
            header("Content-Type: application/octet-stream");
            header("Content-Type: application/download");
            header("Content-Disposition: attachment; filename=$down_name".".csv"); 
            header('Cache-Control:must-revalidate,post-check=0,pre-check=0'); 
            header('Expires:0'); 
            header('Pragma:public');
            echo $content;
        }
 }

第三种:这种办法是我在大神指点下做出来的,画面比较炫酷,单独做了导出的页面,下面我会 附张图。数据量大的时候会有动态进度条以及预估的下载时间,当然我用的 进度条插件是ui-progressbars.js和animation.js,弹层插件是layer,下面我把后台代码以及html页面分享给大家。

HTML:

<script src="__PUBLIC__/js/ui-progressbars.js"></script>
<script src="__PUBLIC__/js/animation.js"></script>
<div class="tab-content" style="border-bottom:0px;">
<div class="form-group">
<div class="progress progress-striped active">
   <div id="progress-bar" role="progressbar" style="width:0" class="progress-bar"></div>
</div>
</div>
<p id="tips"></p>
<div class="form-group">
<label class="col-sm-5 control-label"></label>
<div id="btn_download" class="col-sm-7"></div>
</div>
</div>
<script>
$(function(){
Excelexport();
function Excelexport(option){//把返回的json格式数据整理后继续请求
$.ajax({
type: 'GET',
data: option,
url: 'index.php?m=cdr&a=excelExportAll&ids={$ids}',
dataType: "json",
success: function(data){
if(!data.is_end){
var progress = Math.round(data.cur_s/data.count*100) +"%";
$("#tips").html("共 "+data.count+" 条数据,大约需要 "+data.total+" 秒,请耐心等待。");
$("#progress-bar").css('width',progress);
$("#progress-bar").html(progress);
var e_opt = {file:data.file,step:data.step,cur_s:data.cur_s,count:data.count,fileName:data.fileName};
Excelexport(e_opt);
}else{//导出完毕后出现下载按钮,点击调用后台下载方法实现下载
layer.title('导出完毕。感谢您的耐心等待!');
progress = '100%';
$("#tips").html("导出完成,请点击下载。");
$("#progress-bar").css('width',progress);
$("#progress-bar").html(progress);
$("#btn_download").html("<a οnclick='javascript:layer.closeAll();' href='index.php?m=cdr&a=excelDownload&fileName="+data.fileName+"&file="+data.file+"' class='btn btn-primary'>下载</a>");
}
}
});
}
});
</script>


PHP:

//导出的代码,就是前台ajax不停请求的方法

public function excelExportAll(){
$ids = !!$_REQUEST['ids'] ? $_REQUEST['ids'] : false;
        $fileDir=(substr(dirname(__FILE__),0,strpos(dirname(__FILE__),'\App'))."/App/Runtime/Temp/");
        if(!is_dir($fileDir)) mkdir($fileDir);//设置文件生成的路径
        $fileName=substr(basename(__FILE__),0,strpos(basename(__FILE__),'.'));
        $fileTime=time();
        $fileType=".csv";
        $file=$fileDir.$fileName.'-'.$fileTime.$fileType;设置导出文件的名称,这么长是为了防止重复,保证生成文件的唯一性
        $fp=fopen($file,"w+");//以写入的方式打开文件
        $field_list = M()->select();//获取所有导出字段
        $title_name    = array();
        foreach($field_list as $column=>$detail) {//循环写入标题
            array_push($title_name,utf2gb($detail['name']));//这里注意设计汉字的需要转码,否则导出来你会看到火星文
        }

        $step = !!$_REQUEST['step'] ? $_REQUEST['step'] : 0;//方法一方法二唯一的区别在于此,把方法二循环的原理改为前台ajax请求,这样巧妙地的防止了内存的增长
        if($step == 0) {   
            fputcsv($fp,$title_name);
        }
        $where =  'id in('.$ids.")";
        $once_c =10000; //手动分批次,这里根据服务器性能和内存情况适量定义
        $cur_s  = !!$_REQUEST['cur_s'] ? $_REQUEST['cur_s'] : 0;

$limit  = $cur_s.",".$once_c;

        $once_c = 10000;
        $count  = $step == 0 ? $m->where($where)->count() : $_REQUEST['count'];

$run_time=floor($count/$once_c);
        $list = $m->where($where)->limit($limit)->select();

 foreach ($list as $k => $row) {
               $array_column[$k] = $row;//把 数据都放在$array_column这个数组里
    
      //这里可进行一系列转化操作,如时间戳的字段转化为日期格式等。
               fputcsv($fp,$array_column[$k]);//把$array_column数组循环写入到打开文件中 fputcsv($fp,$array_column[$k]);//把$array_column数组循环写入到打开文件中
         }
   
        $cur_s += $once_c;
        $step  ++;
        if($step > $run_time) {
            $is_end = true;  
        }else{
            $is_end = false; //最后一次循环的时候告诉前台停止ajax请求
        }
        $time = sec_format($run_time * 1.9);
        fclose($fp);
        $download['file'] = urlencode($file);
        $download['is_end'] = $is_end;
        $download['total'] = $time;
        $download['step'] = $step;
        $download['cur_s'] = $cur_s;
        $download['count'] = $count;
        $download['fileName'] = $fileName;
        echo json_encode($download);//把一系列参数整理后以json格式返回
        exit;
}
//下载的代码
public function excelDownload(){
        set_time_limit(0);  
        ini_set('memory_limit', '1024M');//这两句是为了防止数据库崩溃,临时扩大内存,按需修改。
        ob_start();
        $down_name=$_REQUEST['fileName'];
        header("Content-Type: text/csv;charset=utf-8"); 
        header("Content-Type: application/force-download");
        header("Content-Type: application/octet-stream");
        header("Content-Type: application/download");
        header("Content-Disposition: attachment; filename=$down_name".".csv"); 
        header('Cache-Control:must-revalidate,post-check=0,pre-check=0'); 
        header('Expires:0'); 
        header('Pragma:public');
        readfile($_REQUEST['file']);
        ob_flush();

}

第四种:方法三稍作修改就可以实现像Mysql数据库导出那样的效果,即点击导出后,浏览器下方出现下载文件,随着导出的进行,前面一个小圈就不停的转啊转,直到下载完毕。他们其实就是把导出的东西放在浏览器进行,边导出边写入,只需要把上面 fputcsv($fp,$array_column[$k])这句代码改成echo impolde(',',$array_column[$k]).'/r/n'就可以了,其余的前台页面等等的都不要了,差不多是下面这个意思。

public function excelExportAll(){
$ids = !!$_REQUEST['ids'] ? $_REQUEST['ids'] : false;
        $fileDir=(substr(dirname(__FILE__),0,strpos(dirname(__FILE__),'\App'))."/App/Runtime/Temp/");
        if(!is_dir($fileDir)) mkdir($fileDir);//设置文件生成的路径
        $fileName=substr(basename(__FILE__),0,strpos(basename(__FILE__),'.'));
        $fileTime=time();
        $fileType=".csv";
        $file=$fileDir.$fileName.'-'.$fileTime.$fileType;设置导出文件的名称,这么长是为了防止重复,保证生成文件的唯一性
        $fp=fopen($file,"w+");//以写入的方式打开文件
        $field_list = M()->select();//获取所有导出字段
        $title_name    = array();
        foreach($field_list as $column=>$detail) {//循环写入标题
            array_push($title_name,utf2gb($detail['name']));//这里注意设计汉字的需要转码,否则导出来你会看到火星文
        }
        $step = !!$_REQUEST['step'] ? $_REQUEST['step'] : 0;//方法一方法二唯一的区别在于此,把方法二循环的原理改为前台ajax请求,这样巧妙地的防止了内存的增长
        if($step == 0) {   
            fputcsv($fp,$title_name);
        }
        $where =  'id in('.$ids.")";
        $once_c =10000; //手动分批次,这里根据服务器性能和内存情况适量定义
        $cur_s  = !!$_REQUEST['cur_s'] ? $_REQUEST['cur_s'] : 0;

$limit  = $cur_s.",".$once_c;

        $once_c = 10000;
        $count  = $step == 0 ? $m->where($where)->count() : $_REQUEST['count'];

$run_time=floor($count/$once_c);
        $list = $m->where($where)->limit($limit)->select();

 foreach ($list as $k => $row) {
               $array_column[$k] = $row;//把 数据都放在$array_column这个数组里
    
      这里可进行一系列转化操作,如时间戳的字段转化为日期格式等。
           
   echo impolde(',',$array_column[$k]).'/r/n';
         }
    
        $cur_s += $once_c;
        $step  ++;
        if($step > $run_time) {
ob_start();
        $down_name=$_REQUEST['fileName'];
        header("Content-Type: text/csv;charset=utf-8"); 
        header("Content-Type: application/force-download");
        header("Content-Type: application/octet-stream");
        header("Content-Type: application/download");
        header("Content-Disposition: attachment; filename=$down_name".".csv"); 
        header('Cache-Control:must-revalidate,post-check=0,pre-check=0'); 
        header('Expires:0'); 
        header('Pragma:public');
        readfile($_REQUEST['file']);
        ob_flush();
        }else{

exit;

}
}


重点来了,分析一下上述4种方法的利弊:

第一种:适用于数据量小的导出,优点是导出的xls格式,不会导致乱码的问题,但数据量大的话会直接崩掉。

第二种:优点是可以导出大量的数据,但比较依靠服务器内存,因为如果你导出的数据需要处理的情况比较多,尤其是需要关联其他表转化等等的时候,内存依然会随着循环而增长,这样如果数据量很大的话依然会导致崩的问题,而且相比第四种情况,这种方法导出大量数据的时候会显得比较死板,没有像方法三炫酷的进度提示,也没有方法四那样浏览器下方的运行状态。

第三种:这种方法相对而言对于各种情况最兼容的办法,当然如果你不需要转化很多数据,可以用方法二或者四,因为方法三也有缺点,比如下载时依然会依赖内存,导出完毕时必须下载略显繁琐等等,希望广大技术大牛继续探讨完善。

第四种:简单直观的导出方式,我认为i,如果是那种可以直接导出的数据优先选择这种方法比较好。

凡事皆有利弊,择优录取。这是我第一次写博客,以后依然会把我所掌握的,总结的方法陆续更新上来,或者有什么好的技术也会分享给大家,我也是刚入行不到一年的新手,望有什么错误请谅解,共同探讨学习。

以下是使用ThinkPHP框架和PHPExcel类库导出Excel表格的步骤: 1.下载并安装PHPExcel类库,将下载的PHPExcel文件夹放入项目的vendor目录下。 2.创建一个控制器,例如ExcelController,并在控制器中添加一个export方法。 3.在export方法中,实例化PHPExcel类库,并设置Excel表格的属性,例如表格标题、表格列名等。 4.从数据库中获取需要导出数据,并将数据填充到Excel表格中。 5.将Excel表格输出到浏览器,让用户可以下载。 以下是一个示例代码: ```php <?php namespace app\index\controller; use think\Controller; use PHPExcel; use PHPExcel_IOFactory; class ExcelController extends Controller { public function export() { // 实例化PHPExcel类库 $objPHPExcel = new PHPExcel(); // 设置Excel属性 $objPHPExcel->getProperties()->setCreator("ThinkPHP") ->setLastModifiedBy("ThinkPHP") ->setTitle("Office 2007 XLSX Test Document") ->setSubject("Office 2007 XLSX Test Document") ->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.") ->setKeywords("office 2007 openxml php") ->setCategory("Test result file"); // 设置表格标题 $objPHPExcel->setActiveSheetIndex(0) ->setCellValue('A1', '姓名') ->setCellValue('B1', '年龄') ->setCellValue('C1', '性别'); // 从数据库中获取数据 $data = db('user')->select(); // 将数据填充到Excel表格中 $i = 2; foreach ($data as $item) { $objPHPExcel->setActiveSheetIndex(0) ->setCellValue('A' . $i, $item['name']) ->setCellValue('B' . $i, $item['age']) ->setCellValue('C' . $i, $item['gender']); $i++; } // 输出Excel表格到浏览器 header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment;filename="user.xlsx"'); header('Cache-Control: max-age=0'); $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); $objWriter->save('php://output'); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值