好的,让我先说我不是框架的忠实粉丝。我已经使用旧会话 (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'];
现在这一切正常,用户可以登录并访问他们的个人资料,但现在我正在尝试实现 websockets。所有教程都只是向您展示如何在没有会话的情况下实现它,但我想实现一个通知系统,当一个用户做了某事(例如添加另一家公司发布的项目)时,我希望通知该特定公司。这是我在实现 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 上使用带有遗留会话($_SESSION)的 Symfony 会话的好的文档。大多数教程和线程都建议在整个应用程序中只使用 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 来使用它在 websocket 服务器上设置会话,session_id($sessid)
但为了避免我在这样做时遇到的问题,我建议你在用户登录后将 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 会话提出的最佳替代方案。随意问的问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句