首页 > 编程语言 >ecshop | php接入支付宝申报海关接口的总结【避坑】

ecshop | php接入支付宝申报海关接口的总结【避坑】

时间:2023-10-17 16:02:59浏览次数:52  
标签:避坑 sign private ecshop key curl php data 报关

第一次对接支付宝的报关接口,害!不明白这个流程是很难接上的,搞了一天半,终于给搞出来了。在这里留下一点文字吧。

代码前工作:

  1. 用支付宝的密钥生成工具生成一对2048的公私钥,这对公私钥用来完成支付宝支付的加签和验签。在这里插入图片描述 把公钥上传到 开放平台密钥中对应使用的应用接口加签方式中,私钥是用在支付接口中加签的,保存好! 在这里插入图片描述 在这里插入图片描述
  2. 用支付宝的密钥生成工具生成一对1024的公私钥,这对公私钥用来完成报关流程(1024位是技术客服推荐的),把公钥上传至 mapi网关产品密钥和老板wap支付密钥 的开发者公钥中去,密钥保存好,用来给报关文档中的sign字段加签。 在这里插入图片描述

现在开始写代码

看文档可以知道,要确认海关申报是否成功要接上两个接口:报关接口报关查询接口,当看到报关查询接口的返回参数中的status==succ时,才算报关成功。那就一步一步来吧,先接报关接口:

  1. 把文档中所需要的参数查询出来,放到一个数组里,注意:sign和sign_type字段先别写进去。
//推送支付宝
if($_REQUEST['act']=='push_ali'){
	//需要进行加签的数据
    $data = array(
        'amount' => $amount,                                    //报关金额
        'buyer_name' => $buyer_name,                            //订购人姓名
        'buyer_id_no' => $buyer_id_no,                          //订购人身份证
        'customs_place' => 'zongshu',                            //海关编号
        'merchant_customs_code' => 'xxxxx',              //商户海关备案号
        'merchant_customs_name' => 'xxxxx有限公司',      //商户海关备案名称
        'out_request_no' => $out_request_no,                   //报关流水号(订单号)
        'partner' => '2088xxxxxxxxxxxx',                      //合作者身份ID,2088开头
        'service' => 'alipay.acquire.customs',                //接口名称
        'trade_no' => $trade_no,                                //支付宝流水号
        '_input_charset' => 'utf-8',                          //参数编码字符集
    );
    
	$data = argSort($data);//对数组排序
    //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
    $sign_data= createLinkstring($data);
    //生成sign参数
    $sign = urlencode(rsaSign($sign_data));

    //签名结果与签名方式 加入请求提交参数组中
    $data['sign_type'] = 'RSA';
    $data['sign'] = $sign;

    $url = 'https://mapi.alipay.com/gateway.do?';
    $data = createLinkstring($data);
    //发送get请求的url
    $getUrl = $url.$data;
    $response = getHttpResponseGET($getUrl);
    //接受报关返回的xml,转换成数组
    $xml = simplexml_load_string($response);
    $data = json_decode(json_encode($xml),TRUE);
    
	/判断报关是否成功,成功则进行报关查询
    if($data['is_success'] == 'T'){
    	//继续写报关查询接口
    }else{
    	//返回错误代码
    }

argSort()、 createLinkstring()、rsaSign()、getHttpResponseGET()是支付宝官方提供的demo中的方法,你不想用他的也可以自己写,简单看一下吧

/**
 * 对数组排序
 * @param $para 排序前的数组
 * return 排序后的数组
 */
function argSort($para) {
    ksort($para);
    reset($para);
    return $para;
}

/**
 * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
 * @param $para 需要拼接的数组
 * return 拼接完成以后的字符串
 */
function createLinkstring($para) {
    $arg  = "";
    while (list ($key, $val) = each ($para)) {
        $arg.=$key."=".$val."&";
    }
    //去掉最后一个&字符
    $arg = substr($arg,0,count($arg)-2);

    //如果存在转义字符,那么去掉转义
    if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
    return $arg;
}

/**
 * RSA签名
 * @param $data 待签名数据
 * @param $private_key 商户私钥字符串
 * return 签名结果
 */
function rsaSign($data) {
    //商户私钥
    $private_key = "上面生成的1024位的密钥写在这里";
    //以下为了初始化私钥,保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
    $private_key=str_replace("-----BEGIN RSA PRIVATE KEY-----","",$private_key);
    $private_key=str_replace("-----END RSA PRIVATE KEY-----","",$private_key);
    $private_key=str_replace("\n","",$private_key);

    $private_key="-----BEGIN RSA PRIVATE KEY-----".PHP_EOL .wordwrap($private_key, 64, "\n", true). PHP_EOL."-----END RSA PRIVATE KEY-----";

    $res=openssl_get_privatekey($private_key);

    if($res)
    {
        openssl_sign($data, $sign,$res);
    }
    else {
        echo "您的私钥格式不正确!"."<br/>"."The format of your private_key is incorrect!";
        exit();
    }
    openssl_free_key($res);
    //base64编码
    $sign = base64_encode($sign);
    return $sign;
}

/**
 * 远程获取数据,GET模式
 * 注意:
 * 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
 * 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
 * @param $url 指定URL完整路径地址
 * @param $cacert_url 指定当前工作目录绝对路径
 * return 远程输出的数据
 */
function getHttpResponseGET($url) {
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
    curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
    $responseText = curl_exec($curl);
    //var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
    curl_close($curl);

    return $responseText;
}

这里有几点要注意一下:

  • rsaSign()方法中的private_key是使用1024位的密钥,用来给数据加签用的。
  • 可以post发送请求也可以发送get请求,官方技术推荐get方式。
  • rsa加签后的sign值是需要urlencode一下再进行拼装。

在这里插入图片描述 请求发送后,打印一下支付宝的同步返回,如果 is_success为 T ,则报关支付宝成功,但这不代表业务处理成功。实际上,海关返回信息并不是同步返回的,他会间隔10分钟左右。所以继续接入报关查询接口

if($data['is_success'] == 'T'){
        $response = $data['response'];//返回数组中的response数组
        $alipay_data = $response['alipay'];//response中的alipay数组

        //报关查询sign值加签参数
        $datas = array(
            'service' => 'alipay.overseas.acquire.customs.query',
            'partner' => '2088xxxxxxxxxxxx',
            '_input_charset' => 'utf-8',
            'out_request_nos' => $alipay_data['out_request_no']
        );
        //排序
        $datas = argSort($datas);
        //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
        $sign_datas= createLinkstring($datas);
        //生成sign参数
        $sign = urlencode(rsaSign($sign_datas));

        //签名结果与签名方式 加入请求提交参数组中
        $datas['sign_type'] = 'RSA';
        $datas['sign'] = $sign;
        //var_dump($datas);

        $datas = createLinkstring($datas);
        //报关查询发送get请求的url
        $getUrls = $url.$datas;

        //接受报关返回的xml,转换成数组
        $response = getHttpResponseGET($getUrls);
        $xml = simplexml_load_string($response);
        $datas = json_decode(json_encode($xml),TRUE);
        //找customs_declare中的status,succ是海关申报成功

在这里插入图片描述 这一步和报关其实差不多,主要是发送的数据不一样。接受到的结果如图,当status对于succ是,恭喜你,成功了!既然工作已经完成了,那就盘点一下我视为障碍的地方: 在这里插入图片描述

  • sign值:文档中写着参见9,签名机制,我找了半天没找到这个9在哪里,后来还是问客服解决的。
  • 刚开始说道的生成的两对公私钥,文档中没有看到对应的提醒,商户中心也没有对应的提醒,害!新手很难的啊。
  • 支付宝的公钥是会变的,每次更改商户的密钥对他都会变化一次。(刚开始我以为他不会变。。。。)
  • 如果你打印出来的数据显示不全,打开php.ini,在xdebug的地方加上:
xdebug.var_display_max_children=128 //允许一个数组最多显示多少个元素
xdebug.var_display_max_data=1024 //允许一个字符串变量最多显示多少个字节
xdebug.var_display_max_depth=10 //允许一个数组最多显示多少个维度

在简单说一下我对密钥对的理解: RSA 是一种非对称的签名算法,即签名密钥(私钥)与验签密钥(公钥)是不一样的, 私钥用于签名,公钥用于验签。

私钥就是锁,公钥就是钥匙,只有拿对应的钥匙(公钥)才能解对应的锁(私钥)。

功夫不负有心人,bug总会被解决的,自己看不懂就多问问多看看,看多了就熟了,问多了就懂了!

标签:避坑,sign,private,ecshop,key,curl,php,data,报关
From: https://blog.51cto.com/u_13727654/7907034

相关文章

  • ubuntu安装php7.4-8.0
    更新,加入源apt-getupdateapt-yinstallsoftware-properties-common安装存储库ppa:ondrej/php,它提供所有PHP版本add-apt-repositoryppa:ondrej/phpapt-getupdate开始安装php74apt-yinstallphp7.4php-v安装额外的php模块apt-getinstall-yphp7.4-clip......
  • uni-app结合PHP实现单用户登陆demo及解析
    这篇文章主要为大家介绍了uni-app结合PHP实现单用户登陆示例过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪单用户登陆uni-appsocket单用户登陆例推送单用户登陆例单用户登陆即在一个应用中,同一个用户只能在线登陆一个,一个用户登陆,在其他设备上会......
  • php中关于token验证的相关问题详解
    这篇文章主要介绍了php中关于token验证的相关问题详解的相关资料,需要的朋友可以参考下目录token验证首先是为什么用?那么怎么用呢?token的组成一般token组成:JWT组成:标准的组成:总结token验证什么是token?我相信很多开发者都或多或少听过基于token的用户鉴权和基于session的用户......
  • PHP轮子批量替换数据库前缀
    <?phpinclude_once('fix_mysql.inc.php');//设置好相关信息echo'<metacharset="utf-8">';$dbserver='localhost';$dbname='test';//替换成你的数据库名$dbuser='root';//替换成你的数据库用户名$dbpassword='123......
  • open_basedir(PHP可访问目录)
       open_basedir指令用来限制PHP只能访问那些目录,通常我们只需要设置Web文件目录即可。如果需要include加载外部脚本,也需要把脚本所在目录路径加入到open_basedir指令中,多个目录以分号(;)分割。   使用open_basedir需要注意的一点是,指定的显示实际上是前缀,而不是目录名......
  • PHP通用权限后台管理系统
    项目介绍一款PHP语言基于ThinkPhp6.x+Vue+ElementUI等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,目前框架已集成了完整的RBAC权限架构和常规基础模块,前端Vue端支持多主题......
  • PHP前后端分离开发框架
    项目介绍一款PHP语言基于ThinkPhp6.x+Vue+ElementUI等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,目前框架已集成了完整的RBAC权限架构和常规基础模块,前端Vue端支持多主题......
  • 下面是一个稍微复杂一些的 PHP 代码示例: <?php // 定义一个 Person 类 class Person
    下面是一个稍微复杂一些的PHP代码示例:<?php//定义一个Person类classPerson{private$name;private$age;//构造函数publicfunction__construct($name,$age){$this->name=$name;$this->age=$age;}//获取姓名publicfunctiong......
  • Mybatis使用SELECT LAST_INSERT_ID()返回0问题避坑
    Mybatis使用SELECTLAST_INSERT_ID()返回0问题避坑SELECTLAST_INSERT_ID()用于返回最后插入表中数据的主键值,一般用于表主键自增且需要用到该自增的主键值的情况<insertid="insertOrder"parameterType="com.example.bobosapce.Entity.WorkOrder">INSERTINTOWORKOR......
  • PhpStudy
    phpstudy使用1.下载安装下载链接:小皮面板(phpstudy)-让天下没有难配的服务器环境!(xp.cn)直接下载V8.1版本就行了,自行安装注意:安装目录不能有中文和空格2.使用安装打开后页面如下:启动apache访问如下就算成功:3.启动mysql可以在左侧软件管理里面下载你所需要的mysq......