PHP,nodeJS和会话

时间:2014-06-18 22:49:00

标签: php node.js sockets session keep-alive

我有一个传统的apache服务器提供php文件,还有一个nodeJS服务器(带有socket.io,但没有表达/连接)用于PHP网站上的实时事件管理。我有时需要对连接到nodeJS服务器的客户端进行身份验证,但是当用户重新加载页面时,此身份验证会丢失,因为它还会重新加载socket.io客户端(我将套接字ID存储在服务器上,每次刷新时都会丢失)
问题是:有没有办法在socket.io中保持连接活动,或者是一种链接apache PHP会话和nodeJS服务器的方法?或者也许是一种使用cookie保持身份验证的方法(知道我必须存储敏感数据,如用户密码和密钥)?

5 个答案:

答案 0 :(得分:8)

您可以使用memcached as your session storage handler in PHP。 Memcached是一个简单的键值存储,可以通过TCP访问;有一个memcached module available for Node.js

PHP使用会话ID作为密钥将会话存储在memcached中。存储在memcached中的会话数据(值)是一个序列化的PHP对象,稍微扭曲。您可以在the SO question "Parse PHP Session in Javascript"了解有关此异常序列化的更多信息。幸运的是,那里已经有一个NPM模块:php-unserialize


现在为How-To。

<强>假设

  • memcached可在127.0.0.1:11211
  • 访问
  • php.ini(或php.d / memcache.ini)配置为:session.save_handler='memcached'session.save_path='tcp://127.0.0.1:11211'
  • 您已安装所需的NPM模块(2):npm install memcached php-unserialize
  • 您可以使用CLI

<强>准备

首先,只是为了获得一些测试数据,保存以下PHP脚本(s.php):

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

使用php s.php执行它,它应该把东西放在stdout中:

74ibpvem1no6ssros60om3mlo5
Array
(
    [some] => thing
)

好的,现在我们知道会话ID(74ibpvem1no6ssros60om3mlo5),并确认会话数据已设置。要确认它在memcached中,您可以运行memcached-tool 127.0.0.1:11211 dump,它提供已知密钥:值对的转储,例如我在测试床中有两个:

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

到目前为止,我们已经1)在php中创建了一个会话ID,2)在memcached中存储了来自php的会话数据,并且3)通过CLI确认了数据存在。

使用Node.js进行检索

这部分实际上非常简单。 NPM模块已经完成了大部分繁重的工作。我编写了一个通过CLI运行的Node.js小脚本,但是你得到了图片:

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
});

假设上述内容保存为m.js,则可以使用node m.js 74ibpvem1no6ssros60om3mlo5运行,输出如下内容:

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

<强>警告/陷阱

我的一个PHP应用程序将一些二进制数据存储在会话值中(即加密),但键和普通会话对象保持不变(如上例所示)。在这种情况下, memcached-tool <host:port> dump将错误的序列化会话字符串打印到stdout;我认为这可能与stdout隔离,但我错了。 使用PHPUnserialize.unserializeSession时,它也无法解析数据(由|分隔)。我在网上尝试了一些其他会话反序列化方法,但没有任何成功。我假设memcached在内部维护正确的数据,因为它与本机PHP会话保存处理程序一起工作,因此,在撰写本文时,我不太确定它是反序列化方法还是memcached NPM模块根本就是没有正确地检索/解释数据。当坚持使用非二进制数据(如ascii或utf-8)时,它应该按预期工作。

答案 1 :(得分:2)

答案 2 :(得分:2)

虽然线程很旧,但我想推荐一下我用于项目的内容。 您也可以使用Redis进行会话处理,而不是memcached。 我使用phpredis作为php redis客户端。而不是将会话存储到文件,您可以保存在Redis中。大部分繁重的工作将由阿帕奇完成。对于每个请求,apache会将会话值附加到cookie。它会从每个请求中读取会话值并对其进行验证。

将php会话保存到redis所需的设置也非常简单。

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

就是这样。这将使php将会话保存为redis而不是文件。这也会将存储在文件中的会话移动到redis。

答案 3 :(得分:1)

如果您的项目将会话存储在数据库中 - 有些会议 - 那么您可以考虑使用数据库作为传输介质。

如果您的特定情况下的分析显示了promise,那么可以使用node-mysql(或类似的) - 请参阅:link

答案 4 :(得分:1)

zamnuts的答案自进行身份验证以来对我有所帮助,这是我已经采用的方法。感谢那。

我发布的原因是使用时的原因:

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

继续给我错误

SyntaxError: String length mismatch

我不确定为什么吗?我编写了一个为我完成工作的函数,并希望分享该函数,以防它可能对其他人有所帮助。

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;

}

我只是这样称呼它:

var PHPUnserialize = Unserialize;

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

您应该能够轻松地修改正则表达式以满足您的需求。