当前位置: 圈子中心 >PHP在线交流社区-详情>经验分享

王二狗丶
PHP在线交流社区提供了PHP问题解答、经验分享、文件资源、视频教程等频道。向PHP开发人员提供:最新PHP资讯、原创内容、开发资料,技术手册,开源代码和PHP视频教程等相关内容
发帖
";       
echo "昨天:".date("Y-m-d",strtotime("-1 day")), "
"; echo "明天:".date("Y-m-d",strtotime("+1 day")). "
"; echo "一周后:".date("Y-m-d",strtotime("+1 week")). "
"; echo "一周零两天四小时两秒后:".date("Y-m-d G:H:s",strtotime("+1 week 2 days 4 hours 2 seconds")). "
"; echo "下个星期四:".date("Y-m-d",strtotime("next Thursday")). "
"; echo "上个周一:".date("Y-m-d",strtotime("last Monday"))."
"; echo "一个月前:".date("Y-m-d",strtotime("last month"))."
"; echo "一个月后:".date("Y-m-d",strtotime("+1 month"))."
"; echo "十年后:".date("Y-m-d",strtotime("+10 year"))."
"; ?>

strtotime()函数的作用是将日期时间描述解析为 Unix 时间戳

int strtotime ( string time [, int now] )

PHP星期几获取代码:

1. date("l");

//data就可以获取英文的星期比如Sunday

2. date("w");

//这个可以获取数字星期比如123,注意0是星期日

获取中文星期可以这样

$weekarray=array("日","一","二","三","四","五","六");
echo "星期".$weekarray[date("w")];

获取指定日期是:

$weekarray=array("日","一","二","三","四","五","六");
echo "星期".$weekarray[date("w","2011-11-11")];

因为date函数非常强大,他完全可以胜任一切这样的工作我附个手册里的表吧

a - "am" 或是 "pm"

A - "AM" 或是 "PM"

d - 几日,二位数字,若不足二位则前面补零; 如: "01" 至 "31"

D - 星期几,三个英文字母; 如: "Fri"

F - 月份,英文全名; 如: "January"

h - 12 小时制的小时; 如: "01" 至 "12"

H - 24 小时制的小时; 如: "00" 至 "23"

g - 12 小时制的小时,不足二位不补零; 如: "1" 至 12"

G - 24 小时制的小时,不足二位不补零; 如: "0" 至 "23"

i - 分钟; 如: "00" 至 "59"

j - 几日,二位数字,若不足二位不补零; 如: "1" 至 "31"

l - 星期几,英文全名; 如: "Friday"

m - 月份,二位数字,若不足二位则在前面补零; 如: "01" 至 "12"

n - 月份,二位数字,若不足二位则不补零; 如: "1" 至 "12"

M - 月份,三个英文字母; 如: "Jan"

s - 秒; 如: "00" 至 "59"

S - 字尾加英文序数,二个英文字母; 如: "th","nd"

t - 指定月份的天数; 如: "28" 至 "31"

U - 总秒数

w - 数字型的星期几,如: "0" (星期日) 至 "6" (星期六)

Y - 年,四位数字; 如: "1999"

y - 年,二位数字; 如: "99"

z - 一年中的第几天; 如: "0" 至 "365"

以上详细的介绍了PHP星期几获取的方法还有date函数的介绍,大家快试试吧。

以上就是PHP怎么获取今天、昨天、明天的日期的详细内容,更多请关注php交流社区其它相关文章!


2019年12月10日 22:14    来自: 王二狗丶
本文为大家讲述了php异步调用方法,分享给大家供大家参考,具体内容如下

客户端与服务器端是通过HTTP协议进行连接通讯,客户端发起请求,服务器端接收到请求后执行处理,并返回处理结果。

有时服务器需要执行很耗时的操作,这个操作的结果并不需要返回给客户端。但因为php是同步执行的,所以客户端需要等待服务处理完才可以进行下一步。

因此对于耗时的操作适合异步执行,服务器接收到请求后,处理完客户端需要的数据就返回,再异步在服务器执行耗时的操作。

1.使用Ajax 与 img 标记

原理,服务器返回的html中插入Ajax 代码或 img 标记,img的src为需要执行的程序。

优点:实现简单,服务端无需执行任何调用

缺点:在执行期间,浏览器会一直处于loading状态,因此这种方法并不算真正的异步调用。

$.get("doRequest.php", { name: "fdipzone"} );

2.使用popen

使用popen执行命令,语法:

// popen — 打开进程文件指针 
resource popen ( string $command
, string $mode
)
pclose(popen('php /home/fdipzone/doRequest.php &', 'r'));

优点:执行速度快

缺点:

1).只能在本机执行

2).不能传递大量参数

3).访问量高时会创建很多进程

3.使用curl

设置curl的超时时间 CURLOPT_TIMEOUT 为1 (最小为1),因此客户端需要等待1秒

4.使用fsockopen

fsockopen是最好的,缺点是需要自己拼接header部分。

'fdipzone',
  'gender'=>'male',
  'age'=>30
);
    
doRequest($url, $param);
    
function
doRequest($url, $param=array()){
    
  $urlinfo
= parse_url($url);
    
  $host
= $urlinfo['host'];
  $path
= $urlinfo['path'];
  $query
= isset($param)? http_build_query($param) : '';
    
  $port
= 80;
  $errno
= 0;
  $errstr
= '';
  $timeout
= 10;
    
  $fp
= fsockopen($host, $port, $errno, $errstr, $timeout);
    
  $out
= "POST ".$path." HTTP/1.1\r\n";
  $out
.= "host:".$host."\r\n";
  $out
.= "content-length:".strlen($query)."\r\n";
  $out
.= "content-type:application/x-www-form-urlencoded\r\n";
  $out
.= "connection:close\r\n\r\n";
  $out
.= $query;
    
  fputs($fp, $out);
  fclose($fp);
}
    
?>

注意:当执行过程中,客户端连接断开或连接超时,都会有可能造成执行不完整,因此需要加上

ignore_user_abort(true); // 忽略客户端断开
set_time_limit(0);    // 设置执行不超时

更多PHP相关知识,请访问PHP交流社区!

以上就是四种PHP异步执行的常用方式的详细内容,更多请关注php交流社区其它相关文章!


2019年12月10日 22:14    来自: 王二狗丶
php类的定义

类是对某个对象的定义。它包含有关对象动作方式的信息,包括它的名称、方法、属性和事件。实际上它本身并不是对象,因为它不存在于内存中。当引用类的代码运行时,类的一个新的实例,即对象,就在内存中创建了。虽然只有一个类,但能从这个类在内存中创建多个相同类型的对象。类是通过class关键字来定义的。

基本语法:

class 类名{
   //属性、方法
}

注意事项:

1.定义一个类(只能用class定义)

2.定义类的属性public(public是修饰符,共有三个,是public,protected,private,这里我们暂时只用public)

举个例子:

定义一个汽车类,属性有车的颜色和价格

class car{
  public $color;     //定义属性
  public $price;
}

php类的实例化方法

类的实例化又叫创建一个对象或者实例化一个对象或者把类实例化。

简单的来举个例子:

我们定义一个人的类,并把这个类实例化。

class Preson {                               //定义了一个Preson类
public $name = ‘aaa’;                //定义类的属性(姓名,性别,年龄等等)
public $age = ‘2’;
public $gender = ‘男’;
}
//new翻译是新的,意思就是创建一个新的人,并把这个新的对象赋值给$Preson1,这个就是实例化
$Preson1 = new Preson();                 //实例化类
$Preson1->name = "张三";
$Preson1->age = 22;
$Preson1->gender = "女";
echo  $Preson1->name.'  '.$Preson1->age.'  '.$Preson1->gender;
//如果想输出第二个实例,直接输出就OK了,只要改一个变量名
$Preson2 = new Preson();                    //实例化类
$Preson2->name = "小亮";
$Preson2->age = 25;
$Preson2->gender = "男";

以上就是类与对象的基本概念及简单的实例化了解。

以上就是关于php类的定义与实例化方法的详细内容,更多请关注php交流社区其它相关文章!


2019年12月10日 22:14    来自: 王二狗丶
前面讲了怎么实现微信支付,详见相关文章:PHP实现微信支付(jsapi支付)流程 和ThinkPHP中实现微信支付(jsapi支付)流程。由于业务需求,还需要有微信退款,经过研究和摸索,也终于搞定了。

前期准备:

当然是搞定了微信支付,不然怎么退款,这次还是使用官方的demo。当然网上可能也有很多大神自己重写和封装了demo,或许更加好用简洁,但是我还是不提倡用,原因如下:

(1)可能功能不全,或许他只是实现了微信支付,但是还有申请退款、查询退款、订单查询、撤销订单等业务功能可能是你后续需要的,如果你依赖于大神的SDK的便捷,如果有新的业务需求,你就懵逼了;

(2)安全考虑,涉及到支付涉及到金钱,必须要非常安全。官方SDK虽然我也吐槽,但至少会相对比较安全,再次重写,虽然暂时没看出问题,但是万一有漏洞就不好了。

本篇还是使用到官方提供的SDK中的最重要的一个类文件WxPay.Api.php中提供的refund()方法来实现,此方法在WxPay.Api.php文件的第141行,代码如下:

/**
 * 
 * 申请退款,WxPayRefund中out_trade_no、transaction_id至少填一个且
 * out_refund_no、total_fee、refund_fee、op_user_id为必填参数
 * appid、mchid、spbill_create_ip、nonce_str不需要填入
 * @param WxPayRefund $inputObj
 * @param int $timeOut
 * @throws WxPayException
 * @return 成功时返回,其他抛异常
 */
public static function refund($inputObj, $timeOut = 6){
$url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
//检测必填参数
if(!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) {
throw new WxPayException("退款申请接口中,out_trade_no、transaction_id至少填一个!");
}else if(!$inputObj->IsOut_refund_noSet()){
throw new WxPayException("退款申请接口中,缺少必填参数out_refund_no!");
}else if(!$inputObj->IsTotal_feeSet()){
throw new WxPayException("退款申请接口中,缺少必填参数total_fee!");
}else if(!$inputObj->IsRefund_feeSet()){
throw new WxPayException("退款申请接口中,缺少必填参数refund_fee!");
}else if(!$inputObj->IsOp_user_idSet()){
throw new WxPayException("退款申请接口中,缺少必填参数op_user_id!");
}
$inputObj->SetAppid(WxPayConfig::APPID);//公众账号ID
$inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
$inputObj->SetNonce_str(self::getNonceStr());//随机字符串
$inputObj->SetSign();//签名
$xml = $inputObj->ToXml();
$startTimeStamp = self::getMillisecond();//请求开始时间
$response = self::postXmlCurl($xml, $url, true, $timeOut);
$result = WxPayResults::Init($response);
self::reportCostTime($url, $startTimeStamp, $result);//上报请求花费时间
return $result;
}

官方的方法,写的很清楚需要哪些参数,还有一些必须参数SDK已经帮我们补齐了,我将这个方法重新封装一下,便于在项目中调用:

/**
 * 微信退款
 * @param  string   $order_id 订单ID
 * @return 成功时返回(array类型),其他抛异常
 */
function wxRefund($order_id){
//我的SDK放在项目根目录下的Api目录下
require_once APP_ROOT."/Api/wxpay/lib/WxPay.Api.php";
//查询订单,根据订单里边的数据进行退款
$order = M('order')->where(array('id'=>$order_id,'is_refund'=>2,'order_status'=>1))->find();
$merchid = WxPayConfig::MCHID;
if(!$order) return false;
$input = new WxPayRefund();
$input->SetOut_trade_no($order['order_sn']);//自己的订单号
$input->SetTransaction_id($order['transaction_id']);  //微信官方生成的订单流水号,在支付成功中有返回
$input->SetOut_refund_no(getrand_num(true));//退款单号
$input->SetTotal_fee($order['total_price']);//订单标价金额,单位为分
$input->SetRefund_fee($order['total_price']);//退款总金额,订单总金额,单位为分,只能为整数
$input->SetOp_user_id($merchid);
$result = WxPayApi::refund($input);//退款操作
// 这句file_put_contents是用来查看服务器返回的退款结果 测试完可以删除了
//file_put_contents(APP_ROOT.'/Api/wxpay/logs/log3.txt',arrayToXml($result),FILE_APPEND);
return $result;
}

这里需要吐槽一下,竟然不说返回值的类型,在支付的时候返回的是XML数据,这里竟然返回的是数组,让我措手不及,哈哈不过还是返回数组比较好,可以直接判断处理。

方法调用就更加简单了:

//微信退款
$result = wxRefund($order_id);
// 这句file_put_contents是用来查看服务器返回的退款结果 测试完可以删除了
//file_put_contents(APP_ROOT.'/Api/wxpay/logs/log4.txt',arrayToXml($result),FILE_APPEND);
if(($result['return_code']=='SUCCESS') && ($result['result_code']=='SUCCESS')){
//退款成功
}else if(($result['return_code']=='FAIL') || ($result['result_code']=='FAIL')){
//退款失败
//原因
$reason = (empty($result['err_code_des'])?$result['return_msg']:$result['err_code_des']);
}else{
//失败
}

退款成功返回如下:

f6615df7f16ff936a26a513aed72b23.png

亲测无误:这是集成了官方的SDK实现的,如果不使用SDK,可以使用更简单的方法,见:PHP实现微信支付(jsapi支付)和退款(无需集成支付SDK)

ff23e522c96093a2c3e58b4188ddd1b.png

更多PHP相关知识,请访问PHP交流社区!

以上就是PHP怎么实现微信申请退款的详细内容,更多请关注php交流社区其它相关文章!


2019年12月10日 22:14    来自: 王二狗丶
希尔排序之交换排序

● 问题引入:

在插入排序中,如果数组元素的排列情况比较乐观,那么插入的次数就比较少,那么效率就很高了,可是很多时候,数据就是那么的不敬人意,比如如下的一个待 \

排序的数组:[2,3,4,5,6,7,1],这个数组,如果使用插入排序,那么就会发生如下的样子:

1. 第一轮:[2,3,4,5,6,7,7]

2. 第二轮:[2,3,4,5,6,6,7]

3. 第三轮:[2,3,4,5,5,6,7]

4. 第四轮:[2,3,4,4,5,6,7]

5. 第五轮:[2,3,3,4,5,6,7]

6. 第六轮:[2,2,3,4,5,6,7]

7. 第七轮:[1,2,3,4,5,6,7]

这样的就是最不乐观的情况,很浪费时间,所以,后来就有大神研究了一下,优化优化,就发明了希尔排序。

希尔排序 (Shell's Sort) 是插入排序的一种又称 “缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。

希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,

整个文件恰被分成一组,算法便终止

数组实例说明:

1. 比如有一个待排序的数组 [9,6,1,3,0,5.7,2,8,4]

2. 上面的数组一共有 10 个元素,它把数组第一次分为 10/2 = 5 组,然后两两比较,大小位置交换:如下:

<?php
$arr = [9,6,1,3,0, 5,7,2,8,4];
$arr[0] > $arr[5] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置';
$arr[1] > $arr[6] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置';
$arr[2] > $arr[7] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置';
$arr[3] > $arr[8] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置';
$arr[4] > $arr[9] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置';
for ($i = 5; $i < 10; $i++) {
     for ($j = $i - 5; $j >= 0; $j-=5) {
         if ($data[$j] > $data[$j+5]) {
         $temp = $data[$j];
         $data[$j] = $data[$j+5];
         $data[$j+5] = $temp; 
         } 
     }
 }

最后第一轮得到的结果就是:[5,6,1,3,0,9,7,2,8,4]

3. 第二轮又开始比较,第二轮是在之前第一轮的基础上,再次分为 5/2 = 2 组,然后两两交换位置,大小指互换:如下:

<?php
$arr = [5,6,1,3,0,9,7,2,8,4];
$arr[0] > $arr[2];//1,5  [1,6,5,3,0,9,7,2,8,4]
$arr[2] > $arr[4];//0,5  [1,6,0,3,5,9,7,2,8,4]
$arr[4] > $arr[6];//5,7  [1,6,0,3,5,9,7,2,8,4]
$arr[6] > $arr[8];//7,8  [1,6,0,3,5,9,7,2,8,4]
$arr[1] > $arr[3];//3,6  [1,3,0,6,5,9,7,2,8,4]
$arr[3] > $arr[5];//6,9  [1,3,0,6,5,9,7,2,8,4]
$arr[5] > $arr[7];//2,9  [1,3,0,6,5,2,7,9,8,4]
$arr[7] > $arr[9];//4,9  [1,3,0,6,5,2,7,4,8,9]
...
for ($i = 2; $i < 10; $i++) {
     for ($j = $i - 2; $j >= 0; $j-=2) {
         if ($data[$j] > $data[$j+2]) {
         $temp = $data[$j];
         $data[$j] = $data[$j+2];
         $data[$j+2] = $temp; 
         } 
     }
 }

最后得到的结果就是:[0,2,1,3,6,4,7,6,8,9]

4. 最后再次分组比较:2/2 = 1 组。也就是最后,每两个都要比较,然后再次互换位置

<?php
$arr = [0,2,1,3,5,4,7,6,8,9];
$arr[0] > $arr[1];//[1,3,0,6,5,2,7,4,8,9]
$arr[1] > $arr[2];//[1,0,3,6,5,2,7,4,8,9]
$arr[2] > $arr[3];//[1,0,3,6,5,2,7,4,8,9]
$arr[3] > $arr[4];//[1,0,3,5,6,2,7,4,8,9]
$arr[4] > $arr[5];//[1,0,3,5,2,6,7,4,8,9]
$arr[5] > $arr[6];//[1,0,3,5,2,6,7,4,8,9]
$arr[6] > $arr[7];//[1,0,3,5,2,6,4,7,8,9]
$arr[7] > $arr[8];//[1,0,3,5,2,6,4,7,8,9]
$arr[8] > $arr[9];//[1,0,3,5,2,6,4,7,8,9]
...
for ($i = 1; $i < 10; $i++) {
     for ($j = $i - 1; $j >= 0; $j-=1) {
         if ($data[$j] > $data[$j+1]) { 
         $temp = $data[$j]; 
         $data[$j] = $data[$j+1];
         $data[$j+1] = $temp;
         }
     }
 }

最后就得到结果:[0,1,2,3,4,5,6,7,8,9]

完整代码如下:

<?php
class ShellSort
{
 /*** Notes: 希尔排序之交换法排序
 * User: LiYi\ * Date: 2019/11/12 0012\ * Time: 14:30\ * @param array $data\ * @return array\ */\
 public static function shellSortArray(array $data):array
 {
 if (!is_array($data)) {
 return ['message' => '必须传入数组比较排序'];
 }
 $count = count($data);//得到数组的个数
 //如果数组的个数小于等于1就直接返回
 if ($count <= 1) {return $data;}
 //$gap 是每次减半的分组,直到只可以分为一组结束,在php里面需要注意,两个整数相除,除不尽的情况下,得到的是一个浮点数,不是一个向下
 //取整的的整数,所以在最后判断gap 退出循环的时候,需要判断它 >= 1
 for ($gap = $count / 2; $gap >= 1; $gap /= 2) {
         for ($i = $gap; $i < $count; $i++) {
             for ($j = $i - $gap; $j >= 0; $j-=$gap) {
                 if ($data[$j] > $data[$j+$gap]) {
                 //这个地方是比较第一个数和它的步长做比较,交换也是一样
                 $temp = $data[$j]; 
                 $data[$j] = $data[$j+$gap];
                 $data[$j+$gap] = $temp;
                 }
             }
         }
     }
     return $data;
 }
 public static function validate(array $data)
 {
      if (!is_array($data)) {
      return ['message' => '必须传入数组比较排序'];
     }
 $count = count($data);//得到数组的个数
 //如果数组的个数小于等于1就直接返回
 if ($count <= 1){
 return $data;
 }
 return [$data, $count];
 }
 /**\ * Notes: 希尔排序之移位法排序
 * User: LiYi
 * Date: 2019/11/12 0012
 * Time: 14:29
 * @param array $data
 * @return array*/
 public static function ShellSortMoveArray(array $data)
 {
 $count = count($data);//得到数组总数
 for ($gap = $count / 2; $gap > 0; $gap /= 2) {
 //缩小增量,每次减半
 $gap = floor($gap);
 for ($i = $gap; $i < $count; $i++) {
 // $insertIndex = $i;//待插入元素的下表
 $insertValue = $data[$insertIndex];//待插入元素的值
 echo "insertIndex=$insertIndex" . PHP_EOL;
 echo "insertValue=$insertValue" . PHP_EOL;
 if ($data[$insertIndex] < $data[$insertIndex - $gap]) {
 //判断待插入元素和它步长的元素比较,待插入元素小就进入循环
 //判断是否越界了,第一个元素的下标是要大于等于0的,否则退出循环
 //判断后面的元素比前面的元素小,进入循环,否则退出循环
 while ($insertIndex - $gap >= 0 && $insertValue < $data[$insertIndex - $gap]) {
 //把步长前面的大的值向后移动
 $data[$insertIndex] = $data[$insertIndex - $gap];
 $insertIndex -= $gap;//每循环一次就把带插入的坐标减去补偿\
 } //把带插的小值插入到前面
 $data[$insertIndex] = $insertValue;
 }
 }
 }
 return $data;
 }
 public static function testShellOne(array $data)
 {
 $temp = 0;
 $count = count($data);
 for ($i = 5; $i < $count; $i++) {
 for ($j = $i - 5; $j >= 0; $j-=5) {
 if ($data[$j] > $data[$j+5]) {
 $temp = $data[$j];
 $data[$j] = $data[$j+5];
 $data[$j+5] = $temp;
 }
 }
 }
 for ($i = 2; $i < $count; $i++) {
 for ($j = $i - 2; $j >= 0; $j-=2) {
 if ($data[$j] > $data[$j+2]) {
 $temp = $data[$j];
 $data[$j] = $data[$j+2];
 $data[$j+2] = $temp;
  }
  } 
  }
 for ($i = 1; $i < 10; $i++) {
 for ($j = $i - 1; $j >= 0; $j-=1) {
 if ($data[$j] > $data[$j+1]) {
 $temp = $data[$j];
 $data[$j] = $data[$j+1];
 $data[$j+1] = $temp;
 } 
 }
 }
 var_dump($data);
 }
 }
var_dump(ShellSort::shellSortMoveArray([0 => 9, 1 => 6, 2 => 1, 3 => 3, 4 => 0, 5 => 5, 6 => 7, 7 => 2, 8 => 8, 9 => 4]));
// $gap = 10 / 2 = 5
// $insertIndex  = $i = $gap = 5
// $insertValue = $data[$insertIndex] = $data[5] = 5;
// $data[$insertIndex] < $data[$insertIndex - $gap] == $data[5] < $data[5-5] = $data[0] ==> 5 < 9
// while(5 - 5 >= 0 && 5 < 9) {
//  $data[5] = $data[5-5] = $data[0] = 9
//  $insertIndex -= 5 = 0;
//}
// $data[$insertIndex] = $data[0] = $insertValue = 5
// $i++ = 6;
// $insertIndex  = $i =  6
// $insertValue = $data[$insertIndex] = $data[6] = 7;
// $data[$insertIndex] < $data[$insertIndex - $gap] == $data[6] < $data[6-5] = $data[1] ==> 7 < 6
// $i++ = 7;
// $insertIndex  = $i =  7
// $insertValue = $data[$insertIndex] = $data[7] = 2;
// $data[$insertIndex] < $data[$insertIndex - $gap] == $data[7] < $data[7-5] = $data[2] ==> 2 < 1
// $i++ = 8;
// $insertIndex  = $i =  8
// $insertValue = $data[$insertIndex] = $data[8] = 8;
// $data[$insertIndex] < $data[$insertIndex - $gap] == $data[8] < $data[8-5] = $data[3] ==> 8 < 3
// $i++ = 9;
// $insertIndex  = $i =  9
// $insertValue = $data[$insertIndex] = $data[9] = 4;
// $data[$insertIndex] < $data[$insertIndex - $gap] == $data[9] < $data[9-5] = $data[4] ==> 4 < 0

以上就是PHP 排序算法之希尔排序的详细内容,更多请关注php交流社区其它相关文章!


2019年12月10日 22:14    来自: 王二狗丶
最近接触到一个项目,涉及到微信支付,搞微信开发这么久以来,还没搞过支付,之前也就搞过公众号发红包,感谢前辈们的探索,我看了他们的博文,让我少走了很多弯路。

前期准备:

1.微信认证服务号,并且开通了微信支付

2.微信支付SDK,下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

3.登录微信支付平台https://pay.weixin.qq.com/index.php/account/api_cert下载支付证书

方法步骤:

1.demo文件处理

(1)将官方的demo下载下来,文件名为WxpayAPI_php_v3,把这文件重命名为wxpay,为了后边书写目录方便;

(2)打开lib文件夹下的WxPay.Api.php文件,在537行有一段curl网络请求配置代码:

curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验

替换成:

curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验

为了禁止 cURL 验证对等证书(peer's certificate)。

(3)打开lib文件夹下的WxPay.Config.php文件,第25行开始,根据自己的账号完成基本信息设置;

const APPID = '公众账号APPID';
const MCHID = '商户号';
const KEY = '商户支付密钥';
const APPSECRET = '公众帐号secert';

(4)打开lib文件夹下的WxPay.Notify.php文件,第79行的代码:

if($needSign == true && 
$this->GetReturn_code($return_code) == "SUCCESS")
{
$this->SetSign();
}

改成:

if($needSign == true && 
$this->GetReturn_code() == "SUCCESS")
{
$this->SetSign();
}

(5)打开cert证书目录,将里边的两个证书换成自己的支付证书。

2.公众号后台设置

(1)配置网页授权域名,我的域名是(xy.chuyin.ren);

ee1473dddcb2669fd889ca5b64129e2.png

(1)配置支付授权目录,域名是(xy.chuyin.ren),我将demo放到此域名指向的目录的weixinopen/文件夹下,demo中jsapi.php文件位于example/目录下,所以支付授权目录为:xy.chuyin.ren/weixinopen/wxpay/example/

082f5920fb14c23b4c01e2e30b6291d.png

3.支付流程

打开example目录下的jsapi.php文件,支付发起和处理,都是在这里完成。

(1)获取用户openid

之前配置好了自己的APPID和APPSecert,所以这里不用处理。

//①、获取用户openid
$tools = new JsApiPay();
$openId = $tools->GetOpenid();

这里首先初始化的一个JsApiPay()类得到一个对象,文件对应example/目录下的WxPay.JsApiPay.php,调用GetOpenid()方法,会自动获取自己的openID。

(2)统一下单

//②、统一下单
$input = new WxPayUnifiedOrder();
$input->SetBody("test");
$input->SetAttach("test");
$input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis"));
$input->SetTotal_fee("1");
$input->SetTime_start(date("YmdHis"));
$input->SetTime_expire(date("YmdHis", time() + 600));
$input->SetGoods_tag("test");
$input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");
$input->SetTrade_type("JSAPI");
$input->SetOpenid($openId);
$order = WxPayApi::unifiedOrder($input);
echo '<font color="#f00"><b>统一下单支付单信息</b></font><br/>';
printf_info($order);
$jsApiParameters = $tools->GetJsApiParameters($order);

对应WxPay.Api.php的第24行的unifiedOrder()方法,配置订单信息和支付回调函数,这里需要修改几个参数:

A. 商品名称:

$input->SetBody("test");

B. 订单号

$input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis"));

C. 支付金额

$input->SetTotal_fee("1");

D. 支付验证链接

设置为你的notify.php文件所在的位置,所以我这里设置为:

http://xy.chuyin.ren/weixinopen/wxpay/example/notify.php

也可以写其他地址,当然要在支付授权域名之下,支付成功之后就会自动回调到该链接指定的方法里边,可以在里边进行判断和数据库操作.

$input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");

E. 附加参数

$input->SetAttach("test");

附加参数,可填可不填,填写的话,里边字符串最好不要出现空格。

这时候,点击支付应该就可以成功支付了。

(3)发起支付

<script type="text/javascript">
//调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
<?php echo $jsApiParameters; ?>,
function(res){
WeixinJSBridge.log(res.err_msg);
alert(res.err_code+res.err_desc+res.err_msg);
}
);
}
 
function callpay()
{
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', jsApiCall); 
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
}else{
jsApiCall();
}
}
</script>

点击立即支付按钮调用的就是 callpay() 函数,他有会调用jsApiCall() 函数打开支付程序。

c31860fe6bbe5dfc7e370a0980a3e28.png

jsApiCall() 函数会监听每一步动作:

263ab4d748e2fa19910fef1848219ce.png

res.err_msg 为get_brand_wcpay_request:cancel 表明前端判断的取消支付,es.err_msg 为get_brand_wcpay_request:ok 表明前端判断的支付成功,我们可以根据这个将支付跳转到成功页面。

(4)支持成功回调

通过前端jsApiCall()函数可以监听支付结果,但是这个并不可信。确认是否支付成功还是应当通过notify.php 处理业务逻辑。前边配置好了支付验证链接SetNotify_url(),支付完成后,微信服务器会根据链接自动请求你的notify.php文件,打开这个文件,其实这个文件最主要的代码就两行:

$notify = new PayNotifyCallBack();
$notify->Handle(false);

由此跟踪到WxPay.Notify.php类文件的Handle()函数:

/**
 * 
 * 回调入口
 * @param bool $needSign  是否需要签名输出
 */
final public function Handle($needSign = true)
{
$msg = "OK";
//当返回false的时候,表示notify中调用NotifyCallBack回调失败获取签名校验失败,此时直接回复失败
$result = WxpayApi::notify(array($this, 'NotifyCallBack'), $msg);
if($result == false){
$this->SetReturn_code("FAIL");
$this->SetReturn_msg($msg);
$this->ReplyNotify(false);
return;
} else {
//该分支在成功回调到NotifyCallBack方法,处理完成之后流程
$this->SetReturn_code("SUCCESS");
$this->SetReturn_msg("OK");
}
$this->ReplyNotify($needSign);
}

主要代码:

$result = WxpayApi::notify(array($this, 'NotifyCallBack'), $msg);
然后来到WxPay.Api.php文件的第411行,notify()函数:
/**
 * 
 * 支付结果通用通知
 * @param function $callback
 * 直接回调函数使用方法: notify(you_function);
 * 回调类成员函数方法:notify(array($this, you_function));
 * $callback  原型为:function function_name($data){}
 */
public static function notify($callback, &$msg)
{
//获取通知的数据
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
//file_put_contents('log.txt',$xml,FILE_APPEND);
//如果返回成功则验证签名
try {
$result = WxPayResults::Init($xml);
} catch (WxPayException $e){
$msg = $e->errorMessage();
return false;
}
return call_user_func($callback, $result);
}

这里面的$xml=$GLOBALS['HTTP_RAW_POST_DATA'],就是支付成功后用户返回给你的一个结果,他是一个xml格式的字符串。

8666f766899c14392f0496a83aac807.png

我们可以将这里返回的xml数据记录下来,然后打开看看$out_trade_no就是在支付之前我自己设置的订单号码,$attach就是设置的附加参数。

得到了这个订单号,然后我就直接在下面写支付成功后的逻辑了,比如改变数据库中的数据等等。

这样 微信支付的 JsApi支付就大致分析完成了。

472012b1488c5804460321c2dc517d5.png

这是集成了官方的SDK实现的,如果不使用SDK,可以使用更简单的方法,见:PHP实现微信支付(jsapi支付)和退款(无需集成支付SDK).

更多PHP相关知识,请访问PHP交流社区!

以上就是PHP实现微信支付(jsapi支付)流程的方法的详细内容,更多请关注php交流社区其它相关文章!


2019年12月10日 22:14    来自: 王二狗丶
插入排序 Insert Sort

● 插入排序的思想:

将一个待排序的无序的数组看作是两个列表,一个有序的列表,一个无序的列表,从无序的列表每次拿出一个待插入的元素,插入到有序的列表中,直到无序列表为空,排序完毕

● 实际举例:

1. 有一个无序的一维数组是这次需要排序的数组,数组是:[36,12,96,-1]

2. 首先把数组的第一个元素 [36] 看作是一个独立的有序的列表,把剩下的元素 [12, 96, -1] 看作是一个无序的列表

3. 第一个待插入的元素就是 12,要把 12 插入到有序的列表中,首先需要 12 和 36 比较,如果带插入的元素 12 小于 36, 就需要把 12 插入到 36前面,也就是 36 要后移一位。

4. 插入排序实际是需要比较数组元素的总数减一轮,因为第一个元素不需要比较。

$arr = [36,12,96,-1];
//待插入的数
$insertValue = $arr[1];
//待插入数前面的数的索引
$insertIndek = 1 - 1;
//$insertIndek >= 0 保证插入循环时,不越界,保证第一个元素的下标要大于等0
//$insertValue < $arr[$insertIndek] 保证待插入的数还没有找到插入的位置,即待插入的数是小于它前面的那一个元素的
//符合上述条件的,需要将$arr[$insertIndek] 后移
while($insertIndek >= 0 && $insertValue < $arr[$insertIndek]) {
 $arr[$insertIndek+1] = $arr[$insertIndek]; $insertIndek--;
 //代表的就是有序列表的最前面一个元素的前面一个下标 -1;
}
//当退出循环时,代表找到位置 $insertIndek + 1
$arr[$insertIndek + 1] = $insertValue;
//把插入的元素插入到有序列表的第一个位置或者是没发生交换就在本身的位置
$arr = [12,36,96,-1];
//待插入的数
$insertValue = $arr[2];
//待插入数前面的数的索引
$insertIndek = 2 - 1;
//$insertIndek >= 0 保证插入循环时,不越界,保证第一个元素的下标要大于等0
//$insertValue < $arr[$insertIndek] 保证待插入的数还没有找到插入的位置,即待插入的数是小于它前面的那一个元素的
//符合上述条件的,需要将$arr[$insertIndek] 后移
while($insertIndek >= 0 && $insertValue < $arr[$insertIndek]) {
 $arr[$insertIndek+1] = $arr[$insertIndek];
 $insertIndek--;
 //代表的就是有序列表的最前面一个元素的前面一个下标 -1;
}
//当退出循环时,代表找到位置 $insertIndek + 1
$arr[$insertIndek + 1] = $insertValue;//把插入的元素插入到有序列表的第一个位置或者是没发生交换就在本身的位置

依次类推,得到完成的有序数组

5. 完整代码如下:

<?php
class InsertSort
{
 public static function insertArraySort(array $data):array
 { 
 if (!is_array($data)) {
 return ['message' => '待排序的序列非数组'];
 }
 $count = count($data);
 if ($count <= 1) {
 return $data;
 }
 for ($i = 1; $i < $count; $i++) {
 //待插入的元素
 $insertValue = $data[$i];
 //待插入数前面的数的索引
 $insertIndek = $i - 1;
 //$insertIndek >= 0 保证插入循环时,不越界,保证第一个元素的下标要大于等0\
 //$insertValue < $arr[$insertIndek] 保证待插入的数还没有找到插入的位置,即待插入的数是小于它前面的那一个元素的
 //符合上述条件的,需要将$arr[$insertIndek] 后移
 while($insertIndek >= 0 && $insertValue < $data[$insertIndek]) {
 $data[$insertIndek+1] = $data[$insertIndek];
 $insertIndek--;//代表的就是有序列表的最前面一个元素的前面一个下标 -1;
 }
 //当退出循环时,代表找到位置 $insertIndek + 1
 //把插入的元素插入到有序列表的第一个位置
 //或者是没发生交换,即待插入元素大于有序列表的最后一个元素,那么这里只需要将有序列表的最后一个元素的索引 + 1,把待插入元素放在后
 //面一位即可
 $data[$insertIndek + 1] = $insertValue;\ }
 return $data;
 }
 }
$arr = [36,12,96,-1];
var_dump(InsertSort::insertArraySort($arr));

以上就是PHP 排序算法之插入排序的详细内容,更多请关注php交流社区其它相关文章!


2019年12月10日 22:14    来自: 王二狗丶
下面的做法会占用多大的内存?

list($appid,$openid) = ["testcontent","test"];

测试

$m0 = memory_get_usage();
$k = range(1,200000);
$m1 = memory_get_usage();
echo round(($m1-$m0)/pow(1024,2),4) ."MB\n";
foreach ($k as $i){
    $n1 = "kk$i";
    $n2 = "tt$i";
    list($$n1,$$n2) = [$i,$i*3];
}
$m2 = memory_get_usage();
echo round(($m2-$m1)/pow(1024,2),4) ."MB\n";
$m1 = memory_get_usage();
foreach ($k as $i){
    $n1 = "kk$i";
    $n2 = "tt$i";
    $$n1 = $i+time();
    $$n2 = 2*time();
}
$m2 = memory_get_usage();
echo round(($m2-$m1)/pow(1024,2),4) ."MB\n";

上面运行输出的结果如下:

27.9404MB
51.3041MB
9.1553MB

可见数组占用的内存远大于正常分配的内容

原理

在PHP中都使用long类型来代表数字,没有使用int类型。大家都明白PHP是一种弱类型的语言,它不会去区分变量的类型,没有int float char *之类的概念。我们看看php在zend里面存储的变量,PHP中每个变量都有对应的 zval,Zval结构体定义在Zend/zend.h里面,其结构:

typedef struct _zval_struct zval;  
struct _zval_struct {  
    /* Variable information */  
    zvalue_value value;     /* The value 1 12字节(32位机是12,64位机需要8+4+4=16) */  
    zend_uint refcount__gc; /* The number of references to this value (for GC) 4字节 */  
    zend_uchar type;        /* The active type 1字节*/  
    zend_uchar is_ref__gc;  /* Whether this value is a reference (&) 1字节*/  
};

PHP使用一种UNION结构来存储变量的值,即zvalue_value 是一个union,UNION变量所占用的内存是由最大成员数据空间决定。

typedef union _zvalue_value {  
    long lval;                  /* long value */  
    double dval;                /* double value */  
    struct {                    /* string value */  
        char *val;  
        int len;  
    } str;   
    HashTable *ht;              /* hash table value */  
    zend_object_value obj;      /*object value */  
} zvalue_value;

最大成员数据空间是struct str,指针占*val用4字节,INT占用4字节,共8字节。

struct zval占用的空间为8+4+1+1 = 14字节,其实呢,在zval中数组,字符串和对象还需要另外的存储结构,数组则是一个 HashTable:

HashTable结构体定义在Zend/zend_hash.h.

typedef struct _hashtable {  
    uint nTableSize;//4  
    uint nTableMask;//4  
    uint nNumOfElements;//4  
    ulong nNextFreeElement;//4  
    Bucket *pInternalPointer;   /* Used for element traversal 4*/  
    Bucket *pListHead;//4  
    Bucket *pListTail;//4  
    Bucket **arBuckets;//4  
    dtor_func_t pDestructor;//4  
    zend_bool persistent;//1  
    unsigned char nApplyCount;//1  
    zend_bool bApplyProtection;//1  
#if ZEND_DEBUG  
    int inconsistent;//4  
#endif  
} HashTable;

HashTable 结构需要 39 个字节,每个数组元素存储在 Bucket 结构中:

typedef struct bucket {  
    ulong h;    /* Used for numeric indexing                4字节 */  
    uint nKeyLength;    /* The length of the key (for string keys)  4字节 */  
    void *pData;        /* 4字节*/  
    void *pDataPtr;         /* 4字节*/  
    struct bucket *pListNext;  /* PHP arrays are ordered. This gives the next element in that order4字节*/  
    struct bucket *pListLast;  /* and this gives the previous element           4字节 */  
    struct bucket *pNext;      /* The next element in this (doubly) linked list     4字节*/  
    struct bucket *pLast;      /* The previous element in this (doubly) linked list     4字节*/  
    char arKey[1];            /* Must be last element   1字节*/  
} Bucket;

Bucket 结构需要 33 个字节,键长超过四个字节的部分附加在 Bucket 后面,而元素值很可能是一个 zval 结构,另外每个数组会分配一个由 arBuckets 指向的 Bucket 指针数组, 虽然不能说每增加一个元素就需要一个指针,但是实际情况可能更糟。这么算来一个数组元素就会占用 54 个字节,与上面的估算几乎一样。

一个空数组至少会占用 14(zval) + 39(HashTable) + 33(arBuckets) = 86 个字节,作为一个变量应该在符号表中有个位置,也是一个数组元素,因此一个空数组变量需要 118 个字节来描述和存储。从空间的角度来看,小型数组平均代价较大,当然一个脚本中不会充斥数量很大的小型数组,可以以较小的空间代价来获取编程上的快捷。但如果将数组当作容器来使用就是另一番景象了,实际应用经常会遇到多维数组,而且元素居多。比如10k个元素的一维数组大概消耗540k内存,而10k x 10 的二维数组理论上只需要 6M 左右的空间,但是按照 memory_get_usage 的结果则两倍于此,[10k,5,2]的三维数组居然消耗了23M,小型数组果然是划不来的。

以上就是PHP 数组占用内存分析的详细内容,更多请关注php交流社区其它相关文章!


2019年12月10日 22:14    来自: 王二狗丶
返回

圈子成员

关注官方微信
校外加油站微信二维码
领航时时彩软件 虎扑nba比分直播 广州浪奇股票 股票推荐及行业分析 福建快3 荣耀配资 老牌配资 中国最大的股票配资公司 黑龙江36选7 竞彩比分奖金限额 北京快乐8 掌柜配资 二分彩 qq分分彩 网上不能炒 股票融资网 策略盈