PHP对接支付宝支付接口
PHP对接支付宝支付接口
(此文章引用
如不同意联系可删除
)
其实理顺了思路后,按照我接下来的步骤来,真的超级简单啊,为啥有那么多的朋友们折腾了那么久呢,嘿嘿,接下来跟我走吧~
我下载的是PHP的Demo
下载好了之后,我把Demo解压到了我项目的根目录下了,目录结构如下所示:
这里有三个文件很重要很关键,一个是notify_url.php, 一个是return_url.php, 另一个是config.php,他们分别是支付结果异步通知,支付结果同步通知,和配置文件。通知文件是来写业务逻辑的,而配置文件是来写配置参数的
我们打开配置文件config.php,看一下我们需要写哪些配置参数
我们可以看到,需要我们来填写的有6个参数:“应用ID”,“商户私钥”,“异步通知地址”,“同步跳转地址”,“支付宝网关”,“支付宝公钥”
。这些参数非常非常重要,一个都不能填错。然而,我们要怎么获取这些参数呢?
首先,应用ID,这就是我们用的沙箱的ID,可以在蚂蚁金服开放平台的开发者中心的沙箱环境中查看沙箱应用信息,沙箱应用就是给我们在正式应用上线前用来进行测试开发的。
现在我们已经获得了应用ID和支付宝网关了,把这两个参数填到config.php中去。
这里的应用网关和授权回调地址我们不需要填,这是口碑开发才需要填的,我们做的只是普通的电脑网站支付,不需要填这个。
现在商户私钥和支付宝公钥要怎么填呢?当然是还在刚才的沙箱环境找啦
支付宝推荐我们使用RSA2生成一对秘钥,那我们就依着它说的做,点击生成方法下载对应操作系统的秘钥生成器,我是用windows的秘钥生成器,下载之后,很容易操作就生成了一对秘钥,这时我们需要将私钥放进config.php中的商户私钥的参数里,而公钥放到沙箱环境中。
友情提醒:这里有个大坑,就是将私钥粘贴到config.php中里去的时候,私钥这个字符串中间不能有回车符,我当时的私钥粘贴进去的时候,就被格式化了似的,是一个特别整齐的矩形的形状(因为在每一行等长的位置填补了回车符),结果导致前几次支付时一直显示“missing-signature”,缺少签名参数,我去开放平台文档中心的沙箱常见错误里查了一下才发现了原因,因为这个害的我浪费了好多时间呢。大家也可以看一下这个表:
三、在沙箱中填参数
接下来要将生成的公钥放到沙箱环境中,点击“查看应用公钥”,将公钥复制到这里面。
由于我们选择的秘钥方式是RSA2,所以下面的RSA我们就不用填了。
填好了应用公钥之后,我们就可以点击旁边的按钮“查看支付宝公钥”了,因为这时候已经根据应用公钥自动生成了支付宝公钥,将支付宝公钥也填进config.php文件里相应的位置。
这时候我们已经填好了四个参数:“应用ID”,“商户私钥”,“支付宝网关”,以及“支付宝公钥”。
现在还剩下’return_url’ 和 'notify_url’对应的键值没有填写,我当时写的是我的本地的return_url.php 和 notify_url.php对应的项目路径,如图所示,其中JudgeOnline是我的项目名称。
其实异步通知地址这样写是有问题的,然而我是直到今天下午才发现这个bug,待会再说。
打开alipay文件夹下的index.php文件,然后就凭这么多年用支付宝的经验,顺利完成了一次支付。
以下图片是我昨晚用手机拍的支付过程
六、下载沙箱版支付宝(去支付宝控制台申请沙箱账号,https://opendocs.alipay.com/open/200/105311/)
这其中的支付账户不是用自己的支付宝,而是用沙箱版支付宝,沙箱版支付宝安卓版APP可以在这里下载
也可以扫二维码下载
沙箱版支付宝里面有99999元,但只能用于开发测试的时候支付使用。沙箱版支付宝账号可以点击这里获得。支付的时候,如果在电脑上直接打开网页版支付宝付款,就输入沙箱的账号和密码,如果选择扫码登录,就是用安卓版APP在手机上登录后扫码支付。
支付成功后,页面就自动跳转到了return_url.php。
当我进行到这里的时候,已经到夜里十二点左右了,我关上电脑躺在床上,心里就一直构思着接下来要怎么把Demo移植到我的项目里面去,怎么与数据库交互,然后越想越兴奋,居然就失眠了 >_<
于是乎我就干脆不睡了起来继续折腾这个有趣的工程。下半夜里,我将Demo移植到了项目里,并且写了一个捐赠页面,在捐赠页面里填好表单之后就可以进行支付了,支付账号用的是沙箱账号,上面说过了,沙箱工具里有提供。然后我就建了两个数据表,一个存交易trade信息,一个存捐赠donate信息。把数据库部分调试好后,在notify_url.php页面里写好了插入语句,这时已经凌晨四点多了,我正打算通过支付将交易记录存入数据库,没想到这时候沙箱突然又开始进入维护阶段了,支付失败,没办法使用测试账号来支付了,我只好上床睡觉了。
今天早上六点半,我就起来了,继续去完善这个对接支付宝支付工程,然而一上午沙箱都在维护中,我无法测试支付功能了,于是一上午我都只在完善我的其他的PHP页面。
七、怎样将订单存入数据库(需要在服务器上测试)
中午的时候,沙箱账号终于又可以使用了,但我发现我的notify_url.php这个页面却一直没有被调用。我很郁闷,于是去某技术论坛里找到了答案,原来notify_url.php需要被外网访问才行,我之前一直是在本地运行的,外网访问不到,所以支付宝无法调用我的notify_url.php。
我把我的代码git到远程服务器上后(当然此时config.php里面的配置参数也要相应的进行修改),中间的马赛克位置填你服务器的域名或者公网IP地址:
放了这么多图片,该把代码拉出来溜溜了
notify_url.php
<?php /* * * 功能:支付宝服务器异步通知页面 * 版本:2.0 * 修改日期:2017-05-01 * 说明: * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 *************************页面功能说明************************* * 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格。 * 该页面不能在本机电脑测试,请到服务器上做测试。请确保外部可以访问该页面。 * 如果没有收到该页面返回的 success 信息,支付宝会在24小时内按一定的时间策略重发通知 */ require_once 'config.php'; require_once 'pagepay/service/AlipayTradeService.php'; require_once("../include/memcache.php"); $arr=$_POST; $alipaySevice = new AlipayTradeService($config); $alipaySevice->writeLog(var_export($_POST,true)); $result = $alipaySevice->check($arr); /* 实际验证过程建议商户添加以下校验。 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号, 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额), 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email) 4、验证app_id是否为该商户本身。 */ if($result) {//验证成功 / //请在这里加上商户的业务逻辑程序代 //——请根据您的业务逻辑来编写程序(以下代码仅作参考)—— //获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表 //商户订单号 $out_trade_no = $_POST['out_trade_no']; //支付宝交易号 $trade_no = $_POST['trade_no']; //交易状态 $trade_status = $_POST['trade_status']; //订单标题 $subject = $_POST['subject']; //订单金额 $total_amount = $_POST['total_amount']; //实收金额 $receipt_amount = $_POST['receipt_amount']; //交易支付时间 $gmt_payment = $_POST['gmt_payment']; //买家支付宝账号 $buyer_logon_id = $_POST['buyer_logon_id'];//例如: 159****5620 //买家在支付宝的用户id $buyer_user_id = $_POST['buyer_user_id'];//例如:2088101117955611 //订单描述 $body = $_POST['body']; $string_arr = explode("&", $body ); $name = $string_arr[0]; $word = $string_arr[1]; $email = $string_arr[2]; $tel = $string_arr[3]; if($_POST['trade_status'] == 'TRADE_FINISHED') { //判断该笔订单是否在商户网站中已经做过处理 //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序 //请务必判断请求时的total_amount与通知时获取的total_fee为一致的 //如果有做过处理,不执行商户的业务程序 //注意: //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知 } else if ($_POST['trade_status'] == 'TRADE_SUCCESS') { //判断该笔订单是否在商户网站中已经做过处理 //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序 //请务必判断请求时的total_amount与通知时获取的total_fee为一致的 //如果有做过处理,不执行商户的业务程序 //注意: //付款完成后,支付宝系统发送该交易状态通知 } // pdo_query("update donate set word = 'success' where donate_id=1;"); $sql = "insert into trade(out_trade_no, trade_no, trade_status, subject, total_amount, receipt_amount, gmt_payment, buyer_logon_id, buyer_user_id, body, name, word, email, tel, trade_time) values (?,?,?,?,?,?,?,?,?,?, ?,?,?,?,NOW());"; pdo_query($sql,$out_trade_no, $trade_no, $trade_status, $subject, $total_amount,$receipt_amount, $gmt_payment, $buyer_logon_id, $buyer_user_id, $body, $name, $word, $email, $tel); if ($subject == '捐赠'){ $sql = "insert into donate( donate_money, receipt_money, name, word, email, tel, out_trade_no,trade_no, subject, time) VALUES (?,?,?,?,?,?,?,?,?, NOW())"; pdo_query($sql, $total_amount, $receipt_amount, $name, $word, $email, $tel, $out_trade_no,$trade_no, $subject); } //——请根据您的业务逻辑来编写程序(以上代码仅作参考)—— echo "success"; //请不要修改或删除 }else { // pdo_query("update donate set word = 'fail' where donate_id=1;"); //验证失败 echo "fail"; } ?>
return_url.php
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <?php /* * * 功能:支付宝页面跳转同步通知页面 * 版本:2.0 * 修改日期:2017-05-01 * 说明: * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 *************************页面功能说明************************* * 该页面可在本机电脑测试 * 可放入HTML等美化页面的代码、商户业务逻辑程序代码 */ require_once("config.php"); require_once 'pagepay/service/AlipayTradeService.php'; require_once("../include/memcache.php"); $arr=$_GET; $alipaySevice = new AlipayTradeService($config); $result = $alipaySevice->check($arr); /* 实际验证过程建议商户添加以下校验。 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号, 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额), 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email) 4、验证app_id是否为该商户本身。 */ if($result) {//验证成功 / //请在这里加上商户的业务逻辑程序代码 //——请根据您的业务逻辑来编写程序(以下代码仅作参考)—— //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表 //商户订单号 $out_trade_no = htmlspecialchars($_GET['out_trade_no']); //支付宝交易号 $trade_no = htmlspecialchars($_GET['trade_no']); $sql = "select subject from trade where trade_no=?"; $result = pdo_query($sql, $trade_no); //订单标题 $subject = trim($result[0][0]); if($subject == '捐赠'){ echo "<script>alert('感谢您的热心捐赠!');</script>"; header("location:../donate.php"); } else{ echo "<script>alert('这是其他类付款');</script>"; header("location:../index.php"); } echo "验证成功<br />支付宝交易号:".$trade_no."<br>订单标题:".$subject; //——请根据您的业务逻辑来编写程序(以上代码仅作参考)—— / } else { //验证失败 echo "验证失败"; echo "<script>alert('支付失败!如对订单有疑惑,请咨询管理员');</script>"; header("location:../index.php"); } ?> <title>支付结果</title> </head> <body> </body> </html>
使用 PHP 7.2,each 被弃用 将这个循环替换成foreach就可以了,文件路径(pagepay/pagepay.php)
推荐在notify_url.php中存入数据库,而不是在return_url.php
原因:
notify_url.php是异步页面,用户看不到,但程序依然会执行。而return_url.php是支付返回页面,用户在支付完后,可能并没有等待页面跳回到商家的return_url.php页面,而是点了支付宝页面的其他链接,或者是因各种物理因素(如:断网,断电),导致用户最终没有看到return_url.php,如果我们将存入数据库的代码放在return_url.php页面中,则是非常不明智的,很可能会导致数据没写进去。所以
推荐在notify_url.php中存入数据库
下午的时候,修复了一些sql语句的bug后,我的捐赠功终于能顺利地在服务器上跑起来了,顺利地完成了支付,顺利地将交易记录存入了数据库,哈哈
明天我就打算提交我们的自己的应用的审核,审核通过之后,将配置文件config.php中的应用ID改一下,然后将你的公钥上传到支付宝里你的应用中,同时保存下对应的支付宝公钥和支付宝网关到config.php就OK了。
时间仓促,如有错误欢迎指出,欢迎在评论区讨论,如对您有帮助还请点个推荐、关注支持一下
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。
若内容有侵犯您权益的地方,请公告栏处联系本人,本人定积极配合处理或删除。