APP服务端微信支付(PHP服务端)

<?php
/*
大概流程说明:
1、填写必填的参数到地址 微信统一地址 https://api.mch.weixin.qq.com/pay/unifiedorder
2、App端通过统一下单参数 返回一些数据 
3、通过得到的参数掉起微信支付,完成支付
4、此过程中需要做两次签名,
第一次签名是在上传request请求时,拼接的字符串,创建一次sign;
第二次签名是请求统一下单之后,主要是用返回的一个prepay_id的一个字符串,
根据appid、noncestr、package、partnerid、prepayid、timestamp这些字符串的内容,重新创建一次sign,
第二次的sign是为了调起微信支付用的。
*/


//填写必填的参数到地址 微信统一地址
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //微信统一地址

$body = "APP微信支付测试";
$appid = "wx111111111111";    //微信开放平台上的应用id
$mch_id = "2222222222"; //微信申请成功之后邮件中的商户id
$attach = "APP微信支付";
$total_fee = 1; //1分
$out_trade_no = rand(100000,999999);
$api_key = "as3aaaaaaaaaaaaaaaaaaaaaaaa"; //在微信商户平台上自己设定的api密钥 32位
$notify_url = "pay_weixin.php"; //自定义的回调程序地址

$nonce_str = $this->createNoncestr();


//获取签名必要参数
$data["appid"] = $appid;
$data["attach"] = $attach;
$data["body"] = $body;  
$data["mch_id"] = $mch_id;
$data["nonce_str"] = $nonce_str;
$data["notify_url"] = $notify_url;
$data["out_trade_no"] = $out_trade_no;
$data["spbill_create_ip"] = $this->get_client_ip();
$data["total_fee"] = $total_fee;
$data["trade_type"] = "APP";
   
//第一次签名 通过上传拼接的字符串 创建sign
$sign = $this->getSign($data);
$data["sign"] = $sign;


$xml = $this->arrayToXml($data);
$response = $this->postXmlCurl($xml, $url);


//将微信返回的结果xml转成数组
$response = $this->xmlToArray($response);


$new_arr=array();
$new_arr['appid'] = $appid;
$new_arr['partnerid'] = $mch_id;
$new_arr['prepayid'] = $response['prepay_id'];
$new_arr['package'] = "Sign=WXPay";
$new_arr['noncestr'] = $response['nonce_str'];
$new_arr['timestamp'] = time();


//第二次签名 调起微信支付
$sign2 = $this->getSign($new_arr);
$new_arr["sign"] = $sign2;


$xml2 = $this->arrayToXml($new_arr);
   
//将微信返回的结果xml转成数组
$response3 = $this->xmlToArray($xml2);


//数组转成json
echo json_encode($response3);
   


//微信支付 - 生成签名
public function getSign($Obj){
$api_key = "as3aaaaaaaaaaaaaaaaaaaaaaaa";


  foreach ($Obj as $k => $v){
      $Parameters[$k] = $v;
  }


  //签名步骤一:按字典序排序参数
  ksort($Parameters);
  $String = $this->formatBizQueryParaMap($Parameters, false);
  //echo '【string1】'.$String.'</br>';
  //签名步骤二:在string后加入KEY
  $String = $String."&key=".$api_key;
  //echo "【string2】".$String."</br>";
  //签名步骤三:MD5加密
  $String = md5($String);
  //echo "【string3】 ".$String."</br>";
  //签名步骤四:所有字符转为大写
  $result_ = strtoupper($String);
  //echo "【result】 ".$result_."</br>";
  return $result_;
}


//微信支付 - 产生随机字符串,不长于32位
public function createNoncestr( $length = 32 ){
  $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
  $str ="";
  for ( $i = 0; $i < $length; $i++ )  {
      $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
  }
  return $str;
}


//微信支付 - 数组转xml
public function arrayToXml($arr){
  $xml = "<xml>";
  foreach ($arr as $key=>$val){
      if (is_numeric($val)){
          $xml.="<".$key.">".$val."</".$key.">";
      }else{
          $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
      }
  }
  $xml.="</xml>";
  return $xml;
}


//微信支付 - 将xml转为array
public function xmlToArray($xml){
  //将XML转为array
  $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  return $array_data;
}


//微信支付 - 以post方式提交xml到对应的接口url
public function postXmlCurl($xml,$url,$second=30){
  //初始化curl
  $ch = curl_init();
  //设置超时
  curl_setopt($ch, CURLOPT_TIMEOUT, $second);
  //这里设置代理,如果有的话
  //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
  //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
  curl_setopt($ch,CURLOPT_URL, $url);
  curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
  curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
  //设置header
  curl_setopt($ch, CURLOPT_HEADER, FALSE);
  //要求结果为字符串且输出到屏幕上
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  //post提交方式
  curl_setopt($ch, CURLOPT_POST, TRUE);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
  //运行curl
  $data = curl_exec($ch);
  //返回结果


  if($data){
    curl_close($ch);
    return $data;
  }else{
    $error = curl_errno($ch);
    echo "curl出错,错误码:$error"."<br>";
    curl_close($ch);
    return false;
  }
}


//微信支付 - 获取当前服务器的IP
public function get_client_ip(){
  if ($_SERVER['REMOTE_ADDR']) {
     $cip = $_SERVER['REMOTE_ADDR'];
  } elseif (getenv("REMOTE_ADDR")) {
     $cip = getenv("REMOTE_ADDR");
  } elseif (getenv("HTTP_CLIENT_IP")) {
     $cip = getenv("HTTP_CLIENT_IP");
  } else {
     $cip = "unknown";
  }
  return $cip;
}


//微信支付 - 格式化参数,签名过程需要使用
public function formatBizQueryParaMap($paraMap, $urlencode){
  $buff = "";
  ksort($paraMap);
  foreach ($paraMap as $k => $v){
    if($urlencode){
        $v = urlencode($v);
    }
    $buff .= $k . "=" . $v . "&";
  }
  $reqPar;
  if (strlen($buff) > 0){
    $reqPar = substr($buff, 0, strlen($buff)-1);
  }
  return $reqPar;
}
     
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
微信 支付这 官方文档 很乱 写的 也不是很清楚,测试时 一定要与安卓 或 苹果端 一起测试。 否则 根本找不到问题。 废话 不过说 先 说说 几大坑的地方。我也是 借鉴 别人的 博客 才测试成功调起支付。文章后 直接上代码 代码 绝对能调起 微信 测试过的! 第一步,生成prepayid,这一步,只要你的appid,mch_id,key没写错,那么99%以上都能获取到prepayid,如果失败,那肯定是几个ID和key有问题,仔细检查,包括编码等,仔细仔细仔细检查。 问题来了,第二步,对获取到的prepayid进行二次签名,官方文档的坑来了,官方并没有详细说明这一步骤,一切的一切只能靠自己摸索,爬坑。 首先第一坑:参数顺序,我这里用了SortedMap,自动对参数进行asc编码顺序,一劳永逸,当然,也可以用其他map,但一定要注意参数顺序,必须是asc编码顺序。 第二坑:参数package的Sign=WXPay中=的编码问题,转码即可,小坑。 第三坑:苹果系统的timestamp位数,统一成10位即可,小坑。 第四坑:次级大坑,注意,官方文档说到的参与二次签名的参数,prepayId,appId,timeStamp等,如果你用他们的驼峰进行大写,那么你就完了。一定要小写,小写,小写。 第五坑:最大坑,一样,官方文档并没有对于二次签名有过多赘述,如果你上面几个坑完美出坑,那么,你获取到的签名sign跟官方验证的sign绝对是一样的,然而,将这些玩意丢回给APPAPP调起支付,大大的几个字出现了,验证签名失败!WTF!不要急,我已折腾了好几天,终于发现坑在哪里,那就是noncestr随机字符串,参与二次签名的随机字符串不能再次生成,注意,不能再次生成,一定要用第一步中获取prepayid时的那串字符串,一定要用第一步中获取prepayid时的那串字符串,一定要用第一步中获取prepayid时的那串字符串。 第六坑:经历了上述5坑,相信你已经有想干死人的冲动,那么你以为这就结束了吗,还有最后一坑,那就是APP签名已经包名,一定要与开放平台中的一致,然而,即使一致了你以为又结束了吗,NO,如果你更改过开放平台中的签名,并且,在更改前调用过APP微信支付,那么一定一定一定一定记得清除微信缓存。 至此,所有坑都成功出坑,终于出现了支付页面,举国欢腾,微信去年买了个表。最后附上MD5签名类

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值