braintree api調用記錄

國外的支付集成接入。php

只使用基礎的卡支付,跟PayPal支付。前端

braintree 有沙盒環境能夠申請測試,有php sdk包直接下載調用,很是簡單。sql

1,聲明配置信息json

private $_debug         = false; private $_pay_method    = 'braintree'; private $_config        = null; private $_gateway       = null; private $_merchantAccountId     = [ 'usd' => 'xxxUSD' ]; //貨幣對應的merchantAccountId,建議自定義該值,
    private $_customerPre   = ''; //用戶名前綴,用戶生成顧客id,
    private $_customerId    = null; public  $_err           = '';
  
  
public function __construct() { if( $this->_debug ) { $this->_config['environment'] = 'sandbox'; $this->_config['merchantId'] = '6xqytmznhcczwwph'; $this->_config['publicKey'] = 'ks2j7rg234tq7fm7'; $this->_config['privateKey'] = '13012ef64ae8b95443f08226ac25c890'; $this->_merchantAccountId['usd'] = ''; //測試使用默認,也能夠自定義, $this->_customerPre = 'test1'; }else { $this->_config['environment'] = 'production'; $this->_config['merchantId'] = ''; $this->_config['publicKey'] = ''; $this->_config['privateKey'] = ''; $this->_customerPre = 'Pro'; }
   //實例化gate類,爲基礎類 import(
"Pay.braintree_macaroon_app.lib.Braintree", VENDOR_PATH, '.php' ); $this->_gateway = new \Braintree_Gateway( [ 'merchantId' => $this->_config['merchantId'], 'publicKey' => $this->_config['publicKey'], 'privateKey' => $this->_config['privateKey'], 'environment' => $this->_config['environment'], 'timeout' => 2, ] ); }

2,生成並獲取顧客id,顧客id能夠保留顧客的支付方式,方便其下次直接已購買,而不用重複輸入卡或者paypal信息後端

/** create table uro_braintree_uid( id int unsigned not null auto_increment, uid int unsigned not null default 0 comment '本站id', bid varchar(256) not null default '' comment 'braintree customerid', primary key (`id`), unique key (`uid`) ) engine innodb charset utf8 comment 'braintree 用戶對應關係表,creditcard,paypal等信息之後可加字段'; * 獲取、建立braintree 用戶, * author liuxiaodong * date 2018/7/31 15:38 * @param $uid * @return string */
    private function getCreateCustom( $uid ) { $model = M('braintreeUid'); $bid = $model->where( ['uid' => $uid] )->getField( 'bid' ); if( $bid ) return $bid; try{ $res = $this->_gateway->customer()->create( [ 'id'    => $this->_customerPre . $uid ] ); if( $res->success ) { $bid = $res->customer->id; if( !$model->add( ['uid' => $uid, 'bid' => $bid] ) ) $this->_warnNotice( 'send -- into db error', '數據入庫失敗,入庫數據爲 = '.  json_encode( ['uid' => $uid, 'bid' => $bid] ) . ',err =' . $model->getLastSql() .'|'. $model->getDbError() ); }else $this->_warnNotice( 'send -- res error', '請求braintree服務器,生成用戶信息失敗 = ' . json_encode( $res ) ); return $bid; }catch ( \Exception $e ) { $this->_warnNotice( 'send -- createCustom', '請求braintree服務器,拋出異常' . json_encode( $e ) ); return ''; } }

3,獲取客戶端token,同時能夠追加本身的信息,好比這邊追加返回了訂單的信息,讓客戶端回傳,服務器

/** * 初始化訂單信息,返回 clientoken,orderinfo 信息 * author liuxiaodong * date 2018/7/27 17:56 * @param array $params * @return array */
    public function send( $order ) { $this->_customerId  = $this->getCreateCustom( $order['braintree']['uid'] ); $this->_warnNotice( 'send -- getClientToken', 'get request', 'debug' ); $res = ['clientoken' => '', 'transaction' => []]; try{ $res['clientoken']      = $this->_gateway->clientToken()->generate( [ 'customerId'        => $this->_customerId ] ); }catch ( \Exception $e ) { $this->_warnNotice( 'send -- getClientToken', '錯誤信息:格式化exception ==' . json_encode( $e ) . ' , errmsg = ' . $e->getMessage() ); return []; } $res['transaction']     = $this->_encrypt( $order['braintree'] ); $this->_warnNotice( 'send -- getClientToken', 'send request' . json_encode( $res ), 'debug' ); return $res; }

4,支付, 是客戶端請求後,請求braintree直接獲取支付結果,作邏輯操做。app

//此接口作支付
    public function notify( $params ) { $this->_warnNotice( 'notify', '參數' . json_encode( $params ), 'debug' ); if( empty( $params['nonce'] ) || empty( $params['transaction'] ) ) { $this->_warnNotice( 'notify', '請求參數異常 無nonce、transaction, 參數爲 == ' . json_encode( $params ) ); $this->_err         = 'invalid params'; return false; } $transaction = $this->_decrypt( $params['transaction'] ); if( empty( $transaction ) || !is_array( $transaction ) ) { $this->_warnNotice( 'notify', '參數異常, 無transaction == ' . json_encode( $params ) ); $this->_err         = 'invalid params'; return false; } //讀取訂單信息
        $model          = D('Common/OrderRetail'); $order = $model->find( $transaction['oid'] ); if( !$order ) { $this->_err         = 'invalid order info'; $this->_warnNotice( 'notify', '讀取訂單信息異常 == ' . json_encode( $transaction ) . ' from ' . $params['client'] . ' order == ' . json_encode( $order ) . ' sql ==' . $model->getLastSql() ); return false; } if( $order['amount'] != $transaction['amount'] ) { $this->_err         = 'check amount error'; $this->_warnNotice( 'notify', '覈對訂單金額失敗 == ' . json_encode( $transaction ) . ' from ' . $params['client'] . ' order amount = ' .$order['amount'] ); return false; } $amount = $transaction['amount']; if( $this->_debug ) $amount = 0.01; //debug下請保證前端使用的金額也是0.01 //商品信息
        foreach ( $transaction['goods'] as $v ) { $lineItems[] = [ 'description'   => $transaction['oid'], // Maximum 127 characters
                'kind'          => 'debit', 'name'          => mb_substr( $v['product_info']['name'], 0, 30, 'utf8' ) . '...', 'productCode'   => $v['product_id'], //gid
                'quantity'      => $v['num'], 'totalAmount'   => $v['product_info']['price'] * $v['product_info']['num'], 'unitAmount'    => $v['product_info']['price'], 'url'           => '' ]; } $this->_customerId      = $this->getCreateCustom( $transaction['uid'] ); $trans = [ 'amount'                => $amount, //總金額
            'merchantAccountId'     => $this->_merchantAccountId['usd'], //merchantAccountId
            'paymentMethodNonce'    => $params['nonce'], 'lineItems'             => $lineItems, 'orderId'               => $transaction['oid'], //自定義的值 'customerId'            => $this->_customerId, 'options'               => [ 'submitForSettlement'     => true, //申請結算,
 ] ]; $this->_warnNotice( 'notify', 'sale 發送請求' . json_encode( $trans ) . 'from ' . $params['client'], 'debug' ); $res = $this->_gateway->transaction()->sale( $trans ); $this->_warnNotice( 'notify', 'sale 結果' . json_encode( $res->success ) . 'from ' . $params['client'], 'debug' ); if( $res->success ) { $trance = $res->transaction;   
       //我的邏輯
return true; }else { $this->_err = $res->message . '('.$res->transaction->processorResponseCode.')'; $this->_warnNotice( 'notify', '請求 sale 發送交易拋出異常, 簡訊 '.$this->_err.' 詳情 == ' . json_encode( $res ), 'error' ); return false; } }

5, 其餘附加方法,報警;加解密dom

/** * 獲取客戶端token * author liuxiaodong * date 2018/7/26 15:57 * @return array */
    public function getClientToken() { try{ $token = $this->_gateway->clientToken()->generate(); return [true, $token]; }catch ( \Exception $e ) { $this->_warnNotice( 'getClientToken', '獲取clienttoken 失敗。。'  . json_encode( $e ), 'error' ); return [false, $e->getMessage()]; } } private function _warnNotice( $action, $msg, $level = 'error' ) { if( $level == 'debug' && !$this->_debug ) return; $msg .= PHP_EOL; Log::write( $action . ' -- ' . $msg, $level, '', C('LOG_PATH') . 'braintreeErr/' . date( 'Y-m-d' ) . '.log' ); if( !$this->_debug ) { $email = new AliyunEail(); $email->sendEmail( 'email...', 'braintree pay error',  date( 'Y-m-d H:i:s' ) . '<br />' . $msg ); } } /** * Encrypts the input text using the cipher key * * @param $input * @return string */
    private function _encrypt( Array $input) { $input = json_encode( $input ); // Create a random IV. Not using mcrypt to generate one, as to not have a dependency on it.
        $iv = substr(uniqid("", true), 0, self::IV_SIZE); // Encrypt the data
        $encrypted = openssl_encrypt($input, "AES-256-CBC", 'key', 0, $iv); // Encode the data with IV as prefix
        return base64_encode($iv . $encrypted); } /** * Decrypts the input text from the cipher key * * @param $input * @return string */
    private function _decrypt($input) { // Decode the IV + data
        $input  = base64_decode($input); // Remove the IV
        $iv = substr($input, 0, self::IV_SIZE); // Return Decrypted Data
        $output     =  openssl_decrypt(substr($input, self::IV_SIZE), "AES-256-CBC", 'key', 0, $iv); return json_decode( $output, true ); } public function getError() { $msg = 'err: '; $msg .= $this->_err ? $this->_err : 'server fail'; return $msg; }

  

截圖:測試

報警: (該錯誤是前段生成的金額跟後端的不一致致使,可能是debug的時候)ui

相關文章
相關標籤/搜索