PHP实现支付宝当面付-扫码支付接口[纯手写非SDK]

该接口为卢雨高手写完成,不借助其他任何类或现成的SDK,

该支付方式不需要支付宝商户后台做授权,只需要拿到app_id、privatekey、publickey三个参数即可,拿到这三个参数任意一个网站都可以发起支付和通知

类代码

<?php
//支付宝当面付,整合扫码支付
//2020年12月3日
//By:sevstudio
namespace SevStudio;
class Alipayf2fpay{
     
    private $AppID = null;
    private $PrivateKey = null;
    private $PublicKey = null;
    function __construct($config=[]){
        if(!empty($config['app_id'])) $this->AppID = $config['app_id'];
        if(!empty($config['privatekey'])) $this->PrivateKey = $config['privatekey'];
        if(!empty($config['publicKey'])) $this->PublicKey = $config['publicKey'];
    }
     
    //传入配置
    public function init($config){
        if(!is_array($config)) throw new \Exception('配置格式错误');
        if(empty($config['app_id'])) throw new \Exception('请传入商户APPID');
        if(empty($config['privatekey'])) throw new \Exception('请传入商户私钥');
        if(empty($config['publicKey'])) throw new \Exception('请传入商户公钥');
        $this->AppID = $config['app_id'];
        $this->PrivateKey = $config['privatekey'];
        $this->PublicKey = $config['publicKey'];
    }
     
    //检测配置
    private function checkInit(){
        if(empty($this->AppID)) throw new \Exception('请传入商户APPID');
        if(empty($this->PrivateKey)) throw new \Exception('请传入商户私钥');
        if(empty($this->PublicKey)) throw new \Exception('请传入商户公钥');
    }
     
    //发起支付
    public function pay($param){
        //订单基本信息
        $this->checkInit();
        if(empty($param['orderno'])) throw new \Exception('请提供订单号orderno');
        if(empty($param['money_pay'])) throw new \Exception('请提供支付金额(元)money_pay');
        if(empty($param['subject'])) throw new \Exception('请提供商品名称subject');
        $order = [
            'out_trade_no' => $param['orderno'],
            'total_amount' => floatval($param['money_pay']), //支付金额,单位:元
            'subject' => $param['subject']
        ];
        //公共参数
        $base = [
            'app_id' => $this->AppID,
            'method' => 'alipay.trade.precreate',
            'charset' => 'utf-8',
            'sign_type' => 'RSA2',
            'timestamp' => date('Y-m-d H:i:s'),
            'version' => '1.0',
            'notify_url' => APP_URL . '/bin/payclass/Alipayf2fpay/notify.php', //异步通知页面,可换成自己的
            'biz_content' => json_encode($order),
        ];
        //生成签名
        ksort($base);
        $query = [];
        foreach($base as $k=>$v){
            $query[] = $k . '=' . $v;
        }
        $query = implode('&',$query);
        $sign = $this->getSignWithSHA256($query,$this->PrivateKey);
        $base['sign'] = $sign;
        //创建支付宝订单
        $url = 'https://openapi.alipay.com/gateway.do';
        $result = $this->curl_post($url,$base);
 
        $json  = json_decode($result,true);
        if($json && isset($json['alipay_trade_precreate_response']) && 
            isset($json['alipay_trade_precreate_response']['code']) && 
            isset($json['alipay_trade_precreate_response']['qr_code']) && 
            $json['alipay_trade_precreate_response']['code'] == '10000'
        ){
            //下单成功,返回二维码链接
            return $json['alipay_trade_precreate_response']['qr_code'];
        }
        return '';
    }
     
    //获取支付宝发送过来的数据
    public function getRequestData(){
        $response = file_get_contents("php://input");
        parse_str($response,$json_gbk); //$json_gbk
        if(empty($json_gbk)) return [null,null];
        //编码转utf-8
        $json_utf8 = $this->array_iconv($json_gbk);
        if(empty($json_utf8)){
            $this->_log('转换失败','notify');
        }
        return [$json_gbk,$json_utf8];
    }
     
    //异步通知
    public function notify(&$result_data){
        list($json,$json_utf8) = $this->getRequestData();
        if(empty($json) || empty($json_utf8)){
            return false;
        }
        $this->checkInit();
         
        //验证签名
        $param = [];
        foreach($json as $k=>$v){
            if($k == 'sign' || $k == 'sign_type')
                continue;
            $param[$k] = $v;
        }
        ksort($param);
        $arr = [];
        foreach($param as $k=>$v){
            $arr[] = $k . '=' .$v;
        }
        $query = implode('&',$arr);
        $ok = $this->verify($query,$json_utf8['sign'],$this->PublicKey);
        if($ok !== 1){
            $this->_log('签名验证失败','notify');
            return false;
        }
        //验证是否支付成功
        if(isset($json_utf8['trade_status']) && $json_utf8['trade_status'] == 'TRADE_SUCCESS'){
            //支付成功了
            $result_data = [
                'orderno' => $json_utf8['out_trade_no'], //我方订单号
                'liushui' => $json_utf8['trade_no'], //支付宝的交易流水号
                'money' => $json_utf8['total_amount'],//订单金额
                'time_pay' => $json_utf8['gmt_payment'],//付款时间 格式:2020-12-02 22:40:26
            ];
        }
    }
     
    //返回通知成功
    public function notify_success(){
        exit('success');
    }
     
    public function _log($msg,$title='基础'){
        $dir =  __DIR__ . '/log/' . date('Ym');
        if(!is_dir($dir) && !mkdir($dir,0777,true))
            return false;
        $file = $dir . '/' . date('d') . '.txt';
        $content = is_string($msg) ? $msg : json_encode($msg , JSON_UNESCAPED_UNICODE);
        return file_put_contents($file, '['.date('Y-m-d H:i:s') . '][' . $title .']' . PHP_EOL . $content . PHP_EOL . PHP_EOL , FILE_APPEND) > 0;
    }
     
    //签名方法
    //生成 sha256WithRSA 签名
    private function getSignWithSHA256($content, $privateKey){
        $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
            wordwrap($privateKey, 64, "\n", true) .
            "\n-----END RSA PRIVATE KEY-----";
        $key = openssl_get_privatekey($privateKey);
        openssl_sign($content, $signature, $key, "SHA256");
        openssl_free_key($key);
        return base64_encode($signature);
    }
    //验证 sha256WithRSA 签名
    private function verify($content, $sign, $publicKey){
        $publicKey = "-----BEGIN PUBLIC KEY-----\n" .
        wordwrap($publicKey, 64, "\n", true) .
        "\n-----END PUBLIC KEY-----";
        $key = openssl_get_publickey($publicKey);
        $ok = openssl_verify($content,base64_decode($sign), $key, 'SHA256');
        openssl_free_key($key);
        //如果签名正确返回int 1, 签名错误返回 0, 内部发生错误则返回-1.
        return $ok;
    }
     
    private function curl_post($postUrl,$data,$header = ''){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,$postUrl);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
        if(substr($postUrl,0,5) == "https"){
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        }
        if(is_array($header) && count($header)>0){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        }
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
     
    //数组编码转换
    private function array_iconv($arr, $in_charset='gbk', $out_charset='utf-8'){
        $ret = eval('return ' . iconv($in_charset,$out_charset,var_export($arr,true).';'));
        return $ret;
    }
     
}
 
date_default_timezone_set('Asia/Shanghai');

使用方法

实例化时传三个参数或者通过init()方法传递配置参数,然后$url=$object->pay('订单信息');即可获取到二维码图片内容,然后直接通过phpqrcode工具QRcode::png($url);就能显示支付二维码

同样异步通知的时候$object->notify($data); 支付成功会把相关信息存入$data,

转载请注明原文地址:https://www.nomar.cn/?read-335.html
00

New Post(0)