首页 / 资讯中心 / 文章详情

PHP中医诊所后台管理系统源码部署与二次开发实战指南

PHP中医诊所后台管理系统源码部署与二次开发实战指南 ★ FEATURED ARTICLE
简介这份资源是面向PHP开发者与医疗信息化学习者的开源中医诊所后台管理系统附带预配置数据库可直接部署运行帮助解决诊所患者信息、预约记录与药品库存等业务的管理需求。压缩包共约2000个文件整体12.45MB以1290个js、258个less、185个html、163个php及123个json为主涵盖前端交互、样式构建、页面模板与后端逻辑另含sql数据库脚本、md说明文档及图片字体等静态资源。项目涉及PHP编程、MySQL数据库、MVC架构、身份验证与RBAC权限控制、RESTful API设计、数据安全与性能优化等核心知识点适合具备一定Web开发基础、希望研究医疗信息化系统架构或进行二次开发的读者。目前已有928人学习下载可借此理解后台管理系统的目录组织与模块划分掌握从数据库设计到前后端协作的完整实现思路并在此基础上按不同中医诊所的业务需求进行定制扩展。1. 拿到一套 PHP 中医诊所后台先别急着改代码上周有个做医疗信息化的朋友甩给我一个压缩包名字叫「PHP开源中医诊所后台管理【带数据库】.zip」问我能不能直接拿去给一家小型中医馆用。我解压看了一眼目录结构又翻了翻 SQL 文件发现这套东西比想象中完整——不是那种只有几个静态页面的空壳而是带了患者档案、处方管理、药材库存、就诊记录这些核心模块的完整后台。如果你手头正好有中医馆、理疗店、小型诊所这类场景需要一套能跑起来、能改、能自己维护的管理系统这套源码值得花时间拆一拆。它用的是 PHP MySQL 的经典组合部署门槛低虚拟主机就能跑对预算有限但又想要数据自己掌控的团队来说是个务实的选择。下面我按实际拆包和部署的顺序把关键环节和踩过的坑一条条讲清楚。2. 环境搭建与数据库导入从解压到登录后台2.1 运行环境选型与版本匹配这套源码的技术栈是 PHP MySQL没有用框架属于原生写法。原生写法有个好处不依赖 Composer不用配伪静态扔到支持 PHP 的空间里就能跑。但坏处也明显——对 PHP 版本有隐性要求。我实测下来PHP 7.4 是最稳的区间PHP 8.0 以上会在几个文件里报「未定义数组键」的警告虽然不影响主流程但日志会刷得很难看。MySQL 建议 5.7 或 8.0字符集用 utf8mb4因为中医处方里偶尔会出现生僻字utf8 存进去会变问号。如果你用宝塔面板新建站点后把 PHP 版本切到 7.4再装个 phpMyAdmin 备用。如果用手动编译的环境确认mysqli和gd扩展都开了——前者连数据库后者用来生成一些统计图表。常见做法是先本地用 XAMPP 或 phpStudy 跑通再往服务器搬这样出问题好排查。2.2 数据库导入的完整操作解压后你会看到一个sql目录里面通常是一个.sql文件。导入之前先建库命令如下# 登录 MySQL建一个专用库字符集必须指定 mysql -u root -p CREATE DATABASE tcm_clinic DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE tcm_clinic; # 退出后用命令行导入注意路径换成你实际解压的位置 exit; mysql -u root -p tcm_clinic /path/to/sql/tcm_clinic.sql导入完成后用SHOW TABLES;检查一下正常应该有十几张表包括患者信息表、处方表、药材表、库存流水表、用户权限表等。如果导入中途报错大概率是 SQL 文件里写了CREATE DATABASE语句但库名和你建的不一致用文本编辑器搜一下CREATE DATABASE和USE这两行改成你实际的库名即可。2.3 配置文件修改与首次登录数据库通了之后找到配置文件。原生 PHP 项目一般把连接信息放在config.php、conn.php或includes/db.php这类文件里。打开后你会看到类似下面的内容?php // 数据库连接配置按你实际环境改这四个值 $db_host 127.0.0.1; // 数据库地址本地就是 localhost $db_user root; // 数据库用户名 $db_pass your_password; // 数据库密码 $db_name tcm_clinic; // 刚才建的库名 $conn mysqli_connect($db_host, $db_user, $db_pass, $db_name); if (!$conn) { die(连接失败: . mysqli_connect_error()); } mysqli_set_charset($conn, utf8mb4); // 必须设否则中文乱码 ?改完保存浏览器访问站点根目录应该会跳到登录页。默认账号密码通常在 SQL 文件的admin表或user表里用 phpMyAdmin 打开看一眼密码字段可能是 MD5 加密的。如果不知道明文直接在那个表里新增一条记录密码用md5(123456)生成登录后再改。提示首次登录后第一件事是改默认密码第二件事是检查admin目录是否可以直接被外网访问。原生项目经常把后台入口暴露在根目录下建议改个不常见的路径名。3. 核心模块拆解患者档案、处方与库存怎么联动3.1 患者档案表结构与字段含义这套系统最核心的表是患者信息表一般叫patient或members。我拆的这套里字段设计得比较接地气除了姓名、性别、年龄、电话这些基础项还有「体质类型」「过敏史」「既往病史」三个文本字段。体质类型对应中医的九种体质分类过敏史用来在开处方时弹窗提醒。字段类型上电话用varchar(20)而不是int这是对的——座机号带区号、手机号带 86 的情况都能存。有一个细节值得注意患者编号用的是自增id但界面上显示的是另一个「档案号」字段格式类似TCM20240001。这个号是在插入记录时用 PHP 拼出来的逻辑大概是「TCM 年份 四位自增」。如果你要迁移数据这个字段得手动处理不然新老数据会撞号。3.2 处方录入与药材关联逻辑处方模块是这套系统的重头戏。一张处方对应一条prescription主记录然后明细存在prescription_detail里每条明细关联一个药材 ID 和用量。开处方时前端用 JavaScript 动态添加行每选一个药材自动带出库存里的当前单价然后算出小计。这个联动逻辑写在js/prescription.js里核心是监听下拉框的change事件用 AJAX 去get_medicine.php查库存和价格。// 监听药材选择动态更新单价和库存提示 document.querySelectorAll(.medicine-select).forEach(function(select) { select.addEventListener(change, function() { var medicineId this.value; var row this.closest(tr); // 发请求查这个药材的当前库存和单价 fetch(get_medicine.php?id medicineId) .then(res res.json()) .then(data { row.querySelector(.price-input).value data.price; row.querySelector(.stock-hint).textContent 当前库存 data.stock; // 如果库存低于 10标红提醒 if (data.stock 10) { row.querySelector(.stock-hint).style.color red; } }); }); });这段代码的逻辑很直白选药材 → 查库存 → 回填价格 → 库存不足标红。参数上get_medicine.php接收id返回 JSON 格式的price和stock。如果你要改成从 Redis 缓存读改这个接口就行前端不用动。3.3 库存扣减与流水记录处方保存时系统会做两件事一是把处方主表和明细表写进去二是扣减药材库存并写一条库存流水。扣减逻辑在save_prescription.php里用的是「先查后扣」的方式// 开启事务保证处方和库存同时成功或同时失败 mysqli_begin_transaction($conn); try { // 插入处方主表 $sql INSERT INTO prescription (patient_id, doctor_id, create_time) VALUES (?, ?, NOW()); // ... 执行插入拿到 prescription_id foreach ($medicines as $med) { // 插入明细 $sql2 INSERT INTO prescription_detail (prescription_id, medicine_id, quantity, price) VALUES (?, ?, ?, ?); // ... 执行 // 扣库存加判断防止扣成负数 $sql3 UPDATE medicine SET stock stock - ? WHERE id ? AND stock ?; mysqli_query($conn, $sql3); if (mysqli_affected_rows($conn) 0) { throw new Exception(库存不足 . $med[name]); } // 写库存流水 $sql4 INSERT INTO stock_log (medicine_id, change_type, quantity, create_time) VALUES (?, out, ?, NOW()); // ... 执行 } mysqli_commit($conn); } catch (Exception $e) { mysqli_rollback($conn); echo json_encode([code 1, msg $e-getMessage()]); }这里有个关键点UPDATE语句带了AND stock ?条件如果库存不够affected_rows返回 0直接抛异常回滚。这是防止超卖的标准做法比先SELECT再UPDATE安全得多。参数上change_type字段区分「入库」和「出库」方便后面做库存报表。注意如果这套系统要多人同时开处方务必确认medicine表的存储引擎是 InnoDBMyISAM 不支持事务扣库存会出乱子。4. 权限与安全原生 PHP 项目最容易翻车的地方4.1 登录态校验与越权访问原生 PHP 项目最常见的漏洞是「只在前端藏菜单后端接口不校验」。我翻了一下这套源码的admin目录发现大部分文件开头都有include check_login.php;这个文件里用session判断是否登录。但有几个 AJAX 接口漏了比如delete_patient.php和export_excel.php直接访问就能删数据或导出全量患者信息。修复方式很简单在这几个文件顶部补上?php session_start(); // 没登录就直接拒绝返回 JSON 而不是跳转方便前端处理 if (!isset($_SESSION[admin_id])) { http_response_code(403); echo json_encode([code 403, msg 未登录]); exit; }另外check_login.php里最好加上session_regenerate_id(true)在登录成功后调用一次防止会话固定攻击。这个函数会换一个新的 session id旧 id 作废。4.2 SQL 注入与 XSS 过滤现状这套源码在查询患者列表时用了$_GET[keyword]直接拼 SQL典型的注入点。比如patient_list.php里可能有这么一句$keyword $_GET[keyword]; $sql SELECT * FROM patient WHERE name LIKE %$keyword%;如果传入 OR 11就能拖出全表。修复方式是改成预处理$keyword % . $_GET[keyword] . %; $stmt mysqli_prepare($conn, SELECT * FROM patient WHERE name LIKE ?); mysqli_stmt_bind_param($stmt, s, $keyword); mysqli_stmt_execute($stmt); $result mysqli_stmt_get_result($stmt);XSS 方面输出患者姓名、备注这些字段时源码里有的地方用了htmlspecialchars有的地方直接echo。建议全局搜一下echo $和?把输出到 HTML 的地方都包一层htmlspecialchars($str, ENT_QUOTES, UTF-8)。4.3 文件上传与目录权限系统里有个「导入药材数据」的功能允许上传 Excel 文件。上传目录默认是uploads/权限设成了 777。这在生产环境是隐患——如果上传目录能被解析成 PHP传个伪装成 Excel 的 PHP 文件就能拿 shell。正确的做法是上传目录权限设 755属主设为 web 用户在目录里放一个.htaccessApache或配置 Nginx 的location禁止执行 PHP。# 上传目录权限收紧 chmod 755 uploads/ chown www-data:www-data uploads/ # Apache 环境下在 uploads 目录放 .htaccess echo php_flag engine off uploads/.htaccessNginx 的话在站点配置里加location ^~ /uploads/ { location ~ \.php$ { deny all; } }5. 避坑与排查部署和二次开发中的五个血泪教训5.1 中文乱码从数据库到页面的全链路排查现象患者姓名显示成「??」处方里的药材名变成乱码。原因三个环节都可能出问题——数据库建库时没指定utf8mb4、连接时没执行SET NAMES、页面没声明meta charsetutf-8。解决按顺序查。先SHOW CREATE DATABASE tcm_clinic;看字符集再在config.php里确认有mysqli_set_charset($conn, utf8mb4);最后检查 header 文件里的 meta 标签。三处都对了乱码必消。5.2 登录后跳回登录页session 路径与域名问题现象输入账号密码后页面闪一下又回到登录页或者提示「请先登录」。原因session.save_path目录没写权限或者站点用了 www 域名但 session cookie 绑定了不带 www 的域。解决在 PHP 文件里临时加var_dump(session_save_path());看路径确保该目录 web 用户可写。域名问题的话在php.ini里设session.cookie_domain .yourdomain.com或者在登录脚本里用session_set_cookie_params显式指定。5.3 库存扣成负数并发下的经典翻车现象两个医生同时开同一味药库存只剩 5结果两个处方都保存成功库存变成 -3。原因扣库存的 SQL 没加AND stock quantity条件或者表引擎是 MyISAM 不支持事务。解决按 3.3 节的写法UPDATE带条件判断affected_rows为 0 就抛异常回滚。同时ALTER TABLE medicine ENGINEInnoDB;把引擎换掉。5.4 导出 Excel 打开是乱码BOM 头没加现象导出的患者列表用 Excel 打开中文全是乱码但用记事本打开正常。原因Excel 对 UTF-8 的 CSV 文件默认按 GBK 解析需要在文件开头加 BOM 头。解决在输出 CSV 内容之前先echo \xEF\xBB\xBF;再输出表头和内容。这个 BOM 头是三个字节Excel 看到就知道是 UTF-8。5.5 修改代码后不生效OPcache 缓存没清现象改了config.php里的数据库密码刷新页面还是报连接失败用旧密码。原因PHP 开了 OPcache缓存了旧文件。解决重启 PHP-FPM或者在宝塔面板里点「重载配置」。临时调试可以在php.ini里把opcache.enable设为 0改完再开回来。6. 二次开发进阶把处方打印和统计报表接上这套系统默认的处方打印是浏览器直接window.print()打出来排版一般。我一般会改成用wkhtmltopdf生成 PDF这样格式固定也方便存档。做法是把处方详情页的 HTML 单独抽出来去掉导航和侧边栏然后用命令行工具转 PDF。# 把处方页面转成 PDF注意指定页面尺寸和边距 wkhtmltopdf --page-size A5 --margin-top 10mm --margin-bottom 10mm \ http://localhost/prescription_print.php?id123 \ /path/to/save/prescription_123.pdf参数上--page-size A5是因为中医处方通常用 A5 纸比 A4 省一半。--margin留出装订边。PHP 里用exec()调用这个命令注意对id做整型过滤防止命令注入。统计报表方面系统自带的「就诊量统计」只按天汇总。如果你想看「某个药材过去三个月的用量趋势」需要自己写 SQL。我常用的查询是-- 按月统计某味药材的消耗量 SELECT DATE_FORMAT(sl.create_time, %Y-%m) AS month, m.name AS medicine_name, SUM(sl.quantity) AS total_used FROM stock_log sl JOIN medicine m ON sl.medicine_id m.id WHERE sl.change_type out AND m.name 黄芪 AND sl.create_time DATE_SUB(NOW(), INTERVAL 3 MONTH) GROUP BY month, m.name ORDER BY month;这个查询用到了DATE_FORMAT做月份分组DATE_SUB算三个月前的时间点。结果可以直接喂给 ECharts 画折线图。我习惯把这类统计接口单独放在api/stats.php里返回 JSON前端用fetch拿数据渲染。从那以后我每次拿到一套原生 PHP 后台都强制走一遍「建库导数据 → 改配置 → 登后台 → 查注入点 → 测并发扣库存」这五步少一步后面都可能翻车。这套中医诊所后台的底子不错模块全、逻辑直白适合拿来改造成自己需要的版本。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站