zoukankan      html  css  js  c++  java
  • 【微信支付】退款


      微信支付文档申请退款的详细介绍,建议大家先把文档看一遍,然后有什么不明白的再百度。这里记录的是我用php进行微信支付退款

    1. 下载商户证书

      登录上商户平台,依次【账户中心】-->【账户设置】-->【API安全】-->【证书下载】,解压,把apiclient_cert.pem和apiclient_key.pem两个文件放到项目目录中,分别用常量SSLCERT_PATHSSLKEY_PATH表示文件路径。

    	define(SSLCERT_PATH, "apiclient_cert.pem的路径");
    	define(SSLKEY_PATH, "apiclient_key.pem的路径");
    

    2. 组装参数

    	$params = array(
    		'out_trade_no'  =>  $out_trade_no,	//商户订单号
    		'total_fee'     =>  $total_fee,   	//订单总金额,以分为单位
    		'refund_fee'    =>  $refund_fee,    //退款金额,以分为单位
    		'out_refund_no' =>  $mch_id.  date("YmdHis"),
    		'op_user_id'    =>  $mch_id,		//商户Id
    		'appid'         =>  $appId,			//AppId
    		'mch_id'        =>  $mch_id,		
    		'nonce_str'     =>  getNonceStr(),//生成随机字符串
    	);
    	//生成签名
    	$params['sign'] = makeSign($params, $key);	//$key微信支付Key
    	//转为XML格式
    	$xml = toXml($params);
    	
    	/***************工具函数***************/
    	/**
    	 * 生成指定长度的随机字符串
    	 */
    	function getNonceStr($length = 32){
    		$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    		$str ="";
    		for ( $i = 0; $i < $length; $i++ )  {
    			$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
    		}
    		return $str;
    	}
    	
    	/**
    	 * 生成签名
    	 * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
    	 */
    	private function makeSign($values, $key)
    	{
    		//签名步骤一:按字典序排序参数
    		ksort($values);
    		$string = $this->toUrlParams($values);
    		//签名步骤二:在string后加入KEY
    		$string = $string . "&key=".$key;
    		//签名步骤三:MD5加密
    		$string = md5($string);
    		//签名步骤四:所有字符转为大写
    		$result = strtoupper($string);
    		return $result;
    	}
    	/**
    	 * 格式化参数格式化成url参数
    	 */
    	function toUrlParams($values){
    		$buff = "";
    		foreach ($values as $k => $v){
    			if($k != "sign" && $v != "" && !is_array($v)){
    				$buff .= $k . "=" . $v . "&";
    			}
    		}
    		$buff = trim($buff, "&");
    		return $buff;
    	}
    	/**
    	 * 输出xml字符
    	 * @throws WxPayException
    	 **/
    	function toXml($values){
    		if(!is_array($values) || count($values) <= 0){
    			throw new WxPayException("数组数据异常!");
    		}
    
    		$xml = "<xml>";
    		foreach ($values as $key=>$val) {
    			if (is_numeric($val)){
    				$xml.="<".$key.">".$val."</".$key.">";
    			}else{
    				$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
    			}
    		}
    		$xml.="</xml>";
    		return $xml;
    	}
    

    3. 发送HTTPS请求

    	$url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    	$response = postXmlCurl($xml, $url, true, 6);
    	
    	/**
    	 * 以post方式提交xml到对应的接口url
    	 *
    	 * @param string $xml  需要post的xml数据
    	 * @param string $url  url
    	 * @param bool $useCert 是否需要证书,默认不需要
    	 * @param int $second   url执行超时时间,默认30s
    	 * @throws Exception
    	 */
    	function postXmlCurl($xml, $url, $useCert = false, $second = 30) {
    		$ch = curl_init();
    		//设置超时
    		curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    
    		curl_setopt($ch,CURLOPT_URL, $url);
    		curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
    		curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
    		//设置header
    		curl_setopt($ch, CURLOPT_HEADER, FALSE);
    		//要求结果为字符串且输出到屏幕上
    		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    
    		if($useCert == true){
    			//设置证书
    			//使用证书:cert 与 key 分别属于两个.pem文件
    			curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
    			curl_setopt($ch,CURLOPT_SSLCERT, SSLCERT_PATH);
    			curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
    			curl_setopt($ch,CURLOPT_SSLKEY, SSLKEY_PATH);
    		}
    		//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);
    			curl_close($ch);
    			throw new Exception("curl出错,错误码:$error");
    		}
    	}
    

    4. 接收HTTPS响应数据

    	//Https请求返回的数据是XML格式的,要先转为数组
    	$result = fromXml($response);
    	if($result['return_code'] == 'SUCCESS'){
    		//检查签名
    		checkSign($result, $Key);
    	}
    	
    	/**
    	 * xml数据转为数组
    	 */
    	function fromXml($xml){
    		if(!$xml){
    			throw new Exception("xml数据异常!");
    		}
    		//将XML转为array
    		//禁止引用外部xml实体
    		libxml_disable_entity_loader(true);
    		$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    		return $values;
    	}
    	/**
    	 * 检查返回数据的签名
    	 */
    	function checkSign($values, $key){
    		//fix异常
    		if(!array_key_exists('sign', $values)){
    			throw new Exception("签名错误!");
    		}
    
    		$sign = makeSign($values, $key);
    		if($values['sign'] == $sign){
    			return true;
    		}
    		throw new Exception("签名错误!");
    	}
    

    总结

      微信支付退款和其他普通的API请求一样,只不过是多了证书而已。

  • 相关阅读:
    JS继承
    Liunx 常用命令2
    团队作业(四)
    OpenEuler树莓派基础实验(无树莓派)
    thread同步测试
    团队作业(三)
    实验二测试
    浅谈JWT。
    monolog使用 brady
    Blazor Server获取Token访问外部Web Api
  • 原文地址:https://www.cnblogs.com/lhat/p/6770671.html
Copyright © 2011-2022 走看看