mcrypt简单介绍
PHP程序员们在编写代码程序时,除了要保证代码的高性能之外,还有一点是非常重要的,那就是程序的安全性保障。PHP除了自带的几种加密函数外,还有功能更全面的PHP加密扩展库Mcrypt和Mhash。
其中,Mcrypt扩展库可以实现加密解密功能,就是既能将明文加密,也可以密文还原。
mcrypt 是 php 里面重要的加密支持扩展库,linux环境下:该库在默认情况下不开启。window环境下:PHP>=5.3,默认开启mcrypt扩展。
1、Mcrypt()库的安装
mcypt是一个功能十分强大的加密算法扩展库。在标准的PHP安装过程中并没有把Mcrypt安装上,但PHP的主目录下包含了libmcrypt.dll文件,所以我们只用将PHP配置文件中的这行:extension=php_mcrypt.dll前面的分号去掉,然后重启服务器就可以使用这个扩展库了。
支持的算法和加密模式
Mcrypt库支持20多种加密算法和8种加密模式,具体可以通过函数mcrypt_list_algorithms()和mcrypt_list_modes()来显示[1]加密算法
Mcrypt支持的算法有:
cast-128
gost
rijndael-128
twofish
arcfour
cast-256
loki97
rijndael-192
saferplus
wake
blowfish-compat
des
rijndael-256
serpent
xtea
blowfish
enigma
rc2
tripledes
加密模式
Mcrypt支持的加密模式有:
cbc
cfb
ctr
ecb
ncfb
nofb
ofb
stream
这些算法和模式在应用中要以常量来表示,写的时候加上前缀MCRYPT_和MCRYPT_来表示,如下面Mcrypt应用的
例子
DES算法表示为MCRYPT_DES;
ECB模式表示为MCRYPT_MODE_ECB;
<?php
$str = "我的名字是?一般人我不告诉他!"; //加密内容
$key = "key:111"; //密钥
$cipher = MCRYPT_DES; //密码类型
$modes = MCRYPT_MODE_ECB; //密码模式
$iv = mcrypt_create_iv(mcrypt_get_iv_size($cipher,$modes),MCRYPT_RAND);//初始化向量
echo "加密明文:".$str."<p>";
$str_encrypt = mcrypt_encrypt($cipher,$key,$str,$modes,$iv); //加密函数
echo "加密密文:".$str_encrypt." <p>";
$str_decrypt = mcrypt_decrypt($cipher,$key,$str_encrypt,$modes,$iv); //解密函数
echo "还原:".$str_decrypt;
?>
运行结果:
加密明文:我的名字是?一般人我不告诉他!
加密密文: 锍??]??q???L 笑 ??"? ?
还原:我的名字是?一般人我不告诉他!
<1>由例子中可看到,使用PHP加密扩展库Mcrypt对数据加密和解密之前,首先创建了一个初始化向量,简称为iv。由 $iv = mcrypt_create_iv(mcrypt_get_iv_size($cipher,$modes),MCRYPT_RAND);可见创建初始化向 量需要两个参数:size指定了iv的大小;source为iv的源,其中值MCRYPT_RAND为系统随机数。
<2>函数mcrypt_get_iv_size($cipher,$modes)返回初始化向量大小,参数cipher和mode分别指算法和加 密模式。
<3>加密函数$str_encrypt = mcrypt_encrypt($cipher,$key,$str,$modes,$iv); 该函数的5个参数分 别如下:cipher——加密算法、key——密钥、data(str)——需要加密的数据、mode——算法模式、 iv——初始化向量
<4>解密函数 mcrypt_decrypt($cipher,$key,$str_encrypt,$modes,$iv); 该函数和加密函数的参数几乎 一样,唯一不同的是data,也就是说data为需要解密的数据$str_encrypt,而不是原始数据$str。
注:加密和解密函数中的参数cipher、key和mode必须一一对应,否则数据不能被还原
总结
mcrypt库常量
Mcrypt库支持20多种加密算法和8种加密模式。可以通过函数mcrypt_list_algorithms()和mcrypt_list_modes()来查看。
PHP中提供了Autoload来帮助我们方便的进行文件的包含,但是autoload并非想象的那样能够处理所有的情况,今天就来记录一下前几天遇到的autoload存在的一些问题。
为什么要使用 Autoload
在PHP中使用类时,我们必须在使用前加载进来,不管是通过 require 的方式还是 include 的方式,但是会有两个问题影响我们做出加载的决定。
首先是不知道这个类文件存放在什么地方,另外一个就是不知道什么时候需要用到这个文件。特别是项目文件特别多时,不可能每个文件都在开始的部分写很长一串的 require ….
在PHP5之后,我们可以通过 __autoload来解决这个问题。 而且在PHP5.1之后,还提供了 spl_autoload_register() 来提供更完善的加载机制。
通过阅读了 Autoloading in PHP 这篇文章,我理解的 Autoload 的加载机制,当通过 new 来实例化一个类时,PHP会通过定义的__autoload 函数加载相应的文件,如果这个类文件使用了 extends 或者 implements 需要用到其他的类文件,php会重新运行 autoload 去进行类文件的查找和加载,如果发生了两次对同一类文件的请求,就会报错。原文作者提供了三个很有趣的例子来说明这个问题,可以通过 这里 下载源码查看。
一般情况下,有很多种方法来解决加载时到相应位置查找文件的方法。用的最多的就是指定特定的命名标准。
Zend的方法
zend推荐了一种最流行的办法,在文件名中包含路径。例如下面的例子:
// Main.class
function __autoload($class_name) {
$path = str_replace('_', DIRECTORY_SEPARATOR, $class_name);
require_once $path.'.php';
}
$temp = new Main_Super_Class(); 所有的下划线都会被替换成路径中的分隔符,上例中就会去 Main/Super/Class.php文件
这种方法的缺点是在编码过程中,我们必须明确的知道代码文件应当所处的位置,而且由于
将文件路径硬编码在了类名中,如果需要修改文件夹的结构时,我们必须手工修改所有的类名。
'Include All'方法
如果是在一个开发环境中,并且对于速度不是很在意的话,使用这个方法是非常方便的。通过将所有类文件放在一个或几个特定文件夹中,然后通过遍历的方式查找加载。
例如:
<?php
$arr = array (
'Project/Classes',
'Project/Classes/Children',
'Project/Interfaces'
);
foreach($arr as $dir) {
$dir_list = opendir($dir);
while ($file = readdir($dir_list)) {
$path = $dir.DIRECTORY_SEPARATOR.$file;
if(in_array($file, array('.', '..')) || is_dir($path))
continue;
if (strpos($file, ".class.php"))
require_once $path;
}
}
?>
关联文件和位置
另外一个方法是在类文件和他的位置之间建立关联的配置文件,例如:
// configuration.php
array_of_associations = array(
'MainSuperClass' = 'C:/Main/Super/Class.php',
'MainPoorClass' = 'C:/blablabla/gy.php'
);
调用的文件
<?php
require 'autoload_generated.php';
function __autoload($className) {
global $autoload_list;
require_once $autoload_list[$className];
}
$x = new A();
?>
当然,如果文件特别多的时候,维护起来会是一件麻烦事,但是与在类名中硬编码位置,哪个更好呢?
我们当然不希望手工来维护这个列表,那么可以使用自动生成这个文件来实现,这个对应关系的文件可以是php\xml\json等等。原文的作者实现了一个这样的工具,仔细考虑一下的话,这个不是很难实现,原文作者甚至发展了一个小型的 Autoload 框架,值得学习。
<?php
// PHP根据身份证号,自动获取对应的星座函数
function get_xingzuo($cid) { // 根据身份证号,自动返回对应的星座
if (!isIdCard($cid)) return '';
$bir = substr($cid,10,4);
$month = (int)substr($bir,0,2);
$day = (int)substr($bir,2);
$strValue = '';
if (($month == 1 && $day >= 20) || ($month == 2 && $day <= 18)) {
$strValue = "水瓶座";
} else if (($month == 2 && $day >= 19) || ($month == 3 && $day <= 20)) {
$strValue = "双鱼座";
} else if (($month == 3 && $day > 20) || ($month == 4 && $day <= 19)) {
$strValue = "白羊座";
} else if (($month == 4 && $day >= 20) || ($month == 5 && $day <= 20)) {
$strValue = "金牛座";
} else if (($month == 5 && $day >= 21) || ($month == 6 && $day <= 21)) {
$strValue = "双子座";
} else if (($month == 6 && $day > 21) || ($month == 7 && $day <= 22)) {
$strValue = "巨蟹座";
} else if (($month == 7 && $day > 22) || ($month == 8 && $day <= 22)) {
$strValue = "狮子座";
} else if (($month == 8 && $day >= 23) || ($month == 9 && $day <= 22)) {
$strValue = "处女座";
} else if (($month == 9 && $day >= 23) || ($month == 10 && $day <= 23)) {
$strValue = "天秤座";
} else if (($month == 10 && $day > 23) || ($month == 11 && $day <= 22)) {
$strValue = "天蝎座";
} else if (($month == 11 && $day > 22) || ($month == 12 && $day <= 21)) {
$strValue = "射手座";
} else if (($month == 12 && $day > 21) || ($month == 1 && $day <= 19)) {
$strValue = "魔羯座";
}
return $strValue;
}
function get_shengxiao($cid) { //根据身份证号,自动返回对应的生肖
if (!isIdCard($cid)) return '';
$start = 1901;
$end = $end = (int)substr($cid,6,4);
$x = ($start - $end) % 12;
$value = "";
if ($x == 1 || $x == -11) {$value = "鼠";}
if ($x == 0) { $value = "牛";}
if ($x == 11 || $x == -1) {$value = "虎";}
if ($x == 10 || $x == -2) {$value = "兔";}
if ($x == 9 || $x == -3) {$value = "龙";}
if ($x == 8 || $x == -4) {$value = "蛇";}
if ($x == 7 || $x == -5) {$value = "马";}
if ($x == 6 || $x == -6) {$value = "羊";}
if ($x == 5 || $x == -7) {$value = "猴";}
if ($x == 4 || $x == -8) {$value = "鸡";}
if ($x == 3 || $x == -9) {$value = "狗";}
if ($x == 2 || $x == -10) {$value = "猪";}
return $value;
}
function get_xingbie($cid) { //根据身份证号,自动返回性别
if (!isIdCard($cid)) return '';
$sexint = (int)substr($cid,16,1);
return $sexint % 2 === 0 ? '女' : '男';
}
function isIdCard($number) { // 检查是否是身份证号
// 转化为大写,如出现x
$number = strtoupper($number);
//加权因子
$wi = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
//校验码串
$ai = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
//按顺序循环处理前17位
$sigma = 0;
for ($i = 0;$i < 17;$i++) {
//提取前17位的其中一位,并将变量类型转为实数
$b = (int) $number{$i};
//提取相应的加权因子
$w = $wi[$i];
//把从身份证号码中提取的一位数字和加权因子相乘,并累加
$sigma += $b * $w;
}
//计算序号
$snumber = $sigma % 11;
//按照序号从校验码串中提取相应的字符。
$check_number = $ai[$snumber];
if ($number{17} == $check_number) {
return true;
} else {
return false;
}
}
?>