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"后缀的方式存储
格式如下:
1 | 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、默认配置文件的路径
1 | /etc/php .ini |
1.6.2、查找配置文件
1 | find / -name php.ini |
显示如下:
1 | /etc/php .ini |
1.6.3、配置文件的参数
vim编辑/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)默认路径:
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)路径查找方法:
1 | find / -name session |
显示如下:
1 | /var/lib/php/session |
3)配置文件自定路径
1 | grep session.save_path /etc/php .ini |
会发现如下行:
1 | session.save_path = "/var/lib/php/session" |
注:session.save_path定义的路径需手动创建并赋予apache用户读写权限。
4)分层子目录定义
1 | 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 |
使用格式如下:
1234 | bash mod_files.sh <directory> <depth> <hashbits> directory -- Session目录存放的根目录 depth -- 目录的深度 hashbits -- 哈希值(散列值) |
使用范例(N=2):
1 | 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)文件方式保存
1 | session.save_handler = files |
2)处理器方式(如mysql)
1 | session.save_handler = user |
1.6.6、开启客户端会话保存
1 | session.use_cookies = 1 |
1.7、Session的同步
场景:应用程序层有多台服务器,服务器之间做负载均衡,可通过如下方式解决:
1)Session存储于数据库
2)存储于共享存储(NFS)
3)负载均衡器保持会话
1.8、Session的管理脚本
删除24分钟内没有被改变的Session文件
1 | cd /var/lib/php/session ; find -cmin +24 | xargs rm |
1.9、内存直存Session的方法
内存直接存储Session可以改善Session存储的性能(重启丢失),设置方法如下:
vim编辑/etc/php.ini
修改如下参数
1 | session.save_path = "/dev/shm" |
注:"/dev/shm"相当于内存入口
2、实践部分
2.1、基础环境配置
请参阅如下文档配置PHP环境:
http://cmdschool.blog.51cto.com/2420395/1708325
2.2、yum源安装
1 | yum -y install wget tree |
2.3、配置部分
2.3.1、step1
官方下载源安装包
http://php.net/downloads.php
12 | cd ~ wget http: //cn2 .php.net /distributions/php-7 .0.2. tar .bz2 |
2.3.2、step2
解压源码包
1 | tar -xf php-7.0.2. tar .bz2 |
2.3.3、step3
执行设置脚本
1234 | 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
检查目录结构
1 | 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
检查目录权限
1 | ls -l /var/lib/php/session/ |
2.3.6、step6
重启httpd服务使PHP的Session相关设置生效
1 | /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 " <a href=\"test2.php\">test2</a>" ?> |
vim编辑/var/www/www.cmdschool.org/test2.php
创建如下代码:
<?php session_start(); echo $_SESSION[ "user_name" ]; ?> |
2.3.8、step8
模拟DNS解析:
1 | notepad %SystemRoot%\System32\drivers\etc\hosts |
建立如下映射:
1 | 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)日志检查
1 | tail /var/log/httpd/error_log |
3)检查生成的Session文件
1 | 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 #后有节删 |
文件查阅
1 | cat /var/lib/php/session/n/o/sess_no8luf5jctfd2igrqikpc6mji2 |
显示如下:
1 | 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