LayIM接入案例PHP篇 源码+demo

提问 已结 精帖
70 40966
我是隔壁云老王
悬赏:5飞吻
首先老规矩,php是世界上最好的语言!(或许马上就变成宇宙中最好的语言)

demo地址:http://php.77wx.cn/

服务端
php用到的是 基于Workerman的 GatewayWorker 框架。该框架开源,免费,文档友好。

客户端
html5原生websocket 协议 ,因为 我不清楚是 Workerman GatewayWorker 还是socket.io 存在跨域问题



功能:
微信登陆,QQ登陆,
单聊,群聊 传图片,传文件,好友不在线提醒
实时显示好友上线下线等。
mysql 保存聊天记录
服务端 监听3003端口

服务端







Workerman GatewayWorker安装流程
首先下载和系统对应的 Workerman GatewayWorker ,注意这个分 win版 和linux版
之后 配置系统变量 //自行百度
然后配置协议类型 ip地址 端口
重要!!!,好多人和我反应说 websocket 无法链接, 其实是没有配置 websocket协议导致
配置协议 打开 start_gateway.php 在25行左右 把 text协议改成 Websocket

最后 把下面源码 复制到 Events.php 保存
在命令行启动 应用。
完成。


php 源码
<?php
use GatewayWorker\Lib\Gateway;
class Events
{
public static $user = [];
public static $uuid = [];
public static function onWorkerStart($businessWorker)
{ //服务准备就绪
echo "Worker_socket_ready\n";
}

public static function onConnect($client_id)
{
//当客户端链接上时触发,这里可以做 session 域名来源排除 ,安全过滤等

}


public static function onMessage($client_id, $message)
{

/*监听事件,需要把客户端发来的json转为数组*/
$data = json_decode($message, true);
switch ($data['type']) {

//当有用户上线时
case 'reg':
//绑定uid 用于数据分发
Gateway::bindUid($client_id, $data['content']['uid']);
self::$user[$data['content']['uid']] = $client_id;
self::$uuid[$data['content']['uid']] = $data['content']['uid'];

//给当前客户端 发送当前在线人数,以及当前在线人的资料
$reg_data['uuser'] = self::$uuid;
$reg_data['num'] = count(self::$user);
$reg_data['type'] = "reguser";
Gateway::sendToClient($client_id, json_encode($reg_data));

//将当前在线用户数量,和新上线用户的资料发给所有人 但把排除自己,否则会出现重复好友
$all_data['type'] = "addList";
$all_data['content'] = $data['content'];
$all_data['content']['type'] = 'friend';
$all_data['content']['groupid'] = 2;
$all_data['num'] = count(self::$user);
Gateway::sendToAll(json_encode($all_data), '', $client_id);
break;


case 'chatMessage':
//处理聊天事件
$msg['username'] = $data['content']['mine']['username'];
$msg['avatar'] = $data['content']['mine']['avatar'];
$msg['id'] = $data['content']['mine']['id'];
$msg['content'] = $data['content']['mine']['content'];
$msg['type'] = $data['content']['to']['type'];
$chatMessage['type'] = 'getMessage';
$chatMessage['content'] = $msg;

//处理单聊
if ($data['content']['to']['type'] == 'friend') {

if (isset(self::$uuid[$data['content']['to']['id']])) {
Gateway::sendToUid(self::$uuid[$data['content']['to']['id']], json_encode($chatMessage));
} else {
//处理离线消息
$noonline['type'] = 'noonline';
Gateway::sendToClient($client_id, json_encode($noonline));
}
} else {
//处理群聊
$chatMessage['content']['id'] = $data['content']['to']['id'];
Gateway::sendToAll(json_encode($chatMessage), '', $client_id);
}
break;
}


}
/**
* 当用户断开连接时触发
* @param int $client_id 连接id
*/
public static function onClose($client_id)
{

//有用户离线时触发 并推送给全部用户
$data['type'] = "out";
$data['id'] = array_search($client_id, self::$user);
unset(self::$user[$data['id']]);
unset(self::$uuid[$data['id']]);
$data['num'] = count(self::$user);
Gateway::sendToAll(json_encode($data));

}
}
回帖
  • 贤心
    贤心 (管理员)
    2016-7-8
    非常棒,已置顶加精
    5 回复
  • 我也是用的THINKPHP 想弄一个在线IM的客服系统
    功能需求很简单
    前台判断 是否已登录用户
    登录就显示该账户昵称和头像 没登录就显示为临时用户
    IM初始化好友里只有客服人员 客服在后台登录后 会在前台显示在线
    发消息也是 前台用户跟后台客服之间交流
    研究了一天了
    现在的程度是 在入口文件建立了个PHP文件 可以在命令行模式下启动这文件

    前台IM可以发送数据到 workerman 并且返回数据
    收到数据后的处理 整个系统的搭建 还有数据表设计 让我有点迷茫

    楼主可以加个QQ 给我指导点思路吗
    6 回复
  • 我已登陆账号 准备接客了
    1 回复
  • 不错不错,看来所有的版本都有了
    1 回复
  • @老彭 python的呢[白眼]
    1 回复
  • [给力]
    1 回复
  • 顶,等下试试
    1 回复
  • @我是隔壁老王 什么时候做一个java的demo
    1 回复
  • 大王
    2016-7-8
    [good]
    1 回复
  • @微笑 本屌 只会脚本语言 不会编译语言。。。
    1 回复
  • @我是隔壁老王 本吊不会。。。
    1 回复
  • 楼主,这个错怎么解决Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.
    1 回复
  • @阳光下 等页面加载完之后 先 new WebSocket(); 然后再send。 如果还没有new 出来 ,你就send 会有类似的错误
    1 回复
  • @我是隔壁老王 我已经把send事件放到layim.on('ready', function(res){})里面了啊
    1 回复
  • @阳光下 如果你用的是 lay 自带的 socket可以这样 如果是html5 原生的还是建议你 加setTimeout 来延迟执行send,
    1 回复
  • @我是隔壁老王 可是用了自带的socket也提示Still in CONNECTING state.不知道是怎么回事,workerman正常运行
    1 回复
  • PHP Parse error: syntax error, unexpected '[' in F:\phpStudy\WWW\workerman\Applications\layim\Events.php on line 5 这个是什么错误
    1 回复
  • @阳光下 layim 自带的socket 不能用于workerman(起码我没有配置成功),layim自带的socket适用于node,貌似不适合 workerman
    1 回复
  • @毕业以后 你可以尝试着把第五行删掉
    1 回复
  • @我是隔壁老王 我看你的demo源代码是用的layim自带的啊
    1 回复
  • iseeyo
    2016-7-9
    怎么不用GatewayWorker呢,GatewayWorker貌似更强大点吧
    1 回复
  • @阳光下 我做了两个demo 一个是Node.js版本 这个用的是 layim自带的 socket模块
    PHP版本 用的是 html5 原生的 WebSocket 协议

    node版 :http://im.77wx.cn
    PHP版:http://php.77wx.cn

    可能这两个页面看起来一模一样 所以你搞混了,你可以查看源代码,会发现 js代码是不一样的
    1 回复
  • @iseeyo 我用的就是 GatewayWorker, 不过GatewayWorker也是基于 workerman 。
    1 回复
  • 服务器连接上了,下一下如何来操作呢
    1 回复
  • 锐志
    2016-7-19
    @我是隔壁老王
    //给当前客户端 发送当前在线人数,以及当前在线人的资料
    $reg_data['uuser'] = self::$uuid;
    $reg_data['num'] = count(self::$user);
    $reg_data['type'] = "reguser";

    代码里面的$reg_data['uuser'] 传过客户端的只有uid,是不是根据uid到数据库里面去获取当前在线人数的资料呢?然后再用layim.addList 加入的好友列表中去?
    1 回复
  • @锐志 对的对的,就是这个意思
    1 回复
  • 锐志
    2016-7-20
    @我是隔壁老王
    uid传过来的是json格式的数据吧? 可是用json_decode 不起作用。 是我搞错了?
    1 回复
  • 那里有源码??
    1 回复
  • 大猫
    2016-7-22
    哈哈,workerman最适合做这个了
    1 回复
  • 锐志
    2016-7-26
    @我是隔壁老王
    当用户A用同一个浏览器打开了2个以上的页面同时打开了两个主面板,当用户B向A发送一条消息的时候,第一个页面中A对B的聊天窗口(聊天窗口事先没有打开的)收到来自B的一条消息,第二个页面中A对B的聊天窗口收到来自B的两条消息(内容是一样的,实际上B就发了一条消息),如此类推,第三个页面就发送了3条。如果是每个页面A对B的聊天窗口事先打开的情况下,每个聊天窗口就接收到一条信息,这应该是layim导致的,请问这个问题有好的解决方法吗?
    1 回复
本帖已设置禁止回复