微信服务商分账功能 PHP

项目说明

  1. 微信服务商分账接口说明:https://pay.weixin.qq.com/wiki/doc/api/allocation_sl.php?chapter=24_1&index=1

项目大概逻辑

  1. 开通分账功能(https://pay.weixin.qq.com/wiki/doc/api/allocation_sl.php?chapter=24_2&index=2)
  2. 服务商代子商户发起添加分账接收方请求
  3. 在统一下单API、付款码支付API、委托扣款API中上传新增参数profit_sharing,请求支付
  4. 支付完成后,调用请求分账接口,完成分账

其他注意事项

  1. 分账接口分为单次分账和多次分账
  2. 当用户需要退款时,单次分账调用接口的步骤是:分账回退->申请退款
  3. 当用户需要退款时,多次分账调用接口的步骤是:分账完结->分账回退->申请退款
  4. 这里画重点,商户系统内部的分账单号,在商户系统内部唯一(***单次分账、多次分账、完结分账应使用不同的商户分账单号),同一分账单号多次请求等同一次。**只能是数字、大小写字母_-|@
  5. Ilog是一个日志类,这里就不提供了,大家都有自己的
  6. ProfitSharingSign.class.php是用来生成签名的,跟微信支付、微信退款生成签名类是一样的,会贴在最后
  7. ProfitSharingCurl.class.php是一个发送http请求的类,会贴在最后
  8. pdo_*的方法是微擎框架自带的数据库操作(这框架估计没谁会喜欢…)
  9. 使用例子就不写了,单身狗都知道,new一个对象嘛,大家给我介绍一个也行的,然后照着参数传就行
  10. 最后,欢迎指错~~

代码

分账接口类 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 <chanzonghuang@gmail.com> 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;
    }
}
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值