支付宝官方文档:
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. 细节问题:
- 易错:订单号没带引号:
- 支付宝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"
}
- 无法阻止支付宝一直发回通知,所以需要把
notify_id
入库,以和下次支付宝发过来的通知做比对,同一个order的notify_id不变。
- 实际检测的接收到的通知和支付宝官方给的文档并不相同: