2016-08-29 1 views
1

У меня есть чат для работы, но у меня есть жесткий код ID пользователя в Chat.php.Как добавить пользователя в чат с веб-чатом

Мой логин установлен в их электронной почте на сеанс ($_SESSION['email']=$email;), когда они заходят на сайт.

Я могу поместить скрытое поле в форме чата с их идентификатором и передать его в Chat.php, но я думаю, что есть лучший способ.

Отказ от ответственности: Я знаю, что он не очень хорошо кодируется, я просто хочу изучить его, заставить его работать, а затем лучше его кодировать.

chat_box.php

<?php 
echo '<div id="chatbox" class="nav chatbox">', 
    '<div class="chatbox-1">', 
    '</div>', 
    '<div id="send_chat" class="send_chat">', 
     '<input type="text" class="text" id="chatsay" name="chatsay" maxlength="200" autocomplete="off">', 
     '<button class="submit-chatsend" id="chatsend">Send</button>', 
    '</div>', 
'</div>'; 

JS

window.connect = function() { 
    window.ws = $.websocket("ws://domain.com:8080/", { 
     open: function() { 
     }, 
     close: function() { 
     }, 
     events: { 
      fetch: function (e) { 
      }, 
      single: function (e) { 
       var elem = e.data; 

       if (elem.type == "text") { 
        var html = "<div class='msg' id='" + elem.id + "'><div class='name'>" + elem.name + "</div><div class='msgc'>" + elem.msg.linkify() + "<div class='posted'><time class='timeago' datetime='" + elem.posted + "'>" + elem.posted + "</time></div></div></div>"; 

        if (typeof elem.append != "undefined") { 
         $(".msg:last").remove(); 
        } 

        if (typeof elem.earlier_msg == "undefined") { 
         $(".chatbox .chatbox-1").append(html); 
         $.scrollToBottom(); 
        } 
        else { 
         $(".chatbox .chatbox-1 #load_earlier_messages").remove(); 
         $(".chatbox .chatbox-1 .msg:first").before(html); 
        } 
       } 
       else if (elem.type == "more_messages") { 
        $(".chatbox .chatbox-1 .msg:first").before("<a id='load_earlier_messages'>Load Earlier Messages...</a>"); 
       } 
       $("time.timeago").timeago(); 
      } 
     } 
    }); 
}; 
$(document).ready(function() { 
    connect(); 

    $(document).on("click", "#load_earlier_messages", function() { 
     ws.send("fetch", {"id": $(".msg:first").attr("id")}); 
    }); 

    $('#chatsend').click(function() { //use clicks message send button 
     var chatsay_val = $('#chatsay').val(); //get message text 
     if (chatsay_val != "") { 
      ws.send("send", {"type": "text", "msg": chatsay_val}); 
      $('#chatsay').val(''); //reset text 
     } 
    }); 
}); 

Chat.php

<?php 
namespace MyApp; 

use DateTime; 
use DateTimeZone; 
use Exception; 
use PDO; 
use Ratchet\MessageComponentInterface; 
use Ratchet\ConnectionInterface; 

class Chat implements MessageComponentInterface 
{ 
    protected $clients=array(); 
    private $dbh; 

    /** 
    * Chat constructor. 
    */ 
    public function __construct() 
    { 
     global $db_host; 
     global $db_username; 
     global $db_password; 
     global $db; 
     require_once BASE_PATH.'modules'.DS.'Database'.DS.'Database.php'; 
     $database=new Database($db_host, $db, $db_username, $db_password); 
     $this->dbh=$database; 
    } 

    /** 
    * @param ConnectionInterface $conn 
    */ 
    public function onOpen(ConnectionInterface $conn) 
    { 
     $this->clients[$conn->resourceId]=$conn; 
     echo "New connection! ({$conn->resourceId})\n"; 
     $this->fetchMessages($conn); 
    } 

    /** 
    * @param ConnectionInterface $conn 
    * @param int /null $id 
    */ 
    public function fetchMessages(ConnectionInterface $conn, $id=NULL) 
    { 
     $database=$this->dbh; 

     if($id===NULL) 
     { 
      $database->query('SELECT * FROM `chat` ORDER BY `id` ASC', array()); 
      $msgs=$database->statement->fetchAll(PDO::FETCH_ASSOC); 
      $msgCount=$database->count(); 

      if($msgCount>0) 
      { 
       # If more then 5 chat messages... 
       if($msgCount>5) 
       { 
        # Extract a slice of the array. 
        $msgs=array_slice($msgs, $msgCount-5, $msgCount); 
       } 

       foreach($msgs as $msg) 
       { 
        $date=new DateTime($msg['posted']); 
        $date->setTimezone(new DateTimeZone(TIMEZONE)); 

        $user=SearchUser($msg['user_id']); 

        $return=array(
         "id"=>$msg['id'], 
         "name"=>$user['staffname'], 
         "type"=>$msg['type'], 
         "msg"=>$msg['msg'], 
         "posted"=>$date->format("Y-m-d H:i:sP") 
        ); 
        $this->send($conn, "single", $return); 
       } 
       if($msgCount>5) 
       { 
        $this->send($conn, "single", array(
         "type"=>"more_messages" 
        )); 
       } 
      } 
     } 
     else 
     { 
      $database->query('SELECT * FROM `chat` WHERE `id` < :id ORDER BY `id` DESC LIMIT 10', array(':id'=>$id)); 
      $msgs=$database->statement->fetchAll(PDO::FETCH_ASSOC); 
      $msgCount=$database->count(); 

      if($msgCount>0) 
      { 
       foreach($msgs as $msg) 
       { 
        $date=new DateTime($msg['posted']); 
        $date->setTimezone(new DateTimeZone(TIMEZONE)); 

        $user=SearchUser($msg['user_id']); 

        $return=array(
         "id"=>$msg['id'], 
         "name"=>$user['staffname'], 
         "type"=>$msg['type'], 
         "msg"=>$msg['msg'], 
         "posted"=>$date->format("Y-m-d H:i:sP"), 
         "earlier_msg"=>TRUE 
        ); 
        $this->send($conn, "single", $return); 
       } 

       sort($msgs); 
       $firstID=$msgs[0]['id']; 
       if($firstID!="1") 
       { 
        $this->send($conn, "single", array(
         "type"=>"more_messages" 
        )); 
       } 
      } 
     } 
    } 

    /** 
    * @param ConnectionInterface $client 
    * @param $type 
    * @param $data 
    */ 
    public function send(ConnectionInterface $client, $type, $data) 
    { 
     $send=array(
      "type"=>$type, 
      "data"=>$data 
     ); 
     $send=json_encode($send, TRUE); 
     $client->send($send); 
    } 

    /** 
    * @param ConnectionInterface $conn 
    * @param string $data 
    */ 
    public function onMessage(ConnectionInterface $conn, $data) 
    { 
     $database=$this->dbh; 

     $data=json_decode($data, TRUE); 

     if(isset($data['data']) && count($data['data'])!=0) 
     { 
      $type=$data['type']; 
      # How can I get the user's ID? 
      $user_id=1; 
      $user_name=SearchUser($user_id); 

      $return=NULL; 

      if($type=="send" && isset($data['data']['type']) && $user_name!=-1) 
      { 
       $msg=htmlspecialchars($data['data']['msg']); 
       $date=new DateTime; 
       $date->setTimezone(new DateTimeZone(TIMEZONE)); 

       if($data['data']['type']=='text') 
       { 
        $database->query('SELECT `id`, `user_id`, `msg`, `type` FROM `chat` ORDER BY `id` DESC LIMIT 1', array()); 
        $lastMsg=$database->statement->fetch(PDO::FETCH_OBJ); 

        if($lastMsg->user_id==$user_id && (strlen($lastMsg->msg)<=100 || strlen($lastMsg->msg)+strlen($msg)<=100)) 
        { 
         # Append message. 
         $msg=$lastMsg->msg."<br/>".$msg; 

         $database->query('UPDATE `chat` SET `msg`=:msg, `posted`=NOW() WHERE `id`=:lastmsg', array(
          ':msg'=>$msg, 
          ':lastmsg'=>$lastMsg->id 
         )); 

         $return=array(
          "id"=>$lastMsg->id, 
          "name"=>$user_name['staffname'], 
          "type"=>"text", 
          "msg"=>$msg, 
          "posted"=>$date->format("Y-m-d H:i:sP"), 
          "append"=>TRUE 
         ); 
        } 
        else 
        { 
         $database->query('INSERT INTO `chat` (`user_id`, `msg`, `type`, `posted`) VALUES (?, ?, "text", NOW())', array(
          $user_id, 
          $msg 
         )); 

         # Get last insert ID. 
         $get_chat_id=$database->lastInsertId(); 
         $return=array(
          "id"=>$get_chat_id, 
          "name"=>$user_name['staffname'], 
          "type"=>"text", 
          "msg"=>$msg, 
          "posted"=>$date->format("Y-m-d H:i:sP") 
         ); 
        } 
       } 

       foreach($this->clients as $client) 
       { 
        $this->send($client, "single", $return); 
       } 
      } 
      elseif($type=="fetch") 
      { 
       # Fetch previous messages. 
       $this->fetchMessages($conn, $data['data']['id']); 
      } 
     } 
    } 

    /** 
    * @param ConnectionInterface $conn 
    */ 
    public function onClose(ConnectionInterface $conn) 
    { 
     # The connection is closed, remove it, as we can no longer send it messages. 
     unset($this->clients[$conn->resourceId]); 
     echo "Connection {$conn->resourceId} has disconnected\n"; 
    } 

    /** 
    * @param ConnectionInterface $conn 
    * @param Exception $e 
    */ 
    public function onError(ConnectionInterface $conn, Exception $e) 
    { 
     echo "An error has occurred: {$e->getMessage()}\n"; 
     $conn->close(); 
    } 
} 

start_server.php (запуск сервера с помощью командной строки: PHP start_server.php)

<?php 
# Need this for the database insert. 
if(!defined('DOMAIN_NAME')) 
{ 
    define('DOMAIN_NAME', 'domain.com'); 
} 
require_once 'includes/config.php'; 
include_once BASE_PATH.'modules'.DS.'WS'.DS.'server.php'; 

server.php

<?php 

use Ratchet\Server\IoServer; 
use Ratchet\Http\HttpServer; 
use Ratchet\WebSocket\WsServer; 
use MyApp\Chat; 

$ip="domain.com"; 
$port="8080"; 

# Need this for the database insert. 
if(!defined('DOMAIN_NAME')) 
{ 
    define('DOMAIN_NAME', $ip); 
} 

require_once '../../vendor/autoload.php'; 

$server = IoServer::factory(
    new HttpServer(
     new WsServer(
      new Chat() 
     ) 
    ), 
    $port, 
    $ip 
); 

$server->run(); 

Вот мой метод methodToGetSessionData(), как @Sherif предложил

/** 
* @param $sessionId 
* @return mixed 
*/ 
private function methodToGetSessionData($sessionId) 
{ 
    if(file_exists(session_save_path().'/sess_'.$sessionId)) 
    { 
     $file=session_save_path().'/sess_'.$sessionId; 
    } 
    else 
    { 
     $file=sys_get_temp_dir().'/sess_'.$sessionId; 
    } 
    $contents=file_get_contents($file); 
    session_decode($contents); 

    return $_SESSION; 
} 
+0

websocket и веб-интерфейс полностью независимы друг от друга. то, что вы делаете, в основном, является единственным способом связать их вместе. веб-интерфейс получает какой-то уникальный идентификатор, а затем он проходит через websocket обратно на сервер, поэтому соединение сокета может быть связано с интерфейсом. –

ответ

1

Просто используйте сеанс, как вы уже делаете. В вашем методе onOpen$conn имеет начальный HTTP-запрос как объект GuzzleHttp. Вы можете извлечь куки-файл сеанса из этого и прочитать в сеансе на ваш сервер websocket.

public function onOpen(ConnectionInterface $conn) 
{ 
    // get the cookies 
    $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! 
    } 

    // Extract the session data using the session id from the cookie 
    $conn->session = $this->methodToGetSessionData($sessionId); 

    // now you have access to things in the session 
    $this->clinets[] = $conn; 
} 

В зависимости от того, как вы храните сессии на своем сайте с PHP вы должны реализовать метод methodToGetSessionData, чтобы иметь возможность читать из этой сессии магазина и десериализации данных. Оттуда у вас будет доступ к чему-либо, хранящемуся в сеансе, через $conn->session или $client->session на вашем сервере веб-сервера.

Как правило, если вы используете хранилище на основе файлов по умолчанию на PHP, достаточно просто просто прочитать файл сеанса с вашего session.storage_path и неэтериализовать его. Я думаю, что Ratchet предлагает некоторые компоненты сеанса для таких вещей, как Redis/Memcached, которые вы можете легко ввести в свое приложение для веб-приложений.

+0

Не могу заставить это работать. Я получаю '$ cookies', но не могу прочитать данные сеанса. – Draven

+0

Я получаю «не удалось открыть поток: Permission denied» в файле сеанса. Я поместил метод methodToGetSessionData() в мой вопрос. – Draven

+0

Хорошо, потому что пользователь, который запускает ваш PHP с вашего веб-сервера, может быть не тем же пользователем, с которого вы работаете на сервере websocket, вам нужно убедиться, что у обоих пользователей есть разрешения на эти файлы сеанса. – Sherif

Смежные вопросы