从零开始之ecshop基础篇(20)_项目管理_非技术区_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 非技术区 > 项目管理 > 从零开始之ecshop基础篇(20)

从零开始之ecshop基础篇(20)

 2013/12/15 15:09:30  cnblogs`  博客园  我要评论(0)
  • 摘要:处理session数据当服务器端所保存的session数据,变的数量数量巨大是,如何更好地管理?子目录形式保存session数据文件如果以文件的形式出现,目录内的文件过多,应该将目录分子目录管理:通过简单的服务器的配置,就可以将session分子目录保存session.save_path:保存路径session.save_path="N:e:/php1116/temp";(php.ini)——表示目录以N级子目录的形式管理:表示,在temp下建立N级的子目录确定子目录的方法是
  • 标签:

处理session数据

当服务器端所保存的session数据,变的数量数量巨大是,如何更好地管理?

子目录形式保存session数据文件

如果以文件的形式出现,目录内的文件过多,应该将目录分子目录管理:

通过简单的服务器的配置,就可以将session分子目录保存

session.save_path:保存路径

session.save_path = "N:e:/php1116/temp";(php.ini)——表示目录以N级子目录的形式管理:表示,在temp下建立N级的子目录

确定子目录的方法是,依据session的首字母,确定第一集子目录名。

类推,几级子目录,就是使用第几个sessionID的字母,来确定名字。

注意:该子目录需要手动创建子目录。

Tips:如何确定sessionID的每个字母的可能性字符?

确定的方式,由配置文件(php.ini)session.hash_bits_per_character = 5 决定,表示的是,sessionID中,每个字符,表示几个二进制位。从而决定了sessionID的每个字符的可能性:

????sessionID的总长度是固定的(128bit位),为了方便表示成字符的形式。

????当前的这个配置,指的是,使用每个字符,表示几个二进制位的意思。

????默认5个,一个字符,表示5个位。5个位的组合,有32中可能性(00000—11111(2^5-1)由0-9,a-v)。

重写session的存储机制

如果session数据需要共享如何处理?

????当站点负载太大,一台web服务器支持不了!此时将session数据,放置在一台数据服务器上。(mysql,memcache内存数据服务器)

????以session数据存储在mysql服务器上为例,说明,session的存储机制重写(session入库)

????

????至少:1,在session开启时,完成读数据。

????????2,在脚本结束时,将数据写入。

????改写,默认的session在存储读取数据的处理代码,完成其他位置的数据的存储读写:

????告知PHP,在需要读session数据和谐session数据时,使用用户设置的行为(定义可以完成读和写的方法)

需要六个方法才能完成seesion数据的存储工作?

1
2
3
4
5
6
7
8
9
10
11
12
13
14

?

<?php
//定义几个需要储存session数据的方法
function?sess_read()?{
}
function?sess_write()?{
}?
function?sess_destroy()?{
}
function?sess_open()?{
}
function?sess_close()?{
}
function?sess_dc()?{
}

?

将六个方法,设置成session可以自动处理调用的方法

内置函数session_set_save_handler(开始,关闭,读,写,销毁,垃圾回收);

1
2
3
4
5
6
7
8
9

?

<?php
session_set_save_handler(
????'sess_open',
????'sess_close',
????'sess_read',
????'sess_write',
????'sess_destroy',
????'sess_gc'
);

?

session入库,建立session数据表

session表中每条记录????对应????session文件

sess_id字段????????对应????session文件名

sess_data字段????????对应????session文件内容

读,sess_read

在该方法运行时,sessionID一定是确定好了的(PHP核心)。

接收的参数是:$sess_id当前的sessionID,返回值是session数据的内容即可,不需要反序列化(PHP核心)。如果没读到,返回数据为空字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

?

<?php
function?sess_read($sess_id)?{
????//连接数据
????mysql_connect('127.0.0.1','root','1234abcd');
????mysql_query('set?names?utf8');
????mysql_query('use?itcast');
????//读数据
????$sql?=?"select?sess_data?from?`session`?where?sess_id?=?'$sess_id'";
????$result?=?mysql_query($sql);
????if?($row?=?mysql_fetch_assoc($result))?{
????????return?$row['sess_data'];
????}?else?{
????????return?'';
????}
}

?

写,sess_write

负责将session数据保存到session表内,不需要我们序列化(PHP核心完成)

需要的参数:

当前的sessionID和买药存储的数据

1
2
3
4
5
6
7
8
9
10

?

<?php
function?sess_read($sess_id)?{
????//连接数据
????mysql_connect('127.0.0.1','root','1234abcd');
????mysql_query('set?names?utf8');
????mysql_query('use?itcast');
????//存在则更新,不存在则插入
????$sql?=?"insert?into?`session`?values?('$sess_id','$sess_data')?on?duplicate?key?update?sess_data='$sess_data'";
????$result?=?mysql_query($sql);
}

?

销毁,sess_destroy()

删除,当前session表中,当前session记录

得到当前的sessionID,执行delete,以sessionID作为条件

当用户脚本调用了session_destroy()函数后,该自定义函数被调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

?

<?php

/**
?*?销毁
?*
?*?@param?$sess_id?string
?*
?*?@return?bool
?*/
?function?sess_destroy($sess_id)?{
????//连接数据
????mysql_connect('127.0.0.1:3306','root','root');
????mysql_query('set?names?utf8');
????mysql_query('use?itcast');
????$sql?=?"delete?from?`session`?where?sess_id='$sess_id'";
????return?mysql_query($sql);
?}

?

开始,sess_open

初始化,session存储所需要的资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

?

<?php

<?php

/**
?*?开始
?*?初始化资源
?*
?*/
?function?sess_open()?{
????//连接数据
????mysql_connect('127.0.0.1:3306','root','root');
????mysql_query('set?names?utf8');
????mysql_query('use?itcast');
?}

Tips:接收到$sess_name,$sess_path参数:

$sess_name,cookie中,保存sessionID的cookie变量的名:

PHPSESSID

session.name = PHPSESSID(php.ini),可以使用php函数session_name()得到当前的配置值(ini_get('session.name'))

$sess_path指的是session的存储路径看,session.save_path配置

关闭,sess_desc

session存储时占用的资源,典型的return true

1
2
3
4

?

<?php
function?sess_close()?{
????return?true;
}

垃圾回收,sess_gc();

session的有效期是关闭浏览器失效。原因是:浏览器所保存的sessionID是临时性的,关闭浏览器丢失。

问题1:如何识别那些记录(文件)是垃圾?

????判断哪些记录(文件),在多久之后已经没有被使用过了就认为是垃圾。默认是1440是,24m

????session.gc_maxlifrtime = 1440(php.ini)

问题2:如何删除?

????记录下来当前数据(文件)的最后的处理时间:

????增加一个字段保存,最后的修改时间

????

????在写的时候,记录当前的时间戳才可以:

1
2
3
4
5
6

?

<?php
function?sess_write($sess_id,$sess_data)?{
????//存在则更新,不存在测插入
????$sql?=?"insert?into?`session`?values?('$sess_id',$sess_data',unix_timestamp())?on?duplicate?key?update?sess_data='$sess_data',expire=unix_timpstamp()";
????return?mysql_query($sql);
}

????怎么执行?在session_start()开启session机制时,有机率的调用垃圾回收方法来找到过期的session数据并把它删除。

????机率由以下几个配置决定:

????可能性:session.gc_probability = 1

????除数 :session.gc_divisor = 1000

????1/1000的可能性。

????sess_gc(),可以得到当前的最大保存周期为参数

1
2
3
4
5
6
7
8
9
10

?

<?php
/**
?*?垃圾回收
?*
?*?@param?$maxlifetime
?*/
?function?sess_gc($maxlifetime)?{
????$sql?=?"delete?from?`session`?where?expire?<?unix_timstamp()?-?$maxlifetime";
????return?mysql_query($sql);
?}

注意

应该先重写session的存储机制,再开启session

seesion_set_save_handler();

session_start();

如果session设置为自动开启怎么办?

????此时,ini_set();也不顶用。因为自动开启,意味着用户脚本执行前,开启完毕了。

????可以利用Apache的配置文件,.htaccess分布式配置文件完成。

????php_flag session.auto_start 0(0,表示关闭php的自动开启,也就是说Apache的配置文件可以控制php的配置文件)

项目中的session入库的处理

增加一个session入库的工具类(SessionDBTool.class.php)。在框架目录中,为工具类,独立使用子目录进行管理。

六个处理函数,都由对象的方法完成

在open的时候,完成数据库的连接。利用mysqlDB类完成,增加一个属性保存MySQLDB类的对象,在open执行是,得到该对象。

1
2
3
4
5
6
7
8
9
10

?

<?php
private?$db;
/**
?*?开始
?*?初始化资源
?*/?
?function?sess_open()?{
????//连接数据
????$this->db?=?new?MySQLDB($GLOBALS['config']['database']);
?}

余下的所有数据库的操作,有$this->db完成:

1
2
3
4
5
6
7

?

<?php
function?sess_read($sess_id)?{
????//读数据
????$sql?=?"select?sess_data?from?`session`?where?sess_id?=?'$sess_id'";
????return?(string)?$this->db->fetchColumn();//得到的数据一定是个字符串?
}
?

1
2
3
4
5
6
7
8
9
10
11

?

<?php
/**
?*?垃圾回收
?*
?*?@param?$maxlifetime
?*/
function?sess_gc($maxlifetime)?{
????//读数据
????$sql?=?"delete?from?`session`?where?expire?<?unix_timestamp()-$maxlifetime";
????return?$this->db->query($sql);
}

处理表:保证数据库内存在it_session表

创建该表

将语句内都改成正确的格式:

1
2
3
4
5
6

?

<?php
function?see_write($sess_id,$sess_data)?{
????//存在则更新,不存在则插入
????$sql?=?"insert?into?`it_session`?values?('$sess_id','$sess_data',unix_timestamp())?on?duplicate?key?update?sess_data='$sess_data'";
????return?$this->db->query($sql);
}

将权限改成public

在得到SessionDBTool类对象时,就完成session处理器的设置,与开启session机制

增加该类对象的构造方法。设置处理器,此时是由六个对象方法,充当的session数据的处理器。使用一个数组,第一元素是对象,第二元素是方法名,来实现:

1
2
3
4
5
6
7
8
9
10
11
12

?

<?php
/**
?*?构造
?*/
?public?function?__construct()?{
????array($this,'sess_open'),
????array($this,'sess_close'),
????array($this,'sess_read'),
????array($this,'sess_write'),
????array($this,'sess_destroy'),
????array($this,'see_dc')
?};

开启session

使用session入库

凡事session_start(),则直接实例化该类对象即可。

back/AdminController????signinAction()

1
2
3
4
5
6
7

?

if?($result)?{
????//合法管理员
????//记录登录标识
????//使用SessionDB工具
????new?SessionDBTool;
????$_SESSION['is_login']?=?'yes';
}

back/IndexController????IndexAction()

1
2
3
4

?

public?function?indexAction()?{
????//判断当前是否登陆
????new?SessionDBTool;
}

为工具类增加自动加载操作

以规则的方式:

framework/Framework.class.php????static userAutoload()

1
2
3
4

?

//是否是工具类
elseif?(substr($class_name,-4)?==?'Tool')?{
????require?FRAME_TOOL_PATH.$class_name.'.class.php';
}

将这个目录常量设置好:framework/Framework.class.php????static initPath()

1
2
3

?

private?static?function?initPath()?{
????define('FRAME_TOOL_PATH',FRAME_PATH.'tool'.DS);//工具类目录
}

测试:shop.235.com/index.php?p=back&c=Index&a=index

Tips:应该再修改一个配置session.save_handler=files,最好将这个值,改成user,表示用户自定义。ini_set('session.save_handler','user');

1
2
3
4
5

?

<?php
public?function?__construct()?{
????//以用户的方式,存储session数据
????ini_set('session.save_handler','user');
}

?

session补充问题

问题1:如何持久化sessio数据

session,在浏览器关闭就失效了。原因是cookie中的sessionID丢失了。延长seesionID的cookie变量的生命周期即可。

setcookie(名,值,有效期)名:session_name;值:session_id();

setcookie(session_name(),session_id(),time()+3600);

$_SESSION['where'] = 'itcast-php';

php同时提供一个专门的函数:session_set_cookie_params(有效期,有效路径,有效域名);//设置一下session相关的cookie变量(sessionID变量)的参数信息

有效期:时间区间的概念,不是时间戳。

session_set_cookie_params(3600);

session_start();

firbug或者自带查看器(网络),查看Set-Cookie

Tips:将session数据的垃圾判定时间加长,session.gc_maxlifetime = 3600

问题2:cookie禁用,session是否可用

session的sessionID保存在cookie内。典型的,如果浏览器用户强制禁用了cookie技术,则浏览器用户放弃会话技术,不提供对session的支持。(例如Firefox)

技术上,可以实现,找到可以在多次请求间传递数据的方案,就可以传递sessionID,典型的使用URL上传递PHPSESSID=随机生成的名字,即可

session.user_only_cookies设置为0(php.ini),表示可以用其他的方案传递sessionID

session.user_trans_sid设置成1(php.ini),表示自动传输到sessionID在url上(或者表单内部)

此时,如果浏览器金庸了cookie,则php会自动地在所有的超链接的href属性的url值上,增加一个参数PHPSESSID值为当前的sessionID(观察浏览器请求地址栏)

在form表单内可以自动生成,典型为,value="随机生成的名字" name="PHPSESSID"

Tips:使用php输出的url字符串,不能自动增加该参数:需要手动添加。 ?

1
2
3

?

$_SESSION['where']?=?'itcast-php';
header('Location:103.php?'.session_name().'='.session_id());
?>

后台首页完整展示

整体页面

控制器

back/IndexController????IndexAction()

模型????暂时没有

视图????

view/back/index.html

采用框架集的布局模式:frameset框架集????frame框架????采用(上,左中右)

因此后台首页的整体需要: 整体 、上、左、中、右5个功能才能完成。每个功能应该为一个动作。

我们把exshop的后台首页拿来用,修改frame下的src为我们定义的参数

例如:top:????src="index.php?p=back&c=Index&a=top"

back/IndexController创建四个动作,topAction(),menuAction(),dragAction(),mainAction

浏览器:shop.235.com/index.php?p=back&c=Index&a=index(Firefox查看发出5个请求)

top页面

控制器

back/IndexController????topAction()????加载top部分的视图

1
2
3

?

public?function?topAction()?{
????require?CURRENT_VIEW_PATH?.?'top.html';
}

模型

视图????back/top.html????Tips:注意修改href中CSS的路径

menu页面

drag页面

main页面

后台整体的登陆权限的控制

除了index动作之外,后台所有的动作都需要登陆后才能执行。如何增加一段,可以在某个平台内,都执行的代码?(增加平台基础控制器)

?

平台基础控制器

在每个平台的控制目录下:

1
2
3

?

<?php
class?PlatformController?extends?Controller?{
}

当前平台的其他控制器继承:

1
2
3
4
5
6
7
8
9
10
11

?

<?php
/**
?*?后台首页控制器类
?*/
?class?IndexController?extends?PlatformController?{
}
/**
?*?后台管理员控制器类
?*/
?class?AdminController?extends?PlatformController?{
?}

?

增加后台的公共功能,验证用户是否登陆

back/PlatformController????checkLogin()

1
2
3
4
5
6
7
8
9

?

<?php
class?PlatformController?extends?Controller?{
????/**
?????*?验证管理员是否登陆
?????*/
?????protected?function?checkLogin()?{
?????
?????}
}

在控制器方法执行前,先判断当前用户是否登陆。

实例化控制器对象。在公共后台平台控制器的构造方法中,完成对验证是否登陆的调用。

back/PlatformController????__construct()

1
2
3
4
5
6
7
8
9

?

<?php
class?PlatformController?extends?Controller?{
????/**
?????*?验证管理员是否登陆
?????*/
?????protected?function?checkLogin()?{
????????$this->checkLogin();
?????}
}

完成登陆验证的方法

back/PlatformController????checkLogin()

后台,所有的,但是除了登陆相关的动作,才需要验证。因此,在验证是否登陆是,先排除当前不需要验证的动作:

1
2
3

?

if?(CONTROLLER_NAME?!=?'Admin'?||?!in_array(ACTION_NAME,array('login','signin')))?{
????//验证
}

验证码

验证码是干什么用的?防止计算机,模拟浏览器提交表单,速度快,次数多,得到可以被登陆后才可以看到的数据。

典型的:暴力破解,论坛灌水,恶意评论。

验证原理?

验证码生成

将可能的值,形成一个合集,丛集合中随机获取。

session技术

生成图片技术

gd就是php中最常用的图片处理技术。

GD的图片处理

首先开启gd扩展:extendsion=php_gd2.dll(php.ini)

gd的基本使用流程:

PHP操作图片的工具即可。就类似用户操作图片处理软件一样

场景:利用PHP制作一张 纯色的绿色的500 * 400 的图片

新建一个画布资源

利用函数:创建新画布(新建)

imagecreatetruecolor(),创建一个真彩色图片画布

imagecreate(),创建一个调色板图片画布,需要提供尺寸,宽,高

基于原有图片创建(打开)

imagecreatefromXXX()其中XXX表示图片格式

imagecreatefromjpeg(),imagecreatefrompng(),imagecreatefromgif()

操作画布

利用gd提供的各种工具函数(写字,填充,画矩形,画圆),去完成对画布的操作。

使用绿色填充当前画布

选择颜色(分配颜色)????将颜色分配到画布上,此画布,可以使用该颜色进行操作

????函数:imagecolorallocate();为画布分配颜色

????颜色标识 = imagecolorallocate(画布,R,G,B);

????采用RGB颜色管理方式,设置颜色,每个颜色值在0—255之间的整数

????

填充画布????imagefill()函数可以完成填充

????填充结果 = imagefill(画布,填充位置X,填充位置Y,颜色)

????将填充点的周围相邻的颜色相同的点进行填充。

????填充位置表示:使用填充点的坐标表示(X,Y)。原点在哪里,左上角,在画布的左上角,范围从(0,0)开始表示原点到右下角 X-1,Y-1

????

输出图片

一个画布资源,可以输出任意多次,并且可以保存成任意格式。

使用函数:????imageXXX()XXX表示类型

????????imagejpeg()输出jpeg

????????imagepng()输出png

????????imagegif()输出gif

imageXXX(画布)支持,直接输出到浏览器,或者输出到某个文件内,

如果增加第二个参数,则表示输出到文件。

如果没有第二个参数,则输出到浏览器。

但是,浏览器会将服务器做出的响应数据当作文本html字符串看,因此,需要告知浏览器,服务器个你的响应数据,是图片png格式的图片:

使用header()函数,header('Content-Type:image/png');

释放资源

imagedestroy(画布)

模拟ecshop生成验证码图片

背景在优先的图片内随机切换、白色边框、码值由大写字母和数字组成、颜色(黑白随机)

新建画布

去ecshop下把图片拿到captcha文件夹

随机得到图片名,基于该图片,创建画布:画布 = imagecreatefromjpeg(文件地址);

操作

增加白色边框(画一个矩形即可)

利用一个函数:结果 = imagerectangle(画布,左上角X,左上角Y,右下角X,右下角Y,颜色);

分配白色:

写码值????生成码值

保存到session:

将字符串写到图片上:结果 = imagestring(画布,字体大小,位置X,位置Y,字符串,颜色);

字体大小:1-5,由小到大

颜色,黑白随机

输出

销毁

测试:

  • 相关文章
发表评论
用户名: 匿名