APP支付(支付宝和微信生成客户端签名及回调验签)
<?php
namespace Pn\Controller;
use Think\Controller\RestController;
class PayController extends RestController{
    public function __construct(){
        import('Vendor.WePay.WeEncryption');
        import('Vendor.WePay.Curl');
    }
    public function Payment(){
        $arr['appid'] = $_POST['appid'];//应用id
        $arr['userdid'] = $_POST['userdid'];//登录用户id
        $arr['paytype'] = $_POST['paytype'];//支付方式
        $arr['productid'] = $_POST['productid'];//商品id
        $arr['time'] = $_POST['time'];
        $sign = $_POST['sign'];//安全验证sign
        $vsign = strrank($arr);//签名加密
        
        if($vsign!=$sign){
            $return['respCode'] = 1001;
            $return['msg'] = "签名错误";
            $this -> response($return,'json');//返回数据
            exit();
        }else{
            switch ($_POST["paytype"]){
                case 1://支付宝
                    $data["signdata"] = $this->alipay();
                    echo json_encode($data);
                break;
                case 2://微信支付
                    $data = $this->wechatpay($_POST['appid'],$_POST['userdid'],$_POST['productid']);
                    echo $data;
                break;
                default:
                $return["respCode"] = "error"; 
                $return['msg'] = "支付方式错误";
                $this -> response($return,'json');//返回数据
                exit();
            }
        }
    }
    /**
     * 微信APP客户端支付
     */
    public function wechatpay($appid,$userdid,$productid){
       $WeEncryption = new \WeEncryption();	//实例化传输类;
       switch ($productid){
           case 1://季付商品(¥100)
               $body = "陪你季付VIP";//商品描述
               $total_fee = "100.00";//总金额
           break;
           case 2://月付商品(¥50)
               $body = "陪你月付VIP";//商品描述
               $total_fee = "50.00";//总金额
           break;
       }
       $out_trade_no = date("YmdHis").rand(10,100);//商户订单号
       $spbill_create_ip = getclientip();//终端IP

       $data = array(
           'body'				=>	$body,
           'out_trade_no'		=>	$out_trade_no,
           'total_fee'			=>	$total_fee,
           'spbill_create_ip'	=>	$spbill_create_ip,
       );
       
       $encpt = $WeEncryption::getInstance();	//实例化签名类
       $url = "http://xxxx.com/Pay/wx_notify_verify";
       $encpt->setNotifyUrl($url);			//设置异步通知地址
       
       $curl = new \Curl();				//实例化传输类;
       $xml_data = $encpt->sendRequest($curl, $data);		//发送请求

       $postObj = $encpt->xmlToObject($xml_data);			//解析返回数据
       if ($postObj === false) {
           echo 'FAIL';
           exit;
       }
       if ($postObj->return_code == 'FAIL') {
           echo $postObj->return_msg;
       } else {
           $resignData = array(
               'appid'			=>	$postObj->appid,
               'partnerid'		=>	$postObj->mch_id,
               'prepayid'		=>	$postObj->prepay_id,
               'noncestr'		=>	$postObj->nonce_str,
               'timestamp'		=>	time(),
               'package'	=>	'Sign=WXPay'
           );
           $sign = $encpt->getClientPay($resignData);
           $resignData['sign'] = $sign;
           return  json_encode($resignData);
       }
    }
    /**
     * 微信App支付回调
     */
    public function wx_notify_verify(){
        $WeEncryption = new \WeEncryption();	//实例化传输类;
        $encpt = $WeEncryption::getInstance();
        $obj = $encpt->getNotifyData();
        if ($obj === false) {
            exit;
        }
        if ($obj) {
            $data = array(
                'appid'				=>	$obj->appid,
                'mch_id'			=>	$obj->mch_id,
                'nonce_str'			=>	$obj->nonce_str,
                'result_code'		=>	$obj->result_code,
                'openid'			=>	$obj->openid,
                'trade_type'		=>	$obj->trade_type,
                'bank_type'			=>	$obj->bank_type,
                'total_fee'			=>	$obj->total_fee,
                'cash_fee'			=>	$obj->cash_fee,
                'transaction_id'	=>	$obj->transaction_id,
                'out_trade_no'		=>	$obj->out_trade_no,
                'time_end'			=>	$obj->time_end
            );
            $sign = $encpt->getSign($data);
            if ($sign == $obj->sign) {//验签通过
                $reply = "<xml>
					<return_code><![CDATA[SUCCESS]]></return_code>
					<return_msg><![CDATA[OK]]></return_msg>
				</xml>";
                echo $reply;
                exit;
            }else{
                $reply = "<xml>
					<return_code><![CDATA[FAIL]]></return_code>
					<return_msg><![CDATA[NO]]></return_msg>
				</xml>";
                echo $reply;
                exit;
            }
        }
    }
    
    /**
     * https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.NgdeQA&treeId=59&articleId=103663&docType=1
     * 服务端生成app支付使用的参数以及签名
     * @param $params <Array>
     * @return <Array>
    */
    public function alipay(){ 

        $ali = array(
          'service' => 'mobile.securitypay.pay',
          'partner' => 'xxxx',
          '_input_charset' => 'utf-8',
          'sign_type' => 'RSA',
          'sign' => '',
          'notify_url' => 'http://xxxxxxxx.com/Pay/alipay_notify_url',//回调地址
          'out_trade_no' => date("YmdHis").rand(10,100),//商户网站唯一订单号
          'subject' => '测试',//商品名称
          'payment_type' => 1,//支付类型
          'seller_id' => 'lql@jieku.com',//支付宝账号
          'total_fee' => '0.01',//总金额
          'body' => 'Iphone6 16G',//商品详情
        );
        
        $ali = self::argSort($ali);
        $str = '';
        
        foreach($ali as $key=>$val){
            if($key == 'sign_type' || $key == 'sign'){
                continue;
            }else{
                if($str == ''){
                    $str = $key.'='.'"'.$val.'"';
                }else{
                    $str = $str.'&'.$key.'='.'"'.$val.'"';
                }
            }
        }        
                               
        $sign = urlencode(self::sign($str));
        $str = $str.'&sign='.'"'.$sign.'"'.'&sign_type='.'"'.$ali['sign_type'].'"';//传给支付宝接口的数据
        return $str;
    }
    
    /**
     * 准备签名参数
     */
    public function argSort($para) {
        ksort($para);
        reset($para);
        return $para;
    }
    
   /**
     * 生成请求参数的签名
     * @param $params <Array>
     * @return <String>
     *
   */
   public function sign($data) {
        //读取私钥文件
        $priKey = file_get_contents('./Public/key/rsa_private_key.pem');//私钥文件路径
        //转换为openssl密钥,必须是没有经过pkcs8转换的私钥
        $res = openssl_get_privatekey($priKey);
        //调用openssl内置签名方法,生成签名$sign
        openssl_sign($data, $sign, $res);
        //释放资源
        openssl_free_key($res);
        //base64编码
        $sign = base64_encode($sign);
        return $sign;
    }
    
   /**
     * 支付宝回调地址
    */
    public function alipay_notify_url(){

        $orderpay = M("orderpay");
        $async = empty($_GET);
        $data = $async ? $_POST : $_GET;
  
        if (empty($data)) {
            return FALSE;
        }

        $signValid = $this->verifyParameters($data, $data["sign"]);//验签
        $notify_id = isset($data['notify_id']) ? $data['notify_id'] : NULL;
        
        //获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
        $responseTxt = 'true';
        if (!empty($notify_id)) {
            $responseTxt = $this->verifyFromServer($notify_id);
        }

        if($signValid && preg_match("/true$/i", $responseTxt)){//验证成功
            if($_POST['trade_status'] == 'TRADE_FINISHED'){
                
               $_POST["createdatetime"] = time();
               
               if($orderpay->create()){
                    $orderpay->add();
                    echo "success";
               }else{
                   echo "fail";//验证失败
               }
            }
            else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
                $_POST["createdatetime"] = time();
                if($orderpay->create()){
                    $orderpay->add();
                    echo "success";
                }else{
                    echo "fail";//验证失败
                }
            }
        }else{
            echo "fail";//验证失败
        }
    }
    /**
     * 将剩下参数进行url_decode, 然后进行字典排序,组成字符串,得到待签名字符串
     * @param unknown $params
     * @param unknown $sign
     * @return boolean
     */
    function verifyParameters($params, $sign) {
        
        $public_key_path = './Public/key/alipay_public_key.pem';//公钥(合作伙伴)

        $params = $this->filterSignParameter($params);
        ksort($params);
        reset($params);
    
        $content = urldecode(http_build_query($params));
       
        return $this->rsaVerify($content, $public_key_path, $sign);

    }
    /**
     * 过滤参数,去除sign/sign_type参数
     * @param $params
     * @return <Array>
     */
    function filterSignParameter($params) {
        $result = array();
        foreach ($params as $key => $value) {
            if ($key != 'sign' && $key != 'sign_type' && $value) {
                $result[$key] = $value;
            }
        }
        return $result;
    }
    /**
     * RSA验签,注意验签的公钥是支付宝的公钥,不是自己生成的rsa公钥,可以在淘宝的demo中获得
     * @param $data string 待签名数据
     * @param $ali_public_key_path string 支付宝的公钥文件路径
     * @param $sign string 要校对的的签名结果
     * @return <Boolean> 验证结果
     * @throws Exception
     */
    function rsaVerify($data, $ali_public_key_path, $sign) {
        $pubKey = file_get_contents($ali_public_key_path);
        $res = openssl_get_publickey($pubKey);
        if(!$res){
            throw new \Exception('公钥格式错误');
        }
        $result = (bool)openssl_verify($data, base64_decode($sign), $res);
        openssl_free_key($res);
        return $result;
    }
    function verifyFromServer($notify_id) {
        $transport = "http";
        $partner = "xxxxxxxxxxx";
        $cacert = "./Public/key/cacert.pem";
        $transport = strtolower(trim($transport));
        $partner = trim($partner);
        $veryfy_url = "http://notify.alipay.com/trade/notify_query.do?partner=$partner¬ify_id=$notify_id";
        $curl = curl_init($veryfy_url);
        curl_setopt($curl, CURLOPT_HEADER, 0); // 过滤HTTP头
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
        curl_setopt($curl, CURLOPT_CAINFO, $cacert);//证书地址
        $responseText = curl_exec($curl);
        // var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
        curl_close($curl);
        return $responseText;
    }
      /**格式化公钥
    * $pubKey PKCS#1格式的公钥串
    * return pem格式公钥, 可以保存为.pem文件
    */
   function formatPubKey($pubKey) {
       $fKey = "-----BEGIN PUBLIC KEY-----\n";
       $len = strlen($pubKey);
       for($i = 0; $i < $len; ) {
           $fKey = $fKey . substr($pubKey, $i, 64) . "\n";
           $i += 64;
       }
       $fKey .= "-----END PUBLIC KEY-----";
       return $fKey;
   }
}
问题咨询QQ1370373713http://blog.csdn.net/apensu/article/details/46945193

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Qiang1370373713/article/details/53433976
个人分类: PHP
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

APP支付(支付宝和微信生成客户端签名及回调验签)

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭