
简介这是一套面向中小企业、站长及个人开发者的PHPlivechat在线客服系统源码主打无限坐席与手机APP客服端适合需要自建客服渠道、替代第三方付费工具的技术人员部署使用。资源包共451个文件约133.83MB以100个php核心程序、122个js脚本、110个png界面素材为主另含html模板、css样式、mp3提示音、字体图标及sql数据库文件并附带一个apk安卓客服端结构完整、开箱即用。目前已有1104人学习下载。系统支持宝塔Linux与Windows环境Apache2.4.41搭配PHP5.6以上即可运行上传解压后按引导填写数据库与后台账号即可完成安装无需手动改配置或导入数据库。手机端通过扫码绑定WEB后台QR码即可在APP内接收与回复访客消息资源内附有详细使用教程与截图方便快速上手与二次开发。1. 从一套 2021 年 12 月修复版 PHPlivechat 说起无限坐席 手机 APP 客服端到底解决了什么如果你在 2021 年底前后折腾过 PHP 在线客服系统大概率踩过同一个坑网上流传的 PHPlivechat 源码包装完能跑但坐席数一加就报错手机端要么打不开要么消息延迟到怀疑人生。所谓「2021 年 12 月修复版」核心修的就是这几件事——坐席授权校验被绕过、手机 APP 客服端接口签名对不上、以及 PHP 7.4 之后一批废弃函数导致的 500。它面向的是中小团队自建客服台的真实需求不想按坐席数付费想在自己服务器上跑还想让客服拿手机就能回消息。这套东西不是 SaaS是一份可以自己部署、自己改的 PHP 源码配合一个打包好的移动端。下面我按「先讲清它是什么 → 怎么装起来 → 参数怎么调 → 坑在哪」的顺序把能复现的路径写出来新手照着走熟手可以直接跳到参数和排错那几章。2. PHPlivechat 的运行骨架坐席、访客、手机端三条链路怎么串起来先把架构讲清楚不然装到一半你不知道自己在配什么。PHPlivechat 本质是一个「长轮询 MySQL 会话表」的 PHP 应用没有用 WebSocket所以它对虚拟主机和低配 VPS 都友好代价是消息有秒级延迟。理解这一点后面所有参数和排错都会顺很多。2.1 三条链路访客端、坐席后台、手机 APP 客服端访客端是一段嵌进网页的 JS负责在右下角弹出对话框、发消息、收消息。坐席后台是 PHP 页面客服在浏览器里登录后看到会话列表。手机 APP 客服端不是原生重写常见做法是一个 WebView 壳套着移动版坐席页面通过同一套接口拿数据。三条链路共用一张chat_session会话表和一张chat_message消息表谁在线、谁接了哪个访客全靠表里的状态字段。关键状态字段有三个session_status0 等待、1 进行中、2 已结束、operator_id当前接待坐席、last_active最后活跃时间。手机端和网页端看到的是同一份数据所以你在网页端把会话转接给同事手机端刷新就能看到。这也是为什么「无限坐席」能成立——坐席只是operator表里的记录不涉及任何按人头计费的授权服务加一条记录就是一个新坐席。2.2 无限坐席的实现逻辑与数据库表结构所谓「无限坐席」不是破解了谁的授权而是这套源码本身就没有坐席数量校验。你打开operator表字段大致是id、username、password、nickname、group_id、online_status。加坐席就是插一行登录就是查这一行。真正需要留意的是group_id分组它决定了会话怎么轮询分配。下面这段 SQL 是我一般用来快速加一个坐席并归到默认组的写法字段名以你实际表结构为准先DESC operator;看一眼再改-- 先确认表结构避免字段名对不上 DESC operator; -- 插入一个新坐席密码建议用 password_hash 生成后再填 INSERT INTO operator (username, password, nickname, group_id, online_status) VALUES (kefu02, $2y$10$替换成你的哈希, 客服小张, 1, 0); -- 查一下当前所有坐席确认插入成功 SELECT id, username, nickname, group_id, online_status FROM operator;逻辑说明online_status初始给 0坐席登录后由后台脚本改成 1手机端和网页端都读这个字段判断谁可接待。参数上group_id要和operator_group表里的记录对应否则会话分配会找不到组表现为访客一直排队没人接。密码不要明文存用 PHP 的password_hash()生成登录时用password_verify()校验这是修复版里比较重要的一处安全改动。2.3 手机 APP 客服端是怎么复用同一套接口的手机端能收到消息靠的是定时请求一个拉取接口常见路径是/api/pull_message.php带上坐席 token 和上次拿到的消息 id服务端返回增量消息。这个接口和网页端用的是同一个所以你在网页端能收到的消息手机端只要 token 有效就能收到。这里有个容易忽略的点token 的生成和校验。修复版一般把 token 存在operator_token表里字段是operator_id、token、expire_time。手机端登录成功后拿到 token之后每次请求都带。如果 token 过期时间设得太短客服手机放一会儿就要重新登录体验很差设得太长又有安全风险。我一般设 7 天配合「记住登录」用。// 生成坐席 token 的常见写法供手机端登录后返回 function makeToken($operatorId) { $token bin2hex(random_bytes(16)); // 32 位随机串 $expire time() 7 * 24 * 3600; // 7 天有效期 // 先清掉旧 token保证一个坐席一个有效 token $pdo-prepare(DELETE FROM operator_token WHERE operator_id ?) -execute([$operatorId]); $pdo-prepare(INSERT INTO operator_token (operator_id, token, expire_time) VALUES (?, ?, ?)) -execute([$operatorId, $token, $expire]); return $token; }逻辑说明random_bytes(16)生成 32 位十六进制串比md5(time())这种可预测的写法安全得多。参数上expire_time用 Unix 时间戳存校验时和time()比较。手机端每次请求先查这张表token 对得上且没过期才放行否则返回 401 让客户端重新登录。这套机制不复杂但它是手机端能不能稳定收消息的关键配错了就是「网页能收、手机收不到」的经典现象。3. 从零把 PHPlivechat 跑起来环境、安装、手机端打包的完整步骤这一章是给要动手的人看的。我按「先跑通网页端再打通手机端」的顺序写每一步都给出可执行的命令或配置你照着做基本能复现。环境上PHP 7.4 是最稳的PHP 8 以上会因为一批废弃函数报错修复版虽然处理了一部分但仍有残留。3.1 环境准备PHP 7.4 MySQL 5.7 Nginx 的最小配置先装环境。以 Ubuntu 20.04 为例PHP 7.4 和 MySQL 5.7 是这套源码验证过的组合。命令如下# 安装 PHP 7.4 及常用扩展 sudo apt update sudo apt install -y php7.4 php7.4-fpm php7.4-mysql php7.4-mbstring php7.4-curl php7.4-gd php7.4-json # 安装 MySQL 5.7若源里是 8.0注意改认证插件 sudo apt install -y mysql-server # 安装 Nginx sudo apt install -y nginx # 确认 PHP 版本 php -v逻辑说明php7.4-mysql是连数据库必须的mbstring处理中文消息curl给手机端接口用gd一般用于验证码或头像。参数上MySQL 8.0 默认用caching_sha2_password认证老 PHP 客户端可能连不上遇到就改成mysql_native_password。Nginx 的站点配置里root指向源码的public目录location ~ \.php$那段交给php7.4-fpm这是标准写法不展开。装完先别急着导数据确认php -m里能看到mysqli、mbstring、curl这几个模块缺哪个补哪个不然后面报错你会以为是源码问题。3.2 导入数据库与修改配置文件四个必须改的参数源码包里一般有个install.sql导入它建表。然后改配置文件通常是config/database.php或include/config.php不同版本路径不一样用find . -name *.php | xargs grep -l db_host找一下。# 建库并导入 mysql -u root -p -e CREATE DATABASE phplivechat DEFAULT CHARSET utf8mb4; mysql -u root -p phplivechat install.sql # 找配置文件 grep -rn db_host\|db_user\|db_pass --include*.php .四个必须改的参数数据库主机、库名、用户名、密码。改完访问首页能出登录页就说明网页端通了。这里有个血泪经验utf8mb4一定要在建库时就定好后期改字符集要动一堆表中文和 emoji 都会出问题。// config/database.php 常见结构 return [ db_host 127.0.0.1, db_name phplivechat, db_user phplivechat_user, // 别用 root db_pass 你的强密码, db_charset utf8mb4, ];逻辑说明单独建一个只有本库权限的数据库用户比直接用 root 安全。参数上db_host用127.0.0.1比localhost在某些环境下更稳避免走 socket 出问题。db_charset必须是utf8mb4否则手机端发 emoji 会存成问号。3.3 手机 APP 客服端的打包与接口地址配置手机端常见是一个 HBuilder 或 Cordova 打包的 WebView 壳源码里有个mobile目录里面是移动版页面。你要做的是把接口地址改成你自己的域名然后打包成 APK。// mobile/js/config.js 里一般有接口基地址 window.API_BASE https://你的域名/api/; // 拉取消息的轮询间隔单位毫秒 window.POLL_INTERVAL 3000;逻辑说明API_BASE必须带https因为手机系统对明文 HTTP 请求限制越来越严用 HTTP 会出现「网页能登、APP 登不上」。POLL_INTERVAL是轮询间隔3000 毫秒是延迟和服务器压力的折中设成 1000 服务器扛不住设成 10000 客服会觉得消息半天不来。打包时注意 Android 的targetSdkVersion别太高太高会触发后台限制消息推送更不稳。打包完装到手机上用坐席账号登录发一条测试消息看网页端能不能收到。收不到就回到 3.2 检查接口地址和 token 表这是最常见的翻车点。4. 参数调优与接口联调让消息不丢、坐席不掉线装起来只是第一步真正决定好不好用的是参数。这一章讲几个我实际调过的参数以及网页端和手机端联调时怎么定位问题。很多人装完觉得「能用但不好用」问题基本都出在这里。4.1 轮询间隔、超时时间、会话回收三个核心参数轮询间隔前面提过网页端和手机端可以分开设。网页端可以激进一点2000 毫秒手机端考虑省电和流量3000 到 5000 毫秒。超时时间指的是坐席多久没动作算离线常见设在operator表的last_active判断里。// 判断坐席是否在线的常见逻辑 $onlineThreshold 60; // 60 秒内有心跳算在线 $isOnline (time() - $operator[last_active]) $onlineThreshold;逻辑说明$onlineThreshold设太小客服去倒杯水就显示离线访客被转走设太大客服关了页面还显示在线访客白等。60 秒是我试下来比较平衡的值。会话回收指的是访客多久没说话自动结束会话一般设 300 秒配合一个定时脚本扫chat_session表。# 定时回收超时会话加到 crontab 每分钟跑一次 * * * * * php /var/www/phplivechat/cron/close_idle_session.php参数上回收脚本里判断last_active超过 300 秒且状态为进行中的改成已结束。不加这个脚本会话表会越积越大坐席列表越来越卡。4.2 用 curl 手动调接口定位「手机收不到消息」手机端收不到消息别急着改代码先用 curl 手动打接口看返回什么。这是最快的定位方式。# 手动拉取消息替换 token 和 last_id curl -X POST https://你的域名/api/pull_message.php \ -d token你的坐席token \ -d last_id0 \ -H Content-Type: application/x-www-form-urlencoded逻辑说明last_id0表示拉全部消息如果返回空数组说明服务端认为没有新消息问题在写入端如果返回 401说明 token 无效或过期如果返回 500去看 PHP 错误日志。参数上last_id传上次拿到的最大消息 id服务端只返回比它大的这是增量拉取的标准做法。定位清楚是写入问题还是读取问题再动手改能省很多时间。4.3 坐席分配策略轮询、分组、指定接待怎么配会话分配决定了访客进来找谁。常见三种轮询按顺序分给在线坐席、分组按group_id分、指定访客从某页面进来固定找某人。轮询最简单也最容易出问题——如果在线状态判断不准会把会话分给已经离线的坐席。// 轮询分配取在线坐席里 last_active 最早的那个 $sql SELECT id FROM operator WHERE online_status 1 AND group_id ? ORDER BY last_active ASC LIMIT 1;逻辑说明按last_active升序取保证分配均匀。参数上group_id来自访客来源或默认组。如果你们客服分售前售后就用分组策略访客从售前页面进来进售前组。指定接待适合大客户一般靠 URL 参数带坐席 id 实现。三种策略没有优劣看业务但轮询一定要配合准确的心跳否则就是「分给离线坐席、访客干等」的经典投诉。5. 避坑与排查这套源码最容易翻车的五个地方这一章是我踩过的坑按「现象 → 原因 → 解决」写。你装的时候对照着看能少走很多弯路。5.1 现象装完首页 500日志报 deprecated 函数原因PHP 8 移除了一批函数比如each()、create_function()修复版处理了大部分但仍有残留。解决降到 PHP 7.4或者用grep -rn each( --include*.php .找出来逐个替换成foreach。别硬扛 PHP 8改起来没完。5.2 现象手机端登录提示「网络错误」网页端正常原因九成是接口地址用了 HTTP或者域名没配 SSL 证书手机系统拦截了明文请求。解决给域名配 HTTPSAPI_BASE改成https://。还有一种可能是手机端打包时没加网络权限检查AndroidManifest.xml里的INTERNET权限。5.3 现象消息发出去对方半天才收到甚至丢消息原因轮询间隔太长或者last_id没正确递增导致重复拉或漏拉。解决把POLL_INTERVAL调到 3000 以内检查客户端有没有把每次返回的最大 id 存下来下次带上。丢消息多半是last_id逻辑写错用 4.2 的 curl 手动验证。5.4 现象坐席显示在线但访客排队没人接原因online_status和last_active不同步坐席关了页面但状态还是 1。解决加心跳接口坐席页面每隔 30 秒调一次更新last_active分配时同时判断online_status 1和last_active在阈值内。只判断前者就会出这个问题。5.5 现象中文乱码emoji 变问号原因数据库或表字符集不是utf8mb4或者连接时没设字符集。解决建库建表都用utf8mb4连接后执行SET NAMES utf8mb4。已经建好的表用ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4改但要注意字段长度utf8mb4下varchar(255)占的字节更多索引可能超长。6. 进阶把手机端消息延迟压到 1 秒内的一个取巧做法轮询这套东西延迟天然受限于间隔。想把手机端压到 1 秒内又不改成长连接我一般用一个取巧做法把轮询间隔设成 1000 毫秒但服务端加一层「有消息才返回、没消息挂起 800 毫秒」的短挂起逻辑。这样客户端请求频率没变但消息一到就能立刻返回体感延迟接近实时。// pull_message.php 里的短挂起逻辑 $deadline microtime(true) 0.8; // 最多挂起 800 毫秒 while (microtime(true) $deadline) { $rows 查询新消息($lastId); if (!empty($rows)) { echo json_encode($rows); exit; } usleep(200000); // 每 200 毫秒查一次 } echo json_encode([]); // 挂起结束仍无消息返回空逻辑说明客户端还是 1 秒一次请求但服务端在没消息时不会立刻返回空而是挂起最多 800 毫秒等消息。消息一来立刻返回客户端下一轮马上又能拿到。参数上挂起时间要小于客户端超时时间800 毫秒配 1 秒轮询比较稳挂太久会占满 PHP-FPM 进程。这个做法对服务器进程数有要求pm.max_children要调大不然并发一高就 502。验证方法很简单手机端发消息掐表看网页端多久收到正常应该在 1 秒出头。如果还是两三秒检查是不是挂起逻辑没生效或者 Nginx 的fastcgi_read_timeout太短把请求掐了。我自己的习惯是任何轮询系统上线前先用 curl 手动打一百次接口看平均响应和有没有偶发 500比在界面上点半天靠谱。这套 PHPlivechat 修复版不是什么新东西但胜在能自己掌控、坐席不花钱适合预算有限又要自建客服台的小团队。装的时候耐心点参数调对了它比很多付费的还稳。希望帮到你。本文还有配套的精品资源点击获取