棘轮PHP Websockets:私人消息(控制谁发送消息)

时间:2016-08-11 16:40:13

标签: javascript php jquery websocket ratchet

还有一个问题。 我开始习惯websocket如何工作。 我甚至设法实现了跨域通信。 但现在我还没有达到另一个里程碑。

以下是我当前实现的片段

 public function onMessage(ConnectionInterface $conn, $msg)
{
     $msgjson = json_decode($msg);
     $tag = $msgjson->tag;
     global $users; 

     if($tag == "[msgsend]")
     {

            foreach($this->clients as $client)
            {
                  $client->send($msg);    
            }
     }
     else if($tag == "[bye]")
     {

         foreach($this->clients as $client)
         {
              $client->send($msg);    
         }

         foreach($users as $key => $user)
         {
             if($user->name == $msgjson->uname)
             {
                unset($users[$key]); 
             }
         }

         $this->clients->detach($conn);
     }
     else if($tag == "[connected]")
     {
         //store client information
         $temp = new Users();
         $temp->name = $msgjson->uname;
         $temp->connection = $conn;
         $temp->timestamp = new \DateTime();



         $users[] = $temp;





          usort($users, array($this, "cmp"));


         //send out messages
          foreach($this->clients as $client)
         {
              $client->send($msg);    
         }           

     }
     else if($tag == "[imalive]")
     {
         //update user timestamp who sent [imalive]
         global $users;

          foreach($users as $user)
             {
                if($msgjson->uname == $user->name)
                {
                        $user->timestamp = new \DateTime(); 
                }
             }

     }   

}

现在我的问题是。正如我们所看到的,在onMessage()函数和我已完成的教程中,我知道如何读取和解析JSON数据,理解消息,告诉消息来自谁($ conn).....

但是当我在JSON数据包中发送消息时,我想要包含消息来自的昵称以及消息的来源。 这将允许我在我正在构建的社交网络和聊天室中实现私人即时消息。

我只想将消息发送到特定的客户端,而不是for循环向所有连接的客户端发送消息。我知道客户有一个属性($ this-> $ client-> resourceID或类似的东西),但不知道如何将其作为解决方案合并。我还希望用户在跳转到网站上的不同页面时保持连接,即使刷新后仍然可以继续发送消息。我假设每次刷新都会断开客户端的连接。因此,我必须有一种方法,服务器可以告诉每次消息来自谁以及他们将去往何处。

但是,私信。我不想向所有人或非预期目标发送不必要的消息。我怎么能做到这一点? 我希望我的问题有道理。感谢。

1 个答案:

答案 0 :(得分:3)

能够唯一地识别连接到WebSocket服务器然后能够定位这些用户的用户,特别是在发送消息时需要从onOpen回调开始,其中实际与服务器协商连接

onOpen方法中,您应该通过一些全局存储在数据库或持久性存储中的用户ID,以某种方式唯一地识别系统上的用户。由于通过HTTP协商连接,因此您可以通过$conn->WebSocket->request访问HTTP请求,GuzzleHttp是包含客户端HTTP请求信息的$client对象。例如,您可以使用它来提取一个cookie,其中包含一些用户ID数据或令牌,您可以将其与数据库进行比较以确定用户是谁,然后将其存储为PHPSESSID对象的属性。 / p>

现在,让我们假装您正在编写一个普通的PHP脚本,您可以通过HTTP进行用户身份验证,并将用户ID存储在会话中。此会话在客户端的计算机上设置cookie(默认情况下,cookie名称是会话名称,通常为PHPSESSID,除非您更改)包含会话ID。此会话ID可以在WebSocket服务器中用于访问会话存储,就像在PHP中一样。

这是一个简单的示例,我们希望请求中的public function onOpen(ConnectionInterface $conn) { // extract the cookie header from the HTTP request as a string $cookies = (string) $conn->WebSocket->request->getHeader('Cookie'); // look at each cookie to find the one you expect $cookies = array_map('trim', explode(';', $cookies)); $sessionId = null; foreach($cookies as $cookie) { // If the string is empty keep going if (!strlen($cookie)) { continue; } // Otherwise, let's get the cookie name and value list($cookieName, $cookieValue) = explode('=', $cookie, 2) + [null, null]; // If either are empty, something went wrong, we'll fail silently here if (!strlen($cookieName) || !strlen($cookieValue)) { continue; } // If it's not the cookie we're looking for keep going if ($cookieName !== "PHPSESSID") { continue; } // If we've gotten this far we have the session id $sessionId = urldecode($cookieValue); break; } // If we got here and $sessionId is still null, then the user isn't logged in if (!$sessionId) { return $conn->close(); // close the connection - no session! } } cookie从cookie中捕获会话ID。

$sessionId

现在您实际拥有$conn可以使用它来访问该会话的会话存储,将会话信息提取到WebSocket服务器并将其存储为客户端连接对象的属性{{1} }。

继续上面的示例,我们将此代码添加到onOpen方法。

public function onOpen(ConnectionInterface $conn) {
    $conn->session = $this->methodToGetSessionData($sessionId);
    // now you have access to things in the session
    $this->clinets[] = $conn;
}

现在,让我们回到您想要专门向一个用户发送消息的示例。假设我们在会话中存储了以下属性,现在可以从客户端连接对象中访问...

$conn->session->userName = 'Bob';
$conn->session->userId   = 1;

所以让我们说Bob希望向Jane发送消息。请求以{"from":1,"to":2,tag:"[msgsend]"}之类的内容进入您的WS服务器,其中该JSON的tofrom属性基本上是消息来自的用户的用户ID 和用户将消息分别发送到。我们假设Jane是userId = 2这个例子。

public function onMessage(ConnectionInterface $conn, $msg) {
    $msgjson = json_decode($msg);
    $tag = $msgjson->tag;
    if ($tag == '[msgsend]') {
        foreach($this->clients as $client) {
            // only send to the designated recipient user id
            if ($msgjson->to == $client->session->userId) {
                $client->send($msg);    
            }
        }
    }
}

显然你可能希望在那里进行更详细的验证,但是你应该可以从这里进行扩展。