这篇文章主要为大家详细介绍了PHP微信支付开发过程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

PHP微信支付开发过程,分享给大家,供大家参考,具体内容如下

1.开发环境 
Thinkphp 3.2.3 
微信:服务号,已认证 
开发域名:http://test.paywechat.com (自定义的域名,外网不可访问)

2.需要相关文件和权限 
微信支付需申请开通 
微信公众平台开发者文档:http://mp.weixin.qq.com/wiki/home/index.html 
微信支付开发者文档:https://pay.weixin.qq.com/wiki/doc/api/index.html 
微信支付SDK下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

3.开发 
下载好微信支付PHP版本的SDK,文件目录为下图:

正在上传…重新上传取消

正在上传…重新上传取消 

把微信支付SDK的Cert和Lib目录放入Thinkphp,目录为 

正在上传…重新上传取消 

现在介绍微信支付授权目录问题,首先是微信支付开发配置里面的支付授权目录填写, 

正在上传…重新上传取消

然后填写js接口安全域。 

正在上传…重新上传取消

最后设置网页授权 

正在上传…重新上传取消

正在上传…重新上传取消

这些设置完,基本完成一半,注意设置的目录和我thinkphp里面的目录。 

正在上传…重新上传取消

4.微信支付配置

正在上传…重新上传取消

把相关配置填写正确。

[php] view plain copy

 
  1. /** 
  2. * 配置账号信息 
  3. */  
  4.   
  5. class WxPayConfig  
  6. {  
  7.  //=======【基本信息设置】=====================================  
  8.  //  
  9.  /** 
  10.  * TODO: 修改这里配置为您自己申请的商户信息 
  11.  * 微信公众号信息配置 
  12.  *  
  13.  * APPID:绑定支付的APPID(必须配置,开户邮件中可查看) 
  14.  *  
  15.  * MCHID:商户号(必须配置,开户邮件中可查看) 
  16.  *  
  17.  * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置) 
  18.  * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert 
  19.  *  
  20.  * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置), 
  21.  * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN 
  22.  * @var string 
  23.  */  
  24.  const”;  
  25.  const”;  
  26.  const”;  
  27.  const”;  
  28.   
  29.  //=======【证书路径设置】=====================================  
  30.  /** 
  31.  * TODO:设置商户证书路径 
  32.  * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载, 
  33.  * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书) 
  34.  * @var path 
  35.  */  
  36.  const‘../cert/apiclient_cert.pem’;  
  37.  const‘../cert/apiclient_key.pem’;  
  38.   
  39.  //=======【curl代理设置】===================================  
  40.  /** 
  41.  * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0 
  42.  * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器, 
  43.  * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置) 
  44.  * @var unknown_type 
  45.  */  
  46.  const“0.0.0.0”//”10.152.18.220″;  
  47.  const//8080;  
  48.   
  49.  //=======【上报信息配置】===================================  
  50.  /** 
  51.  * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】, 
  52.  * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少 
  53.  * 开启错误上报。 
  54.  * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报 
  55.  * @var int 
  56.  */  
  57.  const REPORT_LEVENL = 1;  
  58. }  

现在开始贴出代码:

[php] view plain copy

 
  1. namespace Wechat\Controller;  
  2. use Think\Controller;  
  3. /** 
  4.  * 父类控制器,需要继承 
  5.  * @file ParentController.class.php 
  6.  * @author Gary <lizhiyong2204@sina.com> 
  7.  * @date 2015年8月4日 
  8.  * @todu 
  9.  */  
  10. class Controller {   
  11.  protected$options (  
  12.  ‘token’// 填写你设定的key  
  13.  ‘encodingaeskey’// 填写加密用的EncodingAESKey  
  14.  ‘appid’// 填写高级调用功能的app id  
  15.  ‘appsecret’// 填写高级调用功能的密钥  
  16.  ‘debug’ => false,  
  17.  ‘logcallback’”  
  18.  );   
  19.  public$errCode = 40001;   
  20.  public$errMsg“no access”;   
  21.   
  22.  /** 
  23.  * 获取access_token 
  24.  * @return mixed|boolean|unknown 
  25.  */  
  26.  public getToken(){  
  27.  $cache_token‘exp_wechat_pay_token’);  
  28.  if$cache_token)){  
  29.  return$cache_token;  
  30.  }  
  31.  $url‘https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s’;  
  32.  $url$url$this‘appid’$this‘appsecret’]);   
  33.  $result$this$url);  
  34.  $result$result,true);   
  35.  if$result)){  
  36.  return false;  
  37.  }   
  38.  S(‘exp_wechat_pay_token’$result’access_token”type’‘file”expire’=>3600));  
  39.  return$result’access_token’];  
  40.  }  
  41.   
  42.  /** 
  43.  * 发送客服消息 
  44.  * @param array $data 消息结构{“touser”:”OPENID”,”msgtype”:”news”,”news”:{…}} 
  45.  */  
  46.  public sendCustomMessage($data){  
  47.  $token$this->getToken();  
  48.  ifempty$token false;   
  49.  $url‘https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s’;  
  50.  $url$url$token);  
  51.  $result$this$url$data));  
  52.  if$result)  
  53.  {  
  54.  $json$result,true);  
  55.  if$jsonempty$json’errcode’])) {  
  56.  $this$json’errcode’];  
  57.  $this$json’errmsg’];  
  58.  return false;  
  59.  }  
  60.  return$json;  
  61.  }  
  62.  return false;  
  63.  }  
  64.   
  65.  /** 
  66.  * 发送模板消息 
  67.  * @param unknown $data 
  68.  * @return boolean|unknown 
  69.  */  
  70.  public sendTemplateMessage($data){  
  71.  $token$this->getToken();  
  72.  ifempty$token false;  
  73.  $url“https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s”;  
  74.  $url$url$token);  
  75.  $result$this$url$data));  
  76.  if$result)  
  77.  {  
  78.  $json$result,true);  
  79.  if$jsonempty$json’errcode’])) {  
  80.  $this$json’errcode’];  
  81.  $this$json’errmsg’];  
  82.  return false;  
  83.  }  
  84.  return$json;  
  85.  }  
  86.  return false;  
  87.  }  
  88.   
  89.   
  90.  public getFileCache($name){  
  91.  return$name);  
  92.  }  
  93.   
  94.  /** 
  95.  * 微信api不支持中文转义的json结构 
  96.  * @param array $arr 
  97.  */  
  98.  static json_encode($arr) {  
  99.  $parts ();  
  100.  $is_list = false;  
  101.  //Find out if the given array is a numerical array  
  102.  $keysarray_keys$arr );  
  103.  $max_lengthcount$arr ) – 1;  
  104.  if$keys$keys$max_length$max_length//See if the first key is 0 and last key is length – 1  
  105.  $is_list = true;  
  106.  for$i$icount$keys$i//See if each key correspondes to its position  
  107.  if$i$keys$i//A key fails at position check.  
  108.   $is_list//It is an associative array.  
  109.   break;  
  110.  }  
  111.  }  
  112.  }  
  113.  foreach$arr $key$value ) {  
  114.  ifis_array$value//Custom handling for arrays  
  115.  if$is_list)  
  116.   $parts$value/* :RECURSION: */  
  117.  else  
  118.   $parts‘”‘$key‘”:’$value/* :RECURSION: */  
  119.  } else {  
  120.  $str”;  
  121.  if$is_list)  
  122.   $str‘”‘$key‘”:’;  
  123.  //Custom handling for multiple data types  
  124.  ifis_string$valueis_numeric$value$value<2000000000)  
  125.   $str$value//Numbers  
  126.  elseif$value === false)  
  127.  $str‘false’//The booleans  
  128.  elseif$value === true)  
  129.  $str‘true’;  
  130.  else  
  131.   $str‘”‘addslashes$value‘”‘//All other things  
  132.  // :TODO: Is there any more datatype we should be in the lookout for? (Object?)  
  133.  $parts$str;  
  134.  }  
  135.  }  
  136.  $json‘,’$parts );  
  137.  if$is_list)  
  138.  return‘[‘$json‘]’//Return numerical JSON  
  139.  return‘{‘$json‘}’//Return associative JSON  
  140.  }  
  141.   
  142.  /** 
  143.  +———————————————————- 
  144.  * 生成随机字符串 
  145.  +———————————————————- 
  146.  * @param int $length 要生成的随机字符串长度 
  147.  * @param string $type 随机码类型:0,数字+大小写字母;1,数字;2,小写字母;3,大写字母;4,特殊字符;-1,数字+大小写字母+特殊字符 
  148.  +———————————————————- 
  149.  * @return string 
  150.  +———————————————————- 
  151.  */  
  152.  static function$length$type = 2){  
  153.  $arr(1 => “0123456789”“abcdefghijklmnopqrstuvwxyz”“ABCDEFGHIJKLMNOPQRSTUVWXYZ”“~@#$%^&*(){}[]|”);  
  154.  if$type == 0) {  
  155.  $arr);  
  156.  $string“”$arr);  
  157.  } elseif$type“-1”) {  
  158.  $string“”$arr);  
  159.  } else {  
  160.  $string$arr$type];  
  161.  }  
  162.  $countstrlen$string) – 1;  
  163.  $code”;  
  164.  for$i$i$length$i++) {  
  165.  $code$string$count)];  
  166.  }  
  167.  return$code;  
  168.  }   
  169.   
  170.   
  171.  /** 
  172.  * GET 请求 
  173.  * @param string $url 
  174.  */  
  175.  private http_get($url){  
  176.  $oCurl = curl_init();  
  177.  if$url”https://”)!==FALSE){  
  178.  curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);  
  179.  curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);  
  180.  curl_setopt($oCurl//CURL_SSLVERSION_TLSv1  
  181.  }  
  182.  curl_setopt($oCurl$url);  
  183.  curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );  
  184.  $sContent$oCurl);  
  185.  $aStatus$oCurl);  
  186.  curl_close($oCurl);  
  187.  if$aStatus”http_code”])==200){  
  188.  return$sContent;  
  189.  }else{  
  190.  return false;  
  191.  }  
  192.  }  
  193.   
  194.  /** 
  195.  * POST 请求 
  196.  * @param string $url 
  197.  * @param array $param 
  198.  * @param boolean $post_file 是否文件上传 
  199.  * @return string content 
  200.  */  
  201.  private http_post($url$param$post_file=false){  
  202.  $oCurl = curl_init();  
  203.  if$url”https://”)!==FALSE){  
  204.  curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);  
  205.  curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);  
  206.  curl_setopt($oCurl//CURL_SSLVERSION_TLSv1  
  207.  }  
  208.  ifis_string$param$post_file) {  
  209.  $strPOST$param;  
  210.  } else {  
  211.  $aPOST();  
  212.  foreach$param $key$val){  
  213.  $aPOST$key”=”$val);  
  214.  }  
  215.  $strPOST“&”$aPOST);  
  216.  }  
  217.  curl_setopt($oCurl$url);  
  218.  curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );  
  219.  curl_setopt($oCurl, CURLOPT_POST,true);  
  220.  curl_setopt($oCurl$strPOST);  
  221.  $sContent$oCurl);  
  222.  $aStatus$oCurl);  
  223.  curl_close($oCurl);  
  224.  if$aStatus”http_code”])==200){  
  225.  return$sContent;  
  226.  }else{  
  227.  return false;  
  228.  }  
  229.  }  
  230. }  
[php] view plain copy

 
  1. namespace Wechat\Controller;  
  2. use Wechat\Controller\ParentController;  
  3. /** 
  4.  * 微信支付测试控制器 
  5.  * @file TestController.class.php 
  6.  * @author Gary <lizhiyong2204@sina.com> 
  7.  * @date 2015年8月4日 
  8.  * @todu 
  9.  */  
  10. class ParentController {  
  11.  private$_order_body‘xxx’;  
  12.  private$_order_goods_tag‘xxx’;  
  13.  public __construct(){  
  14.  parent::__construct();  
  15.  require_once“Api/lib/WxPay.Api.php”;  
  16.  require_once“Api/lib/WxPay.JsApiPay.php”;  
  17.  }  
  18.   
  19.  public index(){  
  20.  //①、获取用户openid  
  21.  $tools \JsApiPay();  
  22.  $openId$tools->GetOpenid();   
  23.  //②、统一下单  
  24.  $input \WxPayUnifiedOrder();   
  25.  //商品描述  
  26.  $input$this->_order_body);  
  27.  //附加数据,可以添加自己需要的数据,微信回异步回调时会附加这个数据  
  28.  $input‘xxx’);  
  29.  //商户订单号  
  30.  $out_trade_nodate”YmdHis”);  
  31.  $input$out_trade_no);  
  32.  //总金额,订单总金额,只能为整数,单位为分   
  33.  $input->SetTotal_fee(1);  
  34.  //交易起始时间  
  35.  $inputdate”YmdHis”));  
  36.  //交易结束时间  
  37.  $inputdate”YmdHis”, time() + 600));  
  38.  //商品标记  
  39.  $input$this->_order_goods_tag);  
  40.  //通知地址,接收微信支付异步通知回调地址 SITE_URL=http://test.paywechat.com/Charge  
  41.  $notify_url‘/index.php/Test/notify.html’;  
  42.  $input$notify_url);  
  43.  //交易类型  
  44.  $input“JSAPI”);  
  45.  $input$openId);  
  46.  $order$input);  
  47.  $jsApiParameters$tools$order);  
  48.  //获取共享收货地址js函数参数  
  49.  $editAddress$tools->GetEditAddressParameters();  
  50.   
  51.  $this‘openId’$openId);  
  52.  $this‘jsApiParameters’$jsApiParameters);  
  53.  $this‘editAddress’$editAddress);  
  54.  $this->display();   
  55.  }  
  56.   
  57.  /** 
  58.  * 异步通知回调方法 
  59.  */  
  60.  public notify(){  
  61.  require_once“Api/lib/notify.php”;  
  62.  $notify \PayNotifyCallBack();  
  63.  $notify->Handle(false);  
  64.  //这里的IsSuccess是我自定义的一个方法,后面我会贴出这个文件的代码,供参考。  
  65.  $is_success$notify->IsSuccess();   
  66.  $bdata$is_success’data’];   
  67.  //支付成功  
  68.  if$is_success’code’] == 1){   
  69.  $news(  
  70.   ‘touser’$bdata’openid’],  
  71.   ‘msgtype’‘news’,  
  72.   ‘news’ (  
  73.   ‘articles’ (  
  74.    array(  
  75.    ‘title’‘订单支付成功’,  
  76.    ‘description’“支付金额:{$bdata[‘total_fee’]}\n”.  
  77.    “微信订单号:{$bdata[‘transaction_id’]}\n”  
  78.    ‘picurl’”,  
  79.    ‘url’”   
  80.    )  
  81.   
  82.   )  
  83.   )  
  84.  );  
  85.  //发送微信支付通知  
  86.  $this$news);   
  87.  }else//支付失败  
  88.   
  89.  }  
  90.  }  
  91.   
  92.  /** 
  93.  * 支付成功页面 
  94.  * 不可靠的回调 
  95.  */  
  96.  public ajax_PaySuccess(){  
  97.  //订单号  
  98.  $out_trade_no‘post.out_trade_no’);  
  99.  //支付金额  
  100.  $total_fee‘post.total_fee’);  
  101.  /*相关逻辑处理*/  
  102.   
  103.  }  

贴上模板HTML

[xhtml] view plain copy

 
  1. <html>  
  2. <head>  
  3.  <metahttp-equiv”content-type”content”text/html;charset=utf-8″/>  
  4.  <metaname”viewport”content”width=device-width, initial-scale=1″/>   
  5.  <title>  
  6.  <scripttype”text/javascript”>  
  7.  //调用微信JS api 支付  
  8.  function jsApiCall()  
  9.  {  
  10.  WeixinJSBridge.invoke(  
  11.  ‘getBrandWCPayRequest’,  
  12.  {$jsApiParameters},  
  13.  function(res){  
  14.  WeixinJSBridge.log(res.err_msg);  
  15.  //取消支付  
  16.  if(res.err_msg == ‘get_brand_wcpay_request:cancel’){  
  17.  //处理取消支付的事件逻辑  
  18.  }else if(res.err_msg
  19.  /*使用以上方式判断前端返回,微信团队郑重提示:  
  20.  res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。  
  21.  这里可以使用Ajax提交到后台,处理一些日志,如Test控制器里面的ajax_PaySuccess方法。  
  22.  */  
  23.  }  
  24.  alert(res.err_code+res.err_desc+res.err_msg);  
  25.  }  
  26.  );  
  27.  }  
  28.   
  29.  function callpay()  
  30.  {  
  31.  if (typeof WeixinJSBridge
  32.  if( document.addEventListener ){  
  33.  document.addEventListener(‘WeixinJSBridgeReady’, jsApiCall, false);  
  34.  }else if (document.attachEvent){  
  35.  document.attachEvent(‘WeixinJSBridgeReady’, jsApiCall);   
  36.  document.attachEvent(‘onWeixinJSBridgeReady’, jsApiCall);  
  37.  }  
  38.  }else{  
  39.  jsApiCall();  
  40.  }  
  41.  }  
  42.  //获取共享地址  
  43.  function editAddress()  
  44.  {  
  45.  WeixinJSBridge.invoke(  
  46.  ‘editAddress’,  
  47.  {$editAddress},  
  48.  function(res){  
  49.  var value1res.proviceFirstStageName;  
  50.  var value2res.addressCitySecondStageName;  
  51.  var value3res.addressCountiesThirdStageName;  
  52.  var value4res.addressDetailInfo;  
  53.  var telres.telNumber;   
  54.  alert(value1 + value2 + value3 + value4 + “:” + tel);  
  55.  }  
  56.  );  
  57.  }  
  58.   
  59.  window.onloadfunction(){  
  60.  if (typeof WeixinJSBridge
  61.  if( document.addEventListener ){  
  62.  document.addEventListener(‘WeixinJSBridgeReady’, editAddress, false);  
  63.  }else if (document.attachEvent){  
  64.  document.attachEvent(‘WeixinJSBridgeReady’, editAddress);   
  65.  document.attachEvent(‘onWeixinJSBridgeReady’, editAddress);  
  66.  }  
  67.  }else{  
  68.  editAddress();  
  69.  }  
  70.  };  
  71.   
  72.  </script>  
  73. </head>  
  74. <body>  
  75.  <br/>  
  76.  <fontcolor”#9ACD32″><b> style”color:#f00;font-size:50px”></b></font><br/><br/>  
  77.  <divalign”center”>  
  78.  <buttonstyle”width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;”type”button”onclick”callpay()”立即支付</button>  
  79.  </div>  
  80. </body>  
  81. </html>  

notify.php文件代码,这里有在官方文件里新添加的一个自定义方法。

[php] view plain copy

 
  1. require_once“Api/lib/WxPay.Api.php”;  
  2. require_once‘Api/lib/WxPay.Notify.php’;  
  3. require_once‘Api/lib/log.php’;  
  4.   
  5. //初始化日志  
  6. $logHandler \CLogFileHandler(ROOT_PATH.”/logs/”‘Y-m-d”.log’);  
  7. $log$logHandler, 15);  
  8.   
  9. class WxPayNotify  
  10. {  
  11.  protected$para(‘code’‘data’”);  
  12.  //查询订单  
  13.  public Queryorder($transaction_id)  
  14.  {  
  15.  $input \WxPayOrderQuery();  
  16.  $input$transaction_id);  
  17.  $result$input);  
  18.  \Log::DEBUG(“query:”$result));  
  19.  if“return_code”$result)  
  20.  && “result_code”$result)  
  21.  && $result”return_code”“SUCCESS”  
  22.  && $result”result_code”“SUCCESS”)  
  23.  {  
  24.  return true;  
  25.  }  
  26.  $this‘code’] = 0;  
  27.  $this‘data’”;  
  28.  return false;  
  29.  }  
  30.   
  31.  //重写回调处理函数  
  32.  public NotifyProcess($data$msg)  
  33.  {  
  34.  \Log::DEBUG(“call back:”$data));  
  35.  $notfiyOutput();  
  36.   
  37.  if“transaction_id”$data)){  
  38.  $msg“输入参数不正确”;  
  39.  $this‘code’] = 0;  
  40.  $this‘data’”;  
  41.  return false;  
  42.  }  
  43.  //查询订单,判断订单真实性  
  44.  if$this$data”transaction_id”])){  
  45.  $msg“订单查询失败”;  
  46.  $this‘code’] = 0;  
  47.  $this‘data’”;  
  48.  return false;  
  49.  }  
  50.   
  51.  $this‘code’] = 1;  
  52.  $this‘data’$data;  
  53.  return true;  
  54.  }  
  55.   
  56.  /** 
  57.  * 自定义方法 检测微信端是否回调成功方法 
  58.  * @return multitype:number string 
  59.  */  
  60.  public IsSuccess(){  
  61.  return$this->para;  
  62.  }  
  63. }  

到这里基本上完成,可以在微信端打开http://test.paywechat.com/Charge/index.php/Test/index/
我的环境,HTTP服务器没有重写url,微信支付继续探索中,有些地方可能写的有问题或不足,望大家谅解,互相学习。


版权声明:本文为Alvin大神原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/alvin123/p/16179711.html