thinkphp微信瀏覽器內拉起微信支付

 

vendor/wxpay/pay.php
<?php
/*
+-----------------------------------+
| 微信支付類 |
+-----------------------------------+
*/
require_once 'config.php';

class pay{

  public $params = array();
  private $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
  private $prepay_id; //統一下單號

  /**
  *
  * 獲取jsapi支付的參數
  * @param array $UnifiedOrderResult 統一支付接口返回的數據
  * @throws WxPayException
  * @return json數據,可直接填入js函數做爲參數
  */
  public function GetJsApiParameters()
  {
    $this->doneOrder();
    $timeStamp = time();
    $this->params = array(
      'appId' => Config::APPID,
      'timeStamp'=> "$timeStamp",
      'nonceStr' => $this->getNonceStr(),
      'package' => 'prepay_id=' . $this->prepay_id,
      'signType' => 'MD5'
    );
    $this->params['paySign'] = $this->MakeSign();
  }

  /**
  * 統一下單
  * @return array
  */
  public function doneOrder(){
    $this->params['mch_id'] = Config::MCHID;
    $this->params['appid'] = Config::APPID;
    $this->params['sign'] = $this->MakeSign($this->params);
    $response = $this->FromXml($this->postXmlCurl($this->ToXml(), $this->url, false));
    $this->prepay_id = $response['prepay_id'];

  }

  /**
  * 驗證
  * @return array 返回數組格式的notify數據
  */
  public function notify(){
    //獲取xml
    $xml = file_get_contents('php://input');
    //轉成php數組
    $this->params = $this->FromXml($xml);
    //保存原sign
    $data_sign = $this->params['sign'];
    //sign不參與簽名
    unset($this->params['sign']);
    $sign = $this->makeSign();
    //判斷簽名是否正確 判斷支付狀態
    if ($sign===$data_sign && $this->params['return_code']=='SUCCESS' && $this->params['result_code']=='SUCCESS') {
      $result = $this->params;
      $str = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
    }else{
      $result = false;
      $str = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[簽名失敗]]></return_msg></xml>';
    }
    echo $str;
    return $result;
  }


  /**
  * 生成簽名
  * @return 簽名,本函數不覆蓋sign成員變量,如要設置簽名須要調用SetSign方法賦值
  */
  public function MakeSign()
  {
    //簽名步驟一:按字典序排序參數
    ksort($this->params);
    $string = $this->ToUrlParams();
    //簽名步驟二:在string後加入KEY
    $string = $string . '&key=' . Config::KEY;
    //簽名步驟三:MD5加密
    $string = md5($string);
    //簽名步驟四:全部字符轉爲大寫
    $result = strtoupper($string);
    return $result;
  }

  /**
  * 格式化參數格式化成url參數
  */
  public function ToUrlParams()
  {
    $buff = '';
    foreach($this->params as $k => $v)
    {
      if($k!='sign' && $v!='' && !is_array($v)){
        $buff .= $k . '=' . $v . '&';
      }
    }
    $buff = trim($buff, '&');
    return $buff;
  }

  /**
  * 以post方式提交xml到對應的接口url
  * @param string $xml 須要post的xml數據
  * @param string $url url
  * @param bool $useCert 是否須要證書,默認不須要
  * @param int $second url執行超時時間,默認30s
  * @throws WxPayException
  */
  private static function postXmlCurl($xml, $url, $useCert = false, $second = 30)
  {
    $ch = curl_init();
    //設置超時
    curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    //若是有配置代理這裏就設置代理
    if(Config::CURL_PROXY_HOST != "0.0.0.0" && Config::CURL_PROXY_PORT != 0){
      curl_setopt($ch,CURLOPT_PROXY, Config::CURL_PROXY_HOST);
      curl_setopt($ch,CURLOPT_PROXYPORT, Config::CURL_PROXY_PORT);
    }
    curl_setopt($ch,CURLOPT_URL, $url);
    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
    curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);//嚴格校驗
    //設置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, Config::SSLCERT_PATH);
      curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
      curl_setopt($ch,CURLOPT_SSLKEY, Config::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);
      throw new Exception("curl出錯,錯誤碼:$error");
    }
  }

  /**
  * 輸出xml字符
  * @throws WxPayException
  **/
  public function ToXml()
  {
    if(!is_array($this->params) || count($this->params) <= 0)
    {
      throw new Exception('數組數據異常!');
    }
    $xml = '<xml>';
    foreach($this->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
  * @throws WxPayException
  */
  public function FromXml($xml)
  {
    if(!$xml){
      throw new Exception('xml數據異常!');
    }
    //將XML轉爲array
    //禁止引用外部xml實體
    libxml_disable_entity_loader(true);
    $this->params = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    return $this->params;
  }

  /**
  *
  * 產生隨機字符串,不長於32位
  * @param int $length
  * @return 產生的隨機字符串
  */
  public function getNonceStr($length = 32)
  {
    $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
    $str = '';
    for($i = 0; $i<$length; $i++){
      $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
    }
    return $str;
  }
}
?>
 
 

  

 vendor/wxpay/config.php
<?php
/**
* 配置帳號信息
*/

class Config
{
//=======【基本信息設置】=====================================
//
/**
* TODO: 修改這裏配置爲您本身申請的商戶信息
* 微信公衆號信息配置
*
* APPID:綁定支付的APPID(必須配置,開戶郵件中可查看)
*
* MCHID:商戶號(必須配置,開戶郵件中可查看)
*
* KEY:商戶支付密鑰,參考開戶郵件設置(必須配置,登陸商戶平臺自行設置)
* 設置地址:https://pay.weixin.qq.com/index.php/account/api_cert
*
* APPSECRET:公衆賬號secert(僅JSAPI支付的時候須要配置, 登陸公衆平臺,進入開發者中心可設置),
* 獲取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
* @var string
*/
const APPID = 'wx000000000000';
const MCHID = 'xxxxxxx';
const KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx';
const APPSECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

//=======【證書路徑設置】=====================================
  /**
  * TODO:設置商戶證書路徑
  * 證書路徑,注意應該填寫絕對路徑(僅退款、撤銷訂單時須要,可登陸商戶平臺下載,
  * API證書下載地址:https://pay.weixin.qq.com/index.php/account/api_cert,下載以前須要安裝商戶操做證書)
  * @var path
  */
  const SSLCERT_PATH = 'cert/apiclient_cert.pem';
  const SSLKEY_PATH = 'cert/apiclient_key.pem';

//=======【curl代理設置】===================================
  /**
  * TODO:這裏設置代理機器,只有須要代理的時候才設置,不須要代理,請設置爲0.0.0.0和0
  * 本例程經過curl使用HTTP POST方法,此處可修改代理服務器,
  * 默認CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此時不開啓代理(若有須要才設置)
  * @var unknown_type
  */
  const CURL_PROXY_HOST = "0.0.0.0";//"10.152.18.220";
  const CURL_PROXY_PORT = 0;//8080;

//=======【上報信息配置】===================================
  /**
  * TODO:接口調用上報等級,默認緊錯誤上報(注意:上報超時間爲【1s】,上報不管成敗【永不拋出異常】,
  * 不會影響接口調用流程),開啓上報以後,方便微信監控請求調用的質量,建議至少
  * 開啓錯誤上報。
  * 上報等級,0.關閉上報; 1.僅錯誤出錯上報; 2.全量上報
  * @var int
  */
  const REPORT_LEVENL = 0;
}
 
 

  

 vendor/cert/apiclient_cert.pem vendor/cert/apiclient_key.pem 控制器Controller
Vendor('wechat.pay');

class Wechat extends Base
{
  public function wxPay(){
    $payobj = new \pay();    
    $openid    = input('post.openid/s'); 
    $needMoney = input('post.money/s');   
    if (!empty($openid)) {
      //統一下單
      $orderid = $this->build_order_no();
      $notify_url = 'http://xxxxxx/Wechat/notify';

      $payobj->params = [
        'openid' => $openid,
        'body' => 'body',
        'out_trade_no' => $orderid,
        'total_fee' => $needMoney * 100, 
        'nonce_str' => $this->getNonceStr(),
        'spbill_create_ip' => getIp(),
        'notify_url' => $notify_url,
        'trade_type' => 'JSAPI'
      ];

      $payobj->GetJsApiParameters();
      $data = [
        'order_num' => $orderid,
        'user_open_id' => $openid,
        'pay_money' => $needMoney,
      ];
   

      $oid = Db::name('order_pay')->insert($data);
      if($oid){
        return ['status'=>'0','info'=>'ok','data'=>json_encode($payobj->params)];
      }
      return ['status'=>'-1','info'=>'下單失敗,請重試'];

    }
  }

  //微信支付回調
  public function notify(){ 
    $payobj = new \pay();
    $result = $payobj->notify();
    if($result){
      //成功後回調
      $where['order_num'] = $result['out_trade_no'];
      //根據需求處理邏輯

    }
  }


  

  /**
  * 生成訂單號碼
  * @return string
  */
  public function build_order_no() {
    return date('Ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 6), 1))), 0, 8) . mt_rand(100,999);
  }

  /**
  * 產生隨機字符串,不長於32位
  * @param int $length
  * @return 產生的隨機字符串
  */
  public function getNonceStr($length = 32) {
    $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
    $str = '';
    for($i = 0; $i<$length; $i++){
      $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
    }
    return $str;
  }

}
 
 

  

 頁面上View 引用jquery; 引用layui.js 引用jweixin-1.1.0.js
<script type="text/javascript">

  $.ajax({
    url:"http://xxxxxx/Wechat/wxPay",
    type:'post',
    data:{'money':money,'openid':openid},
    async : false,
    dataType: "JSON",
    success:function(data){
      if(data.status === '0'){
        var params = $.parseJSON(data.data);
        // alert(data.url);
        WeixinJSBridge.invoke('getBrandWCPayRequest', params, function(res){
          if(res.err_msg == 'get_brand_wcpay_request:cancel'){
            layer.open({
              content: '您消了這次支付'
              ,skin: 'msg'
              ,time: 5 //2秒後自動關閉
            });
          }else if(res.err_msg == 'get_brand_wcpay_request:fail'){
            layer.open({
              content: '支付失敗,請從新支付'
              ,skin: 'msg'
              ,time: 5 //2秒後自動關閉
            });
          }else if(res.err_msg == 'get_brand_wcpay_request:ok'){
            layer.open({
              content: '支付成功'
              ,skin: 'msg'
              ,time: 5 //2秒後自動關閉
            });
            setTimeout(function(){
              window.location.href = 'index.html';
            },2000);
          }else{
            layer.open({
              content: "未知錯誤"+res.error_msg
              ,skin: 'msg'
              ,time: 5 //2秒後自動關閉
            });
          }
        });
    }else{
      layer.open({
        content: data.info
        ,skin: 'msg'
        ,time: 5 //2秒後自動關閉
      });
      return false;
    }
  }
});

</script>

 

相關文章
相關標籤/搜索