1

I use Redis server for sharing session between Php and Node js. For Node js client use "connect-redis" and for php client use redis-session-php and Predis. I took most of code from here gist upgraded version on stack (from correct answer).

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>";

?>

Problem is that: When first execute "php file" then execute "node js server page" - "node js server page" have not seen session creation from "php file". When vice versa (first execute "node js server page" then execute "php file") session variables have seen in both page

result app.php

[]{
    "php": "Hello from PHP",
    "cookie": []
}

result node js page (http://127.0.0.1:8080)

{
    "cookie": {
        "originalMaxAge": null,
        "expires": null,
        "httpOnly": true,
        "path": "/"
    },
    "nodejs": "Hello from node.js!"
}
Community
  • 1
  • 1
Ramin Darvishov
  • 1,043
  • 1
  • 15
  • 30

2 Answers2

1

You are probably facing a cross domain issue. If you are running PHP and Node in a different address or port than PHP (and probably you are), HTML won't share Cookies between requests that go to the other domain, it will keep separated copies to each domain.

If you are using subdomains (for example, your PHP in a URL like app1.mydomain.com and your NodeJS running in app2.mydomain.com), you can share your cookies configuring them to be set/read using the main domain cookie path ( mydomain.com ).

There is good information about this topic over here:

Using Express and Node, how to maintain a Session across subdomains/hostheaders.

Let me us if you need more information or if your problem is not exactly that one.

Community
  • 1
  • 1
David Rissato Cruz
  • 3,347
  • 2
  • 17
  • 17
  • i use same domain. php on apache server (port 80) and node js server in a same domain (port 443) – Ramin Darvishov Nov 23 '15 at 14:48
  • They are in different ports (one is 80 and other is 443), and if any platform (php or node) set cookie's port parameter, they wont be considered living in the same domain (at least for your browser). But i think about one more issue in your case: one is HTTP and one is HTTPS. Sharing cookies between unsecure and secure connections require additional configuration in your code (and will make your app more vulnerable). And there is one more thing: if you are calling one URL using localhost and the other using 127.0.0.1, they wont share same cookies. As you can see, the problem need to be traced – David Rissato Cruz Nov 23 '15 at 14:59
1

i solve this problem from this article: 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();
?>
Ramin Darvishov
  • 1,043
  • 1
  • 15
  • 30