简介:一套基于PHP技术的中医诊所后台管理系统,面向医疗信息化开发者和中小型诊所,提供患者档案、预约记录、药品库存等核心功能,满足快速部署与二次开发的需要。压缩包内含两千个文件,主要包含服务端脚本、网页结构、交互逻辑、样式定义、数据交换等文件,另有数据库脚本和说明文档,整体约十二点四五兆字节,目录结构清晰易检索。系统融合了经典分层架构、登录认证与权限控制、接口化设计以及数据安全防护等关键技术,并兼顾缓存与日志等实践细节,可帮助读者理解商业级后台项目的组织方式。目前已有九百二十八人学习,适合作为服务端脚本语言工程实践与医疗信息化系统学习的参考,可直接复用后台框架与数据表设计。
1. 拿到这个带数据库的 PHP 包,先别急着说它“老”
“PHP开源中医诊所后台管理【带数据库】.zip”这个东西,第一眼很容易被归进“又老又过时的私活代码”那一类,但我实际用下来的体感正好相反:它把中医诊所最绕不开的“挂号 → 病历 → 处方 → 划价 → 药房 → 复诊”这条数据链路完整落了一遍,里面几十张表的关系,就是诊所业务那个“黑匣子”被拆开的样子。对使用者来说,它能解决手工台账对不上账、复诊患者档案翻不出来的痛点;对 PHP 开发者和诊所 IT 人员来说,它是一份能改能跑的参考实现,不用从零开始建业务模型。它适合两类人:一类是想低成本验证“给诊所上个后台到底值不值”的经营者,另一类是准备接诊所外包、但还没梳理过中医业务流程的开发者。花一个晚上把环境跑起来,比看十篇需求分析文档都管用。
2. 先看清货架再动手:这套系统的边界与技术底座
2.1 用 PHP 做诊所后台,是妥协还是最优解
先回答一个绕不开的问题:为什么这类“带数据库”的诊所后台大多是 PHP 写的?常见做法是跑在 LAMP 或 LNMP 环境上,即 Linux + Apache/Nginx + MySQL + PHP。相比 Java、.NET 那类企业级 HIS(医院信息系统),PHP 方案的部署门槛低到“上传压缩包、建库、改配置”三步就能跑起来,虚拟主机甚至不用自己装环境,控制面板里点两下就完成。诊所规模通常就是几个窗口、几十个并发,这个负载对 PHP 来说非常轻松,杀鸡用牛刀不是好选择。
但从业务边界看,PHP 诊所后台并不是万能的。医保接口对接、电子发票、区域卫生平台上报这类强合规需求,往往要在这套代码上做不少二次开发,甚至要重写部分模块。我一般会先跟需求方确认清楚:是要一套“内部管账管药管病历”的工具,还是要跟外部系统打通的平台。前者用这种 PHP 包很划算,后者建议一开始就规划好接口层。这套系统的价值,恰恰在于它把中医诊所内部的信息化骨架给齐了,省去的是从零建模的周期。
2.2 模块地图:挂号收费、处方、药房、报表先做到哪一步
打开这类系统的后台,菜单通常涵盖六大块,对应诊所日常的完整链路。
| 模块 | 核心页面 | 主要数据表 | 业务上的价值 |
|---|---|---|---|
| 患者管理 | 患者建档、检索、详情 | 患者表、病历表 | 复诊时能快速调出既往病史 |
| 挂号收费 | 挂号台、收费单、退费 | 挂号表、收费表 | 每天对得上账 |
| 处方管理 | 开方、审方、划价 | 处方表、处方明细表 | 记录每一味药和剂量 |
| 药房库存 | 入库、出库、盘点 | 药材表、库存表、流水表 | 知道库存还能撑几天 |
| 统计报表 | 日报表、医师工作量、收入结构 | 汇总时跨多表联查 | 给经营决策提供依据 |
| 系统设置 | 用户、角色、权限、诊所信息 | 用户表、角色表 | 控制谁能动钱、谁能动药 |
先别急着端到端全跑通,我的建议是先走一遍“患者建档 → 挂号收费 → 开处方 → 划价 → 发药 → 退费”这六步,因为它覆盖了诊所最核心的资金流和药品流。报表和权限可以后面再看,前面的链路如果对得上账,这套系统的基础就算立住了。
2.3 打开 zip 先看这 5 个地方:快速判断技术栈与代码质量
解压之后不要直接扔进 Web 目录,先花十分钟看结构,能避免后面踩大坑。我会按下面顺序检查:
- 根目录入口文件。看是不是有 index.php 加 application 或 app 目录,这是大多数 PHP MVC 框架的特征。
- 配置文件位置。找 config 目录下的 database.php 或根目录的 config.php,打开看数据库连接用的是 PDO 还是 mysqli,这决定了 PHP 版本的兼容范围。
- 数据库文件在哪、多大。通常在 database、sql 或根目录下,名字类似 clinic.sql。文件越大,初始化数据越完整,同时也意味着导入时间越长。
- 有没有 composer.json 和 vendor 目录。有说明是现代框架的依赖管理,扩展机制清晰;没有则是原生 PHP 居多,改起来直接但也更容易遇到兼容性问题。
- 有没有 install 向导目录。有 install 的话部署更傻瓜化,没有就完全靠手工建库和改配置。
查看目录结构不用装额外工具,命令行一条命令就够了:
unzip -l "PHP开源中医诊所后台管理【带数据库】.zip" | head -60 find . -maxdepth 2 -type d | sort | head -40第一行命令先看压缩包内文件的路径规律,第二行是解压后看目录层级。如果看到 application、public、runtime、addons 这类目录名,基本可以判断是 PHP 框架项目;如果全是 admin、include、config 这类平铺目录,更接近原生 PHP 的老项目。目录越规整,后面改代码的定位成本越低,这一步的判断会直接影响你要不要继续投入时间。
3. 部署不是双击解压就行:从 zip 到登录后台的完整路径
3.1 部署前的环境核对:PHP 版本、MySQL 与扩展
这套系统最常见的运行环境是 PHP 7.0~7.4 配 MySQL 5.6~5.7,也有老项目跑在 PHP 5.6 上。生产服务器上不要直接上最新的 PHP 8.x,很多老代码会在语法层面直接翻车。建议先做一个环境清单核对:
| 组件 | 推荐范围 | 检查命令 |
|---|---|---|
| PHP | 5.6~7.4 | php -v |
| MySQL | 5.6~5.7 或兼容的 MariaDB | mysql --version |
| pdo_mysql 扩展 | 必须存在 | php -m | grep pdo_mysql |
| mbstring 扩展 | 必须存在,否则中文处理会乱 | php -m | grep mbstring |
| fileinfo 扩展 | 文件上传相关功能需要 | php -m | grep fileinfo |
| GD 库 | 验证码、图片裁剪需要 | php -m | grep gd |
检查缺扩展时,在 Debian/Ubuntu 系服务器上通常执行:
sudo apt install -y php7.4-pdo php7.4-mysql php7.4-mbstring php7.4-gd装完用 php -m 再看一遍确认生效。接下来创建数据库和专用账号,不给 root,减少后续风险:
mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS clinic DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -uroot -p -e "CREATE USER 'clinic_user'@'localhost' IDENTIFIED BY '你的强密码';" mysql -uroot -p -e "GRANT ALL PRIVILEGES ON clinic.* TO 'clinic_user'@'localhost'; FLUSH PRIVILEGES;"这里的逻辑是:先建库并明确字符集,再建专用账号并只授权给这一个库。用 utf8mb4 而不是 utf8 的原因,是为了后面存患者姓名里的生僻字和少量现代汉字扩展字符时不至于变问号。这一条是血泪经验,很多系统部署完才发现患者姓名带生僻字就乱码,回头改库的字符集非常痛苦,最好在第一步就定死。
3.2 导入数据库的两种姿势:phpMyAdmin 和 mysql 命令行
数据库文件一般是 .sql 或 .sql.gz。如果是 .sql.gz 先解压再导入,不要试图让 mysql 命令直接理解 gzip:
gzip -dk clinic.sql.gz mysql -uclinic_user -p clinic < clinic.sql导入时看到刷屏的 Query OK 是正常的,说明结构在逐步写入。如果终端啥都没输出就返回了,反而要去确认是不是真的导入了,可以用后续的 show tables 验证。在虚拟主机上没有命令行的用户,用 phpMyAdmin 导入,要点如下:
- 导入前先在 phpMyAdmin 里选中医诊所对应的库,再点“导入”。
- 文件编码不用改,但要在导入页面确认 SQL 文件的格式不是“latin1”。
- 文件超过 20MB 时经常超时,这时候优先用命令行,或把 SQL 拆成两段导入。
导入完成后做一次最性价比的验证:
mysql -uclinic_user -p clinic -e "SHOW TABLES;"这条命令如果返回几十张表,比如 patient、doctor、herb、stock 之类的名字,就说明库已经活了。如果只有零星十几张,或者完全为空,优先怀疑选错了库,再检查是不是 SQL 本身有预处理头、被 phpMyAdmin 跳过。
3.3 改数据库连接配置与目录权限
找到配置文件,多数项目集中在 config 目录,比较常见的形态是 database.php。改的内容明确,但几个参数容易写错:
<?php // application/config/database.php return [ 'hostname' => '127.0.0.1', // 用 127.0.0.1 避免走 socket 'database' => 'clinic', // 库名 'username' => 'clinic_user', // 专用账号 'password' => '你的强密码', // 密码 'hostport' => '3306', 'charset' => 'utf8mb4', 'dbdriver' => 'mysqli', ];这里的核心是 hostname。localhost 和 127.0.0.1 在部分服务器上会走不同的连接方式,前者可能走 unix socket 而后者强制走 TCP,如果 PHP 和 MySQL 不在同一台机器,必须写 TCP 地址。dbdriver 要看 PHP 装了 pdo_mysql 还是 mysqli,两者写错会在运行时报“找不到驱动”。改完配置后,目录权限是第二个新手重灾区:
chmod -R 775 runtime uploads logs chown -R www-data:www-data runtime uploads logsruntime 目录很多框架用来放缓存和日志,uploads 是放患者证件、处方图片的。这俩目录不可写,轻则登录后页面缓慢,重则提交表单直接 500,而且错误日志不会出现在浏览器上,只会默默躺在服务器日志里,排查起来很消耗耐心。
3.4 默认账号登录与首次跑通后的功能核对
环境就绪后,访问 http://你的域名/ 或 http://你的域名/admin,大多数这类系统的默认账号密码是 admin/admin123 或 admin/123456,以压缩包里附带的说明为准。登录进后台第一件事不是截图发给老板,而是把默认密码立刻改掉,这种后台不带 IP 限制,暴露在公网上就等于把患者病历数据送给别人看。
改完密码后,我会按“一个假患者走到底”的方式测试:建档一个“测试脾胃虚寒”的患者,挂一个号,开一张包含 10 味药的处方,到收费台划价后去药房发药,接着再做一次退费和重收。就这一套流程,能把患者表、挂号表、处方表、明细表、库存表、收费表的联动关系全部激活。任何一个环节报错,直接去 runtime/logs 下看今天的日志文件名,框架的 log 一般会精确到具体文件和行号,比在浏览器里瞎猜高效得多。
4. 数据库不是附赠品:核心表结构与业务关系串讲
4.1 患者主表:挂号、复诊与病历索引怎么串
患者是诊所业务的中心,典型表名是 patient、member 或 archive。一张合格的患者主表至少要包含姓名、性别、出生日期、手机号、身份证号、过敏史、既往病史、建档时间这些字段。中医诊所特别需要关注“过敏史”,因为开草药方时如果患者对某味药过敏,医生开方时能直接看到,比事后问诊安全得多。
患者、挂号、病历之间常见的关联关系是“一对多”:一个患者有多条挂号记录,一条挂号记录对应一份当次病历。用 SQL 做患者档案页统计时经常会写成这样:
SELECT p.id, p.name, p.sex, DATE_FORMAT(p.birthday, '%Y-%m-%d') AS birthday, COUNT(a.id) AS visit_times, MAX(a.create_time) AS last_visit FROM clinic_patient p LEFT JOIN clinic_appointment a ON a.patient_id = p.id AND a.status < 9 WHERE p.name LIKE '张%' GROUP BY p.id ORDER BY last_visit DESC;这条查询的逻辑是:以患者表为主表,左连接挂号表,统计每位张姓患者的就诊次数和最近一次就诊时间。关键在 WHERE 条件 a.status < 9,9 在很多系统里代表“已取消”的状态码,如果不排除,患者明明取消了两次挂号的记录也会被算成就诊次数,档案页的数据就失真了。DATE_FORMAT 是为了把日期格式化成‘年-月-日’,避免时间部分干扰阅读。
4.2 处方与收费:金额、状态与退费的三方核对
这套系统里最容易对不上账的地方,是处方明细的合计与收费单的总额不一致。常见的设计是:开处方时写入处方表和明细表,划价后生成一条收费记录,收费记录里有一个 pay_status 字段标识未付、已付、已退。退费时如果只改收费记录的状态而不动处方表,第二天统计就会莫名其妙的少一笔钱。
我接手这类系统的第一周,最常用的排查 SQL 是核对付费表与明细表的金额差:
SELECT o.id, o.patient_name, o.total_amount, o.pay_status, SUM(d.amount) AS detail_sum FROM clinic_order o LEFT JOIN clinic_order_detail d ON d.order_id = o.id GROUP BY o.id HAVING ABS(o.total_amount - detail_sum) > 0.01;HAVING 子句里的 0.01 是浮点计算误差的容忍区间。如果 equal 判断写成 =,很多金额因为浮点精度差异会被误报,所以金额对比一律建议用 ABS 差值。pay_status 字段在系统里通常约定 0 未付、1 已付、2 已退。退费单出现时,除了把状态改成 2,还要确认有没有对应的红字冲销记录或退费操作日志,不然流水审计时解释不清“为什么收入少了但订单还在”。
4.3 药房库存:扣库存的两种模式与期末盘点
药房模块的表一般有药材字典表、库存表、出入库流水表。中医诊所和西药房最大的差别在药材形态:有饮片、颗粒、代煎几种,有的按“剂”算,有的按“克”算,库存表里最好存最小单位数量,否则盘点时单位换算会让人算到崩溃。
扣库存有两种常见模式。一种是划价即扣,出方就预占库存,优点是流程简单,缺点是有患者不交费导致库存虚减;另一种是发药时再扣,以药房发药动作为准,准确但需要药房人员认真扫码或勾选。我倾向于后者,理由是这个系统面对的诊所规模不大,发药时肉眼核对患者姓名和处方编号的成本很低,而虚减库存会导致医生误判“这味药没了”,影响临床开方。
发药扣库存的数据库操作,正确姿势是放在事务里,防止扣一半断电产生脏数据:
BEGIN; UPDATE clinic_herb_stock SET stock_num = stock_num - 10 WHERE herb_id = 1024 AND stock_num >= 10; INSERT INTO clinic_stock_log (herb_id, change_num, operator_id, remark) VALUES (1024, -10, 3, '处方单 P20240515001 发药'); COMMIT;这段 SQL 要重点看 UPDATE 语句的 WHERE 部分,它不只是定位药材,还承担了“库存不足时拒绝扣减”的职责。如果 stock_num 只有 8,这个 UPDATE 影响行数为 0,下面的流水就不该写,事务回滚后前台应该提示库存不够。这类防超卖的写法在诊所系统里非常实用,等于把业务规则下沉到数据库层。
5. 部署与使用排查:五个常见坑的记录与修复
5.1 坑一:PHP 版本兼容性翻车,症状是首页直接 500
我在一台预装 PHP 8.1 的服务器上部署这类老包时,打开首页直接白屏,Apache 日志里报语法错误,指向某个文件里用了老式写法。原因很明确:这套代码当初是 PHP 5.x/7.x 时代写的,PHP 8 里移除了一些老函数,也把某些弱类型行为改严格了,于是原本能跑的逻辑全部炸掉。
解决方式分两层。第一层是省事的:直接装 PHP 7.4,这是兼容性最好的版本,业界很多老系统长期趴在上面。第二层是被迫留在 PHP 8 时,逐个修改代码,把 mysql_ 开头的旧函数替换成 mysqli 或 PDO 写法,把数组短语法和 list() 的差异处理掉。我的建议是别硬修,诊所后台系统图的是稳定,生产环境跑 PHP 7.4 不是什么丢人的事,反而是成熟运维的选择。
5.2 坑二:MySQL 8 密码插件导致连接失败,配置看着没问题
数据库账号权限都正常,配置文件也改了,但后台登录时提示 Access denied,反复核对密码也没错。这个问题在 MySQL 8 上很典型:默认认证插件是 caching_sha2_password,老代码里的 mysqli 连接方式处理不了这个插件,导致密码验证始终失败。
解决思路不是改密码,而是给这套系统一个兼容旧认证方式的账号:
CREATE USER 'clinic_user'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的强密码'; GRANT ALL PRIVILEGES ON clinic.* TO 'clinic_user'@'localhost'; FLUSH PRIVILEGES;mysql_native_password 是老 PHP 连接 MySQL 最稳的认证方式。如果你已经在用 MySQL 8,并且不想降级,这是最顺手的处理路径。代码不用动,只要把之前建的用户删掉重建即可。
5.3 坑三:导入 SQL 后中文全部变成问号,数据直接没法看
数据库文件导入很顺利,表也建出来了,打开后台发现患者姓名、药材名全是问号或乱码。常见原因是 SQL 文件里表结构声明了 utf8,但导入时客户端的连接字符集没有指定,数据被当成 latin1 写进去了。
命令行导入时务必带上字符集参数再重导一遍:
mysql -uclinic_user -p --default-character-set=utf8mb4 clinic < clinic.sqlphpMyAdmin 里则要在导入前把界面语言和编码都切到 utf8。已经导错数据的话,不要试图原地 UPDATE 改字符,直接删库重导更干净。这种事我在模拟项目里翻过一次车,修复乱码花掉的时间比重导一次还多,后悔药唯一有效的是“第一步就带参数”。
5.4 坑四:时区不一致,挂号记录和收费时间错了 8 小时
系统跑起来了,但患者挂号单上的时间和实际时间差了好几个小时。这类问题通常不在代码 bug,而是 PHP 和 MySQL 各用一套时区,PHP 默认 UTC,MySQL 用服务器本地时间,两边一拼就出现偏移。
两种修复手法配合使用。PHP 侧在配置里打开时区设置:
date_default_timezone_set('Asia/Shanghai');MySQL 侧直接改会话时区:
SET time_zone = '+08:00';部署完数据库后,顺手写上这行 SQL 能省掉后面一堆报表时间错乱的麻烦。判断到底是哪一侧出问题时,在后台发一条测试挂号记录,看数据库里 create_time 存的值,再对照页面显示的时间,偏移量就是时区差。这种问题越是“感觉很玄学”,越要第一时间对着数据库原始值排查,不要猜。
5.5 坑五:默认弱口令暴露在公网,后台沦为攻击目标
最常见的生产事故不是系统崩溃,而是部署完不改密码。admin/admin123 挂在公网上,等于把患者病历、处方、库存全敞开。某个测试环境甚至被改了后台密码,整个诊所的挂号和收费直接被锁死。
解决的做法是三个动作一起做。一是后台用户管理里强制改成强密码;二是后台入口加访问限制,只允许诊所内网的几个 IP 访问:
location /admin { allow 192.168.1.0/24; deny all; }三是把默认的 /admin 路径换掉,不叫 admin,减少被扫描器命中的概率。这三步属于部署完顺手就该做的操作,不做的话后续的风险完全不可控。
6. 教你一套验证与改造顺序:让 zip 变成自己的产品
拿到这套系统,我建议按这个顺序推进,少走弯路。第一步是 15 步验收路径:建档 → 挂号 → 开方 → 划价 → 收费 → 发药 → 退费 → 再挂复诊,核对患者档案就诊次数是否加一、库存数量是否正确减少、报表收入与收费记录总和是否一致。第二步是改诊所信息,把 Logo、诊所名称、地址、电话换成真实信息。第三步是调整打印模板,重点看处方单和收费票据的尺寸是否匹配。第四步再往统计报表里加自己的字段。
改造打印模板时,最容易踩坑的是比例:代码里写的是 A4 纸横版还是竖版,与小票热敏纸完全不同。如果直接改 CSS 无效果,优先检查是否有独立的 print 样式文件,不要动公共样式以免连累后台布局。报表需要在原基础上新增“医生工作量排行”这类统计时,直接对收费表和处方表按医生 id 分组聚合即可,系统自带报表大多只覆盖基础维度,这正好是自己的发挥空间。
改完表和逻辑后,建议立刻导出一份“干净库”备份,作为后悔药:
mysqldump -uclinic_user -p clinic > clinic_clean_backup.sql这个备份要放在 Web 目录之外,否则被下载又是新的灾难。我做这类系统有一个习惯:改任何表结构前先导出原结构,跑通一个功能就提交一次代码备份,绝不一边改一边不留退路。这套 PHP 诊所后台真正教给我的不是 PHP 语法,而是诊所业务里“每一笔钱都必须能溯源”这件事,患者、处方、库存、收费永远是闭环的。希望你也能在它的基础上少走弯路,希望帮到你。
本文还有配套的精品资源,点击获取