古詩詞大全網 - 藝術簽名 - Thinkphp5.1微信小程序支付

Thinkphp5.1微信小程序支付

研究了好幾天,坑也遇到了,也百度了很久現在終於做完了,給大家分享出來,

我這個也是參考別人寫的。有不明白的朋友可以問我

public function unifiedorder($order_no, $openid, $total_fee, $attach, $order_id, $user_id){

// 當前時間

$time = time();

// 生成隨機字符串

$nonceStr = md5($time . $openid);

// API參數

$params = [

'appid' => $this->appid, ? //微信分配的小程序id

'attach' => $attach, ? //附加數據,在查詢API和支付通知中原樣返回,可作為自定義參數使用。

'body' => '會員卡', ? //募捐描述

'mch_id' => $this->mchid, //微信支付分配的商戶號

'nonce_str' => $nonceStr, ? //隨機字符串,32位以內

'notify_url' => $this->notify_url, // base_url() . 'notice.php?s=/task/notify/order/wxapp_id/'.$wxapp_id, // 異步通知地址

'openid' => $openid, ? //用戶標識;trade_type=JSAPI,此參數必傳,用戶在商戶appid下的唯壹標識。

'out_trade_no' => $order_no, ? //商戶賬單號

'spbill_create_ip' => \request()->ip(), //終端IP;支持IPV4和IPV6兩種格式的IP地址。調用微信支付API的機器IP

'total_fee' => (int)$total_fee * 100, // 價格:單位分 ? // 價格:單位分

'trade_type' => 'JSAPI', ? //交易類型

];

// 生成簽名

$params['sign'] = $this->makeSign($params);? //這個地方最坑,需要的是配置 1、appid和商戶號必須是綁定的狀態

// 請求API

$url = '/pay/unifiedorder';

$result = $this->post($url, $this->toXml($params));

$prepay = $this->fromXml($result);

//添加preapay_id

$data = [

'user_id' => $user_id,

'order_id' => $order_id,

'attach' => json_encode($attach),

'prepay_id' => $prepay['prepay_id'],

];

(new AppleWxPrepay())->addInfo($data);

// 請求失敗

if ($prepay['return_code'] === 'FAIL') {

return [API_CODE_NAME => 2000004, API_MSG_NAME => $prepay['return_msg']];

}

if ($prepay['result_code'] === 'FAIL') {

return [API_CODE_NAME => 2000004, API_MSG_NAME => $prepay['err_code_des']];

}

// 生成 nonce_str 供前端使用

$paySign = $this->makePaySign($params['nonce_str'], $prepay['prepay_id'], $time);

return [

'prepay_id' => $prepay['prepay_id'],

'nonceStr' => $nonceStr,

'timeStamp' => (string)$time,

'paySign' => $paySign

];

}

/**

* 生成簽名

* @param $values

* @return string 本函數不覆蓋sign成員變量,如要設置簽名需要調用SetSign方法賦值

*/

private function makeSign($values)

{

//簽名步驟壹:按字典序排序參數

ksort($values);

$string = $this->toUrlParams($values);

//簽名步驟二:在string後加入KEY

$string = $string . '&key=' . $this->apikey;

//簽名步驟三:MD5加密

$string = md5($string);

//簽名步驟四:所有字符轉為大寫

$result = strtoupper($string);

return $result;

}

/**

* 格式化參數格式化成url參數

* @param $values

* @return string

*/

private function toUrlParams($values)

{

$buff = '';

foreach ($values as $k => $v) {

if ($k != 'sign' && $v != '' && !is_array($v)) {

$buff .= $k . '=' . $v . '&';

}

}

return trim($buff, '&');

}

/**

* 模擬POST請求

* @param $url

* @param array $data

* @param bool $useCert

* @param array $sslCert

* @return mixed

*/

public function post($url, $data = [], $useCert = false, $sslCert = [])

{

$header = [

'Content-type: application/json; charset=UTF8'

];

$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_HTTPHEADER, $header);

curl_setopt($curl, CURLOPT_HEADER, false);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($curl, CURLOPT_POST, TRUE);

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

if ($useCert == true) {

// 設置證書:cert 與 key 分別屬於兩個.pem文件

curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');

curl_setopt($curl, CURLOPT_SSLCERT, $sslCert['certPem']);

curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');

curl_setopt($curl, CURLOPT_SSLKEY, $sslCert['keyPem']);

}

$result = curl_exec($curl);

curl_close($curl);

return $result;

}

/**

* 輸出xml字符

* @param $values

* @return bool|string

*/

private function toXml($values)

{

if (!is_array($values) || count($values) <= 0) {

return false;

}

$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;

}

/**

* 將xml轉為array

* @param $xml

* @return mixed

*/

private function fromXml($xml)

{

// 禁止引用外部xml實體

libxml_disable_entity_loader(true);

return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

}

/**

* 生成paySign

* @param $nonceStr

* @param $prepay_id

* @param $timeStamp

* @return string

*/

private function makePaySign($nonceStr, $prepay_id, $timeStamp)

{

$data = [

'appId' => $this->appid,

'nonceStr' => $nonceStr,

'package' => 'prepay_id=' . $prepay_id,

'signType' => 'MD5',

'timeStamp' => $timeStamp,

];

// 簽名步驟壹:按字典序排序參數

ksort($data);

$string = $this->toUrlParams($data);

// 簽名步驟二:在string後加入KEY

$string = $string . '&key=' . $this->apikey;

// 簽名步驟三:MD5加密

$string = md5($string);

// 簽名步驟四:所有字符轉為大寫

$result = strtoupper($string);

return $result;

}

/*********************************微信回調**********************/

public function getNotify()

{

if (!$xml = file_get_contents('php://input')) {

$this->returnCode(50000001, 'Not found DATA');

}

// 將服務器返回的XML數據轉化為數組

$data = $this->fromXml($xml);

$payLog = new ApplePayLog();

// 記錄日誌

$payLog->addInfo(['content'=>json_encode($xml)]);

$payLog->addInfo(['content'=>json_encode($data)]);

// 實例化賬單模型

$OrderModel = new AppleOrder();

// 賬單信息

$orderInfo = $OrderModel->getInfo(['id'=>$data['attach']],'*');

if (empty($orderInfo)) {

$this->returnCode(50000001, '賬單不存在');

}

if($orderInfo['pay_status'] != 1 || !empty($orderInfo['pay_time'])){

$this->returnCode(50000001,'訂單已支付,請勿再次支付');

}

// 保存微信服務器返回的簽名sign

$dataSign = $data['sign'];

$return_code = $data['return_code'];

$result_code = $data['result_code'];

$data['body'] = '會員卡';

$data['spbill_create_ip'] = \request()->ip();

$data['notify_url'] = $this->notify_url;

// sign 與 s 參數 不參與簽名算法

unset($data['sign']);

unset($data['transaction_id']);

unset($data['coupon_id']);

unset($data['coupon_type']);

unset($data['coupon_count']);

unset($data['coupon_fee']);

unset($data['time_end']);

unset($data['return_code']);

unset($data['result_code']);

unset($data['is_subscribe']);

unset($data['fee_type']);

unset($data['bank_type']);

unset($data['bank_type']);

// 生成簽名

$sign = $this->makeSign($data);

// 判斷簽名是否正確? 判斷支付狀態

if (($sign === $dataSign) && ($return_code == 'SUCCESS') && ($result_code == 'SUCCESS')) {

$OrderModel->startTrans();

try {

// 賬單支付成功業務處理

$appleOrderInfo = $OrderModel->where(['id'=>$orderInfo['id']])->lock(true)->find();

$result = $appleOrderInfo->addInfo(['pay_status'=>2,'pay_time'=>time()],['id'=>$orderInfo['id']]);

if(!$result){

$OrderModel->rollback();

$this->returnCode(5000003, '修改訂單失敗,失敗原因:'.$OrderModel->getError());

}

$appleUserModel = new AppleUser();

$appleUserInfo =? $appleUserModel->where(['openid'=>$orderInfo['openid']])->lock(true)->find();

$appleUser = $appleUserInfo->where(['openid'=>$orderInfo['openid']])->setInc('moxibustion',$orderInfo['moxibustion']);

if(!$appleUser){

$OrderModel->rollback();

$this->returnCode(5000003, '添加會員針灸次數失敗,失敗原因:'.$appleUserModel->getError());

}

}catch (\Exception $exception){

$OrderModel->rollback();

$this->returnCode(5000003, '操作失敗,失敗原因:'.$exception->getMessage());

}

$OrderModel->commit();

// 返回狀態

die(json(['code'=>0,'支付成功']));

}

// 返回狀態

$this->returnCode(2000003, '簽名失敗');

}