[英]How can I use legacy sessions ($_SESSION) with symfony sessions in Ratchet websocket application
好吧,讓我首先說我不是框架的忠實擁護者。 我已經使用舊版會話(login.php)開發了我的應用程序:
<?php
$_SESSION{'user_type'} = 'u';
$_SESSION{'id'} = $q[0]['id'];
$_SESSION{'email'} = $q[0]['email'];
$_SESSION{'username'} = $q[0]['username'];
$_SESSION{'firstname'} = $q[0]['firstname'];
$_SESSION{'lastname'} = $q[0]['lastname'];
$_SESSION{'about_me'} = $q[0]['about_me'];
$_SESSION{'gender'} = $q[0]['gender'];
現在,這可以正常工作,用戶可以登錄並訪問其個人資料,但是現在我正在嘗試實現websocket。 所有教程僅向您展示如何在沒有會話的情況下實現它,但是我想實現一個通知系統,當一個用戶做某事(例如添加另一家公司發布的商品)時,我希望該特定公司得到通知。 這是我在實現websockets(server.php)時在終端上運行的代碼:
<?php
require 'vendor/autoload.php';
require 'include/connect.php';
include 'models/Notify.php';
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\Session\SessionProvider;
//use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\PhpBridgeSessionStorage;
use Ratchet\App;
use Notify\Notification;
try{
$domain = '127.0.0.1';
$storage = new PhpBridgeSessionStorage();
$session = new Session($storage);
$session->migrate();
$server = IoServer::factory(
new HttpServer(
new SessionProvider(
new WsServer(
new Notification
),
new \SessionHandler
)
),
3002,
$domain
);
$server->run();
}catch(Exception $e){
echo "Error: {$e->getMessage()}";
}
當我嘗試訪問會話變量時,會話為空。 在使用PhpBridgeSessionStorage
https://symfony.com/doc/current/session/php_bridge.html時,我遵循了symfony的文檔,但是不清楚。 這是我在Notification
類(Notify.php)中使用的代碼:
<?php
namespace Notify;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\PhpBridgeSessionStorage;
class Notification implements MessageComponentInterface{
protected $clients;
private $users;
function __construct(){
$this->clients = new \SplObjectStorage;
$this->users = [];
}
public function onOpen(ConnectionInterface $conn){
echo "Connected ({$conn->resourceId})\n";
//$conn->Session->start();
var_dump($conn->Session->all());
}
public function onMessage(ConnectionInterface $from, $msg){
//echo "$msg [{$from->Session->get('username')}]\n";
}
public function onClose(ConnectionInterface $conn){
echo "\nConnection Closed ({$conn->resourceId})\n";
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e){
}
}
當我在終端上輸出$conn->Session->all()
時,我得到一個警告PHP Warning: SessionHandler::open(): Session is not active
並帶有空數組,當我將$_SESSION
輸出到終端時,我得到了:
array(3) {
["_sf2_attributes"]=>
&array(0) {
}
["_symfony_flashes"]=>
&array(0) {
}
["_sf2_meta"]=>
&array(3) {
["u"]=>
int(1518882401)
["c"]=>
int(1518882401)
["l"]=>
string(1) "0"
}
}
我越來越沒有會話數據,我已經使用其他會話處理程序就像試圖MemcacheSessionHandler, MemcachedSessionHandler, PdoSessionHandler
但他們都離開了會議空的,我試過其他存儲類,但symfony的文檔建議使用PhpBridgeSessionStorage
當你想傳統的會話與集成symfony會議。
我知道那里有用於推送通知的框架,但是我不想使用它們的第三方服務。
我已經研究了好幾天,但找不到任何有用的東西。
如果您不喜歡像我這樣的框架,那么我猜這個答案可以幫助您。 實際上,我找不到關於如何在WebSocket上將Symfony會話與舊版會話($ _SESSION)結合使用的良好文檔。 大多數教程和主題建議僅在整個應用程序中使用Symfony會話。但是,如果您像我一樣並且已經在大多數應用中使用了舊式會話,則可以嘗試這種替代方法。
擺脫您的symfony會話代碼和棘輪會話提供程序,這就是我的server.php現在的樣子:
<?php
require 'vendor/autoload.php';
require 'include/connect.php';
include 'models/Notify.php';
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\App;
use Notify\Notification;
try{
$domain = '127.0.0.1';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Notification
)
),
3002,
$domain
);
$server->run();
}catch(Exception $e){
echo "Error: {$e->getMessage()}";
}
接下來需要做的是,每當客戶端連接到WebSocket服務器時,就需要獲取其PHPSESSID。 您可以在我的案例Notification類中從您的應用程序類中的連接對象獲取。 執行$conn->httpRequest->getHeader('Cookie')
將返回一個cookie數組,因此,您需要編寫代碼來循環並獲取PHPSESSID,如下所示:
function getPHPSESSID(array $cookies){
foreach($cookies as $cookie):
if(strpos($cookie, "PHPSESSID") == 0):
$sess_id = explode('=', $cookie)[1];
break;
endif;
endforeach;
return $sess_id;
}
有了它后,您可以使用它通過設置會話ID session_id($sessid)
來在websocket服務器上設置會話,但是為了避免我遇到的麻煩,我建議您在用戶登錄后將PHPSESSID存儲在數據庫中。 ..該ID應該是唯一的,為防止沖突,請不要使用session_regenerate_id()
,而應使用session_create_id()
。 因此,在WebSocket服務器上,您將運行查詢以獲取具有PHPSESSID的用戶的信息。 我建議像執行此操作那樣創建Session類:
<?php
namespace Library;
class _Session {
private $sess_id;
private $session;
public function __construct(array $cookies){
include 'include/connect.php';
foreach($cookies as $cookie):
if(strpos($cookie, "PHPSESSID") == 0):
$this->sess_id = explode('=', $cookie)[1];
break;
endif;
endforeach;
$query = "SELECT * FROM general_user WHERE sess_id = ?";
$query_run = $database->prepare($query);
if($query_run->execute([$this->sess_id])):
if($query_run->rowCount() == 1):
$query = "SELECT g.id, g.email, u.username, u.firstname, u.lastname, g.about_me, u.gender, p.name AS profile_pic, 'u' AS user_type FROM general_user g INNER JOIN userdata u ON u.id = g.id LEFT JOIN profile_photo p ON g.id = p.user_id WHERE sess_id = ?";
$query_run = $database->prepare($query);
if($query_run->execute([$this->sess_id])):
if($query_run->rowCount() == 0):
$query = "SELECT g.id, g.email, g.about_me AS company_description, c.category, c.subcategory, c.company_name, c.contact_num, c.website, p.name AS profile_pic, 'c' AS user_type FROM general_user g INNER JOIN companydata c ON c.id = g.id LEFT JOIN profile_photo p ON g.id = p.user_id WHERE sess_id = ?";
$query_run = $database->prepare($query);
if($query_run->execute([$this->sess_id])):
$this->session = $query_run->fetchAll()[0];
endif;
else:
$this->session = $query_run->fetchAll()[0];
endif;
endif;
else:
$this->session = [];
endif;
endif;
}
function get($key){
foreach($this->session as $k => $value)
if($key == $k)
return $value;
throw new \Exception("Undefined index $key");
}
}
因此,在您提供的“ Cookie”數組中,當您在應用類中創建會話對象時,您將獲得有關登錄用戶的信息:
<?php
namespace Notify;
require __DIR__.'/../vendor/autoload.php';
include __DIR__.'/../classes/CustomSession.php';
use Library\_Session;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\PhpBridgeSessionStorage;
class Notification implements MessageComponentInterface{
protected $clients;
function __construct(){
$this->clients = [];
echo "WebSocket Server Running...\n";
}
public function onOpen(ConnectionInterface $conn){
$session = new _Session($conn->httpRequest->getHeader('Cookie'));//My custom session
if($session->get('user_type') == 'u'){
echo $session->get('username')." has connected\n";
}else{
echo $session->get('company_name')." has connected\n";
}
array_push($this->clients, ['connection' => $conn, 'session'=> $session]);
}
}
對於具有舊式會話的Symfony會話,這是我能想到的最佳選擇。 隨意問的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.