我使用Redis服务器在Php和Node js之间共享会话。对于Node js客户端使用" connect-redis"并为PHP客户端使用redis-session-php和Predis。我从gist处获取了stack升级版本的大部分代码(来自正确答案)。
app.js
var express = require('express'),
app = express(),
cookieParser = require('cookie-parser'),
session = require('express-session'),
RedisStore = require('connect-redis')(session);
app.use(express.static(__dirname + '/public'));
app.use(function(req, res, next) {
if (~req.url.indexOf('favicon'))
return res.send(404);
next();
});
app.use(cookieParser());
app.use(session({
store: new RedisStore({
// this is the default prefix used by redis-session-php
prefix: 'session:php:'
}),
// use the default PHP session cookie name
name: 'PHPSESSID',
secret: 'node.js rules',
resave: false,
saveUninitialized: false
}));
app.use(function(req, res, next) {
req.session.nodejs = 'Hello from node.js!';
res.send('<pre>' + JSON.stringify(req.session, null, ' ') + '</pre>');
});
app.listen(8080);
app.php
<?php
// this must match the express-session `secret` in your Express app
define('EXPRESS_SECRET', 'node.js rules');
// ==== BEGIN express-session COMPATIBILITY ====
// this id mutator function helps ensure we look up
// the session using the right id
define('REDIS_SESSION_ID_MUTATOR', 'express_mutator');
function express_mutator($id) {
if (substr($id, 0, 2) === "s:")
$id = substr($id, 2);
$dot_pos = strpos($id, ".");
if ($dot_pos !== false) {
$hmac_in = substr($id, $dot_pos + 1);
$id = substr($id, 0, $dot_pos);
}
return $id;
}
// check for existing express-session cookie ...
$sess_name = session_name();
if (isset($_COOKIE[$sess_name])) {
// here we have to manipulate the cookie data in order for
// the lookup in redis to work correctly
// since express-session forces signed cookies now, we have
// to deal with that here ...
if (substr($_COOKIE[$sess_name], 0, 2) === "s:")
$_COOKIE[$sess_name] = substr($_COOKIE[$sess_name], 2);
$dot_pos = strpos($_COOKIE[$sess_name], ".");
if ($dot_pos !== false) {
$hmac_in = substr($_COOKIE[$sess_name], $dot_pos + 1);
$_COOKIE[$sess_name] = substr($_COOKIE[$sess_name], 0, $dot_pos);
// https://github.com/tj/node-cookie-signature/blob/0aa4ec2fffa29753efe7661ef9fe7f8e5f0f4843/index.js#L20-L23
$hmac_calc = str_replace("=", "", base64_encode(hash_hmac('sha256', $_COOKIE[$sess_name], EXPRESS_SECRET, true)));
if ($hmac_calc !== $hmac_in) {
// the cookie data has been tampered with, you can decide
// how you want to handle this. for this example we will
// just ignore the cookie and generate a new session ...
unset($_COOKIE[$sess_name]);
}
}
} else {
// let PHP generate us a new id
session_regenerate_id();
$sess_id = session_id();
$hmac = str_replace("=", "", base64_encode(hash_hmac('sha256', $sess_id, EXPRESS_SECRET, true)));
// format it according to the express-session signed cookie format
session_id("s:$sess_id.$hmac");
}
// ==== END express-session COMPATIBILITY ====
require('redis-session-php/redis-session.php');
RedisSession::start();
$_SESSION["php"] = "Hello from PHP";
if (!isset($_SESSION["cookie"]))
$_SESSION["cookie"] = array();
echo "<pre>";
echo json_encode($_COOKIE, JSON_PRETTY_PRINT);
echo json_encode($_SESSION, JSON_PRETTY_PRINT);
echo "</pre>";
?>
问题在于:首次执行&#34; php文件&#34;然后执行&#34;节点js服务器页面&#34; - &#34;节点js服务器页面&#34;没有看到来自&#34; php文件&#34;的会话创建。反之亦然(首先执行&#34;节点js服务器页面&#34;然后执行&#34; php文件&#34;)会话变量已在两个页面中看到
结果app.php
[]{
"php": "Hello from PHP",
"cookie": []
}
结果节点js页面(http://127.0.0.1:8080)
{
"cookie": {
"originalMaxAge": null,
"expires": null,
"httpOnly": true,
"path": "/"
},
"nodejs": "Hello from node.js!"
}
答案 0 :(得分:1)
您可能面临跨域问题。如果您在与PHP不同的地址或端口中运行PHP和Node(可能是您),则HTML不会在转到其他域的请求之间共享Cookie,它会将分隔的副本保留到每个域。
如果您正在使用子域(例如,您的PHP在app1.mydomain.com等URL中运行,而您的NodeJS在app2.mydomain.com中运行),您可以共享您的cookie,使用main来设置/读取它们域cookie路径(mydomain.com)。
这里有关于这个主题的很好的信息:
Using Express and Node, how to maintain a Session across subdomains/hostheaders
如果您需要更多信息或者您的问题不是那个问题,请告诉我们。
答案 1 :(得分:1)
我从这篇文章中解决了这个问题:PHP and Node.JS session share using Redis
app.js
var app = require("http").createServer(handler),
fs = require("fs"),
redis = require("redis"),
co = require("./cookie.js");
app.listen(443);
//On client incomming, we send back index.html
function handler(req, res) {
//Using php session to retrieve important data from user
var cookieManager = new co.cookie(req.headers.cookie);
//Note : to specify host and port : new redis.createClient(HOST, PORT, options)
//For default version, you don't need to specify host and port, it will use default one
var clientSession = new redis.createClient();
console.log('cookieManager.get("PHPSESSID") = ' + cookieManager.get("PHPSESSID"));
clientSession.get("sessions/" + cookieManager.get("PHPSESSID"), function(error, result) {
console.log("error : " + result);
if(error) {
console.log("error : " + error);
}
if(result != null) {
console.log("result exist");
console.log(result.toString());
} else {
console.log("session does not exist");
}
});
//clientSession.set("sessions/" + cookieManager.get("PHPSESSID"), '{"selfId":"salamlar22", "nodejs":"salamlar33"}');
}
cookie.js
//Directly send cookie to system, if it's node.js handler, send :
//request.headers.cookie
//If it's socket.io cookie, send :
//client.request.headers.cookie
module.exports.cookie = function(co){
this.cookies = {};
co && co.split(';').forEach(function(cookie){
var parts = cookie.split('=');
this.cookies[parts[0].trim()] = (parts[1] || '').trim();
}.bind(this));
//Retrieve all cookies available
this.list = function(){
return this.cookies;
};
//Retrieve a key/value pair
this.get = function(key){
if(this.cookies[key]){
return this.cookies[key];
}else{
return {};
}
};
//Retrieve a list of key/value pair
this.getList = function(map){
var cookieRet = {};
for(var i=0; i<map.length; i++){
if(this.cookies[map[i]]){
cookieRet[map[i]] = this.cookies[map[i]];
}
}
return cookieRet;
};
};
app.php
<?php
include 'redis.php';
session_start();
echo '<pre>';
var_dump($_COOKIE);
echo '</pre>';
echo '$_SESSION["nodejs"] = '.$_SESSION[selfId].'<br>';
$_SESSION[selfId] = 2;
echo '$_SESSION["nodejs"] = '.$_SESSION[selfId].'<br>';
?>
redis.php
<?php
//First we load the Predis autoloader
//echo dirname(__FILE__)."/predis-1.0/src/Autoloader.php";
require(dirname(__FILE__)."/redis-session-php/modules/predis/src/Autoloader.php");
//Registering Predis system
Predis\Autoloader::register();
/**
* redisSessionHandler class
* @class redisSessionHandler
* @file redisSessionHandler.class.php
* @brief This class is used to store session data with redis, it store in json the session to be used more easily in Node.JS
* @version 0.1
* @date 2012-04-11
* @author deisss
* @licence LGPLv3
*
* This class is used to store session data with redis, it store in json the session to be used more easily in Node.JS
*/
class redisSessionHandler{
private $host = "127.0.0.1";
private $port = 6379;
private $lifetime = 0;
private $redis = null;
/**
* Constructor
*/
public function __construct(){
$this->redis = new Predis\Client(array(
"scheme" => "tcp",
"host" => $this->host,
"port" => $this->port
));
session_set_save_handler(
array(&$this, "open"),
array(&$this, "close"),
array(&$this, "read"),
array(&$this, "write"),
array(&$this, "destroy"),
array(&$this, "gc")
);
}
/**
* Destructor
*/
public function __destruct(){
session_write_close();
$this->redis->disconnect();
}
/**
* Open the session handler, set the lifetime ot session.gc_maxlifetime
* @return boolean True if everything succeed
*/
public function open(){
$this->lifetime = ini_get('session.gc_maxlifetime');
return true;
}
/**
* Read the id
* @param string $id The SESSID to search for
* @return string The session saved previously
*/
public function read($id){
$tmp = $_SESSION;
$_SESSION = json_decode($this->redis->get("sessions/{$id}"), true);
if(isset($_SESSION) && !empty($_SESSION) && $_SESSION != null){
$new_data = session_encode();
$_SESSION = $tmp;
return $new_data;
}else{
return "";
}
}
/**
* Write the session data, convert to json before storing
* @param string $id The SESSID to save
* @param string $data The data to store, already serialized by PHP
* @return boolean True if redis was able to write the session data
*/
public function write($id, $data){
$tmp = $_SESSION;
session_decode($data);
$new_data = $_SESSION;
$_SESSION = $tmp;
$this->redis->set("sessions/{$id}", json_encode($new_data));
$this->redis->expire("sessions/{$id}", $this->lifetime);
return true;
}
/**
* Delete object in session
* @param string $id The SESSID to delete
* @return boolean True if redis was able delete session data
*/
public function destroy($id){
return $this->redis->delete("sessions/{$id}");
}
/**
* Close gc
* @return boolean Always true
*/
public function gc(){
return true;
}
/**
* Close session
* @return boolean Always true
*/
public function close(){
return true;
}
}
new redisSessionHandler();
?>