Gowhich

Durban's Blog

关于session的memcache的存储,原因为什么要使用它。要看你的项目的需求,网站访问量大的话,默认使用session的文件存储,会导致一个问题就是用户登录不了,原始是,session文件的大量生成,导致读取文件出现问题,就是IO的问题,这时候我们可以考虑使用memcache,还有另外一种是mysql的使用方式。但是目前对于我的这个项目还打不到这种需求,so,还是使用memcache吧。

目前又因为我的项目是使用Qeephp,哈哈,估计现在使用的人少了,不过这里还是说一下,使用他如何进行配置吧。

用过qee的都知道,qee有个文件叫做myapp的文件,ok,解决的问题的办法就在这里。

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
// 打开 session
if (Q::ini('runtime_session_start'))
{
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");
session_start();

// #IFDEF DEBUG
QLog::log('session_start()', QLog::DEBUG);
QLog::log('session_id: ' . session_id(), QLog::DEBUG);
// #ENDIF
}

其实就是在打开session的地方加上了关于session的存储设置

1
2
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");

memcache考虑的还是蛮周到。

关于memcache的安装,请使用站内搜索

关于Memcache与memcached

Memcache是项目名,memcached是服务名。让很多初接触的人感觉很是莫名其妙。个人认为正确的应该是用前者用更为正确一点。

1)安装Memcache服务端

1
sudo apt-get install memcached

安装完Memcache服务端以后,我们需要启动该服务:

1
memcached -d -m 128 -p 11211 -u www

memcached服务的启动参数:

-p 监听的端口
-l 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u 以的身份运行 (仅在以root运行的时候有效)
-m 最大内存使用,单位MB。默认64MB
-M 内存耗尽时返回错误,而不是删除项
-c 最大同时连接数,默认是1024
-f 块大小增长因子,默认是1.25-n 最小分配空间,key+value+flags默认是48
-h 显示帮助

我们使用php脚本做一个测试(这个是在qeephp里面做的测试)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public function actionTestMema(){
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");
session_start();
$_SESSION['test0'] = 'my value';
$_SESSION['test1'] = 'Thisvalue';
$sid = session_id();

echo "<a href='".url('default/testmemb',array('sid'=>$sid))."'>session</a>";
}

public function actionTestMemb(){
$mem = new Memcache();
$mem->connect('127.0.0.1',11211);

if(isset($_REQUEST['sid'])){
$value = $mem->getstats();
// var_dump($value);
$sess_value = $mem->get($_REQUEST['sid']);
var_dump($sess_value);
echo $sess_value;
}else{
echo "error args";
}
}

其中:

1
2
3
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");
session_start();

这句话是应该放在myapp.php这个文件中的

1
2
3
4
5
6
7
8
9
10
11
12
// 打开 session
if (Q::ini('runtime_session_start'))
{
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");
session_start();

// #IFDEF DEBUG
QLog::log('session_start()', QLog::DEBUG);
QLog::log('session_id: ' . session_id(), QLog::DEBUG);
// #ENDIF
}

如果你的输出结果是类似下面这样的话

1
string(2044) "test0|s:8:"my value";test1|s:9:"Thisvalue";

说明你的安装就成功了,以上是在非命令行模式下测试的。如果你是cli命令行的话,我不能保证。

第一步:首先是下载文件:

下载地址

http://projects.unbit.it/downloads/

这里面有你自己想要的文件版本

第二步:执行两条命令

1
2
yum update
yum install python python-devel libxml2 libxml2-devel python-setuptools zlib-devel wget openssl-devel pcre pcre-devel sudo gcc make autoconf automake

第三步:解压安装

1
2
3
4
5
tar -zxvf uwsgi-0.9.6.5.tar.gz
mv uwsgi-0.9.6.5/ uwsgi/
cd uwsgi/
sudo python setup.py build
make

第四步:将安装成功的uwsgi文件copy一份到自己使用bin目录下,我的是copy到了/usr/local/bin目录

第五步:测试是否安装成功

1
uwsgi --help

会打印出类似下面的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Usage: /usr/local/bin/uwsgi [options...]
-s|--socket bind to the specified UNIX/TCP socket using default protocol
-s|--uwsgi-socket bind to the specified UNIX/TCP socket using uwsgi protocol
--http-socket bind to the specified UNIX/TCP socket using HTTP protocol
--http-socket-modifier1 force the specified modifier1 when using HTTP protocol
--http-socket-modifier2 force the specified modifier2 when using HTTP protocol
--fastcgi-socket bind to the specified UNIX/TCP socket using FastCGI protocol
--fastcgi-nph-socket bind to the specified UNIX/TCP socket using FastCGI protocol (nph mode)
--fastcgi-modifier1 force the specified modifier1 when using FastCGI protocol
--fastcgi-modifier2 force the specified modifier2 when using FastCGI protocol
--scgi-socket bind to the specified UNIX/TCP socket using SCGI protocol
--scgi-nph-socket bind to the specified UNIX/TCP socket using SCGI protocol (nph mode)
--scgi-modifier1 force the specified modifier1 when using SCGI protocol
--scgi-modifier2 force the specified modifier2 when using SCGI protocol
--protocol force the specified protocol for default sockets
--socket-protocol force the specified protocol for default sockets
--shared-socket create a shared sacket for advanced jailing or ipc
--undeferred-shared-socket create a shared sacket for advanced jailing or ipc (undeferred mode)
-p|--processes spawn the specified number of workers/processes
-p|--workers spawn the specified number of workers/processes
--More--

安装成功

CFRunLoop的初次相识,不了解他,也不认识她。

我参考的文章中,有一处是这么说的

Run loops是线程的基础架构部分。一个run loop就是一个事件处理循环,用来不停的调配工作以及处理输入事件。使用run loop的目的是使你的线程在有工作的时候工作,没有的时候休眠。

Run loop的管理并不完全是自动的。你仍必须设计你的线程代码以在适当的时候启动run loop并正确响应输入事件。Cocoa和CoreFundation都提供了run loop对象方便配置和管理线程的run loop。你创建的程序不需要显示的创建run loop;每个线程,包括程序的主线程(main thread)都有与之相应的run loop对象。但是,自己创建的次线程是需要手动运行run loop的。在carbon和cocoa程序中,程序启动时,主线程会自行创建并运行run loop。

接下来的部分将会详细介绍run loop以及如何为你的程序管理run loop。关于run loop对象可以参阅sdk文档。

解析Run Loop

run loop,顾名思义,就是一个循环,你的线程在这里开始,并运行事件处理程序来响应输入事件。你的代码要有实现循环部分的控制语句,换言之就是要有while或for语句。在run loop中,使用run loop对象来运行事件处理代码:响应接收到的事件,启动已经安装的处理程序。

Run loop处理的输入事件有两种不同的来源:输入源(input source)和定时源(timer source)。输入源传递异步消息,通常来自于其他线程或者程序。定时源则传递同步消息,在特定时间或者一定的时间间隔发生。两种源的处理都使用程序的某一特定处理路径。

在苹果官方是这样解释的。

A CFRunLoop object monitors sources of input to a task and dispatches control when they become ready for processing. Examples of input sources might include user input devices, network connections, periodic or time-delayed events, and asynchronous callbacks.

无奈,找到了一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//    used by thread2 to force thread exit
- (void)forceExit:(ThreadObj*)obj {
obj.nExitFlag = 1;
NSLog(@"The current forceExit id = %@", self);
}


// for thread1
- (void)func1 {
nExitFlag = 0;
NSLog(@"The current func1 id = %@", self);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

//A runloop with no sources returns immediately from runMode:beforeDate:
//That will wake up the loop and chew CPU. Add a dummy source to prevent
//it.

NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
NSMachPort *dummyPort = [[NSMachPort alloc] init];
[runLoop addPort:dummyPort forMode:NSDefaultRunLoopMode];
[dummyPort release];
[pool release];

while (!nExitFlag){
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
[loopPool drain];
}
}


// for thread2
- (void)func2:(NSArray *)args {
nExitFlag = 0;

NSLog(@"The current func2 id = %@", self);
NSThread* thread1 = [args objectAtIndex:1];
id id1 = [args objectAtIndex:0];

// force thread1 to exit
[self performSelector:@selector(forceExit:) onThread:thread1 withObject:id1 waitUntilDone:YES];
}

里面就是这样调用了一下,输出的结果是:

1
2
3
4
2013-07-30 10:06:04.714 MyRunLoop[55395:1803] The current func1 id = <ThreadObj: 0x7132590>
2013-07-30 10:06:04.716 MyRunLoop[55395:2003] The current func2 id = <ThreadObj: 0x7132600>
2013-07-30 10:06:04.720 MyRunLoop[55395:1803] The current forceExit id = <ThreadObj: 0x7132600>
2013-07-30 10:06:05.135 MyRunLoop[55395:c07] Application windows are expected to have a root view controller at the end of application launch

是这样子的,你如果自己运行的话,估计会跟我有些区别的。

具体干嘛用,有时间继续 研究,对了还有一个知识点就是:NSMachPort

这个看起来也有大用处,好像跟传递文件有关系

NSMachPort is a subclass of NSPort that can be used as an endpoint for distributed object connections (or raw messaging). NSMachPort is an object wrapper for a Mach port, the fundamental communication port in OS X. NSMachPort allows for local (on the same machine) communication only. A companion class, NSSocketPort, allows for both local and remote distributed object communication, but may be more expensive than NSMachPort for the local case.

好像越来越强大啦,呵呵

参考的文章地址:

参考链接1 参考链接2 参考链接3

标准写法的 application/json,人们有时候也习惯text/json,但是text/json不兼容的,建议你用标准application/json

服务端 向 客户端 发送 JSON数据 时:

Content-Type = ‘application/json;charset=UTF-8’

服务端 向 客户端 发送 JS 代码 时:

Content-Type = ‘text/javascript;charset=UTF-8’

服务端 判断 客户端 提交的是否是 JSON数据 时 :

1
2
3
4
Content-Type = 'application/json;charset=UTF-8'
Content-Type = 'text/json;charset=UTF-8'
Content-Type = 'text/javascript;charset=UTF-8'
Content-Type = 'application/javascript;charset=UTF-8'

只要 Content-Type 满足上面4个条件中的 任意一个时,就可以认为提交的数据是 JSON数据

javascript 中的数组 可以当做数据字典用,还可以当栈用,等很多用法。普通的数组用法只是数据字典用法的一个特例。

比如:arr[1]=”gao”;

只是key是int类型,value是字符串类型。其实数组的key和value都是object类型。相当于c# 中的hashtable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
var dict=new Array;
dict["省"]="山东";
dict["市"]="济南";
dict["县"]="市中心";
alert(dict["省"]);
for(var k in dict)
{
alert(k); //结果是key的值,也就是 "省","市","县"
}
for(var k in dict)
{
alert(dict[k]); //结果是value的值,也就是 "山东","济南","市中心"
}
</script>

复制到自己的html页面去吧,运行一下,效果不是吹的,呵呵

前面一篇文章说的,主要是讲解了一些关于find命令的参数的信息,这里说下如果去使用,先看看我在别处引用的说法

要删除系统中就的备份文件,就需要使用命令了:

#find /tmp -mtime +30 -type f -name *.sh[ab] -exec rm -f {} ;

假如在一个目录中保留最近30天的文件,30天前的文件自动删除

#find /tmp -mtime +30 -type f -name *.sh[ab] -exec rm -f {} ;

/tmp –设置查找的目录;

-mtime +30 –设置时间为30天前;

-type f –设置查找的类型为文件;

-name *.sh[ab] –设置文件名称中包含sha或者shb;

  -exec rm -f –查找完毕后执行删除操作;

  提示:将此命令写入crontab后即可自动完成查找并删除的工作

  另外的方法大同小异

  #find . -mtime +30 -type f | xargs rm -rf

  我的操作是:先ls -ltr 查看时间,没有太久的所以就用 -cmin n查找系统中最后N分钟被改变文件状态的文件。具体命令:$ find /home/oracle/test6 -cmin +20 -type f -name *.xml -exec rm -f { } ;

  另外的方法大同小异

  #find . -mtime +30 -type f | xargs rm -rf

  $find . -type f -cmin +10 -exec rm -rf *.xml {} ;

  find . type f -name “debug*“ -atime +3 -exec rm -f {} ;

  首先cd进入目录:

  find . -name “*~” -exec rm {} ;

  find . -ctime +n -exec -exec rm -vi {} ;

  这里的+n是指多少天以前,比如:+7

  find . -ctime +7 -exec -exec rm -vi {} ;

  如果不想手动确认,把命令中的-vi改成-fv

  请详查find命令。

  使用find时要区分清楚atime,ctime,mtime的区别,一般都使用mtime来查找,因为在ls -al显示出来的就是mtime时间戳,可以使用: # find $PAHT -mtime +3 -ok rm {} ;

  在交互模式下删除比较保险。

  一、按照一定日期格式命名文件

  1、按照一定的格式输出日期:

  date +”%y%m%d”

  格式说明:

  % : 印出 %

  %n : 下一行

  %t : 跳格

  %H : 小时(00-23)

  %I : 小时(01-12)

  %k : 小时(0-23)

  %l : 小时(1-12)

  %M : 分钟(00-59)

  %p : 显示本地 AM 或 PM

  %r : 直接显示时间 (12 小时制,格式为 hh:mm:ss [AP]M)

  %s : 从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数

  %S : 秒(00-60)

  %T : 直接显示时间 (24 小时制)

  %X : 相当于 %H:%M:%S

  %Z : 显示时区

  日期方面 :

  %a : 星期几 (Sun-Sat)

  %A : 星期几 (Sunday-Saturday)

  %b : 月份 (Jan-Dec)

  %B : 月份 (January-December)

  %c : 直接显示日期与时间

  %d : 日 (01-31)

  %D : 直接显示日期 (mm/dd/yy)

  %h : 同 %b

  %j : 一年中的第几天 (001-366)

  %m : 月份 (01-12)

  %U : 一年中的第几周 (00-53) (以 Sunday 为一周的第一天的情形)

  %w : 一周中的第几天 (0-6)

  %W : 一年中的第几周 (00-53) (以 Monday 为一周的第一天的情形)

  %x : 直接显示日期 (mm/dd/yy)

  %y : 年份的最后两位数字 (00.99)

  %Y : 完整年份 (0000-9999)

  2、命名带有日期的文件:filenamedate +%y%m%d,此处的”`”不是单引号。

  二、以创建文件日期为界线删除文件

  1、find命令简解

  find pathname -options [-print -exec -ok …]

  pathname: find命令所查找的目录路径。例如用。来表示当前目录,用/来表示系统根目录。

  -print: find命令将匹配的文件输出到标准输出。

  -exec: find命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为’command’ { } ;,注意{ }和;之间的空格。

  -ok: 和-exec的作用相同,只不过以一种更为安全的模式来执行该参数所给出的shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。

  options:

  -name

  按照文件名查找文件。

  -perm

  按照文件权限来查找文件。

  -prune

  使用这一选项可以使find命令不在当前指定的目录中查找,如果同时使用-depth选项,那么-prune将被find命令忽略。

  -user

  按照文件属主来查找文件。

  -group

  按照文件所属的组来查找文件。

  -mtime -n +n

  按照文件的更改时间来查找文件, - n表示文件更改时间距现在n天以内,+ n表示文件更改时间距现在n天以前。find命令还有-atime和-ctime 选项,但它们都和-m time选项。

  -nogroup

  查找无有效所属组的文件,即该文件所属的组在/etc/groups中不存在。

  -nouser

  查找无有效属主的文件,即该文件的属主在/etc/passwd中不存在。

  -newer file1 ! file2

  查找更改时间比文件file1新但比文件file2旧的文件。

  -type

  查找某一类型的文件,诸如:

  b - 块设备文件。

  d - 目录。

  c - 字符设备文件。

  p - 管道文件。

  l - 符号链接文件。

  f - 普通文件。

  -size n:[c] 查找文件长度为n块的文件,带有c时表示文件长度以字节计。

  -depth:在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。

  -fstype:查找位于某一类型文件系统中的文件,这些文件系统类型通常可以在配置文件/etc/fstab中找到,该配置文件中包含了本系统中有关文件系统的信息。

  -mount:在查找文件时不跨越文件系统mount点。

  -follow:如果find命令遇到符号链接文件,就跟踪至链接所指向的文件。

  -cpio:对匹配的文件使用cpio命令,将这些文件备份到磁带设备中。

  对于时间相关的参数,有以下补充:

  -amin n

  查找系统中最后N分钟访问的文件

  -atime n

  查找系统中最后n*24小时访问的文件

  -cmin n

  查找系统中最后N分钟被改变文件状态的文件

  -ctime n

  查找系统中最后n*24小时被改变文件状态的文件

  -mmin n

  查找系统中最后N分钟被改变文件数据的文件

  -mtime n

  查找系统中最后n*24小时被改变文件数据的文件

  2、删除固定日期以前的文件

  find logs -type f -mtime +5 -exec rm { } ;

关于linux下按照日期删除文件,用的最多的方式就是使用find命令

操作就是这样的:(这个是我的删除session文件的命令,你可以直接运行,也可以放在crontab中运行)

1
find /tmp/session -mtime +1 -type f -exec rm -rf {} \;

find相关参数
 -amin<分钟>  查找在指定时间曾被存取过的文件或目录,单位以分钟计算。
 -anewer<参考文件或目录>  查找其存取时间较指定文件或目录的存取时间更接近现在的文件或目录。
 -atime<24小时数>  查找在指定时间曾被存取过的文件或目录,单位以24小时计算。
 -cmin<分钟>  查找在指定时间之时被更改的文件或目录。
 -cnewer<参考文件或目录>  查找其更改时间较指定文件或目录的更改时间更接近现在的文件或目录。
 -ctime<24小时数>  查找在指定时间之时被更改的文件或目录,单位以24小时计算。
 -daystart  从本日开始计算时间。
 -depth  从指定目录下最深层的子目录开始查找。
 -expty  寻找文件大小为0 Byte的文件,或目录下没有任何子目录或文件的空目录。
 -exec<执行指令>  假设find指令的回传值为True,就执行该指令。
 -false  将find指令的回传值皆设为False。
 -fls<列表文件>  此参数的效果和指定”-ls”参数类似,但会把结果保存为指定的列表文件。
 -follow  排除符号连接。
 -fprint<列表文件>  此参数的效果和指定”-print”参数类似,但会把结果保存成指定的列表文件。
 -fprint0<列表文件>  此参数的效果和指定”-print0”参数类似,但会把结果保存成指定的列表文件。
 -fprintf<列表文件><输出格式>  此参数的效果和指定”-printf”参数类似,但会把结果保存成指定的列表文件。
 -fstype<文件系统类型>  只寻找该文件系统类型下的文件或目录。
 -gid<群组识别码>  查找符合指定之群组识别码的文件或目录。
 -group<群组名称>  查找符合指定之群组名称的文件或目录。
 -help或–help  在线帮助。
 -ilname<范本样式>  此参数的效果和指定”-lname”参数类似,但忽略字符大小写的差别。
 -iname<范本样式>  此参数的效果和指定”-name”参数类似,但忽略字符大小写的差别。
 -inum<inode编号>  查找符合指定的inode编号的文件或目录。
 -ipath<范本样式>  此参数的效果和指定”-ipath”参数类似,但忽略字符大小写的差别。
 -iregex<范本样式>  此参数的效果和指定”-regexe”参数类似,但忽略字符大小写的差别。
 -links<连接数目>  查找符合指定的硬连接数目的文件或目录。
 -iname<范本样式>  指定字符串作为寻找符号连接的范本样式。
 -ls  假设find指令的回传值为True,就将文件或目录名称列出到标准输出。
 -maxdepth<目录层级>  设置最大目录层级。
 -mindepth<目录层级>  设置最小目录层级。
 -mmin<分钟>  查找在指定时间曾被更改过的文件或目录,单位以分钟计算。
 -mount  此参数的效果和指定”-xdev”相同。
 -mtime<24小时数>  查找在指定时间曾被更改过的文件或目录,单位以24小时计算。
 -name<范本样式>  指定字符串作为寻找文件或目录的范本样式。
 -newer<参考文件或目录>  查找其更改时间较指定文件或目录的更改时间更接近现在的文件或目录。
 -nogroup  找出不属于本地主机群组识别码的文件或目录。
 -noleaf  不去考虑目录至少需拥有两个硬连接存在。
 -nouser  找出不属于本地主机用户识别码的文件或目录。
 -ok<执行指令>  此参数的效果和指定”-exec”参数类似,但在执行指令之前会先询问用户,若回答”y”或”Y”,则放弃执行指令。
 -path<范本样式>  指定字符串作为寻找目录的范本样式。
 -perm<权限数值>  查找符合指定的权限数值的文件或目录。
 -print  假设find指令的回传值为True,就将文件或目录名称列出到标准输出。格式为每列一个名称,每个名称之前皆有”./“字符串。
 -print0  假设find指令的回传值为True,就将文件或目录名称列出到标准输出。格式为全部的名称皆在同一行。
 -printf<输出格式>  假设find指令的回传值为True,就将文件或目录名称列出到标准输出。格式可以自行指定。
 -prune  不寻找字符串作为寻找文件或目录的范本样式。
 -regex<范本样式>  指定字符串作为寻找文件或目录的范本样式。
 -size<文件大小>  查找符合指定的文件大小的文件。
 -true  将find指令的回传值皆设为True。
 -typ<文件类型>  只寻找符合指定的文件类型的文件。
 -uid<用户识别码>  查找符合指定的用户识别码的文件或目录。
 -used<日数>  查找文件或目录被更改之后在指定时间曾被存取过的文件或目录,单位以日计算。
 -user<拥有者名称>  查找符合指定的拥有者名称的文件或目录。
 -version或–version  显示版本信息。
 -xdev  将范围局限在先行的文件系统中。
 -xtype<文件类型>  此参数的效果和指定”-type”参数类似,差别在于它针对符号连接检查。

最近服务器登录不了啦,登录后就退出来了,为什么?看下面吧

一台服务器流量比较大,因为程序的需要,session的过期时间设置的是3小时,导致/tmp下堆积了近20万的session文件。进而导致内核占用 的cpu急剧上升。因为session的读写涉及到大量小文件的随机读写,并且是集中在一个目录下,iowait也急剧升高。

首先考虑将session放入内存中

最简单的办法莫过于将/tmp挂载为 tmpfs文件系统,也就是内存中

将session存储到不通的目录中

php本身支持session的多级散列

在php.ini中,将

1
;session.save_path = /tmp

改为

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

表示将session存储到 /tmp/session这个文件夹中,并且是用2及散列。

保存退出,等第三步结束后重启php

创建session存储文件夹

php并不会自动去创建这些文件夹,不过在源文件中提供了一些创建文件夹的脚本。下面这个脚本也好用

1
2
3
4
5
6
7
8
9
10
I="0 1 2 3 4 5 6 7 8 9 a b c d e f"
for acm in $I;
do
for x in $I;
do
mkdir -p /tmp/session/$acm/$x;
done;
done
chown -R nobody:nobody /tmp/session
chmod -R 1777 /tmp/session

因为/tmp是用的内存,服务器重启后,里面的所有文件都会丢失,所以,需要把上面的脚本加入到 /etc/rc.local中,并且要放在启动php之前

session的回收

session在经过session.gc_maxlifetime后会过期,但并不会马上被删除,时间长了以后会造成/tmp空间占用很大。具体的删除算法懒得去研究。下面这个命令可以删除过期的session,我这里定义的过期时间是3小时。

1
find /tmp/session -amin +180 -exec rm -rf {} \;

放入cron中,10分钟执行一次,完事。

其中有些步骤本网站已经有说明,但是缺少的是如果删除生成的session文件,娘炮哦,我原因为它会自动删除生成的session文件的哈,结果,跟我想的逆天啦。

关于php.ini文件的配置和session文件的目录的设置,这篇文章有讲到的

session.save_path目录大量session临时文件带来的服务器效率问题

可以去看下,我这里主要记录下,关于删除生成的session文件的处理办法

很简单的:

1
find /tmp/session -mtime +1 -type f -exec rm -rf {} \;

就是这条语句,想知道如何理解这行命令吗?要不继续往下看,要不就自己google去吧。

方法调用要比其他的查询稍微复杂一点,下面是需要记住的几点:

1,在方法查询的时候,如果一个方法触发了异常,这个异常会传递从而导致渲染失
败,但是如果异常有一个值为True的silent_variable_failure属性,这个变量会渲染成空string:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
>>> t = Template("My name is {{ person.first_name }}.")   

>>> class PersonClas3:

... def first_name(self):

... raise AssertionError, "foo"

>>> p = PersonClass3()

>>> t.render(Context({"person": p}))

Traceback (most recent call last):

...

AssertionError: foo

>>> class SilentAssetionError(AssertionError):

... silent_variable_failure = True

>>> class PersonClass4:

... def first_name(self):

... raise SilentAssertionError

>>> p = PersonClass4()

>>> t.render(Context({"person": p}))

"My name is ."

2,方法调用仅仅在它没有参数时起作用,否则系统将继续查找下一个类型(列表索引查询)

3,显然一些方法有副作用,让系统访问它们是很愚蠢的,而且很可能会造成安全性问题。

例如你有一个BankAccount对象,该对象有一个delete()方法,模板系统不应该允许做下面的事情

1
I will now delete this valuable data. {{ account.delete }} 

为了防止这种状况,可以在方法里设置一个方法属性alters_data

如果设置了alters_data=True的话模板系统就不会执行这个方法:

代码

1
2
3
4
5
def delete(self):   

# Delete the account

delete.alters_data = True

不合法的变量怎样处理

默认情况下如果变量不存在,模板系统会把它渲染成空string,例如:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> from django.template import Template, Context   

>>> t = Template('Your name is {{ name }}.')

>>> t.render(Context())

'Your name is .'

>>> t.render(Context({'var': 'hello'}))

'Your name is .'

>>> t.render(Context({'NAME': 'hello'}))

'Your name is .'

>>> t.render(Context({'Name': 'hello'}))

'Your name is .'

系统会静悄悄地显示错误的页面,而不是产生一个异常,因为这种情况通常是人为的错误。

在现实情形下,一个web站点因为一个模板代码语法的错误而变得不可用是不可接受的。

我们可以通过设置Django配置更改Django的缺省行为,第10章扩展模板引擎会我们会讨论这个

玩玩Context对象

大多数情况下你初始化Context对象会传递一个字典给Context()

一旦你初始化了Context,你可以使用标准Python字典语法增减Context对象的items:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> from django.template import Context   

>>> c = Context({"foo": "bar"})

>>> c['foo']

'bar'

>>> del c['foo']

>>> c['foo']

''

>>> c['newvariable'] = 'hello'

>>> c['newvariable']

'hello'

Context对象是一个stack,你可以push()和pop()

如果你pop()的太多的话它将触发django.template.ContextPopException:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
>>> c = Context()   

>>> c['foo'] = 'first level'

>>> c.push()

>>> c['foo'] = 'second level'

>>> c['foo']

'second level'

>>> c.pop()

>>> c['foo']

'first level'

>>> c['foo'] = 'overwritten'

>>> c['foo']

'overwritten'

>>> c.pop()

Traceback (most recent call last):

...

django.template.ContextPopException

if/else

{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值
系统则会显示{% if %}{% endif %}间的所有内容:

代码

1
2
3
4
5
6
7
8
9
{% if today_is_weekend %}   

<p>Welcome to the weekend!</p>

{% else %}

<p>Get back to work.</p>

{% endif %}

{% if %}标签接受and,or或者not来测试多个变量值或者否定一个给定的变量,例如:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{% if athlete_list and coach_list %}   

Both athletes and coaches are available.

{% endif %}

{% if not athlete_list %}

There are no athletes.

{% endif %}

{% if athlete_list or coach_list %}

There are some athletes or some coaches.

{% endif %}

{% if not athlete_list or coach_list %}

There are no athletes or there are some coaches.

{% endif %}

{% if athlete_list and not coach_list %}

There are some athletes and absolutely no coaches.

{% endif %}

{% if %}标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:

代码

1
{% if athlete_list and coach_list or cheerleader_list %}  

如果你想结合and和or来做高级逻辑,只需使用嵌套的{% if %}标签即可:

代码

1
2
3
4
5
6
7
8
9
{% if athlete_list %}   

{% if coach_list or cheerleader_list %}

We have athletes, and either coaches or cheerleaders!

{% endif %}

{% endif %}

多次使用同一个逻辑符号是合法的:

代码

1
{% if athlete_list or coach_list or parent_list or teacher_list %}  

没有{% elif %}标签,使用嵌套的{% if %}标签可以做到同样的事情:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% if athlete_list %}   

<p>Here are the athletes: {{ athlete_list }}.</p>

{% else %}

<p>No athletes are available.</p>

{% if coach_list %}

<p>Here are the coaches: {{ coach_list }}.</p>

{% endif %}

{% endif %}

确认使用{% endif %}来关闭{% if %}标签,否则Django触发TemplateSyntaxError

for

{% for %}标签允许你按顺序遍历一个序列中的各个元素

Python的for语句语法为for X in Y,X是用来遍历Y的变量

每次循环模板系统都会渲染{% for %}{% endfor %}之间的所有内容

例如,显示给定athlete_list变量来显示athlete列表:

代码

1
2
3
4
5
6
7
8
9
<ul>  

{% for athlete in athlete_list %}

<li>{{ athlete.name }}</li>

{% endfor %}

</ul>

在标签里添加reversed来反序循环列表:

代码

1
2
3
4
5
{% for athlete in athlete_list reversed %}   

...

{% endfor %}

{% for %}标签可以嵌套:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% for country in countries %}   

<h1>{{ country.name }}</h1>

<ul>

{% for city in country.city_list %}

<li>{{ city }}</li>

{% endfor %}

</ul>

{% endfor %}

系统不支持中断循环,如果你想这样,你可以改变你想遍历的变量来使得变量只包含你想遍历的值

类似的,系统也不支持continue语句

{% for %}标签内置了一个forloop模板变量,这个变量含有一些属性可以提供给你一些关于循环的信息

1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1,例如:

代码

1
2
3
4
5
{% for item in todo_list %}   

<p>{{ forloop.counter }}: {{ item }}</p>

{% endfor %}

2,forloop.counter0类似于forloop.counter,但它是从0开始计数,第一次循环设为0
3,forloop.revcounter表示循环中剩下的items数量,第一次循环时设为items总数,最后一次设为1
4,forloop.revcounter0类似于forloop.revcounter,但它是表示的数量少一个,即最后一次循环时设为0
5,forloop.first当第一次循环时值为True,在特别情况下很有用:

代码

1
2
3
4
5
6
7
8
9
{% for object in objects %}   

{% if forloop.first %}<li class="first">{% else %}<li>{% endif %}

{{ object }}

</li>

{% endfor %}

6,forloop.last当最后一次循环时值为True

代码

1
{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}  

7,forloop.parentloop在嵌套循环中表示父循环的forloop:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{% for country in countries %}   

<table>

{% for city in country.city_list %}

<tr>

<td>Country #{{ forloop.parentloop.counter }} </td>

<td>City #{{ forloop.counter }}</td>

<td>{{ city }}</td>

</tr>

{% endfor %}

</table>

{% endfor %}

富有魔力的forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了

如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它

Django会在for标签的块中覆盖你定义的forloop变量的值

在其他非循环的地方,你的forloop变量仍然可用

我们建议模板变量不要使用forloop,如果你需要这样做来访问你自定义的forloop,你可以使用forloop.parentloop

ifequal/ifnotequal

Django模板系统并不是一个严格意义上的编程语言,所以它并不允许我们执行Python语句

然而在模板语言里比较两个值并且在他们一致的时候显示一些内容,确实是一个在常见不过的需求了——所以Django提供了ifequal标签。

{% ifequal %}比较两个值,如果相等,则显示{% ifequal %}{% endifequal %}之间的所有内容:

代码

1
2
3
4
5
{% ifequal user currentuser %}   

<h1>Welcome!</h1>

{% endifequal %}

参数可以是硬编码的string,单引号和双引号均可,下面的代码是合法的:

代码

1
2
3
4
5
6
7
8
9
10
11
{% ifequal section 'sitenews' %}   

<h1>Site News</h1>

{% endifequal %}

{% ifequal section "community" %}

<h1>Community</h1>

{% endifequal %}

{% if %}一样,{% ifequal %}标签支持{% else %}

代码

1
2
3
4
5
6
7
8
9
{% ifequal section 'sitenews' %}   

<h1>Site News</h1>

{% else %}

<h1>No News Here</h1>

{% endifequal %}

其它的模板变量,strings,integers和小数都可以作为{% ifequal %}的参数:

代码

1
2
3
4
5
6
7
{% ifequal variable 1 %}   

{% ifequal variable 1.23 %}

{% ifequal variable 'foo' %}

{% ifequal variable "foo" %}

其它的Python类型,如字典、列表或booleans不能硬编码在{% ifequal %}里面,下面是不合法的:

代码

1
2
3
4
5
{% ifequal variable True %}   

{% ifequal variable [1, 2, 3,]%}

{% ifequal variable {'key': 'value'} %}

如果你需要测试某个变量是true或false,用

0%