目前微信支付集成到框架里面有太多的坑了,项目中刚好遇到一个,把经验和重要的坑写出来,一步一步从0开始,大家有什么不会的可以留言。
1.首先,我们要去官方下载人家做好的DEMO,链接是https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
2.下载好以后,我们可以把里面的东西放到app\Wechat里(文件夹需要新建)
3.打开lib/WxPay.Config.php,把里面四个重要参数改成自己的,下面有两个证书路径,如果有退款什么的才需要,光支付就不管他
- const APPID = '在你的公众号里看';
- const MCHID = '商户ID';
- const KEY = '自己在公众号设置的32位';
- const APPSECRET = '也在公众号里看';
4.在resource/view/下新建文件夹wechat,里面视图就把app\Wechat里面的jsapi.php改名为jsapi.blade.php放进去,这里要说一下,引用的文件路径,必须是我这种格式“../app/Wechat”下才能正确读取,而且把所有app/Wechat下的各种文件都打开,里面只要用到路径,你就在require_once后面加个“../app/Wechat/”
- <?php
- ini_set('date.timezone','Asia/Shanghai');
- //error_reporting(E_ERROR);
- require_once "../app/Wechat/lib/WxPay.Api.php";
- require_once "../app/Wechat/example/WxPay.JsApiPay.php";
- require_once '../app/Wechat/example/log.php';
- //①、获取用户openid
- $tools = new JsApiPay();
- $openId = $tools->GetOpenid("/wechat?money=".$money); //传参要这样传,还要改一下example/WxPay.JsApiPay.php文件
- //②、统一下单
- $input = new WxPayUnifiedOrder();
- $input->SetBody("微信支付");
- $input->SetAttach("微信支付");
- $input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis"));
- $input->SetTotal_fee($money);
- $input->SetTime_start(date("YmdHis"));
- $input->SetTime_expire(date("YmdHis", time() + 600));
- $input->SetGoods_tag("");
- $input->SetNotify_url("http://aaa.com/wechat/notify");//这里填你的回调路径,是绝对路径,例如http://aaa.com/wechat/notify
- $input->SetTrade_type("JSAPI");
- $input->SetOpenid($openId);
- $order = WxPayApi::unifiedOrder($input);
- // echo '<font color="#f00"><b>统一下单支付单信息</b></font><br/>';
- // printf_info($order);
- $jsApiParameters = $tools->GetJsApiParameters($order);
- //获取共享收货地址js函数参数
- $editAddress = $tools->GetEditAddressParameters();
- //③、在支持成功回调通知中处理成功之后的事宜,见 notify.php
- /**
- * 注意:
- * 1、当你的回调地址不可访问的时候,回调通知会失败,可以通过查询订单来确认支付是否成功
- * 2、jsapi支付时需要填入用户openid,WxPay.JsApiPay.php中有获取openid流程 (文档可以参考微信公众平台“网页授权接口”,
- * 参考http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html)
- */
- ?>
- <html>
- <head>
- <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1"/>
- <title>微信支付</title>
- <script src="http://7xwdxi.com1.z0.glb.clouddn.com/lib/js/jquery-2.0.3.min.js"></script>
- <script type="text/javascript">
- //调用微信JS api 支付
- function jsApiCall()
- {
- WeixinJSBridge.invoke(
- 'getBrandWCPayRequest',
- <?php echo $jsApiParameters; ?>,
- function(res){
- //这底下的东西就是上面$input->SetNotify_url("http://aaa.com/notify");这个传过来的
- WeixinJSBridge.log(res.err_msg);
- // alert(res.err_code+res.err_desc+res.err_msg);
- if (res.err_msg == "get_brand_wcpay_request:ok") { //如果微信支付成功
- // message: "微信支付成功!"
- alert("支付成功!");
- window.location.href="/wechat/do;//你成功后要跳转的页面或控制器
- }else if(res.err_msg == "get_brand_wcpay_request:cancel"){ //如果取消微信支付
- alert("您已取消支付");
- }
- }
- );
- }
- 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>
- <script type="text/javascript">
- //获取共享地址
- function editAddress()
- {
- WeixinJSBridge.invoke(
- 'editAddress',
- <?php echo $editAddress; ?>,
- function(res){
- var value1 = res.proviceFirstStageName;
- var value2 = res.addressCitySecondStageName;
- var value3 = res.addressCountiesThirdStageName;
- var value4 = res.addressDetailInfo;
- var tel = res.telNumber;
- alert(value1 + value2 + value3 + value4 + ":" + tel);
- }
- );
- }
- window.onload = function(){
- if (typeof WeixinJSBridge == "undefined"){
- if( document.addEventListener ){
- document.addEventListener('WeixinJSBridgeReady', editAddress, false);
- }else if (document.attachEvent){
- document.attachEvent('WeixinJSBridgeReady', editAddress);
- document.attachEvent('onWeixinJSBridgeReady', editAddress);
- }
- }else{
- editAddress();
- }
- };
- </script>
- </head>
- <body>
- <div class="title-bar">
- <span><a href="/home/student/pay"><img src="http://7xwdxi.com1.z0.glb.clouddn.com/images/back-icon.png"></a></span>
- <h1>充值</h1>
- </div>
- <br/>
- <font color="#9ACD32"><b>该笔订单支付金额为<span style="color:#f00;font-size:50px"><?php $sum=$money/100; ?>{{$sum}}</span>元钱</b></font><br/><br/>
- <div align="center">
- <button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" type="button" οnclick="callpay()" >立即支付</button>
- </div>
- </body>
- </html>
5.写控制器,新建控制器叫WechatController,主要是回调函数里写好你的逻辑(官方无回调文档,很坑)
- ...
- public function index(Request $request){
- if(!is_numeric(Input::get('money'))){
- return Redirect::back();
- }
- $money = Input::get('money')*10;
- //因为微信的钱是按分为单位,所以传进来,先*10,然后微信会回调回来,在执行一次这个方法,所以再*10,如果是5元,传个5就变成500分,就是5元钱了
- return view("home.student.jsapi")
- ->withMoney($money);//把money作为参数带到jsapi.blade.php
- }
- public function notify(){ //这里是你的回调函数,这个很坑,官方都没有文档的
- public function notify(Request $request){
- $streamData = isset($GLOBALS['HTTP_RAW_POST_DATA'])? $GLOBALS['HTTP_RAW_POST_DATA'] : ''; //拿到微信回调回来的信息判断支付成功没
- if(empty($streamData)){
- $streamData = file_get_contents('php://input');
- }
- if($streamData!=''){
- $streamData=xmlToArray($streamData);
- $Data=json_encode($streamData);
- Log::debug('Alipay notify post data verification fail.', [ //写入服务器文档,你不加这个也行
- 'data' => $Data.'xxxxxx'
- ]);
- if($streamData['return_code'] == 'SUCCESS' && $streamData['result_code'] == 'SUCCESS'){ //支付成功
- try { //开始事务
- //支付成功,你要干些什么都写这里,例如增加余额的操作什么的
- } catch (Exception $e) {
- //如果try里面的东西出现问题的话,进行数据库回滚
- throw $e;
- }
- }
- }else{
- $ret = false; //支付失败
- }
- }
- }
- Route::any(‘wechat’,'WechatController@index');
- Route::any(‘wechat/notify’,'WechatController@notify');
7.app/Wechat/example/WxPay.JsApiPay.php里面的getopenid方法还要改一下,否则不能传参数
- ...
- public function GetOpenid($addUrl="")
- {
- //通过code获得openid
- if (!isset($_GET['code'])){
- //触发微信返回code码
- $baseUrl = urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$addUrl);
- $url = $this->__CreateOauthUrlForCode($baseUrl);
- Header("Location: $url");
- exit();
- } else {
- //获取code码,以获取openid
- $code = $_GET['code'];
- $openid = $this->getOpenidFromMp($code);
- return $openid;
- }
- }
8.这样程序这块基本就完事了,访问时你要花的钱要这么传http://aaa.com/wechat?money=5(这样的话是充5元钱)
9.下面就要说说微信公众平台上,一共要改3个地方
(1)在开发者工具下面,修改网页账号(否则通过不了Oauth2.0验证会报redirect_url错误)
(2)验证你的URL,URL就是这个验证文件在项目中的位置,如果放到public文件夹下,你就直接写http://aaa.com/wx_sample.php
验证文件如下:
wx_sample.php
- <?php
- /**
- * wechat php test
- */
- //define your token
- define("TOKEN", "weixin");//和你在公众号中填的TOKEN相同
- $wechatObj = new wechatCallbackapiTest();
- $wechatObj->valid();
- class wechatCallbackapiTest
- {
- public function valid()
- {
- $echoStr = $_GET["echostr"];
- //valid signature , option
- if($this->checkSignature()){
- echo $echoStr;
- exit;
- }
- }
- public function responseMsg()
- {
- //get post data, May be due to the different environments
- $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
- //extract post data
- if (!empty($postStr)){
- /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
- the best way is to check the validity of xml by yourself */
- libxml_disable_entity_loader(true);
- $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
- $fromUsername = $postObj->FromUserName;
- $toUsername = $postObj->ToUserName;
- $keyword = trim($postObj->Content);
- $time = time();
- $textTpl = "<xml>
- <ToUserName><![CDATA[%s]]></ToUserName>
- <FromUserName><![CDATA[%s]]></FromUserName>
- <CreateTime>%s</CreateTime>
- <MsgType><![CDATA[%s]]></MsgType>
- <Content><![CDATA[%s]]></Content>
- <FuncFlag>0</FuncFlag>
- </xml>";
- if(!empty( $keyword ))
- {
- $msgType = "text";
- $contentStr = "Welcome to wechat world!";
- $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
- echo $resultStr;
- }else{
- echo "Input something...";
- }
- }else {
- echo "";
- exit;
- }
- }
- private function checkSignature()
- {
- // you must define TOKEN by yourself
- if (!defined("TOKEN")) {
- throw new Exception('TOKEN is not defined!');
- }
- $signature = $_GET["signature"];
- $timestamp = $_GET["timestamp"];
- $nonce = $_GET["nonce"];
- $token = TOKEN;
- $tmpArr = array($token, $timestamp, $nonce);
- // use SORT_STRING rule
- sort($tmpArr, SORT_STRING);
- $tmpStr = implode( $tmpArr );
- $tmpStr = sha1( $tmpStr );
- if( $tmpStr == $signature ){
- return true;
- }else{
- return false;
- }
- }
- }
- ?>
(3)修改开发配置(支付授权目录和测试授权目录),这里要注意,如果你的支付路径是http://aaa.com/index.php/wechat,你就填http://aaa.com/index.php/,反正就是最后那个斜杠后面的别加