增加PHP的Session存储和处理能力

  可能很多PHPer都用到了PHP提供的Session功能,可以方便的进行会话功能处理,PHP服务端默认的session存储是文件存放方式,在Windows上PHP默认的Session服务端文件存放在C:\WINDOWS\Temp下,*NIX下默认存放在/tmp下,如果说并发访问很大或者session建立太多,在这两个目录下就会存在大量类似sess_xxxxxx的session文件,同一个目录下文件数过多会导致性能下降,并且可能导致受到攻击最终出现文件系统错误。针对这样的情况,PHP本身体提供了比较好的解决办法。
  不少朋友可能都没有注意到php.ini里面Session设置部分中有这样一项:

;     session.save_path = "N;MODE;/path"


  这项设置提供给我们可以给session存放目录进行多级散列,其中“N”表示要设置的目录级数,“MODE”表示目录的权限属性,默认为600,在WINDOWS上基本是不用设置的,*NIX上也可以不用设置,后面的“/path”表示session文件存放的根目录路径,比如我们设置为下面的格式

session.save_path = "2;/tmp/phpsession"

  上面的设置表示我们把/tmp/phpsession目录作为php的session文件存放根目录,在该目录下进行两级目录散列,每一级目录分别是0-9和a-z共36个字母数字为目录名,这样存放session的目录可以达到36*36个,相信作为单台服务器来说,这是完全够用了,如果说您的系统架构设计为多台服务器共享session数据,可以把目录级增加到3级或者更多。
  需要注意的是,php自己并不会自动创建子目录,需要您自己动手去创建,网上找到这样的自动创建目录的代码,大家可以做个参考。下面的代码自动创建3级子目录,可以自己动手根据需要进行修改。

<?php
set_time_limit(0);
$string = '0123456789abcdefghijklmnopqrstuvwxyz';
$length = strlen($string);
function makeDir($param)
{
    
if(!file_exists($param)) {
        
makeDir(dirname($param));
        
mkdir($param);
    
}
}
for($i = 0; $i < $length; $i++) {
    
for($j = 0; $j < $length; $j++) {
        
for($k = 0; $k < $length; $k++) {
            
makeDir($string[$i].'/'.$string[$j].'/'.$string[$k]);
        
}
    
}
}
?>

  大家可能注意到前面的文字中提到了有关多服务器共享php的SESSION,这是很多应用都会遇到的问题,网上也有不少相关的资源,大家可以去google一下,Michael这里只提一下大概的思路。
  一般来说我们用到最多的方法有两种:
  1、NFS或者Samba共享的方法,让各个服务器上存放session文件的磁盘共享,这种方法简单可行。
  2、集中存储到数据库中,这是比较多的实现方法,通过php提供的session_set_save_handler()函数来重定义session函数,推荐使用这种方法。

  欢迎大家一起交流和讨论php中和session相关的技巧和经验。

Category: PHP / Zend
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
10 Responses
  1. diogin says:

    不错,以前就注意到这个功能,不过一直没试过,现在正好一试:)
    另外,关于session,我遇到了一个调试了几乎一个下午也没解决的问题,不知Michael有没有遇到过,简单地说就是下面的三段代码:

    index.php:

    diogin.php:

    another.php:

    这样,访问index.php,将新建一个session,然后删除,再检查cookie数组。这三段代码是能正常工作的,可以把session使用的cookie删除。但当我把类似的代码集成进系统后,想用setcookie来删除会话cookie,就行不通,调试了一下午都没解决。不知这里是不是有什么需要注意的事情我没察觉到,Michael遇到过类似的情况吗?

  2. diogin says:

    啊,奇怪,源代码怎么给过滤掉了?
    那再发一次,不好意思:)

    index.php:

    session_save_path(‘./’);
    session_name(‘DIOGIN_SESSID’);
    session_start();
    $_SESSION[‘diogin’] = ‘haha’;
    header(‘Location: diogin.php’);

    diogin.php:

    session_save_path(‘./’);
    session_name(‘DIOGIN_SESSID’);
    if (isset($_COOKIE[‘DIOGIN_SESSID’])) {
    session_start();
    $_SESSION = array();
    session_destroy();
    setcookie(‘DIOGIN_SESSID’, false);
    header(‘Location: another.php’);
    }

    another.php:

    var_dump($_COOKIE);

  3. Michael says:

    说实话,我仔细看了您的留言,但是我还没有搞明白你到底想实现的需求和功能,从你的代码来看,很少看到这样使用cookie和session的,不知道是为了满足什么需求,通常来说,session在我们的应用里面,迫不得已才使用,比如验证码图片,别的地方如果要使用到session,我们都是使用自己开发的session管理,session存储在内存数据库中。
    如有可能,你可以再把要实现的需求整理一下告知。

  4. Charles says:

    有一个将 PHP Session 利用 memcached 来保存的类。好像是一个丹麦的人写的。 🙂

  5. Michael says:

    [Comment ID #13354 Will Be Quoted Here]

    这位朋友说得很对,我用数据库保存过,为了多台机器共享session,用memcached原理一样,就是存储和读取的时候把从数据库改成从memcached操作,另外还可以使用共享内存,比如PHP的APC扩展。

  6. 逆雪寒 says:

    我 PHP.INI 知道有这个设置。但真不知道可以设置散列目录储存。
    一般我用session_save_path 不过好象这个函数并不支持目录散列。呵呵

  7. Michael says:

    [Comment ID #25801 Will Be Quoted Here]

    最新的pecl_memcached 扩展可以支持直接在php.ini里面设置类似这样的东西:
    session.save_handler = memcache
    session.save_path = “tcp://host:port?persistent=1&weight=2&timeout=2&retry_interval=15,tcp://host2:port2”

    比如设置:session.save_path = “tcp://127.0.0.1:11211″, 连接本机上11211端口的memcached来存储session

    详细的语法可以参考官方文档 php_memcache.h cvs log

  8. Michael says:

    最新的session共享和性能提升将使用memcached来存储session,见php.ini的文档部分就明白了,可以设置多个memcached给php的session来使用,并且可以配置各个mc的权重,这是我们现在主流的使用手段。

  9. 小赵 says:

    你好! 我想问一下 我用了 session_save_path 更改了session保存路径 后来发现我生成的sesion文件夹一直都没有删除过。 就是生成一个之后这一个文件一直都会在。请问这种 情况是什么 原因呢

  10. Michael says:

    你好!我想问一下 我用了 session_save_path 更改了session保存路径 后来发现我生成的sesion文件夹一直都没有删除过。 就是生成一个之后这一个文件一直都会在。请问这种 情况是什么 原因呢

    这个问题是这样的,php的session有自动回收机制,通过session.cookie_lifetime,session.gc_probability,session.gc_divisor以及session.gc_maxlifetime几个参数来控制,在满足条件的情况下,系统会自动进行垃圾回收,但是有一种情况,如果你在session.save_path选项中设定使用子目录来存储session数据文件,垃圾回收程序不会自动启动,你必须使用自己编写的shell脚本、cron项或者其他办法来执行垃圾文件处理。

    如我前面所说的,现在普遍采用的办法已经不是使用多集目录的方式来存储session文件,而是采用更高效的memcached或者redis等内存缓存来实现,建议你研究研究,在机器上配置一个memcached,很简单的,这样一劳永逸,还可以实现分布式的服务器之间共享session

Leave a Reply

Your email address will not be published. Required fields are marked *

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Anti-spam image