Wechat支付,使用php实现快钱支付功用_php技艺_脚本

2019-11-24 作者:yzc216.com官网   |   浏览(160)

本项目用zend framework框架实现的modules/default/controllers/IndexController.phpIndexController.php复制代码 代码如下:

引言

秋高气爽,天气转凉,正是学习工作做的好时候。(~ ̄▽ ̄)~~(~ ̄▽ ̄)~

我是个phper最近在写微信支付(APP支付),微信给的官方文档并不是很详细也没有dome之类的代码啥的(对于新手来说比较麻烦),本人是新手以前也没写过支付,踩了好多坑,所以想写篇文章给没写过支付的新手几个建议。

view->BillRequest = new Application_Model_BillRequest;Zend_Debug::dump($this->view->BillRequest);exit; } //bgUrl地址指向这里 public function receiveAction() { //receive数据库设计 /*用$MockReceive数组模拟 * $MockReceive = array(); * $MockReceive['id']主键; * $MockReceive['orderId']商户订单号; * $MockReceive['receiveTime']接受时间; * $MockReceive['queryString']http_build_encode; * $MockReceive['dealId']快钱交易号; * $MockReceive['bankDealId']银行交易号; * $MockReceive['payResult']处理结果10:支付成功;11:支付失败; * $MockReceive['dealTime']快钱交易时间; * $MockReceive['payAmount']订单实际支付金额; * $MockReceive['fee']费用; * $MockReceive['errCode']错误代码; */ /*$_REQUEST是快钱那边返回来的数据 * merchantAcctId人民币账号,与提交订单时的块钱账号保持一致。 * version网关版本,固定值:v2.0,与提交订单时的网关版本号保持一致。 * language网页显示语言种类,1中文显示,与提交订单时的网页显示语言种类保持一致 * signType签名类型,4PKI签名,与提交订单时的签名类型保持一致 * payType支付方式,00全部,与提交订单时的支付方式保持一致 * bankId银行代码 * orderId商户订单号,与提交订单时的商户订单号保持一致 * orderTime商户订单提交时间,与提交订单时的商户订单提交时间保持一致 * orderAmount商户订单金额,与提交订单时的商户订单金额保持一致。 * dealId快钱交易号 * bankDealId银行交易号 * dealTime快钱交易时间 * payAmount订单实际支付金额 * fee费用 * ext1扩展字段1,与提交订单时的扩展字段1保持一致 * ext2扩展字段2,与提交订单时的扩展字段2保持一致 * payResult处理结果 10:支付成功;11:支付失败 * errCode错误代码,可为空 * signMsg签名字符串 */$BillResponse = new Application_Model_BillResponse;//$BillResponse->checkSignMsg验证签名字符串是否正确,防止bug漏洞等if($BillResponse->checkSignMsg){//判断订单支付是否成功if($BillResponse->isSuccess){//返回给快钱,快钱会按照redirecturl地址跳到新页面,这里是成功页面return "1 "1 "1; } //redirecturl地址 //成功 public function success() { } //失败 public function fail() { }}modules/default/views/scripts/index/index.phtml 代码如下:

准备工作

这首先呢你得注册个开放平台以及商户平台的账号吧,注册完成后呢你会收到一封微信里邮件里面有你的商户号等信息,注册这俩账号完你会拥有商户号,appid,appkey等需要的东西。

BillRequest;?>

开发流程

准备完成后我们来看一下支付的大体流程

商户APP应用与微信支付主要的交互说明:

1.用户在商户APP应用(移动端)中选择商品提交订单,支付方式选择微信支付。

2.商户APP应用(后台)收到用户支付订单,调用微信支付中的统一下单接口。

3.商户APP应用(后台)统一下单接口调用成功后,返回的数据中有我们需要的prepay_id,按照签名规范重新生成一个签名,然后把这个重新生成的签名及app需要的数据返回给商户APP应用(移动端)。

4.商户APP应用(移动端)收到商户APP应用(后台)的数据调起微信支付,用户进行支付

5.商户APP应用(后台)的回调接口会收到微信发来的支付结果通知

6.商户APP应用(后台)查询支付结果通知

附:1,4是移动端所要做的事情,2,3,5是我们PHP服务端后台要做的6也是,但我没做,这个根据情况而定如果需要的话就做

models/BillRequest.phpBillRequest.php复制代码 代码如下:

开始干活

merchantAcctId = "1001011111101";

步骤1由移动端完成

//服务器接收支付结果的后台地址,该参数务必填写,绝对路径//不能为空。$this->bgUrl

" = 'TOLPC'.sprintf(" d", $MockOrder['orderId']);//订单金额,金额以“分”为单位,商户测试以1分测试即可,切勿以大金额测试,该参数必填//不能为空$this->orderAmount =$MockOrder['orderAmount'];//订单提交时间,格式:yyyyMMddHHmmss,如:20071117020101//不能为空。$this->orderTime = date("YmdHis", $MockOrder['orderTime']);//支付人姓名,可以为空。$this->payerName= ""; //支付人联系类型,1 代表电子邮件方式;2 代表手机联系方式。可以为空。$this->payerContactType = "";//支付人联系方式,与payerContactType设置对应,payerContactType为1,则填写邮箱地址;payerContactType为2,则填写手机号码。可以为空。$this->payerContact = "";//商品名称,可以为空。$this->productName= "TOLPC";//商品数量,可以为空。$this->productNum = "1";//商品代码,可以为空。$this->productId =

步骤2.调用同一下单接口:

先要做的是流程中的第二步,调用同一下单接口。官方文档里说了请求的地址与参数,其中有一些是必填参数,有

appid

应用ID 固定值,你申请账号时就给你了

mch_id

商户号 固定值,你申请账号时就给你了

nonce_str

随机字符串 这个是自己写的要求不能长于32位,参见官方给的[标准][8]

sign

签名 我们把这个签名叫做第一次签名,注意这个是个坑,得自己写了,官方只给了如何写的[标准][9]没有代码,这个就比较蛋疼了。好多人掉进这个坑里,写的签名函数不对,老是出错。但不用担心我在文章的最后会贴出代码里面有签名函数直接调用就可以了。(注意看我写的函数使用规则)

body

商品描述 固定值 商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。

out_trade_no

商户订单号 我们自己定义的订单号,32个字符内、可包含字母。

total_fee

总金额 这个就是你要支付的钱数了,由前端返回。注意一下这里的货币单位是分!

spbill_create_ip

终端IP 这个用户的IP地址,写个取IP地址的函数一调用就行

notify_url

通知地址 这又是一个坑,好多人不理解是干嘛的,这是接收微信支付异步通知回调地址用的,通知url必须为直接可访问的url,不能携带参数! 也可以这样理解,这个是给微信支付的接口,微信来调用的接口,微信调这接口干嘛用呢?就是告诉你用户付款成功啦或者用户付款失败了,然后你就可以在这个接口里通过微信给你返回的信息来做逻辑处理了。

trade_type

固定值  写 “APP” 因为咱写的是APP支付嘛,所以就填APP。

好了就是这些必选参数了,剩下就可以自己选择是否要用的参数了根据自己情况而定。

参数选完了就要发送参数了呗,如何发呢?

我们来调用wechatAppPay类中的unifiedOrder()函数。

啊哈啥!!!!!!??????

(⊙o⊙)?(⊙o⊙)?(⊙o⊙)?(⊙o⊙)?(⊙o⊙)?

wechatAppPay类???unifiedOrder()函数???

对就这这俩东西,不要惊讶,不要着急看最后有代码,有这个类,有代码的O(∩_∩)O哈哈~,

你只需在你的项目中加载这个类就可以调用这个方法了!不要崇拜我( ╯▽╰)(因为这个类不是我写的我也忘了从哪找的了,我从百度搜的然后整理的做了些改动╮(╯▽╰)╭ -_-|||-_-|||-_-!好吧好吧好吧没做改动,只是加了点注释而已,感谢写这个类的大神谢谢O(∩_∩)O谢谢O(∩_∩)O谢谢)

好了抽完疯了,开是干正事!

我们先来new下wechatAppPay类

$wxappid          = 'wx0000000000000';//应用ID 字符串

$mch_id            = '1000000000';//商户号 字符串

$notify_url        = ' 字符串

$wxkey            = '00000000000000000000000';//这个是在商户中心设置的那个值用来生成签名时保证安全的 字符串

$this->wechatAppPay = new wechatAppPay($wxappid, $mch_id, $notify_url, $wxkey);

调用wechatAppPay类中的unifiedOrder()函数。unifiedOrder()需要的参数是个数组我们定义为$params

$params                    = array();

$params['body']            = 'APP-在线支付';      //必填项 商品描述

$params['out_trade_no']    =  time()."$member";  //必填项 自定义的订单号

$params['total_fee']        = ($money*100);      //必填项 订单金额 单位为分所以要*100

$params['trade_type']      = 'APP';              //必填项 交易类型固定写  APP

$params['根据自己情况定的值'] = "根据自己情况定的值" //非必填项 根据自己情况定的值 这个可有好多个可以参看开发文档中的参数

$result = $this->wechatAppPay->unifiedOrder( $params );

注:如果你加了$params['根据自己情况定的值'] wechatAppPay类里要做相应的改动,文章的最后有代码,你一看代码就明白了

现在$result就是我们调用统一下单接口返回的数据了,这个$resutl通过unifiedOrder()函数的处理已经把xml格式变成数组了。$result 里有return_code,return_msg,appid,mch_id,nonce_str,sign,result_code,prepay_id,trade_type。这里面就用一个prepay_id(预支付交易会话ID),其他都不重要了

$MockOrder['ets_license'];//商品描述,可以为空。$this->productDesc

"";//支付方式,一般为00,代表所有的支付方式。如果是银行直连商户,该值为10,必填//不能为空$this->payType = "00";//编码方式,1代表 UTF-8; 2 代表 GBK; 3代表 GB2312 默认为1,该参数必填//不能为空$this->inputCharset = "1";//网关版本,固定值:v2.0,该参数必填//不能为空$this->version =

步骤2完毕

"v2.0";//语言种类,1代表中文显示,2代表英文显示。默认为1,该参数必填//不能为空$this->language

"1";//签名类型,该值为4,代表PKI加密方式,该参数必填//不能为空$this->signType

步骤3 把数据返回给商户APP应用(移动端)调起支付接口

现在我们要把调用统一下单接口返回的数据$resutl里的几个值返回给移动端

那几个值呢?这几个:

appid

应用ID 这个是固定的 可以自己写也可以从$resutl里拿 可以让移动端写死 就不用每次返回了

partnerid

商户号 这个也是固定的 可以自己写也可以从$resutl里拿 可以让移动端写死 就不用每次返回了

prepayid

预支付交易会话ID 这个很重要必须返回给移动端 是必须从$resutl里拿的

package

扩展字段 可以自己写也可以从$resutl里拿 暂填写固定值"Sign=WXPay"可以让移动端写死 就不用每次返回了

noncestr

随机字符串 这个可以自己写也可以从$resutl里拿

timestamp

时间戳 自己生成 标准北京时间,时区为东八区注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字),这里有个坑,ISO端接收的时候好像得强行转化一下,因为返回的是字符串不是数字,还有什么几位的数字之类的,我也不太懂,反正就是写的时候提醒下iOS工程师就行。安卓不清楚。

sign

签名 又来一个坑,我们把这个签名叫做二次签名,但是这个签名不是从$resutl里拿的,而是自己写的,如何写呢,又有坑!因为参与签名的参数值是那几个不清楚,参数名写不对!不怕我有代码!贴给你看!需要参与签名的值有六个!

$sign_array              = array();

$sign_array['appid']    = $wx_result['appid'];    //注意 $sign_array['appid'] 里的参数名必须是appid

$sign_array['partnerid'] = $wx_result['mch_id'];  //注意 $sign_array['partnerid'] 里的参数名必须是partnerid

$sign_array['prepayid']  = $wx_result['prepay_id'];//注意 $sign_array['prepayid'] 里的参数名必须是prepayid

$sign_array['package']  = 'Sign=WXPay';          //注意 $sign_array['package'] 里的参数名必须是package

$sign_array['noncestr']  = $wx_result['nonce_str'];//注意 $sign_array['noncestr'] 里的参数名必须是noncestr

$sign_array['timestamp'] = time();                //注意 $sign_array['timestamp'] 里的参数名必须是timestamp

$sign_two = $this->wechatAppPay->MakeSign($sign_array);//调用wechatAppPay类里的MakeSign()函数生成sign

现在就可以把重新生成的sign($sign_two)以及其他参数返回给移动端了,一共返回七个值,有三个之可以让前端写死(appid,partnerid,package),其余四个必须由服务器返回给移动端。

= "4";//接收支付结果的页面地址,该参数一般置为空即可。$this->pageUrl

步骤3完毕

"";//扩展字段1,商户可以传递自己需要的参数,支付完快钱会原值返回,可以为空。$this->ext1

步骤4由移动端完成

$MockOrder['orderId'];//扩展自段2,商户可以传递自己需要的参数,支付完快钱会原值返回,可以为空。$this->ext2

步骤5 回调接口支付结果通用通知

还记得步骤2中我们设置的$notify_url吗,对现在就要对这个微信返回到这个接口的数据进行一系列的逻辑处理了

官方是这样写的:

支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。

对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒)

注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。

推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。

特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,防止数据泄漏导致出现“假通知”,造成资金损失。

首先来接收数据

$data = $this->wechatAppPay->getNotifyData();//获取数据 用wechatAppPay类里的getNotifyData()方法,这里数据也被getNotifyData()由xml转化成了数组。

然后官方说要采用数据锁进行并发控制,这个我不懂所以没写(如果你懂你会的话请给我留言私信告诉我,在这谢谢了),对数据进行状态检查这个写了,如何写的呢?很简单微信返回的值有好多其中就可以判断result_code(业务结果)和return_code(返回状态码)是否为SUCCESS就可以了代码就不写了。

然后验签,这个很重要因为这是保证数据没有被第三方人为篡改的标准!

如何验签呢?

把返回的数据$data里除去sign剩下的值都参与重新签名我们把这次签名叫做验签签名,验签签名生成后再与$data里的sign对比,如果相同验签通过,否则不通过。这次签名的参数名与二次签名时的参数名不同,$data数组里叫什么参数名就验签时叫什么参数名。听乱了吧?(~ ̄▽ ̄)~(~ ̄▽ ̄)~没关系请看代码

//假如$data里有如下参数

$w_sign = array();          //参加验签签名的参数数组

$w_sign['appid']            = $data['appid'];

$w_sign['bank_type']        = $data['bank_type'];

$w_sign['cash_fee']          = $data['cash_fee'];

$w_sign['fee_type']          = $data['fee_type'];

$w_sign['is_subscribe']      = $data['is_subscribe'];

$w_sign['mch_id']            = $data['mch_id'];

$w_sign['nonce_str']        = $data['nonce_str'];

$w_sign['openid']            = $data['openid'];

$w_sign['out_trade_no']      = $data['out_trade_no'];

$w_sign['result_code']      = $data['result_code'];

$w_sign['return_code']      = $data['return_code'];

$w_sign['time_end']          = $data['time_end'];

$w_sign['total_fee']        = $data['total_fee'];

$w_sign['trade_type']        = $data['trade_type'];

$w_sign['transaction_id']    = $data['transaction_id'];

$verify_sign = $this->wechatAppPay->MakeSign($w_sign);//生成验签签名

好了现在假设你的验签已经通过了接下里就是你自己的逻辑处理了

///////////////////////////////////////////////////////

商户APP应用(后台)处理逻辑代码

//////////////////////////////////////////////////////

自己的逻辑处理已经处理完之后,还得告诉微信一下,别再一直发结果通用通知啦,我已经收到通知并处理完啦!

$this->wechatAppPay->replyNotify();//商户处理后同步返回给微信参数

$MockOrder['orderTime'];//银行代码,如果payType为00,该值可以为空;如果payType为10,该值必须填写,具体请参考银行列表。$this->bankId

"";//同一订单禁止重复提交标志,实物购物车填1,虚拟产品用0。1代表只能提交一次,0代表在支付不成功情况下可以再提交。可为空。$this->redoFlag = "";//快钱合作伙伴的帐户号,即商户编号,可为空。$this->pid = "";//快钱提供的request参数。$KeyOrders =

步骤5结束

array('inputCharset','pageUrl','bgUrl','version','language','signType','merchantAcctId','payerName','payerContactType','payerContact','orderId','orderAmount','orderTime','productName','productNum','productId','productDesc','ext1','ext2','payType','bankId','redoFlag','pid',);//判断快钱提供的request参数的值是否为空,把非空的参数及值重新组建数组foreach{if{continue;}$params[$key]

$this->{$key};}//http_build_query()生成URL-encode之后的请求字符串//urldecode()还原未编码的字符串//getSignMsg() PKI加密,也可使用MD5加密//MD5加密方式 strtoupper(md5(urldecode(http_build_query;这种不常用了。//常用PKI加密$this->signMsg = $this->getSignMsg(urldecode(http_build_query;}//PKI加密技术public function getSignMsg{//99bill-rsa.pem是快钱的一个CA证书//本地随机生成一个KEY,用此KEY加密数据 KEY为$priv_key_id$priv_key_id = openssl_get_privatekey(file_get_contents("99bill-rsa.pem", "r"));//用$priv_key_id给$param数据加密。//计算一个签名字符串$param通过使用SHA1哈希加密,随后$priv_key_id私钥加密。数据本身是不加密的。openssl_sign($param, $signMsg, $priv_key_id, OPENSSL_ALGO_SHA1);//从存储器上释放$priv_key_idopenssl_free_key;//使用base64对数据进行编码return base64_encode;}}models/BillResponse.phpBillResponse.php复制代码 代码如下:

errCode的值可能为空 */public function __construct{$KeyOrders = array('merchantAcctId','version','language','signType','payType','bankId','orderId','orderTime','orderAmount','dealId','bankDealId','dealTime','payAmount','fee','ext1','ext2','payResult','errCode', 'signMsg');foreach{$this->{$key} = $response[$key];}}/* * 检查签名字符串 * 快钱返回的签名字符串是$this->signMsg * 使用base64对前面字符串进行解码 * 验证使用快钱给的公钥验证 * 快钱那边他们把返回来的参数值不为空的使用私钥加密生成了$this->signMsg * 快钱给了我们私钥对应的公钥,我们使用这个公钥来验证。1成功,0失败,-1错误。 */public function checkSignMsg(){$KeyOrders = array('merchantAcctId','version','language','signType','payType','bankId','orderId','orderTime','orderAmount','dealId','bankDealId','dealTime','payAmount','fee','ext1','ext2','payResult','errCode',);foreach{if{continue;}$params[$key] = $this->{$key};}//$pub_key_id 公钥$pub_key_id = openssl_get_publickey(file_get_contents("99bill-rsa.cer", "r"));return openssl_verify(urldecode(http_build_query, base64_decode, $pub_key_id); }public function isSuccess(){//$this->payResult成功时10,失败时11return '10'==$this->payResult;}public function getOrderId(){return str_replace('XXX', '', $this->orderId);}}需要一个公钥和一个私钥,这个不是一对的都是一半99bill-rsa.cer99bill-rsa.pem

步骤6根据自己情况而定

结束语

至此微信支付处理完成~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦

写的有不对的方还请大家多多指导指教!!!给我留言!!b( ̄▽ ̄)db( ̄▽ ̄)db( ̄▽ ̄)d

还有感谢在我写微信支付地时候 那些被我问烦了的大神们! !谢谢啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦O(∩_∩)O哈哈~O(∩_∩)O哈哈~O(∩_∩)O哈哈~<( ̄︶ ̄)><( ̄︶ ̄)><( ̄︶ ̄)>

代码 注:我不知道在简书上如何贴代码,要清楚代码的同学可以移步到这里传送门

wechatAppPay类

class wechatAppPay {      //接口API URL前缀    const API_URL_PREFIX = '';    //下单地址URL    const UNIFIEDORDER_URL = "/pay/unifiedorder";    //查询订单URL    const ORDERQUERY_URL = "/pay/orderquery";    //关闭订单URL    const CLOSEORDER_URL = "/pay/closeorder";    //公众账号ID    private $wxappid;    //商户号    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;    //交易类型    private $trade_type;    //支付密钥    private $key;    //证书路径    private $SSLCERT_PATH;    private $SSLKEY_PATH;    //所有参数    private $params = array();    public function __construct($wxappid, $mch_id, $notify_url, $key)    {        $this->appid = $wxappid;        $this->mch_id = $mch_id;        $this->notify_url = $notify_url;        $this->key = $key;    }    /**    * 下单方法    * @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'] = $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;        $data['partnerid'] = $this->mch_id;        $data['prepayid'] = $prepayid;        $data['package'] = 'Sign=WXPay';        $data['noncestr'] = $this->genRandomString();        $data['timestamp'] = time();        $data['sign'] = $this->MakeSign( $data );          return $data;    }    /**    * 生成签名    *  @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 = "";

foreach ($params as $key=>$val)

{

if (is_numeric($val)){

$xml.="<".$key.">".$val."";

}else{

$xml.="<".$key.">";

}

}

$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];        }    }}

本文由yzc216亚洲城发布于yzc216.com官网,转载请注明出处:Wechat支付,使用php实现快钱支付功用_php技艺_脚本

关键词: yzc216亚洲城 yzc216.com官网