Android_APP微信支付之实现代码

在之前的一篇Android_APP微信支付接口开发中说了大概的实现方式和一些注意细节,这是说在微信支付中应该由我们的服务器来生成支付订单,以及对prepay_id的再次签名都应该在我们的服务器中完成。

下面就贴出服务器端的代码,主要是生成支付订单以及对prepay_id进行签名,然后将生成的签名prepay_id传给客户端,在客户端进行二次签名并调起支付:

<?php
$json = stripslashes($_SGET['json']); //去斜杠,stripslashes()函数:删除反斜杠
$getarray = json_decode($json,true); //转码,json_decode()函数:对JSON格式的字符串进行编码//json_encode()函数:对变量进行JSON编码
//防止SQL注入
foreach($getarray as $k=>$v){
	$str=show_sql_keyword($v);
	if($str){
		$msg = urlencode ("含有非法字符");//urlencode()函数:编码URL字符串;urldecode()函数:解码已经编码的URL字符串
		$data = array(result => 2,msg => $msg);	
		echo urldecode ( json_encode ( $data ) );
		exit;
	}
}

if($getarray['submit']){
	$OS = $getarray['OS'];
	$paymentid = $getarray['paymentid'];
	$username = $getarray['username'];
	$money = $getarray['money'];
	$orderNO = $getarray['orderNO'];
	
	//判断金额是否为负数
    if($money<0){
	   $msg = urlencode ("提款金额不能为负数");
	   $data = array(result => 5,msg => $msg);	
	   echo urldecode ( json_encode ( $data ) );
	   exit;  
    }
	
	$sql = "select `username`,`uid` from ".$_SC['tablepre']."user where `username`='{$username}'";
	$query = $_SGLOBAL['db']->query($sql);
	$consignee = $_SGLOBAL['db']->fetch_array($query);
	//用户判断
	if($consignee['username'] == ''){
		$msg = urlencode ("nouser");
		$data = array(result => 2,msg => $msg);	
		echo urldecode ( json_encode ( $data ) );
		exit;	
	}
	//充值金额判断
	$money = $money;
	$money_rules = '/^([123456789]+)\d*(\.?\d{0,2})$|^(0{1})(\.{1}\d{0,2})$/';
	if(!preg_match($money_rules,$money)){ //preg_match()函数:执行一个正则表达式匹配
		$msg = urlencode ("error");
		$data = array(result => 4,msg => $msg);	
		echo urldecode ( json_encode ( $data ) );
		exit;	
	}
	//订单号判断
	if($orderNO != ''){
		$orderNO = $getarray['orderNO']; //如果订单号不为空 则取出数组里的订单号
	}else{
		$orderNO = substr(date("YmdHis"),2,8).mt_rand(100000,999999); //否则随机生成一个订单号
		//记录充值
		$payorder_data = array(
			'payuserid'=>$consignee['uid'],
			'orderNO'=>$orderNO,
			'tradeNO'=>'',
			'payname'=>'',
			'consignee'=>$consignee['username'],
			'consigneeuid'=>'',
			'money'=>$money,
			'paymentid'=>$paymentid,
			'paymentlabel'=>"微信支付",
			'payresult'=>0,
			'deliverrs'=>'',
			'paydate'=>'',
			'dateline'=>time(),
		);
	    inserttable($_SC['tablepre'],"payorder", $payorder_data, 1 );
	}
	//上面大部分代码是根据每个项目需要进行的逻辑处理,下面微信支付生成支付订单以及prepay_id的主要代码
	$prepayxml='';
	$data=array();
	//判断是否是Android端传过来的调起支付
	if($OS=="Android"){
		$noncestr=md5(rand());//int rand(void)函数:产生一个随机整数,返回0到getrandMax()之间的伪随机整数。
		//亦可带参数int rand ( int $min , int $max )
		$prepayid_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		$appkey='API密钥'; //API密钥,在商户平台设置
		//注:appid、body、mch_id、notify_url填写上对应的值
		$preamdata = array (
				'appid' => 'appid',
				'body' => '标题',
				'input_charset'=>'UTF-8',
				'mch_id'=>'商户号',
				'notify_url'=>'http://www.XXXX.com/payapi/wxnotify.php',
				'out_trade_no'=>$orderNO,
				'spbill_create_ip'=>"192.168.1.16",
				'total_fee'=>$money*100,
				'trade_type'=>"APP",
				"nonce_str"=>$noncestr,
		);
		$sign=MakeSign($preamdata,$appkey); //生成sign签名
		//echo $str;
		
		// 参数数组,拼接成XML
		$preamstr='<?xml version="1.0" encoding="UTF-8"?>';
		$preamstr.='<xml>';
		$preamstr.='<appid>appid</appid>'; //appid
		$preamstr.='<body>标题</body>'; //标题
		$preamstr.='<input_charset>UTF-8</input_charset>'; //编码,不然body不能出现中文
		$preamstr.='<mch_id>商户号</mch_id>'; //商户号
		$preamstr.='<notify_url>http://www.XXXX.com/payapi/wxnotify.php</notify_url>'; //成功支付回调地址
		$preamstr.='<out_trade_no>'.$orderNO.'</out_trade_no>'; //订单号
		$preamstr.='<spbill_create_ip>192.168.1.16</spbill_create_ip>'; //ip
		$preamstr.='<total_fee>'.($money*100).'</total_fee>'; //金额,微信支付默认分为单位,所以要乘以100
		$preamstr.='<trade_type>APP</trade_type>'; //交易类型
		$preamstr.='<nonce_str>'.$noncestr.'</nonce_str>';
		$preamstr.='<sign>'.$sign.'</sign>'; //sign签名
		$preamstr.='</xml>';
		
		//echo $preamstr;
		//创建一个新curl资源
		$ch = curl_init ();
		// print_r($ch);
		//设置URL和相应的选项
		curl_setopt ( $ch, CURLOPT_URL, $prepayid_url );
		curl_setopt ( $ch, CURLOPT_POST, 1 );
		curl_setopt ( $ch, CURLOPT_HEADER, 0 );
		curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
		curl_setopt ( $ch, CURLOPT_POSTFIELDS, $preamstr );
		//抓取URL并把它传递给浏览器
		$return = curl_exec ( $ch );
		//关闭curl资源,并且释放系统资源
		curl_close ( $ch );
		$prepayxml = $return;
	}elseif($OS=="IOS"){ //判断是否是IOS端传过来的调起支付
		$noncestr=md5(rand());
		$prepayid_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		$appkey='API密钥';
		$preamdata = array (
				'appid' => 'appid',
				'body' => '标题',
				'input_charset'=>'UTF-8',
				'mch_id'=>'商户号',
				'notify_url'=>'http://www.XXXX.com/payapi/wxnotify.php',
				'out_trade_no'=>$orderNO,
				'spbill_create_ip'=>"192.168.1.16",
				'total_fee'=>$money*100,
				'trade_type'=>"APP",
				"nonce_str"=>$noncestr,
		);
		$sign=MakeSign($preamdata,$appkey); //生成sign签名
		//echo $str;
		
		// 参数数组,拼接成XML
		$preamstr='<?xml version="1.0" encoding="UTF-8"?>';
		$preamstr.='<xml>';
		$preamstr.='<appid>appid</appid>';
		$preamstr.='<body>标题</body>';
		$preamstr.='<input_charset>UTF-8</input_charset>';
		$preamstr.='<mch_id>商户号</mch_id>';
		$preamstr.='<notify_url>http://www.XXXX.com/payapi/wxnotify.php</notify_url>';
		$preamstr.='<out_trade_no>'.$orderNO.'</out_trade_no>';
		$preamstr.='<spbill_create_ip>192.168.1.16</spbill_create_ip>';
		$preamstr.='<total_fee>'.($money*100).'</total_fee>';
		$preamstr.='<trade_type>APP</trade_type>';
		$preamstr.='<nonce_str>'.$noncestr.'</nonce_str>';
		$preamstr.='<sign>'.$sign.'</sign>';
		$preamstr.='</xml>';
		
		//echo $preamstr;
		//创建一个新curl资源
		$ch = curl_init ();
		// print_r($ch);
		//设置URL和相应的选项
		curl_setopt ( $ch, CURLOPT_URL, $prepayid_url );
		curl_setopt ( $ch, CURLOPT_POST, 1 );
		curl_setopt ( $ch, CURLOPT_HEADER, 0 );
		curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
		curl_setopt ( $ch, CURLOPT_POSTFIELDS, $preamstr );
		//抓取URL并把它传递给浏览器
		$return = curl_exec ( $ch );
		//关闭curl资源,并且释放系统资源
		curl_close ( $ch );
		
		//print_r($return);
		//echo $return;
		$prepayxml = $return;
		
	}else{
		$msg = urlencode ("error");
		$data = array(result => 5,msg => $msg);	
		echo urldecode ( json_encode ( $data ) );
		exit;	
	}

	$data['msg']='done';
	$data['orderno'] = $orderNO;
	$data['result'] = 1;
	$str=urldecode ( json_encode ( $data ) );
	echo substr($str,0,-1).',"prepayxml":"'.$prepayxml.'"}';
}
/**
 * 生成签名
 * @param $arr 用到的参数数组
 * @param $appkey
 * @return string
 */
function MakeSign($arr,$appkey){
	//签名步骤一:按字典序排序参数,ksort()函数:对关联数组按照键名进行升序排序
	ksort($arr);
	$string = ToUrlParams($arr);
	//签名步骤二:在string后加入KEY
	$string = $string . "&key=".$appkey;
	//签名步骤三:MD5加密
	$string = md5($string);
	//签名步骤四:所有字符转为大写
	$result = strtoupper($string);
	return $result;
}
/**
 * 将参数进行拼接
 * @param $arr 要拼接的数组
 * @return string 拼接后得到的字符串
 */
function ToUrlParams($arr){
	$buff = "";
	foreach ($arr as $k => $v)
	{
		if($k != "sign" && $v != "" && !is_array($v)){
			$buff .= $k . "=" . $v . "&";
		}
	}
	//trim()函数:移除字符串两侧的空白字符或其他预定义字符
	$buff = trim($buff, "&");
	return $buff;
}
?>

下面是调起支付后回调页面的服务器处理代码:

<?php
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
//writelog($postStr);
//$pos = strpos($postStr, 'xml');
//simplexml_load_string()函数:把XML字符串载入对象中,如果失败,则返回false
$obj=simplexml_load_string($postStr,'SimpleXMLElement', LIBXML_NOCDATA);

$obj=json_decode(json_encode($obj), true);

$sign=$obj['sign'];
$orderno=$obj['out_trade_no']; 
$tradeno=$obj['transaction_id'];
$return_code = $obj['return_code'];
$return_msg = $obj['return_msg'];

if($return_code == 'SUCCESS'){
	$xmlstr="<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg><sign>
	<![CDATA[".$sign."]]></sign></xml>";
	//下面是我们根据项目需要而进行的处理
	echo $xmlstr;
	include_once('../common.php');
	$data = array( 
		"tradeNO"=>$tradeno,
		"payresult"=> 1,
		"paydate"=> $_SGLOBAL['timestamp'],
	);
	updatetable($_SC['tablepre'],"payorder",$data,"orderNO='".$orderno."'",0);
	$sql = "select * from ".$_SC['tablepre']."payorder where orderNO='$orderno'";
	$query = $_SGLOBAL['db']->query($sql);
	$payorder = $_SGLOBAL['db']->fetch_array($query);
	$money=$payorder['money'];
	$sql="update ".$_SC['tablepre']."user set money=money+$money where username='".$payorder['consignee']."'";
	$query = $_SGLOBAL['db']->query($sql);
	//记录充值记录
	$data=array(
		"uid"=> $payorder['payuserid'],
		"wishid"=> 0,
		"iotype"=> 1,
		"buytype"=> 9,
		"money"=> $money,
		"description"=> "微信充值".$money."元",
		"dateline"=> $_SGLOBAL['timestamp'],
	);
    inserttable($_SC['tablepre'],"userfinance", $data, 1 );
}else{
	$xmlstr="<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[".$return_msg."]]></return_msg></xml>";
	echo $xmlstr;
}

//日志记录
function logger($log_content)
{
    $max_size = 100000;
    $log_filename = "log.xml";
    if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);}
    file_put_contents($log_filename,$log_content."\r\n", FILE_APPEND);
}
exit;

?>

最后,贴出客户端接收服务端生成的签名prepay_id再进行二次签名并调起支付的主要代码:

Map<String,String> resultunifiedorder;
resultunifiedorder = decodeXml(prepayId);
//生成签名参数并发起支付请求
genPayReq();


public Map<String,String> decodeXml(String content) {

		try {
			Map<String, String> xml = new HashMap<String, String>();
			XmlPullParser parser = Xml.newPullParser();
			parser.setInput(new StringReader(content));
			int event = parser.getEventType();
			while (event != XmlPullParser.END_DOCUMENT) {

				String nodeName=parser.getName();
				switch (event) {
					case XmlPullParser.START_DOCUMENT:

						break;
					case XmlPullParser.START_TAG:

						if("xml".equals(nodeName)==false){
							xml.put(nodeName,parser.nextText());
						}
						break;
					case XmlPullParser.END_TAG:
						break;
				}
				event = parser.next();
			}
			return xml;
		} catch (Exception e) {
			Log.e("orion",e.toString());
		}
		return null;
	}
	
   //获取二次签名sign并调起微信支付
	private void genPayReq() {
		req.appId = Constants.APP_ID;
		req.partnerId = Constants.MCH_ID;
		req.prepayId = resultunifiedorder.get("prepay_id");
		req.packageValue = "Sign=WXPay";
		req.nonceStr = genNonceStr();
		req.timeStamp = String.valueOf(genTimeStamp());

		List<NameValuePair> signParams = new LinkedList<NameValuePair>();
		signParams.add(new BasicNameValuePair("appid", req.appId));
		signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
		signParams.add(new BasicNameValuePair("package", req.packageValue));
		signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
		signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
		signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));

		req.sign = genAppSign(signParams);
		sb.append("sign\n"+req.sign+"\n\n");	
		Log.e("orion++++++++++  ", signParams.toString());
		//发送请求调起微信支付
		msgApi.registerApp(Constants.APP_ID);
		msgApi.sendReq(req);
	}

在接收到prepay _id后,须对prepay_ id进行解码,最后再调用genPayReq()获取二次签名sign并调起微信支付。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值