ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PHP+MySQL在线招生考试报名系统:从报名到准考证打印全链路实现

PHP+MySQL在线招生考试报名系统:从报名到准考证打印全链路实现 简介这是一套面向学校招生考试场景的在线报名系统 PHP 源码适合教育机构搭建报名、缴费、准考证查询与打印一体化平台也适合 PHP 开发者学习完整业务系统的实现思路。压缩包共 1086 个文件约 5.54MB以 257 个 php 业务脚本、82 个 js 交互脚本、72 个 html 与 55 个 htm 页面为主另含 36 个 css 样式、330 个 gif 与 133 个 png 界面素材以及 sql、config、db 等数据库与配置文件和少量说明文档结构完整、便于二次开发。系统分前后台前台支持准考证查询与在线打印报名表后台涵盖报名管理、用户管理、基本设置、考点设置、考试时间、准考证设置、数据统计与分类管理并内置支付宝即时到账接口需自行配置支持一键导出报名表部分分类为系统保留不可删除。目前已有 178 人学习下载可帮助读者快速掌握报名缴费、准考证生成与后台数据统计的完整实现路径。1. 在线招生考试报名系统从考生填表到准考证打印一条链路怎么跑通每年招生季最让技术负责人头疼的不是流量峰值而是报名数据从考生点击「提交」那一刻起到最终打印出带照片的准考证中间要穿过表单校验、资格审核、考区分配、座位编排、照片合成、PDF 生成这六七道关卡。任何一环掉链子考生看到的就是「提交失败」或「准考证打不开」。这套在线招生考试报名系统核心要解决的就是把这条链路做成可配置、可追溯、可批量处理的闭环而不是每年换一批人手工整理 Excel。它适合两类人一是手里已经有一套 PHP 源码、想把它跑起来并改造成自己业务逻辑的开发者二是需要快速搭建报名、准考证查询、在线打印报名表三件套的院校或考试机构技术团队。下面按「先跑通最小链路再逐个拆解参数和坑」的顺序讲所有操作都基于常见的 PHP MySQL 技术栈不依赖任何特定框架。2. 把 PHP 源码跑起来环境、建表与最小配置2.1 环境选型为什么 PHP 7.4 MySQL 5.7 仍是这类系统的稳妥组合在线招生考试报名系统这类项目通常不是新写的而是从早期版本迭代而来。我见过太多人一上来就换 PHP 8.2 MySQL 8.0结果卡在mysql_connect废弃、utf8mb4排序规则冲突、strict mode下group by报错这些老问题上。稳妥做法是先用 PHP 7.4 配 MySQL 5.7 把链路跑通再逐步升级。PHP 7.4 对mysqli和PDO的支持足够且大量老源码里的each()、create_function()虽然已移除但报名系统里很少用到这些。MySQL 5.7 的utf8mb4_unicode_ci能存 4 字节 emoji避免考生姓名里带生僻字或表情符号时插入失败。具体环境清单组件推荐版本说明PHP7.4.x兼容老源码fileinfo、gd、mbstring必开MySQL5.7.x支持utf8mb4避免生僻字乱码Web 服务器Nginx 1.20配fastcgi_pass到 PHP-FPM扩展gd、fileinfo、mbstring、openssl照片处理和 PDF 生成依赖安装命令以 Ubuntu 20.04 为例sudo apt update sudo apt install php7.4-fpm php7.4-mysql php7.4-gd php7.4-mbstring php7.4-fileinfo php7.4-openssl nginx mysql-server-5.7 sudo systemctl enable php7.4-fpm nginx mysql逻辑说明php7.4-gd用于准考证照片的缩放和合成php7.4-fileinfo用于校验上传照片的真实 MIME 类型php7.4-mbstring处理中文截取。参数上php.ini里把upload_max_filesize调到5Mpost_max_size调到8M因为报名表常带照片和扫描件。2.2 建表报名表、考生表、准考证表三张核心表怎么设计很多 PHP 源码包里 SQL 文件是散的我一般会先统一成三张主表。报名表存考生填写的原始信息考生表存审核后的正式数据准考证表存编排结果。这样查询准考证时不用反复扫报名表。CREATE TABLE bm_registration ( id int(11) NOT NULL AUTO_INCREMENT, bm_no varchar(20) NOT NULL COMMENT 报名号, name varchar(50) NOT NULL, id_card varchar(18) NOT NULL, photo_path varchar(255) DEFAULT NULL, status tinyint(1) DEFAULT 0 COMMENT 0待审 1通过 2驳回, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_bm_no (bm_no), KEY idx_id_card (id_card) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE bm_student ( id int(11) NOT NULL AUTO_INCREMENT, bm_no varchar(20) NOT NULL, exam_room varchar(20) DEFAULT NULL, seat_no varchar(10) DEFAULT NULL, ticket_no varchar(30) DEFAULT NULL COMMENT 准考证号, PRIMARY KEY (id), UNIQUE KEY uk_ticket_no (ticket_no), KEY idx_bm_no (bm_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE bm_ticket ( id int(11) NOT NULL AUTO_INCREMENT, ticket_no varchar(30) NOT NULL, pdf_path varchar(255) DEFAULT NULL, printed tinyint(1) DEFAULT 0, print_time datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_ticket_no (ticket_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;逻辑说明bm_registration的bm_no用唯一索引防止重复提交bm_student的ticket_no唯一保证准考证号不重复bm_ticket记录打印状态方便统计已打印人数。参数上id_card建普通索引因为按身份证查询是高频操作。2.3 最小配置数据库连接与路由入口怎么改拿到源码后先找config.php或database.php把数据库账号密码改成自己的。常见写法?php // config.php return [ db_host 127.0.0.1, db_port 3306, db_name bm_system, db_user bm_user, db_pass YourStrongPass123, db_charset utf8mb4, upload_dir /data/www/bm_system/uploads/, ticket_template /data/www/bm_system/templates/ticket.html, ];逻辑说明upload_dir必须可写且不要放在 Web 根目录下避免照片被直接 URL 访问。ticket_template是准考证 HTML 模板路径后面生成 PDF 时用。参数上db_charset必须和建表时一致否则中文乱码。提示改完配置后先访问install.php或手动导入 SQL再删掉安装文件避免被重复初始化。3. 准考证查询与在线打印报名表从 SQL 到 PDF 的完整链路3.1 准考证查询接口按报名号或身份证号查怎么防注入和防遍历准考证查询是考生用得最多的功能通常提供两个入口输入报名号或输入身份证号。PHP 源码里常见写法是直接拼 SQL这是血泪教训的重灾区。正确做法是用 PDO 预处理?php // query_ticket.php $pdo new PDO(mysql:host127.0.0.1;dbnamebm_system;charsetutf8mb4, bm_user, YourStrongPass123); $pdo-setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $keyword trim($_GET[keyword] ?? ); if ($keyword ) { exit(json_encode([code 400, msg 请输入报名号或身份证号])); } $sql SELECT r.bm_no, r.name, s.exam_room, s.seat_no, s.ticket_no FROM bm_registration r JOIN bm_student s ON r.bm_no s.bm_no WHERE r.bm_no :kw OR r.id_card :kw LIMIT 1; $stmt $pdo-prepare($sql); $stmt-execute([:kw $keyword]); $row $stmt-fetch(PDO::FETCH_ASSOC); if (!$row) { exit(json_encode([code 404, msg 未查询到准考证信息])); } echo json_encode([code 200, data $row], JSON_UNESCAPED_UNICODE);逻辑说明LIMIT 1防止身份证号重复时返回多条OR条件用同一个占位符PDO 会正确处理。参数上keyword要做trim避免用户复制时带空格。防遍历方面不要用自增id作为查询参数否则容易被批量爬取。如果必须用id加一个token校验。3.2 在线打印报名表HTML 模板转 PDF 的两种方案与参数对比在线打印报名表本质是把考生数据填充到 HTML 模板再转成 PDF 让浏览器下载或直接打印。常见两种方案wkhtmltopdf和TCPDF。我一般优先用wkhtmltopdf因为它对 CSS 支持好模板改起来快。方案优点缺点适用场景wkhtmltopdfCSS 支持好分页容易需要装二进制服务器权限报名表、准考证TCPDF纯 PHP无需外部程序CSS 支持弱中文需字体简单表格wkhtmltopdf调用示例wkhtmltopdf --enable-local-file-access \ --page-size A4 \ --margin-top 10mm --margin-bottom 10mm \ --encoding utf-8 \ /data/www/bm_system/templates/baoming.html \ /data/www/bm_system/output/baoming_20250001.pdf逻辑说明--enable-local-file-access允许模板里引用本地图片如照片--page-size A4固定纸张--encoding utf-8防中文乱码。参数上--margin-*根据模板留白调整一般 10mm 够用。生成后PHP 里用exec()调用注意转义路径。?php $bmNo preg_replace(/[^0-9A-Za-z]/, , $_GET[bm_no]); $htmlPath /data/www/bm_system/templates/baoming_{$bmNo}.html; $pdfPath /data/www/bm_system/output/baoming_{$bmNo}.pdf; $cmd wkhtmltopdf --enable-local-file-access --page-size A4 --encoding utf-8 . escapeshellarg($htmlPath) . . escapeshellarg($pdfPath); exec($cmd, $output, $ret); if ($ret ! 0) { exit(PDF生成失败请检查模板路径); } header(Content-Type: application/pdf); header(Content-Disposition: attachment; filenamebaoming.pdf); readfile($pdfPath);逻辑说明escapeshellarg防止命令注入preg_replace过滤报名号只留字母数字。参数上$ret非 0 说明wkhtmltopdf执行失败常见原因是模板里图片路径不对或字体缺失。3.3 准考证照片合成GD 库缩放与裁剪的 3 个必调参数准考证上的照片有固定尺寸通常是 1 寸或 2 寸。考生上传的照片尺寸不一必须用 GD 库处理。核心三个参数目标宽、目标高、裁剪模式。?php function makeTicketPhoto($srcPath, $dstPath, $targetW 295, $targetH 413) { $info getimagesize($srcPath); if (!$info) return false; $src imagecreatefromstring(file_get_contents($srcPath)); $srcW imagesx($src); $srcH imagesy($src); // 按目标比例裁剪避免拉伸变形 $ratio max($targetW / $srcW, $targetH / $srcH); $newW (int)($srcW * $ratio); $newH (int)($srcH * $ratio); $tmp imagecreatetruecolor($newW, $newH); imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newW, $newH, $srcW, $srcH); $cropX (int)(($newW - $targetW) / 2); $cropY (int)(($newH - $targetH) / 2); $dst imagecreatetruecolor($targetW, $targetH); imagecopy($dst, $tmp, 0, 0, $cropX, $cropY, $targetW, $targetH); imagejpeg($dst, $dstPath, 90); imagedestroy($src); imagedestroy($tmp); imagedestroy($dst); return true; }逻辑说明$ratio取宽高比例的最大值保证缩放后能覆盖目标区域cropX、cropY居中裁剪。参数上295x413是 1 寸照片 300dpi 的像素值90是 JPEG 质量低于 80 会模糊。注意imagecreatefromstring比imagecreatefromjpeg更通用能处理 PNG 和 GIF。4. 避坑与排查报名系统上线前必须过的 5 道坎4.1 照片上传成功但准考证不显示路径与权限的连环坑现象考生上传照片提示成功但生成准考证时照片位置空白。原因通常有三层一是upload_dir没有写权限PHP 以www-data运行目录属主是root二是模板里图片路径用了相对路径wkhtmltopdf解析不到三是照片文件名含中文或空格wkhtmltopdf加载失败。解决chown -R www-data:www-data uploads/模板里用绝对路径文件名统一用md5重命名。4.2 准考证号重复并发下自增与随机数的取舍现象批量生成准考证时偶尔出现两个考生准考证号一样。原因是用rand()或time()拼接高并发下碰撞。解决用数据库唯一索引兜底生成时INSERT ... ON DUPLICATE KEY UPDATE重试或者直接用bm_student表的id加前缀保证唯一。4.3 在线打印报名表 PDF 中文乱码字体嵌入与编码声明现象PDF 里中文变成方框或问号。原因wkhtmltopdf默认字体不含中文或 HTML 里没声明meta charsetutf-8。解决HTML 模板头部加meta charsetutf-8CSS 里指定font-family: SimSun, Microsoft YaHei, sans-serif;服务器安装fonts-wqy-zenhei包。4.4 查询接口被批量刷限流与验证码的轻量做法现象准考证查询接口被脚本高频调用数据库压力大。原因没有频率限制。解决用 Redis 或文件缓存记录 IP 查询次数超过 10 次/分钟弹验证码。轻量做法在query_ticket.php开头加session_start()记录$_SESSION[last_query]间隔小于 2 秒直接拒绝。4.5 报名表提交后数据丢失事务与字段长度检查现象考生提交后提示成功但数据库里没有记录。原因id_card字段长度不够或者name字段用了varchar(10)存不下少数民族姓名。解决建表时name至少varchar(50)id_card用varchar(18)提交时用事务包裹INSERT失败回滚并返回具体错误。5. 进阶技巧用模板缓存把准考证生成速度压到 200ms 以内当报名人数上万时每次查询都重新渲染 HTML 再转 PDF服务器扛不住。我一般会做两层缓存第一层把考生数据填充后的 HTML 缓存到runtime/ticket_html/目录文件名用ticket_no命名第二层PDF 生成后直接存output/下次请求先检查文件是否存在且未过期。这样重复查询同一考生时直接readfile输出耗时从 1.5 秒降到 200 毫秒以内。?php $ticketNo preg_replace(/[^0-9A-Za-z]/, , $_GET[ticket_no]); $pdfPath /data/www/bm_system/output/ticket_{$ticketNo}.pdf; $htmlPath /data/www/bm_system/runtime/ticket_html/{$ticketNo}.html; if (!file_exists($pdfPath) || filemtime($pdfPath) time() - 86400) { // 重新生成 HTML $data getTicketData($ticketNo); // 从数据库取 $html renderTemplate($data); file_put_contents($htmlPath, $html); // 调用 wkhtmltopdf $cmd wkhtmltopdf --enable-local-file-access --page-size A4 --encoding utf-8 . escapeshellarg($htmlPath) . . escapeshellarg($pdfPath); exec($cmd, $out, $ret); if ($ret ! 0) exit(生成失败); } header(Content-Type: application/pdf); header(Content-Disposition: inline; filenameticket.pdf); readfile($pdfPath);逻辑说明filemtime判断缓存是否超过 24 小时超过则重新生成inline让浏览器直接预览方便考生在线打印。参数上86400是一天秒数可根据考试周期调整。注意runtime目录也要可写且不要被 Web 直接访问。验证缓存是否生效连续请求同一ticket_no两次第二次看响应头X-Cache: HIT可以在代码里加或者直接看output目录文件时间戳是否变化。我习惯在生成 PDF 后记录日志包括耗时和文件大小方便排查慢查询。最后说个习惯每次改完模板先手动跑一遍wkhtmltopdf命令确认 PDF 正常再走 PHP 调用。因为 PHP 的exec环境变量和终端不一样字体路径经常是玄学问题。希望帮到你。本文还有配套的精品资源点击获取
返回列表