[置顶] 实现APP支付QQ,微信,支付宝三方的后端服务------php实现微信APP支付
2018-02-12 14:34
816 查看
接上篇支付宝支付,下面我这边讲的是微信支付:
下面简单介绍下微信App支付后端的实现(这边是用php实现的):一、 一些琐碎的申请和设置的方式就不说明了,这些微信上都有说,但相比于支付宝吗,微信和QQ的文档相比差之千里,太简单太low了,并且没有SDKDEMO,但小伙伴们不用担心,下面是我这边封装好的一个类,可供直接使用,都有标注说明
一、封装好的微信调用类库:(这个不管是app支付还是其他支付都可共用)
<?php /** * Created by PhpStorm. * User: wyb * Date: 2017/3/29 * Time: 10:17 */ class wechatAppPay { //接口API URL前缀 const API_URL_PREFIX = 'https://api.mch.weixin.qq.com'; //下单地址URL const UNIFIEDORDER_URL = "/pay/unifiedorder"; //查询订单URL const ORDERQUERY_URL = "/pay/orderquery"; //关闭订单URL const CLOSEORDER_URL = "/pay/closeorder"; //公众账号ID private $wxappid; private $appid; //商户号 private $mch_id ; //随机字符串 private $nonce_str; //签名 private $sign; //商品描述 private $body; //商户订单号 private $out_trade_no; //支付总金额 private $total_fee; //终端IP private $spbill_create_ip; //支付结果回调通知地址 private $notify_url='http://apps.ifeimo.com/Sysj218/Recharge/wxpayNotify'; //不能写固定于该文件内,后续变更为外部传入 //交易类型 private $trade_type; //支付密钥 private $key='269F02392183A8FB13E11A752E5E8FCA'; //证书路径 private $SSLCERT_PATH; private $SSLKEY_PATH; //所有参数 private $params = array(); public function __construct($wxappid,$mch_id) { $this->appid = $wxappid; $this->mch_id = $mch_id; } /** * 下单方法 * @param $params 下单参数 */ public function unifiedOrder( $params ){ $this->body = $params['body']; $this->out_trade_no = $params['out_trade_no']; $this->total_fee = $params['total_fee']; $this->trade_type = $params['trade_type']; $this->nonce_str = $this->genRandomString(); $this->spbill_create_ip = $_SERVER['REMOTE_ADDR']; $this->params['appid'] = $this->appid; $this->params['mch_id'] = $this->mch_id; $this->params['nonce_str'] = $this->nonce_str; $this->params['body'] = $this->body; $this->params['out_trade_no'] = $this->out_trade_no; $this->params['total_fee'] = $this->total_fee; $this->params['spbill_create_ip'] = $this->spbill_create_ip; $this->params['notify_url'] = $params['notify_url'] ? $params['notify_url'] : $this->notify_url; $this->params['trade_type'] = $this->trade_type; //获取签名数据 $this->sign = $this->MakeSign( $this->params ); $this->params['sign'] = $this->sign; $xml = $this->data_to_xml($this->params); $response = $this->postXmlCurl($xml, self::API_URL_PREFIX.self::UNIFIEDORDER_URL); if( !$response ){ return false; } $result = $this->xml_to_data( $response ); if( !empty($result['result_code']) && !empty($result['err_code']) ){ $result['err_msg'] = $this->error_code( $result['err_code'] ); } return $result; } /** * 查询订单信息 * @param $out_trade_no 订单号 * @return array */ public function orderQuery( $out_trade_no ){ $this->params['appid'] = $this->appid; $this->params['mch_id'] = $this->mch_id; $this->params['nonce_str'] = $this->genRandomString(); $this->params['out_trade_no'] = $out_trade_no; //获取签名数据 $this->sign = $this->MakeSign( $this->params ); $this->params['sign'] = $this->sign; $xml = $this->data_to_xml($this->params); $response = $this->postXmlCurl($xml, self::API_URL_PREFIX.self::ORDERQUERY_URL); if( !$response ){ return false; } $result = $this->xml_to_data( $response ); if( !empty($result['result_code']) && !empty($result['err_code']) ){ $result['err_msg'] = $this->error_code( $result['err_code'] ); } return $result; } /** * 关闭订单 * @param $out_trade_no 订单号 * @return array */ public function closeOrder( $out_trade_no ){ $this->params['appid'] = $this->appid; $this->params['mch_id'] = $this->mch_id; $this->params['nonce_str'] = $this->genRandomString(); $this->params['out_trade_no'] = $out_trade_no; //获取签名数据 $this->sign = $this->MakeSign( $this->params ); $this->params['sign'] = $this->sign; $xml = $this->data_to_xml($this->params); $response = $this->postXmlCurl($xml, self::API_URL_PREFIX.self::CLOSEORDER_URL); if( !$response ){ return false; } $result = $this->xml_to_data( $response ); return $result; } /** * * 获取支付结果通知数据 * return array */ public function getNotifyData(){ //获取通知的数据 $xml = $GLOBALS['HTTP_RAW_POST_DATA']; $data = array(); if( empty($xml) ){ return false; } $data = $this->xml_to_data( $xml ); if( !empty($data['return_code']) ){ if( $data['return_code'] == 'FAIL' ){ return false; } } return $data; } /** * 接收通知成功后应答输出XML数据 * @param string $xml */ public function replyNotify(){ $data['return_code'] = 'SUCCESS'; $data['return_msg'] = 'OK'; $xml = $this->data_to_xml( $data ); echo $xml; die(); } /** * 生成APP端支付参数 * @param $prepayid 预支付id */ public function getAppPayParams( $prepayid ){ $data['appid'] = $this->appid;//注意 $sign_array['appid'] 里的参数名必须是appid $data['partnerid'] = $this->mch_id;//注意 $sign_array['partnerid'] 里的参数名必须是partnerid $data['prepayid'] = $prepayid;//注意 $sign_array['prepayid'] 里的参数名必须是prepayid $data['package'] = 'Sign=WXPay';//注意 $sign_array['package'] 里的参数名必须是package $data['noncestr'] = $this->genRandomString();//注意 $sign_array['noncestr'] 里的参数名必须是noncestr $data['timestamp'] = time(); $data['sign'] = $this->MakeSign( $data ); $info=[ 'alipay'=>'', 'appId'=>$data['appid'],//QQ或者微信的应用ID 'bargainorId'=>$data['partnerid'],//QQ商户ID 'tokenId'=> $data['prepayid'],//QQ预备支付ID 'nonce'=>$data['noncestr'],//QQ随机字段串 'timestamp'=>$data['timestamp'],//时间戳 'package'=> $data['package'],//微信 'pubAcc'=>'',//微信 'sign'=>$data['sign'], ]; return $info; } /** * 生成签名 * @return 签名 */ public function MakeSign( $params ){ //签名步骤一:按字典序排序数组参数 ksort($params); $string = $this->ToUrlParams($params); //签名步骤二:在string后加入KEY $string = $string . "&key=".$this->key; //签名步骤三:MD5加密 $string = md5($string); //签名步骤四:所有字符转为大写 $result = strtoupper($string); return $result; } /** * 将参数拼接为url: key=value&key=value * @param $params * @return string */ public function ToUrlParams( $params ){ $string = ''; if( !empty($params) ){ $array = array(); foreach( $params as $key => $value ){ $array[] = $key.'='.$value; } $string = implode("&",$array); } return $string; } /** * 输出xml字符 * @param $params 参数名称 * return string 返回组装的xml **/ public function data_to_xml( $params ){ if(!is_array($params)|| count($params) <= 0) { return false; } $xml = "<xml>"; foreach ($params as $key=>$val) { if (is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return $xml; } /** * 将xml转为array * @param string $xml * return array */ public function xml_to_data($xml){ if(!$xml){ return false; } //将XML转为array //禁止引用外部xml实体 libxml_disable_entity_loader(true); $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $data; } /** * 获取毫秒级别的时间戳 */ private static function getMillisecond(){ //获取毫秒的时间戳 $time = explode ( " ", microtime () ); $time = $time[1] . ($time[0] * 1000); $time2 = explode( ".", $time ); $time = $time2[0]; return $time; } /** * 产生一个指定长度的随机字符串,并返回给用户 * @param type $len 产生字符串的长度 * @return string 随机字符串 */ private function genRandomString($len = 32) { $chars = array( "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ); $charsLen = count($chars) - 1; // 将数组打乱 shuffle($chars); $output = ""; for ($i = 0; $i < $len; $i++) { $output .= $chars[mt_rand(0, $charsLen)]; } return $output; } /** * 以post方式提交xml到对应的接口url * * @param string $xml 需要post的xml数据 * @param string $url url * @param bool $useCert 是否需要证书,默认不需要 * @param int $second url执行超时时间,默认30s * @throws WxPayException */ private 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,FALSE); 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, WxPayConfig::SSLCERT_PATH); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); //curl_setopt($ch,CURLOPT_SSLKEY, WxPayConfig::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); return false; } } /** * 错误代码 * @param $code 服务器输出的错误代码 * return string */ public function error_code( $code ){ $errList = array( 'NOAUTH' => '商户未开通此接口权限', 'NOTENOUGH' => '用户帐号余额不足', 'ORDERNOTEXIST' => '订单号不存在', 'ORDERPAID' => '商户订单已支付,无需重复操作', 'ORDERCLOSED' => '当前订单已关闭,无法支付', 'SYSTEMERROR' => '系统错误!系统超时', 'APPID_NOT_EXIST' => '参数中缺少APPID', 'MCHID_NOT_EXIST' => '参数中缺少MCHID', 'APPID_MCHID_NOT_MATCH' => 'appid和mch_id不匹配', 'LACK_PARAMS' => '缺少必要的请求参数', 'OUT_TRADE_NO_USED' => '同一笔交易不能多次提交', 'SIGNERROR' => '参数签名结果不正确', 'XML_FORMAT_ERROR' => 'XML格式错误', 'REQUIRE_POST_METHOD' => '未使用post传递参数 ', 'POST_DATA_EMPTY' => 'post数据不能为空', 'NOT_UTF8' => '未使用指定编码格式', ); if( array_key_exists( $code , $errList ) ){ return $errList[$code]; } } }
二、封装好的微信调用类库的工具类:
<?php /** * @encoding UTF-8 * @author wyb * @datetime 2017-4-16 11:41:09 * @Description 微信APP支付控制器,不对外访问 */ namespace Pay\Controller; use Think\Controller; /** * @name * Class AlipayAppPayController */ class WechatAppPayController extends Controller { //这里的是因为公司有多个产品,所以根据不同产品选择不同的appId,可放在配置文件方便管理 private $appidByTarget = [ 'app标识' => 'wxxcxcxzcxcvxxxccc', 'app标识' => 'wxxcxcxzcxcvxxxccc', 'app标识' => 'wxxcxcxzcxcvxxxccc', 'app标识' => 'wxxcxcxzcxcvxxxccc', 'app标识' => 'wxxcxcxzcxcvxxxccc', 'app标识' => 'wxxcxcxzcxcvxxxccc', ]; //这里的是因为公司有多个产品,所以根据不同产品选择不同的商户ID,可放在配置文件方便管理 private $mchIdByTarget = [ 'app标识' => '1234223423, 'app标识' => '1234223423', 'app标识' => '1234223423', 'app标识' => '1234223423', 'app标识' => '1234223423', 'app标识' => '1234223423' ]; /** * 传入订单数据,进行整理、签名后,返回前端APP支付调起SDK信息 * @param array $order 待支付的订单信息,数组中的必要信息如下: * $order['id'] : 订单ID * $order['price'] : 实付金额,单位:元 * $order['notifyUrl'] : 支付端异步通知地址,用于接受订单的支付结果 * $order['target'] : 支付请求的来源,根据不同的来源,需要使用不同的支付账号信息 * $order['description'] : 订单介绍 * $order['time'] : 订单提交时间 */ public function getCallSDKInfo($order){ //做简单的参数检查 if(!$order || !is_array($order) || !$order['id'] || !$order['price'] || !$order['notifyUrl'] || !$order['target']){ return false; } $wxappid = $this->appidByTarget[$order['target']];//应用ID 字符串 $mch_id = $this->mchIdByTarget[$order['target']]; Vendor('wxpay.wxpay'); $wechat = new \wechatAppPay($wxappid,$mch_id); $params = [ 'body' => $order['description'], //必填项 商品描述 'out_trade_no' => $order['id'], //商家订单ID 'total_fee' => ($order['price']*100), //必填项 订单金额 单位为分 'trade_type' => 'APP', //必填项 交易类型固定写 APP 'time_start' => date('yyyyMMddHHmmss',$order['add_time']), //可支付有效时间,超过则无效,需要重新请求 'time_expire' => date('yyyyMMddHHmmss',($order['add_time'] + 1800)), //可支付有效时间,超过则无效,需要重新请求 'notify_url' => $order['notifyUrl'], ]; $result = $wechat->unifiedOrder($params); $data = $wechat->getAppPayParams($result['prepay_id']); return $data; } /** * 微信查询支付结果 * @param $data */ public function enquiriesOrderInfo($data) { $wxappid = $this->appidByTarget[$data['target']];//应用ID 字符串 $mch_id = $this->mchIdByTarget[$data['target']]; Vendor('wxpay.wxpay'); $wechat = new \wechatAppPay($wxappid,$mch_id); $result = $wechat->orderQuery($data['out_trade_no']); return $result; } }
三、接下来你就可以根据你的相关产品订单信息进行调用相应的类方法,下面我就简单的写一下:
<?php /** * 根据相应的场景而写的支付接口 * Created by PhpStorm. * User: wyb * Date: 2017/6/1 * Time: 13:51 */ class productPayController extents Controller{ public function paymentAction(){ IS_POST ||$this->returnError(); //判断是否是POST $parameters = I('post.'); //接收所以参数,相应的参数校验我这里就不写,如果有问题可以给我留言反馈 $wechatPay = new WechatAppPayController();//实例化微信的APP控制器类 $order['notifyUrl'] = 'http://xxxxxxxxxxxxxxx;//微信的回调接口 $data = $wechatPay->getCallSDKInfo($order);//调用微信生成预订单并整理好返回验签参数,这里调用上面的类封装的方法 return $data //这里可以根据你们前端定义接受什么数据类型进行转化 } }
php后端实现支付宝APP支付,请点击这里:GO
注:这个就是我php后端实现支付的业务的相关代码,若有什么问题反馈请指出,谢谢,(这里并附上我自己的博客地址:blog.taobaoroom.cn,若有什么问题可根据博客上赋有的QQ群地址联系我哦!!
相关文章推荐
- [置顶] 实现APP支付QQ,微信,支付宝三方的后端服务------php实现支付宝APP支付
- [置顶] 实现APP支付QQ,微信,支付宝三方的后端服务------php实现QQAPP支付
- js实现微信/QQ直接跳转到支付宝APP打开口令领红包功能
- PHP实现QQ、微信和支付宝三合一收款码实例代码
- PHP 实现手机端APP支付宝支付功能
- 开源!js实现微信/QQ直接跳转到支付宝APP打开口令领红包
- 梦行扫码付(收银台条码支付 微信钱包条码支付 支付宝二维码支付 手机APP钱包支付 PHP扫码支付 )
- iOS调起微信,qq,支付宝app支付总结
- [置顶] 支付宝APP支付-php后台生成请求参数
- php实现微信H5支付开发记录(非微信浏览器)
- C#+Hybrid App(Android)实现微信APP支付
- iOS app被拒------iOS 提交应用到 APP Store 因包含微信和支付宝支付被拒
- php 支付宝App支付服务端操作
- JAVA实现微信App支付(二)
- 微信扫码支付,扫商户二维码后,输入金额支付 php源代码下载 类似闪惠、到店付功能实现教程和源代码
- 关于微信的APP支付、公众号(服务号)支付,商户问题
- 支付宝pc端支付接入PHP实现
- [置顶] Android支付宝-2016最新版支付宝,实现支付功能
- [置顶] Android仿微信APP实现源码
- 支付宝app支付后端(java)