基于TP5、phpspreadsheet导出数据和图片到excel,以及我导出图片时的踩坑分享

本文介绍如何使用PhpSpreadsheet替代PHPExcel进行Excel操作,包括安装方法、基础及进阶使用技巧,并详细讲解了如何在Excel中嵌入图片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于PHPExcel已经被废弃已经无法获取更新,所以建议优先使用phpspreadsheet

1、composer安装(全局安装composer教程)
	composer require phpoffice/phpspreadsheet

或者在composer.json文件require下面加上 "phpoffice/phpspreadsheet": "^1.2", ,之后在终端 composer update 就可以安装了

2、开始前小知识点

2.1 基础常用
	use PhpOffice\PhpSpreadsheet\IOFactory;   // 必须引入
	use PhpOffice\PhpSpreadsheet\Spreadsheet; // 必须引入

    $newExcel = new Spreadsheet();            // 实例化

    // 将默认字体设置为Arial
    $newExcel->getDefaultStyle()->getFont()->setName('微软雅黑');
    // 将字体大小设置为12
    $newExcel->getDefaultStyle()->getFont()->setSize(12);
    // 将A7至B7两单元格设置为粗体字,Arial字体
    $newExcel->getActiveSheet()->getStyle('A7:B7')->getFont()->setBold(true)->setName('Arial')->setSize(10);
    // 将A列单元格设置为粗体字
    $newExcel->getActiveSheet()->getStyle('A')->getFont()->setBold(true);
    // 将A列单元格文字颜色设置为红色
    $newExcel->getActiveSheet()->getStyle('A')->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_RED);
    // 将A列宽度设置为50
    $newExcel->getActiveSheet()->getColumnDimension('A')->setWidth(50);
    // 如果需要自动计算列宽,可以这样
    $newExcel->getActiveSheet()->getColumnDimension('A')->setAutoSize(true);
    // 设置默认列宽为50,作用于所有列
    $newExcel->getActiveSheet()->getDefaultColumnDimension()->setWidth(50);
    // 设置第5行行高为50
    $newExcel->getActiveSheet()->getRowDimension('5')->setRowHeight(50);
    // 设置默认行高为60,作用于所有行
    $newExcel->getActiveSheet()->getDefaultRowDimension()->setRowHeight(60);
    // 给A到F列单元格设置水平居中对齐
    $newExcel->getActiveSheet()->getStyle('A:F')->getAlignment()->setVertical('center');
    // 给A到F列单元格设置垂直居中对齐
    $newExcel->getActiveSheet()->getStyle('A:F')->getAlignment()->setHorizontal('center');
    // 单独给A列单元格设置垂直居中对齐
    $newExcel->getActiveSheet()->getStyle('A')->getAlignment()->setHorizontal('center');
2.2 拓展小知识
2.2.1 将B2至B8的区域添加红色边框
	$styleArray = [
	    'borders' => [
	        'outline' => [
	            'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,
	            'color'       => ['argb' => 'FFFF0000']
	        ],
	    ]
	];
	
	$newExcel->getActiveSheet()->getStyle('B2:B8')->applyFromArray($styleArray);
2.2.2 将A1单元格设置为水平居中对齐
	$styleArray = [
	    'alignment' => [
	        'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
	    ],
	];
	
	$newExcel->getActiveSheet()->getStyle('A1')->applyFromArray($styleArray);

	# 也可以对A1到C1单元格做单独处理,这里要注意的是样式覆盖,如果你上面做的是垂直居中,那这里就会把上面的覆盖掉
	$newExcel->getActiveSheet()->getStyle('A1:C1')->applyFromArray($styleArray);
2.2.3 对A1到A5单元格添加背景填充色
	$newExcel->getActiveSheet()->getStyle('A1:A5')->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setARGB('ffffff');
3、以上知识点对于一般的导出基本够用了,接下来我们引入类库正式开始
    # PhpSpreadsheet导出图片
    public static function export()
    {
        set_time_limit(0);

        // 读取数据
        $orderList = Db::name("goods_order")->where([])->limit(3)->select();

        $newExcel = new Spreadsheet();             //创建一个新的excel文档
        $objSheet = $newExcel->getActiveSheet();   //获取当前操作sheet的对象
        $objSheet->setTitle('订单表');             //设置当前sheet的标题

        // 将默认字体设置为Arial
        $newExcel->getDefaultStyle()->getFont()->setName('微软雅黑');
        // 将字体大小设置为12
        $newExcel->getDefaultStyle()->getFont()->setSize(12);
        // 将D列单元格设置为粗体字
        $newExcel->getActiveSheet()->getStyle('H')->getFont()->setBold(true);
        // 将D列单元格文字颜色设置为红色
        $newExcel->getActiveSheet()->getStyle('H')->getFont()->getColor()->setARGB(Color::COLOR_RED);
        // 设置默认行高为60
        $newExcel->getActiveSheet()->getDefaultRowDimension()->setRowHeight(60);

        // 给标题单元格设置水平垂直居中对齐
        $newExcel->getActiveSheet()->getStyle('A:K')->getAlignment()->setHorizontal('center');
        $newExcel->getActiveSheet()->getStyle('A:K')->getAlignment()->setVertical('center');

        // 给每列单元格设置宽度
        $newExcel->getActiveSheet()->getColumnDimension('A')->setWidth(15);
        $newExcel->getActiveSheet()->getColumnDimension('B')->setWidth(30);
        $newExcel->getActiveSheet()->getColumnDimension('C')->setWidth(15);
        $newExcel->getActiveSheet()->getColumnDimension('D')->setWidth(15);
        $newExcel->getActiveSheet()->getColumnDimension('E')->setAutoSize(true);
        $newExcel->getActiveSheet()->getColumnDimension('F')->setWidth(15);
        $newExcel->getActiveSheet()->getColumnDimension('G')->setWidth(15);
        $newExcel->getActiveSheet()->getColumnDimension('H')->setWidth(30);
        $newExcel->getActiveSheet()->getColumnDimension('I')->setAutoSize(true);
        $newExcel->getActiveSheet()->getColumnDimension('J')->setWidth(30);
        $newExcel->getActiveSheet()->getColumnDimension('K')->setWidth(50);

        //设置第一栏的标题
        $objSheet->setCellValue('A1', '用户id')
            ->setCellValue('B1', '订单编号')
            ->setCellValue('C1', '商品分类')
            ->setCellValue('D1', '商品品牌')
            ->setCellValue('E1', '尺寸说明')
            ->setCellValue('F1', '订单状态')
            ->setCellValue('G1', '回收进度')
            ->setCellValue('H1', '操作说明')
            ->setCellValue('I1', '下单时间')
            ->setCellValue('J1', '正面图')
            ->setCellValue('K1', '备用多图');

        // 第二行起,每一行的值,setCellValueExplicit是用来导出文本格式的
        foreach ($orderList as $key => $val) {
            $key = $key + 2;
            $objSheet->setCellValue('A' . $key, $val['user_id'])
                ->setCellValue('B' . $key, $val['order_sn'])
                ->setCellValue('C' . $key, $val['category_ids'])
                ->setCellValue('D' . $key, $val['brand_id'])
                ->setCellValue('E' . $key, $val['dimensions'])
                ->setCellValue('F' . $key, $val['status'])
                ->setCellValue('G' . $key, $val['process'])
                ->setCellValue('H' . $key, $val['memo'])
                ->setCellValue('I' . $key, date('Y-m-d H:i:s', $val['createtime']));

            $num = 10;

            // 多图导出
            if (!empty($val['images'])) {
                $images = explode(",", $val['images']);
                foreach ($images as $k => $v){
                    $image = request()->domain() . $v;

                    // 获取本地文件夹路径
                    $dir = ROOT_PATH . '/public/uploads/' . date('Ymd', time()) . '/';
                    $file_info = pathinfo($image);

                    // 过滤非文件类型
                    if (!empty($file_info['basename'])) {
                        $basename = $file_info['basename'];
                        // 进行检测文件是否存在
                        is_dir($dir) OR mkdir($dir, 0777, true);
                        file_put_contents($dir . $basename, file_get_contents($image));

                        // 引入操作图片类
                        $drawings[$key] = new Drawing();
                        $drawings[$key]->setResizeProportional(false); // TODO 此处顺序不可调,因为导出默认是按原图像缩放的,设置成false才可以设置成可控制的宽度,要注意哦!
                        $drawings[$key]->setName('备用多图');
                        $drawings[$key]->setDescription('备用多图');
                        $drawings[$key]->setPath($dir . $basename);
                        $drawings[$key]->setWidth(60);
                        $drawings[$key]->setHeight(60);
                        $drawings[$key]->setOffsetX($num);
                        $drawings[$key]->setOffsetY(10);
                        $drawings[$key]->setCoordinates('K' . $key);
                        $drawings[$key]->setWorksheet($objSheet);
                    }

                    $num = $num + 70; // 增加每张图之间的间距
                }
            }
            else
            {
                $objSheet->setCellValue('K' . $key, '');
            }

            // 单图导出
            if (!empty($val['positive_image'])) {
                $positive_image = request()->domain() . $val['positive_image'];
                // 获取本地文件夹路径
                $dir = ROOT_PATH . '/public/uploads/' . date('Ymd', time()) . '/';
                $file_info = pathinfo($positive_image);

                // 过滤非文件类型
                if (!empty($file_info['basename'])) {
                    $basename = $file_info['basename'];

                    // 进行检测文件是否存在
                    is_dir($dir) OR mkdir($dir, 0777, true);
                    file_put_contents($dir . $basename, file_get_contents($positive_image));

                    // 引入操作图片类
                    $drawing = new Drawing();
                    $drawing->setResizeProportional(false); // TODO 此处顺序不可调,因为导出默认是按原图像缩放的,设置成false才可以设置成可控制的宽度,要注意哦!
                    $drawing->setName('正面图');
                    $drawing->setDescription('正面图');
                    $drawing->setPath($dir . $basename);
                    $drawing->setWidth(60);
                    $drawing->setHeight(60);
                    $drawing->setOffsetX(10);
                    $drawing->setOffsetY(10);
                    $drawing->setCoordinates('J' . $key);
                    $drawing->setWorksheet($objSheet);
                }
            }
            else
            {
                $objSheet->setCellValue('J' . $key, '');
            }
        }

        return self::downloadExcel($newExcel, '订单表', 'Xls');
    }

    # 公共文件,用来传入xls并下载
    public static function downloadExcel($newExcel, $filename, $format)
    {
        // $format只能为 Xlsx 或 Xls
        if ($format == 'Xlsx') {
            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        } elseif ($format == 'Xls') {
            header('Content-Type: application/vnd.ms-excel');
        }

        header("Content-Disposition: attachment;filename=" . $filename . date('Y-m-d') . '.' . strtolower($format));
        header('Cache-Control: max-age=0');
        $objWriter = IOFactory::createWriter($newExcel, $format);

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

        //通过php保存在本地的时候需要用到
        //$objWriter->save($dir . '/demo.xlsx');

        // 以下为需要用到IE时候设置
        // If you're serving to IE 9, then the following may be needed
        // header('Cache-Control: max-age=1');
        // If you're serving to IE over SSL, then the following may be needed

        // header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
        // header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
        // header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
        // header('Pragma: public'); // HTTP/1.0

        return true;
    }

在这里插入图片描述

4、踩坑分享

首先我说明一下可能是我太菜了,我是第一次用PhpSpreadsheet导出图片到excel

// 引入操作图片类
$drawings[$key] = new Drawing();
$drawings[$key]->setResizeProportional(false); 
$drawings[$key]->setName('备用多图');
$drawings[$key]->setDescription('备用多图');
$drawings[$key]->setPath($dir . $basename);
$drawings[$key]->setWidth(60);
$drawings[$key]->setHeight(60);
$drawings[$key]->setOffsetX($num);
$drawings[$key]->setOffsetY(10);
$drawings[$key]->setCoordinates('K' . $key);
$drawings[$key]->setWorksheet($objSheet);

因为导出图片默认是按原图像成比例缩放的,这里需要把 setResizeProportional() 设置成false才可以设置成可控制的宽度,而且设置的位置要在顶部,否则不起作用,要注意了 $drawings[$key]->setResizeProportional(false); 这一行代码放的位置,千万不能放错了

感慨一下,我希望我们都能有一点奉献精神,就遇到问题踩的坑大家都能仔细的分享出来,与其你给我完整的demo不如给我分享你踩的坑,因为这次我没踩过这个坑不代表我下一次不会踩坑或许是因为项目需求的问题反正方方面面了,就是大家搞技术的都能奉献一点,这样很多问题都能得到解决,我就是随心写的,如果对你的心理造成伤害我表示抱歉哈,嘿嘿。

5、参考文献

1、https://www.cnblogs.com/windyet/articles/9711044.html
2、https://blog.youkuaiyun.com/VI7591/article/details/102129994
3、https://phpspreadsheet.readthedocs.io/en/latest/

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值