微信支付支持多种支付方式:扫码支付、刷卡支付、APP支付、公众号支付。其中APP支付和公众号支付是APP和网站上使用最多的。前者集成在APP中,后者主要是为微信用户提供另一种支付方式(需要在微信内置浏览器中打开页面,然后调整微信支付)。同样,微信的APP支付和支付宝的APP支付也很简单:APP支付商户系统与微信支付系统的主要交互:第一步:用户在商户APP中选择商品,提交订单,选择微信支付.第二步:商户后台收到用户支付订单,调用微信支付统一下单接口。参见【统一下单API】。第三步:统一下单接口返回正常的prepay_id,然后根据签名规范重新生成签名,再将数据传输给APP。签名中涉及的字段有appId、partnerId、prepayId、nonceStr、timeStamp、package。注:包的取值格式为Sign=WXPay第四步:商户APP调用微信支付。第五步:商户后台收到付款通知。第六步:在商户后台查看支付结果。这里主要是后台工作(获取prepay_id,生成随机字符串nonceStr和时间戳timeStamp,appId和partnerId可以在后台管理中查看。)后台步骤也很简单,就是上面的步骤1和步骤2。获取prepayId:设置获取prepayId所需的参数。这里需要调用微信统一下单接口。这个过程,官方文档已经写的很详细了,包括要调用的接口API地址,需要传递的参数(必要参数和非必要参数),返回结果也写的很清楚。以下是我在实际项目开发中传入的参数。符号。签名相似,所有有签名的参数先按字典顺序排序。ksort($数据);然后用&连接{key}={value}形式的参数。$a=array();foreach($dataas$k=>$v){if((string)$v===''){继续;}$a[]="{$k}={$v}";}$a=内爆('&',$a);最后把&key={YourapiKey}放在一起,然后把整个字符串用MD5加密。$sign=strtoupper(md5($a));将拼好的数据以XML格式发送给微信,请求prepayId正确,就是转成XML格式再发送。不过这种XML格式很简单,只需要拼接一下:publicfunctionarrayToXml(array$data){$xml="";foreach($dataas$k=>$v){if(is_numeric($v)){$xml.="<{$k}>{$v}{$k}>";}else{$xml.="<{$k}>{$k}>";}}$xml.="";return$xml;}参数值可以用XML进行转义,CDATA标签用来表示数据没有被XML解析器解析。.然后请求统一下单API(url=https://api.mch.weixin.qq.com/pay/unifiedorder)$ch=curl_init();curl_setopt($ch,CURLOPT_TIMEOUT,30);curl_setopt($ch,CURLOPT_URL,$url);curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);curl_setopt($ch,CURLOPT_HEADER,FALSE);curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);curl_setopt($ch,CURLOPT_RETURNTRANSFER,真);ch,CURLOPT_POST,TRUE);curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);$response=curl_exec($ch);如果(!$response){thrownewException('CURLError:'.curl_errno($ch));}curl_close($ch);请求返回的数据也是XML格式。只需要处理转换成数组:publicfunctionxmlToArray($xml){returnjson_decode(json_encode(simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOCDATA)),true);}如果return中的return_code和result_codevalue均为SUCCESS,则返回交易类型trade_type和预付款交易会话标识prepayId。至此,我们就可以拿到prepayId了。将获取到的prepayId与其他参数拼接返回给APP。$params=array();//商家ID$params['appid']=$this->config->appId;//时间戳$params['timestamp']=''.time();//随机字符串$params['noncestr']=md5(uniqid(mt_rand(),true));//固定为'Sign=WXPay'$params['package']='Sign=WXPay';//Step3获取$params['prepayid']=$prepayId;//Partnerid$params['partnerid']=$this->config->partnerId;//step2生成的签名$params['sign']=$this->sign($params);微信APP支付,后台需要做的工作暂时到这里就结束了(因为支付成功后有异步通知商户,后面再说)jsapi支付下面是网页版的微信支付(公司项目在微信浏览器,选择微信支付后,在微信中调用微信支付),调用jsapi进行支付。但是这里有两个坑:1:支付时出现appid和openid不匹配错误的原因很简单,就是支付时获取的openid不属于支付商户。这个openid就是商户对应appid下微信用户的唯一标识。也就是说,必须根据支付商户的appid获取用户的openid。由于业务逻辑需要,项目中微信登录使用的公众号A与支付使用的公众号B不同(其实也不同于开放平台APP支付使用的appId)。获取unionid是一致的,openid不是!一!样本!的!所以在获取openid的时候,需要使用当前支付使用的appid来请求用户的openid。同时请求openid后的回调也必须是支付商户后台设置的回调地址,否则会报redirect_uri参数错误错误。坑2:参数名大小写不一致。↑APP支付参数↑网页支付参数仔细看横线。没错,app里面参数的key都是小写的,web支付里面的key都是驼峰命名的。而且签名方法signType是必须的,签名字段也改成了paySign,其中package的值也不同,APP支付是固定值,web支付是prepayId,这个也要注意。当然官方文档也很详细,但是需要仔细观察(所以,直接copyrequireditems2333是最稳妥的)。获取到所有参数后,就可以在页面发起微信支付请求了。代码可以直接使用官方js代码以上方法判断前端返回,微信团队郑重提醒:res.err_msg会在用户支付成功后返回ok,但不保证绝对可靠。}));}if(typeofWeixinJSBridge=="undefined"){if(document.addEventListener){document.addEventListener('WeixinJSBridgeReady',onBridgeReady,false);}elseif(document.attachEvent){document.attachEvent('WeixinJSBridgeReady',onBridgeReady);document.attachEvent('onWeixinJSBridgeReady',onBridgeReady);}}else{onBridgeReady();}其中YOUR_PARAMS是转换成json格式直接渲染到页面的参数。如果参数正确,则可以成功激活支付窗口。陷阱三:APP支付和jsapi支付不是同一个号码。APP支付在开放平台申请,appId和apiKey不同。jsapi支付的本质是公众号支付,通过在公众平台申请获得。所以,在这里,你需要注意。重点来了,能体现后台重要性的地方终于来了---支付结果异步通知的官方文档也写的很详细(不得不说微信的开发文档真的很清楚。很容易找到。没有详细的步骤区分)。首先要声明的是:异步通知的URL必须是公网可访问的,并且不能带参数。换句话说,http://domain.com/payment/wxp...可以,但像http://domain.com/payment/not...这样的URL是不可接受的。如果要实现这种效果,需要重写服务端(Nginx、Apache),或者手动修改notify.php中$_GET中的参数。返回的数据都是一致的:此时商户后台可以拿到这些异步通知的数据进行简单的校验,然后在商户中修改相应订单的支付状态。检查返回码是否成功$d=$this->xmlToArray(file_get_contents('php://input'));if(empty($d)){thrownewException(__METHOD__);}if($d['return_code']!='SUCCESS'){thrownewException($d['return_msg']);}if($d['result_code']!='SUCCESS'){thrownewException("[{$d['err_code']}]{$d['err_code_des']}");}检查返回的数据和请求prepayId时处理数据类似,先取出签名sign,再取出签名,对字典进行排序到{key}={value},在末尾加上&key={apiKey},得到要验证的字符串。最后将待验证字符串用MD5加密,并与签名进行比对。如果一致,则verify验证成功,支付成功,然后在后台进行相应的操作。if(!$this->verify($d)){thrownewException("Invalidsignature");}//验证函数if(empty($d['sign'])){returnfalse;}$sign=$d['sign'];取消设置($d['sign']);返回$sign==$this->sign($d);微信退款支付了会有退款。微信的退款操作也很简单,而且退款速度很快,在测试中基本是即时退款。但退款有注意事项:交易时间超过一年的订单不能提交退款;微信支付退款支持单笔多次退款,多次退款需要提交商户订单号和原支付订单设置的不同退款订单号。退款总额不能超过用户实际支付的金额。退款失败后重新提交,请勿更改退款单号,请使用原商户退款单号。退款申请需要证明。【证书获取方式:】在微信支付接口中,涉及资金回滚的接口会使用商户证书,包括退款和注销接口。商户申请微信支付成功并收到相应邮件后,可按照提示下载API证书,或通过以下路径下载:微信商户平台(pay.weixin.qq.com)-->账户中心-->账户设置-->API安全-->证书下载。微信退款程序流程:设置退款时的参数。请求参数为:appid:公众号IDmch_id:商户号nonce_str:随机字符串sign:签名transaction_id/out_trade_no:微信订单号/商户订单号,两者取其一即可。out_refund_no:商户退款订单号(商户自行生成的唯一标识)total_fee:订单金额(美分)refund_fee:退款金额(美分),退款金额不能大于订单金额。op_user_id:运营商账号,默认为商户号签名或老规矩(默认为MD5),先将所有参数整理成字典,然后用$key=$value形式的&字符拼接成一个string,最后放在一起&key=YOUR_APIKEY待签名的字符串可以用MD5加密。将参数列表转换为XML格式。发送退款请求。退款申请需要携带微信下载的凭证。请确保不能从外部网络直接访问证书存储路径。解析请求结果。当返回结果中return_code和result_code均为SUCCESS时,退款申请成功。更多返回结果,请移步官网末尾。微信支付的官方开发文档其实写的很详细。传递的参数,返回结果,判断是否成功,都写的很好。不过发展的逻辑过程需要自己慢慢摸索。理清了思路之后,其实开发还是很快的。但是在开发微信支付的时候需要小心,所有涉及到的微信后台提供的数据都需要小心保存(比如AppSecret,忘记了只能重新设置。)祝开发顺利过程。