审查视图

simplewind/extend/Charge.php 6.6 KB
lihan authored
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
<?php

class Payment {

    protected $attach;
    protected $openid;
    protected $body;
    protected $total_fee;

    function __construct($attach=null, $openid=null, $body=null, $total_fee=null) {
        $this->attach = $attach;
        $this->openid = $openid;
        $this->body = $body;
        $this->total_fee = $total_fee;
    }

    /**
     * 对外暴露的支付接口
     * @return array
     */
    public function pay() {
        return $this->weixinPay();
    }

    private function weixinPay() {
        //统一下单接口
        $unifiedorder = $this->unifiedorder();
        $parameters = array(
            'appId'     => config('AppID'),
            'timeStamp' => '' . time() . '', //时间戳
            'nonceStr'  => $this->createNoncestr(), //随机串
            'package'   => 'prepay_id=' . $unifiedorder['prepay_id'], //数据包
            'signType'  => 'MD5'//签名方式
        );
        //签名
        $parameters['paySign'] = $this->getSign($parameters);
        return $parameters;
    }

    //统一下单接口
    private function unifiedorder() {
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $parameters = array(
            'appid'             =>  config('AppID'),
            'mch_id'            =>  config('MchId'),
            'nonce_str'         =>  $this->createNoncestr(),
            'body'              =>  $this->body,
            'out_trade_no'      =>  config('MchId').time(),
            'total_fee'         =>  $this->total_fee,
            'spbill_create_ip'  =>  '114.215.223.17', //终端IP
            'notify_url'        =>  'http://sami.w.bronet.cn/charge/Charge/notify',
            'openid'            =>  $this->openid,
            'trade_type'        =>  'JSAPI',//交易类型
            'attach'            =>  $this->attach
        );
        //统一下单签名
        $parameters['sign'] = $this->getSign($parameters);
        $xmlData = $this->arrayToXml($parameters);
        $return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60));
        return $return;
    }

    //作用:生成签名
    private function getSign($Obj) {
        foreach ($Obj as $k => $v) {
            $Parameters[$k] = $v;
        }
        //签名步骤一:按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //签名步骤二:在string后加入KEY
        $String = $String . "&key=" . config('Key');
        //签名步骤三:MD5加密
        $String = md5($String);
        //签名步骤四:所有字符转为大写
        $result_ = strtoupper($String);
        return $result_;
    }

    private static function postXmlCurl($xml, $url, $second = 30) {
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
        curl_setopt($ch, CURLOPT_TIMEOUT, 40);
        set_time_limit(0);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            throw new WxPayException("curl出错,错误码:$error");
        }
    }

    //数组转换成xml
    private function arrayToXml($arr) {
        $xml = "<root>";
        foreach ($arr as $key => $val) {
            if (is_array($val)) {
                $xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            }
        }
        $xml .= "</root>";
        return $xml;
    }


    //xml转换成数组
    private function xmlToArray($xml) {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $val = json_decode(json_encode($xmlstring), true);
        return $val;
    }

    //作用:产生随机字符串,不长于32位
    private function createNoncestr($length = 32) {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    ///作用:格式化参数,签名过程需要使用
    private function formatBizQueryParaMap($paraMap, $urlencode) {
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v) {
            if ($urlencode) {
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar='';
        if (strlen($buff) > 0) {
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }

    public function handleNotify() {
        //$postXml = $GLOBALS["HTTP_RAW_POST_DATA"]; //接收微信参数
        $postXml=file_get_contents("php://input");
        cache('xml', $postXml);
        if (empty($postXml)) {
            return false;
        }else {
            $data = $this->xmlToArray($postXml);
            if($data['return_code'] == 'SUCCESS' && $data['result_code'] == 'SUCCESS') {
                $data = (array)simplexml_load_string($postXml, 'SimpleXMLElement', LIBXML_NOCDATA);
                $signA = "appid=".$data['appid']."&attach=".$data['attach']."&bank_type=".$data['bank_type']."&cash_fee=".$data['cash_fee']."&fee_type=".$data['fee_type']."&is_subscribe=".$data['is_subscribe']."&mch_id=".$data['mch_id']."&nonce_str=".$data['nonce_str']."&openid=". $data['openid']."&out_trade_no=".$data['out_trade_no']."&result_code=".$data['result_code']."&return_code=".$data['return_code']."&time_end=".$data['time_end']."&total_fee=".$data['total_fee']."&trade_type=".$data['trade_type']."&transaction_id=".$data['transaction_id']."&key=".config('Key');
                $sign = strtoupper(MD5($signA));
                if($sign == $data['sign']) {
                    return $data;
                }else {
                    return false;
                }
            }else {
                return false;
            }
        }
    }

}