当前位置:  编程技术>php
本页文章导读:
    ▪discuz程序的PHP加密函数原理分析       原理如下,假如:   加密   明文:1010 1001   密匙:1110 0011   密文:0100 1010   得出密文0100 1010,解密之需和密匙异或下就可以了   解密   密文:0100 1010   密匙:1110 0011 .........
    ▪PHP源码之explode使用说明       当我们需要将一个数组根据某个字符或字串进行分割成数组的时候,explode用的很happy,但是你知道~explode是怎么工作的么~~ 首先可以肯定的是,explode也是会分配空间的,毫无疑问。 代.........
    ▪PHP在获取指定目录下的目录,在获取的目录下面再创建文件,多平台       代码如下: //取得指定文件夹的目录名称 function get_dir_name($dir_path,$file) { $dirpath = $dir_path; $dir = scandir($dirpath); foreach ($dir as $key=>$value) { if (is_dir($dirpath.'/'.$value) && $value != '.' && $va.........

[1]discuz程序的PHP加密函数原理分析
    来源: 互联网  发布时间: 2013-11-30
原理如下,假如:
  加密
  明文:1010 1001
  密匙:1110 0011
  密文:0100 1010
  得出密文0100 1010,解密之需和密匙异或下就可以了
  解密
  密文:0100 1010
  密匙:1110 0011
  明文:1010 1001
  并没有什么高深的算法,密匙重要性很高,所以,关键在于怎么生成密匙。
  那我们一起看下康盛的authcode怎么做的吧
代码如下:

// 参数解释
// $string: 明文 或 密文
// $operation:DECODE表示解密,其它表示加密
// $key: 密匙
// $expiry:密文有效期
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
// 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
$ckey_length = 4;

// 密匙
$key = md5($key ? $key : $GLOBALS['discuz_auth_key']);

// 密匙a会参与加解密
$keya = md5(substr($key, 0, 16));
// 密匙b会用来做数据完整性验证
$keyb = md5(substr($key, 16, 16));
// 密匙c用于变化生成的密文
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length):
  substr(md5(microtime()), -$ckey_length)) : '';
// 参与运算的密匙
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
// 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),解密时会通过这个密匙验证数据完整性
// 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) :
  sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
// 产生密匙簿
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
// 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
// 核心加解密部分
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
// 从密匙簿得出密匙进行异或,再转成字符
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == 'DECODE') {
// substr($result, 0, 10) == 0 验证数据有效性
// substr($result, 0, 10) - time() > 0 验证数据有效性
// substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性
// 验证数据有效性,请看未加密明文的格式
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) &&
  substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
// 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
// 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
return $keyc.str_replace('=', '', base64_encode($result));
}
}

但是有点遗憾,这个函数所有权属于康盛创想,并不能自由使用的

    
[2]PHP源码之explode使用说明
    来源: 互联网  发布时间: 2013-11-30
当我们需要将一个数组根据某个字符或字串进行分割成数组的时候,explode用的很happy,但是你知道~explode是怎么工作的么~~
首先可以肯定的是,explode也是会分配空间的,毫无疑问。
代码如下:

//文件1:ext/standard/string.c
//先来看下explode的源代码
PHP_FUNCTION(explode)
{
char *str, *delim;
int str_len = 0, delim_len = 0;
long limit = LONG_MAX; /* No limit */
zval zdelim, zstr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &delim, &delim_len, &str, &str_len, &limit) == FAILURE) {
return;
}
if (delim_len == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
RETURN_FALSE;
}
//这里会开辟一个数组,用来存放分割后的数据
array_init(return_value);
//因为这个,我们用explode('|', '');成为了合法的
if (str_len == 0) {
if (limit >= 0) {
add_next_index_stringl(return_value, "", sizeof("") - 1, 1);
}
return;
}
//下面这两个是将原字串和分割符都构建成_zval_struct 结构,
//ZVAL_STRINGL会分配空间哦~~源代码随后贴出
ZVAL_STRINGL(&zstr, str, str_len, 0);
ZVAL_STRINGL(&zdelim, delim, delim_len, 0);
//limit值是explode中允许传递的explode的第三个参数,它允许正负
if (limit > 1) {
php_explode(&zdelim, &zstr, return_value, limit);
} else if (limit < 0) {
php_explode_negative_limit(&zdelim, &zstr, return_value, limit);
} else {
add_index_stringl(return_value, 0, str, str_len, 1);
}
}

代码如下:

//ZVAL_STRINGL的源代码:
//文件2:zend/zend_API.c
#define ZVAL_STRINGL(z, s, l, duplicate) { \
const char *__s=(s); int __l=l; \
Z_STRLEN_P(z) = __l; \
Z_STRVAL_P(z) = (duplicate?estrndup(__s, __l):(char*)__s);\
Z_TYPE_P(z) = IS_STRING; \
}
....
//estrndup才是主菜:
//文件3:zend/zend_alloc.h
#define estrndup(s, length) _estrndup((s), (length) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
....
//_estrndup的实现: zend/zend_alloc.c
ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
char *p;
p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
if (UNEXPECTED(p == NULL)) {
return p;
}
memcpy(p, s, length); //分配空间
p[length] = 0;
return p;
}
//另外在substr和strrchr strstr中用到的ZVAL_STRING也是使用了上诉的实现

下面根据explode的第三个参数limit来分析调用:条件对应的是explode中最后的三行,对limit条件的不同
注: limit在缺省的时候(没有传递),他的默认值是LONG_MAX,也就是属于分支1的情况
1、limit > 1 :
调用php_explode方法,该方法也可以在ext/standard/string.c中找到,并且是紧接着explode实现的上面出现(所以在查找本函数中调用来自本文件的方法的时候很方便,几乎无一列外都是在该函数的紧接着的上面^_^),
代码如下:

PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, long limit)
{
char *p1, *p2, *endp;
//先得到的是源字串的末尾位置的指针
endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
//记录开始位置
p1 = Z_STRVAL_P(str);
//下面这个是获得分割符在str中的位置,可以看到在strrpos和strpos中也用到了这个方法去定位
p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
if (p2 == NULL) {
//因为这个,所以当我们调用explode('|', 'abc');是合法的,出来的的就是array(0 => 'abc')
add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1);
} else {
//依次循环获得下一个分隔符的位置,直到结束
do {
//将得到的子字串(上个位置到这个位置中间的一段,第一次的时候上个位置就是开始
add_next_index_stringl(return_value, p1, p2 - p1, 1);
//定位到分隔符位置p2+分隔符的长度的位置
//比如,分隔符='|', 原字串= 'ab|c', p2 = 2, 则p1=2+1=3
p1 = p2 + Z_STRLEN_P(delim);
} while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL &&
--limit > 1);
//将最后的一个分隔符后面的字串放到结果数组中
//explode('|', 'avc|sdf'); => array(0 => 'avc', 1= > 'sdf')
if (p1 <= endp)
add_next_index_stringl(return_value, p1, endp-p1, 1);
}
}

2、limit < 0 :
调用php_explode_negative_limit方法
代码如下:

PHPAPI void php_explode_negative_limit(zval *delim, zval *str, zval *return_value, long limit)
{
#define EXPLODE_ALLOC_STEP 64
char *p1, *p2, *endp;
endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
p1 = Z_STRVAL_P(str);
p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
if (p2 == NULL) {
//它这里竟然没有处理,那explode('|', 'abc', -1) 就成非法的了,获得不了任何值
/*
do nothing since limit <= -1, thus if only one chunk - 1 + (limit) <= 0
by doing nothing we return empty array
*/
} else {
int allocated = EXPLODE_ALLOC_STEP, found = 0;
long i, to_return;
char **positions = emalloc(allocated * sizeof(char *));
//注意这里的positions的声明,这个数组是用来保存所有子字串的读取位置
positions[found++] = p1; //当然起始位置还是需要保存
//下面两个循环,第一个是循环所有在字符串中出现的分隔符位置,并保存下一个子字串读取位置起来
do {
if (found >= allocated) {
allocated = found + EXPLODE_ALLOC_STEP;/* make sure we have enough memory */
positions = erealloc(positions, allocated*sizeof(char *));
}
positions[found++] = p1 = p2 + Z_STRLEN_P(delim);
} while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL);
//这个就是从数组中开始获得返回的结果将从哪个子字串开始读
to_return = limit + found;
/* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
for (i = 0;i < to_return;i++) { /* this checks also for to_return > 0 */
add_next_index_stringl(return_value, positions[i],
(positions[i+1] - Z_STRLEN_P(delim)) - positions[i],
1
);
}
efree(positions);//很重要,释放内存
}
#undef EXPLODE_ALLOC_STEP
}

3、limit = 1 or limit = 0 :
当所有第一和第二条件都不满足的时候,就进入的这个分支,这个分支很简单就是将源字串放到输出数组中,explode('|', 'avc|sd', 1) or explode('|', 'avc|sd', 0) 都将返回array(0 => 'avc|sd');
代码如下:

//add_index_stringl源代码
//文件4:zend/zend_API.c
ZEND_API int add_next_index_stringl(zval *arg, const char *str, uint length, int duplicate) /* {{{ */
{
zval *tmp;
MAKE_STD_ZVAL(tmp);
ZVAL_STRINGL(tmp, str, length, duplicate);
return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL);
}
//zend_hash_next_index_insert
//zend/zend_hash.h
#define zend_hash_next_index_insert(ht, pData, nDataSize, pDest) \
_zend_hash_index_update_or_next_insert(ht, 0, pData, nDataSize, pDest, HASH_NEXT_INSERT ZEND_FILE_LINE_CC)
//zend/zend_hash.c
///太长了~~~~不贴了

可见(不包含分配空间这些),
当limit>1的时候,效率是O(N)【N为limit值】,
当limit<0的时候,效率是O(N+M)【N为limit值, M 为分割符出现次数】,
当limit=1 or limit=0 的时候, 效率是O(1)

    
[3]PHP在获取指定目录下的目录,在获取的目录下面再创建文件,多平台
    来源: 互联网  发布时间: 2013-11-30
代码如下:

//取得指定文件夹的目录名称
function get_dir_name($dir_path,$file)
{
$dirpath = $dir_path;
$dir = scandir($dirpath);
foreach ($dir as $key=>$value)
{
if (is_dir($dirpath.'/'.$value) && $value != '.' && $value != '..')
{
//echo $dirpath.'/'.$value.'/'.$file;
//在目录下生成一个config.php文件,当然这个文件可以自己定义了
if (!file_exists($dirpath.'/'.$value.'/'.$file))
{
$fo = fopen($dirpath.'/'.$value.'/'.$file,'xb+'); //在这里的时候,我之前尝试用w+,结果失败,
//在windows 下,我有创建成功,请注意了!所有建议用xb+,兼容多平台
chmod($file,"0777");
fwrite( $fo,'i is a zongzi ,here is config file!') or die('配置文件创建失败!请检查是否有此目录和文件的操作权限!');
fclose($fo);
}
$arr[] = $value;
}
}
return $arr;
}

    
最新技术文章:
▪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