Hyperf结合PhpOffice/PhpSpreadsheet实现Excel&CSV文件导出导入

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: Hyperf结合PhpOffice/PhpSpreadsheet实现Excel&CSV文件导出导入。PhpSpreadsheet是一个用纯PHP编写的库,它提供了一组类,允许您读取和写入各种电子表格文
本文环境 Hyperf2.1,PHP7.3,Mysql5.7
不懂的可以评论或联系我邮箱:owen@owenzhang.com
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Hyperf & PhpSpreadsheet介绍

Hyperf 介绍

Hyperf 是基于 Swoole 4.5+ 实现的高性能、高灵活性的 PHP 协程框架,内置协程服务器及大量常用的组件,性能较传统基于 PHP-FPM 的框架有质的提升,提供超高性能的同时,也保持着极其灵活的可扩展性,标准组件均基于 PSR 标准 实现,基于强大的依赖注入设计,保证了绝大部分组件或类都是 可替换 与 可复用 的。

PhpOffice/PhpSpreadsheet 介绍

PhpSpreadsheet是一个用纯PHP编写的库,它提供了一组类,允许您读取和写入各种电子表格文件格式,如Excel和LibreOffice Calc。

PhpSpreadsheet是PHPExcel的下一个版本。它破坏了兼容性,从而大大提高了代码库质量(命名空间、PSR 合规性、使用最新的 PHP 语言功能等)。

因为所有的努力都转移到了PhpSpreadsheet上,PHPExcel将不再被维护。所有对 PHPExcel 的贡献、补丁和新功能都应针对 PhpSpreadsheet 分支。master

PhpOffice/PhpSpreadsheet 安装

使用composer将 PhpSpreadsheet 安装到你的项目中:

composer require phpoffice/phpspreadsheet

或者,如果您计划使用它们,还可以下载文档和示例:

composer require phpoffice/phpspreadsheet --prefer-source

image.png

文件导出导入&代码实例

csv文件导出

导出实例类文件

函数说明:使用hyperf框架的跨域中间件

  • ->withHeader 添加浏览器响应头
  • ->withBody 添加浏览器内容主体
  • Headers 可以根据实际情况进行改写。

代码实例:

<?php
/**
 * Created by PhpStorm.
 * Created by OwenZhang at 2021/11/8 14:39
 */

namespace App\Common;

use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\HttpServer\Response;

class Csv
{
    /**
    $head = ['name'=>'名字','score'=>'得分'];
    $data = [
                ['name' => '张三', 'score' => '80'],
                ['name' => '李四', 'score' => '90'],
                ['name' => '王五', 'score' => '60'],
            ];
     $fileName = '测试'
     */
    /**
     * Describe:   导数数据 (csv 格式)
     * @param array $head
     * @param array $body
     * @param string $fileName '测试.csv','测试.xlsx'
     * @return \Psr\Http\Message\ResponseInterface
     * Created by lkz at 2021/11/8 14:47
     */
    static function export(array $head, array $body, string $fileName)
    {
        $head_keys = array_keys($head);
        $head_values = array_values($head);
        $fileData = self::utfToGbk(implode(',', $head_values)) . "\n";

        foreach ($body as $value) {
            $temp_arr = [];
            foreach ($head_keys as $key) {
                $temp_arr[] = $value[$key] ?? '';
            }
            $fileData .= self::utfToGbk(implode(',', $temp_arr)) . "\n";
        }
        $response = new Response();
        $contentType = 'text/csv';
        return $response->withHeader('content-description', 'File Transfer')
            ->withHeader('content-type', $contentType)
            ->withHeader('content-disposition', "attachment; filename={$fileName}")
            ->withHeader('content-transfer-encoding', 'binary')
            ->withHeader('pragma', 'public')
            ->withBody(new SwooleStream($fileData));
    }

    /**
     * 字符转换(utf-8 => GBK)
     * @param $data
     * @return false|string
     */
    static function utfToGbk($data)
    {
        return mb_convert_encoding($data,"GBK","UTF-8");
       # return iconv('utf-8', 'GBK', $data);
    }

}

调用导出实例函数方法

调用上面的csv文件导出类,浏览器调整新页面直接下载导出。

代码实例:

/**
 * Describe: 列表导出
 * Route: get /admin/badword_list_export
 * Created by OwenZhang at 2021/12/13 10:14
 */
public function getBadwordListExport(): ResponseInterface
{
    $page = (int)$this->request->input('page', 1);
    $pageSize = (int)$this->request->input('page_size', 15);
    $word = (string)$this->request->input('word', '');
    $type = (string)$this->request->input('type', '');

    $container = ApplicationContext::getContainer();
    $exportArray = $container->get(BadwordServiceInterface::class)->getBadwordListExport($page, $pageSize, $word, $type);
    //$exportArray 数组,每个里面键值和$header一样   
    
    set_time_limit(0);
    ini_set('memory_limit', '5048M');
    $filename = '敏感词数据' . date('ymdHis');

    $header = [
        'badword_id' => '敏感词id',
        'word' => '敏感词',
        'type' => '分类',
        'style_name' => '应用区域',
        'replace_word' => '替换词',
    ];

    return Csv::export($header, $exportArray, $filename);
}

excel文件导出

导出实例类文件

  1. xls后缀excel文件导出的heard头:\
    xls='application/vnd.ms-excel'
  2. xlsx后缀excel文件导出的heard头:\
    xlsx='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

函数说明:

  • 构造函数 创建一个PhpSpreadsheet实例 __construct()
  • 设置表头 $title=['id','标题','内容'] setHeader($title)
  • 添加表内容 $data=[ [1,标题1,内容1], [2,标题2,内容2], ... ] addData($data)
  • 保存到服务器本地 $fileName=文件名 saveToLocal($fileName)
  • 直接从浏览器下载到本地,有问题,不使用,php://output 目前PhpSpreadsheet插件有问题,PhpSpreadsheet插件作者还在修复 saveToBrowser($fileName)
  • 保存临时文件在从浏览器自动下载到本地 saveToBrowserByTmp($fileName)

代码实例:

<?php
/**
 * Created by PhpStorm.
 * Created by OwenZhang at 2021/12/28 14:39
 */

namespace App\Common;

use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\HttpServer\Response;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;

class ExportExcelHandle
{
    private $sheet;
    private $spreadsheet;
    private $row;

    //构造函数 创建一个PhpSpreadsheet实例
    public function __construct()
    {
        // Create new Spreadsheet object
        $this->spreadsheet = new Spreadsheet();
        // Set document properties
        $this->spreadsheet->getProperties()->setCreator('Maarten Balliauw')
            ->setLastModifiedBy('Maarten Balliauw')
            ->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');
        // Add some data
        $this->spreadsheet->setActiveSheetIndex(0);
        $this->sheet = $this->spreadsheet->getActiveSheet();
        // Rename worksheet
        $this->spreadsheet->getActiveSheet()->setTitle('Sheet1');
    }

    //设置表头
    public function setHeader($title)
    {
        foreach ($title as $key => $item) {
            $this->sheet->setCellValue(chr($key + 65) . '1', $item);
        }
        $this->row = 2; // 从第二行开始
        return $this;
    }

    //添加表内容
    public function addData($data)
    {
        foreach ($data as $item) {
            $dataCol = 'A';
            foreach ($item as $value) {
                // 单元格内容写入
                $this->sheet->setCellValue($dataCol . $this->row, $value);
                $dataCol++;
            }
            $this->row++;
        }
        return $this;
    }

    //保存到服务器本地
    public function saveToLocal($fileName)
    {
        // Set active sheet index to the first sheet, so Excel opens this as the first sheet
        $this->spreadsheet->setActiveSheetIndex(0);

        $fileName = $fileName . '.xlsx';
        $url = '/storage/' . $fileName;
        $outFilename = BASE_PATH . $url;
        $writer = IOFactory::createWriter($this->spreadsheet, 'Xlsx');
        $writer->save($outFilename);
        $this->spreadsheet->disconnectWorksheets();
        unset($this->spreadsheet);
        return ['path' => $outFilename, 'filename' => $fileName];
    }

    //直接从浏览器下载到本地,有问题,不使用
    // php://output 目前PhpSpreadsheet插件有问题,PhpSpreadsheet插件作者还在修复
    public function saveToBrowser($fileName)
    {
        $fileName = $fileName . '.xlsx';
        //xls='application/vnd.ms-excel'
        //xlsx='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

        $writer = IOFactory::createWriter($this->spreadsheet, 'Xlsx');
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="' . $fileName . '"');
        header('Cache-Control: max-age=0');

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

    //保存临时文件在从浏览器自动下载到本地
    public function saveToBrowserByTmp($fileName)
    {
        $fileName = $fileName . '.xlsx';

        $writer = IOFactory::createWriter($this->spreadsheet, "Xlsx");
        //保存到服务器的临时文件下
        $writer->save("./tmp.xlsx");

        //将文件转字符串
        $content = file_get_contents('./tmp.xlsx');

        //删除临时文件
        unlink("./tmp.xlsx");

        $response = new Response();
        //xls='application/vnd.ms-excel'
        //xlsx='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        $contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';

        return $response->withHeader('content-description', 'File Transfer')
            ->withHeader('content-type', $contentType)
            ->withHeader('content-disposition', "attachment; filename={$fileName}")
            ->withHeader('content-transfer-encoding', 'binary')
            ->withHeader('pragma', 'public')
            ->withBody(new SwooleStream((string)$content));
    }

}

调用导出实例函数方法

函数说明:

  • 保存到服务器本地

$exportService->setHeader($title)->addData($data)->saveToLocal($fileName);

  • 下载服务器的文件到本地

$this->response->download($result['path'], $result['filename']);

  • 保存临时文件在从浏览器自动下载到本地

$exportService->setHeader($title)->addData($data)->saveToBrowserByTmp($fileName);

代码实例:

 /**
     * Describe: 列表导出
     * Route: get /admin/badword_list_export
     * Created by OwenZhang at 2021/12/13 10:14
     */
    public function getBadwordListExport()
    {
        set_time_limit(0);
        ini_set('memory_limit', '5048M');

        $fileName = '敏感词数据' . date('YmdHis');
        //表头
        $title = [
            '敏感词id',
            '敏感词',
            '分类',
            '应用区域',
            '替换词',
        ];
        //表体数据
        $list = ($this->applicationContext::getContainer())->get(BadwordServiceInterface::class)->getBadwordListExport();
        $data = [];
        foreach ($list as $value) {
            $data[] = [
                $value['badword_id'],
                $value['word'],
                $value['type'],
                $value['style_name'],
                $value['replace_word'],
            ];
        }
        $exportService = new ExportExcelHandle();
//        //保存到服务器本地
//        $result = $exportService->setHeader($title)->addData($data)->saveToLocal($fileName);
//        //下载服务器的文件到本地
//        return $this->response->download($result['path'], $result['filename']);

        //保存临时文件在从浏览器自动下载到本地
        return $exportService->setHeader($title)->addData($data)->saveToBrowserByTmp($fileName);
    }

php://output问题分享

直接从浏览器下载到本地,有问题,不使用

php://output 目前PhpSpreadsheet插件有问题,PhpSpreadsheet插件作者还在修复

https://github.com/PHPOffice/PhpSpreadsheet/issues/28#issuecomment-263101387

211daea0641e63c1c4e4e2b5bac2682.png

excle文件导入(批量添加数据到Mysql)

查看另外一篇文章详细使用PhpOffice/PhpSpreadsheet读取和写入Excel - 掘金 (juejin.cn)

调用PhpSpreadsheet读取函数方法

函数说明:

  • 获取上传文件的临时路径 $file['tmp_file']
  • 指定第一个工作表为当前 $spreadsheet->getSheet(0)->toArray();
  • execl文件读取数据$container->get(BadwordServiceInterface::class)->getBadwordListImport($data);
  • 批量添加数据到mysql getBadwordListImportToMysql

代码实例:

/**
 * Describe: 列表导入
 * Route: get /admin/badword_list_import
 * Created by OwenZhang at 2021/12/13 10:14
 */
public function getBadwordListImport(): ResponseInterface
{
    $file = $this->request->file('import_file')->toArray();
    //获取上传文件的临时路径
    if (!isset($file['tmp_file'])) {
        throw new BusinessException(ErrorCode::BUSINESS_ERROR, "文件上传失败");
    }
    $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file['tmp_file']);
    //指定第一个工作表为当前
    $data = $spreadsheet->getSheet(0)->toArray();
        
    $container = ApplicationContext::getContainer();
    $result = $container->get(BadwordServiceInterface::class)->getBadwordListImport($data);

    return $this->success($result);
}

/**
 * Describe: 列表导入-批量添加数据到mysql
 * Route: get /admin/badword_list_import
 * @param array $data 数据
 * @return string
 * Created by OwenZhang at 2021/12/16 10:14
 */
public function getBadwordListImportToMysql(array $data): string
{
    $insertData = [];
    $badwordId = (int)$this->ZucaiBadwordModel->orderBy('badword_id', 'desc')->value('badword_id');

    foreach ($data as $key => $datum) {
        //第一个数据是表头
        if ($key != 0) {
            $insertData[] = [
                'badword_id' => $badwordId + $key + 1,
                'word' => $datum[1],
                'type' => $datum[2],
                'style' => 1,
                'replace_word' => '',
                'app' => Context::get('app') ?? 1,
                'created_at' => date('Y-m-d H:i:s'),
                'updated_at' => date('Y-m-d H:i:s'),
            ];
        }
    }

    if (!$insertData) {
        return '添加失败';
    }

    return $this->ZucaiBadwordModel->insert($insertData) ? '添加成功' : '添加失败';
}

Buy me a cup of coffee :)

觉得对你有帮助,就给我打赏吧,谢谢!

2538d4.jpg

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
存储 数据挖掘 Java
csv和excel
【10月更文挑战第18天】csv和excel
75 5
|
2月前
|
数据处理 Python
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档
这篇文章介绍了如何使用Python读取Excel文件中的数据,处理后将其保存为txt、xlsx和csv格式的文件。
52 3
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档
|
23天前
|
Java API Apache
|
26天前
|
存储 Java API
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
35 4
|
2月前
|
JavaScript 前端开发 数据处理
Vue导出el-table表格为Excel文件的两种方式
Vue导出el-table表格为Excel文件的两种方式
|
3月前
|
SQL C# 数据库
EPPlus库的安装和使用 C# 中 Excel的导入和导出
本文介绍了如何使用EPPlus库在C#中实现Excel的导入和导出功能。首先,通过NuGet包管理器安装EPPlus库,然后提供了将DataGridView数据导出到Excel的步骤和代码示例,包括将DataGridView转换为DataTable和使用EPPlus将DataTable导出为Excel文件。接着,介绍了如何将Excel数据导入到数据库中,包括读取Excel文件、解析数据、执行SQL插入操作。
EPPlus库的安装和使用 C# 中 Excel的导入和导出
|
2月前
|
easyexcel Java UED
SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载
在SpringBoot环境中,为了优化大量数据的Excel导出体验,可采用异步方式处理。具体做法是将数据拆分后利用`CompletableFuture`与`ThreadPoolTaskExecutor`并行导出,并使用EasyExcel生成多个Excel文件,最终将其压缩成ZIP文件供下载。此方案提升了导出效率,改善了用户体验。代码示例展示了如何实现这一过程,包括多线程处理、模板导出及资源清理等关键步骤。
|
2月前
|
数据处理 Python
Python 高级技巧:深入解析读取 Excel 文件的多种方法
在数据分析中,从 Excel 文件读取数据是常见需求。本文介绍了使用 Python 的三个库:`pandas`、`openpyxl` 和 `xlrd` 来高效处理 Excel 文件的方法。`pandas` 提供了简洁的接口,而 `openpyxl` 和 `xlrd` 则针对不同版本的 Excel 文件格式提供了详细的数据读取和处理功能。此外,还介绍了如何处理复杂格式(如合并单元格)和进行性能优化(如分块读取)。通过这些技巧,可以轻松应对各种 Excel 数据处理任务。
202 16
|
2月前
|
前端开发 JavaScript
💥【exceljs】纯前端如何实现Excel导出下载和上传解析?
本文介绍了用于处理Excel文件的库——ExcelJS,相较于SheetJS,ExcelJS支持更高级的样式自定义且易于使用。表格对比显示,ExcelJS在样式设置、内存效率及流式操作方面更具优势。主要适用于Node.js环境,也支持浏览器端使用。文中详细展示了如何利用ExcelJS实现前端的Excel导出下载和上传解析功能,并提供了示例代码。此外,还提供了在线调试的仓库链接和运行命令,方便读者实践。
328 5
|
2月前
|
JSON 数据格式
LangChain-20 Document Loader 文件加载 加载MD DOCX EXCEL PPT PDF HTML JSON 等多种文件格式 后续可通过FAISS向量化 增强检索
LangChain-20 Document Loader 文件加载 加载MD DOCX EXCEL PPT PDF HTML JSON 等多种文件格式 后续可通过FAISS向量化 增强检索
79 2

热门文章

最新文章

下一篇
无影云桌面