支付宝公钥证书 PHP 版本 SDK(用于现金红包等业务)

支付宝某些业务只能使用公钥证书方式来验签,但是只有 JAVA 版本的 SDK。所以转载一下大佬们做的 PHP 版本 SDK 供大家使用。
原文地址:https://developer.aliyun.com/ask/138868 ,要往下翻一点,2019-09-12 13:28:54 日用户1628209366284721 发的帖。

function getRootCertSN($str)
    {
        // return '687b59193f3f462dd5336e5abf83c5d8_02941eef3187dddf3d3b83462e1dfcf6';
        $arr = preg_split('/(?=-----BEGIN)/', $str, -1, PREG_SPLIT_NO_EMPTY);
        $str = null;
        foreach ($arr as $e) {
            $sn = getCertSN($e, true);
            if (!$sn) {
                continue;
            }
            if ($str === null) {
                $str = $sn;
            } else {
                $str .= "_" . $sn;
            }
        }
        return $str;
    }

    function getCertSN($str, $matchAlgo = false)
    {
        /*
        根据java SDK源码:AntCertificationUtil::getRootCertSN
        对证书链中RSA的项目进行过滤(猜测是gm国密算法java抛错搞不定,故意略去)
        java源码为:

        if(c.getSigAlgOID().startsWith("1.2.840.113549.1.1"))

        根据 https://www.alvestrand.no/objectid/1.2.840.113549.1.1.html
        该OID为RSA算法系。
         */
        if ($matchAlgo) {
            openssl_x509_export($str, $out, false);
            if (!preg_match('/Signature Algorithm:.*?RSA/im', $out, $m)) {
                return;
            }

        }
        $a = openssl_x509_parse($str);
        $issuer = null;
        // 注意:根据java代码输出,需要倒着排列 CN,OU,O
        foreach ($a["issuer"] as $k => $v) {
            if ($issuer === null) {
                $issuer = "$k=$v";
            } else {
                $issuer = "$k=$v," . $issuer;
            }
        }
        #    echo($issuer . $a["serialNumber"] . "\n");
        $serialNumberHex = decimalNotation($a['serialNumberHex']);
        $sn = md5($issuer . $serialNumberHex);
        return $sn;
    }

    function decimalNotation($hex)
    {
        $dec = 0;
        $len = strlen($hex);
        for ($i = 1; $i <= $len; $i++) {
            $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
        }
        return $dec;
    }

然后在公共请求参数里面传递 app_cert_snalipay_root_cert_sn 两个参数即可。

本作品采用《CC 协议》,转载必须注明作者和本文链接
原创。 所有 Laravel 文章均已收录至 Github laravel-tips 项目。
Ίκαρος
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。