开源PHP在线客服系统WeLive部署实战:踩坑与二次开发
简介WeLive是一款可独立部署的企业级PHP在线客服系统基于WebSocket实现全双工通信面向需要为网站或App快速接入客服能力的开发者、企业及外包团队。资源包共287个文件涵盖56个PHP核心模块、127个PNG界面素材、20个JS交互脚本和13个CSS样式另有MP3提示音、GIF动图及SQL数据库文件等整体仅1.6MB结构精简便于部署。功能上支持Web/移动端、中英文自动切换、5种配色并可设置AI机器人自动回复、访客上传图片/文件客服坐席无限制适合无人值守和多端接入场景5.9.0版本还新增了访客提示音选择、单/多窗口切换、离线访客管理等近十项优化。已有330人学习浏览开发者可借此研究在线客服系统架构、WebSocket消息推送及二次开发也可直接部署到自有服务器开展业务。 做独立站这些年我一直缺一个能自己掌控的客服入口。访客来了想联系我不是被自动回复绕晕就是只能干等邮件回复。后来我把一套免费开源PHP在线客服系统——WeLive——部署到了自己的服务器上这个问题才算真正解决。WeLive基于PHP开发源码开源可控尤其适合中小站点和外包项目。这篇文章不聊虚的只说我从下载源码到二次开发跑通的全过程以及那些文档里没写的坑。1. 为什么我会选WeLive而不是商业客服系统1.1 商业系统看起来很美账单却很诚实我刚接一个小电商项目时客户点名要在线客服我第一反应是去注册几家商业客服SaaS。界面确实漂亮功能也确实全但一看价格方案就头大坐席费按人头算一个客服一个月几十上百年度账单下来比我服务器租金还贵消息量、会话数、离线留言推送每个都能拆成独立收费项目。到后面想导出聊天记录做分析居然还要开更高档套餐。小站点一天可能就几十个会话为了这个去承担一套完整的商业化定价不划算。更关键的是数据归属。商业系统的聊天记录都在厂商服务器上万一平台政策变动或服务中断历史会话说没就没了。对依赖客服转化的小电商站来说这是悬在头上的风险。我当时的底线很明确要么客户接受用QQ/微信要么就把客服系统掌握在自己手里。WeLive这种开源PHP项目成了最自然的选择。1.2 WeLive解决的核心问题WeLive能做的和一个基础商业客服系统差不太多多客服同时接入、客服分组与分配、访客识别、常用语回复、离线留言、历史会话记录、简单的数据统计。访客在电脑端访问网站时右下角弹出一个客服浮窗点击就能发起对话客服打开工作台看到在线访客列表接过来开始聊整个链路是完整的。最让我看重的是这套系统直接用PHP编写底层是常见的Web技术不需要部署Node或者Java那一套体系。我手上大部分服务器都是经典的LNMP/LAMP环境下载源码、配好数据库、改一下配置文件就能跑起来。后续要改逻辑、加功能也是在自己熟悉的PHP代码里改没有黑盒。对于只想解决网站上有个人能即时跟访客说话这个需求的人来说WeLive的性价比是真的高。1.3 谁适合用WeLive谁不适合以我实际体验下来的判断个人站长、中小型电商、外包项目交付、以及那些对数据敏感、不愿意把客户聊天上云的企业都适合用WeLive。它的定位就不是上百坐席的呼叫中心而是三五个客服接待日常咨询这样一个区间。反过来如果你的业务是每天几千上万的并发会话团队也没人懂PHP那我建议你还是老老实实上商业客服平台或直接采购企业级方案。开源系统意味着部署、维护、二次开发都要自己兜底没有厂商的SLA。想清楚这一条再决定要不要自建。2. 部署跑通环境、下载、伪静态那些事2.1 技术栈和版本选择WeLive基于ThinkPHP 3.2.3框架开发这是一个比较有年头的PHP框架。部署之前我特意确认了运行环境PHP官方推荐5.3以上但为了少踩坑我直接选了5.6版本数据库用MySQL 5.6/5.7都行我是用的5.7。Web服务器选NginxApache也能跑只是伪静态规则写法不同。这里要提醒一句别手痒直接上PHP 7.4或者8.x除非你做好了自己改代码的准备。ThinkPHP 3.2.3是2014年前后的产物很多写法在高版本PHP上会直接报错后面我会展开讲。我用的是宝塔面板来管理环境直接装一个PHP 5.6的站点省去不少编译的麻烦。新手如果不会手动编译用面板是最稳的。下载源码时认准官方GitHub仓库或项目主页解压后把整个目录放到网站的根目录。我当时下载的是最新release包解压出来能看到Application、Public、ThinkPHP这几个主要目录数据库文件通常在根目录或docs目录下后缀是.sql。2.2 安装步骤与数据库初始化整个安装过程不复杂核心就三步建库、导数据、改配置。先通过phpMyAdmin或命令行创建一个数据库比如we_live字符集选择utf8mb4然后把SQL文件导入。命令行导入更直接mysql -uroot -p we_live welive.sql导入成功后打开Application/Common/Conf/config.php把数据库地址、库名、用户名、密码改成自己的?php return array( DB_TYPE mysql, DB_HOST 127.0.0.1, DB_NAME we_live, DB_USER your_db_user, DB_PWD your_db_password, DB_PORT 3306, DB_PREFIX we_, );改完保存浏览器访问站点首页理论上就能看到引导页面或者登录入口。第一次登录后系统会自动初始化管理员账号这个入口的URL一般是http://你的域名/index.php?s/Admin/Login/index如果你只想快点看到效果可以直接访问这个后台地址。默认的管理员账号密码是什么以你下载版本里的说明为准但我强烈建议登录后第一时间改掉趁现在还来得及不要拖。2.3 Nginx伪静态和目录权限如果你不想每次都用index.php?s这种难看的URL就需要配置伪静态。网上好多教程用的规则是从Apache搬过来的在Nginx下不一定生效。我当时踩完坑后把能用的规则存到了nginx配置的location部分location / { if (!-e $request_filename) { rewrite ^/index.php(.*)$ /index.php?s$1 last; rewrite ^(.*)$ /index.php?s$1 last; break; } }配置完reload一下Nginx再用友好的URL访问后台比如http://域名/Admin/Login/indexAPACHE用户则在根目录放.htaccess文件规则一般是IfModule mod_rewrite.c RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?s/$1 [QSA,PT,L] /IfModule目录权限方面必须保证Application/Runtime目录可写否则页面打开就是各种报错。对新手来说最简单粗暴的方式是直接设置777权限但要清醒意识到生产环境这么做有风险等跑通了再收紧也不迟。3. 踩坑实录从白屏到正常聊天的完整排查链路3.1 最大坑ThinkPHP3.2.3的PHP版本兼容性我第一次部署时图省事直接用宝塔默认的PHP 7.4装结果打开首页白屏啥提示都没有。然后我去翻了Nginx的error.log和PHP的日志看到的是一堆关于each()函数被移除、mcrypt相关函数消失之类的报错。原因很清楚ThinkPHP 3.2.3的底层用了一些老函数在PHP 7.2之后会逐个被标记废弃或直接移除于是整个框架直接崩溃。这类问题排查起来很费劲因为框架入口会做大量的兼容性判断一个小函数报错就可能让整个请求走到500页面。当时我有两条路一条是把代码里所有老函数换成新写法工程量不小且后续维护麻烦另一条是直接给站点指定PHP 5.6版本。我选了后者。宝塔里切换PHP版本只需要在站点设置里改一下一分钟搞定然后页面瞬间正常。这个操作思路其实挺朴素老项目用老运行时稳定优先。如果你用的是Docker环境那也是同样的道理。直接拉一个php:5.6-apache镜像再把代码挂进去至少能少掉一大部分兼容性问题。新手千万不要在国外论坛上搜PHP 7.4的修复补丁折腾半天性价比极低。3.2 Runtime目录写权限引发的各种灵异报错环境切回PHP 5.6后我本以为万事大吉结果登录后台时又有零星报错不是提示模板缓存无法写入就是提示日志目录不可写。一看就是Application/Runtime没有写权限。系统运行时会在Runtime目录下生成模板编译文件、缓存文件和日志文件如果这个目录对PHP进程不可写所有需要写盘的操作都会失败。解决方法是给Runtime目录设置权限chmod -R 777 /www/wwwroot/你的站点/Application/Runtime生产环境如果想更稳一点可以递归设置目录属主为PHP-FPM运行用户比如www用户chown -R www:www Application/Runtime chmod -R 755 Application/Runtime我到现在都记得当时折腾完这个后台终于能正常登录了。这种看起来是业务报错实际是系统权限问题的坑在PHP老项目里特别常见遇到类似问题先检查目录权限往往能少走不少弯路。3.3 伪静态404和数据库字符合集权限搞定后我又遇到了一个典型问题安装了伪静态规则后访问后台首页404但用index.php?s/Admin/Login/index这个原始URL却能正常访问。排查过程是这样的先确认伪静态规则是否被正确载入在Nginx配置里加了一段rewritereload后访问依然404。再看Nginx错误日志发现请求被送到了PHP-FPM但PHP返回404这说明ThinkPHP自身的URL路由没有识别到路径。最后检查发现Nginx rewrite规则里把路径重写成了index.php?s/Admin而ThinkPHP在伪静态模式下期望的是s/Admin/Login/index少了后面的部分。最终的规则就是上面2.3节那段用if (!-e $request_filename)判断文件不存在才重写然后同时匹配index.php路径和普通路径问题解决。另外数据库字符合集也容易出事。导入SQL后如果发现中文全是乱码多半是数据库表和字段的collation不是utf8mb4。建议建库时直接选utf8mb4字段如果已经是utf8也可以执行一条命令批量转ALTER TABLE we_chat CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;别小看字符集访客消息里混入emoji的时候utf8编码根本存不下只有utf8mb4能兜住不然客服端看到的就会是问号方块。4. 核心功能与实时消息机制的拆解4.1 客服工作台和访客端都做了什么跑起来之后我先把WeLive的客服端和访客端都仔细用了一遍。客服端是一个独立的后台页面左边是当前会话列表中间是聊天窗口右边显示访客信息包括IP、来源页面、浏览器和操作系统。会话列表里可以看到访客当前是否在线、等待了多久客服可以主动发起会话。右侧访客信息对于判断用户需求很有用比如用户是从哪个推广页进来直接决定了客服第一句话怎么接。常用语功能对效率提升特别明显把售后地址、物流查询、发货时间这类高频回答提前存进去客服点一下就能发出去省得每次重复打字。会话结束后历史记录会保留在后台方便复盘和售后追查。这些功能虽然不花哨但日常客服工作该有的都有了。4.2 访客端嵌入和实时性原理访客端就是一段JavaScript插件复制代码嵌到网站的任意页面上刷新后就能看到右下角的浮窗。点击浮窗输入昵称和联系方式就能开始对话。访客端的核心逻辑是向服务器轮询消息每隔几秒发一次HTTP请求问有没有新消息有就把新消息拉到页面上。这种轮询机制最大的好处是部署简单不需要额外维护长连接服务普通Nginx PHP-FPM就能扛住中小规模流量。但它有个天然问题如果同时在线访客多每个访客的轮询请求会不断打到PHP和MySQL上数据库压力会快速上升。在只有几十个并发访客的情况下问题不大但如果期望支撑上千个同时在线就必须改造消息推送机制。4.3 如果要做高并发该往哪个方向改我早先做轮询方案时最担心的是数据库连接被打满。每个轮询请求都会查一次消息表即便没有新消息也是一次完整的PHP进程生命周期。改进思路有三条把轮询间隔拉长比如从2秒改成5秒能显著降低请求量缺点是消息延迟升高。引入Redis做短轮询PHP从内存里读消息不查MySQL这一步能把数据库压力降下来。彻底换成WebSocket前端的连接保持长连接服务器有消息直接推过来。实现上可以用GatewayWorker或Swoole把WeLive的消息收发逻辑抽出来单独做一套服务。我的建议是在日活访客过千之前就别折腾WebSocket了先把Redis短轮询跑起来成本低收益明显。我自己就是这么干的直接把原来查数据库的轮询改成优先读Redis稳定跑到现在。5. 二次开发与上线加固我从这套系统里改了什么5.1 把默认账号体系换成自己的用户系统WeLive默认的客服账号是存在自己的表里管理员在后台维护。但我的场景里客服就是网站前台注册的运营人员我不想维护两套账号。于是改造思路是客服登录时直接用自己用户系统的账号接口去校验校验通过后再把登录状态写进WeLive的session。具体来说修改Application/Admin/Controller/LoginController.class.php里的登录方法把原来查we_admin表的逻辑去掉换成调用自己的用户认证接口。密码校验我建议用password_verify()因为老项目里很多还是md5加盐新改的用户系统不应该再走md5了。为了平滑过渡我做了个兼容逻辑先判断是否是老哈希格式如果是就走老校验否则走新认证接口。这样老客服账号还能继续用同时新账号也能从用户系统登录。改完后客服人员不需要记住两个用户名密码体验好很多。5.2 访客身份识别与消息通知访客进站时WeLive默认用cookie生成一个guest_id来识别身份。这意味着同一个用户只要清了cookie客服端就认不出他来了。我把它改成了优先读取自己主站的用户ID用户已登录就把用户的昵称、手机号写入访客信息没登录才走原来的cookie方案。这个改动对客服效率提升明显咨询时直接看到张三VIP第一句话就能带上称呼。消息通知也是值得扩展的点。WeLive本身有离线留言功能访客在客服不在线时提交留言。我需要让客户第一时间知道有留言进来于是接入了微信公众号模板消息留言入库时在保存逻辑里加一个钩子调用微信模板消息接口把客户姓名留言内容摘要推给客服的微信。public function addMessage($data) { $message_id M(chat_message)-add($data); if ($data[is_offline] 1) { // 调用微信模板消息推送 WechatTemplate::sendOfflineNotice($data[username], $data[content]); } return $message_id; }改造逻辑很简单但用户体验提升非常直观客服不用一直盯后台手机也能及时收到提醒。5.3 上线前的安全加固清单开源系统部署到公网有几件事千万不能省修改后台入口路径默认的Admin目录太容易被扫描器命中我直接改名了控制器目录或在路由层做了映射。给后台登录接口加访问限制如果客服IP固定可以在Nginx层限制IP白名单。上传目录禁用PHP执行权限防止有人传个webshell上去。Nginx下可以这样配location ~ ^/Upload/.*\.(php|php5)$ { deny all; }数据库密码不要用弱密码腾讯云的端口访问记录里能清清楚楚看到有人在扫MySQL的3306端口。定时清理历史会话我用crontab每周清掉3个月前的聊天记录0 4 * * 1 mysql -uroot -p你的密码 we_live -e DELETE FROM we_chat_message WHERE create_time UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 3 MONTH));从我个人的体验来说WeLive这套开源PHP在线客服系统最大的价值不是它有多少黑科技而是它可以完全按自己节奏去改造。从部署时的版本坑到权限问题再到二次开发的账号对接和消息推送每一步都能在PHP代码里找到答案。如果你正在找一个能自己掌握数据的客服方案又想顺手熟悉一下老ThinkPHP项目的维护思路拿WeLive当练手项目比网上那些只提供演示版的付费系统实用得多。本文还有配套的精品资源点击获取