转载自: http://gonzalo123.com/2011/07/25/using-node-js-to-store-php-sessions/
最近一直在研究node-php-session的共享,发现这边文章不错,特留下以备后用。谢谢原创作者。等项目结束了,我把我用symfony2+memcached+nodejs实现的session共享方法,也分享一下。
We use sessions when we want to preserve certain data across subsequent accesses. PHP allows us to use different handlers when we’re using sessions. The default one is filesystem, but we can change it with session.save_handler in the php.ini. session.save_handler defines the name of the handler which is used for storing and retrieving data associated with a session. We also can create our own handler to manage sessions. In this post we’re going to create a custom handler to store sessions in a node.js service. Let’s start:
Imagine we’ve got the following php script:
session_start(); if (!isset($_SESSION["gonzalo"])) $_SESSION["gonzalo"] = 0; $_SESSION["gonzalo"]++; $_SESSION["arr"] = array('key' => uniqid()); var_dump($_SESSION);
A simple usage of sessions with PHP. If we reload the page our counter will be incremented by one. We’re using the default session handler. It works without any problem.
The idea is create a custom handler to use a server with node.js to store the session information instead of filesystem. To create custom handlers we need to use the PHP function: session_set_save_handler and rewrite the callbacks for: open, close, read, write, destroy and gc. PHP’s documentation is great. My proposal is the following one:
Our custom handler:
class NodeSession { const NODE_DEF_HOST = '127.0.0.1'; const NODE_DEF_PORT = 5672; static function start($host = self::NODE_DEF_HOST, $port = self::NODE_DEF_PORT) { $obj = new self($host, $port); session_set_save_handler( array($obj, "open"), array($obj, "close"), array($obj, "read"), array($obj, "write"), array($obj, "destroy"), array($obj, "gc")); session_start(); return $obj; } private function unserializeSession($data) { if( strlen( $data) == 0) { return array(); } // match all the session keys and offsets preg_match_all('/(^|;|\})([a-zA-Z0-9_]+)\|/i', $data, $matchesarray, PREG_OFFSET_CAPTURE); $returnArray = array(); $lastOffset = null; $currentKey = ''; foreach ( $matchesarray[2] as $value ) { $offset = $value[1]; if(!is_null( $lastOffset)) { $valueText = substr($data, $lastOffset, $offset - $lastOffset ); $returnArray[$currentKey] = unserialize($valueText); } $currentKey = $value[0]; $lastOffset = $offset + strlen( $currentKey )+1; } $valueText = substr($data, $lastOffset ); $returnArray[$currentKey] = unserialize($valueText); return $returnArray; } function __construct($host = self::NODE_DEF_HOST, $port = self::NODE_DEF_PORT) { $this->_host = $host; $this->_port = $port; } function open($save_path, $session_name) { return true; } function close() { return true; } public function read($id) { return (string) $this->send(__FUNCTION__, array('id' => $id)); } public function write($id, $data) { try { $this->send(__FUNCTION__, array( 'id' => $id, 'data' => $data, 'time' => time(), 'dataJSON' => json_encode($this->unserializeSession($data)))); return true; } catch (Exception $e) { return false; } } public function destroy($id) { try { $this->send(__FUNCTION__, array('id' => $id)); } catch (Exception $e) { return false; } return true; } function gc($maxlifetime) { try { $this->send(__FUNCTION__, array('maxlifetime' => $maxlifetime, 'time' => time())); } catch (Exception $e) { return false; } return true; } private function send($action, $params) { $params = array('action' => $action) + $params; return file_get_contents("http://{$this->_host}:{$this->_port}?" . http_build_query($params)); } }
Our node.js server:
var http = require('http'), url = require('url'), session = require('nodePhpSessions').SessionHandler; var sessionHandler = new session(); var server = http.createServer(function (req, res) { var parsedUrl = url.parse(req.url, true).query; res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(sessionHandler.run(parsedUrl)); }); server.listen(5672, "127.0.0.1", function() { var address = server.address(); console.log("opened server on %j", address); });
As we can see we need the node.js module nodePhpSessions. You can easily install with:
npm install nodePhpSessions
You can see nodePhpSessions library here.
The library is tested with nodeunit. Without TDD is very hard to test things such as garbage collector.:
var session = require('nodePhpSessions').SessionHandler; var sessionHandler = new session(); var parsedUrl; exports["testReadUndefinedSession"] = function(test){ parsedUrl = { action: 'read', id: 'ts49vmf0p732iafr25mdu8gvg2' }; test.equal(sessionHandler.run(parsedUrl), undefined); test.done(); }; exports["oneSessionShouldReturns1"] = function(test){ parsedUrl = { action: 'write', id: 'ts49vmf0p732iafr25mdu8gvg2', data: 'gonzalo|i:1;arr|a:1:{s:3:"key";s:13:"4e2b1a40d136a";}', time: '1311447616', dataJSON: '{"gonzalo":1,"arr":{"key":"4e2b1a40d136a"}}' }; sessionHandler.run(parsedUrl); parsedUrl = { action: 'readAsArray', id: 'ts49vmf0p732iafr25mdu8gvg2' }; test.equal(sessionHandler.run(parsedUrl).gonzalo, 1); test.done(); }; exports["oneSessionShouldReturns2"] = function(test){ parsedUrl = { action: 'write', id: 'ts49vmf0p732iafr25mdu8gvg2', data: 'gonzalo|i:2;arr|a:1:{s:3:"key";s:13:"4e2b1a40d136a";}', time: '1311447616', dataJSON: '{"gonzalo":2,"arr":{"key":"4e2b1a40d136a"}}' }; sessionHandler.run(parsedUrl); parsedUrl = { action: 'readAsArray', id: 'ts49vmf0p732iafr25mdu8gvg2' }; test.equal(sessionHandler.run(parsedUrl).gonzalo, 2); test.done(); }; exports["destroySession"] = function(test){ parsedUrl = { action: 'destroy', id: 'ts49vmf0p732iafr25mdu8gvg2'}; sessionHandler.run(parsedUrl); parsedUrl = { action: 'readAsArray', id: 'ts49vmf0p732iafr25mdu8gvg2' }; test.equal(sessionHandler.run(parsedUrl), undefined); test.done(); }; exports["garbageColector"] = function(test){ parsedUrl = { action: 'write', id: 'session1', data: 'gonzalo|i:1;arr|a:1:{s:3:"key";s:13:"4e2b1a40d136a";}', time: '1111111200', dataJSON: '{"gonzalo":1,"arr":{"key":"4e2b1a40d136a"}}' }; sessionHandler.run(parsedUrl); parsedUrl = { action: 'write', id: 'session2', data: 'gonzalo|i:1;arr|a:1:{s:3:"key";s:13:"4e2b1a40d136a";}', time: '1111111100', dataJSON: '{"gonzalo":1,"arr":{"key":"4e2b1a40d136a"}}' }; sessionHandler.run(parsedUrl); parsedUrl = { action: 'gc', maxlifetime: '100', time: '1111111210'}; sessionHandler.run(parsedUrl); parsedUrl = { action: 'readAsArray', id: 'session2' }; test.equal(sessionHandler.run(parsedUrl), undefined); parsedUrl = { action: 'readAsArray', id: 'session1' }; test.equal(sessionHandler.run(parsedUrl).gonzalo, 1); test.done(); };
Here you can see the output of the tests:
nodeunit testNodeSessions.js testNodeSessions.js ✔ testReadUndefinedSession ✔ oneSessionShouldReturns1 ✔ oneSessionShouldReturns2 ✔ destroySession ✔ garbageColector OK: 6 assertions (5ms)
Now we change the original PHP script to:
include_once 'NodeSessions.php'; NodeSession::start(); if (!isset($_SESSION["gonzalo"])) $_SESSION["gonzalo"] = 0; $_SESSION["gonzalo"]++; $_SESSION["arr"] = array('key' => uniqid()); var_dump($_SESSION);
We start the node.js server:
node serverSessions.js
Now if we reload our script in the browser we will see the same behaviour, but now our sessions are stored in the node.js server.
array(2) { ["gonzalo"]=> int(16) ["arr"]=> array(1) { ["key"]=> string(13) "4e2a9f6a966f4" } }
This kind of techniques are good when clustering PHP applications.
Full code is available on github (node server, PHP handler, tests and examples) here.
相关推荐
Using S3 to store files 239 Working with buckets 239 Working with objects 240 Using AWS with a Node server 243 Getting and setting data with DynamoDB 244 Searching the database 247 Sending mail via ...
12. Cookies, Sessions, and Authentication 13. Exploring JavaScript 14. Expressions and Control Flow in JavaScript 15. JavaScript Functions, Objects, and Arrays 16. JavaScript and PHP Validation and ...
Node.js-注册-登录-应用程序 这是一个使用Node.js,Express,Mongoose...您需要在系统中安装Node.js,NPM和MongoDB。 正在安装 npm install 跑步 nodemon server.js 代码正在运行 :smiling_face_with_heart-eyes: 谢谢
blog/sessions.js - 会话数据访问助手 blog/users.js - 用户数据访问助手 博客/视图/ - html 模板 家庭作业 运行作业 3.1 npm run hw1 跑作业 3.2 cd blog/ npm install node app.js 跑作业 3.3 cd blog/ npm ...
这是一个用于创建基本 node.js 应用程序框架的生成器。 可选功能: 服务器端修女的意见 客户 nunjucks 意见 i18n 通过 gettext Redis 存根通过connect-redis-sessions 测试骨架 代码文档 自述文件骨架 入门 什么...
Unlike Practical Node.js (Apress, 2014) which covered many libraries, Pro Express.js is focused on the single module Express.js. Of course, where it’s necessary to cover other related libraries, ...
JanusAdmin JanusAdmin是一个node.js http客户端,它实现了Janus WebRTC网关的整个管理界面。用法var JanusAdmin = require ( 'janus-admin' ) . JanusAdmin ;var admin = new JanusAdmin ( { url : '...
Together, the MongoDB database, the Express and AngularJS frameworks, and Node.js constitute the MEAN stack—a powerful platform that uses only one language, top to bottom: JavaScript. Developers and...
A Practical Guide to TPM 2.0: Using the Trusted Platform Module in the New Age of Security is a straight-forward primer for developers. It shows security and TPM concepts, demonstrating their use in ...
Using Functions in Your Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . 491 Using include() and require(). . . . . . . . . . . . . . . . . . . . . . . . . . . 492 Appendix DWriting Your ...
500行Node.js简单实现单点登录(SSO)中央授权单元和客户端 重要的 要运行这些示例,您需要在 linux 中的/etc/hosts文件中添加以下条目 127.0.0.1 sso.ankuranand.com 127.0.0.1 consumer.ankuranand.in 介绍 Web ...
./app.js - 入口点 ./package.json - npm 包描述 ./posts.js - 帖子数据访问助手 ./sessions.js - 会话数据访问助手 ./users.js - 用户数据访问助手 ./views / - html 模板 入门 npm 安装节点 app.js
红鸟Sessions类,用mysql数据库接管原来由文件系统支撑的php session,解决了session兼容性、虚拟主机无法自定义session等问题,内置gc函数,可以按概率触发删除过期session。 在php原始session用法不变的情况下,...
■CHAPTER 16 From Eclipse RCP to the NetBeans Platform . . . . . . . . . . . . . . . . . . 279 ■CHAPTER 17 Tips and Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ...
introduction to Shell Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 About This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ....
log-sessions-2021-08-21-041328.session
node.js中的简单用户配置文件管理。 用户身份验证是使用JWT完成的。 数据库-MYSQL
会话 用于会话管理的Gin中间件,具有多后端支持:用法开始使用它下载并安装: $ go get github.com/gin-contrib/sessions 将其导入您的代码中: import "github.com/gin-contrib/sessions"基本范例单节package main...
To disable this feature set this option to empty value ;user_ini.filename = ; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) ;user_ini.cache_ttl = ...
1.4 Using Pipes to Create a New Tool.....................................................................................................7 ................................................................