注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

@fc_lamp

关注Web应用解决方案MySql/PHP/Python一盏名为"飞川"的灯~

 
 
 

日志

 
 

php session_set_save_handler 简单实例(php session)  

2012-06-27 17:06:00|  分类: Web技术-Php |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

php session_set_save_handler 简单实例(php session)

我前面写过一篇关于PHP SESSION NAME与SESSION ID关系的文章《SESSION NAME引用SESSION ID的问题(Discuz! 用户(自动)登录原理)》,

有兴趣的朋友可以看一下。我在里面提了一下SESSION在服务器端的存储方式问题,这里我们就使用session_set_save_handler 来实现

SESSION在服务器端的“另存为”。(关于session_set_save_handler的用法参看官网)

我们首先写一个存储类(注意这里没有对DB操作进行封装),暂叫session.class.php:


<?php

/**

 * 

 * 以数据库方式存储SESSION值

 * @author fc_lamp

 * @internal

 * 表的结构为:

-- ----------------------------

-- Table structure for `session`

-- ----------------------------

DROP TABLE IF EXISTS `session`;

CREATE TABLE `session` (

  `id` char(32) NOT NULL,

  `data` char(255) NOT NULL,

  `created_time` int(10) unsigned NOT NULL COMMENT '0',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='SESSION表';

 

-- ----------------------------

-- Records of session

-- ----------------------------

 

 * 

 */

class session_mysql

{

private $_db_link;

private $_table;

//这个是SESSION的回收周期(秒)

private $_gc_lifetime = 30;

/**

* 链接数据库(如果有DB类可以扩展此处)

* @param 主机 $host

* @param 用户名 $user

* @param 密码$pwd

* @param 数据库 $db

* @param 表名$table

* @param SESSION COOKIE的周期 $cookieLife

* @param SESSION NAME $sessionName

*/

public function __construct($host, $user, $pwd, $db, $table = 'session', $sessionName = '', $cookieLife = 0)

{

$this->_db_link = mysql_connect ( $host, $user, $pwd );

if (! $this->_db_link)

{

return False;

}

if (mysql_query ( "USE $db" ))

{

$this->_table = $table;

session_set_save_handler ( array (&$this, 'open' ), array (&$this, 'close' ), array (&$this, 'read' ), array (&$this, 'write' ), array (&$this, 'destroy' ), array (&$this, 'gc' ) );

//周期

$cookieLife = intval ( $cookieLife );

if ($cookieLife > 0)

{

session_set_cookie_params ( $cookieLife );

}

if ($this->_gc_lifetime > 0)

{

ini_set ( 'session.gc_maxlifetime', $this->_gc_lifetime );

} else

{

$this->_gc_lifetime = ini_get ( 'session.gc_maxlifetime' );

}

//名称

if (! empty ( $sessionName ))

{

ini_set ( 'session.name', $sessionName );

}

return session_start ();

}

return False;

}

/**

* open方法   

* 此方法在session_start()之后被调用 相当于类的__construct

* @param $save_path

* @param $session_name

* @return true

*/

public function open($save_path, $session_name)

{

return true;

}

/**

* close方法 

* 此方法相当于类的__destructor

* @return bool

*/

public function close()

{

//删除过期的SESSION

$this->gc ( $this->_gc_lifetime );

//关闭数据库

//(注意如果系统其它功能和SESSION共用一个数据库,此处关闭可能会影响到其它功能,根据实际情况而定)

return mysql_close ( $this->_db_link );

}

/**

* read方法

* @return string 读取session_id

*/

public function read($id)

{

$id = mysql_real_escape_string ( $id );

$sql = "select `data` from `$this->_table` where `id`='$id' limit 1";

if ($result = mysql_fetch_assoc ( mysql_query ( $sql, $this->_db_link ) ))

{

return $result ['data'];

}

return '';

}

/**

* write方法

* @param $id session

* @param $data 值

* @return bool

*/

public function write($id, $data)

{

$time = time ();

$id = mysql_real_escape_string ( $id );

$data = mysql_real_escape_string ( $data );

$sql = "replace into `$this->_table` values('$id','$data',$time)";

return mysql_query ( $sql, $this->_db_link );

}

/** 

* destroy方法

* @param $id session

* @return bool

*/

public function destroy($id)

{

$sql = "delete from `$this->_table` where `id`='$id' limit 1";

return mysql_query ( $sql, $this->_db_link );

}

/**

* GC方法

* @param $maxlifetime 存活期时间

* @return bool

*/

public function gc($lifetime)

{

$expire = time () - $lifetime;

$sql = "delete from `$this->_table where `created_time` < $expire";

return mysql_query ( $sql, $this->_db_link );

}

}



 

接着我们写一个公用的方法,暂叫function.php:


<?php

/**

 * 

 * 自定义方法此方法可以放入一个公共方法文件里,

 * 这样每个页面就可以调用得到了。

 * @param SESSION COOKIE的过期时间  $lifetime 

 * @param SESSION NAME的值 $sessionName

 */

function my_session_start($sessionName = '', $lifetime = 0)

{

//这里装载SESSION类(由于这里方便演示,文件结构分布不严谨)

require_once './session.class.php';

//配置好相关内容

$session = new session_mysql ( '127.0.0.1', 'xxx', 'xxx', 'test', 'session', $sessionName, $lifetime );

if ($session)

{

return True;

}

return False;

}



 

最后,我们来测试一下效果,test.php:


<?php

//测试一下

require_once './function.php';

error_reporting ( E_ALL );

my_session_start ();

$_SESSION ['test'] = 'test';

$_SESSION ['testtwo'] = array ('testtwo' );




我们再在另外一个页面输出SESSION,test2.php


<?php

require_once './function.php';

error_reporting ( E_ALL );

my_session_start ();

var_dump($_SESSION);



 

运行后我们可以看到:

array 'test' =>string'test'(length=4) 'testtwo' =>array 0 =>string'testtwo'(length=7)


 恩,一切正常。我们再看一下数据库中是什么:

php session_set_save_handler 简单实例(php session) - fc-lamp - fc-lamp的博客


恩,浏览器里又是怎么样的呐(这里只测试了FIREFOX,在生产时请务必各浏览器都要测试一下)?


php session_set_save_handler 简单实例(php session) - fc-lamp - fc-lamp的博客


恩,好了以就是一个简单的例子,那么如果我们要使用特殊的SESSION NAME或者要求有过期时间呐?test.php


<?php

//测试一下特殊名称

require_once './function.php';

error_reporting ( E_ALL );

my_session_start ( 'testhehe', 60 );//一分钟

$_SESSION ['lifettimetest'] = 'ok';



 

恩,我们来获取看看:test2.php


<?php

//测试一下特殊名称

require_once './function.php';

error_reporting ( E_ALL );

my_session_start ( 'testhehe' );

var_dump ( $_SESSION );




恩,我们来输出:

array 'lifettimetest' =>string'ok'(length=2)恩,貌似正常,我们再看看数据库与浏览器里的值:(数据库)

php session_set_save_handler 简单实例(php session) - fc-lamp - fc-lamp的博客


浏览器:

php session_set_save_handler 简单实例(php session) - fc-lamp - fc-lamp的博客

 

 

这样看来我们测试成功了。好了,以上就是关于session_set_save_handler的操作方法了。恩,如果你是还对PHP SESSION 原理不太熟悉,

请参看:《SESSION NAME引用SESSION ID的问题(Discuz! 用户(自动)登录原理)》

 

附 Cookie:

<?php
/**
*
* COOKIE 登录认证
* @author fc_lamp
*
*/
class cookieAuth
{
//用户模块
protected $userMode = NULL;
protected $uInfo = NULL;

protected $authCookieName = 'c_RSA_c'; //登录认证COOKIE变量
protected $authLastTime = 'c_izw_e'; //登录时间戳
protected $authExpir = 3600; //认证过期时间
protected $cookiePath = '/'; //普通COOKIE path
protected $cookieTime = 604800; //自动登录(-周)
protected $cookieDomain = 'xxx.com'; //普通COOKIE domain


public function __construct()
{
//导入用户模块
$this->userMode = D ( 'user' );

}

/**
*
* 完成登录(状态)
* @param $user array('uid'=>$res,'pwd'=>$data['passwd'])
* @internal
* 加uid与pwd:uid\tpwd加密存入COOKIE
*/
protected function doLogin($user, $cookieTime = 0)
{
$auth = $this->_ucAuthCode ( $user ['uid'] . '@' . $user ['pwd'], 'ENCODE' );
$auth = base64_encode ( $auth ); //防止特殊字符"/"
setcookie ( $this->authCookieName, $auth, $cookieTime, $this->cookiePath, $this->cookieDomain, False, True );

$this->flushAuthTime ( $cookieTime );
}

/**
*
* 完成安全退出
* @internal
*
*/
protected function doLogout()
{
//清除COOKIE
$_COOKIE = array ();
setcookie ( $this->authCookieName, NULL, - 1, $this->cookiePath, $this->cookieDomain );
setcookie ( $this->authLastTime, NULL, - 1, $this->cookiePath, $this->cookieDomain );

$sessionName = session_name ();
setcookie ( $sessionName, null, - 1, $this->cookiePath );

//清除SESSION
$_SESSION = array ();
session_destroy ();
}

/**
*
* 登录状态检测
* @internal
*/
protected function checkLoginStatus()
{
if (! empty ( $_COOKIE [$this->authCookieName] ) and ! empty ( $_COOKIE [$this->authLastTime] ))
{
//认证时间戳
$authorLastTime = base64_decode ( $_COOKIE [$this->authLastTime] );
$authorLastTime = explode ( '@', $this->_ucAuthCode ( $authorLastTime, 'DECODE' ) );
if (count ( $authorLastTime ) != 2 or ! is_numeric ( $authorLastTime [0] ) or ! is_numeric ( $authorLastTime [1] ))
{
$this->doLogout ();
$this->uInfo = NULL;
return False;
}
$cookieTime = $this->_id ( $authorLastTime [1] );
$author_last_time = $this->_id ( $authorLastTime [0] );
//非自动登录
if ($cookieTime <= 0)
{
//是否过期
if (time () > $authorLastTime + $this->authExpir)
{
$this->doLogout ();
$this->uInfo = NULL;
return False;
}
}

//认证用户
$cookieU= base64_decode ( $_COOKIE [$this->authCookieName] );
$cookieU = explode ( '@', $this->_ucAuthCode ( $cookieU, 'DECODE' ) );
$uId = $this->_id ( reset ( $cookieU ) );

//这里是查寻数据库部分
$uInfo = $this->userMode->field ( 'id,name,passwd' )->where ( "id=$uId" )->find ();
if (! empty ( $uInfo ) and $uInfo ['passwd'] == end ( $cookieU ))
{
$this->uInfo = $uInfo;
$uInfo = NULL;
//刷新认证时间戳(登陆)
$this->flushAuthTime ( $cookieTime );
return True;
}
$this->doLogout ();
}
$this->uInfo = NULL;
return False;
}

/**
*
* 刷新认证时间戳
* @internal
* 上次时间戳@cookie本身生存周期
*/
private function flushAuthTime($cookieTime = 0)
{
//认证时间戳
$authExpir = time () . '@' . $cookieTime;
$authExpir = $this->_ucAuthCode ( $authExpir, 'ENCODE' );
$authExpir = base64_encode ( $authExpir );
setcookie ( $this->authLastTime, $authExpir, $cookieTime, $this->cookiePath, $this->cookieDomain, False, True );
}

/**
*
* UC加密函数
* @param unknown_type $string
* @param unknown_type $operation DECODE,ENCODE
* @param unknown_type $key
* @param unknown_type $expiry
*/
private function _ucAuthCode($string, $operation = 'DECODE', $key = 't1568rsd', $expiry = 0)
{
$ckey_length = 4;
$key = md5 ( $key );
$keya = md5 ( substr ( $key, 0, 16 ) );
$keyb = md5 ( substr ( $key, 16, 16 ) );
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr ( $string, 0, $ckey_length ) : substr ( md5 ( microtime () ), - $ckey_length )) : '';

$cryptkey = $keya . md5 ( $keya . $keyc );
$key_length = strlen ( $cryptkey );

$string = $operation == 'DECODE' ? base64_decode ( substr ( $string, $ckey_length ) ) : sprintf ( '%010d', $expiry ? $expiry + time () : 0 ) . substr ( md5 ( $string . $keyb ), 0, 16 ) . $string;
$string_length = strlen ( $string );

$result = '';
$box = range ( 0, 255 );

$rndkey = array ();
for($i = 0; $i <= 255; $i ++)
{
$rndkey [$i] = ord ( $cryptkey [$i % $key_length] );
}

for($j = $i = 0; $i < 256; $i ++)
{
$j = ($j + $box [$i] + $rndkey [$i]) % 256;
$tmp = $box [$i];
$box [$i] = $box [$j];
$box [$j] = $tmp;
}

for($a = $j = $i = 0; $i < $string_length; $i ++)
{
$a = ($a + 1) % 256;
$j = ($j + $box [$a]) % 256;
$tmp = $box [$a];
$box [$a] = $box [$j];
$box [$j] = $tmp;
$result .= chr ( ord ( $string [$i] ) ^ ($box [($box [$a] + $box [$j]) % 256]) );
}

if ($operation == 'DECODE')
{
if ((substr ( $result, 0, 10 ) == 0 || substr ( $result, 0, 10 ) - time () > 0) && substr ( $result, 10, 16 ) == substr ( md5 ( substr ( $result, 26 ) . $keyb ), 0, 16 ))
{
return substr ( $result, 26 );
} else
{
return '';
}
} else
{
return $keyc . str_replace ( '=', '', base64_encode ( $result ) );
}
}

/**
*
* ID参数
* @param unknown_type $id
*/
private function _id($id)
{
return abs ( intval ( $id ) );
}
}



  评论这张
 
阅读(1166)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017