设为首页 收藏本站
查看: 664|回复: 0

[经验分享] PHP and Node.JS session share using memcache

[复制链接]

尚未签到

发表于 2017-4-5 12:10:06 | 显示全部楼层 |阅读模式
最近在部署nodejs和php的通过memcached实现session共享的pc和andriod的实时聊天。看到此片文章,感觉非常不错,留下以备后用。谢谢作者了,帮助很大。
转载自: https://www.evernote.com/shard/s209/sh/740efea8-dded-40d0-95cd-2f1041b48eb5/c75e2226f8d896249b540d9f60f0f7a5
I was needing some real time performance using PHP. After searching and creating « patched » systems, i’ve to admit there is no real good system using only PHP.

First step

The best way i found was using long polling system using a file system + Mysql to store current system (file, when user first connect), and last commands sended (Mysql, for user already logged who need only small updates). The system still have some trouble because of lost messages while transfering and sometimes time difference while using clearstatcache.
You can found a really basic example of such kind of system here.
This system in general is not stable for production. So I decide to extend existing PHP system with Node.JS + socket.io.

Extending PHP

Because the PHP system was already finished, and only few parts use real time, the idea was using a share system between PHP and Node.JS. The main problem was in fact to share session from PHP to Node.JS.

Understanding PHP’s session

PHP session are not easy to change/manipulate when serialized, basically PHP use a handler to store data, a stored sessions will look like this :
user_id|s:1:"1";password|s:0:"";firstname|s:7:"Charles";

Basically it is : key | type : length : value ;
In case of integer, it will be type : value directly.
The problem is that, this serialize system is not so easy to manipulate in PHP, and in Node.JS also. PHP use a specific serializer/unserializer called session_decode and session_encode for that. And Node.JS got nothing. The problem is pretty simple, imagine a string variable using a « ; » inside. In such case you just can’t use a split(« ; ») (like many link on internet suggest) because you will cut the variable content. That’s why we should change the storing system to get a more easy-to-change format for both PHP and Node.JS : JSON.


PHP Session Handler

There is many way to change the session handler, but in fact only one is enough flexible to change the stored result. If you use directly php.ini to set a different storage (like memcache), you will not get what we want, because session will still be stored like previous system but in memcache, and you cannot change anything to that. PHP provide a more flexible system, using the session_set_save_handler. This function allow to manipule each basic operation on session storage : open/read/write/delete/close and gc (garbage collector).
By the way, we must have a shared system flexible for Node.JS and PHP, basically there is two main system : memcache and SQL storage, which are both pretty easy to use in Node and PHP.
From now, I consider you got PHP/Node.JS & memcache configured, with memcache running on port 11211 on localhost, PHP is linked to memcache using php-memcache. There is plenty tutorials on internet, for every system (Windows, linux/OSX).


Custom Handler to share with Node.JS

The problem with session_set_save_handler function, is that save function already got session encoded data version passed (so we recieve the encoded session), and read function must retrieve the same already-encoded version, so we must unserialize before storing, and re-serialize after storing.
This class already do the trick properly :


<?php
/**
* memcacheSessionHandler class
* @class                       memcacheSessionHandler
* @file                        memcacheSessionHandler.class.php
* @brief                       This class is used to store session data with memcache, 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 memcache, it store in json the session to be used more easily in Node.JS
*/
class memcacheSessionHandler{
private $host = "localhost";
private $port = 11211;
private $lifetime = 0;
private $memcache = null;
/**
* Constructor
*/
public function __construct(){
$this->memcache = new Memcache;
$this->memcache->connect($this->host, $this->port) or die("Error : Memcache is not ready");
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->memcache->close();
}
/**
* 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->memcache->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 memcached was able to write the session data
*/
public function write($id, $data){
$tmp = $_SESSION;
session_decode($data);
$new_data = $_SESSION;
$_SESSION = $tmp;
return $this->memcache->set("sessions/{$id}", json_encode($new_data), 0, $this->lifetime);
}
/**
* Delete object in session
* @param string $id The SESSID to delete
* @return boolean True if memcached was able delete session data
*/
public function destroy($id){
return $this->memcache->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 memcacheSessionHandler();
?>

You just need to include this script at the beginning of each script wich use session, it must be included before every session_start call (it start by itself memcacheSessionHandler class).
This system will overpass all php.ini config about session handling. Now if you check inside memcache, the session are now stored in JSON. It will serialize/unserialize to still let PHP system using his own way. It is totally transparent for PHP.
Be carefull session_set_save_handler change with PHP5.4, so in this case you have to modify little bit this class :


class memcacheSessionHandler implements SessionHandlerInterface{

For PHP5.4 now there is interface to implements. There is also session_set_save_handler little bit different (replace on __construct function) :

session_set_save_handler(&$this, true);

Instead of long code function… This is enough for support on PHP5.4.

Node.JS Part

Now we just need to use memcache (wich store JSON session file, and delete them after session max lifetime) inside Node.JS :
First don’t forget to install memcache : npm install memcache

Here is a basic example how to use PHP Session (using cookie session ID) :

var app = require("http").createServer(handler),
fs = require("fs"),
memcache = require("memcache"),
co = require("./cookie.js");
app.listen(7070);
//On client incomming, we send back index.html
function handler(req, res){
fs.readFile(__dirname + "/index.html", function(err, data){
if(err){
res.writeHead(500);
return res.end("Error loading index.html");
}else{
res.writeHead(200);
res.end(data);
}
});

//Using php session to retrieve important data from user
var cookieManager = new co.cookie(req.headers.cookie);
var client = new memcache.Client(11211, "localhost");
client.connect();
client.get("sessions/"+cookieManager.get("PHPSESSID"), function(error, result){
console.log("error : "+error);
if(typeof(error)==="undefined"){
var session = JSON.parse(result);
}
});
}

You need to get also this cookie module (./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]){
cookieRet[map] = this.cookies[map];
}
}
return cookieRet;
};
};

Now it’s almost finish, Node.JS and PHP are both linked to memcache, and share session in JSON. When one (PHP in fact), disconnect, the other (Node.JS) will do the same because PHP continue to keep hand on memcache like it use to do with session (so login & logout should stay on PHP side).
  Don’t forget on Node.JS the PHPSESSID => may be different if you use a different session name on PHP.ini.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-360607-1-1.html 上篇帖子: Windows7系统环境安装配置PHP开发环境 下篇帖子: 无法在发生错误时创建会话,请检查 PHP 或网站服务器日志,并正确配置 PHP 安装。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表