<?php
/**
 * 
 * @author 建站宝
 * @date 2017-08-15
 */
namespace pay;

class Wxpay{
    public $parameters; //提交参数，数组
	public $returnParameters;//返回参数，数组
    //证书路径,注意应该填写绝对路径
    public $SSLCERT_PATH = '/data/wwwroot/58wd/wwwroot/Static/apiclient_cert.pem';
    public $SSLKEY_PATH = '/data/wwwroot/58wd/wwwroot/Static/apiclient_key.pem';
    //本例程通过curl使用HTTP POST方法，此处可修改其超时时间，默认为30秒
    public $CURL_TIMEOUT = 30;
    public function __construct($config=array()) {
    	foreach ($config as $k => $v) {
    		$this->$k=$v;
    	}
		$this->appid=isset($config['appid'])?$config['appid']:C('WX_APPID');
		$this->secret=isset($config['secret'])?$config['secret']:C('WX_APPSECRET');
		$this->mchid=isset($config['mchid'])?$config['mchid']:C('WX_MCHID');
		$this->KEY=isset($config['key'])?$config['key']:C('WX_KEY');
    }
	
	
	/**
     * 调用微信api获取响应数据
     * @param  string $name   API名称
     * @param  string $data   POST请求数据
     * @return array          api返回结果
     */
    public function api($name='',$data=array()){
    	$url="https://api.mch.weixin.qq.com/".$name;
		$xml=$this->createXml($data);
		if($name=='secapi/pay/refund'){
		    $re = $this->postXmlSSLCurl($xml,$url,$this->CURL_TIMEOUT);
		}else{
			$re=$this->postXmlCurl($xml, $url, $this->CURL_TIMEOUT);
		}
		return $this->xmlToArray($re);
    }
	
	
	/**
     * 设置请求参数
     * @param  array $arr   参数数组
     */
    public function setParam($arr=array()){
    	foreach ($arr as $k => $v) {
    		$this->parameters[$k]=$v;
    	}
    }
	
	/**
     * 	作用：H5支付
     */
    public function getH5Api(){
		$this->parameters['appid']=$this->appid;
		$this->parameters['mch_id']=$this->mchid;
		$this->parameters['nonce_str']=uniqid();
		$this->parameters['spbill_create_ip']=get_client_ip();
		$this->parameters['trade_type']='MWEB';
        $result = $this->api('pay/unifiedorder',$this->parameters);
        return $result['mweb_url'];
    }
	
	
	/**
     * 	作用：扫码支付
     */
    public function pc($param){
    	$uid=session("user_auth.id");
		$this->parameters['appid']=$this->appid;
		$this->parameters['mch_id']=$this->mchid;
		$this->parameters['nonce_str']=uniqid();
		$this->parameters['spbill_create_ip']=get_client_ip();
		$this->parameters['trade_type']='NATIVE';
		$this->parameters['body']=$param['title'];
		$this->parameters['out_trade_no']=$param['orderno'];
		$this->parameters['total_fee']=$param['amount']*100;
		$this->parameters['attach']=$param['other']?$param['other']:'1';
		$this->parameters['notify_url']=$param['notify_url'];
        $result = $this->api('pay/unifiedorder',$this->parameters);
        $code_url=$result['code_url'];
		R('Pay/view',array(array(
			'orderno'=>$param['orderno'],
			'ctime'=>time(),
			'code'=>$code_url,
			'model'=>$param['model'],
			'amount'=>$param['amount'],
			'gourl'=>$param['return_url'],
			'tpl'=>'Pay_wxpay_pc',
		)));
		
    }
	
	
	/**
     * 	作用：设置jsapi的参数
     */
    public function getAppApi(){
		$param['appid'] = $this->appid;
		$param['partnerid'] = $this->mchid;
		$param['prepayid']  = $this->getPrepayId();
		$param['package']  = "Sign=WXPay";
		$param['noncestr'] =  uniqid();
		$param['timestamp'] = (string)time();
		$param['sign'] = $this->getSign($param);
      	return $param;
    }
	
    /**
     * 	作用：设置jsapi的参数
     */
    public function getJsApi(){
        $jsApiObj['appId'] = $this->appid;
        //请求生成支付签名时需要,js调起支付参数中不需要
        $timeStamp = (string)time();
        $jsApiObj['timeStamp'] = $timeStamp;
        //用大写的timeStamp参数请求生成支付签名
        $jsParamObj['timeStamp'] = $timeStamp;
        $jsParamObj['appId'] = $this->appid;
        $jsParamObj['nonceStr'] = $jsApiObj['nonceStr'] = uniqid();
        $jsParamObj['package'] = $jsApiObj['package'] = "prepay_id=".$this->getPrepayId();
        $jsParamObj['signType'] = $jsApiObj['signType'] = 'MD5';
        $jsParamObj['paySign'] = $jsApiObj['paySign'] = $this->getSign($jsApiObj);
        $jsParam = json_encode($jsParamObj);
        return $jsParam;
    }
	
	/**
	 * 回调通知
	 */
	function notifyReturn(){
		return $this->arrayToXml(array(
			'return_code'=>'SUCCESS',
			'return_msg'=>'OK',
		));
	}
	
    /**
     * 获取prepay_id
     */
    public function getPrepayId(){
    	$this->parameters['appid']=$this->appid;
		$this->parameters['mch_id']=$this->mchid;
		$this->parameters['nonce_str']=uniqid();
		$this->parameters['spbill_create_ip']=get_client_ip();
        $result = $this->api('pay/unifiedorder',$this->parameters);
        return $result['prepay_id'];
    }
    
	
    /**
     * 	作用：以post方式提交xml到对应的接口url
     */
    public function postXmlCurl($xml, $url, $second = 30) {
        //初始化curl
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOP_TIMEOUT, $this->CURL_TIMEOUT);
        //这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        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
        $data = curl_exec($ch);
        curl_close($ch);
        //返回结果
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            echo "curl出错，错误码:{$error}" . '<br>';
            echo '<a href=\'http://curl.haxx.se/libcurl/c/libcurl-errors.html\'>错误原因查询</a></br>';
            curl_close($ch);
            return false;
        }
    }

	/**
	 * 	作用：使用证书，以post方式提交xml到对应的接口url
	 */
	function postXmlSSLCurl($xml,$url,$second=30){
		$ch = curl_init();
		//超时时间
		curl_setopt($ch,CURLOPT_TIMEOUT,$second);
		//这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        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);
		//设置证书
		//使用证书：cert 与 key 分别属于两个.pem文件
		//默认格式为PEM，可以注释
		curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
		curl_setopt($ch,CURLOPT_SSLCERT, $this->SSLCERT_PATH);
		//默认格式为PEM，可以注释
		curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
		curl_setopt($ch,CURLOPT_SSLKEY, $this->SSLKEY_PATH);
		//post提交方式
		curl_setopt($ch,CURLOPT_POST, true);
		curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
		$data = curl_exec($ch);
		//返回结果
		if($data){
			curl_close($ch);
			return $data;
		}
		else { 
			$error = curl_errno($ch);
			echo "curl出错，错误码:$error"."<br>"; 
			echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
			curl_close($ch);
			return false;
		}
	}
	
	
    /**
     * 	作用：设置标配的请求参数，生成签名，生成接口参数xml
     */
    public function createXml($data=array()) {
        $this->parameters['appid'] = $this->appid;
        $this->parameters['mch_id'] = $this->mchid;
        $this->parameters['nonce_str'] = uniqid();
		foreach ($data as $k => $v) {
			$this->parameters[$k]=$v;
		}
        $this->parameters['sign'] = $this->getSign($this->parameters);
        return $this->arrayToXml($this->parameters);
    }
	
	/**
     * 	作用：将xml转为array
     */
    public function xmlToArray($xml){
        //将XML转为array
        $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $array_data;
    }
	
    /**
     * 	作用：array转xml
     */
    public function arrayToXml($arr) {
        $xml = '<xml>';
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= '<' . $key . '>' . $val . '</' . $key . '>';
            } else {
                $xml .= '<' . $key . '><![CDATA[' . $val . ']]></' . $key . '>';
            }
        }
        $xml .= '</xml>';
        return $xml;
    }
    /**
     * 	作用：生成签名
     */
    public function getSign($Obj) {
        foreach ($Obj as $k => $v) {
            $Parameters[$k] = $v;
        }
        //签名步骤一：按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //echo '【string1】'.$String.'</br>';
        //签名步骤二：在string后加入KEY
        $String = $String . '&key=' . $this->KEY;
        //echo "【string2】".$String."</br>";
        //签名步骤三：MD5加密
        $String = md5($String);
        //echo "【string3】 ".$String."</br>";
        //签名步骤四：所有字符转为大写
        $result_ = strtoupper($String);
        //echo "【result】 ".$result_."</br>";
        return $result_;
    }
	
	
	/**
     * 	验证签名
     */
	function check(){
		$data=$this->getData();
		if($data['result_code']!='SUCCESS' && $data['return_code']!='SUCCESS'){
		    return false;
		}
		$tmpData = $data;
		unset($tmpData['sign']);
		$sign = $this->getSign($tmpData);
		if ($data['sign'] == $sign) {
			$uid=M('recharge')->where(array('no'=>$data['out_trade_no']))->getField('uid');
			$redata=array(
				'orderno'=>$data['out_trade_no'],
				'amount'=>$data['total_fee']/100,
				'other'=>$data['attach'],
				'pay_id'=>$data['transaction_id'],
				'pay_way'=>'微信',
				'pay_time'=>time(),
				'tpl'=>'Pay_qqpay_pc',
			);
			return $redata;
		}
		return FALSE;
	}
	
	/**
     * 	获取返回数据
     */
	function getData(){
		return $this->xmlToArray($GLOBALS['HTTP_RAW_POST_DATA']);
	}
	
	/**
	 * 设置返回微信的xml数据
	 */
	function setReturnParameter($parameter, $parameterValue){
		$this->returnParameters[$this->$parameter] = $parameterValue;
	}
	
	/**
	 * 将xml数据返回微信
	 */
	function returnXml(){
		if($this->returnParameters["return_code"] == "SUCCESS"){
		   	return $this->arrayToXml($this->returnParameters);
		}
	}
	
	
    /**
     * 	作用：格式化参数，签名过程需要使用
     */
    public function formatBizQueryParaMap($paraMap, $urlencode)
    {
        $buff = '';
        ksort($paraMap);
        foreach ($paraMap as $k => $v) {
            if ($urlencode) {
                $v = urlencode($v);
            }
            //$buff .= strtolower($k) . "=" . $v . "&";
            $buff .= $k . '=' . $v . '&';
        }
        $reqPar = '';
        if (strlen($buff) > 0) {
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }
}
