php示例程序(二)
二、ticket生成及检
这个子程序实现的功能看起来挺复杂,到现在我都没想到一个合适的词来解释ticket,但是意思倒是很明确,这相当于远端人员的一个用来标识自己身份的入场券,我们不妨仍将其写成ticket。
而这个程序的功能就是一个ticket的生成及检查,而在用户及服务器间传递的就是这个叫做ticket的变量,由于ticket变量具有时效,并且已经过了初步的加密,所以在安全性方面要比直接传递密码要安全得多。至于在编程上倒是没有多少太多的技巧,下面我们仍从编程的角度来看看这段程序。
<?php 
class  authticket  
        var  
$secret  =  "setme";                //你需要改变它 
        
var  $realm  =  "";                //身份的领域 
        
var  $lifetime  =  2  *  60  *60;        //时间设置为两小时 
        
var  $authenticated  =  0;                //这个数据当且仅当不等于零时有效
        
var  $identity;                //如果解码正确的话,远端的身份
        
var  $issue;                //ticket发行时间
        
var  $remote_addr;        //用户端的远端地址
        
var  $hash;                //hash值
        
var  $autherr;                //记录校验失败的原因
        //  将ticket数据置零的辅助程序
        
function  zerodata() 
        { 
                
$this->authenticated  =  0
                
$this->identity  =  ""
                
$this->issue  =  0
                
$this->remote_addr  =  ""
                
$this->hash  =  ""
                
$this->autherr  =  ""
        } 

        
//获得身份($identity)、时间($time)以及密钥, 然后产生一个字符串以验证远端
        //用户的合法性。这个函数的结果是一个字符串,他可以存在于一个隐藏表甚至是cookie
        //中。
        //如果$time=0,就取当前时间。 
        //$identity不能包含“:”,如果有的话,你需要使用一个转义符来代替他。
        //在使用的时候要特别小心,我建议只在SSL之后再使用它,除非目前的ticket内容使用了
              //比XOR更安全的加密方法。 
        
function  makeauth($identity,  $time
        { 
                global  
$REMOTE_ADDR
                
$this->zerodata(); 
                if  (
$time  ==  0
                        
$time  =  time(); 
                
$ticket_items[]  =  (string)$time
                
$ticket_items[]  =  $this->realm
                
$ticket_items[]  =  $REMOTE_ADDR
                
$ticket_items[]  =  $identity
                
$ticket  =  implode($ticket_items,  ":"); 
                
$hash  =  md5($this->secret  .  $ticket); 
                
$ticket  =  $hash  .  ':'  .  $ticket
                
$this->identity  =  $identity
                
$this->issue  =  $time
                
$this->remote_addr  =  $REMOTE_ADDR
                
$this->hash  =  $hash
                
$this->authenticated  =  1;    /*  data  is  valid  */ 
                
$this->autherr  =  ""
                return  
$ticket
        } 
        
//获得通过makeauth()函数产生的($ticket)以及($time),然后效验这个ticket是否有
        //效而且未到期。
        //如果$time=0,就取当前时间。 
        //如果检查未通过,这个函数返回一个空串"", $authenticated为零,$autherr返回校
        //验失败的原因 
        //如果检查通过了,ticket中加密的身份被返回,$authenticated非零,$autherr被略过
        
function  checkauth($ticket,  $time
        { 
                global  
$REMOTE_ADDR

                
$this->zerodata(); 

                if  (
$time  ==  0
                        
$time  =  time(); 

                
$ticket_items  =  explode":",  $ticket); 

                if  (
$ticket_items[3]  !=  $REMOTE_ADDR)  { 
                        
$this->autherr  =  "Address  mismatch"
                        return  
""
                } 

                if  (
$this->lifetime  !=  0
                        if  (
$time  >  (int)$ticket_items[1]  +  $this->lifetime)  { 
                                
$this->autherr  =  "Ticket  expired"
                                return  
""
                        } 

                if  (
$time  <  (int)$ticket_items[1])  { 
                        
$this->autherr  =  "Ticket  used  before  issued"
                        return  
""
                } 

                if  (
$this->realm  !=  $ticket_items[2])  { 
                        
$this->autherr  =  "Realm  mismatch"
                        return  
""
                } 

                
$tmp_items[]  =  $ticket_items[1]; 
                
$tmp_items[]  =  $ticket_items[2]; 
                
$tmp_items[]  =  $ticket_items[3]; 
                
$tmp_items[]  =  $ticket_items[4]; 

                
$tmp_ticket  =  implode($tmp_items,  ":"); 

                
$hash  =  md5($this->secret  .  $tmp_ticket); 

                if  (
$hash  !=  $ticket_items[0])  { 
                        
$this->autherr  =  "Integrity  check  failed"
                        return  
""
                } 


                
$this->hash  =  $hash
                
$this->issue  =  $ticket_items[1]; 
                
$this->remote_addr  =  $ticket_items[3]; 
                
$this->identity  =  $ticket_items[4]; 
                
$this->authenticated  =  1

                return  
$this->identity
        } 
}; 
?> 
在程序的一开始,定义了一个类authticket;PHP中的类要比其它的面向对象语言单纯得多,抛开继承(extensions)不谈,在这个程序中我们完全可以把类理解为标识一个对象的全部变量的集合,而相对的function我们也可以把他理解为有关类的一个函数(实际上,这里的function的正规的叫法是叫方法,我们在以后的程序中会看到,这里的function的调用跟其他地方并不完全相同,而且类的变化将返回)。 
zerodata提供了一个类的初始化的功能,在这里this表示类本身,也就是说如果调用此方法时是用诸如$tix->zerodata()的形式时,this就是指的tix,this的用法在类的方法中使用非常普遍。 另外,形如$this->authenticated  =  0的格式也给我们提供了一个给类中的变量赋值的基本格式,在这里,$this->authenticated确定了类中的一个变量。
makeauth也就是生成ticket了,在这里我们有三个需要注意的地方,一、implode的使用,本函数将数组的内容组合成一个字符串,第一个参数是字之间的分隔符号,第二个参数是数组,与之相对应的函数是explode,本函数将字符串依指定的字符串或字符 separator 切开。将切开后的字符串返回到数组变量中。二、MD5函数的使用,本函数用来计算 MD5 哈稀。是一种加密算法。三、数组的赋值。$ticket_items[]  =  (string)$time; $ticket_items[]  =  $this->realm; $ticket_items[]  =  $REMOTE_ADDR; $ticket_items[]  =  $identity; 等价于。$ticket_items[0]  =  (string)$time; $ticket_items[1]  =  $this->realm; $ticket_items[2]  =  $REMOTE_ADDR; $ticket_items[3]  =  $identity; 
返加的ticket的内容是md5($this->secret.((string)$time:$this->realm:$REMOTE_ADDR:$identity)): (string)$time:$this->realm:$REMOTE_ADDR:$identity 
类的hash值是md5($this->secret.((string)$time:$this->realm:$REMOTE_ADDR:$identity))
checkauth是检查ticket,首先将ticket分为数组,这时:
ticket_items[0]=md5($this->secret.((string)$time:$this->realm:$REMOTE_ADDR:$identity))
ticket_items[1]=(string)$time
ticket_items[2]=$this->realm
ticket_items[3]=$REMOTE_ADDR
ticket_items[4]=$identity
校验不通过的原因分别是:
$ticket_items[3]  !=  $REMOTE_ADDR:地址不对;
$time  >  (int)$ticket_items[1]  +  $this->lifetime:过期;
$time  <  (int)$ticket_items[1]): ticket尚未发行; 
$this->realm  !=  $ticket_items[2]) :区域不对;
最后一个错误原因实际上是密钥不对。
在下一个示例程序,我们将看到这个子程序的应用。