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 }
  • 相关阅读:
    HDU 1097 a hard puzzle
    HDU 4588 Count The Carries
    不想用锐捷怎么办?锐捷出问题|锐捷不能用怎么办?用menohust代替吧
    线段树及其变种的相关资料(不定期更新)
    UVa 10075
    UVa 1301
    UVa 10256
    UVa 1453
    计算几何相关资料+题目推荐(不定期补充)
    UVa 11524
  • 原文地址:https://www.cnblogs.com/exo5/p/13572606.html
Copyright © 2011-2022 走看看