PHP函数

PHP函数

PHP如何求两个数组的交叉并补集?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 80 次浏览 • 2018-11-09 11:52 • 来自相关话题

PHP升级7.2之后需要注意的“坑”

PHPzkbhj 发表了文章 • 0 个评论 • 245 次浏览 • 2018-09-12 20:25 • 来自相关话题

最近升级了PHP版本,从7.1升级到7.2,升级前版本:
PHP 7.1.14 (cli) (built: Feb 2 2018 08:42:59) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.1.14, Copyright (c) 1999-2018, by Zend Technologies
with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans升级后版本:
PHP 7.2.2 (cli) (built: Feb 24 2018 17:51:12) ( ZTS DEBUG )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.2, Copyright (c) 1999-2018, by Zend Technologies升级完成之后发现有几个框架在使用时都出现了问题,主要原因集中在7.2之后废弃了一些功能,下面列出几个常见的问题:

1、each函数已被废弃:

之前版本写法:<?php
$array = array();
each($array);

// Deprecated: The each() function is deprecated. This message will be suppressed on further calls在7.2版本中会提示过时,可以使用foreach替代each方法,也可以自己修改each方法替代:
<?php
function func_new_each(&$array){
$res = array();
$key = key($array);
if($key !== null){
next($array);
$res[1] = $res['value'] = $array[$key];
$res[0] = $res['key'] = $key;
}else{
$res = false;
}
return $res;
}
2、当传递一个无效参数时,count()函数将抛出warning警告:

之前版本写法<?php
count('');

// Warning: count(): Parameter must be an array or an object that implements Countable在7.2版本中将严格执行类型区分,参数类型不正确,将会出现警告,所以需要在使用count方法时注意参数的值,不过也可以通过自己修改方法来替代(不建议):
<?php
function func_new_count($array_or_countable,$mode = COUNT_NORMAL){
if(is_array($array_or_countable) || is_object($array_or_countable)){
return count($array_or_countable, $mode);
}else{
return 0;
}
}3、create_function被废弃,可以用匿名函数来代替:

之前版本写法:<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "New anonymous function: $newfunc\n";
echo $newfunc(2, M_E) . "\n";
// outputs
// New anonymous function: lambda_1
// ln(2) + ln(2.718281828459) = 1.6931471805599

// Warning This function has been DEPRECATED as of PHP 7.2.0. Relying on this function is highly discouraged.在7.2版本中会有警告提示,可修改为匿名函数来替代:
<?php
$newfunc = function ($a,$b){
return "ln($a) + ln($b) = " . log($a * $b);
};
echo $newfunc(2, M_E) . "\n";以上就是升级之后暂时遇到的几个问题,其它相关修改可详看链家产品技术团队做的翻译及整理:PHP7.2 版本指南
https://mp.weixin.qq.com/s/60pohj2n7Pxba3G9vY92yg 查看全部
最近升级了PHP版本,从7.1升级到7.2,升级前版本:
PHP 7.1.14 (cli) (built: Feb  2 2018 08:42:59) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.1.14, Copyright (c) 1999-2018, by Zend Technologies
with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans
升级后版本:
PHP 7.2.2 (cli) (built: Feb 24 2018 17:51:12) ( ZTS DEBUG )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.2, Copyright (c) 1999-2018, by Zend Technologies
升级完成之后发现有几个框架在使用时都出现了问题,主要原因集中在7.2之后废弃了一些功能,下面列出几个常见的问题:

1、each函数已被废弃:

之前版本写法:
<?php
$array = array();
each($array);

// Deprecated: The each() function is deprecated. This message will be suppressed on further calls
在7.2版本中会提示过时,可以使用foreach替代each方法,也可以自己修改each方法替代:
<?php
function func_new_each(&$array){
$res = array();
$key = key($array);
if($key !== null){
next($array);
$res[1] = $res['value'] = $array[$key];
$res[0] = $res['key'] = $key;
}else{
$res = false;
}
return $res;
}

2、当传递一个无效参数时,count()函数将抛出warning警告:

之前版本写法
<?php
count('');

// Warning: count(): Parameter must be an array or an object that implements Countable
在7.2版本中将严格执行类型区分,参数类型不正确,将会出现警告,所以需要在使用count方法时注意参数的值,不过也可以通过自己修改方法来替代(不建议):
<?php
function func_new_count($array_or_countable,$mode = COUNT_NORMAL){
if(is_array($array_or_countable) || is_object($array_or_countable)){
return count($array_or_countable, $mode);
}else{
return 0;
}
}
3、create_function被废弃,可以用匿名函数来代替:

之前版本写法:
<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "New anonymous function: $newfunc\n";
echo $newfunc(2, M_E) . "\n";
// outputs
// New anonymous function: lambda_1
// ln(2) + ln(2.718281828459) = 1.6931471805599

// Warning This function has been DEPRECATED as of PHP 7.2.0. Relying on this function is highly discouraged.
在7.2版本中会有警告提示,可修改为匿名函数来替代:
<?php
$newfunc = function ($a,$b){
return "ln($a) + ln($b) = " . log($a * $b);
};
echo $newfunc(2, M_E) . "\n";
以上就是升级之后暂时遇到的几个问题,其它相关修改可详看链家产品技术团队做的翻译及整理:PHP7.2 版本指南
https://mp.weixin.qq.com/s/60pohj2n7Pxba3G9vY92yg

PHP函数的参数里,前面三个点的形式...$args是什么含义和用法?

PHPzkbhj 发表了文章 • 0 个评论 • 273 次浏览 • 2018-09-07 13:30 • 来自相关话题

这是PHP5.6添加的功能(一种语法糖): 
可以通过...将函数参数存储在紧接的可遍历的变量中。
 
function add($a, $b, $c)
{
return $a + $b + $c;
}

$num=[2, 3];
echo add(1, ...$num); //6 
上面的第二个和第三个参数将会从$num中循环赋值($b为2,$c为3)。
 
手册地址:http://php.net/manual/zh/migra ... s.php 查看全部
这是PHP5.6添加的功能(一种语法糖): 
可以通过...将函数参数存储在紧接的可遍历的变量中。
 
function add($a, $b, $c)
{
return $a + $b + $c;
}

$num=[2, 3];
echo add(1, ...$num); //6
 
上面的第二个和第三个参数将会从$num中循环赋值($b为2,$c为3)。
 
手册地址:http://php.net/manual/zh/migra ... s.php

PHP获取远程文件的mime类型的方法

PHPzkbhj 发表了文章 • 0 个评论 • 125 次浏览 • 2018-09-06 19:45 • 来自相关话题

 /**
* 获取远程或本地文件信息
* @param string $strUrl 远程文件或本地文件地址
* @param integer $intType 调用方式(1:get_headers 2:fsocketopen 3:curl 4:本地文件)
* @param array $arrOptional
* @return array
* @author mengdj<mengdj#outlook.com>
*/
function remote_filesize($strUrl,$intType=1,$arrOptional=array()){
$arrRet=array(
"length"=>0, //大小,字节为单位
"mime"=>"", //mime类型
"filename"=>"", //文件名
"status"=>0 //状态码
);
switch($intType){
case 1:
//利用get_headers函数
if(($arrTmp=get_headers($strUrl,true))){
$arrRet=array("length"=>$arrTmp['Content-Length'],"mime"=>$arrTmp['Content-Type']);
if(preg_match('/filename=\"(.*)\"/si',$arrTmp['Content-Disposition'],$arr)){
$arrRet["filename"]=$arr[1];
}
if(preg_match('/\s(\d+)\s/',$arrTmp[0],$arr)){
$arrRet["status"]=$arr[1];
}
}
break;
case 2:
//利用fsocket
if(($arrUrl=parse_url($strUrl))){
if($fp=@fsockopen($arrUrl['host'],empty($arrUrl['port'])?80:$arrUrl['port'],$error)){
@fputs($fp,"GET ".(empty($arrUrl['path'])?'/':$arrUrl['path'])." HTTP/1.1\r\n");
@fputs($fp,"Host: $arrUrl[host]\r\n");
@fputs($fp,"Connection: Close\r\n\r\n");
while(!feof($fp)){
$tmp=fgets($fp);
if(trim($tmp)==''){
//此行代码只读到头信息即可
break;
}else{
(preg_match('/(HTTP.*)(\s\d{3}\s)/',$tmp,$arr))&&$arrRet['status']=trim($arr[2]);
(preg_match('/Content-Length:(.*)/si',$tmp,$arr))&&$arrRet['length']=trim($arr[1]);
(preg_match('/Content-Type:(.*)/si',$tmp,$arr))&&$arrRet['mime']=trim($arr[1]);
(preg_match('/filename=\"(.*)\"/si',$tmp,$arr))&&$arrRet['filename']=trim($arr[1]);
}
}
@fclose($fp);
}
}
break;
case 3:
//利用curl
if(($ch=curl_init($strUrl))){
curl_setopt($ch,CURLOPT_HEADER,1);
curl_setopt($ch,CURLOPT_NOBODY,1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
if(isset($arrOptional['user'])&&isset($arrOptional['password'])){
$headers=array('Authorization: Basic '.base64_encode($arrOptional['user'].':'.$arrOptional['password']));
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
}
$tmp=curl_exec($ch);
curl_close($ch);
(preg_match('/Content-Length:\s([0-9].+?)\s/',$tmp,$arr))&&$arrRet['length']=trim($arr[1]);
(preg_match('/Content-Type:\s(.*)\s/',$tmp,$arr))&&$arrRet['mime']=trim($arr[1]);
(preg_match('/filename=\"(.*)\"/i',$tmp,$arr))&&$arrRet['filename']=trim($arr[1]);
(preg_match('/(HTTP.*)(\s\d{3}\s)/',$tmp,$arr))&&$arrRet['status']=trim($arr[2]);
}
break;
case 4:
//本地处理
if(file_exists($strUrl)) {
$arrRet=array(
"length"=>filesize($strUrl),
"mime" =>mime_content_type($strUrl),
"filename"=>basename($strUrl),
"status"=>200
);
}else{
$arrRet=array(
"length"=>0,
"mime" =>'',
"filename"=>basename($strUrl),
"status"=>404
);
}
break;
}
if(isset($arrOptional['getimagesize'])&&$arrRet['status']=='200'){
if(($arrTmp=@getimagesize($strUrl))){
$arrRet['width']=$arrTmp[0];
$arrRet['height']=$arrTmp[1];
$arrRet['type']=$arrTmp[2];
$arrRet['tag']=$arrTmp[3];
$arrRet['bits']=$arrTmp['bits'];
$arrRet['channels']=$arrTmp['channels'];
!isset($arrRet['mime'])&&$arrRet['mime']=$arrTmp['mime'];
}
}
return $arrRet;
} 查看全部
 
/**
* 获取远程或本地文件信息
* @param string $strUrl 远程文件或本地文件地址
* @param integer $intType 调用方式(1:get_headers 2:fsocketopen 3:curl 4:本地文件)
* @param array $arrOptional
* @return array
* @author mengdj<mengdj#outlook.com>
*/
function remote_filesize($strUrl,$intType=1,$arrOptional=array()){
$arrRet=array(
"length"=>0, //大小,字节为单位
"mime"=>"", //mime类型
"filename"=>"", //文件名
"status"=>0 //状态码
);
switch($intType){
case 1:
//利用get_headers函数
if(($arrTmp=get_headers($strUrl,true))){
$arrRet=array("length"=>$arrTmp['Content-Length'],"mime"=>$arrTmp['Content-Type']);
if(preg_match('/filename=\"(.*)\"/si',$arrTmp['Content-Disposition'],$arr)){
$arrRet["filename"]=$arr[1];
}
if(preg_match('/\s(\d+)\s/',$arrTmp[0],$arr)){
$arrRet["status"]=$arr[1];
}
}
break;
case 2:
//利用fsocket
if(($arrUrl=parse_url($strUrl))){
if($fp=@fsockopen($arrUrl['host'],empty($arrUrl['port'])?80:$arrUrl['port'],$error)){
@fputs($fp,"GET ".(empty($arrUrl['path'])?'/':$arrUrl['path'])." HTTP/1.1\r\n");
@fputs($fp,"Host: $arrUrl[host]\r\n");
@fputs($fp,"Connection: Close\r\n\r\n");
while(!feof($fp)){
$tmp=fgets($fp);
if(trim($tmp)==''){
//此行代码只读到头信息即可
break;
}else{
(preg_match('/(HTTP.*)(\s\d{3}\s)/',$tmp,$arr))&&$arrRet['status']=trim($arr[2]);
(preg_match('/Content-Length:(.*)/si',$tmp,$arr))&&$arrRet['length']=trim($arr[1]);
(preg_match('/Content-Type:(.*)/si',$tmp,$arr))&&$arrRet['mime']=trim($arr[1]);
(preg_match('/filename=\"(.*)\"/si',$tmp,$arr))&&$arrRet['filename']=trim($arr[1]);
}
}
@fclose($fp);
}
}
break;
case 3:
//利用curl
if(($ch=curl_init($strUrl))){
curl_setopt($ch,CURLOPT_HEADER,1);
curl_setopt($ch,CURLOPT_NOBODY,1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
if(isset($arrOptional['user'])&&isset($arrOptional['password'])){
$headers=array('Authorization: Basic '.base64_encode($arrOptional['user'].':'.$arrOptional['password']));
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
}
$tmp=curl_exec($ch);
curl_close($ch);
(preg_match('/Content-Length:\s([0-9].+?)\s/',$tmp,$arr))&&$arrRet['length']=trim($arr[1]);
(preg_match('/Content-Type:\s(.*)\s/',$tmp,$arr))&&$arrRet['mime']=trim($arr[1]);
(preg_match('/filename=\"(.*)\"/i',$tmp,$arr))&&$arrRet['filename']=trim($arr[1]);
(preg_match('/(HTTP.*)(\s\d{3}\s)/',$tmp,$arr))&&$arrRet['status']=trim($arr[2]);
}
break;
case 4:
//本地处理
if(file_exists($strUrl)) {
$arrRet=array(
"length"=>filesize($strUrl),
"mime" =>mime_content_type($strUrl),
"filename"=>basename($strUrl),
"status"=>200
);
}else{
$arrRet=array(
"length"=>0,
"mime" =>'',
"filename"=>basename($strUrl),
"status"=>404
);
}
break;
}
if(isset($arrOptional['getimagesize'])&&$arrRet['status']=='200'){
if(($arrTmp=@getimagesize($strUrl))){
$arrRet['width']=$arrTmp[0];
$arrRet['height']=$arrTmp[1];
$arrRet['type']=$arrTmp[2];
$arrRet['tag']=$arrTmp[3];
$arrRet['bits']=$arrTmp['bits'];
$arrRet['channels']=$arrTmp['channels'];
!isset($arrRet['mime'])&&$arrRet['mime']=$arrTmp['mime'];
}
}
return $arrRet;
}

PHP中new self()和new static()有什么区别?

回复

PHPzkbhj 发起了问题 • 1 人关注 • 0 个回复 • 186 次浏览 • 2018-08-21 09:56 • 来自相关话题

如何过滤掉数组中不符合要求或者是false类型的数据?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 203 次浏览 • 2018-08-17 15:44 • 来自相关话题

PHP中如何能让json_encode之后的内容更易读?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 204 次浏览 • 2018-08-03 15:17 • 来自相关话题

PHP按照数组中某个键的值进行排序怎么处理?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 207 次浏览 • 2018-07-19 11:52 • 来自相关话题

PHP如何高效的遍历目录及子目录下的所有文件获取文件路径信息?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 210 次浏览 • 2018-07-17 11:38 • 来自相关话题

如何根据经纬度坐标获得墨卡托原理计算的格子编号?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 245 次浏览 • 2018-06-28 17:46 • 来自相关话题

条新动态, 点击查看
zkbhj

zkbhj 回答了问题 • 2017-06-02 10:43 • 1 个回复 不感兴趣

如何生成全局唯一ID并能大致有序?

赞同来自:

Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序(方便客户端排序),并且在分布式系统中不同机器产生的id必须不同。

Snowflake算法核... 显示全部 »
Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序(方便客户端排序),并且在分布式系统中不同机器产生的id必须不同。

Snowflake算法核心

把时间戳,工作机器id,序列号组合在一起。

133
 
除了最高位bit标记为不可用以外,其余三组bit占位均可浮动,看具体的业务需求而定。默认情况下41bit的时间戳可以支持该算法使用到2082年,10bit的工作机器id可以支持1023台机器,序列号支持1毫秒产生4095个自增序列id。下文会具体分析。
 结构为:
0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---0000000000 00
在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。

这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。 
/**
* ID 生成策略
* 毫秒级时间41位+机器ID 10位+毫秒内序列12位。
* 0 41 51 64
+-----------+------+------+
|time |pc |inc |
+-----------+------+------+
* 最高位bit标记为不可用
* 前41bits是以微秒为单位的timestamp。
* 接着10bits是事先配置好的机器ID。
* 最后12bits是累加计数器。
* macheine id(10bits)标明最多只能有1024台机器同时产生ID,sequence number(12bits)也标明1台机器1ms中最多产生4096个ID,
*
*/
class SnowFlake{
private static $epoch = 1462264156000;


public function createID($machineId){
/*
* Time - 41 bits
*/
$time = floor(microtime(true) * 1000);


/*
* Substract custom epoch from current time
*/
$time -= SnowFlake::$epoch;

/*
* flag number - 1 bits - can not change, beacause is shoule be a positive number
*/
$suffix = 0;

/*
* Create a base and add time to it
*/
$base = decbin(pow(2,40) - 1 + $time);
//$base = sprintf("1s", decbin($time));
/*
* Configured machine id - 10 bits - up to 512 machines
*/
$machineid = decbin(pow(2,9) - 1 + $machineId);
//$machineid = sprintf("0s", decbin($machineId));
/*
* sequence number - 12 bits - up to 2048 random numbers per machine
*/
$random = mt_rand(1, pow(2,11)-1);
$random = decbin(pow(2,11)-1 + $random);
//$random = mt_rand(1, pow(2, 12) - 1);
//$random = sprintf("2s", decbin($random));

/*
* 拼装$base
*/
$base = $suffix.$base.$machineid.$random;
/*
* 讲二进制的base转换成long
*/
$base = bindec($base);


$id = sprintf('%.0f', $base);


return $id;
}
}
我这里的PHP代码序列号是随机产生的,因为我们的业务还不达不到需要有序生成的必要, 而且对于PHP来说要序列化生成必须把这个序列存储到缓存里面去。
 
GIT源码:https://github.com/search?l=PHP&q=snowflake&type=Repositories&utf8=%E2%9C%93

PHP如何求两个数组的交叉并补集?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 80 次浏览 • 2018-11-09 11:52 • 来自相关话题

PHP中new self()和new static()有什么区别?

回复

PHPzkbhj 发起了问题 • 1 人关注 • 0 个回复 • 186 次浏览 • 2018-08-21 09:56 • 来自相关话题

如何过滤掉数组中不符合要求或者是false类型的数据?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 203 次浏览 • 2018-08-17 15:44 • 来自相关话题

PHP中如何能让json_encode之后的内容更易读?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 204 次浏览 • 2018-08-03 15:17 • 来自相关话题

PHP按照数组中某个键的值进行排序怎么处理?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 207 次浏览 • 2018-07-19 11:52 • 来自相关话题

PHP如何高效的遍历目录及子目录下的所有文件获取文件路径信息?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 210 次浏览 • 2018-07-17 11:38 • 来自相关话题

如何根据经纬度坐标获得墨卡托原理计算的格子编号?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 245 次浏览 • 2018-06-28 17:46 • 来自相关话题

如何计算两个日期相差的天数?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 253 次浏览 • 2018-06-27 14:36 • 来自相关话题

PHP如何将多维数组中的指定字符串替换为指定字符串?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 402 次浏览 • 2018-05-31 19:11 • 来自相关话题

PHP如何实现将数组中的某个元素移动到指定位置?

回复

PHPzkbhj 回复了问题 • 1 人关注 • 1 个回复 • 369 次浏览 • 2018-05-30 09:57 • 来自相关话题

PHP升级7.2之后需要注意的“坑”

PHPzkbhj 发表了文章 • 0 个评论 • 245 次浏览 • 2018-09-12 20:25 • 来自相关话题

最近升级了PHP版本,从7.1升级到7.2,升级前版本:
PHP 7.1.14 (cli) (built: Feb 2 2018 08:42:59) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.1.14, Copyright (c) 1999-2018, by Zend Technologies
with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans升级后版本:
PHP 7.2.2 (cli) (built: Feb 24 2018 17:51:12) ( ZTS DEBUG )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.2, Copyright (c) 1999-2018, by Zend Technologies升级完成之后发现有几个框架在使用时都出现了问题,主要原因集中在7.2之后废弃了一些功能,下面列出几个常见的问题:

1、each函数已被废弃:

之前版本写法:<?php
$array = array();
each($array);

// Deprecated: The each() function is deprecated. This message will be suppressed on further calls在7.2版本中会提示过时,可以使用foreach替代each方法,也可以自己修改each方法替代:
<?php
function func_new_each(&$array){
$res = array();
$key = key($array);
if($key !== null){
next($array);
$res[1] = $res['value'] = $array[$key];
$res[0] = $res['key'] = $key;
}else{
$res = false;
}
return $res;
}
2、当传递一个无效参数时,count()函数将抛出warning警告:

之前版本写法<?php
count('');

// Warning: count(): Parameter must be an array or an object that implements Countable在7.2版本中将严格执行类型区分,参数类型不正确,将会出现警告,所以需要在使用count方法时注意参数的值,不过也可以通过自己修改方法来替代(不建议):
<?php
function func_new_count($array_or_countable,$mode = COUNT_NORMAL){
if(is_array($array_or_countable) || is_object($array_or_countable)){
return count($array_or_countable, $mode);
}else{
return 0;
}
}3、create_function被废弃,可以用匿名函数来代替:

之前版本写法:<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "New anonymous function: $newfunc\n";
echo $newfunc(2, M_E) . "\n";
// outputs
// New anonymous function: lambda_1
// ln(2) + ln(2.718281828459) = 1.6931471805599

// Warning This function has been DEPRECATED as of PHP 7.2.0. Relying on this function is highly discouraged.在7.2版本中会有警告提示,可修改为匿名函数来替代:
<?php
$newfunc = function ($a,$b){
return "ln($a) + ln($b) = " . log($a * $b);
};
echo $newfunc(2, M_E) . "\n";以上就是升级之后暂时遇到的几个问题,其它相关修改可详看链家产品技术团队做的翻译及整理:PHP7.2 版本指南
https://mp.weixin.qq.com/s/60pohj2n7Pxba3G9vY92yg 查看全部
最近升级了PHP版本,从7.1升级到7.2,升级前版本:
PHP 7.1.14 (cli) (built: Feb  2 2018 08:42:59) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.1.14, Copyright (c) 1999-2018, by Zend Technologies
with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans
升级后版本:
PHP 7.2.2 (cli) (built: Feb 24 2018 17:51:12) ( ZTS DEBUG )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.2, Copyright (c) 1999-2018, by Zend Technologies
升级完成之后发现有几个框架在使用时都出现了问题,主要原因集中在7.2之后废弃了一些功能,下面列出几个常见的问题:

1、each函数已被废弃:

之前版本写法:
<?php
$array = array();
each($array);

// Deprecated: The each() function is deprecated. This message will be suppressed on further calls
在7.2版本中会提示过时,可以使用foreach替代each方法,也可以自己修改each方法替代:
<?php
function func_new_each(&$array){
$res = array();
$key = key($array);
if($key !== null){
next($array);
$res[1] = $res['value'] = $array[$key];
$res[0] = $res['key'] = $key;
}else{
$res = false;
}
return $res;
}

2、当传递一个无效参数时,count()函数将抛出warning警告:

之前版本写法
<?php
count('');

// Warning: count(): Parameter must be an array or an object that implements Countable
在7.2版本中将严格执行类型区分,参数类型不正确,将会出现警告,所以需要在使用count方法时注意参数的值,不过也可以通过自己修改方法来替代(不建议):
<?php
function func_new_count($array_or_countable,$mode = COUNT_NORMAL){
if(is_array($array_or_countable) || is_object($array_or_countable)){
return count($array_or_countable, $mode);
}else{
return 0;
}
}
3、create_function被废弃,可以用匿名函数来代替:

之前版本写法:
<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "New anonymous function: $newfunc\n";
echo $newfunc(2, M_E) . "\n";
// outputs
// New anonymous function: lambda_1
// ln(2) + ln(2.718281828459) = 1.6931471805599

// Warning This function has been DEPRECATED as of PHP 7.2.0. Relying on this function is highly discouraged.
在7.2版本中会有警告提示,可修改为匿名函数来替代:
<?php
$newfunc = function ($a,$b){
return "ln($a) + ln($b) = " . log($a * $b);
};
echo $newfunc(2, M_E) . "\n";
以上就是升级之后暂时遇到的几个问题,其它相关修改可详看链家产品技术团队做的翻译及整理:PHP7.2 版本指南
https://mp.weixin.qq.com/s/60pohj2n7Pxba3G9vY92yg

PHP函数的参数里,前面三个点的形式...$args是什么含义和用法?

PHPzkbhj 发表了文章 • 0 个评论 • 273 次浏览 • 2018-09-07 13:30 • 来自相关话题

这是PHP5.6添加的功能(一种语法糖): 
可以通过...将函数参数存储在紧接的可遍历的变量中。
 
function add($a, $b, $c)
{
return $a + $b + $c;
}

$num=[2, 3];
echo add(1, ...$num); //6 
上面的第二个和第三个参数将会从$num中循环赋值($b为2,$c为3)。
 
手册地址:http://php.net/manual/zh/migra ... s.php 查看全部
这是PHP5.6添加的功能(一种语法糖): 
可以通过...将函数参数存储在紧接的可遍历的变量中。
 
function add($a, $b, $c)
{
return $a + $b + $c;
}

$num=[2, 3];
echo add(1, ...$num); //6
 
上面的第二个和第三个参数将会从$num中循环赋值($b为2,$c为3)。
 
手册地址:http://php.net/manual/zh/migra ... s.php

PHP获取远程文件的mime类型的方法

PHPzkbhj 发表了文章 • 0 个评论 • 125 次浏览 • 2018-09-06 19:45 • 来自相关话题

 /**
* 获取远程或本地文件信息
* @param string $strUrl 远程文件或本地文件地址
* @param integer $intType 调用方式(1:get_headers 2:fsocketopen 3:curl 4:本地文件)
* @param array $arrOptional
* @return array
* @author mengdj<mengdj#outlook.com>
*/
function remote_filesize($strUrl,$intType=1,$arrOptional=array()){
$arrRet=array(
"length"=>0, //大小,字节为单位
"mime"=>"", //mime类型
"filename"=>"", //文件名
"status"=>0 //状态码
);
switch($intType){
case 1:
//利用get_headers函数
if(($arrTmp=get_headers($strUrl,true))){
$arrRet=array("length"=>$arrTmp['Content-Length'],"mime"=>$arrTmp['Content-Type']);
if(preg_match('/filename=\"(.*)\"/si',$arrTmp['Content-Disposition'],$arr)){
$arrRet["filename"]=$arr[1];
}
if(preg_match('/\s(\d+)\s/',$arrTmp[0],$arr)){
$arrRet["status"]=$arr[1];
}
}
break;
case 2:
//利用fsocket
if(($arrUrl=parse_url($strUrl))){
if($fp=@fsockopen($arrUrl['host'],empty($arrUrl['port'])?80:$arrUrl['port'],$error)){
@fputs($fp,"GET ".(empty($arrUrl['path'])?'/':$arrUrl['path'])." HTTP/1.1\r\n");
@fputs($fp,"Host: $arrUrl[host]\r\n");
@fputs($fp,"Connection: Close\r\n\r\n");
while(!feof($fp)){
$tmp=fgets($fp);
if(trim($tmp)==''){
//此行代码只读到头信息即可
break;
}else{
(preg_match('/(HTTP.*)(\s\d{3}\s)/',$tmp,$arr))&&$arrRet['status']=trim($arr[2]);
(preg_match('/Content-Length:(.*)/si',$tmp,$arr))&&$arrRet['length']=trim($arr[1]);
(preg_match('/Content-Type:(.*)/si',$tmp,$arr))&&$arrRet['mime']=trim($arr[1]);
(preg_match('/filename=\"(.*)\"/si',$tmp,$arr))&&$arrRet['filename']=trim($arr[1]);
}
}
@fclose($fp);
}
}
break;
case 3:
//利用curl
if(($ch=curl_init($strUrl))){
curl_setopt($ch,CURLOPT_HEADER,1);
curl_setopt($ch,CURLOPT_NOBODY,1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
if(isset($arrOptional['user'])&&isset($arrOptional['password'])){
$headers=array('Authorization: Basic '.base64_encode($arrOptional['user'].':'.$arrOptional['password']));
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
}
$tmp=curl_exec($ch);
curl_close($ch);
(preg_match('/Content-Length:\s([0-9].+?)\s/',$tmp,$arr))&&$arrRet['length']=trim($arr[1]);
(preg_match('/Content-Type:\s(.*)\s/',$tmp,$arr))&&$arrRet['mime']=trim($arr[1]);
(preg_match('/filename=\"(.*)\"/i',$tmp,$arr))&&$arrRet['filename']=trim($arr[1]);
(preg_match('/(HTTP.*)(\s\d{3}\s)/',$tmp,$arr))&&$arrRet['status']=trim($arr[2]);
}
break;
case 4:
//本地处理
if(file_exists($strUrl)) {
$arrRet=array(
"length"=>filesize($strUrl),
"mime" =>mime_content_type($strUrl),
"filename"=>basename($strUrl),
"status"=>200
);
}else{
$arrRet=array(
"length"=>0,
"mime" =>'',
"filename"=>basename($strUrl),
"status"=>404
);
}
break;
}
if(isset($arrOptional['getimagesize'])&&$arrRet['status']=='200'){
if(($arrTmp=@getimagesize($strUrl))){
$arrRet['width']=$arrTmp[0];
$arrRet['height']=$arrTmp[1];
$arrRet['type']=$arrTmp[2];
$arrRet['tag']=$arrTmp[3];
$arrRet['bits']=$arrTmp['bits'];
$arrRet['channels']=$arrTmp['channels'];
!isset($arrRet['mime'])&&$arrRet['mime']=$arrTmp['mime'];
}
}
return $arrRet;
} 查看全部
 
/**
* 获取远程或本地文件信息
* @param string $strUrl 远程文件或本地文件地址
* @param integer $intType 调用方式(1:get_headers 2:fsocketopen 3:curl 4:本地文件)
* @param array $arrOptional
* @return array
* @author mengdj<mengdj#outlook.com>
*/
function remote_filesize($strUrl,$intType=1,$arrOptional=array()){
$arrRet=array(
"length"=>0, //大小,字节为单位
"mime"=>"", //mime类型
"filename"=>"", //文件名
"status"=>0 //状态码
);
switch($intType){
case 1:
//利用get_headers函数
if(($arrTmp=get_headers($strUrl,true))){
$arrRet=array("length"=>$arrTmp['Content-Length'],"mime"=>$arrTmp['Content-Type']);
if(preg_match('/filename=\"(.*)\"/si',$arrTmp['Content-Disposition'],$arr)){
$arrRet["filename"]=$arr[1];
}
if(preg_match('/\s(\d+)\s/',$arrTmp[0],$arr)){
$arrRet["status"]=$arr[1];
}
}
break;
case 2:
//利用fsocket
if(($arrUrl=parse_url($strUrl))){
if($fp=@fsockopen($arrUrl['host'],empty($arrUrl['port'])?80:$arrUrl['port'],$error)){
@fputs($fp,"GET ".(empty($arrUrl['path'])?'/':$arrUrl['path'])." HTTP/1.1\r\n");
@fputs($fp,"Host: $arrUrl[host]\r\n");
@fputs($fp,"Connection: Close\r\n\r\n");
while(!feof($fp)){
$tmp=fgets($fp);
if(trim($tmp)==''){
//此行代码只读到头信息即可
break;
}else{
(preg_match('/(HTTP.*)(\s\d{3}\s)/',$tmp,$arr))&&$arrRet['status']=trim($arr[2]);
(preg_match('/Content-Length:(.*)/si',$tmp,$arr))&&$arrRet['length']=trim($arr[1]);
(preg_match('/Content-Type:(.*)/si',$tmp,$arr))&&$arrRet['mime']=trim($arr[1]);
(preg_match('/filename=\"(.*)\"/si',$tmp,$arr))&&$arrRet['filename']=trim($arr[1]);
}
}
@fclose($fp);
}
}
break;
case 3:
//利用curl
if(($ch=curl_init($strUrl))){
curl_setopt($ch,CURLOPT_HEADER,1);
curl_setopt($ch,CURLOPT_NOBODY,1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
if(isset($arrOptional['user'])&&isset($arrOptional['password'])){
$headers=array('Authorization: Basic '.base64_encode($arrOptional['user'].':'.$arrOptional['password']));
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
}
$tmp=curl_exec($ch);
curl_close($ch);
(preg_match('/Content-Length:\s([0-9].+?)\s/',$tmp,$arr))&&$arrRet['length']=trim($arr[1]);
(preg_match('/Content-Type:\s(.*)\s/',$tmp,$arr))&&$arrRet['mime']=trim($arr[1]);
(preg_match('/filename=\"(.*)\"/i',$tmp,$arr))&&$arrRet['filename']=trim($arr[1]);
(preg_match('/(HTTP.*)(\s\d{3}\s)/',$tmp,$arr))&&$arrRet['status']=trim($arr[2]);
}
break;
case 4:
//本地处理
if(file_exists($strUrl)) {
$arrRet=array(
"length"=>filesize($strUrl),
"mime" =>mime_content_type($strUrl),
"filename"=>basename($strUrl),
"status"=>200
);
}else{
$arrRet=array(
"length"=>0,
"mime" =>'',
"filename"=>basename($strUrl),
"status"=>404
);
}
break;
}
if(isset($arrOptional['getimagesize'])&&$arrRet['status']=='200'){
if(($arrTmp=@getimagesize($strUrl))){
$arrRet['width']=$arrTmp[0];
$arrRet['height']=$arrTmp[1];
$arrRet['type']=$arrTmp[2];
$arrRet['tag']=$arrTmp[3];
$arrRet['bits']=$arrTmp['bits'];
$arrRet['channels']=$arrTmp['channels'];
!isset($arrRet['mime'])&&$arrRet['mime']=$arrTmp['mime'];
}
}
return $arrRet;
}

#日常积累# 将一个二维数组按元素类别(大类+小类)进行打散重新排序

PHPzkbhj 发表了文章 • 0 个评论 • 433 次浏览 • 2018-05-30 09:57 • 来自相关话题

需求大概如下:
 
有一个N个元素的数组要按下面的要求进行排序,这N个元素分别是一个个手机,每个手机都有自己的品牌属性,假设有两大品牌,华为A和小米B,实体手机会有:
华为手机(A1),
小米又分为
小米8(B2)、
小米6(B3)、
小米MIX(B4)。

然后要实现以下排序规则:

1、当某一类数据(AB两大类或B大类中的小类)连续超过3条时,按顺序将后面另一类型数据插入到第2条之后。优先进行AB类数据之间的相互插入,当A类数据不足时,进行B类中各小类数据的相互插入。
2、特殊规则:前2条数据为B类时,将后面第1条A类数据插入到第一条B类数据之后,后面数据的插入规则沿用2中描述的规则。

eg:
原顺序:B2,B2,A1,B2,B3,B4,A1,A1,A1,A1,B3,B3,B3,B3,B2
新顺序:B2,A1,B2,B2,A1,B3,B4,A1,A1,B3,A1,B3,B3,B2,B3

这个算法可以怎么实现?
 
按这个需求,想了很久并没有想到合适的办法。后来更改了下规则,将AB大类进行穿插打散,然后如果B类数据偏多,再将多余的B类数据,按照B小类进行穿插打散。实现代码如下:
 
/*
*1 华为手机
*3 小米手机5
*4 小米手机6
*5 小米手机8
*8 小米MIX
*9 小米MIX2S
*
*/
function phoneBreakUp($phone_list,$sort_by = 'phone_type')
{

//定义规则
$rule = [
'huawei' => [1],
'xiaomi' => [3,4,5,8,9]
];

//循环每类房源的数据,将华为和小米区分开
foreach ($phone_list as $key => $value) {

if(in_array($value[$sort_by], $rule['huawei'])){
$temp_phone_list['huawei'][] = $value;

}else{
$temp_phone_list['xiaomi'][] = $value;
}
}


//将华为数据和小米数据进行穿插处理
if(count($temp_phone_list['xiaomi']) >= count($temp_phone_list['huawei'])){

//首先把能够穿插的华为数据穿插处理
$break_phone_list = alternateArray($temp_phone_list['xiaomi'],$temp_phone_list['huawei']);

//如果小米类的数量比华为的多,还需要在剩余的小米数据里,进行穿插处理
for($i=2 * count($temp_phone_list['huawei']) + 1 ; $i < count($break_phone_list); $i++ ){
$whole_rent_list[$break_phone_list[$i][$sort_by]][] = $break_phone_list[$i];

}

//将获得的多余的小米数据进行穿插处理
$new_rent_list = alternateArrayMore($whole_rent_list);

//将穿插后的小米数据,替换掉大数组中的后面部分
array_splice($break_phone_list,2 * count($temp_phone_list['huawei']) + 1,count($break_phone_list) - 2 * count($temp_phone_list['huawei']) - 1,$new_rent_list);


}else{
$break_phone_list = alternateArray($temp_phone_list['huawei'],$temp_phone_list['xiaomi']);
}



return $break_phone_list;
}


/**
*
* 将华为和小米数据进行穿插(大类之间穿插)
*
*/
function alternateArray($big_array, $small_array)
{

$total_counts = count($big_array) + count($small_array);
$big_counts = $small_counts = 0;

for($i=0 ; $i< $total_counts; $i++){

if($i%2 == 0 && $small_counts < count($small_array)){
$break_up_list[$i] = $big_array[$big_counts];
$big_counts++;
}elseif($i%2 != 0 && $small_counts < count($small_array)){
$break_up_list[$i] = $small_array[$small_counts];
$small_counts++;
}else{
$break_up_list[$i] = $big_array[$big_counts];
$big_counts++;
}
}

return $break_up_list;

}


/**
*
* 将多余小米数据进行穿插(小类之间穿插)
*
*/
function alternateArrayMore($more_array)
{
//将二维数组依据二维元素的个数进行排序
foreach ($more_array as $key => $value) {
$more_array[$key]['counts'] = count($value);
}
array_multisort($more_array,SORT_DESC);

foreach ($more_array as $key => $value) {
unset($more_array[$key]['counts']);
}



//一直循环,直到取出二维数组中的所有元素
while (!empty($more_array)) {
foreach ($more_array as $key => $value) {
if(!empty($value)){
$break_up_list[] = array_pop($more_array[$key]);
}else{
//如果某个二维数组元素已经取尽,销毁掉
unset($more_array[$key]);
}
}
}

return $break_up_list;
} 查看全部
需求大概如下:
 
有一个N个元素的数组要按下面的要求进行排序,这N个元素分别是一个个手机,每个手机都有自己的品牌属性,假设有两大品牌,华为A和小米B,实体手机会有:
华为手机(A1),
小米又分为
小米8(B2)、
小米6(B3)、
小米MIX(B4)。

然后要实现以下排序规则:

1、当某一类数据(AB两大类或B大类中的小类)连续超过3条时,按顺序将后面另一类型数据插入到第2条之后。优先进行AB类数据之间的相互插入,当A类数据不足时,进行B类中各小类数据的相互插入。
2、特殊规则:前2条数据为B类时,将后面第1条A类数据插入到第一条B类数据之后,后面数据的插入规则沿用2中描述的规则。

eg:
原顺序:B2,B2,A1,B2,B3,B4,A1,A1,A1,A1,B3,B3,B3,B3,B2
新顺序:B2,A1,B2,B2,A1,B3,B4,A1,A1,B3,A1,B3,B3,B2,B3

这个算法可以怎么实现?
 
按这个需求,想了很久并没有想到合适的办法。后来更改了下规则,将AB大类进行穿插打散,然后如果B类数据偏多,再将多余的B类数据,按照B小类进行穿插打散。实现代码如下:
 
/*
*1 华为手机
*3 小米手机5
*4 小米手机6
*5 小米手机8
*8 小米MIX
*9 小米MIX2S
*
*/
function phoneBreakUp($phone_list,$sort_by = 'phone_type')
{

//定义规则
$rule = [
'huawei' => [1],
'xiaomi' => [3,4,5,8,9]
];

//循环每类房源的数据,将华为和小米区分开
foreach ($phone_list as $key => $value) {

if(in_array($value[$sort_by], $rule['huawei'])){
$temp_phone_list['huawei'][] = $value;

}else{
$temp_phone_list['xiaomi'][] = $value;
}
}


//将华为数据和小米数据进行穿插处理
if(count($temp_phone_list['xiaomi']) >= count($temp_phone_list['huawei'])){

//首先把能够穿插的华为数据穿插处理
$break_phone_list = alternateArray($temp_phone_list['xiaomi'],$temp_phone_list['huawei']);

//如果小米类的数量比华为的多,还需要在剩余的小米数据里,进行穿插处理
for($i=2 * count($temp_phone_list['huawei']) + 1 ; $i < count($break_phone_list); $i++ ){
$whole_rent_list[$break_phone_list[$i][$sort_by]][] = $break_phone_list[$i];

}

//将获得的多余的小米数据进行穿插处理
$new_rent_list = alternateArrayMore($whole_rent_list);

//将穿插后的小米数据,替换掉大数组中的后面部分
array_splice($break_phone_list,2 * count($temp_phone_list['huawei']) + 1,count($break_phone_list) - 2 * count($temp_phone_list['huawei']) - 1,$new_rent_list);


}else{
$break_phone_list = alternateArray($temp_phone_list['huawei'],$temp_phone_list['xiaomi']);
}



return $break_phone_list;
}


/**
*
* 将华为和小米数据进行穿插(大类之间穿插)
*
*/
function alternateArray($big_array, $small_array)
{

$total_counts = count($big_array) + count($small_array);
$big_counts = $small_counts = 0;

for($i=0 ; $i< $total_counts; $i++){

if($i%2 == 0 && $small_counts < count($small_array)){
$break_up_list[$i] = $big_array[$big_counts];
$big_counts++;
}elseif($i%2 != 0 && $small_counts < count($small_array)){
$break_up_list[$i] = $small_array[$small_counts];
$small_counts++;
}else{
$break_up_list[$i] = $big_array[$big_counts];
$big_counts++;
}
}

return $break_up_list;

}


/**
*
* 将多余小米数据进行穿插(小类之间穿插)
*
*/
function alternateArrayMore($more_array)
{
//将二维数组依据二维元素的个数进行排序
foreach ($more_array as $key => $value) {
$more_array[$key]['counts'] = count($value);
}
array_multisort($more_array,SORT_DESC);

foreach ($more_array as $key => $value) {
unset($more_array[$key]['counts']);
}



//一直循环,直到取出二维数组中的所有元素
while (!empty($more_array)) {
foreach ($more_array as $key => $value) {
if(!empty($value)){
$break_up_list[] = array_pop($more_array[$key]);
}else{
//如果某个二维数组元素已经取尽,销毁掉
unset($more_array[$key]);
}
}
}

return $break_up_list;
}

PHP安全:一些需要禁用的PHP危险函数

PHPzkbhj 发表了文章 • 0 个评论 • 209 次浏览 • 2018-05-15 18:06 • 来自相关话题

phpinfo()
功能描述:输出 PHP 环境信息以及相关的模块、WEB 环境等信息。
危险等级:中

passthru()
功能描述:允许执行一个外部程序并回显输出,类似于 exec()。
危险等级:高

exec()
功能描述:允许执行一个外部程序(如 UNIX Shell 或 CMD 命令等)。
危险等级:高

system()
功能描述:允许执行一个外部程序并回显输出,类似于 passthru()。
危险等级:高

chroot()
功能描述:可改变当前 PHP 进程的工作根目录,仅当系统支持 CLI 模式
PHP 时才能工作,且该函数不适用于 Windows 系统。
危险等级:高

scandir()
功能描述:列出指定路径中的文件和目录。
危险等级:中

chgrp()
功能描述:改变文件或目录所属的用户组。
危险等级:高

chown()
功能描述:改变文件或目录的所有者。
危险等级:高

shell_exec()
功能描述:通过 Shell 执行命令,并将执行结果作为字符串返回。
危险等级:高

proc_open()
功能描述:执行一个命令并打开文件指针用于读取以及写入。
危险等级:高

proc_get_status()
功能描述:获取使用 proc_open() 所打开进程的信息。
危险等级:高

error_log()
功能描述:将错误信息发送到指定位置(文件)。
安全备注:在某些版本的 PHP 中,可使用 error_log() 绕过 PHP safe mode,
执行任意命令。
危险等级:低

ini_alter()
功能描述:是 ini_set() 函数的一个别名函数,功能与 ini_set() 相同。
具体参见 ini_set()。
危险等级:高

ini_set()
功能描述:可用于修改、设置 PHP 环境配置参数。
危险等级:高

ini_restore()
功能描述:可用于恢复 PHP 环境配置参数到其初始值。
危险等级:高

dl()
功能描述:在 PHP 进行运行过程当中(而非启动时)加载一个 PHP 外部模块。
危险等级:高

pfsockopen()
功能描述:建立一个 Internet 或 UNIX 域的 socket 持久连接。
危险等级:高

syslog()
功能描述:可调用 UNIX 系统的系统层 syslog() 函数。
危险等级:中

readlink()
功能描述:返回符号连接指向的目标文件内容。
危险等级:中

symlink()
功能描述:在 UNIX 系统中建立一个符号链接。
危险等级:高

popen()
功能描述:可通过 popen() 的参数传递一条命令,并对 popen() 所打开的文件进行执行。
危险等级:高

stream_socket_server()
功能描述:建立一个 Internet 或 UNIX 服务器连接。
危险等级:中

putenv()
功能描述:用于在 PHP 运行时改变系统字符集环境。在低于 5.2.6 版本的 PHP 中,可利用该函数
修改系统字符集环境后,利用 sendmail 指令发送特殊参数执行系统 SHELL 命令。
危险等级:高

禁用方法如下:
打开/etc/php.ini文件,
查找到 disable_functions ,添加需禁用的函数名,如下:phpinfo,eval,passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,fsocket,fsockopen 查看全部
phpinfo()
功能描述:输出 PHP 环境信息以及相关的模块、WEB 环境等信息。
危险等级:中

passthru()
功能描述:允许执行一个外部程序并回显输出,类似于 exec()。
危险等级:高

exec()
功能描述:允许执行一个外部程序(如 UNIX Shell 或 CMD 命令等)。
危险等级:高

system()
功能描述:允许执行一个外部程序并回显输出,类似于 passthru()。
危险等级:高

chroot()
功能描述:可改变当前 PHP 进程的工作根目录,仅当系统支持 CLI 模式
PHP 时才能工作,且该函数不适用于 Windows 系统。
危险等级:高

scandir()
功能描述:列出指定路径中的文件和目录。
危险等级:中

chgrp()
功能描述:改变文件或目录所属的用户组。
危险等级:高

chown()
功能描述:改变文件或目录的所有者。
危险等级:高

shell_exec()
功能描述:通过 Shell 执行命令,并将执行结果作为字符串返回。
危险等级:高

proc_open()
功能描述:执行一个命令并打开文件指针用于读取以及写入。
危险等级:高

proc_get_status()
功能描述:获取使用 proc_open() 所打开进程的信息。
危险等级:高

error_log()
功能描述:将错误信息发送到指定位置(文件)。
安全备注:在某些版本的 PHP 中,可使用 error_log() 绕过 PHP safe mode,
执行任意命令。
危险等级:低

ini_alter()
功能描述:是 ini_set() 函数的一个别名函数,功能与 ini_set() 相同。
具体参见 ini_set()。
危险等级:高

ini_set()
功能描述:可用于修改、设置 PHP 环境配置参数。
危险等级:高

ini_restore()
功能描述:可用于恢复 PHP 环境配置参数到其初始值。
危险等级:高

dl()
功能描述:在 PHP 进行运行过程当中(而非启动时)加载一个 PHP 外部模块。
危险等级:高

pfsockopen()
功能描述:建立一个 Internet 或 UNIX 域的 socket 持久连接。
危险等级:高

syslog()
功能描述:可调用 UNIX 系统的系统层 syslog() 函数。
危险等级:中

readlink()
功能描述:返回符号连接指向的目标文件内容。
危险等级:中

symlink()
功能描述:在 UNIX 系统中建立一个符号链接。
危险等级:高

popen()
功能描述:可通过 popen() 的参数传递一条命令,并对 popen() 所打开的文件进行执行。
危险等级:高

stream_socket_server()
功能描述:建立一个 Internet 或 UNIX 服务器连接。
危险等级:中

putenv()
功能描述:用于在 PHP 运行时改变系统字符集环境。在低于 5.2.6 版本的 PHP 中,可利用该函数
修改系统字符集环境后,利用 sendmail 指令发送特殊参数执行系统 SHELL 命令。
危险等级:高

禁用方法如下:
打开/etc/php.ini文件,
查找到 disable_functions ,添加需禁用的函数名,如下:
phpinfo,eval,passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,fsocket,fsockopen

PHP中的ctype functions函数

PHPzkbhj 发表了文章 • 0 个评论 • 315 次浏览 • 2018-04-04 10:50 • 来自相关话题

//判断是否是字母和数字或字母数字的组合
if(!ctype_alnum($str)){
echo '只能是字母或数字的组合';exit;
}1.ctype_alnum(string $text)://检查是否是字母或数字或字母数字的 组合
2.ctype_alpha(string $text):check for alphabetic character(s) //检查字符串是否是字母
3.ctype_cntrl(string $text):check for control character(s) //是否是控制字符如\n,\r,\t
4.ctype_digit(strint $text):check for numeric character(s) //是否是数字表示的字符
5.ctype_graph(string $text):Check for any printable character(s) except space //检查是否有任何可打印字符,除了空格(补)
6.ctype_lower():check for lowercase character(s)//检查是否是小写字母
7.ctype_upper():check for uppercase character(s)//检查是否是大写字母
8.ctype_space: check for whitespace character(s)//是否是空白字符
9.ctype_xdigit: check for character(s) representing a hexadecimal digit//检查是否是十六进制数字ctype_digit()  与 is_numeric()  的区别:
例:

$numeric_string='123';
$interger = 123;
ctype_digit($numeric_string);//true
ctype_digit($interger);//false
is_numeric($numeric_string); //true
is_numeric($interger); //true 查看全部
//判断是否是字母和数字或字母数字的组合
if(!ctype_alnum($str)){
echo '只能是字母或数字的组合';exit;
}
1.ctype_alnum(string $text)://检查是否是字母或数字或字母数字的 组合
2.ctype_alpha(string $text):check for alphabetic character(s) //检查字符串是否是字母
3.ctype_cntrl(string $text):check for control character(s) //是否是控制字符如\n,\r,\t
4.ctype_digit(strint $text):check for numeric character(s) //是否是数字表示的字符
5.ctype_graph(string $text):Check for any printable character(s) except space //检查是否有任何可打印字符,除了空格(补)
6.ctype_lower():check for lowercase character(s)//检查是否是小写字母
7.ctype_upper():check for uppercase character(s)//检查是否是大写字母
8.ctype_space: check for whitespace character(s)//是否是空白字符
9.ctype_xdigit: check for character(s) representing a hexadecimal digit//检查是否是十六进制数字
ctype_digit()  与 is_numeric()  的区别:
例:

$numeric_string='123';
$interger = 123;
ctype_digit($numeric_string);//true
ctype_digit($interger);//false
is_numeric($numeric_string); //true
is_numeric($interger); //true

PHP取整函数的具体使用方法介绍

PHPzkbhj 发表了文章 • 0 个评论 • 165 次浏览 • 2018-01-04 17:51 • 来自相关话题

我们经常用到的PHP取整函数,主要是:ceil,floor,round,intval。
 
ceil -- 进一法取整

说明
float ceil ( float value )
返回不小于 value 的下一个整数,value 如果有小数部分则进一位。ceil() 返回的类型仍然是 float,因为 float 值的范围通常比 integer 要大。PHP取整函数例子 1. ceil() 例子< ?php
echo ceil(4.3); // 5
echo ceil(9.999); // 10
?> floor -- 舍去法取整
说明
float floor ( float value )
返回不大于 value 的下一个整数,将 value 的小数部分舍去取整。floor() 返回的类型仍然是 float,因为 float 值的范围通常比 integer 要大。

PHP取整函数例子 1. floor() 例子
< ?php
echo floor(4.3); // 4
echo floor(9.999); // 9
?> round -- 对浮点数进行四舍五入
 
说明
float round ( float val [, int precision] )
返回将 val 根据指定精度 precision(十进制小数点后数字的数目)进行四舍五入的结果。precision 也可以是负数或零(默认值)。

PHP取整函数例子 1. round() 例子
< ?php
echo round(3.4); // 3
echo round(3.5); // 4
echo round(3.6); // 4
echo round(3.6, 0); // 4
echo round(1.95583, 2); // 1.96
echo round(1241757, -3); // 1242000
echo round(5.045, 2); // 5.05
echo round(5.055, 2); // 5.06
?> intval---对变数转成整数型态

PHP取整函数例子intval()< ?php
echo intval(4.3); //4
echo intval(4.6); // 4
?> 查看全部
我们经常用到的PHP取整函数,主要是:ceil,floor,round,intval。
 
ceil -- 进一法取整

说明
float ceil ( float value )
返回不小于 value 的下一个整数,value 如果有小数部分则进一位。ceil() 返回的类型仍然是 float,因为 float 值的范围通常比 integer 要大。PHP取整函数例子 1. ceil() 例子
< ?php  
echo ceil(4.3); // 5
echo ceil(9.999); // 10
?>
floor -- 舍去法取整
说明
float floor ( float value )
返回不大于 value 的下一个整数,将 value 的小数部分舍去取整。floor() 返回的类型仍然是 float,因为 float 值的范围通常比 integer 要大。

PHP取整函数例子 1. floor() 例子
< ?php  
echo floor(4.3); // 4
echo floor(9.999); // 9
?>
round -- 对浮点数进行四舍五入
 
说明
float round ( float val [, int precision] )
返回将 val 根据指定精度 precision(十进制小数点后数字的数目)进行四舍五入的结果。precision 也可以是负数或零(默认值)。

PHP取整函数例子 1. round() 例子
< ?php  
echo round(3.4); // 3
echo round(3.5); // 4
echo round(3.6); // 4
echo round(3.6, 0); // 4
echo round(1.95583, 2); // 1.96
echo round(1241757, -3); // 1242000
echo round(5.045, 2); // 5.05
echo round(5.055, 2); // 5.06
?>
intval---对变数转成整数型态

PHP取整函数例子intval()
< ?php  
echo intval(4.3); //4
echo intval(4.6); // 4
?>

PHP中使用json_encode需要注意的点

PHPzkbhj 发表了文章 • 0 个评论 • 183 次浏览 • 2017-12-26 19:48 • 来自相关话题

一、json_encode()

该函数主要用来将数组和对象,转换为json格式。先看一个数组转换的例子:
$arr = array ('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);
echo json_encode($arr);结果为
{"a":1,"b":2,"c":3,"d":4,"e":5}再看一个对象转换的例子:
$obj->body = 'another post';
$obj->id = 21;
$obj->approved = true;
$obj->favorite_count = 1;
$obj->status = NULL;
echo json_encode($obj);结果为
{
    "body":"another post",
  
    "id":21,
  
    "approved":true,
  
    "favorite_count":1,
  
    "status":null
}
  由于json只接受utf-8编码的字符,所以json_encode()的参数必须是utf-8编码,否则会得到空字符或者null。当中文使用GB2312编码,或者外文使用ISO-8859-1编码的时候,这一点要特别注意。

二、索引数组和关联数组

PHP支持两种数组,一种是只保存"值"(value)的索引数组(indexed array),另一种是保存"名值对"(name/value)的关联数组(associative array)。

由于javascript不支持关联数组,所以json_encode()只将索引数组(indexed array)转为数组格式,而将关联数组(associative array)转为对象格式。

比如,现在有一个索引数组
$arr = Array('one', 'two', 'three');
echo json_encode($arr);结果为:
 ["one","two","three"] 如果将它改为关联数组:
$arr = Array('1'=>'one', '2'=>'two', '3'=>'three');
echo json_encode($arr);结果就变了:
{"1":"one","2":"two","3":"three"} 注意,数据格式从"[]"(数组)变成了"{}"(对象)。

如果你需要将"索引数组"强制转化成"对象",可以这样写
json_encode( (object)$arr );或者
json_encode ( $arr, JSON_FORCE_OBJECT );三、类(class)的转换

下面是一个PHP的类:
 class Foo {
  
    const ERROR_CODE = '404';
  
    public $public_ex = 'this is public';
  
    private $private_ex = 'this is private!';
  
    protected $protected_ex = 'this should be protected';
  
    public function getErrorCode() {
  
      return self::ERROR_CODE;
  
    }
  
  }
  现在,对这个类的实例进行json转换:
 $foo = new Foo;
  
  $foo_json = json_encode($foo);
  
  echo $foo_json;输出结果是
{"public_ex":"this is public"} 可以看到,除了公开变量(public),其他东西(常量、私有变量、方法等等)都遗失了。

四、json_decode()

该函数用于将json文本转换为相应的PHP数据结构。下面是一个例子:$json = '{"foo": 12345}';
  
  $obj = json_decode($json);
  
  print $obj->{'foo'}; // 12345通常情况下,json_decode()总是返回一个PHP对象,而不是数组。比如:
$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
  
  var_dump(json_decode($json));结果就是生成一个PHP对象:
object(stdClass)#1 (5) {
  
    ["a"] => int(1)
    ["b"] => int(2)
    ["c"] => int(3)
    ["d"] => int(4)
    ["e"] => int(5)
  
  }如果想要强制生成PHP关联数组,json_decode()需要加一个参数true:
$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
  
  var_dump(json_decode($json,true));
  结果就生成了一个关联数组:
 array(5) {
  
     ["a"] => int(1)
     ["b"] => int(2)
     ["c"] => int(3)
     ["d"] => int(4)
     ["e"] => int(5)
  
  }五、json_decode()的常见错误

下面三种json写法都是错的,你能看出错在哪里吗?$bad_json = "{ 'bar': 'baz' }";
  
  $bad_json = '{ bar: "baz" }';
  
  $bad_json = '{ "bar": "baz", }';对这三个字符串执行json_decode()都将返回null,并且报错。

第一个的错误是,json的分隔符(delimiter)只允许使用双引号,不能使用单引号。第二个的错误是,json名值对的"名"(冒号左边的部分),任何情况下都必须使用双引号。第三个的错误是,最后一个值之后不能添加逗号(trailing comma)。

另外,json只能用来表示对象(object)和数组(array),如果对一个字符串或数值使用json_decode(),将会返回null。
var_dump(json_decode("Hello World")); //null 查看全部
一、json_encode()

该函数主要用来将数组和对象,转换为json格式。先看一个数组转换的例子:
$arr = array ('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);
echo json_encode($arr);
结果为
{"a":1,"b":2,"c":3,"d":4,"e":5}
再看一个对象转换的例子:
$obj->body           = 'another post';
$obj->id = 21;
$obj->approved = true;
$obj->favorite_count = 1;
$obj->status = NULL;
echo json_encode($obj);
结果为
{
    "body":"another post",
  
    "id":21,
  
    "approved":true,
  
    "favorite_count":1,
  
    "status":null
}
  
由于json只接受utf-8编码的字符,所以json_encode()的参数必须是utf-8编码,否则会得到空字符或者null。当中文使用GB2312编码,或者外文使用ISO-8859-1编码的时候,这一点要特别注意。

二、索引数组和关联数组

PHP支持两种数组,一种是只保存"值"(value)的索引数组(indexed array),另一种是保存"名值对"(name/value)的关联数组(associative array)。

由于javascript不支持关联数组,所以json_encode()只将索引数组(indexed array)转为数组格式,而将关联数组(associative array)转为对象格式。

比如,现在有一个索引数组
$arr = Array('one', 'two', 'three');
echo json_encode($arr);
结果为:
 ["one","two","three"] 
如果将它改为关联数组:
$arr = Array('1'=>'one', '2'=>'two', '3'=>'three');
echo json_encode($arr);
结果就变了:
{"1":"one","2":"two","3":"three"} 
注意,数据格式从"[]"(数组)变成了"{}"(对象)。

如果你需要将"索引数组"强制转化成"对象",可以这样写
json_encode( (object)$arr );
或者
json_encode ( $arr, JSON_FORCE_OBJECT );
三、类(class)的转换

下面是一个PHP的类:
 class Foo {
  
    const ERROR_CODE = '404';
  
    public $public_ex = 'this is public';
  
    private $private_ex = 'this is private!';
  
    protected $protected_ex = 'this should be protected';
  
    public function getErrorCode() {
  
      return self::ERROR_CODE;
  
    }
  
  }
  
现在,对这个类的实例进行json转换:
 $foo = new Foo;
  
  $foo_json = json_encode($foo);
  
  echo $foo_json;
输出结果是
{"public_ex":"this is public"} 
可以看到,除了公开变量(public),其他东西(常量、私有变量、方法等等)都遗失了。

四、json_decode()

该函数用于将json文本转换为相应的PHP数据结构。下面是一个例子:
$json = '{"foo": 12345}';
  
  $obj = json_decode($json);
  
  print $obj->{'foo'}; // 12345
通常情况下,json_decode()总是返回一个PHP对象,而不是数组。比如:
$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
  
  var_dump(json_decode($json));
结果就是生成一个PHP对象:
object(stdClass)#1 (5) {
  
    ["a"] => int(1)
    ["b"] => int(2)
    ["c"] => int(3)
    ["d"] => int(4)
    ["e"] => int(5)
  
  }
如果想要强制生成PHP关联数组,json_decode()需要加一个参数true:
$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
  
  var_dump(json_decode($json,true));
  
结果就生成了一个关联数组:
 array(5) {
  
     ["a"] => int(1)
     ["b"] => int(2)
     ["c"] => int(3)
     ["d"] => int(4)
     ["e"] => int(5)
  
  }
五、json_decode()的常见错误

下面三种json写法都是错的,你能看出错在哪里吗?
$bad_json = "{ 'bar': 'baz' }";
  
  $bad_json = '{ bar: "baz" }';
  
  $bad_json = '{ "bar": "baz", }';
对这三个字符串执行json_decode()都将返回null,并且报错。

第一个的错误是,json的分隔符(delimiter)只允许使用双引号,不能使用单引号。第二个的错误是,json名值对的"名"(冒号左边的部分),任何情况下都必须使用双引号。第三个的错误是,最后一个值之后不能添加逗号(trailing comma)。

另外,json只能用来表示对象(object)和数组(array),如果对一个字符串或数值使用json_decode(),将会返回null。
var_dump(json_decode("Hello World")); //null

PJAX的实现与应用

前端开发zkbhj 发表了文章 • 0 个评论 • 250 次浏览 • 2017-06-22 11:40 • 来自相关话题

一、前言
web发展经历了一个漫长的周期,最开始很多人认为Javascript这们语言是前端开发的累赘,是个鸡肋,那个时候人们还享受着从一个a链接蹦到另一个页面的web神奇魔术。后来随着JavaScript的不断更新换代,他的功能不仅仅是为网页添加一点特效了,语言本身的加强以及对DOM操作能力的提升让他在前端大放光彩。尤其是ajax的出现,让JavaScript以及整个web的发展翻开了崭新的一页。

利用ajax局部刷新页面,相信很多人玩得相当熟练了。如果整个页面的刷新都是使用ajax,我们可以称之为一个webapp,所有的逻辑都是在当页处理,这种形式的页面带来的体验是十分不错的,减少了那些比较“冗余”的页面跳转、新开页面等。不过,webapp的代码是十分不好维护的,页面逻辑太多太深,出点小问题,整个页面就会瘫痪,而且不方便定位bug,可维护性很低。
 
二、PJAX的实现与应用

1.场景再现-ajax弊端

ajax是一个非常好玩的小东西,不过用起来也会存在一些问题。

我们可以利用ajax进行无刷新改变文档内容,但是没办法去修改URL,有童鞋要问,这里为什么一定要修改URL呢?一个URL代表一个特定的网络资源,ajax修改了页面的内容,所以用不同的URL去标识他们,这个还是挺有必要的。

比如我们设计了一个单词查询的页面,比较合理的UR应该是http://example.com/word,不同的word对应不同的内容,但是如果整个页面都是ajax实现,我们就没法去修改/word了,当然我们可以使用hash如http://example.com#word,但这样就不能很好的处理浏览器的前进和后退问题。如:在页面中查询了单词A的翻译,接着又查询了单词B,这个时候浏览器的浏览历史会生成http://example.com#A和http://example.com#B两个记录,可是当我们从B转回A的时候,AJAX的效果还停留在B的状态(页面显示的还是单词B的翻译)。部分浏览器对此问题引入了onhashchange的接口,只要URL的hash值发生变化,我们的程序就可以监听并做出相应。不过对于那些木有这个接口的浏览器,就得定时去判断hash的变化了。

而这样的方式对搜索引擎是十分不友好的,twitter和google约定使用hash bang (#!xxx),也就是hash后面的第一个字符为感叹号,这样的网址他们是会爬取的,但是其他搜索引擎不支持。PJAX可以在改变页面内容的同时也改变他的URL,下面来说说PJAX和他的应用。

2.什么是PJAX

history API中有几个新特性,分别是history.pushState和history.replaceState,我们把pushState+AJAX进行封装,合起来简单点叫,就是PJAX~ 虽说实现技术上没什么新东西,但是概念上还是有所不同的。

PJAX的基本思路是,用户点击一个链接,通过ajax更新页面变化的部分,然后使用HTML5的pushState修改浏览器的URL地址,这样有效地避免了整个页面的重新加载。如果浏览器不支持history的两个新API或者JS被禁用了,那这个链接就只能跳转并重新刷新整个页面了。和传统的ajax设计稍微不同,ajax通常是从后台获取JSON数据,然后由前端解析渲染,而PJAX请求的是一个在服务器上生成好的HTML碎片,如下图所示:



客户端向服务器发送一个普通的请求(1),其实也就是点击了一个链接,服务器会相应这个请求(2),返回一个html文档。客户端向服务器发送一个有PJAX标志的请求(3),此时服务器只返回一个html碎片(4)。但是这两次请求都让客户端的URL变化了,希望上面的说明可以让你明白了PAJX和AJAX的区别了。

3.PJAX的实现

先看一个小DEMO吧,这个DEMO也写了我半个多小时,看之前先说明一下,打开你的现代浏览器(chrome,Firefox,opera,IE9+等),进入gallery页面,查看图片的时候注意观察浏览器的title和url变化,点击前进后退按钮也注意查看其变化。我已经在浏览历史管理中push了三条历史记录。

DEMO地址:http://qianduannotes.duapp.com ... .html

如果你还没有理解上面说的PJAX和AJAX的区别,看完这个demo,你应该有所领悟吧!在URL变化之后,页面并没有刷新,而是继续完成自己的动画(demo中为fadeOut)。

在HTML4,Histroy对象有下面属性方法:
length:历史堆栈中的记录数。back():返回上一页。forward():前进到下一页。go([delta]):delta是个数字,如果不写或为0,则刷新本页;如果为正数,则前进到相应数目的页面;若为负数,则后退到相应数目的页面。
 
在HTML5中,新增了两个方法:
pushState(data, title [, url]):往历史堆栈的顶部添加一条记录。data为一个对象或null,它会在触发window的popstate事件(window.onpopstate)时,作为参数的state属性传递过去;title为页面的标题,但当前所有浏览器都忽略这个参数;url为页面的URL,不写则为当前页。replaceState(data, title [, url]):更改当前页面的历史记录。参数同上。这种更改并不会去访问该URL。
 
当点击“上一张”、“下一张”这两个链接的时候,首先通过pushState修改URL以及修改document.title,那这个时候你就可以当做文档已经进入了另外一个链接了,然后该干什么干什么。demo中是让图片fadeOut,fadeOut完了之后让浏览器去加载资源,这个步骤就是正常的AJAX操作啦,没有什么特殊之处了~

因为只准备了三张图片,所有后台写的也比较简单:<?php
error_reporting(false);

$num = $_GET['num'];

if(array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'] === 'true'){
if($num == 1) {
?>
<div class="imgwrap">
<img src="./images/1.jpg" />
</div>
<span><a href="num=2" class="next">下一张>></a></span>
<?php
} else if ($num == 2) {
?>
<div class="imgwrap">
<img src="./images/2.jpg" />
</div>
<span><a href="num=1" class="previous"><<上一张</a>
<a href="num=3" class="next">下一张>></a></span>
<?php
} else {
?>
<div class="imgwrap">
<img src="./images/3.jpg" />
</div>
<span><a href="num=2" class="previous"><<上一张</a></span>
<?php
}
}
?>

 上面那张图中,我们看到了,并不是每个连接都使用PJAX来加载,如果有X_PJAX标识,我们才会添加相应的处理。js中稍加注意可以看到:$.ajax({
"url": "./interface.php",
"data": {
"num": num
},
"dataType": "html",
"headers": {
"X_PJAX": true
}
}); 请求中:Accept:text/html, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Connection:keep-alive
Host:qianduannotes.duapp.com
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
X-Requested-With:XMLHttpRequest
X_PJAX:true 我在请求的header中加了一个X_PJAX的头,而后台在处理的时候也做了判断:function is_pjax(){
return array_key_exists('HTTP_X_PJAX', $_SERVER)
&& $_SERVER['HTTP_X_PJAX'] === 'true';
} 并不是一定要求在header头部中加入X_PJAX的信息,你也可以在url中加入相关的参数,比如:http://example.com?pjax=1,或者其他方式,只要前后端达到一个共识就行。
 
三、开源的PJAX库

已经有人对这个东西做了封装,我就不重复造轮子了。
welefen封装的库,对jquery、qwrap和kissy都做了封装,github地址Yahoo团队 PJAX地址

并不是页面中所有的链接都需要使用PJAX加载,所有在需要这个东西的a标签上加一个属性,如data-pjax=true,然后统一添加事件。
 
四、注意事项
如果浏览器不支持pushState接口函数,那就只能退化为ajax或者使用hash bang了~本地环境下使用的话,浏览器会报错:`Uncaught SecurityError: A history state object with URL file:///E:/baidu_app/demo/PJAX/pic-2' cannot be created in a document with origin 'null'. ,所以如果你要测试的话,请把代码丢到服务器上!为了得到更好的体验,PJAX经常配合localStorage来使用,把请求到的内容缓存到本地,再一次请求的时候先从本地查看。如果你的内容是动态变化的,缓存的时候加一个缓存时间,方便更新缓存。还有一个容易忽略的东西是统计,使用PJAX只会局部刷新页面,如果忽略了对统计函数的更新,那就会让你失去很多数据。
 
原文地址:http://www.cnblogs.com/hustskyking/p/history-api-in-html5.html
pjax实例demo下载:链接: https://pan.baidu.com/s/1dEJoh93 密码: h14z 查看全部
一、前言
web发展经历了一个漫长的周期,最开始很多人认为Javascript这们语言是前端开发的累赘,是个鸡肋,那个时候人们还享受着从一个a链接蹦到另一个页面的web神奇魔术。后来随着JavaScript的不断更新换代,他的功能不仅仅是为网页添加一点特效了,语言本身的加强以及对DOM操作能力的提升让他在前端大放光彩。尤其是ajax的出现,让JavaScript以及整个web的发展翻开了崭新的一页。

利用ajax局部刷新页面,相信很多人玩得相当熟练了。如果整个页面的刷新都是使用ajax,我们可以称之为一个webapp,所有的逻辑都是在当页处理,这种形式的页面带来的体验是十分不错的,减少了那些比较“冗余”的页面跳转、新开页面等。不过,webapp的代码是十分不好维护的,页面逻辑太多太深,出点小问题,整个页面就会瘫痪,而且不方便定位bug,可维护性很低。
 
二、PJAX的实现与应用

1.场景再现-ajax弊端

ajax是一个非常好玩的小东西,不过用起来也会存在一些问题。

我们可以利用ajax进行无刷新改变文档内容,但是没办法去修改URL,有童鞋要问,这里为什么一定要修改URL呢?一个URL代表一个特定的网络资源,ajax修改了页面的内容,所以用不同的URL去标识他们,这个还是挺有必要的。

比如我们设计了一个单词查询的页面,比较合理的UR应该是http://example.com/word,不同的word对应不同的内容,但是如果整个页面都是ajax实现,我们就没法去修改/word了,当然我们可以使用hash如http://example.com#word,但这样就不能很好的处理浏览器的前进和后退问题。如:在页面中查询了单词A的翻译,接着又查询了单词B,这个时候浏览器的浏览历史会生成http://example.com#Ahttp://example.com#B两个记录,可是当我们从B转回A的时候,AJAX的效果还停留在B的状态(页面显示的还是单词B的翻译)。部分浏览器对此问题引入了onhashchange的接口,只要URL的hash值发生变化,我们的程序就可以监听并做出相应。不过对于那些木有这个接口的浏览器,就得定时去判断hash的变化了。

而这样的方式对搜索引擎是十分不友好的,twitter和google约定使用hash bang (#!xxx),也就是hash后面的第一个字符为感叹号,这样的网址他们是会爬取的,但是其他搜索引擎不支持。PJAX可以在改变页面内容的同时也改变他的URL,下面来说说PJAX和他的应用。

2.什么是PJAX

history API中有几个新特性,分别是history.pushState和history.replaceState,我们把pushState+AJAX进行封装,合起来简单点叫,就是PJAX~ 虽说实现技术上没什么新东西,但是概念上还是有所不同的。

PJAX的基本思路是,用户点击一个链接,通过ajax更新页面变化的部分,然后使用HTML5的pushState修改浏览器的URL地址,这样有效地避免了整个页面的重新加载。如果浏览器不支持history的两个新API或者JS被禁用了,那这个链接就只能跳转并重新刷新整个页面了。和传统的ajax设计稍微不同,ajax通常是从后台获取JSON数据,然后由前端解析渲染,而PJAX请求的是一个在服务器上生成好的HTML碎片,如下图所示:
06100721-6cff436c5fc84037807d4cce03658f9b.jpg
客户端向服务器发送一个普通的请求(1),其实也就是点击了一个链接,服务器会相应这个请求(2),返回一个html文档。客户端向服务器发送一个有PJAX标志的请求(3),此时服务器只返回一个html碎片(4)。但是这两次请求都让客户端的URL变化了,希望上面的说明可以让你明白了PAJX和AJAX的区别了。

3.PJAX的实现

先看一个小DEMO吧,这个DEMO也写了我半个多小时,看之前先说明一下,打开你的现代浏览器(chrome,Firefox,opera,IE9+等),进入gallery页面,查看图片的时候注意观察浏览器的title和url变化,点击前进后退按钮也注意查看其变化。我已经在浏览历史管理中push了三条历史记录。

DEMO地址:http://qianduannotes.duapp.com ... .html

如果你还没有理解上面说的PJAX和AJAX的区别,看完这个demo,你应该有所领悟吧!在URL变化之后,页面并没有刷新,而是继续完成自己的动画(demo中为fadeOut)。

在HTML4,Histroy对象有下面属性方法:
  • length:历史堆栈中的记录数。
  • back():返回上一页。
  • forward():前进到下一页。
  • go([delta]):delta是个数字,如果不写或为0,则刷新本页;如果为正数,则前进到相应数目的页面;若为负数,则后退到相应数目的页面。

 
在HTML5中,新增了两个方法:
  • pushState(data, title [, url]):往历史堆栈的顶部添加一条记录。data为一个对象或null,它会在触发window的popstate事件(window.onpopstate)时,作为参数的state属性传递过去;title为页面的标题,但当前所有浏览器都忽略这个参数;url为页面的URL,不写则为当前页。
  • replaceState(data, title [, url]):更改当前页面的历史记录。参数同上。这种更改并不会去访问该URL。

 
当点击“上一张”、“下一张”这两个链接的时候,首先通过pushState修改URL以及修改document.title,那这个时候你就可以当做文档已经进入了另外一个链接了,然后该干什么干什么。demo中是让图片fadeOut,fadeOut完了之后让浏览器去加载资源,这个步骤就是正常的AJAX操作啦,没有什么特殊之处了~

因为只准备了三张图片,所有后台写的也比较简单:
<?php
error_reporting(false);

$num = $_GET['num'];

if(array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'] === 'true'){
if($num == 1) {
?>
<div class="imgwrap">
<img src="./images/1.jpg" />
</div>
<span><a href="num=2" class="next">下一张>></a></span>
<?php
} else if ($num == 2) {
?>
<div class="imgwrap">
<img src="./images/2.jpg" />
</div>
<span><a href="num=1" class="previous"><<上一张</a>
<a href="num=3" class="next">下一张>></a></span>
<?php
} else {
?>
<div class="imgwrap">
<img src="./images/3.jpg" />
</div>
<span><a href="num=2" class="previous"><<上一张</a></span>
<?php
}
}
?>

 上面那张图中,我们看到了,并不是每个连接都使用PJAX来加载,如果有X_PJAX标识,我们才会添加相应的处理。js中稍加注意可以看到:
$.ajax({
"url": "./interface.php",
"data": {
"num": num
},
"dataType": "html",
"headers": {
"X_PJAX": true
}
});
 请求中:
Accept:text/html, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Connection:keep-alive
Host:qianduannotes.duapp.com
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
X-Requested-With:XMLHttpRequest
X_PJAX:true
 我在请求的header中加了一个X_PJAX的头,而后台在处理的时候也做了判断:
function is_pjax(){
return array_key_exists('HTTP_X_PJAX', $_SERVER)
&& $_SERVER['HTTP_X_PJAX'] === 'true';
}
 并不是一定要求在header头部中加入X_PJAX的信息,你也可以在url中加入相关的参数,比如:http://example.com?pjax=1,或者其他方式,只要前后端达到一个共识就行。
 
三、开源的PJAX库

已经有人对这个东西做了封装,我就不重复造轮子了。
  • welefen封装的库,对jquery、qwrap和kissy都做了封装,github地址
  • Yahoo团队 PJAX地址


并不是页面中所有的链接都需要使用PJAX加载,所有在需要这个东西的a标签上加一个属性,如data-pjax=true,然后统一添加事件。
 
四、注意事项
  1. 如果浏览器不支持pushState接口函数,那就只能退化为ajax或者使用hash bang了~
  2. 本地环境下使用的话,浏览器会报错:`Uncaught SecurityError: A history state object with URL file:///E:/baidu_app/demo/PJAX/pic-2' cannot be created in a document with origin 'null'. ,所以如果你要测试的话,请把代码丢到服务器上!
  3. 为了得到更好的体验,PJAX经常配合localStorage来使用,把请求到的内容缓存到本地,再一次请求的时候先从本地查看。如果你的内容是动态变化的,缓存的时候加一个缓存时间,方便更新缓存。
  4. 还有一个容易忽略的东西是统计,使用PJAX只会局部刷新页面,如果忽略了对统计函数的更新,那就会让你失去很多数据。

 
原文地址:http://www.cnblogs.com/hustskyking/p/history-api-in-html5.html
pjax实例demo下载:链接: https://pan.baidu.com/s/1dEJoh93 密码: h14z

PHP实现RSA加密解密

PHPzkbhj 发表了文章 • 0 个评论 • 206 次浏览 • 2017-06-16 10:25 • 来自相关话题

class Someet
{

//加密方法 $data 加密字符串
public static function getencrypt($data){

// 公钥加密
$encrypt_data = '';
//获取公钥
$pubkey = openssl_pkey_get_public(file_get_contents('someet_pub.key'));
openssl_public_encrypt($data, $encrypt_data, $pubkey);
$encrypt_data = base64_encode($encrypt_data);
return $encrypt_data;

}


//解密方法 $encrypt_data 获取的加密后的字符串
public static function getdecrypt($encrypt_data)
{
//把解密的字符串里的,空格转换为+号
$encrypt_data = str_replace(' ','+', $encrypt_data);
// 私钥解密
$prikey = openssl_pkey_get_private(file_get_contents('someet.key'));
$encrypt_data = base64_decode($encrypt_data);
openssl_private_decrypt($encrypt_data, $decrypt_data, $prikey);
return $decrypt_data;
}


}

//使用
$sommet = new Someet();
//加密
$encrypt = $sommet->getencrypt($encryptkey);
//解密
$decrypt = $sommet->getdecrypt($decryptkey);


RSA的加密解密,对加密串的格式要求非常严格,不同语言,像Java,.net 加密输出的串,到达php页面,会出现加号被转成空格的情况,因为php get 会默认执行一遍 urldecode, 而urldecode 会把加号转为空格,从而导致整个加密串发生了变化,所以解密不出来。
生成公钥、私钥对,私钥加密的内容能通过公钥解密(反过来亦可以)

下载开源RSA密钥生成工具openssl(通常Linux系统都自带该程序),解压缩至独立的文件夹,进入其中的bin目录,执行以下命令:openssl genrsa -out rsa_private_key.pem 1024
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out private_key.pem
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
第一条命令生成原始 RSA私钥文件 rsa_private_key.pem,第二条命令将原始 RSA私钥转换为 pkcs8格式,第三条生成RSA公钥 rsa_public_key.pem
从上面看出通过私钥能生成对应的公钥,因此我们将私钥private_key.pem用在服务器端,公钥发放给Android跟iOS等前端。 查看全部

timg_(1).jpg
class Someet
{

//加密方法 $data 加密字符串
public static function getencrypt($data){

// 公钥加密
$encrypt_data = '';
//获取公钥
$pubkey = openssl_pkey_get_public(file_get_contents('someet_pub.key'));
openssl_public_encrypt($data, $encrypt_data, $pubkey);
$encrypt_data = base64_encode($encrypt_data);
return $encrypt_data;

}


//解密方法 $encrypt_data 获取的加密后的字符串
public static function getdecrypt($encrypt_data)
{
//把解密的字符串里的,空格转换为+号
$encrypt_data = str_replace(' ','+', $encrypt_data);
// 私钥解密
$prikey = openssl_pkey_get_private(file_get_contents('someet.key'));
$encrypt_data = base64_decode($encrypt_data);
openssl_private_decrypt($encrypt_data, $decrypt_data, $prikey);
return $decrypt_data;
}


}

//使用
$sommet = new Someet();
//加密
$encrypt = $sommet->getencrypt($encryptkey);
//解密
$decrypt = $sommet->getdecrypt($decryptkey);


RSA的加密解密,对加密串的格式要求非常严格,不同语言,像Java,.net 加密输出的串,到达php页面,会出现加号被转成空格的情况,因为php get 会默认执行一遍 urldecode, 而urldecode 会把加号转为空格,从而导致整个加密串发生了变化,所以解密不出来。
生成公钥、私钥对,私钥加密的内容能通过公钥解密(反过来亦可以)

下载开源RSA密钥生成工具openssl(通常Linux系统都自带该程序),解压缩至独立的文件夹,进入其中的bin目录,执行以下命令:
openssl genrsa -out rsa_private_key.pem 1024
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out private_key.pem
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

第一条命令生成原始 RSA私钥文件 rsa_private_key.pem,第二条命令将原始 RSA私钥转换为 pkcs8格式,第三条生成RSA公钥 rsa_public_key.pem
从上面看出通过私钥能生成对应的公钥,因此我们将私钥private_key.pem用在服务器端,公钥发放给Android跟iOS等前端。
    记录学习过的PHP相关函数的用法和注意事项等~