Maison > Article > développement back-end > 赶时髦~俺家小店接入了微信支付,赶时髦小店_PHP教程
一、有言在先
1、俺家公众号开通微信支付时间是9月22号,所以适用文档版本号是v3.3.6,当时一不小心从微信客服那里拿到一个v2.7的文档,扑腾了1天时间,从一个个水坑里爬出来又跌入尿坑,把人坑惨了,后面找到相关人士才拿到真相,不过现在公众平台也可以下载到了~希望大家伙绕开这个坑!
2、最重要一点:此文有软广告嫌疑,慎入!先帮朋友们把评论写在这里~~~
二、需要到这些地方去扒参数
1、登录微信公众号管理后台mp.weixin.qq.com,在左侧菜单栏找到开发者中心,点开如下图就能看到AppID和AppSecret:
2、在微信支付通过之后,财付通会发3封邮件到申请人邮箱中,俺家之前开通过财付通的账户用于主站支付接口, 不过这次又新发了一个财付通账号,不过让人惊喜的是这次微信支付免了保证金,不知为啥?
点开weixinpay那封邮件就可以看到这些账号信息,把附件中pem格式的文件下载保存到web服务器上,请记下文件绝对路径,在下面代码中需要用到:
3、登录微信商户平台(mch.weixin.qq.com),去设置商户支付密钥Key:
4、登录微信公众号管理后台mp.weixin.qq.com,设置支付配置,支付测试,支付白名单
三、找到参数来配置该个类class WxPayConf
class WxPayConf
{
//=======【基本信息设置】=====================================
//微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
const APPID = "填上二、1中看到的AppID";
//受理商ID,身份标识
const MCHID = "填上二、2中看到的MCHID";
//商户支付密钥Key。审核通过后,在微信发送的邮件中查看(如果没有,可以登录微信商户平台去设置)
const KEY = "填上二、3中设置的密钥";
//JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
const APPSECRET = "填上二、1中看到的AppSecret";
//=======【JSAPI路径设置】===================================
//获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面
const JS_API_CALL_URL = "http://www.xxx.com/wxpay/js_api_call.php";
//=======【证书路径设置】=====================================
//证书路径,注意应该填写绝对路径
const SSLCERT_PATH = "填上二、2中下载的pem文件放在服务器上的路径";
const SSLKEY_PATH = "填上二、2中下载的pem文件放在服务器上的路径";
//=======【异步通知url设置】===================================
//异步通知url,商户根据实际开发过程设定
const NOTIFY_URL = http://www.xxxx.com/wxpay/notify_url.php;
}
四、JSAPI支付
微信JS API只能在微信内置浏览器中使用,其他浏览器调用无效。
下面代码是微信官方提供的JS API支付demo
include_once("WxPayHelper/WxPayHelper.php");
//使用jsapi接口 $jsApi = new JsApi(); //=========步骤1:网页授权获取用户openid============ //通过code获得openid if(!isWeixin()){ echo "请在微信内扫描二维码"; exit; } if (!isset($_GET['code'])) { //触发微信返回code码 $url = $jsApi->createOauthUrlForCode(WxPayConf::JS_API_CALL_URL."); Header("Location: $url"); }else { //获取code码,以获取openid $code = $_GET['code']; $jsApi->setCode($code); $openid = $jsApi->getOpenId(); } if(empty($order)){ echo "数据错误!"; exit; } } //=========步骤2:使用统一支付接口,获取prepay_id============ //使用统一支付接口 $unifiedOrder = new UnifiedOrder(); //设置统一支付接口参数 //设置必填参数 //appid已填,商户无需重复填写 //mch_id已填,商户无需重复填写 //noncestr已填,商户无需重复填写 //spbill_create_ip已填,商户无需重复填写 //sign已填,商户无需重复填写 $unifiedOrder->setParameter("openid","$openid");//商品描述 $unifiedOrder->setParameter("body","test");//商品描述 //自定义订单号,此处仅作举例 $timeStamp = time(); $out_trade_no = timeStamp; $total_fee = 1; $unifiedOrder->setParameter("out_trade_no","$out_trade_no");//商户订单号 $unifiedOrder->setParameter("total_fee",$total_fee);//总金额 $unifiedOrder->setParameter("notify_url",WxPayConf::NOTIFY_URL);//通知地址 $unifiedOrder->setParameter("trade_type","JSAPI");//交易类型 //非必填参数,商户可根据实际情况选填 //$unifiedOrder->setParameter("sub_mch_id","XXXX");//子商户号 //$unifiedOrder->setParameter("device_info","XXXX");//设备号 //$unifiedOrder->setParameter("attach","XXXX");//附加数据 //$unifiedOrder->setParameter("time_start","XXXX");//交易起始时间 //$unifiedOrder->setParameter("time_expire","XXXX");//交易结束时间 //$unifiedOrder->setParameter("goods_tag","XXXX");//商品标记 //$unifiedOrder->setParameter("openid","XXXX");//用户标识 //$unifiedOrder->setParameter("product_id","XXXX");//商品ID $prepay_id = $unifiedOrder->getPrepayId(); //=========步骤3:使用jsapi调起支付============ $jsApi->setPrepayId($prepay_id); $jsApiParameters = $jsApi->getParameters(); function isWeixin(){ $agent = strtolower($_SERVER['HTTP_USER_AGENT']); $is_weixin = strpos($agent, 'micromessenger') ? true : false ; if($is_weixin){ return true; }else{ return false; } } ?> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <title>微信安全支付</title> <script type="text/javascript"> //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', <?php echo $jsApiParameters; ?>, function(res){ WeixinJSBridge.log(res.err_msg); //alert(res.err_code+res.err_desc+res.err_msg); } ); } function callpay() { if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } } </script> </head> <body onload=""> </br> </br> </br> </br> <div align="center"> <button style="width: 210px; height: 30px; background-color: #FE6714; border: 0px #FE6714 solid; cursor: pointer; color: white; font-size: 16px;" type="button" onclick="callpay()">贡献一下</button> </div> </body> </html>
将其中的微信支付参数修改成自己申请得到的,然后将网页上传到微信支付目录下,使用公众号给测试账号回复该网页地址。用户就可以实现一次JS API支付。
五、NATIVE支付
采用了官方提供的demo,native支付模式2完成
下面代码是微信官方提供的natice支付demo
include_once("WxPayHelper/WxPayHelper.php");
//使用统一支付接口 $unifiedOrder = new UnifiedOrder(); //设置统一支付接口参数 //设置必填参数 //appid已填,商户无需重复填写 //mch_id已填,商户无需重复填写 //noncestr已填,商户无需重复填写 //spbill_create_ip已填,商户无需重复填写 //sign已填,商户无需重复填写 $unifiedOrder->setParameter("body","贡献一分钱");//商品描述 //自定义订单号,此处仅作举例 $timeStamp = time(); $out_trade_no = WxPayConf::APPID."$timeStamp"; $unifiedOrder->setParameter("out_trade_no","$out_trade_no");//商户订单号 $unifiedOrder->setParameter("total_fee","1");//总金额 $unifiedOrder->setParameter("notify_url",WxPayConf::NOTIFY_URL);//通知地址 $unifiedOrder->setParameter("trade_type","NATIVE");//交易类型 //非必填参数,商户可根据实际情况选填 //$unifiedOrder->setParameter("sub_mch_id","XXXX");//子商户号 //$unifiedOrder->setParameter("device_info","XXXX");//设备号 //$unifiedOrder->setParameter("attach","XXXX");//附加数据 //$unifiedOrder->setParameter("time_start","XXXX");//交易起始时间 //$unifiedOrder->setParameter("time_expire","XXXX");//交易结束时间 //$unifiedOrder->setParameter("goods_tag","XXXX");//商品标记 //$unifiedOrder->setParameter("openid","XXXX");//用户标识 //$unifiedOrder->setParameter("product_id","XXXX");//商品ID //获取统一支付接口结果 $unifiedOrderResult = $unifiedOrder->getResult(); //商户根据实际情况设置相应的处理流程 if ($unifiedOrderResult["return_code"] == "FAIL") { //商户自行增加处理流程 echo "通信出错:".$unifiedOrderResult['return_msg']."<br>"; } elseif($unifiedOrderResult["result_code"] == "FAIL") { //商户自行增加处理流程 echo "错误代码:".$unifiedOrderResult['err_code']."<br>"; echo "错误代码描述:".$unifiedOrderResult['err_code_des']."<br>"; } elseif($unifiedOrderResult["code_url"] != NULL) { //从统一支付接口获取到code_url $code_url = $unifiedOrderResult["code_url"]; //商户自行增加处理流程 //...... } ?> <!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>微信安全支付</title> </head> <body> <div align="center" id="qrcode"> </div> <div align="center"> <p>订单号:<?php echo $out_trade_no; ?></p> </div> <div align="center"> <form action="./order_query.php" method="post"> <input name="out_trade_no" type='hidden' value="<?php echo $out_trade_no; ?>"> <button type="submit" >查询订单状态</button> </form> </div> <br> <div align="center"> <form action="./refund.php" method="post"> <input name="out_trade_no" type='hidden' value="<?php echo $out_trade_no; ?>"> <input name="refund_fee" type='hidden' value="1"> <button type="submit" >申请退款</button> </form> </div> <br> <div align="center"> <a href="../index.php">返回首页</a> </div> </body> <script src="./qrcode.js"></script> <script> if(<?php echo $unifiedOrderResult["code_url"] != NULL; ?>) { var url = "<?php echo $code_url;?>"; //参数1表示图像大小,取值范围1-10;参数2表示质量,取值范围'L','M','Q','H' var qr = qrcode(10, 'M'); qr.addData(url); qr.make(); var wording=document.createElement('p'); wording.innerHTML = "扫我,扫我"; var code=document.createElement('DIV'); code.innerHTML = qr.createImgTag(); var element=document.getElementById("qrcode"); element.appendChild(wording); element.appendChild(code); } </script> </html>
六、调用WxPayHelper.php存在的问题
在做开发时,官方demo 提供的wxPayHeler.php 存在部分问题,导致结果sign 错误。
使用jpapi 支付时候需要修改3
大家可以根据自己下载到的版本看是否需要修改
这里贴出修改后的代码
<?php /** * 微信支付帮助库 * ==================================================== * 接口分三种类型: * 【请求型接口】--Wxpay_client_ * 统一支付接口类--UnifiedOrder * 订单查询接口--OrderQuery * 退款申请接口--Refund * 退款查询接口--RefundQuery * 对账单接口--DownloadBill * 短链接转换接口--ShortUrl * 【响应型接口】--Wxpay_server_ * 通用通知接口--Notify * Native支付——请求商家获取商品信息接口--NativeCall * 【其他】 * 静态链接二维码--NativeLink * JSAPI支付--JsApi * ===================================================== * 【CommonUtil】常用工具: * trimString(),设置参数时需要用到的字符处理函数 * createNoncestr(),产生随机字符串,不长于32位 * formatBizQueryParaMap(),格式化参数,签名过程需要用到 * getSign(),生成签名 * arrayToXml(),array转xml * xmlToArray(),xml转 array * postXmlCurl(),以post方式提交xml到对应的接口url * postXmlSSLCurl(),使用证书,以post方式提交xml到对应的接口url */ include_once("SDKRuntimeException.php"); include_once("WxPay.config.php"); /** * 所有接口的基类 */ class Common_util_ { function __construct($argument) { } function trimString($value) { $ret = null; if (null != $value) { $ret = $value; if (strlen($ret) == 0) { $ret = null; } } return $ret; } /** * 作用:产生随机字符串,不长于32位 */ public function createNoncestr( $length = 32 ) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } /** * 作用:格式化参数,签名过程需要使用 */ function formatBizQueryParaMap($paraMap, $urlencode) { $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v) { if($urlencode) { $v = urlencode($v); } //$buff .= strtolower($k) . "=" . $v . "&"; $buff .= $k. "=" . $v . "&"; } $reqPar; if (strlen($buff) > 0) { $reqPar = substr($buff, 0, strlen($buff)-1); } return $reqPar; } /** * 作用:生成签名 */ public function getSign($Obj) { foreach ($Obj as $k => $v) { // $Parameters[strtolower($k)] = $v; $Parameters[$k] = $v; } //签名步骤一:按字典序排序参数 ksort($Parameters); $String = $this->formatBizQueryParaMap($Parameters, false); //echo "【string】 =".$String."</br>"; //签名步骤二:在string后加入KEY $String = $String."&key=".WxPayConf::KEY; //echo "【string】 =".$String."</br>"; //签名步骤三:MD5加密 $result_ = strtoupper(md5($String)); return $result_; } /** * 作用:array转xml */ function arrayToXml($arr) { $xml = "<xml>"; foreach ($arr as $key=>$val) { if (is_numeric($val)) { $xml.="<".$key.">".$val."</".$key.">"; } else $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } $xml.="</xml>"; return $xml; } /** * 作用:将xml转为array */ public function xmlToArray($xml) { //将XML转为array $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $array_data; } /** * 作用:以post方式提交xml到对应的接口url */ public function postXmlCurl($xml,$url) { //初始化curl $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); //设置header curl_setopt($ch, CURLOPT_HEADER, 0); //要求结果为字符串且输出到屏幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //post提交方式 curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); //运行curl $data = curl_exec($ch); curl_close($ch); //返回结果 if($data) { curl_close($ch); return $data; } else { $error = curl_errno($ch); echo "curl出错,错误码:$error"."<br>"; curl_close($ch); return false; } } /** * 作用:使用证书,以post方式提交xml到对应的接口url */ function postXmlSSLCurl($xml,$url) { $ch = curl_init(); curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch,CURLOPT_HEADER, 0); curl_setopt($ch,CURLOPT_URL,$url); //设置证书 curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,true); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2); curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, WxPayConf::SSLCERT_PATH); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, WxPayConf::SSLKEY_PATH); //post提交方式 curl_setopt($ch,CURLOPT_POST, true); curl_setopt($ch,CURLOPT_POSTFIELDS,$xml); $data = curl_exec($ch); //返回结果 if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); echo "curl出错,错误码:$error"."<br>"; curl_close($ch); return false; } } /** * 作用:打印数组 */ function printErr($wording='',$err='') { print_r('<pre class="brush:php;toolbar:false">'); echo $wording."</br>"; var_dump($err); print_r(''); } } /** * 请求型接口的基类 */ class Wxpay_client_ extends Common_util_ { var $parameters;//请求参数,类型为关联数组 public $response;//微信返回的响应 public $result;//返回参数,类型为关联数组 var $url;//接口链接 /** * 作用:设置请求参数 */ function setParameter($parameter, $parameterValue) { $this->parameters[$this->trimString($parameter)] = $this->trimString($parameterValue); } /** * 作用:设置标配的请求参数,生成签名,生成接口参数xml */ function createXml() { $this->parameters["appid"] = WxPayConf::APPID;//公众账号ID $this->parameters["mch_id"] = WxPayConf::MCHID;//商户号 $this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串 $this->parameters["sign"] = $this->getSign($this->parameters);//签名 return $this->arrayToXml($this->parameters); } /** * 作用:post请求xml */ function postXml() { $xml = $this->createXml(); $this->response = $this->postXmlCurl($xml,$this->url); return $this->response; } /** * 作用:使用证书post请求xml */ function postXmlSSL() { $xml = $this->createXml(); $this->response = $this->postXmlSSLCurl($xml,$this->url); return $this->response; } /** * 作用:获取结果,默认不使用证书 */ function getResult() { $this->postXml(); $this->result = $this->xmlToArray($this->response); return $this->result; } } /** * 统一支付接口类 */ class UnifiedOrder extends Wxpay_client_ { function __construct($argument) { //设置接口链接 $this->url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; } /** * 生成接口参数xml */ function createXml() { try { //检测必填参数 if($this->parameters["out_trade_no"] == null) { throw new SDKRuntimeException("缺少统一支付接口必填参数out_trade_no!"."
恭喜您~有超一流的忍耐力看完这篇臭(凑)文-_-,如果觉得对你有那么一点点帮助,点赞就不要了, 省下那点力气请猛戳俺家小店(www.wsyu.com),为您的女盆友(我一直坚信程序猿有女盆友!!!)备上一款精美项链、手链或脚链,她一高兴,您晚上就不用撸管了!
或者关注下俺家的公众号:
近期正在赶工微信小店的接口,欢迎加群:204689062 讨论~
我不太喜欢赶时髦,当大家早就在使用微信传递信息的时候,我还是恪守习惯的交流方式,电话,短信和电子邮件。这并非是我不接受新生事物,因为我知道,在信息传递的过程中,中间环节越多,信息的安全性就越差,飞信不如短信,短信不如电话,手机不如座机,座机不如见面,在咖啡馆聊不如在家里聊。当政府严格要求网络实名制的时候,微信,把你的手机号码、所在位置、你的亲朋好友。。。一网打尽的时候,任何“实名制”都相形见绌了。在用飞信的时候就发生过这样的事情:飞信系统把俺的前女友的号码推介给俺媳妇:你们有一个共同的好友。 在朋友的忽悠下,再看看周边的哥们都在用微信联系打球等事宜,你不加微信,人家都不带你玩了。于是,也换了手机,上了微信。却不料用了微信后第一次和朋友约会打球时,就收到了微信要收费的传言。在到网上去一看,为了微信收费的问题,已经打成一锅粥了:微信的制造商腾讯急忙出来辟谣;受到微信正面直接冲击的中国移动的董事长也赤膊上阵大谈“微信等OTT服务确实造成了运营商的网络负担加重”等论调;政府主管部门、工信部部长苗圩公开表示,工信部目前正协调运营商微信收费一事,“收流量以外的费用也是合情合理的”;与政府保持一致的官媒也纷纷找出了国外收费的案例加以渲染;但是,已经习惯了免费的网民们根本不接受除了数据流量费以外的其他收费,一时间,板砖一致飞向“收费”。 专家们,不论是挺收费的还是反收费,都在用很多诸如OTT(增值业务)、信令信道之类的专业术语,试图向大家说明微信的是与非。但这些东西除了业内人士能够听明白,就连我这曾经在北邮混过8年的人都听得云山雾罩。我就曾为此问过IT专家:你们老说微信占用了信令信道,你们要是认为信令信道拥堵了,那就再从其他7条信道里面拿出一个信道来做信令呗。被专家们嘲讽:别老外了,再拿一条信道做信令?那语音岂不是受影响?!语音才是移动运营商的根本!可见,对于数据业务,移动运营商是爱恨交加。数据多了,必然冲击传统的语音通话,而他们又不愿意放弃传统的话务量,现在还要死守语音这个阵地,而置数据业务发展大趋势于不顾。照此下去,移动运营商或可成为下一个柯达。 其实,对于微信的收费而言,不存在这么多的专业术语,也不需要找到什么理论根据和外国的经验。收费与否,收费的多寡,都取决于提供商品服务的买卖双方的博弈和达成的共识。 就微信而言,腾讯是服务提供商,我们都是用户,移动运营商则是传递这个服务的中介。所以,在这一个服务链中,可以有3个收费的服务项目:收费1:腾讯向用户收(买卖关系);收费2:腾讯付给运营商(卖方中介),收费3:运营商收用户(买方中介)。在这3个或有的收费项目中,与用户直接有关的,是“收费1”和“收费3”这两个项目,“收费3”是已经在收的,不论是总量包月,还是计算流量,用户都已经向运营商支付了费用;而“收费1”,腾讯已经再三表态:目前不会收费。那么,作为用户我们还有什么可担心的?还需要扔什么板砖呢? 所以,需要讨论的只有“收费2”——运营商向腾讯收取接入费用。从道理上来说,这个收费是可以的,也是应该的。但是,这必须在一个公平的条件下进行,不能有歧视。运营商不能只对腾讯的微信收费,而要对运营商接入的所有的OTT产品都有一个明确的收费标准。即,对腾讯微信收费了,也要对skype、飞聊、翼信等采取同样的收费标准。当然,对于运营商的收费,腾讯也有权选择不交费,如,对某一家运营商的收费说不,从而不使用该运营商提供的网络。这样一来,由于腾讯不使用该运营商的网络,对腾讯来讲,可能会导致使用该运营商网络的一些微信用户的流失,同时,该运营商的数据流量的业务会受到影响,而一些手机用......余下全文>>