微信服務商分賬功能 PHP

項目說明

微信服務商分賬接口說明:
鏈接: 微信服務商分賬接口說明.

開通分賬功能
鏈接: 微信服務商分賬接口說明.

服務商代子商戶發起添加分賬接收方請求

在統一下單API、付款碼支付API、委託扣款API中上傳新增參數profit_sharing,請求支付
支付完成後,調用請求分賬接口,完成分賬

注意事項

  1. 分賬接口分爲單次分賬和多次分賬
  2. 當用戶需要退款時,單次分賬調用接口的步驟是:分賬回退->申請退款
  3. 當用戶需要退款時,多次分賬調用接口的步驟是:分賬完結->分賬回退->申請退款
  4. 商戶系統內部的分賬單號,在商戶系統內部唯一(單次分賬、多次分賬、完結分賬應使用不同的商戶分賬單號),同一分賬單號多次請求等同一次
  5. Ilog是一個日誌類
  6. ProfitSharingSign.class.php是用來生成簽名的,跟微信支付、微信退款生成簽名類是一樣的
  7. ProfitSharingCurl.class.php是一個發送http請求的類
  8. pdo_*的方法是微擎框架自帶的數據庫操作

PHP代碼

分賬接口類 ProfitSharing.class.php

<?php
require_once dirname(__FILE__) . "/ProfitSharingSign.class.php";
require_once dirname(__FILE__) . "/ProfitSharingCurl.class.php";

class ProfitSharing
{
    private $wxConfig = null;
    private $sign = null;
    private $curl = null;

    public function __construct()
    {
        $this->wxConfig = $this->wxConfig();
        $this->sign = new ProfitSharingSign();
        $this->curl = new ProfitSharingCurl();
    }


    /**
     * @function 發起請求所必須的配置參數
     * @return mixed
     */
    private function wxConfig()
    {
        $wxConfig['app_id'] = '';//服務商公衆號AppID
        $wxConfig['mch_id'] = ''; //服務商商戶號
        $wxConfig['sub_app_id'] = '';//todo 子服務商公衆號AppID
        $wxConfig['sub_mch_id'] = ''; //todo 子服務商商戶號
        $wxConfig['md5_key'] = ''; //md5 祕鑰
        $wxConfig['app_cert_pem'] = '';//證書路徑
        $wxConfig['app_key_pem'] = '';//證書路徑
        return $wxConfig;
    }


    /**
     * @function 請求多次分賬接口
     * @param $orders array 待分賬訂單
     * @param $accounts array 分賬接收方
     * @return array
     * @throws Exception
     */
    public function multiProfitSharing($orders,$accounts)
    {
        if(empty($orders)){
            throw new Exception('沒有待分帳訂單');
        }
        if(empty($accounts)){
            throw new Exception('接收分賬賬戶爲空');
        }

        //1.設置分賬賬號
        $receivers = array();
        foreach ($accounts as $account)
        {
            $tmp = array(
                'type'=>$account['type'],
                'account'=>$account['account'],
                'amount'=>intval($account['amount']),
                'description'=>$account['desc'],
            );
            $receivers[] = $tmp;
        }
        $receivers = json_encode($receivers,JSON_UNESCAPED_UNICODE);

        $totalCount = count($orders);
        $successCount = 0;
        $failCount = 0;
        $now = time();
        foreach ($orders as $order)
        {
            //2.生成簽名
            $postArr = array(
                'appid'=>$this->wxConfig['app_id'],
                'mch_id'=>$this->wxConfig['mch_id'],
                'sub_mch_id'=>$this->wxConfig['sub_mch_id'],
                'sub_appid'=>$this->wxConfig['sub_app_id'],
                'nonce_str'=>md5(time() . rand(1000, 9999)),
                'transaction_id'=>$order['trans_id'],
                'out_order_no'=>$order['order_no'].$order['ticket_no'],
                'receivers'=>$receivers,
            );

            $sign = $this->sign->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
            $postArr['sign'] = $sign;


            //3.發送請求
            $url = 'https://api.mch.weixin.qq.com/secapi/pay/multiprofitsharing';
            $postXML = $this->toXml($postArr);
            Ilog::DEBUG("multiProfitSharing.postXML: " . $postXML);

            $opts = array(
                CURLOPT_HEADER    => 0,
                CURLOPT_SSL_VERIFYHOST    => false,
                CURLOPT_SSLCERTTYPE   => 'PEM', //默認支持的證書的類型,可以註釋
                CURLOPT_SSLCERT   => $this->wxConfig['app_cert_pem'],
                CURLOPT_SSLKEY    => $this->wxConfig['app_key_pem'],
            );
            Ilog::DEBUG("multiProfitSharing.opts: " . json_encode($opts));

            $curl_res = $this->curl->setOption($opts)->post($url,$postXML);
            Ilog::DEBUG("multiProfitSharing.curl_res: " . $curl_res);

            $ret = $this->toArray($curl_res);
            if($ret['return_code']=='SUCCESS' and $ret['result_code']=='SUCCESS')
            {
                //更新分賬訂單狀態
                $params = array();
                $params['order_no'] =  $order['order_no'];
                $params['trans_id'] =  $order['trans_id'];
                $params['ticket_no'] =  $order['ticket_no'];

                $data = array();
                $data['profitsharing'] = $receivers;
                $data['state'] = 2;
                pdo_update('ticket_orders_profitsharing',$data,$params);
                $successCount++;

            }else{
                $failCount++;
            }
            usleep(500000);//微信會報頻率過高,所以停一下
        }

        return array('processTime'=>date('Y-m-d H:i:s',$now),'totalCount'=>$totalCount,'successCount'=>$successCount,'failCount'=>$failCount);

    }


    /**
     * @function 請求單次分賬接口
     * @param $profitSharingOrders array 待分賬訂單
     * @param $profitSharingAccounts array 分賬接收方
     * @return array
     * @throws Exception
     */
    public function profitSharing($profitSharingOrders,$profitSharingAccounts)
    {
        if(empty($profitSharingOrders)){
            throw new Exception('沒有待分帳訂單');
        }
        if(empty($profitSharingAccounts)){
            throw new Exception('接收分賬賬戶爲空');
        }

        //1.設置分賬賬號
        $receivers = array();
        foreach ($profitSharingAccounts as $profitSharingAccount)
        {
            $tmp = array(
                'type'=>$profitSharingAccount['type'],
                'account'=>$profitSharingAccount['account'],
                'amount'=>intval($profitSharingAccount['amount']),
                'description'=>$profitSharingAccount['desc'],
            );
            $receivers[] = $tmp;
        }
        $receivers = json_encode($receivers,JSON_UNESCAPED_UNICODE);

        $totalCount = count($profitSharingOrders);
        $successCount = 0;
        $failCount = 0;
        $now = time();

        foreach ($profitSharingOrders as $profitSharingOrder)
        {
            //2.生成簽名
            $postArr = array(
                'appid'=>$this->wxConfig['app_id'],
                'mch_id'=>$this->wxConfig['mch_id'],
                'sub_mch_id'=>$this->wxConfig['sub_mch_id'],
                'sub_appid'=>$this->wxConfig['sub_app_id'],
                'nonce_str'=>md5(time() . rand(1000, 9999)),
                'transaction_id'=>$profitSharingOrder['trans_id'],
                'out_order_no'=>$profitSharingOrder['order_no'].$profitSharingOrder['ticket_no'],
                'receivers'=>$receivers,
            );

            $sign = $this->sign->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
            $postArr['sign'] = $sign;

            //3.發送請求
            $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharing';
            $postXML = $this->toXml($postArr);
            Ilog::DEBUG("profitSharing.postXML: " . $postXML);

            $opts = array(
                CURLOPT_HEADER    => 0,
                CURLOPT_SSL_VERIFYHOST    => false,
                CURLOPT_SSLCERTTYPE   => 'PEM', //默認支持的證書的類型,可以註釋
                CURLOPT_SSLCERT   => $this->wxConfig['app_cert_pem'],
                CURLOPT_SSLKEY    => $this->wxConfig['app_key_pem'],
            );
            Ilog::DEBUG("profitSharing.opts: " . json_encode($opts));

            $curl_res = $this->curl->setOption($opts)->post($url,$postXML);
            Ilog::DEBUG("profitSharing.curl_res: " . $curl_res);

            $ret = $this->toArray($curl_res);
            if($ret['return_code']=='SUCCESS' and $ret['result_code']=='SUCCESS')
            {
                //更新分賬訂單狀態
                $params = array();
                $params['order_no'] =  $profitSharingOrder['order_no'];
                $params['trans_id'] =  $profitSharingOrder['trans_id'];
                $params['ticket_no'] =  $profitSharingOrder['ticket_no'];

                $data = array();
                $data['profitsharing'] = $receivers;
                $data['state'] = 2;
                pdo_update('ticket_orders_profitsharing',$data,$params);
                $successCount++;

            }else{
                $failCount++;
            }

        }

        return array('processTime'=>date('Y-m-d H:i:s',$now),'totalCount'=>$totalCount,'successCount'=>$successCount,'failCount'=>$failCount);

    }


    /**
     * @function 查詢分賬結果
     * @param $trans_id string 微信支付單號
     * @param $out_order_no string 分賬單號
     * @return array|false
     * @throws Exception
     */
    public function query($trans_id,$out_order_no)
    {
        //1.生成簽名
        $postArr = array(
            'mch_id'=>$this->wxConfig['mch_id'],
            'sub_mch_id'=>$this->wxConfig['sub_mch_id'],
            'transaction_id'=>$trans_id,
            'out_order_no'=>$out_order_no,
            'nonce_str'=>md5(time() . rand(1000, 9999)),
        );

        $sign = $this->sign->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
        $postArr['sign'] = $sign;

        //2.發送請求
        $url = 'https://api.mch.weixin.qq.com/pay/profitsharingquery';
        $postXML = $this->toXml($postArr);
        Ilog::DEBUG("query.postXML: " . $postXML);

        $curl_res = $this->curl->post($url,$postXML);
        Ilog::DEBUG("query.curl_res: " . $curl_res);

        $ret = $this->toArray($curl_res);
        return $ret;
    }


    /**
     * @function 添加分賬接收方
     * @param $profitSharingAccount array 分賬接收方
     * @return array|false
     * @throws Exception
     */
    public function addReceiver($profitSharingAccount)
    {
        //1.接收分賬賬戶
        $receiver = array(
            'type'=>$profitSharingAccount['type'],
            'account'=>$profitSharingAccount['account'],
            'name'=>$profitSharingAccount['name'],
            'relation_type'=>$profitSharingAccount['relation_type'],
        );
        $receiver = json_encode($receiver,JSON_UNESCAPED_UNICODE);

        //2.生成簽名
        $postArr = array(
            'appid'=>$this->wxConfig['app_id'],
            'mch_id'=>$this->wxConfig['mch_id'],
            'sub_mch_id'=>$this->wxConfig['sub_mch_id'],
            'sub_appid'=>$this->wxConfig['sub_app_id'],
            'nonce_str'=>md5(time() . rand(1000, 9999)),
            'receiver'=>$receiver
        );

        $sign = $this->sign->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
        $postArr['sign'] = $sign;


        //3.發送請求
        $url = 'https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver';
        $postXML = $this->toXml($postArr);
        Ilog::DEBUG("addReceiver.postXML: " . $postXML);

        $curl_res = $this->curl->post($url,$postXML);
        Ilog::DEBUG("addReceiver.curl_res: " . $curl_res);

        $ret = $this->toArray($curl_res);
        return $ret;
    }


    /**
     * @function 刪除分賬接收方
     * @param $profitSharingAccount array 分賬接收方
     * @return array|false
     * @throws Exception
     */
    public function removeReceiver($profitSharingAccount)
    {
        //1.接收分賬賬戶
        $receiver = array(
            'type'=>$profitSharingAccount['type'],
            'account'=>$profitSharingAccount['account'],
            'name'=>$profitSharingAccount['name'],
        );
        $receiver = json_encode($receiver,JSON_UNESCAPED_UNICODE);

        //2.生成簽名
        $postArr = array(
            'appid'=>$this->wxConfig['app_id'],
            'mch_id'=>$this->wxConfig['mch_id'],
            'sub_mch_id'=>$this->wxConfig['sub_mch_id'],
            'sub_appid'=>$this->wxConfig['sub_app_id'],
            'nonce_str'=>md5(time() . rand(1000, 9999)),
            'receiver'=>$receiver
        );

        $sign = $this->sign->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
        $postArr['sign'] = $sign;


        //3.發送請求
        $url = 'https://api.mch.weixin.qq.com/pay/profitsharingremovereceiver';
        $postXML = $this->toXml($postArr);
        Ilog::DEBUG("removeReceiver.postXML: " . $postXML);

        $curl_res = $this->curl->post($url,$postXML);
        Ilog::DEBUG("removeReceiver.curl_res: " . $curl_res);

        $ret = $this->toArray($curl_res);
        return $ret;
    }


    /**
     * @function 完結分賬
     * @param $profitOrder array 分賬訂單
     * @param $description string 完結分賬描述
     * @return array|false
     * @throws Exception
     */
    public function finish($profitOrder,$description='分賬完結')
    {
        $ret = array();
        if(!empty($profitOrder))
        {
            //1.簽名
            $postArr = array(
                'mch_id'=>$this->wxConfig['mch_id'],
                'sub_mch_id'=>$this->wxConfig['sub_mch_id'],
                'appid'=>$this->wxConfig['app_id'],
                'nonce_str'=>md5(time() . rand(1000, 9999)),
                'transaction_id'=>$profitOrder['trans_id'],
                'out_order_no'=>'finish'.'_'.$profitOrder['order_no'],
                'description'=>$description,
            );

            $sign = $this->sign->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
            $postArr['sign'] = $sign;

            //2.請求
            $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish';
            $postXML = $this->toXml($postArr);
            Ilog::DEBUG("finish.postXML: " . $postXML);

            $opts = array(
                CURLOPT_HEADER    => 0,
                CURLOPT_SSL_VERIFYHOST    => false,
                CURLOPT_SSLCERTTYPE   => 'PEM', //默認支持的證書的類型,可以註釋
                CURLOPT_SSLCERT   => $this->wxConfig['app_cert_pem'],
                CURLOPT_SSLKEY    => $this->wxConfig['app_key_pem'],
            );
            Ilog::DEBUG("finish.opts: " . json_encode($opts));

            $curl_res = $this->curl->setOption($opts)->post($url,$postXML);
            Ilog::DEBUG("finish.curl_res: " . $curl_res);

            $ret = $this->toArray($curl_res);
        }

        return $ret;
    }


    /**
     * @function 分賬回退
     * @param $profitOrder array 分賬訂單
     * @return array
     * @throws Exception
     */
    public function profitSharingReturn($profitOrder)
    {
        $ret = array();
        if(!empty($profitOrder) and $profitOrder['channel']==1)
        {
            $accounts = json_decode($profitOrder['profitsharing'],true);
            foreach ($accounts as $account)
            {
                //1.簽名
                $postArr = array(
                    'appid'=>$this->wxConfig['app_id'],
                    'mch_id'=>$this->wxConfig['mch_id'],
                    'sub_mch_id'=>$this->wxConfig['sub_mch_id'],
                    'sub_appid'=>$this->wxConfig['sub_app_id'],
                    'nonce_str'=>md5(time() . rand(1000, 9999)),
                    'out_order_no'=>$profitOrder['order_no'].$profitOrder['ticket_no'],
                    'out_return_no'=>'return_'.$profitOrder['order_no'].$profitOrder['ticket_no'].'_'.$account['account'],
                    'return_account_type'=>'MERCHANT_ID',
                    'return_account'=>$account['account'],
                    'return_amount'=>$account['amount'],
                    'description'=>'用戶退款',
                    'sign_type'=>'HMAC-SHA256',
                );

                $sign = $this->sign->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
                $postArr['sign'] = $sign;


                //2.請求
                $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharingreturn';
                $postXML = $this->toXml($postArr);
                Ilog::DEBUG("profitSharingReturn.postXML: " . $postXML);

                $opts = array(
                    CURLOPT_HEADER    => 0,
                    CURLOPT_SSL_VERIFYHOST    => false,
                    CURLOPT_SSLCERTTYPE   => 'PEM', //默認支持的證書的類型,可以註釋
                    CURLOPT_SSLCERT   => $this->wxConfig['app_cert_pem'],
                    CURLOPT_SSLKEY    => $this->wxConfig['app_key_pem'],
                );
                Ilog::DEBUG("profitSharingReturn.opts: " . json_encode($opts));

                $curl_res = $this->curl->setOption($opts)->post($url,$postXML);
                Ilog::DEBUG("profitSharingReturn.curl_res: " . $curl_res);

                $ret[] = $this->toArray($curl_res);
            }

        }
        return $ret;
    }


    /**
     * @function 回退結果查詢
     * @param $order_no string 本地訂單號
     * @param $ticket_no string 本地票號
     * @return array|false
     * @throws \Exception
     */
    public function returnQuery($order_no,$ticket_no)
    {
        $ret = array();
        $profitOrder = pdo_fetch("SELECT * FROM zc_ticket_orders_profitsharing WHERE order_no='{$order_no}' AND ticket_no='{$ticket_no}'");
        if($profitOrder['channel']==1 and $profitOrder['state']==2)
        {
            $accounts = json_decode($profitOrder['profitsharing'],true);
            foreach ($accounts as $account)
            {
                //1.簽名
                $postArr = array(
                    'appid'=>$this->wxConfig['app_id'],
                    'mch_id'=>$this->wxConfig['mch_id'],
                    'sub_mch_id'=>$this->wxConfig['sub_mch_id'],
                    'nonce_str'=>md5(time() . rand(1000, 9999)),
                    'out_order_no'=>$profitOrder['order_no'].$profitOrder['ticket_no'],
                    'out_return_no'=>'return_'.$profitOrder['order_no'].$profitOrder['ticket_no'].'_'.$account['account'],
                    'sign_type'=>'HMAC-SHA256',
                );

                $sign = $this->sign->getSign($postArr, 'HMAC-SHA256',$this->wxConfig['md5_key']);
                $postArr['sign'] = $sign;

                //2.請求
                $url = 'https://api.mch.weixin.qq.com/pay/profitsharingreturnquery';
                $postXML = $this->toXml($postArr);
                Ilog::DEBUG("returnQuery.postXML: " . $postXML);

                $curl_res = $this->curl->post($url,$postXML);
                Ilog::DEBUG("returnQuery.curl_res: " . $curl_res);

                $ret[] = $this->toArray($curl_res);
            }

        }
        return $ret;
    }


    /**
     * @function 將array轉爲xml
     * @param array $values
     * @return string|bool
     * @author xiewg
     **/
    public 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;
    }

    /**
     * @function 將xml轉爲array
     * @param string $xml
     * @return array|false
     * @author xiewg
     */
    public function toArray($xml)
    {
        if (!$xml) {
            return false;
        }

        // 檢查xml是否合法
        $xml_parser = xml_parser_create();
        if (!xml_parse($xml_parser, $xml, true)) {
            xml_parser_free($xml_parser);
            return false;
        }

        //將XML轉爲array
        //禁止引用外部xml實體
        libxml_disable_entity_loader(true);

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

        return $data;
    }
}

發送請求類: ProfitSharingCurl.class.php

<?php

/**
 * CUrl CURL請求類
 *
 * 通過curl實現的快捷方便的接口請求類
 *
 * <br>示例:<br>
 *
 *  // 失敗時再重試2次
 *  $curl = new CUrl(2);
 *
 *  // GET
 *  $rs = $curl->get('http://phalapi.oschina.mopaas.com/Public/demo/?service=Default.Index');
 *
 *  // POST
 *  $data = array('username' => 'dogstar');
 *  $rs = $curl->post('http://phalapi.oschina.mopaas.com/Public/demo/?service=Default.Index', $data);
 *
 * @package     PhalApi\CUrl
 * @license     http://www.phalapi.net/license GPL 協議
 * @link        http://www.phalapi.net/
 * @author      dogstar <[email protected]> 2015-01-02
 */

class ProfitSharingCurl {

    /**
     * 最大重試次數
     */
    const MAX_RETRY_TIMES = 10;

    /**
     * @var int $retryTimes 超時重試次數;注意,此爲失敗重試的次數,即:總次數 = 1 + 重試次數
     */
    protected $retryTimes;

    protected $header = array();

    protected $option = array();

    protected $hascookie = FALSE;

    protected $cookie = array();

    /**
     * @param int $retryTimes 超時重試次數,默認爲1
     */
    public function __construct($retryTimes = 1) {
        $this->retryTimes = $retryTimes < static::MAX_RETRY_TIMES
            ? $retryTimes : static::MAX_RETRY_TIMES;
    }

    /** ------------------ 核心使用方法 ------------------ **/

    /**
     * GET方式的請求
     * @param string $url 請求的鏈接
     * @param int $timeoutMs 超時設置,單位:毫秒
     * @return string 接口返回的內容,超時返回false
     */
    public function get($url, $timeoutMs = 3000) {
        return $this->request($url, array(), $timeoutMs);
    }

    /**
     * POST方式的請求
     * @param string $url 請求的鏈接
     * @param array $data POST的數據
     * @param int $timeoutMs 超時設置,單位:毫秒
     * @return string 接口返回的內容,超時返回false
     */
    public function post($url, $data, $timeoutMs = 3000) {
        return $this->request($url, $data, $timeoutMs);
    }

    /** ------------------ 前置方法 ------------------ **/

    /**
     * 設置請求頭,後設置的會覆蓋之前的設置
     *
     * @param array $header 傳入鍵值對如:
    ```
     * array(
     *     'Accept' => 'text/html',
     *     'Connection' => 'keep-alive',
     * )
    ```
     *
     * @return $this
     */
    public function setHeader($header) {
        $this->header = array_merge($this->header, $header);
        return $this;
    }

    /**
     * 設置curl配置項
     *
     * - 1、後設置的會覆蓋之前的設置
     * - 2、開發者設置的會覆蓋框架的設置
     *
     * @param array $option 格式同上
     *
     * @return $this
     */
    public function setOption($option) {
        $this->option = $option + $this->option;
        return $this;
    }

    /**
     * @param array $cookie
     */
    public function setCookie($cookie) {
        $this->cookie = $cookie;
        return $this;
    }

    /**
     * @return array
     */
    public function getCookie() {
        return $this->cookie;
    }

    public function withCookies() {
        $this->hascookie = TRUE;

        if (!empty($this->cookie)) {
            $this->setHeader(array('Cookie' => $this->getCookieString()));
        }
        $this->setOption(array(CURLOPT_COOKIEFILE => ''));

        return $this;
    }

    /** ------------------ 輔助方法 ------------------ **/

    /**
     * 統一接口請求
     * @param string $url 請求的鏈接
     * @param array $data POST的數據
     * @param int $timeoutMs 超時設置,單位:毫秒
     * @return string 接口返回的內容,超時返回false
     * @throws Exception
     */
    protected function request($url, $data, $timeoutMs = 3000) {
        $options = array(
            CURLOPT_URL                 => $url,
            CURLOPT_RETURNTRANSFER      => TRUE,
            CURLOPT_HEADER              => 0,
            CURLOPT_CONNECTTIMEOUT_MS   => $timeoutMs,
            CURLOPT_HTTPHEADER          => $this->getHeaders(),
        );

        if (!empty($data)) {
            $options[CURLOPT_POST]          = 1;
            $options[CURLOPT_POSTFIELDS]    = $data;
        }

        $options = $this->option + $options; //$this->>option優先

        $ch = curl_init();
        curl_setopt_array($ch, $options);
        $curRetryTimes = $this->retryTimes;
        do {
            $rs = curl_exec($ch);
            $curRetryTimes--;
        } while ($rs === FALSE && $curRetryTimes >= 0);
        $errno = curl_errno($ch);
        if ($errno) {
            throw new InternalServerErrorException(sprintf("%s::%s(%d)\n", $url, curl_error($ch), $errno));
        }

        //update cookie
        if ($this->hascookie) {
            $cookie = $this->getRetCookie(curl_getinfo($ch, CURLINFO_COOKIELIST));
            !empty($cookie) && $this->cookie = $cookie + $this->cookie;
            $this->hascookie = FALSE;
            unset($this->header['Cookie']);
            unset($this->option[CURLOPT_COOKIEFILE]);
        }
        curl_close($ch);

        return $rs;
    }

    /**
     *
     * @return array
     */
    protected function getHeaders() {
        $arrHeaders = array();
        foreach ($this->header as $key => $val) {
            $arrHeaders[] = $key . ': ' . $val;
        }
        return $arrHeaders;
    }

    protected function getRetCookie(array $cookies) {
        $ret = array();
        foreach ($cookies as $cookie) {
            $arr = explode("\t", $cookie);
            if (!isset($arr[6])) {
                continue;
            }
            $ret[$arr[5]] = $arr[6];
        }
        return $ret;
    }

    protected function getCookieString() {
        $ret = '';
        foreach ($this->getCookie() as $key => $val) {
            $ret .= $key . '=' . $val . ';';
        }
        return trim($ret, ';');
    }
}

簽名類 ProfitSharing.class.php

<?php

class ProfitSharingSign
{

    /**
     * 根據Url傳遞的參數,生成簽名字符串
     * @param array $param
     * @param string $signType
     * @param $md5Key
     * @return string
     * @throws \Exception
     */
    public function getSign(array $param, $signType = 'MD5', $md5Key)
    {
        $values = $this->paraFilter($param);
        $values = $this->arraySort($values);
        $signStr = $this->createLinkstring($values);

        $signStr .= '&key=' . $md5Key;
        switch ($signType)
        {
            case 'MD5':
                $sign = md5($signStr);
                break;
            case 'HMAC-SHA256':
                $sign = hash_hmac('sha256', $signStr, $md5Key);
                break;
            default:
                $sign = '';
        }
        return strtoupper($sign);
    }


    /**
     * 移除空值的key
     * @param $para
     * @return array
     */
    public function paraFilter($para)
    {
        $paraFilter = array();
        while (list($key, $val) = each($para))
        {
            if ($val == "") {
                continue;

            } else {
                if (! is_array($para[$key])) {
                    $para[$key] = is_bool($para[$key]) ? $para[$key] : trim($para[$key]);
                }

                $paraFilter[$key] = $para[$key];
            }
        }
        return $paraFilter;
    }


    /**
     * @function 對輸入的數組進行字典排序
     * @param array $param 需要排序的數組
     * @return array
     * @author helei
     */
    public function arraySort(array $param)
    {
        ksort($param);
        reset($param);
        return $param;
    }


    /**
     * @function 把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串
     * @param array $para 需要拼接的數組
     * @return string
     * @throws \Exception
     */
    public function createLinkString($para)
    {
        if (! is_array($para)) {
            throw new \Exception('必須傳入數組參數');
        }

        reset($para);
        $arg  = "";
        while (list($key, $val) = each($para)) {
            if (is_array($val)) {
                continue;
            }

            $arg.=$key."=".urldecode($val)."&";
        }
        //去掉最後一個&字符
        $arg = substr($arg, 0, count($arg) - 2);

        //如果存在轉義字符,那麼去掉轉義
        if (get_magic_quotes_gpc()) {
            $arg = stripslashes($arg);
        }

        return $arg;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章