简介:一套基于2021年12月修复版的PHP在线客服系统,采用PHPlivechat方案,支持无限坐席,并附带Android手机APP客服端与搭建教程。面向需要快速搭建客服系统的个人站长、中小企业或开发者,可解决网站实时沟通、多坐席协作等需求。资源包共451个文件,压缩后约133.83MB,主体为100个PHP逻辑文件、122个JS交互脚本、110张PNG界面素材,辅以23个HTML页面、13个CSS样式及SQL数据库文件,还包含APK安装包与音频、视频教程,结构完整。已有1102人学习下载。资源亮点是安装流程已优化,无需手工修改源码或导入数据库,按向导即可完成部署;手机APP支持扫码绑定后台,便于移动管理。教程配有截图与文字指引,可帮助快速上手,适合有一定服务器基础的学习者。
1. 为什么还在用PHP写的PHPlivechat:无限坐席与APP客服端到底解决什么问题
先给结论:如果你的业务需要一套能自己控制数据的在线客服系统,PHP写的PHPlivechat依然是性价比最高的一条路,尤其是这个号称“2021年12月修复版”的包——它在老版本的易用性基础上解决了PHP 7.x环境下最常见的报错,还带一套可以直接打包的APP客服端。你可能觉得PHP做客服系统太土,但换个角度想:虚拟主机能跑、宝塔能跑、一台1核2G的服务器也能跑,这对绝大多数中小网站和电商站长来说,恰恰是最现实的方案。
这套系统解决的是三个具体问题:一是访客在网页上发起咨询时,客服能实时收到并回复;二是客服不用一直守在电脑前,APP端能带着会话跑;三是“无限坐席”意味着你不需要按人头付费,也不用在用户表里去数客服账号。往下我会先把部署流程拆开讲清楚,再解释无限坐席的实现逻辑,然后带你把APP端跑起来,最后把常见问题列成清单。适合谁看?准备给公司或客户搭客服系统的人、在用第三方客服软件但嫌贵的站长、以及想拿PHP源码做二次开发的从业者。
2. 从零部署PHPlivechat:LNMP环境、权限配置与数据库初始化
2.1 环境选型:PHP 7.4还是PHP 5.6,扩展与伪静态怎么定
部署PHPlivechat之前,先把环境想清楚。官方老版本对PHP 5.6支持得最好,但2021年这个修复版的主要目的就是把老代码搬到PHP 7.x上跑,所以我建议你直接用PHP 7.4,兼顾兼容性和安全性。PHP 8.0以上暂时别碰,老代码里的一些写法在PHP 8下会直接抛致命错误,例如each()函数被移除、count()对非数组的报错级别提高,修复版未必覆盖到这些边界。
在宝塔面板里创建站点时,PHP版本选7.4,运行目录指向web文件夹。如果你的源码包没有明确标注目录结构,常见做法是将压缩包解压后把web目录作为站点根目录,因为PHPlivechat的入口文件和静态资源都在这里。装完面板后还需要给PHP安装这几个扩展:pdo_mysql、openssl、mbstring、curl、fileinfo,这些在宝塔的PHP扩展管理里都是开关式安装。fileinfo容易被忽略,但它负责上传图片时读取文件类型,少了它客服端传头像会出错。
伪静态配置也要说清楚:Nginx环境下加入下面这段规则,目的是让URL去掉index.php,让客服系统内部的跳转和资源加载走正常路径。
location / { if (!-e $request_filename){ rewrite ^/(.*)$ /index.php?r=$1 last; } }这段配置的含义是:当请求的路径不是一个真实存在的文件或目录时,把请求重写到index.php并带上原始路径作为r参数。PHPlivechat基于Yii框架,它的路由入口就是index.php,所以这条规则必须配上,否则访客打开聊天窗口时会看到404。
还有一个容易翻车的点:PHP的disable_functions里如果有proc_open、exec、shell_exec,一些跑定时任务的版本会静默失败。排查办法是打开探针或者写一个<?php echo phpinfo(); ?>页面去查。我习惯把proc_open从禁用列表里放出来,因为某些版本的修复版会用它在后台生成桌面通知进程。
2.2 目录权限、数据库导入与管理端登录:三步把系统跑起来
环境就绪后,开始正式安装。先说明,这个包的安装过程本质上是“解压 → 导库 → 改配置 → 登录”,没有复杂的编译步骤,但每一步都有讲究。
第一步,把压缩包里的全部文件上传到站点根目录后,执行权限调整命令。Yii框架有runtime目录和assets目录,必须可写,否则页面能打开但缓存写不进去,报错信息千奇百怪。
chown -R www:www /www/wwwroot/你的站点目录 chmod -R 755 /www/wwwroot/你的站点目录 chmod -R 777 /www/wwwroot/你的站点目录/web/assets chmod -R 777 /www/wwwroot/你的站点目录/runtimewww:www是宝塔的默认运行用户,PHP-FPM以这个用户身份执行,如果文件属主是root,PHP进程就没有写权限。assets目录专门放Yii发布的前端资源副本,每访问一次可能生成新的文件,权限不足直接白屏。runtime目录存应用日志和缓存,权限不足时系统会尝试写日志失败,表现为页面打开极慢。
第二步,创建数据库并导入SQL文件。大多数源码包会带一个database.sql或db.sql,用命令行导入比图形界面更不容易出字符集问题。
mysql -uroot -p你的密码 -e "CREATE DATABASE IF NOT EXISTS livechat DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;" mysql -uroot -p你的密码 livechat < database.sqlutf8_general_ci是PHPlivechat老代码最安全的字符集选择,utf8mb4虽然能存emoji,但老程序建表的字段长度可能以utf8字节数计算,换编码后索引会超出长度限制导致导入报错。数据库名随意,但后面配置文件里要跟着改。
第三步,修改数据库连接配置。配置文件一般在web/protected/config/database.php,内容类似:
<?php return array( 'connectionString' => 'mysql:host=localhost;dbname=livechat', 'username' => '你的数据库用户', 'password' => '你的数据库密码', 'charset' => 'utf8', );改完保存,打开http://你的域名/index.php?r=site/login,默认管理账号通常是admin,初始密码源码包的文档里会写,拿不到文档就试admin或admin123这种常见组合,修复版一般不会把初始密码设得太复杂。登录后第一件事是去「系统设置」里把后台路径和密码改掉。
2.3 验证访客入口:把聊天窗口嵌到任意网页的最小代码
系统装好以后,要在自己的网站上挂一个“在线咨询”按钮。PHPlivechat管理后台会有“代码生成器”,生成一段JavaScript嵌入代码。代码的核心逻辑是通过iframe或动态脚本加载聊天窗口,而不是把整个PHP应用嵌进去。
<script type="text/javascript"> var phpLiveChat = { serverUrl: 'https://你的域名', style: 'float', color: '#007aff', buttonText: '在线咨询' }; </script> <script type="text/javascript" src="https://你的域名/js/visitor.js"></script>serverUrl必须是完整的站点地址,末尾不要带斜杠;style设成float会在右下角浮出一条按钮,设成page则嵌入页面内部;color控制按钮主色。visitor.js这个文件在站点的js目录下,它会在页面加载完成后建立与客服端的连接。
嵌入后怎么确认跑通了?打开访客页面,右下角能看到按钮,点击后弹出聊天窗口,随便发一句话,然后登录客服后台看是否有会话进来。如果聊天窗口出现但发送消息没反应,优先检查浏览器控制台里有没有报403或跨域错误。
3. 坐席机制与无限坐席:授权校验卡在哪、怎么改才不出事
3.1 坐席模型的底层逻辑:操作员表、分组与会话分配
PHPlivechat把客服人员统一叫“操作员”,在数据库里对应user表,每个操作员有一个role字段区分身份。role=0是普通访客,role=1是管理员,role=2是客服坐席。坐在后台的客服,本质上就是拿着role=2的账号登录到后台,然后通过轮询或WebSocket接收访客会话。
会话分配的逻辑分两层:第一层是按部门分组,操作员属于哪个部门,就只能看到哪个部门的会话;第二层是自动分配策略,系统默认是“轮流分配”,即访客发起对话时按操作员的登录顺序依次派单,保证不会某个客服积压太多、另一个闲得慌。这个策略在后台可以改成“空闲优先”,但说实话老版本的实现不算聪明,它只判断操作员是否在线,不判断当前正在处理多少会话,所以并发高的时候还是人工手动转接更靠谱。
这里要注意一个概念:无限坐席不是说系统支持无限个同时登录的客服,而是说它对“创建客服账号”这个动作不做数量限制。原版PHPlivechat的商业授权版本才支持多坐席,免费版限制只能用1个或2个坐席,而这个修复版把坐席判断逻辑跳过了,所以你新增第10个、第20个客服账号都能正常登录工作。
3.2 授权校验的本地化处理:找到license调用点并屏蔽网络请求
实现“无限坐席”的本质,是让程序不再向授权服务器发送验证请求。老版本的程序会在后台登录时定期向官方域名发一个curl请求,校验当前域名是否在白名单内,校验失败就退出登录或冻结坐席功能。修复版做的事情,说穿了就是把这段校验代码注释掉或改成直接返回成功。
常见做法是在源码里搜索license关键词,因为修复版一般不重写整个框架,只是改掉关键文件。实际操作时,我用下面这段命令在源码目录里搜索授权相关调用的位置:
grep -rn "license" /www/wwwroot/你的站点/web/protected/ --include="*.php" | grep -v "vendor/"搜索结果通常集中在protected/components/目录下,比如LicenseComponent.php或web/Config.php里的checkLicense()方法。打开这个文件,你大概率能看到类似下面的代码:
public function checkLicense() { $result = file_get_contents("https://api.example.com/license?domain=" . $_SERVER['HTTP_HOST']); $result = json_decode($result, true); if ($result['code'] !== 200) { return false; } return true; }要让它不再联网校验,又不影响程序其他逻辑,最稳妥的办法是把函数的返回直接改为true:
public function checkLicense() { return true; // 原有网络请求代码保留但不再执行 }改完之后,登录后台、访客发起会话、客服回复,这三条链路里都不会再触发外部网络请求。这个改法有个好处:就算程序在别的文件里也调用了checkLicense(),统一从这个入口返回,覆盖面最广。比直接注释掉所有调用点更靠谱,因为你可能会漏掉隐藏在某个控制器里的第二处调用。
3.3 放开坐席上限后必须重新初始化的三件事
屏蔽授权校验只是第一步,放开坐席上限后还有三件事必须做,少一件都会出现“看着能用但其实有问题”的状态。
第一件,清空缓存目录。Yii框架会把配置和路由信息缓存到runtime/cache下,改动PHP文件后不清理缓存,老代码仍然被执行。执行下面这行命令,然后刷新后台:
rm -rf /www/wwwroot/你的站点/runtime/cache/*第二件,重建数据表索引。修改坐席逻辑后,你需要确认user表里的客服账号能正常被会话分配调度。执行一段SQL,给操作员登录状态加上索引,防止并发登录时锁表:
ALTER TABLE `livechat`.`user` ADD INDEX `idx_role_status` (`role`, `status`);索引的作用是让“查询所有在线的客服人员”这个动作走索引而不是全表扫描。如果之前已经加过这个索引,执行会报重复键名的错误,忽略即可。这一步不是必须的,但加了索引后,十几个客服同时在线的场景下,访客发起会话的响应速度会有明显改善。
第三件,修改密码策略。新增大量坐席账号后,如果admin密码还是默认密码,等于给系统留了后门。到后台「操作员管理」里重置所有测试账号的密码,同时确认config/main.php中的enableCookieValidation和cookieValidationKey已经有值:
'components' => array( 'request' => array( 'enableCookieValidation' => true, 'cookieValidationKey' => '改成一段随机字符串', ), ),cookieValidationKey为空时,会话Cookie存在被伪造的风险,攻击者构造一个非法Cookie可能导致登录绕过。随机字符串可以用openssl rand -hex 16生成,然后粘贴进去。改完这个配置,所有已登录的用户全部要重新登录,这是正常现象。
4. 手机APP客服端:Android端打包、服务器地址配置与消息推送
4.1 APP端文件结构与服务器地址定位
“带手机APP客服端”是这个包的核心卖点。APP端的本质是给客服在手机上处理会话,不是给访客用的。它的实现方式通常是两种:一种是用原生Java/Kotlin写一个WebView壳,把后台的客服工作台页面包进去;另一种是用H5页面配合原生推送插件。老PHPlivechat修复版里带的APP更接近前一种,所以你拿到压缩包后,会看到类似android/或app/这样的独立目录,里面是一个完整的Android工程。
先用文件管理器打开APP目录,确认有没有build.gradle和AndroidManifest.xml——有这两个文件就说明是标准Android工程。接下来最关键的一步是找到服务器地址配置。这个地址通常存在以下位置之一:app/src/main/res/values/strings.xml、app/src/main/java/下的某个常量类,或者assets/config.json。用一条命令在APP源码里搜索域名配置:
grep -rn "http" app/src/main/ --include="*.xml" --include="*.java"搜出来的URL就是APP连接后台的接口地址。把它改成你自己的域名,但要注意一个坑:如果服务器没配HTTPS,APP里面的地址要写http://你的域名,并且Android 9.0以上的系统默认禁止明文HTTP流量,你必须在AndroidManifest.xml里加一行声明才能正常请求。
<application android:usesCleartextTraffic="true" ...>4.2 打包与签名:无Android Studio也能出一版能装的APK
如果你电脑上没有装Android Studio,只用命令行也可以出包。前提是安装了JDK和Android SDK命令行工具。进入APP工程目录后,执行:
gradle assembleDebugassembleDebug会生成一个debug签名APK,路径在app/build/outputs/apk/debug/app-debug.apk。这个APK可以直接安装,但应用图标右下角会有一个“Debug”字样,而且debug签名只能用于测试,正式在手机上长期用,建议做一次release签名。
release签名需要先生成密钥库,用JDK自带的keytool命令:
keytool -genkeypair -v -keystore livechat-release.keystore -alias livechat -keyalg RSA -keysize 2048 -validity 10000生成密钥库后,在app/build.gradle里配置签名信息,再执行gradle assembleRelease。签名这一步很多人忽略,结果装到一半提示“应用未安装”,其实就是debug签名和release签名不一致导致的。如果只是自己手机用,持续用debug包也不会有大问题,但如果要给公司客服统一配发,一定要走release签名流程。
安装好APP后,打开会看到一个登录页,输入后台客服账号密码就能进入工作台。工作台显示会话列表、消息内容、访客信息这几个核心模块,回复消息和电脑端操作逻辑一致。
4.3 掉线与推送失败:APP端特有的三个排查点
APP端最常见的痛点就是“收不到消息”和“用一段时间就掉线”。原因和解决路径如下:
第一个原因是APP的会话保持依赖WebSocket或AJAX轮询,而手机熄屏后系统会冻结后台进程。常见做法是在APP设置里加入“前台服务”或“唤醒锁”机制。如果你没有改代码的打算,至少在测试阶段保持APP在前台运行,不要切到后台太久。
第二个原因是服务器防火墙或安全组没有放行WebSocket端口。PHPlivechat的实时消息如果走的是ws://协议,默认端口是8080或843,而很多云服务器安全组默认只开放80和443。表现为APP能登录、能拉取历史会话,但新消息来了不推。排查命令:
netstat -tlnp | grep 8080如果看到node或php进程在监听8080端口,说明服务没问题,问题出在安全组或防火墙规则,去云控制台把对应端口的入站规则加一下。
第三个原因是服务器时间与手机时间差太多。老程序的会话存在带时间戳的加密串,客户端和服务器时间偏差超过一定阈值会被判定为非法请求。把服务器时间用NTP校准:
ntpdate ntp.aliyun.com校准后重启一下PHP-FPM。这个坑很隐蔽,症状就是“APP能用但消息永远发不出去”,不检查时间根本想不到。
5. PHPlivechat避坑清单:从白屏到会话丢失的5个真实踩坑记录
5.1 安装后页面全白:扩展缺失与错误提示被关掉
现象:打开后台地址,页面一片空白,浏览器控制台看不到任何报错,服务器日志也没记录。
原因:绝大多数情况是PHP扩展缺失,其次是框架错误日志没开,导致致命错误被吞掉。PHPlivechat依赖pdo_mysql和mbstring,少了任何一个,框架初始化就会中断,但又没有输出错误信息的能力。
解决:先看PHP错误日志,日志路径在宝塔的“软件商店 → PHP设置 → 配置文件”里找error_log配置项。如果日志文件里是空的,临时开启错误显示:
ini_set('display_errors', 1); error_reporting(E_ALL);然后把这段写到入口文件web/index.php的最上方,刷新页面就能看到具体报错。看到Call to undefined function mb_strlen()就把mbstring扩展装回来,看到could not find driver就检查pdo_mysql。
5.2 客服登录后看不到访客:会话表时间字段与服务器时区
现象:客服账号正常登录,但访客发消息时后台不出现新会话,刷新页面后会话才推进来。
原因:PHPlivechat的会话列表查询条件是“最近活跃时间大于当前时间减去N秒”,如果服务器时区设置成UTC而数据库存的是北京时间,时间一对比就差了8个小时,新会话会被当成“很久以前的会话”过滤掉。
解决:把PHP和MySQL的时区都设为Asia/Shanghai。PHP侧在php.ini里改:
date.timezone = Asia/ShanghaiMySQL侧执行:
mysql -uroot -p -e "SET GLOBAL time_zone = '+08:00';"改完重启PHP-FPM和MySQL。这个坑最烦人的地方在于它“能用但不好用”——消息能收到但要刷新才出现,极大的误导性。
5.3 网页端聊着聊着变“发送失败”:session锁定与轮询冲突
现象:访客和客服对话正常进行,过几分钟后访客发送的消息一直转圈,最后提示发送失败,刷新页面又恢复正常。
原因:PHPlivechat的网页端采用AJAX轮询方式获取新消息。PHP默认的session机制会在一个请求未结束前锁住session文件,如果两个轮询请求同时到达,后一个请求要等前一个释放锁,等待时间超过浏览器超时就会报失败。老代码在长轮询模式下尤其明显。
解决:把session的存储方式从文件改成Redis,或者缩短PHP的max_execution_time,避免单个请求长时间占用session。最简单见效快的做法是在数据库配置里增加一行设置,关闭session锁:
'session' => array( 'class' => 'CDbHttpSession', 'connectionID' => 'db', 'autoStart' => true, ),这是经典Yii配置,把session存到数据库表里去,不再锁文件。前提是数据库里要有对应的session表,源码包的SQL文件里一般自带。
5.4 数据库UTF-8乱码:建库字符集与连接字符集要一致
现象:管理后台显示的中文全部是问号或乱码,但数据库里直接查询却是正常中文。
原因:建库时用了utf8mb4,但PHP连接数据库时指定的是utf8,两边字符集不一致导致数据读取时编码转换出错。或者反过来,库是utf8,连接指定了gbk。
解决:统一设置连接字符集,在配置文件的charset项里改成和建库字符集一致。如果你确定数据库是utf8mb4,把配置改成:
'charset' => 'utf8mb4',改完清一下浏览器缓存再刷新页面。这里还要注意一点:数据库里现有数据的乱码是不可逆的,如果导入前就已经乱码,只能重新导入一次SQL,所以导入时一定要确认库字符集。
5.5 修复版替换后原数据没了:备份表结构与增量数据分离
现象:把网站上原来的老版本替换成这个修复版后,登录后台发现所有历史会话和客服账号都没了。
原因:安装时覆盖了数据库。很多“修复版”的SQL文件是全新安装脚本,导入它会清空已有的表数据。你以为是在升级,实际上等于重装。
解决:替换文件之前,先把原数据库完整备份,这个习惯应该养成。备份命令:
mysqldump -uroot -p livechat > livechat_backup_$(date +%Y%m%d).sql然后对比新旧SQL文件里的表结构差异,用diff命令看两个文件有没有新增字段或表:
diff old_database.sql new_database.sql如果差异只在个别表,就手动把新字段补到旧库里,而不是直接导入整套新SQL。我一般会把老库备份放一边,先全新安装修复版确认没问题,再把老数据通过SQL脚本迁移过去。别嫌麻烦,数据丢了没有后悔药。
6. 把PHPlivechat收进自己的项目:二次开发前必做的三件事
6.1 把客服按钮做成网站全局插件:嵌入代码与变量注入
如果你的网站是WordPress或ThinkPHP这样的框架,把PHPlivechat的嵌入代码直接复制到主题页脚可行,但每次换主题又得重来一遍。我习惯把嵌入代码封装成一个独立JS文件,放到CDN上,然后在所有页面统一加载。关键在于注入用户信息作为访客标识:
window.phpLiveChatConfig = { serverUrl: 'https://chat.yourdomain.com', visitorName: window.currentUserName || '', visitorEmail: window.currentUserEmail || '', groupId: window.currentUserGroup || 0, customFields: { '用户ID': window.currentUserId || 0 } };这样访客发起咨询时,客服后台能直接看到登录用户的名字和ID,而不是一串随机字符串,处理售后时不用每次都问“您账号是什么”。这个改动只涉及前台JS,不动PHP核心代码,升级修复版时不会被覆盖。
6.2 用数据库钩子把聊天记录同步到业务库
客服系统的价值不止在于聊天,更在于聊天记录能关联到订单和用户。PHPlivechat的消息表是message,里面存了会话ID和消息内容,但没有订单ID的概念。要打通业务数据,常见做法是写一个Shell定时任务,把新产生的聊天记录同步到自己的业务库。
*/5 * * * * mysql -uroot -p密码 livechat -e "INSERT IGNORE INTO business_chat_log (chat_id, visitor_id, content, created_at) SELECT m.chat_id, m.sender_id, m.body, m.created_at FROM message m WHERE m.created_at > DATE_SUB(NOW(), INTERVAL 10 MINUTE);"INSERT IGNORE的语义是如果记录已存在就跳过,避免重复插入。同步表结构比同步数据更重要,建议先建一张和message结构一致的business_chat_log表,再加一个order_id字段,方便后续关联业务订单。定时任务每5分钟跑一次,实时性足够,又不会给数据库太大压力。
6.3 上线前的性能与安全验证
最后一个建议是上线前把这两件事做掉:一是给站点配上HTTPS,APP端和网页端的WebSocket连接建议全部走WSS加密传输,否则访客聊天内容在公网是明文传输的,这在小网站可能无所谓,但涉及用户手机号、订单信息时就是事故。配HTTPS在宝塔里是免费SSL证书一键申请的事,而WSS需要在Nginx配置里加一条WebSocket反向代理规则。
二是压测一下并发会话场景。PHPlivechat的本质是PHP应用,一个PHP-FPM进程同时处理一个请求,并发能力取决于服务器配置。没有压测工具就用简单的ab命令模拟100个并发请求:
ab -n 1000 -c 100 -H "Accept-Encoding: gzip,deflate" https://你的域名/index.php?r=site/login观察Failed requests和Requests per second两项指标。如果失败率超过1%,考虑把PHP-FPM的pm.max_children调大,或者上Redis缓存session。这个验证做完,系统才算真正能接客。
说回我的个人习惯:每次拿到这种修复版源码,第一步永远是看数据库结构和配置文件,而不是直接装上去。搞清楚它改了什么、动过哪里,后面维护才不会两眼一抹黑。这套PHPlivechat方案的维护成本极低,跑起来放那儿半年不管都没关系,但该留的备份一个都不能少。希望帮到你。
本文还有配套的精品资源,点击获取