当前位置:  编程技术>php
本页文章导读:
    ▪让你成为更出色的PHP开发者的10个技巧       Raphael Caixeta作为一个刚开始使用PHP的开发者,总结了十点PHP开发的技术,希望能对这门了不起的放言的初学者能有些帮助:1、尽量使用PHP自带的核心函数和类 2、巧用配置文件 3、时刻注意.........
    ▪理解php Hash函数,增强密码安全       1.声明 密码学是一个复杂的话题,我也不是这方面的专家。许多高校和研究机构在这方面都有长期的研究。在这篇文章里,我希望尽量使用简单易懂的方式向你展示一种安全存储Web程序密码.........
    ▪php中根据某年第几天计算出日期年月日的代码       这个索引值除了方便面数据的记录和搜索,还起着记录日期资讯的作用,信息量很可观。 那么,如何还原索引值为可用的日期资讯呢? date('z')返回的是一年中的第几天,返回值为从0开始至.........

[1]让你成为更出色的PHP开发者的10个技巧
    来源: 互联网  发布时间: 2013-11-30

Raphael Caixeta作为一个刚开始使用PHP的开发者,总结了十点PHP开发的技术,希望能对这门了不起的放言的初学者能有些帮助:

1、尽量使用PHP自带的核心函数和类
2、巧用配置文件
3、时刻注意对要写进数据的数据进行过滤
4、开发阶段打开错误提示
<5、代码注释不要过头,适当就好
6、收藏喜爱的代码片断并放在很容易找到的地方
7、使用一款好的源码编辑器来节约时间
8、使用MySQL管理工具(如phpMyAdmin)
9、使用PHP框架
10、与其他PHP开发者保持交流

    
[2]理解php Hash函数,增强密码安全
    来源: 互联网  发布时间: 2013-11-30
1.声明
密码学是一个复杂的话题,我也不是这方面的专家。许多高校和研究机构在这方面都有长期的研究。在这篇文章里,我希望尽量使用简单易懂的方式向你展示一种安全存储Web程序密码的方法。
2.“Hash”是做什么的?
“Hash将一段数据(小数据或大数据)转换成一段相对短小的数据,如字符串或整数。”
这是依靠单向hash函数来完成的。所谓单向是指很难(或者是实际上不可能)将其反转回来。一个常见的hash函数的例子是md5(),它流行于各种计算机语言和系统。
代码如下:

$data = "Hello World";
$hash = md5($data);
echo $hash; // b10a8db164e0754105b7a99be72e3fe5

使用md5()运算出来的结果总是32个字符的字符串,不过它只包含16进制的字符,从技术上来说它也可以用128位(16字节)的整形数来表示。你可以使用md5()来处理很长的字符串和数据,但是你始终得到的是一个固定长度的hash值,这也可能可以帮助你理解为什么这个函数是“单向”的。
3.使用Hash函数来存储密码
典型的用户注册过程:
用户填写注册表单,其中包含密码字段;
程序将所有用户填写的信息存储到数据库中;
然而密码在存储到数据库前通过hash函数加密处理;
原始的密码不再存储在任何地方,或者说它被丢弃了。
用户登录过程:
用户输入用户名和密码;
程序将密码通过以注册相同的hash函数进行加密;
程序从数据库查到用户,并读取hash后的密码;
程序比较用户名和密码,如果匹配则给用户授权。
如何选择合适的方法来加密密码,我们将在文章的后面讨论这个问题。
4.问题1:hash碰撞
hash碰撞是指对两个不同的内容进行hash得到了相同的hash值。发生hash碰撞的可能性取决于所用的hash算法。
如何产生?
举个例子,一些老式程序使用crc32()来hash密码,这种算法产生一个32位的整数作为hash结果,这意味着只有2^32 (即4,294,967,296) 种可能的输出结果。
让我们来hash一个密码:
代码如下:

echo crc32('supersecretpassword');
// outputs: 323322056

现在我们假设一个人窃取了数据库,得到了hash过的密码。他可能不能将323322056还原为‘supersecretpassword',然而他可以找到另一个密码,也能被hash出同样的值。这只需要一个很简单的程序:
代码如下:

set_time_limit(0);
$i = 0;
while (true) {
if (crc32(base64_encode($i)) == 323322056) {
echo base64_encode($i);
exit;
}
$i++;
}

这个程序可能需要运行一段时间,但是最终它能返回一个字符串。我们可以使用这个字符串来代替‘supersecretpassword',并使用它成功的登录使用该密码的用户帐户。
比如在我的电脑上运行上面的程序几个月后,我得到了一个字符串:‘MTIxMjY5MTAwNg=='。我们来测试一下:
代码如下:

echo crc32('supersecretpassword');
// outputs: 323322056
echo crc32('MTIxMjY5MTAwNg==');
// outputs: 323322056

如何解决?
现在一个稍强一点的家用PC机就可以一秒钟运行十亿次hash函数,所以我们需要一个能产生更大范围的结果的hash函数。比如md5()就更合适一些,它可以产生128位的hash值,也就是有340,282,366,920,938,463,463,374,607,431,768,211,456种可能的 输出。所以人们一般不可能做那么多次循环来找到hash碰撞。然而仍然有人找到方法来做这件事情,详细可以查看例子。
sha1()是一个更好的替代方案,因为它产生长达160位的hash值。
5.问题2:彩虹表
即使我们解决了碰撞问题,还是不够安全。
“彩虹表通过计算常用的词及它们的组合的hash值建立起来的表。”
这个表可能存储了几百万甚至十亿条数据。现在存储已经非常的便宜,所以可以建立非常大的彩虹表。
现在我们假设一个人窃取了数据库,得到了几百万个hash过的密码。窃取者可以很容易地一个一个地在彩虹表中查找这些hash值,并得到原始密码。虽然不是所有的hash值都能在彩虹表中找到,但是肯定会有能找到的。
如何解决?
我们可以尝试给密码加点干扰,比如下面的例子:
代码如下:

$password = "easypassword";
// this may be found in a rainbow table
// because the password contains 2 common words
echo sha1($password); // 6c94d3b42518febd4ad747801d50a8972022f956
// use bunch of random characters, and it can be longer than this
$salt = "f#@V)Hu^%Hgfds";
// this will NOT be found in any pre-built rainbow table
echo sha1($salt . $password); // cd56a16759623378628c0d9336af69b74d9d71a5

在这里我们所做的只是在每个密码前附加上一个干扰字符串后进行hash,只要附加的字符串足够复杂,hash后的值肯定是在预建的彩虹表中找不到的。不过现在还是不够安全。
6.问题3:还是彩虹表
注意,彩虹表可能在窃取到干拢字符串后重头开始建立。干扰字符串一样也可能被和数据库一起被窃取,然后他们可以利用这个干扰字符串从头开始创建彩虹表,如“easypassword”的hash值可能在普通的彩虹表中存在,但是在新建的彩虹表里,“f#@V)Hu^%Hgfdseasypassword”的hash值也会存在。
如何解决?
我们可以对每个用户使用唯一的干扰字符串。一个可用的方案就是使用用户在数据库中的id:
代码如下:

$hash = sha1($user_id . $password);

这种方法的前提是用户的id是一个不变的值(一般应用都是这样的)
我们也可以为每个用户随机生成一串唯一的干扰字符串,不过我们也需要将这个串存储起来:
代码如下:

// generates a 22 character long random string
function unique_salt() {
return substr(sha1(mt_rand()),0,22);
}
$unique_salt = unique_salt();
$hash = sha1($unique_salt . $password);
// and save the $unique_salt with the user record
// ...

这种方法就防止了我们受到彩虹表的危害,因为每一个密码都使用一个不同的字符串进行了干扰。攻击者需要创建和密码数量一样的彩虹表,这是很不切实际的。
7.问题4:hash速度
大部分hash算法在设计时就考虑了速度问题,因为它一般用来计算大数据或文件的hash值,以验证数据的正确性和完整性。
如何产生?
如前所述,现在一台强劲的PC机可以一秒运算数十亿次,很容易用暴力破解法去尝试每个密码。你可能会以为8个以上字符的密码就可以避免被暴力破解了,但是让我们来看看是否真是这样:
如果密码可以包含小写字母,大写字母和数字,那就有62(26+26+10)个字符可选;
一个8位的密码有62^8种可能组合,这个数字略大于218万亿。
以一秒钟运算10亿次hash值的速度计算,这只需要60小时就可以解决。
对于一个6位的密码,也是很常用的密码,只需要1分钟就可以破解。要求9到10位的密码可能会比较安全了,不过这样有的用户可能会觉得很麻烦。
如何解决?
使用慢一点的hash函数。
“假设你使用一个在相同硬件条件下一秒钟只能运行100万次的算法来代替一秒10亿次的算法,那么攻击者可能需要要花1000倍的时间来做暴力破解,60小只将会变成7年!”
你可以自己实现这种方法:
代码如下:

function myhash($password, $unique_salt) {
$salt = "f#@V)Hu^%Hgfds";
$hash = sha1($unique_salt . $password);
// make it take 1000 times longer
for ($i = 0; $i < 1000; $i++) {
$hash = sha1($hash);
}
return $hash;
}

你也可以使用一个支持“成本参数”的算法,比如 BLOWFISH。在php中可以用crypt()函数实现:
代码如下:

function myhash($password, $unique_salt) {
// the salt for blowfish should be 22 characters long
return crypt($password, '$2a$10.$unique_salt');
}

这个函数的第二个参数包含了由”$”符号分隔的几个值。第一个值是“$2a”,指明应该使用BLOWFISH算法。第二个参数“$10”在这里就是成本参数,这是以2为底的对数,指示计算循环迭代的次数(10 => 2^10 = 1024),取值可以从04到31。
举个例子:
代码如下:

function myhash($password, $unique_salt) {
return crypt($password, '$2a$10.$unique_salt');
}
function unique_salt() {
return substr(sha1(mt_rand()),0,22);
}
$password = "verysecret";
echo myhash($password, unique_salt());
// result: $2a$10$dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J1nfRGBCudCCzC

结果的hash值包含$2a算法,成本参数$10,以及一个我们使用的22位干扰字符串。剩下的就是计算出来的hash值,我们来运行一个测试程序:
代码如下:

// assume this was pulled from the database
$hash = '$2a$10$dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J1nfRGBCudCCzC';
// assume this is the password the user entered to log back in
$password = "verysecret";
if (check_password($hash, $password)) {
echo "Access Granted!";
} else {
echo "Access Denied!";
}
function check_password($hash, $password) {
// first 29 characters include algorithm, cost and salt
// let's call it $full_salt
$full_salt = substr($hash, 0, 29);
// run the hash function on $password
$new_hash = crypt($password, $full_salt);
// returns true or false
return ($hash == $new_hash);
}

运行它,我们会看到”Access Granted!”
8.整合起来
根据以上的几点讨论,我们写了一个工具类:
代码如下:

class PassHash {
// blowfish
private static $algo = '$2a';
// cost parameter
private static $cost = '$10';
// mainly for internal use
public static function unique_salt() {
return substr(sha1(mt_rand()),0,22);
}
// this will be used to generate a hash
public static function hash($password) {
return crypt($password,
self::$algo .
self::$cost .
'$'. self::unique_salt());
}
// this will be used to compare a password against a hash
public static function check_password($hash, $password) {
$full_salt = substr($hash, 0, 29);
$new_hash = crypt($password, $full_salt);
return ($hash == $new_hash);
}
}

以下是注册时的用法:
代码如下:

// include the class
require ("PassHash.php");
// read all form input from $_POST
// ...
// do your regular form validation stuff
// ...
// hash the password
$pass_hash = PassHash::hash($_POST['password']);
// store all user info in the DB, excluding $_POST['password']
// store $pass_hash instead
// ...

以下是登录时的用法:
代码如下:

// include the class
require ("PassHash.php");
// read all form input from $_POST
// ...
// fetch the user record based on $_POST['username'] or similar
// ...
// check the password the user tried to login with
if (PassHash::check_password($user['pass_hash'], $_POST['password']) {
// grant access
// ...
} else {
// deny access
// ...
}

9.加密是否可用
并不是所有系统都支持Blowfish加密算法,虽然它现在已经很普遍了,你可以用以下代码来检查你的系统是否支持:
代码如下:

if (CRYPT_BLOWFISH == 1) {
echo "Yes";
} else {
echo "No";
}

不过对于php5.3,你就不必担心这点了,因为它内置了这个算法的实现。
结论
通过这种方法加密的密码对于绝大多数Web应用程序来说已经足够安全了。不过不要忘记你还是可以让用户使用安全强度更高的密码,比如要求最少位数,使用字母,数字和特殊字符混合密码等。

    
[3]php中根据某年第几天计算出日期年月日的代码
    来源: 互联网  发布时间: 2013-11-30
这个索引值除了方便面数据的记录和搜索,还起着记录日期资讯的作用,信息量很可观。
那么,如何还原索引值为可用的日期资讯呢?
date('z')返回的是一年中的第几天,返回值为从0开始至365的整数。要将这些整数还原为日期信息,我们只需要一个简单的计算。以今年(2008年)第159天(实际为160天,php中从0开始,0对应于常规的第一天)为例,计算它的日期、星期方法如下:
代码如下:

<?php
$MyDate=159; //第159天
$milliseconds = mktime(0,0,0,1,1,2008) + $MyDate * 86400; //取得UNIX时间戳记
$msg = date('F jS Y , l',$milliseconds); //格式化日期输出
echo $msg;
?>

运行以上程序,浏览器上显示的信息将是:June 8th 2008 , Sunday
解释:
一. $milliseconds是UNIX时间戳记变量,它表明2008年第159天所经历的从UNIX公元纪(1700年1月1日)以来的毫秒数,它将作为 参数用于date()函数中参与计算日期信息,是个重要的依据。要正确计算$milliseconds的值,我们首先需要得到2008年1日1日所经历的 毫秒数,即,mktime(0,0,0,1,1,2008),然后加上159天的毫秒数,即,$MyDate * 86400,因为,每一天的86400毫秒。
二. $msg是我们格式化输出的日期资讯,此变量值的取得通过date()函数,第一个参数“'F jS Y , l'”只是格式化格式,还可以根据需要设置为别的,第二个参数是毫秒数(长整型),其意义为从UNIX起始年到某个特定时刻所经历的毫秒总数。
为了验证程序的正确性,我们可以打印一下2008年6月8日所经历的毫秒数:mktime(0,0,0,6,8,2008),它的值将与$milliseconds是一样的:1212854400。

    
最新技术文章:
▪PHP函数microtime()时间戳的定义与用法
▪PHP单一入口之apache配置内容
▪PHP数组排序方法总结(收藏)
▪php数组排序方法大全(脚本学堂整理奉献)
▪php数组排序的几个函数(附实例)
▪php二维数组排序(实例)
▪php根据键值对二维数组排序的小例子
▪php验证码(附截图)
▪php数组长度的获取方法(三个实例)
▪php获取数组长度的方法举例
▪判断php数组维度(php数组长度)的方法
▪php获取图片的exif信息的示例代码
▪PHP 数组key长度对性能的影响实例分析
▪php函数指定默认值的方法示例
▪php提交表单到当前页面、提交表单后页面重定...
▪php四舍五入的三种实现方法
▪php获得数组长度(元素个数)的方法
▪php日期函数的简单示例代码
▪php数学函数的简单示例代码
▪php字符串函数的简单示例代码
▪php文件下载代码(多浏览器兼容、支持中文文...
▪php实现文件下载、支持中文文件名的示例代码...
▪php文件下载(防止中文文件名乱码)的示例代码
▪解决PHP文件下载时中文文件名乱码的问题
▪php数组去重(一维、二维数组去重)的简单示例
▪php小数点后取两位的三种实现方法
▪php Redis 队列服务的简单示例
▪PHP导出excel时数字变为科学计数的解决方法
▪PHP数组根据值获取Key的简单示例
▪php数组去重的函数代码示例
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3