如何实现PHP的Session会话保持?

PHP

1 基础知识

1.1 概念

session是服务器保持会话数据的一种方法,对应cookie是在客户端保持用户数据。

1.2 出现理由

HTTP协议的无状态

1.3 PHP的Session设计构造

Session分以下几部分:
1)Session id
用户Session的唯一标识(随机生成,具有唯一性,随机性)
2)Session data
保存用户状态信息(用户数据)
3)Session file
Session的存储方式,文件存储方式以”sess_”前缀+”Session_id”后缀的方式存储
格式如下:

sess_d3eom13a9r9p5i5nj923voqaf7

4)Session lifetime
Session生存时间(从Session的产生到生命周期的结束)

1.4 工作原理

1)客户端与服务器建立联系
2)客户端将session id传递给服务器
3)服务器根据session id建立相应的session id文件(session id序列化保存,读取时反序列化)
唯一标识的方法有两种:cookie或者通过GET方式指定

1.5 Session的缺点

1)使用Session会影响系统性能(受文件系统设计影响,目录定义超过10000个文件非常耗时)
2)Session文件大小1~2K,数量庞大的小文件影响硬盘IO性能

1.6 Session配置文件

1.6.1 默认配置文件的路径

/etc/php.ini

1.6.2 查找配置文件

find / -name php.ini

显示如下:

/etc/php.ini

1.6.3 配置文件的参数

cat /etc/php.ini

可见如下配置:

[Session]
session.save_handler = files #session的存储方式
session.use_cookies= 1 #使用cookies在客户端保存会话
session.use_only_cookies = 1 #去保护URL中传送session id的用户
session.name = PHPSESSID #session名称(默认PHPSESSID)
session.auto_start = 0 #不启用请求自动初始化session
session.cookie_lifetime = 0 #cookie存活时间(0为直至浏览器重启,单位秒)
session.cookie_path = / #cookie的有效路径
session.cookie_domain = #cookie的有效域名
session.cookie_httponly = #httponly标记增加到cookie上(脚本语言无法抓取)
session.serialize_handler = php #PHP标准序列化

session.gc_probability =1
session.gc_divisor =1000 #建议设置1000-5000
#概率=session.gc_probability/session.gc_divisor(1/1000)
#页面访问越频繁概率越小
session.gc_maxlifetime =1440 #过期时间(默认24分钟,单位秒)

session.bug_compat_42 = off #全局初始化session变量
session.bug_compat_warn = off
session.referer_check = #防止带有ID的外部URL
session.entopy_length = 0 #读取的字节
session.cache_limiter = {nocache,private,pblic} #HTTP缓冲类型
session.cache_expire = 180 #文档过期时间(分钟)
session.use_trans_sid = 1 #trans_sid支持(默认0)
session.hash_function = 0 #hash方法{0:md5(128 bits),1:SHA-1(160 bits)}
session.hash_bits_per_character = 5 #当转换二进制hash数据奥可读形式是,每个字符保留位数
session.save_path = "/var/lib/php/session" #session id存放路径

1.6.4 session的保存目录

1)默认路径:

ls -l /var/lib/php/session

显示如下:

total 20
-rw-------. 1 apache apache   31 Jan 13 08:41 sess_0bl5a7anlurcguu1t8qbmjkus5
-rw-------. 1 apache apache 1320 Nov 24 16:40 sess_brv2cvkbhiqehpqu7tgabuvo81
-rw-------. 1 apache apache   31 Jan 13 08:39 sess_d3eom13a9r9p5i5nj923voqaf7
-rw-------. 1 apache apache   31 Jan 13 08:47 sess_j04uc0jaia0sr4qjdrull99hh0
-rw-------. 1 apache apache   31 Jan 13 07:03 sess_me2vo12m5vnlpk1s0oj60mgqv1
-rw-------. 1 apache apache    0 Jan 13 08:41 sess_s4q1ivktojrm8ruv54ob12tol1
-rw-------. 1 apache apache    0 Jan 13 08:41 sess_u3mcdh4cs329131eo6tk7hts22

2)路径查找方法:

 find / -name session

显示如下:

/var/lib/php/session

3)配置文件自定路径

grep session.save_path /etc/php.ini

会发现如下行:

session.save_path = "/var/lib/php/session"

注:session.save_path定义的路径需手动创建并赋予apache用户读写权限。
4)分层子目录定义

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

注:
— N定义目录层数(例如2,目录需手动创建)
— MODE定义单目录最大会话文件数量(默认8进制600)
5)分层子目录的生成脚本
源代码tar包含名称为“mod_files.sh”的分层子目录生成脚本,代码如下:

#!/usr/bin/env bash

if [[ "$2" = "" ]] || [[ "$3" = "" ]]; then
       echo "Usage: $0 BASE_DIRECTORY DEPTH HASH_BITS"
       echo "BASE_DIRECTORY will be created if it doesn't exist"
       echo "DEPTH must be an integer number >0"
       echo "HASH_BITS(session.hash_bits_per_charactor) should be one of 4, 5, or 6"
       exit 1
fi

if [[ "$2" = "0" ]] && [[ ! "$4" = "recurse" ]]; then
       echo "Can't create a directory tree with depth of 0, exiting."
fi

if [[ "$2" = "0" ]]; then
       exit 0
fi

directory="$1"
depth="$2"
hashbits="$3"

hash_chars="0 1 2 3 4 5 6 7 8 9 a b c d e f"

if [[ "$hashbits" -ge "5" ]]; then
       hash_chars="$hash_chars g h i j k l m n o p q r s t u v"
fi

if [[ "$hashbits" -ge "6" ]]; then
       hash_chars="$hash_chars w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z - ,"
fi

while [[ -d $directory ]] && [[ $( ls $directory ) ]]; do
       echo "Directory $directory is not empty! What would you like to do?"

       options="\"Delete directory contents\" \"Choose another directory\" \"Quit\""
       eval set $options
       select opt in "$@"; do

              if [[ $opt = "Delete directory contents" ]]; then
                     echo "Deleting $directory contents... "
                     rm -rf $directory/*
              elif [[ $opt = "Choose another directory" ]]; then
                     echo "Which directory would you like to choose?"
                     read directory
              elif [[ $opt = "Quit" ]]; then
                     exit 0
              fi

              break;
       done
done

if [[ ! -d $directory ]]; then
       mkdir -p $directory
fi


echo "Creating session path in $directory with a depth of $depth for session.hash_bits_per_character = $hashbits"

for i in $hash_chars; do
       newpath="$directory/$i"
       mkdir $newpath || exit 1
       bash $0 $newpath `expr $depth - 1` $hashbits recurse
done

使用格式如下:

bash mod_files.sh   

directory — Session目录存放的根目录
depth — 目录的深度
hashbits — 哈希值(散列值)
使用范例(N=2):

bash mod_files.sh /var/lib/php/session 2 5

生成的目录名称大致如下:
— 有传参下子目录名称一般以16进制”0 1 2 3 4 5 6 7 8 9 a b c d e f”字母命名
— 传参设置hashbits=5 以上加字母”g h i j k l m n o p q r s t u v”
— 传参设置hashbits=6 以上加字母”w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z – ,”

1.6.5 session的保存方式

1)文件方式保存

session.save_handler = files

2)处理器方式(如mysql)

session.save_handler = user

1.6.6 开启客户端会话保存

session.use_cookies = 1

1.7 Session的同步

场景:应用程序层有多台服务器,服务器之间做负载均衡,可通过如下方式解决:
1)Session存储于数据库
2)存储于共享存储(NFS)
3)负载均衡器保持会话

1.8 Session的管理脚本

删除24分钟内没有被改变的Session文件

cd /var/lib/php/session; find -cmin +24 | xargs rm

1.9 内存直存Session的方法

内存直接存储Session可以改善Session存储的性能(重启丢失),设置方法如下:

vim /etc/php.ini

修改如下参数

session.save_path = "/dev/shm"

注:”/dev/shm”相当于内存入口

2、实践部分

2.1 基础环境配置

请参阅如下文档配置PHP环境:
http://www.cmdschool.org/archives/361

2.2 yum源安装

yum -y install wget tree

2.3 配置部分

2.3.1 step1

官方下载源安装包
http://php.net/downloads.php

cd ~
wget http://cn2.php.net/distributions/php-7.0.2.tar.bz2

2.3.2 step2

解压源码包

tar -xf php-7.0.2.tar.bz2

2.3.3 step3

执行设置脚本

cd php-7.0.2/ext/session
bash mod_files.sh /var/lib/php/session/ 2 5
chown -R apache:apache /var/lib/php/session/
chmod 700 -R /var/lib/php/session/

2.3.4 step4

检查目录结构

tree /var/lib/php/session/

显示如下:

/var/lib/php/session/
├── 0
│   ├── 0
│   ├── 1
│   ├── 2
│   ├── 3
│   ├── 4
│   ├── 5
│   ├── 6
│   ├── 7
│   ├── 8
│   ├── 9
│   ├── a
│   ├── b
│   ├── c
│   ├── d
│   ├── e
│   ├── f
│   ├── g
│   ├── h
│   ├── i
│   ├── j
│   ├── k
│   ├── l
│   ├── m
│   ├── n
│   ├── o
│   ├── p
│   ├── q
│   ├── r
│   ├── s
│   ├── t
│   ├── u
│   └── v
├── 1
│   ├── 0
│   ├── 1
│   ├── 2
#中间有节删
1056 directories, 0 files

2.3.5 step5

检查目录权限

ls -l /var/lib/php/session/

2.3.6 step6

重启httpd服务使PHP的Session相关设置生效

/etc/init.d/httpd restart

2.3.7 step7

增加测试代码:

vim /var/www/www.cmdschool.org/test.php

创建如下代码:

<?php
session_start();
$_SESSION["user_name"]="cmdschool.org";
echo $_SESSION["user_name"];
echo "&nbsp;<a href=\"test2.php\">test2</a>"
?>

增加测试代码2:

vim /var/www/www.cmdschool.org/test2.php

创建如下代码:

<?php
session_start();
echo $_SESSION["user_name"];
?>

2.3.8 step8

模拟DNS解析:

notepad %SystemRoot%\System32\drivers\etc\hosts

建立如下映射:

10.168.0.170 www.cmdschool.org

2.3.9 step9

测试与检查:
1)浏览器测试
http://www.cmdschool.org/test.php

如上图所示:
本页生成Session变量”user_name”并赋值”cmdschool.org”
单击【test2】跳转页面

如上图所示:
本页输出Session变量”user_name”的值”cmdschool.org”
2)日志检查

tail /var/log/httpd/error_log

3)检查生成的Session文件

tree /var/lib/php/session

显示如下:

#前有节删
├── n
│   ├── 0
│   ├── 1
│   ├── 2
│   ├── 3
│   ├── 4
│   ├── 5
│   ├── 6
│   ├── 7
│   ├── 8
│   ├── 9
│   ├── a
│   ├── b
│   ├── c
│   ├── d
│   ├── e
│   ├── f
│   ├── g
│   ├── h
│   ├── i
│   ├── j
│   ├── k
│   ├── l
│   ├── m
│   ├── n
│   ├── o
│   │   └── sess_no8luf5jctfd2igrqikpc6mji2
#后有节删

文件查阅

cat /var/lib/php/session/n/o/sess_no8luf5jctfd2igrqikpc6mji2

显示如下:

user_name|s:13:"cmdschool.org";

———————————————————————-
参考文件:
PHP Session的工作原理:
http://www.nowamagic.net/librarys/veda/detail/358
http://www.cnblogs.com/acpp/archive/2011/06/10/2077592.html
http://blog.163.com/lgh_2002/blog/static/4401752620105246517509/
PHP使用Session:
http://www.jb51.net/article/42500.htm
CentOS Session配置:
http://www.centoscn.com/CentOS/Intermediate/2013/1126/2147.html
http://www.2cto.com/os/201202/120886.html
MySQL保存Session的代码:
http://www.jb51.net/article/54226.htm
http://www.oschina.net/code/snippet_59519_2940
PHP多级目录设置方法:
http://www.tuicool.com/articles/Rfa6rii

没有评论

发表评论

PHP
如何编译安装Apache+PHP8.1.1?

1 前言 笔者平素不喜欢简单的编译安装,因为很多系统管理员为了省事,编译安装的东西没有rpm包安装那 …

Apache
如何编译安装Apache+PHP7.4.3?

1 前言 笔者平素不喜欢简单的编译安装,因为很多系统管理员为了省事,编译安装的东西没有rpm包安装那 …

Apache
如何打包Docker Apache+PHP 7.4.11(可连MySQL)?

1 基础知识 以下版本基于MySQL数据库的连接,本章节需要你先掌握Linux系统的PHP 7.4. …