最近公司换了yaf框架,突然对用c实现php拓展感兴趣了,如果一个功能已经很稳定很成熟而且用的地方很多,那么我们就可以尝试用拓展实现(不一定每种情况都可以写成拓展),写成拓展后就不用每次用都包含一下,工具类直接随php启动加载进内存里。
我这次是把用户会话加密类写成了php的拓展,用户类是基于des加密的,主要实现了,
我给这个项目起名slime(史莱姆),勇者斗恶龙里的小怪,黏黏的。。。。。。
ok,先来看下php的实现,因为我们是php -> c,所以先看下php的实现,其实就是很普通用户类
1 <?php 2 class Session_DES 3 { 4 var $key; 5 var $iv; //偏移量 6 7 function Session_DES( $key="AAAAAAAA", $iv="BBBBBBBB") { 8 //key长度8例如:1234abcd 9 $this->key = $key; 10 if( $iv == "" ) { 11 $this->iv = $key; //默认以$key 作为 iv 12 } else { 13 $this->iv = $iv; //mcrypt_create_iv ( mcrypt_get_block_size (MCRYPT_DES, MCRYPT_MODE_CBC), MCRYPT_DEV_RANDOM ); 14 } 15 } 16 17 function encrypt($str) { 18 //加密,返回大写十六进制字符串 19 $size = mcrypt_get_block_size ( MCRYPT_DES, MCRYPT_MODE_CBC ); 20 $str = $this->pkcs5Pad ( $str, $size ); 21 return strtoupper( bin2hex( mcrypt_cbc(MCRYPT_DES, $this->key, $str, MCRYPT_ENCRYPT, $this->iv ) ) ); 22 } 23 24 function decrypt($str) { 25 //解密 26 $strBin = $this->hex2bin( strtolower( $str ) ); 27 $str = mcrypt_cbc( MCRYPT_DES, $this->key, $strBin, MCRYPT_DECRYPT, $this->iv ); 28 $str = $this->pkcs5Unpad( $str ); 29 return $str; 30 } 31 32 function hex2bin($hexData) { 33 $binData = ""; 34 for($i = 0; $i < strlen ( $hexData ); $i += 2) { 35 $binData .= chr ( hexdec ( substr ( $hexData, $i, 2 ) ) ); 36 } 37 return $binData; 38 } 39 40 function pkcs5Pad($text, $blocksize) { 41 $pad = $blocksize - (strlen ( $text ) % $blocksize); 42 return $text . str_repeat ( chr ( $pad ), $pad ); 43 } 44 45 function pkcs5Unpad($text) { 46 $pad = ord ( $text {strlen ( $text ) - 1} ); 47 if ($pad > strlen ( $text )) 48 return false; 49 if (strspn ( $text, chr ( $pad ), strlen ( $text ) - $pad ) != $pad) 50 return false; 51 return substr ( $text, 0, - 1 * $pad ); 52 } 53 }
再来看Session_User
1 <?php 2 define ('BACK_AUTH_NAME','xxxx'); //用到的cookie名 3 class Session_User { 4 static $obj; 5 private $uid; 6 private $username; 7 private $chineseName; 8 public $auth_name = BACK_AUTH_NAME; 9 private $login_url = null; 10 public $domain = null; 11 12 private function __construct($login_url = null, $domain = null){ 13 $host = $_SERVER["HTTP_HOST"]; 14 if (!$login_url) { 15 $this->login_url = "http://{$host}/login"; 16 } 17 else { 18 $this->login_url = $login_url; 19 } 20 21 if (!$domain) { 22 $domain = $_SERVER["SERVER_NAME"]; 23 $this->domain = $domain; 24 } 25 26 if (empty ( $_COOKIE [$this->auth_name] )) { 27 return; 28 } 29 30 list ( $uid, $username, $ua, $tm, $chineseName ) = @$this->decodeAuth ($_COOKIE [$this->auth_name]); 31 32 33 //ua检验 34 if (empty ( $uid ) || $ua !== md5($_SERVER ['HTTP_USER_AGENT'])) { 35 return; 36 } 37 38 //TODO:过期时间检验 39 40 $this->uid = $uid; 41 $this->username = $username; 42 $this->chineseName = $chineseName; 43 } 44 45 static public function instance($login_url = null, $domain = null){ 46 if(self::$obj) 47 return self::$obj; 48 else{ 49 self::$obj = new Session_User($login_url, $domain); 50 } 51 return self::$obj; 52 } 53 54 55 /** 56 * 用户是否登陆 57 * */ 58 public function isLogin(){ 59 if(! empty($this->uid)) 60 return true; 61 else 62 return false; 63 } 64 /** 65 * 66 * 跳转到登录页面 67 * @param unknown_type $forward 68 * @param unknown_type $exit 69 */ 70 public function requireLogin($forward = '', $exit = true){ 71 if(! $this->isLogin()){ 72 if($forward === null) 73 { 74 header("location: " . $this->login_url); 75 76 } 77 else 78 { 79 if(empty($forward)) 80 { 81 $forward = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; 82 } 83 $forward = urlencode($forward); 84 header("location: ". $this->login_url . "?forward=$forward"); 85 } 86 if($exit) 87 exit; 88 } 89 } 90 /** 91 * 92 *设置登录状态 93 * @param unknown_type $uid 94 * @param unknown_type $username 95 * @param unknown_type $ua 96 * @param unknown_type $outtime 97 */ 98 99 public function setLogin($uid, $username, $ua = null,$outtime = null, $chineseName = null){ 100 if(empty($ua)){ 101 $ua = $_SERVER['HTTP_USER_AGENT']; 102 } 103 104 $str = $this->encodeAuth($uid, $username, $ua, $chineseName); 105 setcookie($this->auth_name,urlencode($str),$outtime,'/',$this->domain); 106 } 107 /** 108 * 用户退出 109 */ 110 public function setLogout(){ 111 setcookie($this->auth_name,'',-1,'/',$this->domain); 112 } 113 114 public function __get($key){ 115 if('uid' == $key){ 116 return $this->uid; 117 }elseif ('username' == $key) { 118 return $this->username; 119 }elseif ('chineseName' == $key) { 120 return $this->chineseName; 121 } 122 return ; 123 } 124 125 public function getUid(){ 126 return $this->uid; 127 } 128 129 public function getUserName(){ 130 return $this->username; 131 } 132 133 public function getChineseName(){ 134 return $this->chineseName; 135 } 136 137 /** 138 * 生成加密的登陆cookie 139 */ 140 private function encodeAuth($uid,$username,$ua,$chineseName=null){ 141 $tm = time(); 142 $ua = md5($ua); 143 $info = "$uid\t$username\t$ua\t$tm\t$chineseName"; 144 $des = new Session_DES(); 145 $str = $des->encrypt($info); 146 return $str; 147 } 148 149 /** 150 * 解析加密cookie 151 */ 152 private function decodeAuth($str){ 153 $des = new Session_DES(); 154 $info = explode("\t",@$des->decrypt($str)); 155 if(is_array($info)){ 156 return $info; 157 }else{ 158 return array(); 159 } 160 } 161 162 public function auth($controller,$action) 163 { 164 if(!in_array($controller,$conArr)){ 165 return false; 166 } 167 if(!in_array($action,$actArr)){ 168 return false; 169 } 170 return true; 171 } 172 }
结合上面两段代码,分离出来其实得到的会话类(常常做的就是把一样的的跟不一样的分离出来),只需要3个变量两个是des用到的iv偏移量,key加密秘钥,跟cookie名,然后我们就可以写我们的拓展了,其中踩到了很多坑,一些makefile,config.w4等小语法,lib依赖,总之还是学到了很多
代码地址:https://github.com/lietdai/ldclass