2016-09-01 2 views
1

Попытка понять, как разделить мои данные сеанса между моим приложением и моим чат-сервером (Ratchet). Я думал, что использование Symfony & Memcache будет достаточно простым, но я просто не могу заставить его работать.Разделите сеанс между сервером App и Chat (Symfony & Memcache)

Я пытаюсь получить user_id из сеанса, когда кто-то отправит сообщение в чат, он будет вставлять user_id в базу данных (Chat->onMessage).

Может ли кто-нибудь указать мне в правильном направлении?

Flow:

  1. config.php включен на каждой странице
  2. Когда пользователь регистрируется на сайте он выполняет $login->processLogin() метод
  3. я начинаю мой чат-сервер через командную строку (php server.php)

config.php

<?php 
use MyApp\Login; 
use MyApp\Session as MySession; 

# Define backslash or forward slash for *NIX and IIS systems. 
define('DS', DIRECTORY_SEPARATOR); 
# Attempt to determine the full-server path to the 'root' folder in order to reduce the possibility of path problems. 
define('BASE_PATH', realpath(dirname(__FILE__)).DS); 

# Define the complete path to the root of the domain we are at (ie. /home/user/domain.com) (does't end in a slash) 
define('ROOT_PATH', $_SERVER['DOCUMENT_ROOT']); 
# Define where cookies may be active. ('/' means the entire domain) 
define('COOKIE_PATH', '/'); 
# Name sessions. (needs to be alphanumeric with no periods[.]- can't be solely digits; must contain at least one letter) 
define('SESSIONS_NAME', 'SiteUser'); 

# Get the Session Class. 
require_once BASE_PATH.'modules'.DS.'Session'.DS.'Session.php'; 
# Check if there is a session id set the the $sesh_id variable. 
$sesh_id=((isset($sesh_id)) ? $sesh_id : NULL); 
# Create a new session object, thus starting a new session. 
$mysession=MySession::getInstance(NULL, NULL, NULL, $sesh_id); 

Войти

<?php 
namespace MyApp; 

use Exception; 

# Make sure the script is not accessed directly. 
if(!defined('BASE_PATH')) 
{ 
    exit('No direct script access allowed'); 
} 

# Get the User Class 
require_once BASE_PATH.'modules'.DS.'Login'.DS.'User.php'; 

/** 
* Class Login 
* 
* The Login Class is used to login in and out users as well as checking various login privileges. 
*/ 
class Login extends User 
{ 
    /** 
    * processLogin 
    * 
    * Checks if the Login has been submitted and processes it. 
    * 
    * @access public 
    */ 
    public function processLogin() 
    { 
     if($this->isLoggedIn()===TRUE) 
     { 
      header("location: main.php"); 
      die; 
     } 

     # Check if the form has been submitted. 
     if($_SERVER['REQUEST_METHOD']=='POST') 
     { 
      try 
      { 
       try 
       { 
        $this->setLoginSessions($this->getID(), TRUE); 
        header("location: main.php"); 
       } 
       catch(Exception $e) 
       { 
        throw $e; 
       } 
      } 
      catch(Exception $e) 
      { 
       throw $e; 
      } 
     } 
    } 

    /** 
    * Checks if user is logged in or not. Returns TRUE if logged in, FALSE if not. 
    * 
    * @return bool 
    */ 
    public function isLoggedIn() 
    { 
     global $mysession; 
     $symfony_session=$mysession->symfony_session; 

     //if(!isset($_SESSION['user_logged_in'])) 
     if(!$symfony_session->has('user_id')) 
     { 
      # Check if we have a cookie 
      if(isset($_COOKIE['cookie_id'])) 
      { 
       try 
       { 
        $this->setID($_COOKIE['cookie_id']); 
       } 
       catch(Exception $e) 
       { 
        unset($_COOKIE['user_ip']); 
        unset($_COOKIE['athenticate']); 
        unset($_COOKIE['cookie_id']); 

        return FALSE; 
       } 
      } 
      else 
      { 
       return FALSE; 
      } 
     } 
     //elseif($_SESSION['user_logged_in']===TRUE) 
     if($symfony_session->get('user_logged_in')===TRUE) 
     { 
      return TRUE; 
     } 

     return FALSE; 
    } 

    /** 
    * Sets the login sessions. 
    * 
    * @param null $user_id 
    * @param null $logged_in 
    * @param bool $secure 
    * @throws Exception 
    */ 
    public function setLoginSessions($user_id=NULL, $logged_in=NULL, $secure=FALSE) 
    { 
     global $mysession; 
     $symfony_session=$mysession->symfony_session; 

     # Check if the user is logged in. 
     if($this->isLoggedIn()===TRUE) 
     { 
      if($user_id===NULL) 
      { 
       try 
       { 
        # Get the User's data. 
        $this->findUserData(); 
        $user_id=$this->getID(); 
        $logged_in=TRUE; 
       } 
       catch(Exception $e) 
       { 
        throw $e; 
       } 
      } 
     } 
     $symfony_session->set('user_id', $user_id); 
     $symfony_session->set('user_logged_in', $logged_in); 
     /* 
     # Set the User's login sessions. 
     $_SESSION['user_id']=$user_id; 
     $_SESSION['user_logged_in']=$logged_in; 
     */ 
    } 
} 

Session

<?php 
namespace MyApp; 

use Memcache; 
use Symfony\Component\HttpFoundation\Session\Session as SymfonySession; 
use Symfony\Component\HttpFoundation\Session\Storage\Handler; 
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; 
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcacheSessionHandler; 

/** 
* Class Session 
* 
* The Session class is used to access and manipulate Sessions and data stored in them. 
*/ 
class Session 
{ 
    private static $session; 
    private $message=FALSE; 
    private $sessname=FALSE; 
    public $symfony_session; 

    /** 
    * Session constructor. 
    * 
    * Safely calls session_start(). 
    * Also enables sessions to span sub domains. It names the session (which is necessary for 
    * session_set_cookie_params() to work). If calling this class before setting.php, $sessname (the session name) AND 
    * $cookiepath (the path for cookies) MUST be defined. 
    * 
    * @param null $sessname 
    * @param null $cookiepath 
    * @param bool $secure 
    * @param null $sesh_id 
    */ 
    public function __construct($sessname=NULL, $cookiepath=NULL, $secure=FALSE, $sesh_id=NULL) 
    { 
     require_once BASE_PATH.'vendor'.DS.'autoload.php'; 
     $memcache=new Memcache; 
     $memcache->connect(DOMAIN_NAME, 11211); 
     $storage=new NativeSessionStorage(array(), new Handler\MemcacheSessionHandler($memcache)); 
     $symfony_session=new SymfonySession($storage); 

     # Check if a session ID was passed. 
     if($sesh_id!==NULL) 
     { 
      //session_id($sesh_id); 
      $symfony_session->setId($sesh_id); 
     } 
     # Is a session already started? 
     //if(!isset($_SESSION['s_set'])) 
     if(!$symfony_session->has('s_set')) 
     { 

      # If we haven't been given a session name, we will give it one. 
      if(empty($cookiepath)) 
      { 
       # Set the default cookie path be the root of the site. 
       $cookiepath=DS; 
       # Check if the cookie path was defined in settings.php. 
       if(defined('COOKIE_PATH')) 
       { 
        # Check if the defined path is blank. 
        if(COOKIE_PATH!='') 
        { 
         # If the cookie path has been defined in settings.php, we'll use that path. 
         $cookiepath=COOKIE_PATH; 
        } 
       } 
      } 
      //session_set_cookie_params($life, $cookiepath, '.'.DOMAIN_NAME, $secure); 

      /* 
      * Read the current save path for the session files and append our own directory to this path. 
      * Note: In order to make that platform independent, we need to check for the file-seperator first. 
      * Now we check if the directory already has been created, if not, create one. 
      * Then we set the new path for the session files. 
      */ 
      # Get the session save path. 
      $save_path=session_save_path(); 
      # Find out if our custom_session folder exists. If not, let's make it. 
      if(!is_dir(BASE_PATH.'../custom_sessions'.DS.'.')) 
      { 
       mkdir(BASE_PATH.'../custom_sessions', 0755); 
      } 
      # Is our custom_sessions folder the session save path? If not, let's make it so. 
      if($save_path!==BASE_PATH.'../custom_sessions') 
      { 
       //session_save_path(BASE_PATH.'../custom_sessions'); 

       # How do I set the save path in Symfony? 
      } 

      # If we haven't been given a session name, we will give it one. 
      if(empty($sessname)) 
      { 
       # Set the default session name. 
       $sessname='PHPSESSID'; 
       # Check if the session name was defined in settings.php. 
       if(defined('SESSIONS_NAME')) 
       { 
        # Check if the defined name is blank. 
        if(SESSIONS_NAME!='') 
        { 
         # If the session name has been defined in settings.php, we'll give the session that name. 
         $sessname=SESSIONS_NAME; 
        } 
       } 
      } 
      $storage->setOptions(array(
       'cookie_domain'=>'.'.DOMAIN_NAME, 
       'cookie_lifetime'=>0, 
       'cookie_path'=>$cookiepath, 
       'cookie_secure'=>$secure, 
       'name'=>$sessname 
      )); 
      //$this->setSessname($sessname); 
      # Name the session. 
      //session_name($this->getSessname()); 

      # Session must be started before anything. 
      //session_start(); 
      //$session->setName($this->getSessname()); 
      $symfony_session->start(); 

      # Set the s_set session so we can tell if session_start has been called already. 
      //$_SESSION['s_set']=1; 
      $symfony_session->set('s_set', 1); 
     } 

     $this->symfony_session=$symfony_session; 

     print_r($symfony_session);exit; 
    } 

    /** 
    * getSessname 
    * 
    * Returns the data member $sessname. 
    * 
    * @access public 
    */ 
    public function getSessname() 
    { 
     return $this->sessname; 
    } 

    /** 
    * Sets the data member $sessname. If an empty value is passed, the data member will 
    * be set with FALSE. Returns the set data member value. 
    * 
    * @param $sessname 
    * @return bool 
    */ 
    public function setSessname($sessname) 
    { 
     # Clean it up... 
     $sessname=trim($sessname); 
     # Check if the passed value is now empty. 
     if(empty($sessname)) 
     { 
      # Explicitly set the data member to false. 
      $sessname=FALSE; 
     } 
     # Set the data member. 
     $this->sessname=$sessname; 

     # Return the data member after it has gone through the get method. 
     return $this->getSessname(); 
    } 

    /** 
    * Gets the singleton instance of this class. 
    * 
    * @param null $sessname 
    * @param null $cookiepath 
    * @param bool $secure 
    * @param null $sesh_id 
    * @return Session 
    */ 
    public static function getInstance($sessname=NULL, $cookiepath=NULL, $secure=FALSE, $sesh_id=NULL) 
    { 
     if(!self::$session) 
     { 
      self::$session=new Session($sessname, $cookiepath, $secure, $sesh_id); 
     } 

     return self::$session; 
    } 
} 

server.php

<?php 
use Ratchet\Server\IoServer; 
use Ratchet\Http\HttpServer; 
use Ratchet\WebSocket\WsServer; 
use Ratchet\Session\SessionProvider; 
use Symfony\Component\HttpFoundation\Session\Storage\Handler; 
use MyApp\Chat; 

$port="8080"; 

# Change to this directory. 
chdir(dirname(__FILE__)); 

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

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

$memcache=new Memcache; 
$memcache->connect(DOMAIN_NAME, 11211); 

$session=new SessionProvider(
    new Chat, 
    new Handler\MemcacheSessionHandler($memcache) 
); 

$server=IoServer::factory(
    new HttpServer(
     new WsServer($session) 
    ), 
    $port, 
    DOMAIN_NAME 
); 

$server->run(); 

Чат

<?php 
namespace MyApp; 

use Ratchet\MessageComponentInterface; 
use Ratchet\ConnectionInterface; 

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

    public function onOpen(ConnectionInterface $conn) 
    { 
     # get the cookies 
     $cookies=(string)$conn->WebSocket->request->getHeader('Cookie'); 
     # Returns only PHPSESSID (not SiteUser). 
     //var_dump($cookies);exit; 

     $this->clients[$conn->resourceId]=$conn; 
     echo "New connection! ({$conn->resourceId})\n"; 
    } 

    /** 
    * @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) 
     { 
      require_once BASE_PATH.'vendor'.DS.'autoload.php'; 
      $memcache=new Memcache; 
      $memcache->connect(DOMAIN_NAME, 11211); 
      $storage=new NativeSessionStorage(array(), new Handler\MemcacheSessionHandler($memcache)); 
      $session=new SymfonySession($storage); 

      $type=$data['type']; 
      $user_id=$conn->Session->get('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') 
       { 
        echo 'test 4';exit; 
        $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']); 
      } 
     } 
    } 
} 

ответ

1

Вы не должны фактически разделить эти данные по всем частям вашего приложения.

Если вы откроете учебник по Ratchet, вы найдете информацию о pushServers.

Это позволяет подтолкнуть к определенному channel или $user_id (в вашем случае)

Это делает вас возможность не сохранять или передавать данные в двух частях и облегчит вам иметь рационализировать рабочий процесс.

Лично я использую pushServer в нескольких каналах, они разделены на:

  • Всех пользователей на сайт (sendBroadcast)
  • всех пользователей в группе (sendGroup)
  • Всех пользователей после тега (sendTag)
  • для других пользователей (sendToUser)

Я надеюсь, что это уже дает вам представление о том, как решить ваши проблема, в противном случае не стесняйтесь спрашивать.

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