PHP與微信公眾號支付

2022-01-13 PHP開源社區

<?php
class WxpayService
{
 protected $mchid;
 protected $appid;
 protected $appKey;
 protected $apiKey;
 public $data = null;

 public function __construct($mchid, $appid, $appKey,$key)
 {
  $this->mchid = $mchid; //https://pay.weixin.qq.com 產品中心-開發配置-商戶號
  $this->appid = $appid; //微信支付申請對應的公眾號的APPID
  $this->appKey = $appKey; //微信支付申請對應的公眾號的APP Key
  $this->apiKey = $key; //https://pay.weixin.qq.com 帳戶設置-安全設置-API安全-API密鑰-設置API密鑰
 }

 /**
  * 通過跳轉獲取用戶的openid,跳轉流程如下:
  * 1、設置自己需要調回的url及其其他參數,跳轉到微信伺服器https://open.weixin.qq.com/connect/oauth2/authorize
  * 2、微信服務處理完成之後會跳轉回用戶redirect_uri地址,此時會帶上一些參數,如:code
  * @return 用戶的openid
  */
 public function GetOpenid()
 {
  //通過code獲得openid
  if (!isset($_GET['code'])){
   //觸發微信返回code碼
   $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
   $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
   $url = $this->__CreateOauthUrlForCode($baseUrl);
   Header("Location: $url");
   exit();
  } else {
   //獲取code碼,以獲取openid
   $code = $_GET['code'];
   $openid = $this->getOpenidFromMp($code);
   return $openid;
  }
 }

 /**
  * 通過code從工作平臺獲取openid機器access_token
  * @param string $code 微信跳轉回來帶上的code
  * @return openid
  */
 public function GetOpenidFromMp($code)
 {
  $url = $this->__CreateOauthUrlForOpenid($code);
  $res = self::curlGet($url);
  //取出openid
  $data = json_decode($res,true);
  $this->data = $data;
  $openid = $data['openid'];
  return $openid;
 }

 /**
  * 構造獲取open和access_toke的url地址
  * @param string $code,微信跳轉帶回的code
  * @return 請求的url
  */
 private function __CreateOauthUrlForOpenid($code)
 {
  $urlObj["appid"] = $this->appid;
  $urlObj["secret"] = $this->appKey;
  $urlObj["code"] = $code;
  $urlObj["grant_type"] = "authorization_code";
  $bizString = $this->ToUrlParams($urlObj);
  return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
 }

 /**
  * 構造獲取code的url連接
  * @param string $redirectUrl 微信伺服器回跳的url,需要url編碼
  * @return 返回構造好的url
  */
 private function __CreateOauthUrlForCode($redirectUrl)
 {
  $urlObj["appid"] = $this->appid;
  $urlObj["redirect_uri"] = "$redirectUrl";
  $urlObj["response_type"] = "code";
  $urlObj["scope"] = "snsapi_base";
  $urlObj["state"] = "STATE"."#wechat_redirect";
  $bizString = $this->ToUrlParams($urlObj);
  return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
 }

 /**
  * 拼接籤名字符串
  * @param array $urlObj
  * @return 返回已經拼接好的字符串
  */
 private function ToUrlParams($urlObj)
 {
  $buff = "";
  foreach ($urlObj as $k => $v)
  {
   if($k != "sign") $buff .= $k . "=" . $v . "&";
  }
  $buff = trim($buff, "&");
  return $buff;
 }

 /**
  * 統一下單
  * @param string $openid 調用【網頁授權獲取用戶信息】接口獲取到用戶在該公眾號下的Openid
  * @param float $totalFee 收款總費用 單位元
  * @param string $outTradeNo 唯一的訂單號
  * @param string $orderName 訂單名稱
  * @param string $notifyUrl 支付結果通知url 不要有問號
  * @param string $timestamp 支付時間
  * @return string
  */
 public function createJsBizPackage($openid, $totalFee, $outTradeNo, $orderName, $notifyUrl, $timestamp)
 {
  $config = array(
   'mch_id' => $this->mchid,
   'appid' => $this->appid,
   'key' => $this->apiKey,
  );
  $orderName = iconv('GBK','UTF-8',$orderName);
  $unified = array(
   'appid' => $config['appid'],
   'attach' => 'pay',    //商家數據包,原樣返回,如果填寫中文,請注意轉換為utf-8
   'body' => $orderName,
   'mch_id' => $config['mch_id'],
   'nonce_str' => self::createNonceStr(),
   'notify_url' => $notifyUrl,
   'openid' => $openid,   //rade_type=JSAPI,此參數必傳
   'out_trade_no' => $outTradeNo,
   'spbill_create_ip' => '127.0.0.1',
   'total_fee' => intval($totalFee * 100),  //單位 轉為分
   'trade_type' => 'JSAPI',
  );
  $unified['sign'] = self::getSign($unified, $config['key']);
  $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', self::arrayToXml($unified));
  $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
  if ($unifiedOrder === false) {
   die('parse xml error');
  }
  if ($unifiedOrder->return_code != 'SUCCESS') {
   die($unifiedOrder->return_msg);
  }
  if ($unifiedOrder->result_code != 'SUCCESS') {
   die($unifiedOrder->err_code);
  }
  $arr = array(
   "appId" => $config['appid'],
   "timeStamp" => "$timestamp",  //這裡是字符串的時間戳,不是int,所以需加引號
   "nonceStr" => self::createNonceStr(),
   "package" => "prepay_id=" . $unifiedOrder->prepay_id,
   "signType" => 'MD5',
  );
  $arr['paySign'] = self::getSign($arr, $config['key']);
  return $arr;
 }

 public static function curlGet($url = '', $options = array())
 {
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  if (!empty($options)) {
   curl_setopt_array($ch, $options);
  }
  //https請求 不驗證證書和host
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  $data = curl_exec($ch);
  curl_close($ch);
  return $data;
 }

 public static function curlPost($url = '', $postData = '', $options = array())
 {
  if (is_array($postData)) {
   $postData = http_build_query($postData);
  }
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
  curl_setopt($ch, CURLOPT_TIMEOUT, 30); //設置cURL允許執行的最長秒數
  if (!empty($options)) {
   curl_setopt_array($ch, $options);
  }
  //https請求 不驗證證書和host
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  $data = curl_exec($ch);
  curl_close($ch);
  return $data;
 }

 public static function createNonceStr($length = 16)
 {
  $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $str = '';
  for ($i = 0; $i < $length; $i++) {
   $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  }
  return $str;
 }
 public static 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>";
  file_put_contents('1.txt',$xml);
  return $xml;
 }

 public static function getSign($params, $key)
 {
  ksort($params, SORT_STRING);
  $unSignParaString = self::formatQueryParaMap($params, false);
  $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
  return $signStr;
 }
 protected static function formatQueryParaMap($paraMap, $urlEncode = false)
 {
  $buff = "";
  ksort($paraMap);
  foreach ($paraMap as $k => $v) {
   if (null != $v && "null" != $v) {
    if ($urlEncode) {
     $v = urlencode($v);
    }
    $buff .= $k . "=" . $v . "&";
   }
  }
  $reqPar = '';
  if (strlen($buff) > 0) {
   $reqPar = substr($buff, 0, strlen($buff) - 1);
  }
  return $reqPar;
 }
}
?>

相關焦點

  • PHP開發微信公眾號文章付費閱讀功能
    php開發微信公眾號文章付費閱讀功能!
  • 微信支付公眾號開發流程--JAVA
    chapter=9_1 部分參數,仍然不知道哪裡找的小夥伴們請繼續向下看appid ==應用ID==登陸微信公眾號後臺-開發-基本配置mch_id == 微信支付商戶號==登陸微信支付後臺,即可看到device_info==設備號==終端設備號(門店號或收銀設備ID),注意:PC網頁或公眾號內支付請傳"WEB"body==商品描述==商品或支付單簡要描述
  • (實用篇)微信支付掃碼支付php版
    createUrl.php:創建微信二維碼支付連結<?sign=XXXXX&appid=XXXXXX&productid=XXXXXX×tamp=XXXXXX&noncestr=XXXXXX * appid 是欄位名稱:公眾號id;欄位來源:商戶註冊具有支付權限的公眾號成功後即可獲得;傳入方式:由商戶直接傳入。
  • PHP微信支付開發實例​
    PHP微信支付開發過程,分享給大家,供大家參考,具體內容如下1.開發環境 Thinkphp 3.2.3 微信:服務號,已認證 開發域名:http://test.paywechat.com (自定義的域名,外網不可訪問)2.需要相關文件和權限 微信支付需申請開通
  • 微信公眾號怎麼申請微信支付
    現在做微商城大部分都是需要申請微信支付的,有很多人不是特別了解微信公眾號支付該怎麼申請才能一次性通過,接下來小編就給大家講下關於微信支付申請的一些知識
  • 用PHP搭建微信公眾號淘客三合一系統
    搭建教程:1.PHP接入微信公眾號(即php建立與公眾號通訊,並顯示通訊成功才可以) 前提伺服器資源:你需要擁有一臺公網伺服器資源(阿里雲、騰訊雲或者其他雲資源)伺服器環境:推薦使用LNMP環境,完美契合PHP
  • php實現微信和支付寶支付
    實現微信支付微信支付文檔地址:https://pay.weixin.qq.com/wiki/doc/api/index.html在php下實現微信支付,這裡我使用了EasyWeChat這裡我是在Yii框架實現的,安裝EasyWeChat插件composer
  • 如何申請開通微信公眾號支付功能
    微信支付申請前提未認證的服務號需先完成微信認證,完成服務號認證後可申請微信支付(注:商戶申請微信認證的主體與申請開通微信支付功能的主體需保持一致)微信支付開通流程(1)登陸進入微信公眾號後臺,找到「微信支付」並點擊,進入微信支付頁面,可以看到申請條件、介紹以及申明等,點擊「開通」;(2)之後進入微信支付的商戶平臺開通微信支付之「提交資料「頁面,需要填寫聯繫人姓名、手機號碼、常用郵箱、經營類目、客服電話、公司網站等信息。
  • PHP實現手機網站支付(兼容微信瀏覽器)
    網上的很多PHP支付寶支付接入教程都頗為複雜,且需要配置和引入較多的文件,本人通過整理後給出一個單文件版的,希望可以給各位想接入支付寶支付的帶來些許幫助和借鑑意義
  • 微信支付帳單說明
    針對微信支付的對帳單格式,這裡進行一下詳細的說明。
  • 微信支付之掃碼支付
    :https://pay.weixin.qq.com/wiki/doc/api/app/app.php?準備帳號公眾帳號ID(AppID)首先要申請一個公共帳號,最好申請的時候就是服務號,因為微信支付的前提必須是服務號。如果是公眾號需要先申請驗證才能升級為服務號。
  • 基於 laravel 開發微信公眾號 composer 擴展包
    ,包含 echostr 參數,之後微信伺服器與業務伺服器的交互不再包含此參數。注意命名空間為:namespace LeePrince\WeChat; 該服務提供者用於加載自定義組件中的所有服務<?
  • 【微信公眾號】微信公眾號運營及文案全攻略
    以上數據表明,中國消費者的衣食住行正向移動端深度傾斜,越來越多的人已經習慣了行動支付帶來的便利性,即便是路邊販賣小吃的大媽,也知道如何通過二維碼的掃一掃來收錢。過去20年信用卡沒有搞定的事情,微信和支付寶僅僅用了2年。但同時,瑪麗米克爾也認為,中國網際網路公司很難再從數量上獲得紅利,正如馬化騰和王興曾提到的一樣,每一個用戶的時間、活躍度和購買力變得尤為重要。
  • 微信jssdk 調用微信支付
    在微信商戶平臺(pay.weixin.qq.com)設置您的公眾號支付支付目錄,設置路徑:商戶平臺→產品中心→開發配置。公眾號支付在請求支付的時候會校驗請求來源是否有在商戶平臺做了配置,所以必須確保支付目錄已經正確的被配置,否則將驗證失敗,請求支付不成功。支付目錄配置
  • 讓蘋果「眼紅」的微信支付是這樣實現自主開發的
    支付幾乎是所有商業模式中實現閉環的必經環節,因此微信支付是微信生態中尤為重要的一個組成部分,也是近年來許多創業者願意選擇把產品第一版本的實現使用微信公眾號的原因。服務號的微信支付,按照接入的方式,可以把它們歸納為三大類:微信支付服務商、聚合支付和自主開發。下面對這三類接入方式從適用場景、模式介紹和優劣勢三個維度進行分析對比,大家可根據自身需求進行匹配選擇。
  • 微信公眾號開發系列-獲取微信OpenID
    (取消訂閱)使用網頁調試工具調試該接口掃描帶參數二維碼事件用戶掃描帶場景值二維碼時,可能推送以下兩種事件:如果用戶還未關注公眾號,則用戶可以關注公眾號,關注後微信會將帶場景值關注事件推送給開發者。點擊查看原始幫助文檔-接收事件推送2、通過第三方網頁授權方式獲取OpenID,採用第三方網頁授權(OAuth2.0授權登錄)如果用戶在微信中(Web微信除外)訪問公眾號的第三方網頁,公眾號開發者可以通過此接口獲取當前用戶基本信息(包括暱稱、性別、城市、國家)。利用用戶信息,可以實現體驗優化、用戶來源統計、帳號綁定、用戶身份鑑權等功能。
  • 如何修改公眾號名稱、暱稱、公眾號微信號、更換管理員、運營者微信號
    帳號名稱,即公眾號名稱/暱稱;微信公眾號名稱註冊後不可修改,名稱可設置3~30個字符(1個漢字算2字符)。溫馨提示:1、微信公眾號名稱不支持設置特殊符號;2、公眾號名稱不需要和公司/組織名稱一致,但是公眾號名稱不能與已註冊成功的公眾帳號名稱重複;3、目前公眾帳號沒有改名功能,可以在微信認證過程中有一次重新提交命名的機會。微信認證審核費用300元/次,認證的名稱必須符合微信認證命名規則。
  • 「山西醫保」微信公眾號正式上線!醫保微信脫卡支付也要來了……
    參保人員在關注「山西醫保」微信公眾號並綁定個人社保卡信息後,具體可實現以下功能:   一是繳費消費信息實時查詢。「山西醫保」微信公眾號提供國家和省級通過集中談判、帶量採購的抗癌靶向藥品、特殊疾病藥品的信息公共查詢服務,為群眾具體去哪家定點醫院、哪個科室乃至哪位責任醫師進行診斷,繼而確定使用何種談判藥品,並進一步查詢談判藥品的就近購買藥店提供指南。   三是網上辦理異地就醫備案。
  • (實用篇)php官方微信接口大全(微信支付、微信紅包、微信搖一搖、微信小店)
    以下是文章分享2群,由於群人數已超過300,不能掃碼進群,這個任務呢,就由小篇來拉你們進群了,掃描下面二維碼,加小篇好友~微信入口綁定,微信事件處理,微信API全部操作包含在這些文件中。內容有:微信搖一搖接口/微信多客服接口/微信支付接口/微信紅包接口/微信卡券接口/微信小店接口/JSAPI<?
  • 小程序服務端集成微信支付
    理論上集成微信支付的全部工作可以在小程序端完成,因為小程序js有訪問網絡的能力,但是為了安全,不暴露敏感key,而且可以使用官方提供的現成php demo更省力,於是在服務端完成籤名與發起請求,小程序端只做一個wx.requestPayment(OBJECT)接口的對接。整體集成過程與JSAPI、APP類似,先統一下單,然後拿返回的結果來請求支付。