PHP 写的加密函数,支持私人密钥

在开发PHP系统时,会员部分往往是一个必不可少的模块,而密码的处理又是不得不面对的问题,PHP 的 Mcrypt 加密库又需要额外设置,很多人都是直接使用md5()函数加密,这个方法的确安全,但是因为md5是不可逆加密,无法还原密码,因此也有一些不便之处,本文介绍加密函数支持私钥,用起来还是不错的.

代码如下:

 
<?php
// 说明:PHP 写的加密函数,支持私人密钥
// 整理:http://www.CodeBit.cn

function keyED($txt,$encrypt_key)  
{  
	$encrypt_key = md5($encrypt_key);  
	$ctr=0;  
	$tmp = "";  
	for ($i=0;$i<strlen($txt);$i++)  
	{  
		if ($ctr==strlen($encrypt_key)) $ctr=0;  
		$tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1);  
		$ctr++;  
	}  
	return $tmp;  
}  

function encrypt($txt,$key)  
{  
	srand((double)microtime()*1000000);  
	$encrypt_key = md5(rand(0,32000));  
	$ctr=0;  
	$tmp = "";  
	for ($i=0;$i<strlen($txt);$i++)  
	{  
		if ($ctr==strlen($encrypt_key)) $ctr=0;  
		$tmp.= substr($encrypt_key,$ctr,1) . (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1));  
		$ctr++;  
	}  
	return keyED($tmp,$key);
}  

function decrypt($txt,$key)  
{  
	$txt = keyED($txt,$key);  
	$tmp = "";  
	for ($i=0;$i<strlen($txt);$i++)  
	{  
		$md5 = substr($txt,$i,1);  
		$i++;  
		$tmp.= (substr($txt,$i,1) ^ $md5);  
	}  
	return $tmp;  
} 

$key = "YITU.org";  
$string = "我是加密字符";  

// encrypt $string, and store it in $enc_text  
$enc_text = encrypt($string,$key);  

// decrypt the encrypted text $enc_text, and store it in $dec_text  
$dec_text = decrypt($enc_text,$key);  

print "加密的 text : $enc_text <Br> ";  
print "解密的 text : $dec_text <Br> ";  
?>

每一次加密后的结果是不一样的,大大加强了密码的安全性.

用 unix/linux 格式显示文件权限

用 *nix 格式显示文件权限

用 fileperms 获取文件权限的时候,返回的是以八进制形式显示的文件的权限,如果我们想要得到 unix 或者 linux 显示文件权限的格式,可以用本文介绍的方法。

 
<?php
// 说明:用 unix/linux 格式显示文件权限
// 整理:http://www.CodeBit.cn

$perms = fileperms('/etc/passwd' );

if (($perms & 0xC000) == 0xC000) {
    // Socket
    $info = 's';
} elseif (( $perms & 0xA000) == 0xA000) {
    // Symbolic Link
    $info = 'l';
} elseif (($perms & 0x8000 ) == 0x8000) {
    // Regular
    $info = '-';
} elseif (( $perms & 0x6000) == 0x6000) {
    // Block special
    $info = 'b';
} elseif (($perms & 0x4000 ) == 0x4000) {
    // Directory
    $info = 'd';
} elseif (( $perms & 0x2000) == 0x2000) {
    // Character special
    $info = 'c';
} elseif (($perms & 0x1000 ) == 0x1000) {
    // FIFO pipe
    $info = 'p';
} else {
     // Unknown
    $info = 'u';
}

// Owner
$info .= (($perms & 0x0100) ? 'r' : '-');
$info .= (($perms & 0x0080) ? 'w' : '-');
$info .= (($perms & 0x0040) ?
            (($perms & 0x0800) ? 's' : 'x' ) :
            (($perms & 0x0800) ? 'S' : '-'));

// Group
$info .= (( $perms & 0x0020) ? 'r' : '-');
$info .= (($perms & 0x0010) ? 'w' : '-');
$info .= (($perms & 0x0008) ?
            (($perms & 0x0400) ? 's' : 'x' ) :
            (($perms & 0x0400) ? 'S' : '-'));

// World
$info .= (( $perms & 0x0004) ? 'r' : '-');
$info .= (($perms & 0x0002) ? 'w' : '-');
$info .= (($perms & 0x0001) ?
            (($perms & 0x0200) ? 't' : 'x' ) :
            (($perms & 0x0200) ? 'T' : '-'));

echo $info;
?>

摘录自 User manager for PureFTPd 的权限显示函数

PureFTPd 是 *nix 下的一个 FTP 服务器软件,而User manager for PureFTPd 则是为了方便在线管理 ftp 用户设计制作的。作者是:M.Mastenbroek。

 
<?php
// 说明:摘录自 User manager for PureFTPd 的权限显示函数
// 整理:http://www.CodeBit.cn

function DisplayFilePermissions($Mode) {
	// Determine Type
	if ($Mode & 0x1000) {
		$Type = 'p';	// FIFO pipe
	} else if ($Mode & 0x2000) {
		$Type = 'c';	// Character special
	} else if ($Mode & 0x4000) {
		$Type = 'd';	// Directory
	} else if ($Mode & 0x6000) {
		$Type = 'b';	// Block special
	} else if ($Mode & 0x8000) {
		$Type = '-';	// Regular
	} else if ($Mode & 0xA000) {
		$Type = 'l';	// Symbolic Link
	} else if ($Mode & 0xC000) {
		$Type = 's';	// Socket
	} else {
		$Type = 'u';	// UNKNOWN
	}

	// Determine permissions
	$Owner['read']    = ($Mode & 00400) ? 'r' : '-';
	$Owner['write']   = ($Mode & 00200) ? 'w' : '-';
	$Owner['execute'] = ($Mode & 00100) ? 'x' : '-';
	$Group['read']    = ($Mode & 00040) ? 'r' : '-';
	$Group['write']   = ($Mode & 00020) ? 'w' : '-';
	$Group['execute'] = ($Mode & 00010) ? 'x' : '-';
	$World['read']    = ($Mode & 00004) ? 'r' : '-';
	$World['write']   = ($Mode & 00002) ? 'w' : '-';
	$World['execute'] = ($Mode & 00001) ? 'x' : '-';

	// Adjust for SUID, SGID and sticky bit
	if ($Mode & 0x800) $Owner['execute'] = ($Owner['execute'] == 'x') ? 's' : 'S';
	if ($Mode & 0x400) $Group['execute'] = ($Group['execute'] == 'x') ? 's' : 'S';
	if ($Mode & 0x200) $World['execute'] = ($World['execute'] == 'x') ? 't' : 'T';

	return
		$Type
		. $Owner['read'] . $Owner['write'] . $Owner['execute']
		. $Group['read'] . $Group['write'] . $Group['execute']
		. $World['read'] . $World['write'] . $World['execute'];
}

$perms = fileperms( '/etc/passwd' );

echo DisplayFilePermissions($perms);

?>

检查 url 链接是否已经有参数,添加 ? 或 &

有时候我们需要检查 URL 链接是否已经有参数,然后根据需要判断是添加 ? 还是添加 & 在结尾,这只是一个很小的技巧,但是在做分页或者页面跳转时还是有些用处的。

比如分页,因为有些链接已经有参数了,在附加分页信息的时候不能把原有的参数丢掉,所以判断一下链接是否有参数,然后根据需要附加分页信息。

方法很简单:

 
((strpos($url, '?') !== false) ? '&' : '?');

检查链接中是否含有 ? ,如果有,如:
http://www.test.com/index.php?id=id
则直接在链接后面添加一个 & 然后跟上分页信息:
http://YITU.org/index.php?id=id&page=12

如果链接中没有参数,如:
http://www.test.com/index.php
则需要添加 & 然后跟上分页信息:
http://YITU.org/index.php?page=12

以上代码只是一个示例,具体实现方法需要您自己编写。

附上一个更为健全的检查方法:

 
<?php
$old_url = $_SERVER["REQUEST_URI"];
 
//检查链接中是否存在 ?
$check = strpos($old_url, '?');
 
//如果存在 ?
if($check !== false)
{
	//如果 ? 后面没有参数,如 http://YITU.org/index.php?
	if(substr($old_url, $check+1) == '')
	{
		//可以直接加上附加参数
		$new_url = $old_url;
	}
	else	//如果有参数,如:http://YITU.org/index.php?ID=12
	{
		$new_url = $old_url.'&';
	}
}
else	//如果不存在 ?
{
	$new_url = $old_url.'?';
}
 
echo $new_url;
?>

获取文件夹大小并且显示为易于读取的文件单位

获取文件夹大小并格式化

在获取文件夹中的包含文件时使用了递归的方法,依次取得下级文件和文件夹的大小,然后将返回的大小格式化为易于读取的单位。

 
<?php
// 说明: 获取文件夹大小并且显示为易于读取的文件单位
// 整理:http://www.CodeBit.cn

//获取文件夹大小
function dir_size($dir) {
    if (!preg_match('#/$#', $dir)) {
        $dir .= '/';
    }
    $totalsize = 0;
    //调用文件列表
    foreach (get_file_list($dir) as $name) {
        $totalsize += (@is_dir($dir.$name) ? dir_size("$dir$name/") :
            (int)@filesize($dir.$name));
    }
    return $totalsize;
}

//获取文件列表
function get_file_list($path) {
    $f = $d = array();
    //获取所有文件
    foreach (get_all_files($path) as $name) {
        if (@is_dir($path.$name)) {
            $d[] = $name;
        } else if (@is_file($path.$name)) {
            $f[] = $name;
        }
    }
    natcasesort($d);
    natcasesort($f);
    return array_merge($d, $f);
}

//获取所有文件
function get_all_files($path) {
    $list = array();
    if (($hndl = @opendir($path)) === false) {
        return $list;
    }
    while (($file=readdir($hndl)) !== false) {
        if ($file != '.' && $file != '..') {
            $list[] = $file;
        }
    }
    closedir($hndl);
    return $list;
}

//转换单位
function setupSize($fileSize) {
    $size = sprintf("%u", $fileSize);
    if($size == 0) {
        return("0 Bytes");
    }
    $sizename = array(" Bytes", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB");
    return round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . $sizename[$i];
}

//目录
$path = './test_dir/';

//显示文件列表
print_r(get_file_list($path)).'<br>';

//显示文件大小
echo dir_size($path).'<br>';

//显示转换过单位的大小
echo setupSize(dir_size($path));

?>

代码包含四个函数,dir_size() 是获取文件夹大小的函数,函数中使用了递归的方法,此函数需要调用 get_file_list() ,获取文件夹中的所有文件列表,如果文件列表中有文件夹存在,就调用 get_all_files() 获取文件夹下的文件列表。由此取得目标文件夹的大小。

setupSize() 是将传人的大小转换为易于读取的文件单位,可以转换成 Bytes, KB, MB, GB, TB, PB, EB, ZB, YB 等单位。

摘录自 User manager for PureFTPd 的大小转换函数

PureFTPd 是 *nix 下的一个 FTP 服务器软件,而User manager for PureFTPd 则是为了方便在线管理 ftp 用户设计制作的。作者是:M.Mastenbroek。

 
<?php
// 说明:摘录自 User manager for PureFTPd 的大小转换函数
// 整理:http://www.CodeBit.cn

function DisplayFileSize($filesize) {
	$array = array(
		'YB' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
		'ZB' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
		'EB' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
		'PB' => 1024 * 1024 * 1024 * 1024 * 1024,
		'TB' => 1024 * 1024 * 1024 * 1024,
		'GB' => 1024 * 1024 * 1024,
		'MB' => 1024 * 1024,
		'KB' => 1024,
	);
	if($filesize <= 1024)
	{
		$filesize = $filesize . ' B';
	}
	foreach($array AS $name => $size)
	{
		if($filesize > $size || $filesize == $size)
		{
			$filesize = round((round($filesize / $size * 100) / 100), 0) . ' ' . $name;
		}
	}
	return $filesize;
}

echo DisplayFileSize( 5145115 );

?>

用 stripslashes 还原 addslashes 转义后的数据

首先测试 magic_quotes_gpc 是否为 ON, 如果是,则用 array_map() 递归还原转义的数据。

 
<?php
// 说明: 用 stripslashes 还原 addslashes 转义后的数据
// 整理:http://www.CodeBit.cn
if(get_magic_quotes_gpc())
{
	function stripslashes_deep($value)
	{
		$value = is_array($value) ? array_map('stripslashes_deep', $value) : (isset($value) ? stripslashes($value) : null);
		return $value;
	}
	
	$_POST = stripslashes_deep($_POST);
	$_GET = stripslashes_deep($_GET);
	$_COOKIE = stripslashes_deep($_COOKIE);
}
?>

由于 stripslashes 会将 NULL 转换为 string(0) "" ,所以需要判断是否有值:

(isset($value) ? stripslashes($value) : null)

删除非空目录的解决方案

执行删除文件夹的操作时,必须首先确保您有这个权限!

 
<?php
// 说明: 删除非空目录的解决方案
// 整理:http://www.CodeBit.cn
function removeDir($dirName)
{
	if(! is_dir($dirName))
	{
		return false;
	}
	$handle = @opendir($dirName);
	while(($file = @readdir($handle)) !== false)
	{
		if($file != '.' && $file != '..')
		{
			$dir = $dirName . '/' . $file;
			is_dir($dir) ? removeDir($dir) : @unlink($dir);
		}
	}
	closedir($handle);
	
	return rmdir($dirName) ;
}
?>

先检查此目录下是否有文件,如果有,是文件夹的话就再调用此函数删除,如果是文件就直接调用 unlink 删除,最后删除此目录。

服务器端用 mysql_real_escape_string 清洁客户端数据

用 array_map() 调用 mysql_real_escape_string 清理数组

由于 mysql_real_escape_string 需要 MySQL 数据库连接,因此,在调用 mysql_real_escape_string 之前,必须连接上 MySQL 数据库。

 
<?php
// 说明:用 array_map() 调用 mysql_real_escape_string 清理数组
// 整理:http://www.codebit.cn
function mysqlClean($data)
{
	return (is_array($data))?array_map('mysqlClean', $data):mysql_real_escape_string($data);
}
?>

调用方法

 
<?php
$conn = mysql_connect('localhost', 'user', 'pass');
...

$_POST = mysqlClean($_POST);
?>

经过清洁的数据可以直接插入数据库。

注意!mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用。否则只能用 mysql_escape_string ,两者的区别是:

mysql_real_escape_string 考虑到连接的当前字符集,而mysql_escape_string 不考虑。

用 mysql_real_escape_string 清洁并限制字符长度

由于 mysql_real_escape_string 需要 MySQL 数据库连接,因此,在调用 mysql_real_escape_string 之前,必须连接上 MySQL 数据库。

在知道数据类型为字符串时,我们可以在清洁数据的同时限制字符串长度。此方法来自 David Lane, Hugh E. Williams《Web Database Application with PHP and MySQL 》(O’Reilly, May 2004)

 
<?php
// 说明:用 mysql_real_escape_string 清洁并限制字符长度
// 整理:http://www.codebit.cn
function mysqlClean($array, $index, $maxlength)
{
	if (isset($array[$index]))
	{
		$input = substr($array["{$index}"], 0, $maxlength);
		$input = mysql_real_escape_string($input);
		return ($input);
	}
	return NULL;
}
?>

调用方法:

 
<?php
$conn = mysql_connect('localhost', 'user', 'pass');

if(isset($_POST['username']))
{
	$_POST['username'] = mysqlClean($_POST, 'username', 20);
	echo $_POST['username'];
}
?>

将 $_POST 数组中的 ‘username’ 清洁并截取前20位字符。