对接腾讯IM
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="renderer" content="webkit" /> <meta name="force-rendering" content="webkit" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" /> <title>MY</title> <script type="text/javascript" src="https://www.w3school.com.cn/jquery/jquery.js"></script> </head> <body> <input type="button" value="导入发送方帐号" onClick="one()"></br> <input type="button" value="导入接收方帐号" onClick="one_a()"></br> <input type="button" value="查询账号是否成功导入" onClick="two()"></br> <input type="button" value="发送单发消息" onClick="three()"></br> <input type="button" value="查询聊天记录" onClick="four()"></br> <div class="susersig"></div> <script type="text/javascript"> <?php $identifier = 'administrator'; $sdkappid = 140000000; $secretkey = 'e4e835c96a4354b361dsfsafgsadfsafd307d49de30d454c80f5c'; ?> //导入单个帐号 function one(){ var data = JSON.stringify({ "Identifier": "user1" }); $.post("https://console.tim.qq.com/v4/im_open_login_svc/account_import?sdkappid=<?php echo $sdkappid;?>&identifier=<?php echo $identifier;?>&usersig=<?php echo $userSig;?>&random=<?php echo rand(11111,77777);?>&contenttype=json",data,function(result){ console.log(result); }); } //导入单个帐号 function one_a(){ var data = JSON.stringify({ "Identifier": "user2" }); $.post("https://console.tim.qq.com/v4/im_open_login_svc/account_import?sdkappid=<?php echo $sdkappid;?>&identifier=<?php echo $identifier;?>&usersig=<?php echo $userSig;?>&random=<?php echo rand(11111,77777);?>&contenttype=json",data,function(result){ console.log(result); }); } //批量查询账号是否已经导入 function two(){ var data = JSON.stringify({ "CheckItem":[ { "UserID":"user1" }, { "UserID":"user2" }] }); $.post("https://console.tim.qq.com/v4/im_open_login_svc/account_check?sdkappid=<?php echo $sdkappid;?>&identifier=<?php echo $identifier;?>&usersig=<?php echo $userSig;?>&random=<?php echo rand(11111,77777);?>&contenttype=json",data,function(result){ console.log(result); }); } //单发单聊消息 function three(){ var data = JSON.stringify({ "From_Account": "user1", "To_Account": "user2", "MsgBody": [ { "MsgType": "TIMTextElem", "MsgContent": { "Text": "有没有大码女装?" } } ], "MsgRandom": <?php echo rand(11111,77777);?> }); $.post("https://console.tim.qq.com/v4/openim/sendmsg?sdkappid=<?php echo $sdkappid;?>&identifier=<?php echo $identifier;?>&usersig=<?php echo $userSig;?>&random=<?php echo rand(11111,77777);?>&contenttype=json",data,function(result){ console.log(result); }); } //查询聊天记录 function four(){ var data = JSON.stringify({ "From_Account": "user1", "To_Account": "user2", "MaxCnt": 100, "MinTime": <?php echo strtotime("-5 day");?>, "MaxTime": <?php echo strtotime("+5 day");?> }); $.post("https://console.tim.qq.com/v4/openim/admin_getroammsg?sdkappid=<?php echo $sdkappid;?>&identifier=<?php echo $identifier;?>&usersig=<?php echo $userSig;?>&random=<?php echo rand(11111,77777);?>&contenttype=json",data,function(result){ console.log(result); }); } </script> </body> </html>
PHP生成sign
if (version_compare(PHP_VERSION, '5.1.2') < 0) { trigger_error('need php 5.1.2 or newer', E_USER_ERROR); } $TLSSigAPIv2 = new TLSSigAPIv2(140000000,'e4e835c96a4354b361d25fc136a0fsdf7e04e307d49de30d454c80f5c'); echo $TLSSigAPIv2->genSig('administrator',86400); class TLSSigAPIv2 { private $key = false; private $sdkappid = 0; public function __construct($sdkappid, $key) { $this->sdkappid = $sdkappid; $this->key = $key; } /** * 用于 url 的 base64 encode * '+' => '*', '/' => '-', '=' => '_' * @param string $string 需要编码的数据 * @return string 编码后的base64串,失败返回false * @throws \Exception */ private function base64_url_encode($string) { static $replace = Array('+' => '*', '/' => '-', '=' => '_'); $base64 = base64_encode($string); if ($base64 === false) { throw new \Exception('base64_encode error'); } return str_replace(array_keys($replace), array_values($replace), $base64); } /** * 用于 url 的 base64 decode * '+' => '*', '/' => '-', '=' => '_' * @param string $base64 需要解码的base64串 * @return string 解码后的数据,失败返回false * @throws \Exception */ private function base64_url_decode($base64) { static $replace = Array('+' => '*', '/' => '-', '=' => '_'); $string = str_replace(array_values($replace), array_keys($replace), $base64); $result = base64_decode($string); if ($result == false) { throw new \Exception('base64_url_decode error'); } return $result; } /** * 使用 hmac sha256 生成 sig 字段内容,经过 base64 编码 * @param $identifier 用户名,utf-8 编码 * @param $curr_time 当前生成 sig 的 unix 时间戳 * @param $expire 有效期,单位秒 * @param $base64_userbuf base64 编码后的 userbuf * @param $userbuf_enabled 是否开启 userbuf * @return string base64 后的 sig */ private function hmacsha256($identifier, $curr_time, $expire, $base64_userbuf, $userbuf_enabled) { $content_to_be_signed = "TLS.identifier:" . $identifier . "\n" . "TLS.sdkappid:" . $this->sdkappid . "\n" . "TLS.time:" . $curr_time . "\n" . "TLS.expire:" . $expire . "\n"; if (true == $userbuf_enabled) { $content_to_be_signed .= "TLS.userbuf:" . $base64_userbuf . "\n"; } return base64_encode(hash_hmac( 'sha256', $content_to_be_signed, $this->key, true)); } /** * 生成签名。 * * @param $identifier 用户账号 * @param int $expire 过期时间,单位秒,默认 180 天 * @param $userbuf base64 编码后的 userbuf * @param $userbuf_enabled 是否开启 userbuf * @return string 签名字符串 * @throws \Exception */ private function __genSig($identifier, $expire, $userbuf, $userbuf_enabled) { $curr_time = time(); $sig_array = Array( 'TLS.ver' => '2.0', 'TLS.identifier' => strval($identifier), 'TLS.sdkappid' => intval($this->sdkappid), 'TLS.expire' => intval($expire), 'TLS.time' => intval($curr_time) ); $base64_userbuf = ''; if (true == $userbuf_enabled) { $base64_userbuf = base64_encode($userbuf); $sig_array['TLS.userbuf'] = strval($base64_userbuf); } $sig_array['TLS.sig'] = $this->hmacsha256($identifier, $curr_time, $expire, $base64_userbuf, $userbuf_enabled); if ($sig_array['TLS.sig'] === false) { throw new \Exception('base64_encode error'); } $json_str_sig = json_encode($sig_array); if ($json_str_sig === false) { throw new \Exception('json_encode error'); } $compressed = gzcompress($json_str_sig); if ($compressed === false) { throw new \Exception('gzcompress error'); } return $this->base64_url_encode($compressed); } /** * 生成签名 * * @param $identifier 用户账号 * @param int $expire 过期时间,单位秒,默认 180 天 * @return string 签名字符串 * @throws \Exception */ public function genSig($identifier, $expire=86400*180) { return $this->__genSig($identifier, $expire, '', false); } /** * 验证签名。 * * @param string $sig 签名内容 * @param string $identifier 需要验证用户名,utf-8 编码 * @param int $init_time 返回的生成时间,unix 时间戳 * @param int $expire_time 返回的有效期,单位秒 * @param string $userbuf 返回的用户数据 * @param string $error_msg 失败时的错误信息 * @return boolean 验证是否成功 * @throws \Exception */ private function __verifySig($sig, $identifier, &$init_time, &$expire_time, &$userbuf, &$error_msg) { try { $error_msg = ''; $compressed_sig = $this->base64_url_decode($sig); $pre_level = error_reporting(E_ERROR); $uncompressed_sig = gzuncompress($compressed_sig); error_reporting($pre_level); if ($uncompressed_sig === false) { throw new \Exception('gzuncompress error'); } $sig_doc = json_decode($uncompressed_sig); if ($sig_doc == false) { throw new \Exception('json_decode error'); } $sig_doc = (array)$sig_doc; if ($sig_doc['TLS.identifier'] !== $identifier) { throw new \Exception("identifier dosen't match"); } if ($sig_doc['TLS.sdkappid'] != $this->sdkappid) { throw new \Exception("sdkappid dosen't match"); } $sig = $sig_doc['TLS.sig']; if ($sig == false) { throw new \Exception('sig field is missing'); } $init_time = $sig_doc['TLS.time']; $expire_time = $sig_doc['TLS.expire']; $curr_time = time(); if ($curr_time > $init_time+$expire_time) { throw new \Exception('sig expired'); } $userbuf_enabled = false; $base64_userbuf = ''; if (isset($sig_doc['TLS.userbuf'])) { $base64_userbuf = $sig_doc['TLS.userbuf']; $userbuf = base64_decode($base64_userbuf); $userbuf_enabled = true; } $sigCalculated = $this->hmacsha256($identifier, $init_time, $expire_time, $base64_userbuf, $userbuf_enabled); if ($sig != $sigCalculated) { throw new \Exception('verify failed'); } return true; } catch (\Exception $ex) { $error_msg = $ex->getMessage(); return false; } } /** * 带 userbuf 验证签名。 * * @param string $sig 签名内容 * @param string $identifier 需要验证用户名,utf-8 编码 * @param int $init_time 返回的生成时间,unix 时间戳 * @param int $expire_time 返回的有效期,单位秒 * @param string $error_msg 失败时的错误信息 * @return boolean 验证是否成功 * @throws \Exception */ public function verifySig($sig, $identifier, &$init_time, &$expire_time, &$error_msg) { $userbuf = ''; return $this->__verifySig($sig, $identifier, $init_time, $expire_time, $userbuf, $error_msg); } /** * 验证签名 * @param string $sig 签名内容 * @param string $identifier 需要验证用户名,utf-8 编码 * @param int $init_time 返回的生成时间,unix 时间戳 * @param int $expire_time 返回的有效期,单位秒 * @param string $userbuf 返回的用户数据 * @param string $error_msg 失败时的错误信息 * @return boolean 验证是否成功 * @throws \Exception */ public function verifySigWithUserBuf($sig, $identifier, &$init_time, &$expire_time, &$userbuf, &$error_msg) { return $this->__verifySig($sig, $identifier, $init_time, $expire_time, $userbuf, $error_msg); } }
完美的聊天界面
<?php $identifier = 'administrator'; $sdkappid = 10000000002; $userSig = 'eJwtjFELgjAcxL-LXgv7Oxw6oQeFiIVvaoH0MtiMPadfsafsadfsdafasdfasfafasfd1XBpRX8k3x9wwTRV';//userID等于administrator生成的userSin $master = $_GET['master']; $guest = $_GET['guest']; ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title>即时通讯</title> <link rel="stylesheet" type="text/css" href="/fontawesome/css/font-awesome.css" /> <script src="/layui/layui.all.js"></script> <link rel="stylesheet" href="/layui/css/layui.css"> <script src="/jquery-1.11.3.min.js"></script> <style> .chat_list{border-top:#eee solid 5px;} .chat_list li{height:45px;padding:0px 10px;border-bottom:#dedede solid 1px;} .chat_list li .com_name{float:left;height:45px; line-height:45px;color:#333} .chat_list li .fa{float:right;height:45px; line-height:45px;color:#444} .layui-tab-title li{float:left;padding:0px 0px;} .foot_bottom{ position:fixed;height:55px;padding-top:10px;background:#e2e2e2;bottom:0px;width:100%;} .foot_bottom .text{background:#fff;padding-left:5px;border-radius:3px;height:40px;border:none;width:72%;float:left;font-size:16px;color:#444} .foot_bottom .fasong_btn{height:40px;width:24%;border:0px;margin:0px;paddingf:0px;float:right;background:#ccc} .chat_area{position:fixed;top:43px;width:100%;overflow-y:scroll;} .chat_area ul{padding-top:20px;} .chat_area ul li{min-height:100px;clear:both;} .chat_area ul li.fl{text-align:left;padding-left:10px;} .chat_area ul li.fl span{float:left;border-radius:50%;background:#fff;width:30px;height:30px;text-align:center;line-height:30px;} .chat_area ul li.fl .say_box{background:#fff;clear:both;width:50%;min-height:30px;border-radius:5px;margin-left:50px;position:relative;padding:5px 5px 5px 5px;word-wrap:break-word;top:-30px;} .chat_area ul li.fl .say_box .sjx{width:0;height: 0;border-top: 10px solid transparent;border-right: 20px solid #fff;border-bottom: 10px solid transparent;position:absolute;left:-15px;top:6px;} .chat_area ul li.fl .say_box .txt_area .font_info{color:#444;text-align:left;padding:0px 0px 5px 0px;} .chat_area ul li.fl .say_box .txt_area .date_tip{color:#444;font-size:12px;text-align:right;border-top:#ccc dashed 1px;padding:5px 0px;} .chat_area ul li.fr{text-align:right;padding-right:10px;} .chat_area ul li.fr span{float:right;border-radius:50%;background:#fff;width:30px;height:30px;text-align:center;line-height:30px;} .chat_area ul li.fr .say_box{background:#fff;clear:both;width:50%;float:right;min-height:30px;border-radius:5px;margin-right:50px;position:relative;padding:5px 5px 5px 5px;word-wrap:break-word;top:-30px;text-align:left;} .chat_area ul li.fr .say_box .sjx{width:0;height: 0;border-top: 10px solid transparent;border-left: 20px solid #fff;border-bottom: 10px solid transparent;position:absolute;right:-15px;top:6px;} .chat_area ul li.fr .say_box .txt_area .font_info{color:#444;text-align:left;padding:0px 0px 5px 0px;} .chat_area ul li.fr .say_box .txt_area .date_tip{color:#444;font-size:12px;text-align:right;border-top:#ccc dashed 1px;padding:5px 0px;} </style> </head> <body style="background:#eee"> <div class="hui-wrap"> <div class="layui-tab layui-tab-brief" style="margin:0px;background:#fff"> <ul class="layui-tab-title"> <li style="width:100%"> <span><?php echo $master;?> 正在和 <?php echo $guest;?> 聊天</span> </li> </ul> <div class="layui-tab-content" style="padding:0px;"> <div class="chat_area"> <ul><li style="height:10000px;"></li></ul> </div> <div class="foot_bottom"> <div class="layim-chat-send layim-chat-footer" style="padding:0px 10px;"> <input type="text" class="text" autocomplete="off" onchange="check_text()"> <button type="button" class="layui-btn fasong_btn" onClick="send_info()">发送</button> </div> </div> </div> </div> </div> <script> //检测是否可以发送文字 function check_text(){ if($(".text").val()==''){ $(".fasong_btn").css('background','#ccc'); }else{ $(".fasong_btn").css('background','#009688'); } } $(document).ready(function(){ get_saylist();//拉取聊天记录 $(".chat_area").height($(window).height()-110); $(window).resize(function(){ $(".chat_area").height($(window).height()-94); }); }); $('.text').bind('input propertychange', function(){ if($(this).val()){ $(".fasong_btn").css('background','#009688'); }else{ $(".fasong_btn").css('background','#ccc'); } }) </script> <script type="text/javascript"> //单发单聊消息 function send_info(){ if($(".text").val()==''){ $(".fasong_btn").css('background','#ccc'); return; }else{ $(".fasong_btn").css('background','#009688'); } var data = JSON.stringify({ "From_Account": "<?php echo $master;?>", "To_Account": "<?php echo $guest;?>", "MsgBody": [ { "MsgType": "TIMTextElem", "MsgContent": { "Text":$(".text").val() } } ], "MsgRandom": <?php echo rand(11111,77777);?> }); $.post("https://console.tim.qq.com/v4/openim/sendmsg?sdkappid=<?php echo $sdkappid;?>&identifier=<?php echo $identifier;?>&usersig=<?php echo $userSig;?>&random=<?php echo rand(11111,77777);?>&contenttype=json",data,function(result){ console.log(result); $(".fasong_btn").css('background','#ccc'); $(".text").val(''); get_saylist(); }); } //查询聊天记录 function get_saylist(){ var data = JSON.stringify({ "From_Account": "<?php echo $master;?>", "To_Account": "<?php echo $guest;?>", "MaxCnt": 100, "MinTime": <?php echo strtotime("-5 day");?>, "MaxTime": <?php echo strtotime("+5 day");?> }); $.post("https://console.tim.qq.com/v4/openim/admin_getroammsg?sdkappid=<?php echo $sdkappid;?>&identifier=<?php echo $identifier;?>&usersig=<?php echo $userSig;?>&random=<?php echo rand(11111,77777);?>&contenttype=json",data,function(result){ var say_list_info=''; for (const val in result.MsgList) { if(result.MsgList[val].From_Account=='<?php echo $master;?>'){ say_list_info +='<li class="fr"><span>我</span><div class="say_box"><div class="sjx"></div><div class="txt_area"><div class="font_info">'+result.MsgList[val].MsgBody[0].MsgContent.Text+'</div><div class="date_tip" >'+formatDate(result.MsgList[val].MsgTimeStamp)+'</div></div></div></li>'; }else{ say_list_info +='<li class="fl"><span>Ta</span><div class="say_box"><div class="sjx"></div><div class="txt_area"><div class="font_info">'+result.MsgList[val].MsgBody[0].MsgContent.Text+'</div><div class="date_tip" >'+formatDate(result.MsgList[val].MsgTimeStamp)+'</div></div></div></li>'; } } $(".chat_area ul").html(say_list_info); $(".chat_area").scrollTop($(".chat_area ul").height()); }); } window.setInterval(function(){ get_saylist(); }, 3000); //时间戳转时间 1597814865 function formatDate() { var d=new Date(1597814865*1000); //秒数bai要转为毫秒数 return d.getFullYear()+'-'+d.getMonth()+'-'+d.getDay()+' '+d.getHours()+':'+d.getMinutes()+':'+d.getSeconds(); } </script> </body> </html>