公司网站,需要一个客服在线聊天系统,找了一个基于Workerman的php socket长连接服务代码,前端基于Layim的。
模块分类:
这里我用的是thinkcmfx 的服务器,所以有些逻辑是写在controller中的,比如:登录,session和cookie的设置。
这里的后台端,用户登录将用户信息登录后,写入session中。
前端访客的信息,用cookie保存。时间写长点。当然,用户信息也是自动生成的。
两者的区别不大,就是init 时用户信息取得。不一样。
//获取列表
public function getList()
{
/*
* 1.查询自己信息
* 2.查询客户列表
*/
$img_default = "http://pic.51yuansu.com/pic2/cover/00/44/04/5813a95730ef7_610.jpg";
$uid = session('chat_uid');
if(empty($uid)){
$return = [
'code' => 0,
'msg'=> '',
'data' => [
'mine' => [
'username' => '',
'id' => '',
'status' => 'offline',
'sign' => '您还没有开通此功能,联系云商讯',
'avatar' => $img_default
],
'friend' => '',
'group'=>''
],
];
echo json_encode($return);
exit;
}
$mine = M('chatuser','snake_',$this->db)->field('id,username,avatar,sign')->where(['id'=>$uid])->find();
$mine['avatar'] = empty($mine['avatar'])?$img_default:$mine['avatar'];
//如果是客服登录
$cust_list = M('rel_customer','snake_',$this->db)->where(['salesman_id'=>$uid])->select();
$list_online = array();
$online = 0;
$list_offline = array();
$offline = 0;
foreach ($cust_list as $vo){
$cust = M('chatuser','snake_',$this->db)->field('username,id,status,sign,avatar')->where(['id'=>$vo['customer_id']])->find();
$cust['avatar'] = empty($cust['avatar'])?$img_default :$cust['avatar'];
$list_online[$online]= $cust;
$online ++;
}
/*
* 取得以前的聊天记录
* 将和user id 有关的人设为friend里的项
* 生成friend列表
*
*/
$group =['groupname'=>'访客','id'=>1,'online'=>$online];
$group['list'] =$list_online;
$friends = [];
array_push($friends, $group);
$return = [
'code' => 0,
'msg'=> '',
'data' => [
'mine' => [
'username' => $mine['username'],
'id' => $mine['id'],
'status' => 'online',
'sign' => $mine['sign'],
'avatar' => $mine['avatar']
],
'friend' => $friends,
'group'=>[]
],
];
echo json_encode($return);
// $this->ajaxReturn ($return);
}
注意:示例中的数据库 $db1 写在了switch 的case 中. 用的话写在switch前面吧!
代码贴一下吧!
$message['username'],
'avatar' => $message['avatar'],
'id' => $uid,
'sign' => $message['sign']
];
// 将当前链接与uid绑定
Gateway::bindUid($client_id, $uid);
// 通知当前客户端初始化
$init_message = array(
'message_type' => 'init',
'id' => $uid,
);
Gateway::sendToClient($client_id, json_encode($init_message));
$status_message = [
'message_type' => 'online',
'id' => $uid,
];
Gateway::sendToAll(json_encode($status_message));
//查询最近1周有无需要推送的离线信息
$time = time() - 7 * 3600 * 24;
$resMsg = $db1->select('id,fromid,fromname,fromavatar,timeline,content')->from('snake_chatlog')
->where("toid= {$uid} and timeline > {$time} and type = 'friend' and needsend = 1" )
->query();
$db1->query("UPDATE `snake_chatuser` SET `status` = 'online' WHERE id=" . $uid);
//var_export($resMsg);
if( !empty( $resMsg ) ){
foreach( $resMsg as $key=>$vo ){
$log_message = [
'message_type' => 'logMessage',
'data' => [
'username' => $vo['fromname'],
'avatar' => $vo['fromavatar'],
'id' => $vo['fromid'],
'type' => 'friend',
'content' => htmlspecialchars( $vo['content'] ),
'timestamp'=> $vo['timeline'] * 1000,
]
];
Gateway::sendToUid( $uid, json_encode($log_message) );
//设置推送状态为已经推送
$db1->query("UPDATE `snake_chatlog` SET `needsend` = '0' WHERE id=" . $vo['id']);
}
}
//查询当前的用户是在哪个分组中,将当前的链接加入该分组
/*
$ret = $db1->query("select `groupid` from `snake_groupdetail` where `userid` = {$uid} group by `groupid`");
if( !empty( $ret ) ){
foreach( $ret as $key=>$vo ){
Gateway::joinGroup($client_id, $vo['groupid']); //将登录用户加入群组
}
}
unset( $ret );
*/
return;
break;
case 'addUser' :
//添加用户
$add_message = [
'message_type' => 'addUser',
'data' => [
'type' => 'friend',
'avatar' => $message['data']['avatar'],
'username' => $message['data']['username'],
'groupid' => $message['data']['groupid'],
'id' => $message['data']['id'],
'sign' => $message['data']['sign']
]
];
Gateway::sendToAll( json_encode($add_message), null, $client_id );
return;
break;
case 'delUser' :
//删除用户
$del_message = [
'message_type' => 'delUser',
'data' => [
'type' => 'friend',
'id' => $message['data']['id']
]
];
Gateway::sendToAll( json_encode($del_message), null, $client_id );
return;
break;
case 'addGroup':
//添加群组
$uids = explode( ',', $message['data']['uids'] );
$client_id_array = [];
foreach( $uids as $vo ){
$ret = Gateway::getClientIdByUid( $vo ); //当前组中在线的client_id
if( !empty( $ret ) ){
$client_id_array[] = $ret['0'];
Gateway::joinGroup($ret['0'], $message['data']['id']); //将这些用户加入群组
}
}
unset( $ret, $uids );
$add_message = [
'message_type' => 'addGroup',
'data' => [
'type' => 'group',
'avatar' => $message['data']['avatar'],
'id' => $message['data']['id'],
'groupname' => $message['data']['groupname']
]
];
Gateway::sendToAll( json_encode($add_message), $client_id_array, $client_id );
return;
break;
case 'joinGroup':
//加入群组
$uid = $message['data']['uid'];
$ret = Gateway::getClientIdByUid( $uid ); //若在线实时推送
if( !empty( $ret ) ){
Gateway::joinGroup($ret['0'], $message['data']['id']); //将该用户加入群组
$add_message = [
'message_type' => 'addGroup',
'data' => [
'type' => 'group',
'avatar' => $message['data']['avatar'],
'id' => $message['data']['id'],
'groupname' => $message['data']['groupname']
]
];
Gateway::sendToAll( json_encode($add_message), [$ret['0']], $client_id ); //推送群组信息
}
return;
break;
case 'addMember':
//添加群组成员
$uids = explode( ',', $message['data']['uid'] );
$client_id_array = [];
foreach( $uids as $vo ){
$ret = Gateway::getClientIdByUid( $vo ); //当前组中在线的client_id
if( !empty( $ret ) ){
$client_id_array[] = $ret['0'];
Gateway::joinGroup($ret['0'], $message['data']['id']); //将这些用户加入群组
}
}
unset( $ret, $uids );
$add_message = [
'message_type' => 'addGroup',
'data' => [
'type' => 'group',
'avatar' => $message['data']['avatar'],
'id' => $message['data']['id'],
'groupname' => $message['data']['groupname']
]
];
Gateway::sendToAll( json_encode($add_message), $client_id_array, $client_id ); //推送群组信息
return;
break;
case 'removeMember':
//将移除群组的成员的群信息移除,并从讨论组移除
$ret = Gateway::getClientIdByUid( $message['data']['uid'] );
if( !empty( $ret ) ){
Gateway::leaveGroup($ret['0'], $message['data']['id']);
$del_message = [
'message_type' => 'delGroup',
'data' => [
'type' => 'group',
'id' => $message['data']['id']
]
];
Gateway::sendToAll( json_encode($del_message), [$ret['0']], $client_id );
}
return;
break;
case 'delGroup':
//删除群组
$del_message = [
'message_type' => 'delGroup',
'data' => [
'type' => 'group',
'id' => $message['data']['id']
]
];
Gateway::sendToAll( json_encode($del_message), null, $client_id );
return;
break;
case 'chatMessage':
$db1 = Db::instance('db1'); //数据库链接
// 聊天消息
$type = $message['data']['to']['type'];
$to_id = $message['data']['to']['id'];
$uid = $_SESSION['id'];
$chat_message = [
'message_type' => 'chatMessage',
'data' => [
'username' => $_SESSION['username'],
'avatar' => $_SESSION['avatar'],
'id' => $type === 'friend' ? $uid : $to_id,
'type' => $type,
'content' => htmlspecialchars($message['data']['mine']['content']),
'timestamp'=> time()*1000,
]
];
//聊天记录数组
$param = [
'fromid' => $uid,
'toid' => $to_id,
'fromname' => $_SESSION['username'],
'fromavatar' => $_SESSION['avatar'],
'content' => htmlspecialchars($message['data']['mine']['content']),
'timeline' => time(),
'needsend' => 0
];
switch ($type) {
// 私聊
case 'friend':
// 插入
$param['type'] = 'friend';
if( Gateway::isUidOnline( $to_id )== 0 ){
$param['needsend'] = 1; //用户不在线,标记此消息推送
}
$db1->insert('snake_chatlog')->cols( $param )->query();
return Gateway::sendToUid($to_id, json_encode($chat_message));
// 群聊
case 'group':
$param['type'] = 'group';
$db1->insert('snake_chatlog')->cols( $param )->query();
return Gateway::sendToGroup($to_id, json_encode($chat_message), $client_id);
case 'kefu':
// 插入
$param['type'] = 'kefu';
if( Gateway::isUidOnline( $to_id )== 0 ){
$param['needsend'] = 1; //用户不在线,标记此消息推送
}
$db1->insert('snake_chatlog')->cols( $param )->query();
return Gateway::sendToUid($to_id, json_encode($chat_message));
}
return;
break;
case 'hide':
$status_message = [
'message_type' => $message_type,
'id' => $_SESSION['id'],
];
$_SESSION['online'] = $message_type;
Gateway::sendToAll(json_encode($status_message));
return;
break;
case 'online':
$status_message = [
'message_type' => $message_type,
'id' => $_SESSION['id'],
];
$_SESSION['online'] = $message_type;
Gateway::sendToAll(json_encode($status_message));
return;
break;
case 'logout':
$uid = $message['id'];
$status_message = [
'message_type' => $message_type,
'id' => $_SESSION['id'],
];
$_SESSION['online'] = $message_type;
$db1->query("UPDATE `snake_chatlog` SET `needsend` = '0' WHERE id=" . $uid);
Gateway::sendToAll(json_encode($status_message));
return;
break;
case 'ping':
return;
default:
echo "unknown message $data" . PHP_EOL;
}
}
/**
* 当用户断开连接时触发
* @param int $client_id 连接id
*/
public static function onClose($client_id) {
$logout_message = [
'message_type' => 'logout',
'id' => $_SESSION['id']
];
$db1 = Db::instance('db1');
$db1->query("UPDATE `snake_chatuser` SET `status` = 'offline' WHERE id=" . $_SESSION['id']);
Gateway::sendToAll(json_encode($logout_message));
}
}