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

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

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

代码前工作:

  1. 用支付宝的密钥生成工具生成一对2048的公私钥,这对公私钥用来完成支付宝支付的加签和验签。在这里插入图片描述

把公钥上传到 开放平台密钥中对应使用的应用接口加签方式中,私钥是用在支付接口中加签的,保存好!
在这里插入图片描述
在这里插入图片描述

  1. 用支付宝的密钥生成工具生成一对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总会被解决的,自己看不懂就多问问多看看,看多了就熟了,问多了就懂了!

目录
相关文章
|
2月前
|
Java PHP 数据安全/隐私保护
PHP 面向对象,构造函数,析构函数,继承,方法的重写,接口抽象类,static,final,this,parent,self的异同和作用
本文详细介绍了PHP面向对象编程的一系列核心概念和用法,包括构造函数、析构函数、继承、方法重写、访问控制、接口、抽象类、静态成员、final关键字、以及this、self、parent这三个关键字的异同和作用。通过具体示例代码,展示了如何在PHP中使用这些面向对象的特性,以及它们在实际开发中的应用。
PHP 面向对象,构造函数,析构函数,继承,方法的重写,接口抽象类,static,final,this,parent,self的异同和作用
|
3月前
|
关系型数据库 MySQL 应用服务中间件
win7系统搭建PHP+Mysql+Apache环境+部署ecshop项目
这篇文章介绍了如何在Windows 7系统上搭建PHP、MySQL和Apache环境,并部署ECShop项目,包括安装配置步骤、解决常见问题以及使用XAMPP集成环境的替代方案。
54 1
win7系统搭建PHP+Mysql+Apache环境+部署ecshop项目
|
3月前
|
网络协议 API PHP
PhalApi:在宝塔一键安装部署PHP开源接口框架的教程
要在宝塔面板上一键安装部署PhalApi开源接口框架,首先进入宝塔软件商店,切换到“一键部署”选项,搜索“phalapi”并点击“一键部署”。安装时需填写接口域名、数据库名及密码,提交后等待安装完成。安装成功后可在宝塔面板中查看新站点和源代码目录,并通过DNS解析设置访问接口域名,如`http://myapi.phalapi.net/`。默认开启的调试模式便于测试,可通过修改`config/sys.php`中的`debug`值为`false`关闭。最后,在源代码中开发自己的PHP接口,PhalApi会自动生成在线接口文档,方便后续调用与维护。更多详细教程可参考官方文档。
|
4月前
|
Java API PHP
【亲测有效,官方提供】php版本企查查api接口请求示例代码,php请求企查查api接口,thinkphp请求企查查api接口
【亲测有效,官方提供】php版本企查查api接口请求示例代码,php请求企查查api接口,thinkphp请求企查查api接口
132 1
|
5月前
|
PHP 开发工具
php免费用免认证的微信支付宝支付
php免费用免认证的微信支付宝支付
40 5
|
5月前
|
JSON 安全 API
实战指南:使用PHP构建高性能API接口服务端
构建RESTful API的简要指南:使用PHP和Laravel,先安装Laravel并配置数据库,接着在`api.php`中定义资源路由,创建`PostController`处理CRUD操作,定义`Post`模型与数据库交互。使用Postman测试API功能,如创建文章。别忘了关注安全性、错误处理和性能优化。
130 2
|
4月前
|
PHP
PHP 接口和继承的异同?
【7月更文挑战第2天】PHP 接口和继承的异同?
28 0
|
4月前
|
PHP
PHP中接口如何定义?
【7月更文挑战第2天】PHP中接口如何定义?
26 0
|
4月前
|
前端开发 PHP 数据格式
【附带效果视频】php接口给前端返回流式数据,php使用event-stream进行数据推送,循环一次输出一次
【附带效果视频】php接口给前端返回流式数据,php使用event-stream进行数据推送,循环一次输出一次
153 0
|
6月前
|
PHP 数据安全/隐私保护
【PHP开发专栏】PHP接口与抽象类的应用
【4月更文挑战第30天】本文探讨了PHP中接口与抽象类的使用,包括定义、实现和比较。接口用于规定实现类必须提供的方法签名,而抽象类则可以包含方法实现和抽象方法。一个类可实现多个接口,但只能继承一个抽象类。根据需求,若需定义不相关类的共同方法,选择接口;若需提供共享属性和非抽象方法,选择抽象类。通过实战应用示例,展示了如何在动物园管理系统中结合接口和抽象类进行设计。理解两者有助于提升代码的复用性和可维护性。
42 2
下一篇
无影云桌面