最新ThinkPHP版本实现证书查询系统,实现批量数据导入,自动生成电子证书

前提:朋友弄了一个培训机构,培训考试合格后,给发证书,需要一个证书查询系统。委托我给弄一个,花了几个晚上给写的证书查询系统。

实现功能:

  1. 前端按照姓名+手机号码进行证书查询
  2. 证书信息展示+证书展示,支持点击下载
  3. 后端证书信息录入+带一寸照片数据批量导入

技术栈:
4. ThinkPHP8.0
5. MySQL8.0.12
6. layui

有几个技术点,得记录下:
1、给一个证书模板、一寸照片、两个电子印章图片,这个技术点是:GD库添加水印技术,水印添加也包括文字水印

添加扩展:

"ext-gd": "*",

相关代码:

// 向不同格式的图片中间画一个字符串(也是文字水印)
public function image()
 {
     // $id = Request::param('id');
     $one = Db::table('certificate')->where(Request::param())->find();


     // $this->pic($one['id']);

     /*$one = [
         "certificate_no" => "440420230078",
         "create_time" => "2022-10-10",
         "end_time" => "2032-10-10",
         "id" => 8,
         "id_no" => "4404202206223919",
         "id_type" => "身份证",
         "institution" => "智能研究院",
         "job" => "电工",
         "name" => "曹操",
         "occupation" => "低压电工证",
         "phone" => "13588889999",
         "sex" => "男",
         "skill_level" => "中级",
         "start_time" => "2022-10-10"
     ];*/
     // 图片路径
     $imagePath = './static/images/zsmb.png';
     // 图片信息
     $imageInfo = getimagesize($imagePath);
     //  [0] => 2000 [1] => 1414 [2] => 3 [3] => width="2000" height="1414" [bits] => 8 [mime] => image/png

     // 图片扩展名
     $imageExtension = image_type_to_extension($imageInfo[2], false);
     // png

     // 获取图片
     $func = 'imagecreatefrom' . $imageExtension;
     // imagecreatefrompng
     $image = $func($imagePath);
     /***************************** 文字水印开始 ********************************/
     // 水印字体
     $font = './static/fonts/SourceHanSansSC-Medium-2.otf';
     // 水印文字
     // $content = '曹操';
     // 水印颜色
     $color = imagecolorallocatealpha($image, 0, 0, 0, 30);
     // 添加水印
     imagettftext($image, 22, 0, 1450, 650, $color, $font, $one['name']);
     imagettftext($image, 22, 0, 1450, 740, $color, $font, $one['id_type']);
     imagettftext($image, 22, 0, 1450, 830, $color, $font, $one['id_no']);
     imagettftext($image, 22, 0, 1450, 910, $color, $font, $one['occupation']);
     imagettftext($image, 22, 0, 1480, 985, $color, $font, $one['job']);
     imagettftext($image, 22, 0, 1480, 1075, $color, $font, $one['skill_level']);
     imagettftext($image, 22, 0, 1450, 1155, $color, $font, $one['certificate_no']);
     imagettftext($image, 22, 0, 750, 1080, $color, $font, date("Y年n月j日", strtotime($one['create_time'])));
     imagettftext($image, 22, 0, 300, 1080, $color, $font, date("Y年n月j日", strtotime($one['create_time'])));
     imagettftext($image, 22, 0, 500, 498, $color, $font, $one['institution']);

     /***************************** 文字水印开始 ********************************/

     /***************************** 图片水印开始 ********************************/
     // 获取水印图片
     $watermarkPath = './static/images/water.png';
     $watermarkInfo = getimagesize($watermarkPath);
     $watermarkExtension = image_type_to_extension(getimagesize($watermarkPath)[2], false);
     $func = 'imagecreatefrom' . $watermarkExtension;
     $watermark = $func($watermarkPath);
     // 添加图片水印
     imagecopymerge($image, $watermark, 1280, 180, 0, 0, $watermarkInfo[0], $watermarkInfo[1], 100);
     // 销毁水印图片
     imagedestroy($watermark);

     // 生成二维码
     $qr = "./static/images/qr.png";
     $str = 'http://thinkcms.cc/index/index/image?id=' . $one['id'];
     $img_data = \tekintian\TekinQR::getQRImg($str, 5, null, 3);
     file_put_contents($qr, $img_data);

     $watermarkInfo = getimagesize($qr);
     $watermarkExtension = image_type_to_extension(getimagesize($qr)[2], false);
     $func = 'imagecreatefrom' . $watermarkExtension;
     $watermark = $func($qr);
     // 添加图片水印
     imagecopymerge($image, $watermark, 1580, 370, 0, 0, $watermarkInfo[0], $watermarkInfo[1], 100);
     // 销毁水印图片
     imagedestroy($watermark);

     $watermarkPath = './static/images/nyyz.png';
     $watermarkInfo = getimagesize($watermarkPath);
     $watermarkExtension = image_type_to_extension(getimagesize($watermarkPath)[2], false);
     $func = 'imagecreatefrom' . $watermarkExtension;
     $watermark = $func($watermarkPath);
     // 添加图片水印
     imagecopymerge($image, $watermark, 220, 850, 0, 0, $watermarkInfo[0], $watermarkInfo[1], 100);
     // 销毁水印图片
     imagedestroy($watermark);

     $watermarkPath = './static/images/gjyz.png';
     $watermarkInfo = getimagesize($watermarkPath);
     $watermarkExtension = image_type_to_extension(getimagesize($watermarkPath)[2], false);
     $func = 'imagecreatefrom' . $watermarkExtension;
     $watermark = $func($watermarkPath);
     // 添加图片水印
     imagecopymerge($image, $watermark, 720, 850, 0, 0, $watermarkInfo[0], $watermarkInfo[1], 100);
     // 销毁水印图片
     imagedestroy($watermark);

     /***************************** 图片水印开始 ********************************/

     // 输出图片
     header('Content-Type:' . $imageInfo['mime']);
     $func = 'image' . $imageExtension;
     $func($image, null, 6);
     // 销毁图片
     imagedestroy($image);
     exit;
 }

在这里插入图片描述

2、证书里的二维码,扫码就能扫码出来,是PHP生成二维码,其二维码中间也是支持加logo的

添加扩展:

"tekintian/phpqrcode": "^1.1",

相关代码:

// 生成二维码
$qr = "./static/images/qr.png";
// 这个本地测试域名,不是外网,扫码不了,上线改成外网扫了才有效
$str = 'http://thinkcms.cc/index/index/image?id=' . $one['id'];
$img_data = \tekintian\TekinQR::getQRImg($str, 5, null, 3);
file_put_contents($qr, $img_data);

3、后台实现带图片excel数据导入,这个摸索了点时间,因为PHPExcel停止维护了,改了半天源码还有问题,最后放弃了,换了一个扩展。

添加扩展:

"phpoffice/phpspreadsheet": "^1.20.0"

相关代码:

/**
 * 字母序列化为数字
 */
public function ABC2decimal($abc)
{
    $ten = 0;
    $len = strlen($abc);
    for ($i = 1; $i <= $len; $i++) {
        $char = substr($abc, 0 - $i, 1);//反向获取单个字符
        $int = ord($char);
        $ten += ($int - 65) * pow(26, $i - 1);
    }
    return $ten;
}


public function excel()
{
    if ($file = request()->file('excel')) {
        try {
            $saveName = Filesystem::disk('public')->putFile('/static/upload/excels', $file);
            if (!is_file($saveName)) {
                return json(['code' => 1, 'msg' => '文件不存在', 'data' => null]);
            }
            $ext = pathinfo($saveName, PATHINFO_EXTENSION);
            // xls不支持图片导入
            // if (!in_array($ext, ['xlsx', 'xls'])) {
            if (!in_array($ext, ['xlsx'])) {
                return json(['code' => 1, 'msg' => '文件类型不正确', 'data' => null]);
            }
            // 有两种格式,xlsx和xls
            if ($ext == 'xlsx') {
                $objReader = IOFactory::createReader('Xlsx');
            } else {
                $objReader = IOFactory::createReader('Xls');
            }
            // 图片保存路径
            $imageFilePath1 = root_path() . '/public/'; // 图片保存目录
            $imageFilePath2 = 'static/upload/images/' . date("Ymd") . '/';
            $imageFilePath = $imageFilePath1 . $imageFilePath2;
            if (!file_exists($imageFilePath)) {
                mkdir("$imageFilePath", 0777, true);
            }
            // 载入excel文件
            $excel = $objReader->load($saveName);
            // 读取第一张表
            $sheet = $excel->getActiveSheet();
            // 读取总行数
            $highestRow = $sheet->getHighestRow();
            // 读取第一张表转换成数组
            $data = $sheet->toArray();

            // 处理图片
            foreach ($sheet->getDrawingCollection() as $drawing) {
                list($startColumn, $startRow) = Coordinate::coordinateFromString($drawing->getCoordinates());
                $imageFileName = $drawing->getIndexedFilename();  // 获取文件名
                switch ($drawing->getExtension()) {
                    case 'jpg':
                    case 'jpeg':
                        $source = imagecreatefromjpeg($drawing->getPath());
                        imagejpeg($source, $imageFilePath . $imageFileName);
                        break;
                    case 'gif':
                        $source = imagecreatefromgif($drawing->getPath());
                        imagegif($source, $imageFilePath . $imageFileName);
                        break;
                    case 'png':
                        $source = imagecreatefrompng($drawing->getPath());
                        imagepng($source, $imageFilePath . $imageFileName);
                        break;
                }
                $startColumn = $this->ABC2decimal($startColumn);
                $data[$startRow - 1][$startColumn] = $imageFilePath2 . $imageFileName;
            }

            // 数据写入数据库
            $add_data = [];
            for ($i = 1; $i <= $highestRow - 1; $i++) {
                $add_data[$i]['institution'] = $data[$i][0];
                $add_data[$i]['name'] = $data[$i][1];
                $add_data[$i]['sex'] = $data[$i][2];
                $add_data[$i]['phone'] = $data[$i][3];
                $add_data[$i]['id_type'] = $data[$i][4];
                $add_data[$i]['id_no'] = $data[$i][5];
                $add_data[$i]['occupation'] = $data[$i][6];
                $add_data[$i]['job'] = $data[$i][7];
                $add_data[$i]['skill_level'] = $data[$i][8];
                $add_data[$i]['certificate_no'] = $data[$i][9];
                $add_data[$i]['create_time'] = $data[$i][10];
                $add_data[$i]['start_time'] = $data[$i][11];
                $add_data[$i]['end_time'] = $data[$i][12];
                $add_data[$i]['path'] = $data[$i][13];
            }

            // 数据插入数据库
            $success_count = Db::table('certificate')->insertAll($add_data);
            if ($success_count > 0) {
                return json(['code' => 0, 'msg' => '数据插入成功', 'data' => null]);
            } else {
                return json(['code' => 1, 'msg' => '数据插入失败', 'data' => null]);
            }
        } catch (\Exception $e) {
            return json(['code' => 1, 'msg' => $e->getMessage(), 'data' => null]);
        }
    } else {
        return json(['code' => 1, 'msg' => '上传文件不能为空', 'data' => null]);
    }
}
  1. ThinkPHP8.0开启session,没有采取前后端分离,就是前后端分离后,SEO不友好,再去前端优化搜索,那还不如直接MVC来的快,所以用到了session。根据官方手册没有配置成功,session没有生效,后面尝试了下面的方法,两者都进行配置才生效。这里记录下。

全局config配置middleware.php中

<?php
// 中间件配置
return [
    // 别名或分组
    'alias'    => [],
    // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
    'priority' => ['think\middleware\SessionInit'],
];

后端应用middleware.php中

<?php
// 这是系统自动生成的middleware定义文件
return [
	// 无关代码省略...
    \think\middleware\SessionInit::class
];

弄了写数据模拟下,最终实现的功能成果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/305201.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云仓酒庄的品牌雷盛红酒LEESON分享什么是“小农香槟”?

云仓酒庄的品牌雷盛红酒LEESON分享说起香槟&#xff0c;第一时间会想到法国&#xff0c;因为只有法国的起泡酒才能叫“香槟”。那么&#xff0c;什么又是“小农香槟”呢&#xff1f; 小农香槟是相对大厂香槟而命名的&#xff0c;是指葡萄果农自产、自酿、自销的香槟&#xff0…

【AI】AI和点云(1/2)

目录 一、什么是点云 二、点云的应用领域 三、点云的创建 四、点云感知 一、什么是点云 在三维技术领域中&#xff0c;点云被定义为一种数据结构&#xff0c;用于表示三维空间中一组离散的点。这些点通常由它们的坐标&#xff08;x&#xff0c;y&#xff0c;z&#xff09;…

二分查找

二分查找(binary search)是一种基于分治策略的高效搜索算法。它利用数据的有序性&#xff0c;每轮缩小一半搜索范围&#xff0c;直至找到目标元素或搜索区间为空为止。 例&#xff1a;给定一个n 的数组 nums &#xff0c;元素按从小到大的顺序排列且不重复。请查找并返回元素 …

尝试使用深度学习识别百度旋转验证码

最近研究了一下图像识别&#xff0c;一直找到很好的应用场景&#xff0c;今天我就发现可以用百度的旋转验证码来做一个实验。没想到效果还挺好&#xff0c;下面就是实际的识别效果。 1、效果演示 2、如何识别 2.1准备数据集 首先需要使用爬虫&#xff0c;对验证码图片进行采…

克服VSCode与WSL的互通障碍:访问‘\wsl.localhost’的有效方法

前言 大家好&#xff01;今天染念想和大家分享一下我最近在使用 VS Code 时遇到的一个有趣问题&#xff0c;以及我是如何解决它的。这个问题涉及到在 Windows 上使用 WSL&#xff08;Windows Subsystem for Linux&#xff09;时的一个安全设置问题。 首先&#xff0c;让我简单…

Java中SpringBoot组件集成接入【Knife4j接口文档(swagger增强)】

Java中SpringBoot组件集成接入【Knife4j接口文档】 1.Knife4j介绍2.maven依赖3.配置类4.常用注解使用1.实体类及属性(@ApiModel和@ApiModelProperty)2.控制类及方法(@Api、@ApiOperation、@ApiImplicitParam、 @ApiResponses)3.@ApiOperationSupport注解未生效的解决方法5.…

livp转换成jpg怎么转换?看完这篇文章你就知道了

livp转换成jpg怎么转换&#xff1f;livp文件是一种特定的图片格式&#xff0c;将其转换为jpg格式可以方便我们进行存储、共享和编辑。此外&#xff0c;jpg格式也是一种广泛支持的图片格式&#xff0c;几乎所有的设备和软件都能够识别和打开这种格式的图片。因此&#xff0c;将l…

echarts - legend设置宽度不生效

如图&#xff0c;想要这样的设计&#xff0c;文字和百分比都各自垂直对齐。 本来想要设置 legend.width &#xff0c;但是设置了不生效&#xff0c;后来找到了原因。 orient“horizontal” 的时候&#xff0c;只有width会起作用&#xff0c;height为auto&#xff1b;orient“v…

深入了解鸿鹄工程项目管理系统源码:功能清单与项目模块的深度解析

工程项目管理软件是现代项目管理中不可或缺的工具&#xff0c;它能够帮助项目团队更高效地组织和协调工作。本文将介绍一款功能强大的工程项目管理软件&#xff0c;该软件采用先进的Vue、Uniapp、Layui等技术框架&#xff0c;涵盖了项目策划决策、规划设计、施工建设到竣工交付…

GO语言笔记2-变量与基本数据类型

变量使用步骤 声明赋值使用 package main import "fmt" func main(){var age int //声明一个 int类型的变量叫ageage 18 //给变量用 赋值fmt.Println(age) //使用变量 输出变量的值 } 编译运行输出变量值 变量的四种使用方式 package main import "fmt&q…

vue3 +TS 安装使用router路由模块

一.安装 1.下载安装依赖 npm install vue-routernextnpm install types/vue-router2.router目录创建 在src 目录下 创建 /src/router文件夹 包含两个文件 route.ts import { RouteRecordRaw } from vue-routerconst routes: Array<RouteRecordRaw> [{path: /,name:…

代码随想录算法训练营Day19 | 77.组合、216.组合总和|||、17.电话号码的字母组合

回溯问题的模板 public static void backtracking(参数列表){if(终止条件){存放结果return;}for(选择&#xff1a;本层集合中元素&#xff08;树中节点孩子的数量就是集合的大小&#xff09;){处理节点;backtracking(路径&#xff0c;选择列表); // 递归回溯&#xff0c;撤销处…

3D的兔子=2D的lena?

大家好&#xff0c;今天分享一个资源&#xff0c;免费。 斯坦福兔子是3D初学者绕不开的一张图吧&#xff1f; 今天我简单用pcl读一下&#xff0c;并且把pcd文件分享一下&#xff0c;大家有需要自取。 #include <pcl/io/pcd_io.h> #include <pcl/visualization/cloud…

java⽇志体系

⽇志体系 1.体系概述2.日志的使用1.上古时代的sout2.开创先驱的log4j3.搞事情的JUL4.应运⽽⽣的JCL5.再起波澜的logback6.再度⻘春的log4j2 本篇在jdk21下测试通过 1.体系概述 1.日志接口 JCL&#xff1a;Apache基⾦会所属的项⽬&#xff0c;是⼀套Java⽇志接⼝&#xff0c;之…

python基础练习之—Series

Series介绍&#xff1a; Pandas Series 类似表格中的一个列&#xff08;column&#xff09;&#xff0c;类似于一维数组&#xff0c;可以保存任何数据类型。Series 由索引&#xff08;index&#xff09;和列组成&#xff0c;可以通过列表&#xff0c;元组&#xff0c;数组&…

qss设置某一个widget下的Checkbox的样式

#ObjectName 控件名称{属性&#xff1a;值&#xff1b;属性1&#xff1a;值1} 如下&#xff1a; 效果&#xff1a;

【QT-UI】

1.使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), …

K2P路由器刷OpenWrt官方最新版本固件OpenWrt 23.05.2方法 其他型号的智能路由器OpenWrt固件刷入方法也基本上适用

最近路由器在开机时总出问题,于是就那他来开刀,直接刷一个OpenWrt官方最新版本的固件, 刷其他第三方的固件总是觉得不安全, 而且很多第三方固件都带了些小工具,始终会有安全隐患, 而且占用内存空间太多,本来这个东西就没有多少内存,于是就干脆刷一个官方的原始固件(才6.3M, 相…

分析一个项目(微信小程序篇)一

分析一个项目讲究的是如何进行对项目的解析分解&#xff0c;进一步了解项目的整体结构&#xff0c;熟悉项目的结构&#xff0c;能够知道每个组件所处在哪个位置&#xff0c;发挥什么作用。 本次所介绍的是微信小程序项目&#xff08;甑选商场&#xff09;&#xff1a; 其首页…

论文阅读 BERT GPT - transformer在NLP领域的延伸

文章目录 不会写的很详细&#xff0c;只是为了帮助我理解在CV领域transformer的拓展1 摘要1.1 BERT - 核心1.2 GPT - 核心 2 模型架构2.1 概览 3 区别3.1 finetune和prompt 3.2 transformer及训练总结 不会写的很详细&#xff0c;只是为了帮助我理解在CV领域transformer的拓展 …