记录Laravel 导入Excel, 导出Excel/PDF/Word

背景

最近用 Laravel 处理了 Excel 的导入导出,PDF 和 Word 的导出,记录一下。

Ubuntu 20.04
Laravel 9.*
PHP 8.1

1. 导入excel

常见方案是使用 maatwebsite/excel 包,基于以前的使用经验,处理大的excel略慢,所以寻求更好的方案,找到了 xlswriter 一个PHP C 扩展。

xlswriter 安装

# 是否已安装xlswriter
php -m | grep xlswriter

# 安装pear
apt install php-pear
pecl channel-update pecl.php.net

apt install php8.1-dev
pecl install xlswriter

php --ini
vim /etc/php/8.1/cli/php.ini # 写入 extension=xlswriter.so
systemctl restart php8.1-fpm.service

#验证
php -m | grep xlswriter

xlswriter 使用

composer require viest/php-ext-xlswriter-ide-helper:dev-master
$excel = new \Vtiful\Kernel\Excel([
    "path" => storage_path("/excel_folder"),
]);
$excel->openFile("your_excel_file_name.xlsx");
$excel->openSheet();    // 默认 sheet1, 解析 sheet2 则传入 sheet2名称
$excel->setSkipRows(1); // 跳过一行
$row = $excel->nextRow(); // 读取数据
// 处理数据...

2. 导出excel

需要导出的数据不多,直接使用 maatwebsite/excel

maatwebsite/excel 安装及使用

composer require maatwebsite/excel
php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" --tag=config

php artisan make:export YourExcelExport

生成的文件 app\Exports\YourExcelExport.php 默认 implements FromCollection, 我习惯使用 implements FromView, 可以自定义样式。

具体CSS属性见:docs.laravel-excel.com/3.1/exports...

// 调试:调整excel样式
return view('excel_blade_name', ['data' => $data]);

// 导出
$fileName = 'export_excel_name' . date('YmdHis') . '.xlsx';
return Excel::download(new YourExcelExport($data), $fileName);

// 保存
$filePath = public_path($fileName);
Excel::store(new YourExcelExport($data), $filePath, 'local');

3. 导出pdf

3种方案:

安装 snappy

# 安装 wkhtmltopdf
apt install wkhtmltopdf 
# 注意 wkhtmltopdf 路径,不同系统可能不一样
which wkhtmltopdf

# 检查字体安装,主要是中文字体,如果未安装的话就会导致 pdf 乱码   
fc-list
# 安装 dejavu
apt-get install fonts-dejavu
composer require barryvdh/laravel-snappy
php artisan vendor:publish --provider="Barryvdh\Snappy\ServiceProvider"

config/snappy.php 中确认 pdf.binary 的路径是否正确。

snappy使用

编辑 pdf 的模板文件

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style type="text/css" media="screen">
        * {
            margin: 0;
            padding: 0;
        }
        .pdf {
            font-family: DejaVu Sans, sans-serif;
            /* 设置字体 */
            font-size: 12px;
            /* 设置字号 */
        }
    </style>
    <!-- CSS -->
    <link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet" type="text/css">
</head>
<body>
    <div class="pdf">
        <table class="table table-borderless">
            <!-- YOUR_TABLE_CODE -->
        </table>
    </div>
</body>
</html>

controller 中调用

// 调试
return view('pdf_blade_name', ['data' => $data]);

// 导出
$pdf = SnappyPdf::loadView('pdf_blade_name', ['data' => $data]);
$fileName = 'export_pdf_name.pdf';

// 如果文件名存在中文的话,下面这行取消注释
// $fileName = rawurlencode($fileName);

return $pdf->download($fileName);

// 保存
$filePath = public_path($fileName);
$pdf->save($filePath);

4. 导出word

目前貌似只有 PHPWord 这一种方案。

composer require phpoffice/phpword

基于上面 PDF 已经实现过了,所以突发奇想,以上面 pdf 或者 excel 的模板作为html来导出 word 文件。

具体操作:

// 获取 html 代码
$html_data = view('blade_view_name', ['data' => $this->data])->render();

// 转换为html
$objectWriter = IOFactory::createWriter($html_data, "HTML"); 
// 保存
$objectWriter->save($filePath);
// 导出
return response()->download($filePath);

// pdf 模板解析失败
// excel 模板成功导出 word 文件,但是失去了 table 样式

所以还是得自己写样式,因为有了excel处理的逻辑,就直接一格一格的填充table,没有(用模板文件的方式)[https://learnku.com/articles/42951]。

$phpWord = new PhpWord();
$section = $phpWord->addSection();

// 表格
$table = $section->addTable(['borderColor' => '666666', 'borderSize' => 6, 'cellMargin' => 50]);

// 第一行
$table->addRow(); 
$table->addCell(2000)->addText('cell1'); 
$table->addCell(3000, ['gridSpan' => 5])->addText('cell2'); 
$table->addCell(2000)->addText('cell3'); 
$table->addCell(3000, ['gridSpan' => 5])->addText('cell4'); 

// 合并单元格,垂直居中,首行样式
// $table->addCell(null, ['vMerge' => 'restart', 'valign' => 'center']);
// 剩余行
// $table->addCell(null, ['vMerge' => 'continue']);

5. 总结

处理 excel 最简单,word 最费事。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 1

我之前在使用 dompdf 将 markdown 转换为 pdf 格式上弄了很久,首先将 markdown 转换为 html 文件,然后 html 转换为 pdf,转换的过程中 dompdf 自带的字体不支持中文,网上下载的字体有的 dompdf 不支持,导致中文乱码

另外还有一个 barryvdh/laravel-dompdf 扩展包是基于 dompdf

4周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!