• tp5.1+php导出数据


    php thinkphp5.1 导出百万数据方案

     

    先说一下一般我们在执行大数据操作时,遇到最常见的问题就是:
    1、执行超时 参考这里
    2、内存溢出 参考这里

    看了这两个之后再来看这个方案,实现思路大概是:

    • 先利用set_time_limit(0)不限制执行时间
    • 将要查询的数据分段查询,每次查询创建一个csv临时文件,每次清空缓冲区
    • 数据全部写完之后将所有csv文件合并成一个csv文件
    • 合并之后利用zip扩展进行打包下载(如果没有安装此扩展,请先去安装扩展)
    • 最后将所有生成的文件删除

    安装扩展,PHP开启自带的ZipArchive类,实现压缩解压功能

    Windows环境:

    1. 首先需要从官网上下载,下载地址 https://windows.php.net/downloads/pecl/releases/zip/

    2. 打开官网列表后需要查找适合自己的PHP版本和系统的zip,我的PHP版本是5.5的,这里我选择的版本号是1.13.5


       
    3. 下载完后解压,把里面的php_zip.dll文件放到PHP的扩展文件夹里


       

    扩展文件夹路径一般都是在PHP版本文件夹里的ext文件夹,譬如我的就是D:php-5.5.38ext

    1. 把php_zip.dll文件放进去后,打开PHP的配置文件php.ini,添加extension=php_zip.dll,保存后,重启apache服务器

    Linux环境:
    1、在Linux下没有php_zip.dll这个文件(有也不会起作用的),所以需要重新编译一下php的zip模块。具体安装方法如下:

    cd /usr/src

    wget http://pecl.php.net/get/zip

    tar -zxvf zip

    cd zip-1.x.x

    phpize

    ./configure

    make

    sudo make instal

    其中, 在最后使用make install命令的时候,可能需要用到root的权限,所以建议使用sudo来运行。安装完之后,屏幕上会提示zip.so的位置。然后将其记录下来,如:/usr/local/lib/php/extensions/zip.so。

    2、使用root权限修改php.ini(通常可能会在/usr/local/lib/文件夹下,不过视当初安装php而定,可以通过phpinfo()来查看):

    增加extension = /usr/local/lib/php/extensions/zip.so,然后同样在php.ini文件中,将 zlib.output_compression = Off 改为 zlib.output_compression = On ;

    3、最后别忘了重启一下Apache:apachectl restart;

    这个针对php的zip模块就安装完成了,能够在php中使用ZipArchive类了。

    复制代码
        /**
         * 百万级数据导出
         */
        public function excelout(){
            //不限制执行时间,以防超时
            set_time_limit(0);
            //文件名
            $xlsName = '名字'.date('Ymd His');
            //统计总行数
            $sqlCount = 0;
    
            //表头
            $xlsCell = ['姓名','性别','年龄','电话','QQ','地址'];
            //对应表头的字段
            $fields = 'name,sex,age,tel,qq,address';
    
            //统计总行数
            $sqlCount = UserModel::count();
    
            //每次取多少条
            $sqlLimit = 2000;//每次只从数据库取2000条
    
            // buffer计数器
            $cnt = 0;
    
            $fileNameArr = array();
    
            //分段执行,以免内存写满
            for ($i = 0; $i < ceil($sqlCount / $sqlLimit); $i++) {
                $fp = fopen($xlsName . '_' . $i . '.csv', 'w'); //生成临时文件
    
                $fileNameArr[] = $xlsName . '_' .  $i . '.csv';//将临时文件保存起来
    
                //第一次执行时将表头写入
                if($i == 0){
                    fputcsv($fp, $xlsCell);
                }
    
                //查询出数据
                $xlsData = UserModel::field($fields)
                    ->limit($i * $sqlLimit,$sqlLimit)
                    ->select()->toArray();
    
                foreach ($xlsData as $k=>$v) {
                    $cnt++;
    
                    //执行下一次循环之前清空缓冲区
                    if ($sqlLimit == $cnt) {
                        ob_flush();
                        $cnt = 0;
                    }
    
                    //每行写入到临时文件
                    fputcsv($fp, $v);
                }
                fclose($fp);  //每生成一个文件关闭
            }
    
            //将所有临时文件合并成一个
            foreach ($fileNameArr as $file){
                //如果是文件,提出文件内容,写入目标文件
                if(is_file($file)){
                    $fileName = $file;
                    //打开临时文件
                    $handle1 = fopen($fileName,'r');
                    //读取临时文件
                    if($str = fread($handle1,filesize($fileName))){
                        //关闭临时文件
                        fclose($handle1);
                        //打开或创建要合并成的文件,往末尾插入的方式添加内容并保存
                        $handle2 = fopen($xlsName.'.csv','a+');
                        //写入内容
                        if(fwrite($handle2, $str)){
                            //关闭合并的文件,避免浪费资源
                            fclose($handle2);
                        }
                    }
                }
            }
    
            //将文件压缩,避免文件太大,下载慢
            $zip = new ipArchive();
            $filename = $xlsName . ".zip";
            $zip->open($filename, ipArchive::CREATE);   //打开压缩包
            $zip->addFile($xlsName.'.csv', basename($xlsName.'.csv'));   //向压缩包中添加文件
            $zip->close();  //关闭压缩包
    
            foreach ($fileNameArr as $file) {
                unlink($file); //删除csv临时文件
            }
    
            //输出压缩文件提供下载
            header("Cache-Control: max-age=0");
            header("Content-Description: File Transfer");
            header('Content-disposition: attachment; filename=' . basename($filename)); // 文件名
            header("Content-Type: application/zip"); // zip格式的
            header("Content-Transfer-Encoding: binary"); //
            header('Content-Length: ' . filesize($filename)); //
            @readfile($filename);//输出文件;
            unlink($filename); //删除压缩包临时文件
            unlink($xlsName.'.csv'); //删除合并的临时文件
        }
    复制代码
  • 相关阅读:
    仿函数(functor)
    七周七语言
    面向签名编程
    git checkout简介
    .gitkeep常用写法
    PhpStorm terminal无法输入命令的解决方法
    原 在windows上创建文件名以“.”开头的文件
    cmd 里面运行git提示“不是内部或外部命令,也不是可运行的程序”的解决办法
    .gitkeep
    git/github运用
  • 原文地址:https://www.cnblogs.com/lyzaidxh/p/12600247.html
Copyright © 2020-2023  润新知