支付宝接入Thinkphp

场景 : Thinkphp框架(3.2.3),支付宝即时到帐接口(http://aopsdkdownload.cn-hangzhou.alipay-pub.aliyun-inc.com/demo/alipaydirect.zip?spm=a219a.7629140.0.0.sBr1Z3&file=alipaydirect.zip),MD5加密方式

最近做系统,需要实现在线支付功能,毫不犹豫,选择的是支付宝的接口支付功能。这里我用的是即时到帐的接口,具体实现的步骤如下:

一、下载支付宝接口包

下载地址:

http://aopsdkdownload.cn-hangzhou.alipay-pub.aliyun-inc.com/demo/alipaydirect.zip?spm=a219a.7629140.0.0.sBr1Z3&file=alipaydirect.zip

具体如何下载,我就不在罗嗦了~~

很多人反映,用支付宝的接口到最后面会出现验证错误。其实,这里需要对接口程序进行一下改造。需要添加几个自定义函数。为了让大家以后避免出现同样的问题,我把我改造好的支付宝接口程序上传了(-->
猛戳这里下载附件
)。大家可以下载下来,解压后放到框架的Vendor目录中即可~

二、重新整理接口包文件,这一步应该算是比较关键的(个人认为)

下载下来的接口包文件有很多语言的源码,

我们选择 create_direct_pay_by_user-PHP-UTF-8 这个名称的接口文件。里面包括如下文件:

images文件里是支付宝相关的一些标志的图片,我们暂不管他,lib文件很重要,是整个接口的核心类文件;

alipay.config.php是相关参数的配置文件

alipayapi.php 是支付宝接口入口文件

notify_url.php 是服务器异步通知页面文件;

return_url.php 是页面跳转同步通知文件;

在ThinkPHP的框架文件下,找到Extend 进入,再进入Vendor,在Vendor文件夹下,新建文件夹Alipay,把支付宝作为第三方类库引入。然后,复制支付宝接口文件包中lib文件里的所有文件。一共4个文件,如下:

现在对以上文件进行重命名,

alipay_core.function.php重命名为:Corefunction.php;

alipay_md5.function.php重命名为:Md5function.php;

alipay_notify.class.php重命名为:Notify.php;

alipay_submit.class.php重命名为:Submit.php;

然后,打开Submit.php文件,把以下代码去掉;

  1. require_once("alipay_core.function.php");
  2. require_once("alipay_md5.function.php");

复制代码

同样,打开Notify.php文件,把以下两段代码去掉

  1. require_once("alipay_core.function.php");
  2. require_once("alipay_md5.function.php");

复制代码

为什么要去掉以上两个文件中的这两段代码,因为在项目中调用接口文件的时候,我把所有4个核心文件都通过vendor来进行引入。所以,这不再需要导入。

到此,支付宝接口包相关核心类库的整理基本完成。现在开始在项目中调用;

三、在项目中调用支付宝接口

调用分两步:

1、在配置文件中Conf/Config.php文件中对支付宝相关参数进行配置:

//支付宝配置参数
'alipay_config'=>array(
       'partner' =>'20********50',   //这里是你在成功申请支付宝接口后获取到的PID;
    'key'=>'9t***********ie',//这里是你在成功申请支付宝接口后获取到的Key
    'sign_type'=>strtoupper('MD5'),
    'input_charset'=> strtolower('utf-8'),
    'cacert'=> getcwd().'\\cacert.pem',
    'transport'=> 'http',
      ),
     //以上配置项,是从接口包中alipay.config.php 文件中复制过来,进行配置;

'alipay'   =>array(
 //这里是卖家的支付宝账号,也就是你申请接口时注册的支付宝账号
'seller_email'=>'[email protected]',
//这里是异步通知页面url,提交到项目的Pay控制器的notifyurl方法;
'notify_url'=>'http://www.xxx.com/Pay/notifyurl',
//这里是页面跳转通知url,提交到项目的Pay控制器的returnurl方法;
'return_url'=>'http://www.xxx.com/Pay/returnurl',
//支付成功跳转到的页面,我这里跳转到项目的User控制器,myorder方法,并传参payed(已支付列表)
'successpage'=>'User/myorder?ordtype=payed',
//支付失败跳转到的页面,我这里跳转到项目的User控制器,myorder方法,并传参unpay(未支付列表)
'errorpage'=>'User/myorder?ordtype=unpay',
),

2、新建一个PayAction控制器代码如下:

<?php
class PayAction extends Action{
       //在类初始化方法中,引入相关类库
       public function _initialize() {
        vendor('Alipay.Corefunction');
        vendor('Alipay.Md5function');
        vendor('Alipay.Notify');
        vendor('Alipay.Submit');
    }

    //doalipay方法
        /*该方法其实就是将接口文件包下alipayapi.php的内容复制过来
          然后进行相关处理
        */
    public function doalipay(){
            /*********************************************************
            把alipayapi.php中复制过来的如下两段代码去掉,
            第一段是引入配置项,
            第二段是引入submit.class.php这个类。
           为什么要去掉??
            第一,配置项的内容已经在项目的Config.php文件中进行了配置,我们只需用C函数进行调用即可;
            第二,这里调用的submit.class.php类库我们已经在PayAction的_initialize()中已经引入;所以这里不再需要;
            *****************************************************/
       // require_once("alipay.config.php");
       // require_once("lib/alipay_submit.class.php");

       //这里我们通过TP的C函数把配置项参数读出,赋给$alipay_config;
       $alipay_config=C('alipay_config');  

        /**************************请求参数**************************/
        $payment_type = "1"; //支付类型 //必填,不能修改
        $notify_url = C('alipay.notify_url'); //服务器异步通知页面路径
        $return_url = C('alipay.return_url'); //页面跳转同步通知页面路径
        $seller_email = C('alipay.seller_email');//卖家支付宝帐户必填
        $out_trade_no = $_POST['trade_no'];//商户订单号 通过支付页面的表单进行传递,注意要唯一!
        $subject = $_POST['ordsubject'];  //订单名称 //必填 通过支付页面的表单进行传递
        $total_fee = $_POST['ordtotal_fee'];   //付款金额  //必填 通过支付页面的表单进行传递
        $body = $_POST['ordbody'];  //订单描述 通过支付页面的表单进行传递
        $show_url = $_POST['ordshow_url'];  //商品展示地址 通过支付页面的表单进行传递
        $anti_phishing_key = "";//防钓鱼时间戳 //若要使用请调用类文件submit中的query_timestamp函数
        $exter_invoke_ip = get_client_ip(); //客户端的IP地址
        /************************************************************/

        //构造要请求的参数数组,无需改动
    $parameter = array(
        "service" => "create_direct_pay_by_user",
        "partner" => trim($alipay_config['partner']),
        "payment_type"    => $payment_type,
        "notify_url"    => $notify_url,
        "return_url"    => $return_url,
        "seller_email"    => $seller_email,
        "out_trade_no"    => $out_trade_no,
        "subject"    => $subject,
        "total_fee"    => $total_fee,
        "body"            => $body,
        "show_url"    => $show_url,
        "anti_phishing_key"    => $anti_phishing_key,
        "exter_invoke_ip"    => $exter_invoke_ip,
        "_input_charset"    => trim(strtolower($alipay_config['input_charset']))
        );
        //建立请求
        $alipaySubmit = new AlipaySubmit($alipay_config);
        $html_text = $alipaySubmit->buildRequestForm($parameter,"post", "确认");
        echo $html_text;
    }

        /******************************
        服务器异步通知页面方法
        其实这里就是将notify_url.php文件中的代码复制过来进行处理

        *******************************/
    function notifyurl(){
                /*
                同理去掉以下两句代码;
                */
                //require_once("alipay.config.php");
                //require_once("lib/alipay_notify.class.php");

                //这里还是通过C函数来读取配置项,赋值给$alipay_config
        $alipay_config=C('alipay_config');
        //计算得出通知验证结果
        $alipayNotify = new AlipayNotify($alipay_config);
        $verify_result = $alipayNotify->verifyNotify();
        if($verify_result) {
               //验证成功
                   //获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表
           $out_trade_no   = $_POST['out_trade_no'];      //商户订单号
           $trade_no       = $_POST['trade_no'];          //支付宝交易号
           $trade_status   = $_POST['trade_status'];      //交易状态
           $total_fee      = $_POST['total_fee'];         //交易金额
           $notify_id      = $_POST['notify_id'];         //通知校验ID。
           $notify_time    = $_POST['notify_time'];       //通知的发送时间。格式为yyyy-MM-dd HH:mm:ss。
           $buyer_email    = $_POST['buyer_email'];       //买家支付宝帐号;
                   $parameter = array(
             "out_trade_no"     => $out_trade_no, //商户订单编号;
             "trade_no"     => $trade_no,     //支付宝交易号;
             "total_fee"     => $total_fee,    //交易金额;
             "trade_status"     => $trade_status, //交易状态
             "notify_id"     => $notify_id,    //通知校验ID。
             "notify_time"   => $notify_time,  //通知的发送时间。
             "buyer_email"   => $buyer_email,  //买家支付宝帐号;
           );
           if($_POST['trade_status'] == 'TRADE_FINISHED') {
                       //
           }else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {                           if(!checkorderstatus($out_trade_no)){
               orderhandle($parameter);
                           //进行订单处理,并传送从支付宝返回的参数;
               }
            }
                echo "success";        //请不要修改或删除
         }else {
                //验证失败
                echo "fail";
        }
    }

    /*
        页面跳转处理方法;
        这里其实就是将return_url.php这个文件中的代码复制过来,进行处理;
        */
    function returnurl(){
                //头部的处理跟上面两个方法一样,这里不罗嗦了!
        $alipay_config=C('alipay_config');
        $alipayNotify = new AlipayNotify($alipay_config);//计算得出通知验证结果
        $verify_result = $alipayNotify->verifyReturn();
        if($verify_result) {
            //验证成功
            //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表
        $out_trade_no   = $_GET['out_trade_no'];      //商户订单号
        $trade_no       = $_GET['trade_no'];          //支付宝交易号
        $trade_status   = $_GET['trade_status'];      //交易状态
        $total_fee      = $_GET['total_fee'];         //交易金额
        $notify_id      = $_GET['notify_id'];         //通知校验ID。
        $notify_time    = $_GET['notify_time'];       //通知的发送时间。
        $buyer_email    = $_GET['buyer_email'];       //买家支付宝帐号;

        $parameter = array(
            "out_trade_no"     => $out_trade_no,      //商户订单编号;
            "trade_no"     => $trade_no,          //支付宝交易号;
            "total_fee"      => $total_fee,         //交易金额;
            "trade_status"     => $trade_status,      //交易状态
            "notify_id"      => $notify_id,         //通知校验ID。
            "notify_time"    => $notify_time,       //通知的发送时间。
            "buyer_email"    => $buyer_email,       //买家支付宝帐号
        );

if($_GET['trade_status'] == 'TRADE_FINISHED' || $_GET['trade_status'] == 'TRADE_SUCCESS') {
        if(!checkorderstatus($out_trade_no)){
             orderhandle($parameter);  //进行订单处理,并传送从支付宝返回的参数;
    }
        $this->redirect(C('alipay.successpage'));//跳转到配置项中配置的支付成功页面;
    }else {
        echo "trade_status=".$_GET['trade_status'];
        $this->redirect(C('alipay.errorpage'));//跳转到配置项中配置的支付失败页面;
    }
}else {
    //验证失败
    //如要调试,请看alipay_notify.php页面的verifyReturn函数
    echo "支付失败!";
    }
}
}
?>

3、这里有几个支付处理过程中需要用到的函数,我把这些函数写到了项目的Common/common.php中,这样不用手动调用,即可直接使用这些函数,代码如下:

//////////////////////////////////////////////////////
//Orderlist数据表,用于保存用户的购买订单记录;
/* Orderlist数据表结构;
CREATE TABLE `tb_orderlist` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userid` int(11) DEFAULT NULL,购买者userid
  `username` varchar(255) DEFAULT NULL,购买者姓名
  `ordid` varchar(255) DEFAULT NULL,订单号
  `ordtime` int(11) DEFAULT NULL,订单时间
  `productid` int(11) DEFAULT NULL,产品ID
  `ordtitle` varchar(255) DEFAULT NULL,订单标题
  `ordbuynum` int(11) DEFAULT '0',购买数量
  `ordprice` float(10,2) DEFAULT '0.00',产品单价
  `ordfee` float(10,2) DEFAULT '0.00',订单总金额
  `ordstatus` int(11) DEFAULT '0',订单状态
  `payment_type` varchar(255) DEFAULT NULL,支付类型
  `payment_trade_no` varchar(255) DEFAULT NULL,支付接口交易号
  `payment_trade_status` varchar(255) DEFAULT NULL,支付接口返回的交易状态
  `payment_notify_id` varchar(255) DEFAULT NULL,
  `payment_notify_time` varchar(255) DEFAULT NULL,
  `payment_buyer_email` varchar(255) DEFAULT NULL,
  `ordcode` varchar(255) DEFAULT NULL,       //这个字段不需要的,大家看我西面的修正补充部分的说明!
  `isused` int(11) DEFAULT '0',
  `usetime` int(11) DEFAULT NULL,
  `checkuser` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
*/
//在线交易订单支付处理函数
//函数功能:根据支付接口传回的数据判断该订单是否已经支付成功;
//返回值:如果订单已经成功支付,返回true,否则返回false;
function checkorderstatus($ordid){
    $Ord=M('Orderlist');
    $ordstatus=$Ord->where('ordid='.$ordid)->getField('ordstatus');
    if($ordstatus==1){
        return true;
    }else{
        return false;
    }
}
//处理订单函数
//更新订单状态,写入订单支付后返回的数据
function orderhandle($parameter){
    $ordid=$parameter['out_trade_no'];
    $data['payment_trade_no']      =$parameter['trade_no'];
    $data['payment_trade_status']  =$parameter['trade_status'];
    $data['payment_notify_id']     =$parameter['notify_id'];
    $data['payment_notify_time']   =$parameter['notify_time'];
    $data['payment_buyer_email']   =$parameter['buyer_email'];
    $data['ordstatus']             =1;
    $Ord=M('Orderlist');
    $Ord->where('ordid='.$ordid)->save($data);
}
/*-----------------------------------
2013.8.13更正
下面这个函数,其实不需要,大家可以把他删掉,
具体看我下面的修正补充部分的说明
------------------------------------*/
//获取一个随机且唯一的订单号;
function getordcode(){
    $Ord=M('Orderlist');
    $numbers = range (10,99);
    shuffle ($numbers);
    $code=array_slice($numbers,0,4);
    $ordcode=$code[0].$code[1].$code[2].$code[3];
    $oldcode=$Ord->where("ordcode='".$ordcode."'")->getField('ordcode');
    if($oldcode){
        getordcode();
    }else{
        return $ordcode;
    }
}

四、总结几点

1、接口包中lib文件中的文件复制到Vendor后,重命名为TP规范的命名规则,为的是调用方便,当然你要改成其他名称也可以;

2、把执行支付操作(doalipay),处理异步返回结果(notifyurl),处理跳转返回结果(returnurl)三个支付接口的核心页面写到一个PayAction控制器中。

3、提交支付的页面中,可以在提交之前先把一些参数要传递的内容先通过隐藏域的方法组合好,比如金额先计算好,订单名称,订单描述等先用字符串组合好。然后提交表单,这样,在doalipay方法中只要直接构造传递参数,直接进行提交就行过了。

4、支付返回后的处理因为要在异步和跳转两个方法中都要进行相应的判断和处理,所以,把这些判断和处理写到一个自定义函数中,这样只要调用函数即可,使得代码更加清晰明了。

5、notify_url和return_url两种模式的返回url必须使用http://xxxxxxx这样的绝对路径,因为里是从支付宝平台返回到你的项目页面。不能使用相对路径。

以上代码在ThinkPHP3.0中正常使用!!

------------------------修正补充!!2013.08.13------------------------------

在第三部分中Orderlist数据表结构中,我有一个字段是OrdCode,这个字段是我系统中用来发送短信给客户的消费密码,也就是客户凭手机短信来消费时就要验证这个字段。

其实,大家在做系统的时候,可以把这个字段忽略,可以不用他。代码最后部分中,有一个获取一个随机且唯一的订单号的函数 getordcode(),这里我其实写错了,不是获取订单号,是ordcode,也就是消费密码,这个函数也不需要。系统中的订单号(ordid字段),我用的是时间戳。

在此修正!

--------------------解决签名错误问题 修正 13-08-16------------------------

有人说在在调试时,签名出现无法通过的问题,产生问题的原因是在返回的URL地址中返回的参数中,可能存在__URL__这样的字符串。导致无法正确过滤参数。

解决办法:

方法1:

在向支付宝提交需要的参数时,不要使用__URL__,__PUBLIC__等TP中的模版替换变量,如果TP对这些变量解析不成功,会直接传递过去,所以,在这些地方直接使用原始的URL地址。

方法2:

在接口的Core文件中,加入改造后的过滤函数,如下:

/**
 * 除去数组中的空值和签名参数
 * @param $para 签名参数组
 * return 去掉空值与签名参数后的新签名参数组
 */
function paraFilter($para) {
    $para_filter = array();
    while (list ($key, $val) = each ($para)) {
        if($key == "sign" || $key == "sign_type" || $key == '_URL_' || $val == "")continue;    //添加了$key == '_URL_'
        else    $para_filter[$key] = $para[$key];
    }
    return $para_filter;
}
function myparaFilter($para) {
    $para_filter = array();
    while (list ($key, $val) = each ($para)) {
        if($key == '_URL_')continue;
        else $para_filter[$key] = $para[$key];
    }
    return $para_filter;
}

时间: 2024-10-10 00:34:57

支付宝接入Thinkphp的相关文章

PHP支付宝接入

中秋节在研究php接入支付宝和微信,今天从早上开始到晚上一直再看支付宝接入. 在支付宝接入demo测试配置项采用RSA加密方式会报下面的错误: Fatal error: Call to undefined function openssl_get_privatekey() in C:\Users\Administrator\Desktop\create_direct_pay_by_user-PHP-UTF-8\lib\alipay_rsa.function.php on line 26   解决

支付宝接入记录

已支付宝给的Demo为蓝本,说一下支付宝接入的要点. 01修改 支付宝的回调地址 ,改成自己服务器端的地址. 02 在网站上 找到个人信息 ,填在这个地方. 四个信息 分别为 商户IP , 在支付宝网站上找. 商户收款账号 , 自己登陆支付宝的账号. 商户私钥pkcs8格式, 这个 阅读 支付宝的文档<支付宝钱包支付接口开发包2.0标准版接入与使用规则.pdf> 最后一章, 照着做就行. 填写好这些东西之后,编译运行demo. 在手机的demo上 支付一笔, 0.01 元. 在支付成功后,就应

app的支付宝接入代码及注意事项

//支付宝支付 public function alipay($money,$order_sn,$body) { vendor('aop.AopClient'); //官方sdk引入的文件 vendor('aop.request.AlipayTradeAppPayRequest'); //官方sdk引入的文件 $aop = new \AopClient(); $aop->gatewayUrl="https://openapi.alipay.com/gateway.do"; $ao

支付宝接入文档中TRADE_SUCCESS和TRADE_FINISHED的本质区别

之前一直不知道这2种状态到底有什么不同.支付宝中担保交易和即时到账交易对其的描述为: TRADE_SUCCESS  交易成功(或支付成功) TRADE_FINISHED    交易完成 一头雾水......OK,找例子来说明吧: 例子一: 即时到账普通版.   普通版不支持支付完成后的退款操作,即用户充值完成后,该交易就算是完成了,这笔交易就不能再做任何操作了. 即时到账高级版.   这个版本在用户充值完成后,卖家可以执行退款操作进行退款,即该交易还没有彻底完成,卖家还可以修改这笔交易. OK,

支付宝接入

1.这里是商户PID 2.商户收款帐号 就是支付宝帐号 3.公钥,私钥 要下载这个工具来生成 点脚本生成公钥 私钥在这里 4.服务器修改公钥 原文地址:https://www.cnblogs.com/dubo-/p/8495542.html

Java +支付宝 +接入+最全+最佳-实战-demo

一.支付宝配置: 1.需要在支付宝商户平台购买支付的产品并开通支付. 2.购买支付产品登录支付宝:https://auth.alipay.com/login/index.htm 3.登录之后首页点击查看PID|KEY 4.打开记事本我们需要四个参数这是取到第一个 合作身份者ID:12345564544 支付宝账号: 商户的私钥 : 支付宝的公钥: 5.配置RSA(SHA1)密钥 其实图片上是我配置过了,没配置的RSA(SHA1)密钥 后面有个设置公钥点击下(需要获取手机验证码),点击生成支付宝密

银联与支付宝

摘要:银联终于要结束12年的垄断生涯.在银联12年的发展过程中,最为引人注目的就是和支付宝的多年恩怨.这十年,双方经历了从最初的会面,到不欢而散,再到各自成长和冲突.十年后,银联和支付宝都已经成为各自领域的全球顶级玩家,但是目前仍未达成实质性合作. 注:从2015年6月1日,符合要求的机构可申请"银行卡清算业务许可证",在中国境内从事银行卡清算.这意味着在中国清算市场一家独大12年的局面被打破,中国银联将告别垄断时代.分析称为第三方支付开了正门.发一篇旧文,这篇第一次解开了银联和支付宝

支付宝沙箱环境测试

1.获取电脑网站支付的SDK代码 ①下载代码 具体下载地址:https://docs.open.alipay.com/270/106291/ ②介绍具体的代码中文件 ③具体同步回调跟异步回调 同步回调作用:实现当用户支付完成之后能够跳转到对应的商户页面(确保用户支付完成之后能够正确的对用户的支付做一个处理操作) 异步回调作用:确保商户对用户的支付做了一个正确的处理 2.支付宝接入 测试账号相关地址: https://openhome.alipay.com/platform/developerIn

一文带你了解微信/支付宝支付的相关概念

今天写了一篇非技术文,需求来源于老大的老大,老老大. 这偏文章用以说明微信/支付宝相关参数之间错综复杂的关系,所有资料来自微信/支付宝官网,以及相关银联给的微信/支付宝对接文档. 嘿嘿,如果同行的小伙伴,也有这个疑惑,希望本篇文章帮你解惑. 微信 名词解释: appid:公众号.小程序.移动应用唯一标识 mchid:商户申请微信支付后,由微信支付分配的商户收款账号. openid,微信用户在公众号 appid 下的唯一用户标识,可用于永久标记一个用户 sub_appid:子 appid,服务商模