微信app支付接入后端php数据签名方式

微信app支付接入后端php数据签名方式

微信app支付接入后端php数据签名方式

我们先看看微信app支付的流程

微信app支付接入后端php数据签名方式

商户系统和微信支付系统主要交互说明:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay
步骤4:商户APP调起微信支付。
步骤5:商户后台接收支付通知。
步骤6:商户后台查询支付结果。

我们再看看微信支付app端的代码

appayBtn.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				String url="https://wxpay.wxutil.com/pub_v2/app/app_pay.php";
				Button payBtn = (Button) findViewById(R.id.appay_btn);
				payBtn.setEnabled(false);
					Toast.makeText(MainActivity.this, "获取订单中...", Toast.LENGTH_SHORT).show();
					try{
					byte[] buf = HttpUtil.httpGet(url);
					if (buf != null && buf.length > 0) {
						String content = new String(buf);
						Log.e("get server pay params:",content);
						JSONObject json = new JSONObject(content);

						if(null != json) ){
							PayReq req = new PayReq();
							req.appId	= json.getString("appid");
							req.partnerId		= json.getString("partnerid");
							req.prepayId		= json.getString("prepayid");
							req.nonceStr		= json.getString("noncestr");
							req.timeStamp		= json.getString("timestamp");
							req.packageValue	= json.getString("package");
							req.sign			= json.getString("sign");
							req.extData			= "app data"; // optional
							Toast.makeText(MainActivity.this, "正常调起支付", Toast.LENGTH_SHORT).show();
							// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
							Log.e("wangbo", "checkArgs=" + req.checkArgs());
							boolean ret=api.sendReq(req);
							Log.e("wangbo", "ret=" + ret);
						}else{
							Log.e("PAY_GET", "返回错误"+json.getString("retmsg"));
							Toast.makeText(MainActivity.this, "返回错误"+json.getString("retmsg"), Toast.LENGTH_SHORT).show();
						}
					}else{
						Log.d("PAY_GET", "服务器请求错误");
						Toast.makeText(MainActivity.this, "服务器请求错误", Toast.LENGTH_SHORT).show();
					}
				}catch(Exception e){
					Log.e("PAY_GET", "异常:"+e.getMessage());
					Toast.makeText(MainActivity.this, "异常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
				}
				payBtn.setEnabled(true);
			}
		});

通过上面app的代码我们可以看到后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付!官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

下面我看看后台怎么生成预支付交易单和签名的

<?php

echo apppay('订单号','价格'); //直接输出json给前台APP

//入口函数
function apppay($order_num,$price){
 $json = array();
 //生成预支付交易单的必选参数:
 $newPara = array();
 //应用ID
 $newPara["appid"] = "商户appid";
 //商户号
 $newPara["mch_id"] = "商户id";
 //设备号
 $newPara["device_info"] = "WEB";
 //随机字符串,这里推荐使用函数生成
 $newPara["nonce_str"] = createNoncestr();
 //商品描述
 $newPara["body"] = "APP支付";
 //商户订单号,这里是商户自己的内部的订单号
 $newPara["out_trade_no"] = $order_num;
 //总金额
 $newPara["total_fee"] = $price*100;
 //终端IP
 $newPara["spbill_create_ip"] = $_SERVER["REMOTE_ADDR"];
 //通知地址,注意,这里的url里面不要加参数
 $newPara["notify_url"] = "支付成功后的回调地址";
 //交易类型
 $newPara["trade_type"] = "APP";

 $key = "密钥:在商户后台个人安全中心设置";
 //第一次签名
 $newPara["sign"] = appgetSign($newPara,$key);

 //把数组转化成xml格式
 $xmlData = arrayToXml($newPara);

 $get_data = sendPrePayCurl($xmlData);

 //返回的结果进行判断。
 if($get_data['return_code'] == "SUCCESS" && $get_data['result_code'] == "SUCCESS"){
  //根据微信支付返回的结果进行二次签名
  //二次签名所需的随机字符串
  $newPara["nonce_str"] = createNoncestr();
  //二次签名所需的时间戳
  $newPara['timeStamp'] = time()."";
  //二次签名剩余参数的补充
  $secondSignArray = array(
  "appid"=>$newPara['appid'],
  "noncestr"=>$newPara['nonce_str'],
  "package"=>"Sign=WXPay",
  "prepayid"=>$get_data['prepay_id'],
  "partnerid"=>$newPara['mch_id'],
  "timestamp"=>$newPara['timeStamp'],
  );
  $json['success'] = 1;
  $json['ordersn'] = $newPara["out_trade_no"]; //订单号
  $json['order_arr'] = $secondSignArray; //返给前台APP的预支付订单信息
  $json['order_arr']['sign'] = appgetSign($secondSignArray,$key); //预支付订单签名
  $json['data'] = "预支付完成";
  //预支付完成,在下方进行自己内部的业务逻辑
  /*****************************/
  return json_encode($json);
 }
 else{

  $json['success'] = 0;
  $json['error'] = $get_data['return_msg'];
  return json_encode($json);
 }
 }

//将数组转换为xml格式
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;

  }


 //发送请求
 function sendPrePayCurl($xml,$second=30)

 {

  $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";

  $ch = curl_init();

  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);

  curl_close($ch);

  $data_xml_arr =XMLDataParse($data);

  if($data_xml_arr)

  {

   return $data_xml_arr;
  }

  else

  {

   $error = curl_errno($ch);

   echo "curl出错,错误码:$error"."<br>";

   echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";

   curl_close($ch);

   return false;

  }

 }

//xml格式数据解析函数
function XMLDataParse($data){
 $xml = simplexml_load_string($data,NULL,LIBXML_NOCDATA);
 $array=json_decode(json_encode($xml),true);
 return $array;
}

//随机字符串
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;

 }

/*
* 格式化参数格式化成url参数 生成签名sign
*/
function appgetSign($Obj,$appwxpay_key)

 {

  foreach ($Obj as $k => $v)

  {

   $Parameters[$k] = $v;

  }

  //签名步骤一:按字典序排序参数

  ksort($Parameters);

  $String = formatBizQueryParaMap($Parameters, false);

  //echo '【string1】'.$String.'</br>';

  //签名步骤二:在string后加入KEY
    if($appwxpay_key){
      $String = $String."&key=".$appwxpay_key;
    }

  //echo "【string2】".$String."</br>";

  //签名步骤三:MD5加密

  $String = md5($String);

  //echo "【string3】 ".$String."</br>";

  //签名步骤四:所有字符转为大写

  $result_ = strtoupper($String);

  //echo "【result】 ".$result_."</br>";

  return $result_;

 }

 //按字典序排序参数
 function formatBizQueryParaMap($paraMap, $urlencode)

 {

  $buff = "";

  ksort($paraMap);

  foreach ($paraMap as $k => $v)

  {

    if($urlencode)

    {

    $v = urlencode($v);

   }

   //$buff .= strtolower($k) . "=" . $v . "&";

   $buff .= $k . "=" . $v . "&";

  }

  $reqPar;

  if (strlen($buff) > 0)

  {

   $reqPar = substr($buff, 0, strlen($buff)-1);

  }

  return $reqPar;

 }



{{collectdata}}

网友评论0