支付宝扫码支付

支付宝扫码支付 RSA2签名 RSA2验签
创建于:2020年01月13日 更新于:2020年01月15日

官方文档:https://docs.open.alipay.com/194/105072

在开发之前需要申请应用的APPID,并设置密钥

密钥生成方法:https://docs.open.alipay.com/291/106103/

需要PHP支持openssl扩展
在php.ini中找到:
extension=php_openssl.dll 去掉前面的注释

请求预下单接口官方文档

class AliPay{
    $private $_appId; // 应用ID
    $private $_privateKey;// 应用私钥,加密使用
    $private $_publicKey;// 支付宝公钥,验签使用。ps:注意分清应用公钥和支付宝公钥

    public function __construct($appId, $privateKey, $publicKey){
        $this->_appId = $appId;
        $this->_privateKey = $privateKey;
        $this->_publicKey = $publicKey;
    }

    // 创建支付请求接口,返回生成二维码的链接
    public function createPay($order_code, $amount, $title){
        $param = array(
            "app_id" => $this->_appId,
            "method"  => 'alipay.trade.precreate',
            "notify_url"    => 'xxxxxx', // 异步回调地址
            "charset"    => 'utf-8',
            "sign_type"    => 'RSA2',
            "timestamp"    => date("Y-m-d H:i:s"),
            "version"    => '1.0',
            "biz_content"    => json_encode([
                "out_trade_no" => $order_code, // 商户订单号,唯一
                "total_amount" => $amount, // 订单总金额,单位为元,精确到小数点后两位
                "subject"   => $title, // 订单标题
                "timeout_express"   => "60m" // 该笔订单允许的最晚付款时间
            ])

        );

        $sign = $this->RSA2($param);

        if(!$sign){
            reuturn false;
        }

        $param['sign'] = $sign;

        $url = 'https://openapi.alipay.com/gateway.do';
        $response = $this->curl($url, $param);
        // response :{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"6141161365682511","qr_code":"https:\/\/qr.alipay.com\/bax03206ug0kulveltqc80a8"},"sign":"VrgnnGgRMNApB1QlNJimiOt5ocGn4a4pbXjdoqjHtnYMWPYGX9AS0ELt8YikVAl6LPfsD7hjSyGWGjwaAYJjzH1MH7B2/T3He0kLezuWHsikao2ktCjTrX0tmUfoMUBCxKGGuDHtmasQi4yAoDk+ux7og1J5tL49yWiiwgaJoBE="}

        $response = json_decode($response, true);
        if(is_array($response) && $response['alipay_trade_precreate_response']['msg'] == 'Success'){
            $result = $this->checkSign($response['alipay_trade_precreate_response'], $response['sign']);
            if(!$result){
                return false; // 验证签名失败
            }

            // 返回二维码链接,生成二维码
            return $response['alipay_trade_precreate_response'];
        }
    }

    // RSA2加密,
    public function RSA2($data){

         //将请求的参数进行排序
         ksort($data);//ksort()函数 根据参数的键进行升序排序
         reset($data);
         $signStr = '';
         foreach ($data as $key => $value) {
             if ($key == 'sign' || $value == '') continue;
             $signStr .= $key . '=' .$value .'&';
         }
         $signStr = trim($signStr, '&');


         $secretKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->_privateKey, 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----";
         // 请注意密钥 是不是有带   -----BEGIN RSA PRIVATE KEY-----   -----END RSA PRIVATE KEY-----

         $secretKey = openssl_pkey_get_private($secretKey);

         if ($secretKey) {
             $res = openssl_get_privatekey($secretKey);
             openssl_sign($signStr, $sign, $res, 'SHA256');
             $sign = base64_encode($sign);
             openssl_free_key($secretKey);
             return $sign;
         }
         return null;
     }

    public function curl($url, $postFields = null) {
        //创建curl资源
        $curl = curl_init();

        //设置URL和相应的选项
        curl_setopt($curl, CURLOPT_URL, $url);
        if(!empty($postFields)){
            curl_setopt($curl, CURLOPT_POST, true);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $postFields);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

        //执行curl
        $response = curl_exec($curl);
        curl_close($curl);

        return $response;
    }

    /**
     * 验证签名
     * @param $data 待验签字符串/数组
     * @param $sign 支付宝返回的签名
     * @return bool
     */
    public function checkSign($data, $sign){
        if(is_array($data)){
            $data = json_encode($data);
        }
        $public_key = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->_publicKey, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
        $res=openssl_get_publickey($public_key);
        return (bool)openssl_verify(
            $data,
            base64_decode($sign),
            $res,
            OPENSSL_ALGO_SHA256
        );
    }
}