欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PHP JSAPI調(diào)支付API實(shí)現(xiàn)微信支付功能詳解

 更新時(shí)間:2022年11月17日 09:50:48   作者:一本曾經(jīng)  
本人最近做了微信支付開(kāi)發(fā),是第一次接觸,其中走了很多彎路,遇到的問(wèn)題也很多。為了讓和我一樣的新人不再遇到類(lèi)似的問(wèn)題,我把我的開(kāi)發(fā)步驟和問(wèn)題寫(xiě)出來(lái)以供參考,這篇文章主要介紹了PHP JSAPI調(diào)支付API實(shí)現(xiàn)微信支付功能

一、首先我們來(lái)填個(gè)坑

支付驗(yàn)簽失敗

這個(gè)問(wèn)題折磨了我兩天,官方文檔比較含糊不清。各種百度下來(lái)的方法試過(guò)之后也不盡人意,最后發(fā)現(xiàn)問(wèn)題是沒(méi)有二次簽名

二次簽名需要參數(shù)(代碼會(huì)展示在哪里二次簽名):

appId:      商戶(hù)申請(qǐng)的公眾號(hào)對(duì)應(yīng)的appid(I大寫(xiě))

nonceStr: 隨機(jī)字符串(注意是JSAPI下單接口中返回的 nonce_str、不是重新生成)

package:  統(tǒng)一下單接口返回的prepay_id參數(shù)值 ,(注意格式prepay_id=wx.....)

signType: 簽名類(lèi)型、(官方文檔)僅支持RSA。

(我的簽名類(lèi)型是 HMAC-SHA256 也是可以的,必須和下單使用的簽名類(lèi)型保持一致)

timeStamp:時(shí)間戳(這里要把 time() 轉(zhuǎn)成字符串類(lèi)型)

注明:使用這五個(gè)參數(shù)生成的 paySign 簽名才是需要返給前端的(

官方文檔實(shí)例要計(jì)算簽名也給我整的蒙圈,最后發(fā)現(xiàn)直接將五個(gè)必須參數(shù)生成的簽名返給前端就可以直接調(diào)取API了

二、代碼示例

1.請(qǐng)求參數(shù)配置

		$oInput    = [
			'body'         => '測(cè)試商品',          // 商品說(shuō)明                                                
			'attach'       => '測(cè)試場(chǎng)景',          // 自定義參數(shù):可以用來(lái)做回調(diào)后場(chǎng)景區(qū)分                                             
			'out_trade_no' => '測(cè)試單號(hào)' . time(), // 自定義訂單號(hào)                                       
			'total_fee'    => 1 * 100,           // 付款金額:記得*100 微信官方是以分為單位                                           
			'goods_tag'    => '',                // 優(yōu)惠券相關(guān)參數(shù)                                   
			'notify_url'   => 'http://...',     // 回調(diào)通知地址
			'trade_type'   => 'JSAPI',          // 支付方式                                        
			'openid'       => $openid,          // 付款用戶(hù)openid   
            // 'profit_sharing' => 'Y',         // 是否分賬的標(biāo)識(shí)                                                                                                                              
		];
		$res = $this->unifiedOrder($oInput);     // 這里我調(diào)用的統(tǒng)一下單
		return $res;                             // 返給前端帶APPID等參數(shù)給前端去調(diào)用支付

2.統(tǒng)一下單API

	public function unifiedOrder($inputObj, $timeOut = 6)
	{
		$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		// 首次簽名參數(shù)
		$oValues = [
			'body' 				=> $inputObj['body'],				// 設(shè)置商品或支付單簡(jiǎn)要描述
			'attach' 			=> $inputObj['attach'],				// 設(shè)置附加數(shù)據(jù),用于商戶(hù)攜帶訂單的自定義數(shù)據(jù)
			'out_trade_no' 		=> $inputObj['out_trade_no'], 		// 設(shè)置商戶(hù)系統(tǒng)內(nèi)部的訂單號(hào),transaction_id、out_trade_no二選一,如果同時(shí)存在優(yōu)先級(jí):transaction_id> out_trade_no
			'total_fee' 		=> $inputObj['total_fee'], 			// 設(shè)置訂單總金額,只能為整數(shù),單位:分
			'time_start' 		=> date("YmdHis"), 					// 設(shè)置訂單生成時(shí)間
			'time_expire' 		=> date("YmdHis", time() + 600), 	// 設(shè)置訂單失效時(shí)間
			'goods_tag' 		=> $inputObj['goods_tag'], 			// 設(shè)置商品標(biāo)記,代金券或立減優(yōu)惠功能的參數(shù)
			'notify_url' 		=> $inputObj['notify_url'], 		// 獲取接收微信支付異步通知回調(diào)地址的值
			'trade_type' 		=> $inputObj['trade_type'], 		// JSAPI,NATIVE,APP
			'openid' 			=> $inputObj['openid'], 			// 用戶(hù)在商戶(hù)appid下的唯一標(biāo)識(shí)
			//'profit_sharing' 	=> $inputObj['profit_sharing'],		// 是否需要分賬
			'appid' 			=> 'appid', 			            // app_id:替換真實(shí)的
			'mch_id' 			=> 'mchid', 			            // 商戶(hù)號(hào):替換真實(shí)的
			'spbill_create_ip' 	=> $_SERVER['REMOTE_ADDR'], 		// 終端ip
			'nonce_str' 		=> '自定義生成', 			        // 隨機(jī)32位字符串
			'sign_type' 		=> 'HMAC-SHA256', 					// 簽名類(lèi)型,自行替換
		];
		// 首次簽名
		ksort($oValues);
		$oValues['sign'] = $this->MakeSign($oValues); 		// 調(diào)用簽名
		$xml = $this->ToXml($oValues);                      // 數(shù)字轉(zhuǎn)xml類(lèi)型
		$response = self::postXmlCurl($xml, $url, false, $timeOut); // 請(qǐng)求
		$result   = $this->FromXml($response);              // 請(qǐng)求結(jié)果從xml轉(zhuǎn)成數(shù)組類(lèi)型
        // 二次簽名參數(shù)
		$oResult    = [
			'appId'     => $result['appid'],                   // 首次請(qǐng)求中的appid
			'nonceStr'  => $result['nonce_str'],               // 首次請(qǐng)求中的nonce_str
			'package'   => 'prepay_id=' . $result['prepay_id'],// 首次請(qǐng)求中的prepay_id
			'signType'  => 'HMAC-SHA256',   // 跟首次簽名中的簽名類(lèi)型參數(shù)保持一致
			'timeStamp' => (string)(time()),// 時(shí)間戳轉(zhuǎn)字符串類(lèi)型
		];
        // 二次簽名
		$oResult['paySign'] = $this->MakeSign($oResult);    // 調(diào)用簽名
		$result = json_encode($oResult); // encode數(shù)組
		return $result;                  // 直接返回
	}

3.MakeSign 簽名

	/**
	 * 生成簽名
	 * @param bool $needSignType  是否需要補(bǔ)signtype
	 * @return 簽名,本函數(shù)不覆蓋sign成員變量,如要設(shè)置簽名需要調(diào)用SetSign方法賦值
	 */
	public function MakeSign($values, $needSignType = true)
	{
		if ($needSignType) {
			$sSignType = 'HMAC-SHA256'; // 可以在文檔開(kāi)頭用枚舉定義: 所有簽名類(lèi)型必須一致
		}
		$sKey = 'key';                   // 獲取支付參數(shù)key
		// 簽名步驟一:按字典序排序參數(shù)
		ksort($values);
		$string = $this->ToUrlParams($values);
		// 簽名步驟二:在string后加入KEY
		$string = $string . "&key=" . $sKey;
		// 簽名步驟三:MD5加密或者HMAC-SHA256
		if ($sSignType == "MD5") {
			$string = md5($string);
		} else if ($sSignType == "HMAC-SHA256") {
			$string = hash_hmac("sha256", $string, $sKey);
		} else {
			return "簽名類(lèi)型不支持!";
		}
		// 簽名步驟四:所有字符轉(zhuǎn)為大寫(xiě)
		$result = strtoupper($string);
		return $result;
	}

4.ToXml 數(shù)組參數(shù)轉(zhuǎn)xml

	public function ToXml($values)
	{
		if (!is_array($values) || count($values) <= 0) {
			return "數(shù)組數(shù)據(jù)異常!";
		}
		$xml = "<xml>";
		foreach ($values as $key => $val) {
			if (is_numeric($val)) {
				$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
			} else {
				$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
			}
		}
		$xml .= "</xml>";
		return $xml;
	}

5.postXmlCurl 發(fā)送請(qǐng)求

	/**
	 * 以post方式提交xml到對(duì)應(yīng)的接口url
	 * 
	 * @param WxPayConfigInterface $config  配置對(duì)象
	 * @param string 	$xml  		需要post的xml數(shù)據(jù)
	 * @param string 	$url  		url
	 * @param bool 		$useCert 	是否需要證書(shū),默認(rèn)不需要
	 * @param int 		$second   	url執(zhí)行超時(shí)時(shí)間,默認(rèn)30s
	 */
	private function postXmlCurl($xml, $url, $useCert = false, $second = 30)
	{
		$ch 			= curl_init();
		$curlVersion 	= curl_version();
		$ua 			= "WXPaySDK/" . self::VERSION . " (" . PHP_OS . ") PHP/" . PHP_VERSION . " CURL/" . $curlVersion['version'] . " " . $aWxpayParam['mchid'];
		//設(shè)置超時(shí)
		curl_setopt($ch, CURLOPT_TIMEOUT, $second);
		$proxyHost = "0.0.0.0";
		$proxyPort = 0;
		// 如果有配置代理這里就設(shè)置代理
		if ($proxyHost != "0.0.0.0" && $proxyPort != 0) {
			curl_setopt($ch, CURLOPT_PROXY, $proxyHost);
			curl_setopt($ch, CURLOPT_PROXYPORT, $proxyPort);
		}
		curl_setopt($ch, CURLOPT_URL, $url);
		// curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
		// curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//嚴(yán)格校驗(yàn)
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //嚴(yán)格校驗(yàn)
		curl_setopt($ch, CURLOPT_USERAGENT, $ua);
		// 設(shè)置header
		curl_setopt($ch, CURLOPT_HEADER, FALSE);
		// 要求結(jié)果為字符串且輸出到屏幕上
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
		if ($useCert == true) {
			// 設(shè)置證書(shū)
			// 使用證書(shū):cert 與 key 分別屬于兩個(gè).pem文件
			// 證書(shū)文件請(qǐng)放入服務(wù)器的非web目錄下
			$sslCertPath 	= 'sslCertPath';        // 證書(shū)路徑
			$sslKeyPath 	= 'sslKeyPath';         // 證書(shū)路徑
			curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
			curl_setopt($ch, CURLOPT_SSLCERT, $sslCertPath);
			curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
			curl_setopt($ch, CURLOPT_SSLKEY, $sslKeyPath);
		}
		// post提交方式
		curl_setopt($ch, CURLOPT_POST, TRUE);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
		// 運(yùn)行curl
		$data = curl_exec($ch);
		// 返回結(jié)果
		if ($data) {
			curl_close($ch);
			return $data;
		} else {
			$error = curl_errno($ch);
			curl_close($ch);
			throw new WxPayException("curl出錯(cuò),錯(cuò)誤碼:$error");
		}
	}

6.FromXml 結(jié)果xml參數(shù)轉(zhuǎn)數(shù)組

	/**
	 * 將xml轉(zhuǎn)為array
	 * @param string $xml
	 * @throws WxPayException
	 */
	public function FromXml($xml)
	{
		if (!$xml) {
			return "xml數(shù)據(jù)異常!";
		}
		//將XML轉(zhuǎn)為array
		//禁止引用外部xml實(shí)體
		libxml_disable_entity_loader(true);
		$res = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
		return $res;
	}

總結(jié)

注意統(tǒng)一下單中五個(gè)調(diào)用方法別忘了:

getNonceStr:我沒(méi)貼出來(lái),這個(gè)要自己寫(xiě)(0.0)

MakeSign: 這里面的key要記得替換成自己真實(shí)的參數(shù)

ToXml

postXmlCurl : 注意這里面的證書(shū)要改成自己真實(shí)的哈

FromXml

到此這篇關(guān)于PHP JSAPI調(diào)支付API實(shí)現(xiàn)微信支付功能詳解的文章就介紹到這了,更多相關(guān)PHP微信支付內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論