PHP, nodeJS and sessions

社会主义新天地 提交于 2020-06-24 03:21:32

问题


I have an classical apache server delivering php files, and a nodeJS server (with socket.io, but whithout express/connect) used for real-time event management on that PHP website. I sometimes need to authenticate the clients connecting to the nodeJS server, but this authentication is lost when the user reloads the page, because it also reloads the socket.io client (I store the socket ID on the server, which gets lost at each refresh)
The question is: Is there a way to keep the connection alive in socket.io, or a way to link the apache PHP sessions and the nodeJS server? Or maybe a way to keep this authentication using cookies (knowing I must store sensitive data like user passwords and keys)?


回答1:


You can use memcached as your session storage handler in PHP. Memcached is a simple key value store that can be accessed via TCP; there is a memcached module available for Node.js.

PHP stores the session in memcached by using the session id as the key. The session data (value) stored in memcached is a serialized PHP object, with a slight twist. You can read more about this unusual serialization at the SO question "Parse PHP Session in Javascript". Luckily though, there is already an NPM module out there: php-unserialize.


Now for the How-To.

Assumptions

  • memcached is accessible at 127.0.0.1:11211
  • php.ini (or php.d/memcache.ini) is configured with: session.save_handler='memcached' and session.save_path='tcp://127.0.0.1:11211'
  • you have installed the required NPM modules (2): npm install memcached php-unserialize
  • you're ok with CLI

Prepare

First, just to get some test data to work with, save the following php script (s.php):

<?php
session_start();
$_SESSION['some'] = 'thing';
echo session_id()."\n";
print_r($_SESSION);

Execute it with php s.php, and it should put stuff in stdout:

74ibpvem1no6ssros60om3mlo5
Array
(
    [some] => thing
)

Ok, now we know the session id (74ibpvem1no6ssros60om3mlo5), and have confirmed that the session data was set. To confirm it is in memcached, you can run memcached-tool 127.0.0.1:11211 dump which provides a dump of known key:value pairs, for example I have two in my test bed:

Dumping memcache contents
  Number of buckets: 1
  Number of items  : 3
Dumping bucket 2 - 3 total items
add 74ibpvem1no6ssros60om3mlo5 0 1403169638 17
some|s:5:"thing";
add 01kims55ut0ukcko87ufh9dpv5 0 1403168854 17
some|s:5:"thing";

So far we have 1) created a session id in php, 2) stored session data from php in memcached, and 3) confirmed the data exists via CLI.

Retrieval with Node.js

This part is actually really easy. Most of the heavy-lifting has already been done by the NPM modules. I cooked up a little Node.js script that runs via CLI, but you get the picture:

var Memcached = require('memcached');
var PHPUnserialize = require('php-unserialize');

var mem = new Memcached('127.0.0.1:11211'); // connect to local memcached
var key = process.argv[2]; // get from CLI arg

console.log('fetching data with key:',key);
mem.get(key,function(err,data) { // fetch by key
        if ( err ) return console.error(err); // if there was an error
        if ( data === false ) return console.error('could not retrieve data'); // data is boolean false when the key does not exist
        console.log('raw data:',data); // show raw data
        var o = PHPUnserialize.unserializeSession(data); // decode session data
        console.log('parsed obj:',o); // show unserialized object
});

Assuming the above is saved as m.js, it can be run with node m.js 74ibpvem1no6ssros60om3mlo5 which will output something like:

fetching data with key: 74ibpvem1no6ssros60om3mlo5
raw data: some|s:5:"thing";
parsed obj: { some: 'thing' }

Warnings/Gotchas

One of my PHP applications stores some binary data in the session values (i.e. encrypted), but the keys and the normal session object remain intact (as in the example above). In this case, memcached-tool <host:port> dump printed a malformed serialized session string to stdout; I thought this might be isolated to stdout, but I was wrong. When using PHPUnserialize.unserializeSession, it also had trouble parsing the data (delimited by |). I tried a few other session deserialization methods out on the net, but did not have any success. I would assume memcached is maintaining the correct data internally since it works with the native PHP session save handler, so, at the time of this writing, I'm not quite sure if it is the deserialization methods or if the memcached NPM module simply isn't retrieving/interpreting the data correctly. When sticking with non-binary data like ascii or utf-8, it should work as intended.




回答2:


I think this link will be of some help to you https://simplapi.wordpress.com/2012/04/11/php-nodejs-session-share-memcache/




回答3:


Though the thread is old I would like to recommend what I used for my project. Instead of memcached you can also use Redis for session handling. I have used the phpredis as php redis client.Instead of storing session to files you can save in Redis. Most of the heavy lifting will be done by apache. For every request apache will append the session values to the cookies.And it reads the session values from every request and validates it.

Setting required to save the php session to redis is also very simple.

session.save_handler = redis session.save_path = "tcp://host1:6379?weight=1, tcp://host2:6379?weight=2&timeout=2.5, tcp://host3:6379?weight=2"

That's it.This will make php save the sessions to redis instead of the file. This will also move the session that are stored in files to redis.




回答4:


If your project stores session in database - some do - then you can consider using database as a transfer medium.

If analysis in your particular case shows promise, then node-mysql (or similar) can be used - see this: link




回答5:


The answer from zamnuts helped me make since of doing authentication and was the approach I was already taking. Thanks for that.

The reason I am posting is the for me some reason when using :

var PHPUnserialize = require('php-unserialize');

Kept giving me error

SyntaxError: String length mismatch

I am not sure why? I wrote a function that does the job for me and wanted to share in case it may help someone else.

function Unserialize(data){

  var result = {};

  if(data !== undefined){

    var preg = data.replace(/(^|s:[0-9]+:)|(^|i:)|(^|b:)|(")|(;$)/g,'').split(';'); 

    var a = [];
    preg.forEach(function(value){
      a.push(value.split('|'));
    });

    var b = [];
    a.forEach(function(value){
      if(Array.isArray(value)){
        Array.prototype.push.apply(b, value);
      }else{
        b.push(value);  
      }
    });

    var arr_A = [];
    var arr_B = [];
    b.forEach(function(value, k){
      if(k % 2 == 0){
        arr_A.push(value);
      }else{
        arr_B.push(value);
      }     
     });


     if (arr_A == null) return {};

     for (var i = 0, l = arr_A.length; i < l; i++) {
       if (arr_B) {
        result[arr_A[i]] = arr_B[i];
       } else {
        result[arr_A[i][0]] = arr_A[i][1];
       }
     }

  }

  return result;

}

I just call it like this:

var PHPUnserialize = Unserialize;

memcached.get(key, function(err, data){
   var memData = PHPUnserialize(data);
   console.log(memData.is_logged_in);
}); 

You should be able to modify the regex to suit your needs fairly easily.



来源:https://stackoverflow.com/questions/24296212/php-nodejs-and-sessions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!