三、支付宝扫码支付接入指引

支付宝官方文档:
https://docs.open.alipay.com/194/106078/
当面付快速接入:
https://docs.open.alipay.com/194/105170/

开发之前:需要在支付宝里开通当面付功能,在沙箱环境测试能生成二维码之后,再切换成生产环境。

1. 从沙箱环境切换到生产环境:

a.应用ID APPID
b.支付宝公钥 ALIPAY_RSA_PUBLIC_KEY
c.支付宝网关: $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
注:在生产环境中可以不用网关这一行,因为sdk里写的有。
d. 开发者私钥 RSA_PRIVATE_KEY 注:如果沙箱环境的开发者公钥和私钥与生产环境一样,那就不用修改

2. 生成二维码的代码:

require_once (__DIR__.'/../alipay-sdk-PHP-20180122110057/AopSdk.php');
require_once (__DIR__.'/../alipay-sdk-PHP-20180122110057/aop/AopClient.php');
require_once (__DIR__.'/../alipay-sdk-PHP-20180122110057/aop/SignData.php');
require_once (__DIR__.'/../alipay-sdk-PHP-20180122110057/aop/request/AlipayTradePrecreateRequest.php');
require_once (__DIR__.'/../alipay-sdk-PHP-20180122110057/lotusphp_runtime/Logger/Logger.php');
require_once (__DIR__.'/../phpqrcode/phpqrcode.php');
const APPID = '应用ID';
const RSA_PRIVATE_KEY = '开发者私钥';
const ALIPAY_RSA_PUBLIC_KEY = '支付宝公钥';
/**
 * 支付宝下单api
 * @author syh
 * @Datetime: 2018-3-19 10:19:27
 */
public function zfbOrder(){
    $order_no = $this->input->post('order_no');
    $goods_cate = $this->input->post('goods_cate');
    $price = $this->input->post('price');    // 单位为元
    $payurl = $this->qrcode($order_no,$goods_cate,$price);
    $res['url'] = 'http://jinling.veyd.cn/index.php/AliPay/hc?payurl='.$payurl;
    exit(json_encode($res));
}
/**
 * @author syh
 * 生成支付宝二维码
 */
public function qrcode($order_no,$goods_cate,$price){
    $aop = new AopClient ();
    //$aop->gatewayUrl = 'https://openapi.alipaydev.com/gateway.do';    // 沙箱网关
    //$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';       // 生产网关
    $aop->appId = self::APPID;
    $aop->rsaPrivateKey = self::RSA_PRIVATE_KEY;
    $aop->alipayrsaPublicKey = self::ALIPAY_RSA_PUBLIC_KEY;
    $aop->apiVersion = '1.0';
    $aop->postCharset='utf-8';
    $aop->format='json';
    $aop->signType = 'RSA2';
    $date=date("YmdHis");
    $arr=range(1000,9999);
    shuffle($arr);
    $request = new AlipayTradePrecreateRequest();
    //$request->setBizContent("{\"out_trade_no\":\"".$date.$arr[0]."\",\"total_amount\":0.01,\"subject\":\"二维码测试\"}");

    $request->setBizContent(
        "{\"out_trade_no\":\"".$order_no."\",
        \"total_amount\":".$price.",
        \"subject\":\"".$goods_cate."\"}"
    );
    $request->setNotifyUrl("http://jinling.veyd.cn/index.php/AliPay/yibu");    //  填写自己的http或https的回调地址(异步通知地址)
    $result = $aop->execute($request);
    $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
    //echo '
';
    //print_r($responseNode);die;    // alipay_trade_precreate_response
    //获得输出支付宝返回二维码链接
    $qrCode = $result->$responseNode->qr_code;
    return $qrCode;
    //echo '
';
    //print_r($qrCode);die;   //  https://qr.alipay.com/bax08102xz6xk45x7grs0068
    //定义纠错级别

    //$errorLevel = "L";
    //定义生成图片宽度和高度;默认为3
    //$size = "4";
    //调用QRcode类的静态方法png生成二维码图片//
    //QRcode::png($qrCode, false, $errorLevel, $size);

    //return $qr_img_src = "http://paysdk.weixin.qq.com/example/qrcode.php?data=".urlencode($qrCode);
    //生成网址类型
    /*$url="https://openclub.alipay.com/index.php";
    $url.="\r\n";
    QRcode::png($url, false, $errorLevel, $size);*/
}

/**
 * 把未成形的二维码地址变成实体二维码地址
 * @author syh
 * @Datetime: 2018-3-19 11:39:34
 */
public function hc(){
    $payurl = $this->input->get('payurl');
    $errorCorrectionLevel = 'L';//容错级别
    $matrixPointSize = 6;//生成图片大小
    //生成二维码图片
    QRcode::png($payurl, false, $errorCorrectionLevel, $matrixPointSize, 2);
}

3. 支付成功后的回调: 【zfb和微信都是异步通知】

异步通知官方文档:https://docs.open.alipay.com/194/103296

public function notify(){
    // 1. 验证签名
    $aop = new \AopClient();
    $aop->alipayrsaPublicKey = Alipay::ALIPAY_RSA_PUBLIC_KEY;
    $flag = $aop->rsaCheckV1($_POST, NULL, "RSA2");
    //$txt = json_encode($flag);
    //file_put_contents('zfb03.txt',$txt."|".time()."|",FILE_APPEND);
    // 2. 验签
    if($flag){
        $tnotify_id = json_encode($_POST['notify_id']);
        //file_put_contents('zfb00.txt',time()."|".'notify_id:'.$tnotify_id.'|trade_no:'.$_POST['trade_no']."\r\n",FILE_APPEND);

        //处理业务,并从$_POST中 提取 需要的 参数内容
        if($_POST['trade_status'] == 'TRADE_SUCCESS'
            || $_POST['trade_status'] == 'TRADE_FINISHED'){//处理交易完成或者支付成功的通知
            //$txt2 = json_encode($_POST);
            //file_put_contents('cao.txt',$txt2."|".time()."|",FILE_APPEND);
            //获取订单号
            $order_no = $_POST['out_trade_no'];
            //支付宝交易号
            $trade_no = $_POST['trade_no'];
            //订单支付时间
            $gmt_payment = $_POST['gmt_payment'];
            if($_POST['seller_email'] != '[email protected]'){
                file_put_contents('zfb_err.txt',"seller_email is error|".'trade_no:'.$_POST['trade_no']."|".time()."|"."\r\n",FILE_APPEND);
                return 'seller_email is error';
            }
            //转换为时间戳
            $gtime = strtotime($gmt_payment);
            // 只处理往前推10分钟的通知
            if( !($gtime+600 > time()) ){  // !有效的通知
                die('success');   // Already notified
            }
            //此处编写回调处理逻辑
            $this->load->model('User_model');
            // 查询金额是否一致
            $map['select']='price,notify_id';
            $map['from'] = 'orders';
            $map['where'] = 'order_no='."'$order_no'";
            $price_arr = $this->User_model->find($map);
            if($_POST['total_amount'] != $price_arr['price']){
                file_put_contents('zfb_err.txt',"total_amount is error|".'trade_no:'.$_POST['trade_no']."|".time()."|"."\r\n",FILE_APPEND);
                return 'total_amount is error';
            }
            if($_POST['notify_id'] == $price_arr['notify_id']){
                file_put_contents('zfb_repeat_notify.txt','trade_no:'.$_POST['trade_no']."|".time()."|".'notify_id:'.$_POST['notify_id']."\r\n",FILE_APPEND);
                die('success');   // Already notified
            }
            //$ttt = json_encode($price_arr);
            //file_put_contents('ttt.txt',$ttt."\r\n",FILE_APPEND);

            $update['from'] = 'orders';
            $update['where'] = "order_no= '$order_no' " ;
            $update['set'] = array(
                'is_pay'     => 1,
                'pay_time'   => $gtime,
                'pay_type'   => 'zfb',
                'trade_no'   => $trade_no,
                'notify_id'   => $_POST['notify_id'],
            );
            if($this->User_model->updateByCondition($update)){
                $info['mess'] = 'ok';
                $info['flag'] = 1;
                //exit(json_encode($info));
            }else{
                $info['mess'] = 'Fail';
                $info['flag'] = 0;
                //exit(json_encode($info));
            }
            echo 'success';

            //处理成功一定要返回 success 这7个字符组成的字符串,
            //die('success');//响应success表示业务处理成功,告知支付宝无需在异步通知

        }else{
            file_put_contents('zfb_pay_fail.txt','FAIL'."\r\n",FILE_APPEND);

        }
    }  // if($flag) 判断 over
}

4. 细节问题:

  1. 易错:订单号没带引号:
  2. 支付宝post过来的json样例:
{
    "gmt_create": "2018-03-19 16:50:49",
    "charset": "utf-8",
    "seller_email": "[email protected]",
    "subject": "接口测试74",
    "sign": "xxx可长",
    "buyer_id": "2088602321663935",
    "invoice_amount": "0.01",
    "notify_id": "384c56d13dac216575d663f7304b018n6h",
    "fund_bill_list": "[{\"amount\":\"0.01\",\"fundChannel\":\"ALIPAYACCOUNT\"}]",
    "notify_type": "trade_status_sync",
    "trade_status": "TRADE_SUCCESS",
    "receipt_amount": "0.01",
    "buyer_pay_amount": "0.01",
    "app_id": "2018010601647555",
    "sign_type": "RSA2",
    "seller_id": "2088821836484215",
    "gmt_payment": "2018-03-19 16:50:56",
    "notify_time": "2018-03-19 16:50:56",
    "version": "1.0",
    "out_trade_no": "MD2018031411122711832",
    "total_amount": "0.01",
    "trade_no": "2018031921001004930525701322",
    "auth_app_id": "2018010601647555",
    "buyer_logon_id": "707***@qq.com",
    "point_amount": "0.00"
}
  1. 无法阻止支付宝一直发回通知,所以需要把notify_id入库,以和下次支付宝发过来的通知做比对,同一个order的notify_id不变。
三、支付宝扫码支付接入指引_第1张图片
三、支付宝扫码支付接入指引_第2张图片
  1. 实际检测的接收到的通知和支付宝官方给的文档并不相同:
三、支付宝扫码支付接入指引_第3张图片

你可能感兴趣的:(三、支付宝扫码支付接入指引)