XMPP 踩坑记
经验
- 使用过的失败的组件(原因是SSL连接失败)
 
composer require norgul/xmpp-php
composer require fabiang/xmpp
- 下面这个组件才是实验成功的
 
composer require "jaxl/jaxl=^3.1.0"
安装的环境
- openfire_4_7_1_x64.exe 服务器
 - spark_2_9_4-with-jre.exe 客户端 功能齐全UI不错
 - Swift-4.0.2.msi 客户端 可以开启调试log
 
遇到的坑主要是
1. 连接服务器失败
原因:jid 后面带了@will
$client = new JAXL(array(
    'jid' => 'will',
    'pass' => 'asdasd',
    'host'=>'127.0.0.1',
//    'auth_type'=>'ANONYMOUS', //匿名登录
    'log_level' => JAXLLogger::DEBUG,
));
2. 向房间发送消息失败
原因:进入房间的jid 房间名末尾要加上 /will 就是用户的名字
$_room_full_jid = "will@conference.will/will";
3. 私聊的时候需要列席吗?
实验下来,不需要列席,也可以发出消息(php代码发),对方也可以收到消息(客户端接收)。
4. 自定房间发消息时注意的地方
必须进入房间,才能发送消息
// 进入房间
$client->xeps['0045']->join_room($room_full_jid);
5. 组件 jaxl.php 787 行报错
改为下面代码,可以得到返回值
    if ($this->manage_roster) {
        $type = ($stanza->type ? $stanza->type : "available");
        $jid = new XMPPJid($stanza->from);
        
        if ($type == 'available') {
          try {
            $this->roster[$jid->bare]->resources[$jid->resource] = $stanza;
          } catch (\JAXLException  $e) {
            throw new App\Exceptions\ApiException(App\Common\Err\ApiErrDesc::ERR_SEND_XMPP_MSG_FULFILL);
            die();
          }
        } elseif ($type == 'unavailable') {
            if (isset($this->roster[$jid->bare]) && isset($this->roster[$jid->bare]->resources[$jid->resource])) {
                unset($this->roster[$jid->bare]->resources[$jid->resource]);
            }
        }
    }
代码展示
私聊发消息
<?php
require_once "vendor/autoload.php";
$client = new JAXL(array(
    'jid' => 'will',
    'pass' => 'asdasd',
    'host'=>'127.0.0.1',
//    'auth_type'=>'ANONYMOUS', //匿名登录
    'log_level' => JAXLLogger::DEBUG,
));
$client->add_cb('on_auth_success', function() {
    global $client;
    // set status
//    $client->set_status("在线",'chat',1);
//    $client->get_vcard();               // fetch your vcard
//    $client->get_roster();              // fetch your roster list
    JAXLLogger::info("got on_auth_success cb, jid ".$client->full_jid->to_string());
    $client->send_chat_msg("asd@will","1111111");
    $client->send_end_stream(); //断开连接
});
function on_auth_failure_callback($reason)
{
    global $client;
    $client->send_end_stream();
    JAXLLogger::info("got on_auth_failure cb with reason $reason");
}
$client->add_cb('on_auth_failure', 'on_auth_failure_callback');
function on_disconnect_callback()
{
    JAXLLogger::info("got on_disconnect cb");
}
$client->add_cb('on_disconnect', 'on_disconnect_callback');
$client->start();
向房间发消息
<?php
require_once "vendor/autoload.php";
$client = new JAXL(array(
    'jid' => 'will',
    'pass' => 'asdasd',
    'host'=>'127.0.0.1',
//    'auth_type'=>'ANONYMOUS', //匿名登录
    'log_level' => JAXLLogger::DEBUG,
));
$_room_full_jid = "will@conference.will/will";      // 重要 这里要有/后面的
$room_full_jid = new XMPPJid($_room_full_jid);
$client->require_xep(array(
    '0045',     // MUC
    '0203',     // Delayed Delivery
    '0199',  // XMPP Ping
));
$client->add_cb('on_auth_success', function() {
    global $client, $room_full_jid;
    // set status
    $client->set_status("在线",'chat',1);
    $client->get_vcard();               // fetch your vcard
    $client->get_roster();              // fetch your roster list
    JAXLLogger::info("got on_auth_success cb, jid ".$client->full_jid->to_string());
    JAXLLogger::info("got on_auth_success cb, room_full_jid ".$room_full_jid->to_string());
    // join muc room   必须进入房间才能收到消息
    $client->xeps['0045']->join_room($room_full_jid);
    echo "-----------------》";
    //start send message
    //@link http://wiki.jabbercn.org/XEP-0045#.E5.8F.91.E9.80.81.E6.B6.88.E6.81.AF.E7.BB.99.E6.89.80.E6.9C.89.E6.88.BF.E5.AE.A2 例子60的xml格式
    //@link JAXL 文档 https://jaxl.readthedocs.io/en/latest/users/xml_objects.html
    $xml = new JAXLXml('message');
    $_room_full_jid2 = "will@conference.will";
    $to2 = new XMPPJid($_room_full_jid2);
//    $client->subscribed("xiaokang@will");
    $xml->attrs(array(
        'from'=>$client->full_jid->to_string(),
        'to'=>$to2->to_string(),
        'type'=>'groupchat',
    ));
    $xml->c('body')->t('阿萨德111');
    $client->send( $xml); //发送消息
    echo "《-----------------";
    $client->send_end_stream(); //断开连接
});
function on_auth_failure_callback($reason)
{
    echo "-----------------!!";
    global $client;
    $client->send_end_stream();
    JAXLLogger::info("got on_auth_failure cb with reason $reason");
}
$client->add_cb('on_auth_failure', 'on_auth_failure_callback');
function on_disconnect_callback()
{
    JAXLLogger::info("got on_disconnect cb");
}
$client->add_cb('on_disconnect', 'on_disconnect_callback');
$client->start();
项目中自己封装的函数
// 发送
  public function sendMessage($gmWhere, $roomName, $content, $memberID, $memberName)
  {
    $gm = Gm::get($gmWhere);
    $role_token = $this->get_role_token($gm['OpenUDID'], $gm['PlayerID']);
    // dd($role_token, $gm, $roomName, $content, $memberID);
    $client = new JAXL(array(
      'jid' => 'gateway2|'.env('GAME_ID').'|' . $gm['PlayerID'],
      'pass' =>  $role_token,
      'host' => env('CHAT2SERVER_HOST'),
      'port' => env('CHAT2SERVER_PORT'),
      'log_level' => JAXLLogger::DEBUG,
    ));
    $client->require_xep(array(
      '0045',     // MUC
      '0060',
      '0203',     // Delayed Delivery
      '0199'  // XMPP Ping
    ));
    $str = sprintf(
      '{"payloadTypeInString":"text","payloadTypeInEnum":0,"textPayloadValue":{"sourceLanguage":"","content":"%s","contentTranslated":null},"meta":"{\"playerID\":%d,\"playerName\":\"%s\",\"uniqueMessageID\":\"%s\" ,\"memberID\":\"%d\",\"memberName\":\"%s\"}","source":"player","imagePayloadValue":{"mediaURL":"","title":"","titleTranslated":null},"audioPayloadValue":{"mediaURL":"","mediaURLTranslated":null,"content":"","contentTranslated":""},"userDefinedPayloadValue":{"data":""},"videoPayloadValue":{"mediaURL":""}}',
      $content,
      $gm['PlayerID'],
      $gm['Name'],
      $gm['PlayerID'] . '_' . time(),
      $memberID,
      $memberName
    );
    $room_full_jid = new \XMPPJid($roomName . "/" . $gm['Name']);
    $on_auth_success_callback = function () use ($client, $roomName, $room_full_jid, $str) {
      try {
        // 进入房间
        $client->xeps['0045']->join_room($room_full_jid);
        // 向房间发消息
        $xml = new \JAXLXml('message');
        $to2 = new \XMPPJid($roomName);
        $xml->attrs(array(
          'xmlns' =>  "jabber:client",
          'to' => $to2->to_string(),
          'type' => 'groupchat',
          'original_from' => $client->full_jid->to_string(),
          'from' => $client->full_jid->to_string(),
          'send_time' => date('Y-m-d H:i'),
        ));
        $xml->c('body')->t($str);
        $client->send($xml); //发送消息
      } catch (\JAXLException $e) {
        return $this->jsonErrorData(ApiErrDesc::ERR_SEND_XMPP_MSG);
      }
    };
    $client->add_cb('on_auth_success', $on_auth_success_callback);
    $client->start();
    return $this->jsonSuccessData("已发送");
  }