zoukankan      html  css  js  c++  java
  • 支付宝支付封装【修改至2021.01.11】

    2021.01.11

    关于支付宝退款问题

    1 调用支付宝sdk

    2 自己写封装

    1 调用支付宝sdk,网络是比较强大的,只要搜索都能搜索到。

     1 public function refund_and_query($data)
     2     {
     3         import("alipayaop/AopClient", EXTEND_PATH);
     4         import("alipayaop/request/AlipayTradeRefundRequest", EXTEND_PATH);
     5         // include('alipayaop/AopClient.php');
     6         // // include('alipayaop/request/AlipayTradeAppPayRequest.php');
     7         // include('alipayaop/request/AlipayTradeRefundRequest.php');
     8 
     9 
    10         $aop = new AopClient();
    11         $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
    12         $aop->appId = $this->config['app_id'];
    13         $aop->rsaPrivateKey = $this->config['rsaPrivateKey'];
    14         $aop->alipayrsaPublicKey=$this->config['alipayPublicKey'];
    15         $aop->apiVersion = $this->version;
    16         $aop->signType = $this->sign_type;
    17         $aop->postCharset=$this->charset;
    18         $aop->format='json';
    19         $request = new AlipayTradeRefundRequest();
    20         $bizcontent = json_encode([
    21             'out_trade_no'=>$data['out_trade_no'],
    22             // 'trade_no'=> $wepay_serial,
    23             'refund_amount'=> $data['refund_fee'],
    24             'refund_reason'=>'正常退款'
    25          ]);
    26         $request->setBizContent($bizcontent);
    27         $result = $aop->execute($request);
    28         FLog($result,'refund_and_query_alipay');
    29         $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
    30 
    31         $resultCode = $result->$responseNode->code;
    32         
    33         if(!empty($resultCode)&&$resultCode == 10000){
    34            return ['code'=>1,'msg'=>'退款成功'];
    35         } else {
    36            $resultMsg  = $result->$responseNode->sub_msg;
    37            return ['code'=>0,'msg'=>$resultMsg];
    38         }
    39     }

    对于以上使用sdk 出来的结果以及调用方式来说相当的简单。我这边是直接使用官方提供的sdk 引入后 直接使用 import 调用

    无任何需要注意的地方只要能保证输入的值没有问题,就百分百成功,而且不像支付的时候会遇到各种问题,至少我这边没有

    2 自己写封装

    无论关于使用sdk还是自己写 我都是在以前支付封装中加入书写的。下面不给出完整的代码,只针对支付退款。并且由于时间问题,我这里没有给出特别完美的代码,只能说带入没有问题。主要说的是在这个过程中发现的问题

     1 public function refund_and_query1($data)
     2     {
     3         $biz_content=[
     4             'out_trade_no'=>$data['out_trade_no'],
     5             'refund_amount'=>$data['refund_fee'],
     6             'refund_reason'=>'正常退款'
     7         ];
     8         $postdata=[
     9             'app_id'=>$this->config['app_id'],
    10             'version'=>$this->version,
    11             'format'=>'json',
    12             'sign_type'=>$this->sign_type,
    13             'method'=>'alipay.trade.refund',
    14             'timestamp'=>date('Y-m-d H:i:s'),
    15             // 'timestamp'=>'2021-01-11 10:41:23',
    16 
    17             'charset'=>$this->charset,
    18         ];
    19 
    20         // dump($biz_content);
    21 
    22 
    23         // openssl_sign($str_q, $sign, $rsaPrivateKey, OPENSSL_ALGO_SHA256);
    24 
    25         $bizcontentD=['biz_content'=>json_encode($biz_content)];
    26         $biz_content_res=$this->alisign(array_merge($bizcontentD,$postdata));
    27         $postdata['sign']=$biz_content_res['sign'];
    28         dump($postdata['sign']);
    29         // die;
    30 
    31 
    32 
    33         $str=$this->keyandvalStr($postdata,1);
    34 
    35 
    36 
    37 
    38         //系统参数放入GET请求串
    39         $requestUrl = $this->submitUrl . "?".$str;
    40 
    41         dump($requestUrl);
    42 
    43       
    44 
    45 
    46         //发起HTTP请求
    47         try {
    48             $resp = $this->curl($requestUrl, $bizcontentD);
    49             dump($resp);
    50         } catch (Exception $e) {
    51             $this->logCommunicationError($sysParams["method"], $requestUrl, "HTTP_ERROR_" . $e->getCode(), $e->getMessage());
    52             return false;
    53         }
    54     }

    针对以上代码发现的问题。

    1、对于 biz_content 的处理,不同于支付的时候,除了在sign中使用 在生成数据字符串拼接的时候并没有用到,而在http请求的时候却存在着一定的使用

    2、在发起HTTP请求的时候,最好还是使用官方提供的curl,因为自己写的时候总是会报 验签错误 

    protected function curl($url, $postFields = null)
        {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_FAILONERROR, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    
            $postBodyString = "";
            $encodeArray = Array();
            $postMultipart = false;
    
    
            if (is_array($postFields) && 0 < count($postFields)) {
    
                foreach ($postFields as $k => $v) {
                    if ("@" != substr($v, 0, 1)) //判断是不是文件上传
                    {
    
                        $postBodyString .= "$k=" . $v . "&";
                        $encodeArray[$k] = $v;
                    } else //文件上传用multipart/form-data,否则用www-form-urlencoded
                    {
                        $postMultipart = true;
                        $encodeArray[$k] = new CURLFile(substr($v, 1));
                    }
    
                }
                unset ($k, $v);
                curl_setopt($ch, CURLOPT_POST, true);
                if ($postMultipart) {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, $encodeArray);
                } else {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString, 0, -1));
                }
            }
    
            if (!$postMultipart) {
                $headers = array('content-type: application/x-www-form-urlencoded;charset=utf-8');
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            }
    
            $reponse = curl_exec($ch);
    
            if (curl_errno($ch)) {
    
                throw new Exception(curl_error($ch), 0);
            } else {
                $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                if (200 !== $httpStatusCode) {
                    throw new Exception($reponse, $httpStatusCode);
                }
            }
    
            curl_close($ch);
            return $reponse;
        }

    重新更新后提示几点注意项

    1 生成的公私钥为2048位,上传支付宝公钥自己保留私钥做数据加密

    2 上传支付宝公钥后会出现两个公钥  一个是自己提供的 一个是支付宝端生成的,保留支付宝公钥,主要做回调验签使用

    3 这次改好后就不需要再为支付宝无法验签发愁了。回调中调用 rsaCheck 将获取的数据原封不动的传入  就行了喔 是不是很方便   看图了解

      

    忘记之前有没有做过测试  不过这次的测试是 mobile 直接过 没有问题

      1 <?php
      2 namespace pay;
      3 
      4 /**
      5  * 支付宝支付
      6  */
      7 class  Alipay
      8 {
      9     // 公私钥 2048 位
     10     private $config = [
     11         "app_id"=>"*****************",
     12         "rsaPrivateKey"=>"*******************************",
     13         "alipayPublicKey"=>"*********************",//支付宝公钥
     14        
     15     ];
     16 
     17     private $charset = 'utf-8';
     18     private $sign_type = 'RSA2';
     19     private $version = '1.0';
     20 
     21 
     22     private $calltype = 'app';//调用端口 app mobile pc
     23     private $submitUrl = "https://openapi.alipay.com/gateway.do" ;//提交地址
     24     // private $submitUrl = "https://openapi.alipaydev.com/gateway.do";//测试地址
     25     private $submit_auto = true;
     26 
     27     public function __construct($payTypeInfo=[]){
     28         if($payTypeInfo)
     29         {
     30             foreach ($payTypeInfo as $k => $val) {
     31                 if($k=='calltype')
     32                 {
     33                     $this->calltype=$val['val']!=''?$val['val']:$this->calltype;
     34                 }else{
     35                     // $this->config[$k]=$val['val'];
     36                 }
     37             } 
     38         }
     39     }
     40     public function index($data)
     41     {
     42         // 端口检测
     43         $res=$this->calltypeCheck($data);
     44         if($res['code']==0){ return $res; }
     45 
     46         $calltype=$this->calltype;
     47         return $this->$calltype($data);
     48     }
     49 
     50     public function app($data)
     51     {
     52         $str=$this->keyandvalStr($this->postdata($data),1);
     53           Flog($str);
     54         // $str=$this->submitUrl.'?'.$str;
     55         // //返回链接不能带官方https链接
     56         return ['code'=>1,'data'=>['type'=>'app','str'=>$str]];
     57     }
     58 
     59     public function pc($data)
     60     {
     61         $html=$this->formsubmithtml($this->submitUrl,$this->postdata($data));
     62         // var_dump($html);
     63         return ['code'=>1,'data'=>['type'=>'pc','html'=>$html]];
     64     }
     65 
     66     public function mobile($data)
     67     {
     68         // dump($data);
     69         $str=$this->keyandvalStr($this->postdata($data),1);
     70         $url="https://openapi.alipay.com/gateway.do?".$str;
     71         return ['code'=>1,'data'=>['type'=>'mobile','url'=>$url]];
     72     }
     73 
     74 
     75     // 获取数据
     76     public function postdata($data)
     77     {
     78         $calltypeD=$this->calltypeD();
     79 
     80         $return_url=$data['return_url'];
     81         $notify_url=$data['notify_url'];
     82 
     83         // 对subiect进行 & 删除
     84         $subject=str_replace("&","",$data['subject']);
     85 
     86         $biz_content=[
     87             'body'=>'',
     88             'subject'=>$subject,
     89             'out_trade_no'=>$data['pay_sn'],
     90             'timeout_express'=>'30m',
     91             'total_amount'=>$data['total'],
     92             'product_code'=>$calltypeD['product_code'],
     93             "goods_type"=>1,//商品类型 0虚拟商品 1实物商品
     94         ];
     95         $post=[
     96             'app_id'=>$this->config['app_id'],
     97             'method'=>$calltypeD['method'],
     98             'format'=>'json',
     99             'charset'=>$this->charset,
    100             'sign_type'=>$this->sign_type,
    101             'return_url'=>$return_url,
    102             'sign'=>'',
    103             'timestamp'=>date('Y-m-d H:i:s'),
    104             'version'=>$this->version,
    105             'notify_url'=>$notify_url,
    106             'biz_content'=>json_encode($biz_content),
    107         ];
    108 
    109         $signdata=$this->alisign($post);
    110 
    111         return $signdata;
    112     }
    113 
    114     // 根据类型获取想要的信息
    115     public function calltypeD($field='')
    116     {
    117         $D=[
    118             'app'=>['product_code'=>'QUICK_MSECURITY_PAY','method'=>'alipay.trade.app.pay'],
    119             'pc'=>['product_code'=>'FAST_INSTANT_TRADE_PAY','method'=>'alipay.trade.page.pay'],
    120             'mobile'=>['product_code'=>'QUICK_WAP_WAY','method'=>'alipay.trade.wap.pay'],
    121         ];
    122         if($field!='')
    123         {
    124             return isset($D[$this->calltype])?$D[$this->calltype][$field]:'';
    125         }else{
    126             return isset($D[$this->calltype])?$D[$this->calltype]:[];
    127         }
    128 
    129 
    130     }
    131 
    132     // 端口检测
    133     public function calltypeCheck($data)
    134     {
    135         // 对配置信息进行检测
    136         if($this->config['app_id']=='') { return ['code'=>0,'msg'=>'请先配置 app_id']; }
    137         if($this->config['rsaPrivateKey']=='') { return ['code'=>0,'msg'=>'请先配置 rsaPrivateKey']; }
    138 
    139         return ['code'=>1,'msg'=>'检测通过'];
    140     }
    141 
    142 
    143     /************************** 支付宝公用方法 ************************************/
    144 
    145     public function alisign($data)
    146     {
    147         $rsaPrivateKey=$this->config['rsaPrivateKey'];
    148         $buff = "";
    149         ksort($data);
    150         $buff=$this->keyandvalStr($data);
    151         $str  = chunk_split($rsaPrivateKey, 64, "
    ");
    152         $res = "-----BEGIN RSA PRIVATE KEY-----
    $str-----END RSA PRIVATE KEY-----
    ";
    153 
    154         $sign=$this->ras2Sign($buff,$res);
    155         $data['sign']=$sign;
    156         return $data;
    157     }
    158     public function keyandvalStr($data,$flg=0)
    159     {
    160         $buff="";
    161         foreach ($data as $k => $v) {
    162             if($flg!=0 && $v != "" && !is_array($v))
    163             {
    164                 $v=urlencode($v);
    165                 $buff .= $k . "=" . $v . "&";
    166             }else{
    167                 if($k != "sign" && $v != "" && !is_array($v)){
    168                     $buff .= $k . "=" . $v . "&";
    169                 }
    170             }
    171         }
    172         $buff = trim($buff, "&");
    173         return $buff;
    174     }
    175 
    176     public function ras2Sign($buff,$res)
    177     {
    178         $sign='';
    179         openssl_sign($buff, $sign, $res, OPENSSL_ALGO_SHA256);
    180         $sign = base64_encode($sign);
    181         return $sign;
    182     }
    183     public function formsubmithtml($action,$data)
    184     {
    185         $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$action."' method='POST'>";
    186         foreach ($data as $key => $value) {
    187             $val = str_replace("'","&apos;",$value);
    188             $sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>";
    189         }
    190         $sHtml = $sHtml."<input type='submit' class='paysubmit' value='ok' ></form>";
    191         if($this->submit_auto==true)
    192         {
    193             $sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";
    194         }
    195 
    196         return $sHtml;
    197     }
    198 
    199 
    200 
    201     /******************************回调验签*************************************/
    202     public function rsaCheck($params)
    203     {   
    204         $gmt_create=$params['gmt_create'];
    205         $config=$this->config;
    206         $sign = $params['sign'];
    207 
    208         unset($params['sign']);
    209         unset($params['sign_type']);
    210         return $this->verify($this->getCheckSignContent($params), $sign, $config['alipayPublicKey'], $this->sign_type);
    211     }
    212 
    213     function getCheckSignContent($params)
    214     {
    215         ksort($params);
    216         $stringToBeSigned = "";
    217         $i = 0;
    218         foreach ($params as $k => $v) {
    219             if ($i == 0) {
    220                 $stringToBeSigned .= "$k" . "=" . "$v";
    221             } else {
    222                 $stringToBeSigned .= "&" . "$k" . "=" . "$v";
    223             }
    224             $i++;
    225         }
    226 
    227         unset ($k, $v);
    228         return $stringToBeSigned;
    229     }
    230 
    231 
    232 
    233     function verify($data, $sign, $alipayPublicKey, $signType = 'RSA')
    234     {
    235         $res = "-----BEGIN PUBLIC KEY-----
    " .
    236             wordwrap($alipayPublicKey, 64, "
    ", true) .
    237             "
    -----END PUBLIC KEY-----";
    238 
    239         ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
    240 
    241         //调用openssl内置方法验签,返回bool值
    242 
    243         $result = FALSE;
    244         if ("RSA2" == $signType) {
    245             $result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256) === 1);
    246         } else {
    247             $result = (openssl_verify($data, base64_decode($sign), $res) === 1);
    248         }
    249 
    250         return $result;
    251     }
    252 
    264 }
  • 相关阅读:
    轻重搭配
    EF的优缺点
    使用bootstrap-select有时显示“Nothing selected”
    IIS发布 HTTP 错误 500.21
    js添加的元素无法触发click事件
    sql server查看表是否死锁
    sql server把一个库表的某个字段更新到另一张表的相同字段
    SQLSERVER排查CPU占用高的情况
    SQL server中如何按照某一字段中的分割符将记录拆成多条
    LINQ to Entities does not recognize the method 'System.DateTime AddDays(Double)' method, and this method cannot be translated into a store expression.
  • 原文地址:https://www.cnblogs.com/exo5/p/13572606.html
Copyright © 2011-2022 走看看