支付寶公鑰證照 PHP 版本 SDK(用於現金紅包等業務)

Ίκαρος發表於2019-10-19

支付寶某些業務只能使用公鑰證照方式來驗籤,但是隻有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兩個引數即可。

原創。 所有 Laravel 文章均已收錄至 Github laravel-tips 專案。

相關文章