前三篇简单的总结了下会话控制和文件操作,这一篇说说会话控制的自定义处理方式。既然知道了文件的基本读写,而且在会话控制中,也有人提到,session数据可以保存到缓存或数据库中,实际上当然不会是直接利用php的session处理机制,将所有用户的session信息保存报一个文件中,访问量大、信息数据多、无法共享等等问题可能会出现,因此,我们需要自定义会话控制。在实现自定义会话控制前,就要知道php本身是如何来做会话管理的,。这里,就简单的实现它被保存到自定义目录下的文件里边,那么缓存或数据库就很明显了。
首先看几个命令再说,这将有利于我们理解它的机制。打开php配置文件,找到一些session.打头的命令项:
session.save_handler:它的值默认是files,看它的英文解释可知,如果它的值是files,那么就是使用php本身的机制来处理,它的信息会保存到session.save_path所指定的地方,如果是想自定义session处理的话,需要将users赋给它。
session.save_path:在win版的php配置文件中,它默认是被注释掉的,即在配置文件中并没有说它的值是多少,但总得有个地方放session数据是不,win下,这个地方是C:/Windows/Temp,进去即可找到(如下,如果你练习过session存储的程序的话)以sess_为前缀、后面跟一长串长度一样的字符串、没有扩展名的文件,它就是默认的session数据了,里面存放的是序列化(也有的说是串行化)后的数据(如user|s:4:"Jack";,user是变量名,"Jack"是变量值,s表示变量类型string,冒号后边的4表示长度,最后的分号以结束这个变量,这只是简单的数值型,还有对象等等也可序列化)。关于save_path,他还有一些配置方式,比如按数字分级,更方便大数量的数据文件存放,具体不细说。
弄清楚它的处理及存放后,其实就应该冒出这样一个问题:我们平时又没动session数据,如果它就这么一直放着存着,那不会把磁盘占满吗?难道要专门写一个脚本定时来删除它们?幸运的是php提供了session的自动回收机制,即垃圾回收。了解回收机制还是需穴ky"http://www.it165.net/qq/" target="_blank" html' target='_blank'>class="keylink">qq/tMP8we7P7qGjPC9wPgo8cD4mbmJzcDsgJm5ic3A7ICZuYnNwOyBzZXNzaW9uLmdjX3Byb2JhYmlsaXR5o7pnY8rHZ2FyYmFnZSBjb2xsZWN0aW9uu9jK1bzy0LSjrNLiy7zJz8rHuMXCyqGiv8nE3NDUPC9wPgo8cD4mbmJzcDsgJm5ic3A7ICZuYnNwOyBzZXNzaW9uLmdjX2Rpdmlzb3KjutLiy7zJz8rHs/3K/aOs1eLBvc/u0qrX27rPxvDAtL+0o6zU2tLR09C1xHNlc3Npb27OxLz+wO+x36OsttTT2rn9xtq1xKOs0tRnY19wcm9iYWJpbGl0eS9nY19kaXZpc29ytcS4xcLKwLTRodTxxuTW0NK7uPbJvrP9o6zU2sO/tM5zZXNzaW9us/XKvLuvyrG2vLvh1eLR+df2oaPL+dLUvNnJ6GdjX2Rpdmlzb3LKxzEwMDCjrGdjX3Byb2JhYmlsaXR5yscxo6y2+LTLyrHHobrD09AxMDAwuPa5/cbatcRzZXNzaW9uzsS8/qOsxMfDtNKysrvKx8irsr/JvrP9o6y2+MrHy+a7+sz0xuTW0NK7uPbJvrP9o6y8tDEvMTAwMLXEuMXCyqGjPC9wPgo8cD4mbmJzcDsgJm5ic3A7ICZuYnNwOyBzZXNzaW9uLmdjX21heGxpZmV0aW1lo7pzZXNzaW9utcTT0NCnyrG85KOs1rvT0LOsuf3By9XiuPbT0NCnyrG85LXEc2Vzc2lvbs7EvP6yxbvhsbvB0MjrcGhwwKy7+LvYytW1xLe2zqfE2qGjPC9wPgo8cD4mbmJzcDsgJm5ic3A7ICZuYnNwOyDBy73iwcvV4tCp17yxuNaqyra686OsvdPPwsC0vs29+Mjrtb1zZXNzaW9utcTX1Lao0uW0psDtuf2zzMHLoaM8L3A+CjxwPiZuYnNwOyAmbmJzcDsgJm5ic3A7ILK7udzKx7GjtObU2m1lbWNhY2hlu7nKx8r9vt2/4qOsu7nKx8bky/u3vcq9o6zX7rP1tcTUrcDttrzSu9H5o6xwaHDU2rSmwO1zZXNzaW9uyv2+3cqxyrnTw7XEysfSu7j2uq/K/aO6c2Vzc2lvbl9zZXRfc2F2ZV9oYW5kbGVyoaPG5Nfu0MK1xNSt0M3Kx6O6PC9wPgo8cD4mbmJzcDsgJm5ic3A7ICZuYnNwOyBib29sIHNlc3Npb25fc2V0X3NhdmVfaGFuZGxlciAoIGNhbGxhYmxlICRvcGVuICwgY2FsbGFibGUgJGNsb3NlICwgY2FsbGFibGUmbmJzcDskcmVhZCAsIGNhbGxhYmxlICR3cml0ZSAsIGNhbGxhYmxlICRkZXN0cm95ICwgY2FsbGFibGUgJGdjIFssIGNhbGxhYmxlICRjcmVhdGVfaWRdKTxlbSBpZD0="__mceDel" style="line-height: 1.5;">
可以看到这个函数又会去调用回调函数。首先,我们知道的是,从session的开始到挂掉,要session_start一个会话,要往$_SESSION里边写入数据保存session信息,或者读取该数组中的信息,用完时又会去destroy它的数据,这么几个步骤,对应这几个函数名一看,就八九不离十了。
open:它有两个参数---$save_path和$session_id,传递给它的参数已经表明,它是处理存放session数据的路径的,实际上就是通过它来改变文件的存放目录,就可以不是C:Windows/Temp。它在创建一个全新的会话session_start,或者start一个已经存在的会话时会被php内部去自动调用(session_start()),只有返回true才可以进行下一步处理。
close:它没有参数,作用是关闭当前会话,当你关闭一个会话时会自动调用,或者当你显式调用另一个php的函数session_write_close时。
read:它需要一个参数$session_id,作用是从存储session数据的地方读取id为$session_id的用户的session信息,并返回,以便后续的内部处理。当session_start()开启一个会话时,或者在内部调用open函数后会继续调用它。返回当前用户会话数据写入$_SESSION。
write:它需要两个参数---$session_id和$session_data,很明显,写入用户$session_id的对应的会话信息$session_data到指定文件。这个session_data是序列化后的数据,返回true可以进行下一步操作。它可以是正常的脚本被关闭时执行,也可是内部函数session_write_close()调用或者内部函数session_register_shutdown调用失败时执行。最明显的,当我们给$_SESSION数组赋值时它就会被执行。
destroy:它有一个参数$session_id,在session_destroy时会调用它,删除session_id对应的会话信息。
gc:参数是$maxlifetime,对于启动垃圾回收程序时(开始会话或者session_start被调用)执行,貌似启动垃圾回收时也是be randomly called,任性!
create_sid:这个回调函数是可选的,可以不写。它没有参数,当需要一个新的会话session id时可以写写,比如php还有一个重新生成会话id的函数session_regenerate_id。
总结下就是,session_start()时,要执行open、read、gc,在对$_SESSION数组赋值时,以后再操作$_SESSION不会调用它们,调用session_write_close内部函数时就会去调用write和close。
======================================================================
啰嗦了这么多,就是说,在start一个会话之前,我们要做的事是:
1、session.save_handler改为user,重启Apache,或者,使用ini_set临时修改命令项;
2、编写session_set_save_handler函数里对应的必选的回调函数
3、重新定义session_set_save_handler函数,使用上面的回调函数的名字;
4、code一个会话程序,在每一次调用session_start()之前,确保本次运行脚本时有上面的重定义函数可被调用到。
修改命令的工作已做,先编写一个脚本custom_session.php,自定义session_set_save_handler函数。
<?php ini_set('save_handler', 'users'); // 使用自定义处理 $session_save_path = 'G:/sessionFiles/'; // 自定义一个存放目录 // session_start()会来调用它 function open($save_path, $session_id){ echo '<br>call open.<br>'; global $session_save_path; $save_path = $session_save_path; //修改存放session数据的目录 return true; } // 销毁session或调用session_write_close时调用 function close(){ echo '<br>call close.<br>'; return true; } // 读取session数据并返回 function read($session_id){ echo '<br>call read.<br>'; global $session_save_path; $filename = $session_save_path.'sessionId_'.$session_id.'.txt'; $content = @file_get_contents($filename); return $content; } // 将对应用户(以会话id判断)的数据写入文件 function write($session_id, $session_data){ echo '<br>call write.<br>'; global $session_save_path; $filename = $session_save_path.'sessionId_'.$session_id.'.txt'; // 自定义一个文件名,最好有一定规则 if(($handle = @fopen($filename, 'w+')) == true){ $bytes = @file_put_contents($filename, $session_data); return $bytes; } else{ return false; } return false; } // 调用session_destroy时执行,删除对应 function destroy($session_id){ echo '<br>call destroy.<br>'; global $session_save_path; $filename = $session_save_path.'sessionId_'.$session_id.'.txt'; return @unlink($filename); // 删除文件/数据 } // 垃圾回收 function gc(int $maxlifetime){ echo '<br>call gc.<br>'; global $session_save_path; $files = glob($session_save_path.'sessionId_*'); foreach($files as $filename){ if(filemtime($filename) + $maxlifetime < time()){ @unlink($filename); } } return true; } session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');
然后,写了个简单的用户登录验证的脚本来试试,前办部分是php验证操作,后边是页面,还要include前面的自定处理方式脚本
<?php // 改变session为自定义处理方式 include 'custom_session.php'; echo '<br>before call session_start fun.<br>'; session_start(); //开启session会话,若已开启则返回已存在session id echo 'session id: '.session_id().'<br>'; //输出session id if(!empty($_POST["sub"])) //如果点击登录 { include "conn.inc.php"; //连接数据库 $sql = "select id from sessionuser where username='".$_POST["user"]."' and password='".md5($_POST["pass"])."'"; //echo 'sql=> '.$sql.'<br>'; $result = $mysqli->query($sql); if($result->num_rows > 0) { $assRow = $result->fetch_assoc(); $_SESSION["user"] = $_POST["user"]; // 存储session数据 $_SESSION["uid"] = $assRow["id"]; $_SESSION["islogin"] = 1; }else{ echo "<br>wrong username or password, please relogin.";
} } ?><html> <head> <title>Session Test</title> </head> <body> <form action="login.php" method="post"> <table align="center" > <caption><h3>ID login</h3></caption> <tr> <td>username</td> <td><input type="text" name="user" /></td> </tr> <tr> <td>password</td> <td><input type="password" name="pass" /></td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" name="sub" value="login" /> </td> </tr> </table> </form> </body></html><?php echo '<br>script end.<br>'; ?>
结果如下:
在session_start()前做了标记“before call session_start fun.”,在脚本最后做了标记“script end”,很清楚的看到,在session_start()调用随后就调了open和read,在脚本自动结束前会自动去调用write和close,这里并没有去销毁session信息,但是脚本结束时自动会调write写入session信息,close关闭当前会话。
然后是登出,销毁session信息:
<?php // 自定义session处理方式 include 'custom_session.php'; echo '<br>before call session_start fun.<br>'; session_start(); $_SESSION = array(); //一次性删除存于$_SESSION中所有变量 if(isset( $_COOKIE[session_name()] ) ) { setcookie(session_name(), '', time()-3600, '/'); } echo '<br>before call session_destroy fun.<br>'; session_destroy();?><br><a href="login.php">relogin</a><br><?php echo '<br>script end.<br>'; ?>
同样,在session_start处做了标记,在调用session_destroy出标记了“before call session_destroy fun.”,在脚本结束时标记“script end.”,看看效果:
可以看到,在调用session_start后紧接着是open和read函数,然后走销毁程序,在调用session_destroy后紧接着会去调destroy和close函数,然后才是脚本的结束script end,进一步证明了这些函数的调用情形。
最后,session数据是不是保存到了我们指定的地方呢?look↓ 没跑
当然了,你也可以标记得更细致,来看看其中的道理~ note end
PHP编程
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。
新闻热点
疑难解答