客户的网站需要支付功能,我们选择了业界用的最多的支付宝即时到账支付。申请了两次将近两周的时间终于下来了,于是我开始着手测试SDK整合支付流程。

SDK中的代码并不复杂,就是构造请求发送,接收并验证签名而已。SDK根目录中的文件基本是示例,开发的时候用于参照, lib 目录中是核心库文件,在CodeIgniter中需要把这个目录放到 application/third_party 目录下,并将目录名改为 alipay 方便标识,证书文件 cacert.pem 也放进去。其实更好的方式是把类文件放到 application/libraries 目录并使用Loader加载类库,但是其中有两个公共函数文件引用,省的加载麻烦就直接 require_once() 了。

配置文件也需要单独增加一个 alipay.php 在 application/config 目录中,主要可以照搬示例中的 alipay.config.php 的内容,我是这么写的:

$config['partner']      = '商户id';
$config['key'] = '商户API key';
$config['seller_email'] = '商户支付宝邮箱账号';
$config['payment_type'] = 1;
$config['transport'] = 'http';
$config['input_charset'] = 'utf-8';
$config['sign_type'] = 'MD5';
$config['notify_url'] = 'http://'.$_SERVER['HTTP_HOST'].'/order/callback/notify';
$config['return_url'] = 'http://'.$_SERVER['HTTP_HOST'].'/order/callback/return';
$config['cacert'] = APPPATH.'third_party/alipay/cacert.pem';

之后就是在订单控制器中处理支付了,当创建了一个商品订单后,给用户一个链接按钮,跳转到 /order/pay 控制器进行支付宝请求中转,主要可以参照示例 alipayapi.php 文件内容,调用SDK函数生成一个提交表单,渲染在模板中由JS控制自动提交。

// 订单控制器类
class Order extends CI_Controller{
// ...
public function pay($id) {
// 获取订单数据示例
$order = $this->model->get($id); // 加载支付宝配置
$this->config->load('alipay', TRUE);
// 加载支付宝支付请求类库
require_once(APPPATH."third_party/alipay/alipay_submit.class.php"); $submit = new AlipaySubmit($this->config->item('alipay')); $body = $submit->buildRequestForm(array(
'service' => 'create_direct_pay_by_user',
'partner' => $this->config->item('partner', 'alipay'),
'payment_type' => $this->config->item('payment_type', 'alipay'),
'notify_url' => $this->config->item('notify_url', 'alipay'),
'return_url' => $this->config->item('return_url', 'alipay'),
'seller_email' => $this->config->item('seller_email', 'alipay'),
'out_trade_no' => $id,
'subject' => $order['product']['name'],
'total_fee' => $order['price'],
'body' => $order['product']['name'],
'show_url' => 'http://'.$_SERVER['HTTP_HOST'].'/product/view/'.$order['productId'],
'anti_phishing_key' => '',
'exter_invoke_ip' => '',
'_input_charset' => $this->config->item('input_charset', 'alipay')
)); // 渲染模板,原生的这么写,我自己另外用smarty3
$this->load->view('pay', array('body' => $body));
}
// ...
}

正常的话用户浏览器会跳转到支付宝完成支付,之后再跳转回之前配置了的 return_url 上,这个控制器方法我命名为 /order/callback/<method> ,通过参数指定是同步返回还是异步通知,但里面的业务逻辑处理差不多。

// 还是订单控制器类
class Order extends CI_Controller{
// $method参数只能是'return'或'notify',对应URL
public function callback ($method) {
// 加载支付宝配置
$this->config->load('alipay', TRUE);
// 加载支付宝返回通知类库
require_once(APPPATH."third_party/alipay/alipay_notify.class.php");
// 初始化支付宝返回通知类
$alipayNotify = new AlipayNotify($this->config->item('alipay')); $input = array();
$is_ajax = FALSE;
$notify_status = 'success'; // 这里做同步还是异步的判断并获取返回数据验证请求
switch ($method) {
case 'notify':
$result = $alipayNotify->verifyNotify();
$input = $this->input->post();
$is_ajax = TRUE;
break; case 'return':
$result = $alipayNotify->verifyReturn();
$input = $this->input->get();
break; default:
return $this->out_not_found();
break;
} // 支付宝返回支付成功和交易结束标志
if ($result && ($input['trade_status'] == 'TRADE_FINISHED' || $input['trade_status'] == 'TRADE_SUCCESS')) {
$id = $input['out_trade_no']; // 验证成功则更新订单信息(略)
// ...
} else {
// 否则置状态为失败
$notify_status = 'fail';
} if ($is_ajax) {
// 异步方式调用模板输出状态
$this->view->load('alipay', array('status' => $notify_status));
} else {
// 同步方式跳转到订单详情控制器,redirect方法要你自己写
return $this->redirect("order/view/$id#status:$notify_status");
}
}
}

到这正常的话数据库已经更新订单信息,后台管理也就可以根据支付情况去后面的配送流程。但问题是,在CI中正常情况根本到不了这里!所以我要开始吐槽支付宝的SDK!

会遇到的问题

PHP cURL模块未安装

VPS用的ubuntu系统,默认PHP的cURL模块没有,需要命令行安装:

$ sudo apt-get install curl php5-curl

好吧,这是我没有看 readme.txt 文档,然后 var_dump() 花了三分钱才找到这个问题。

MD5签名验证不通过

这才是真正坑爹的问题!之前测试一直是支付成功但返回调用验证失败,直到我一步一步跟到SDK的源码里去对比要验证的签名串,才发现这根本就是SDK的一个BUG!请看 alipay_core.function.php 文件的 paraFilter 函数,这个函数的作用是过滤掉签名参数和空值参数,以便生成签名串。原来的SDK是这么写的:

function paraFilter($para) {
$para_filter = array();
// 问题就在这
while (list ($key, $val) = each ($para)) {
if($key == "sign" || $key == "sign_type" || $val == "")continue;
else $para_filter[$key] = $para[$key];
}
return $para_filter;
}

问题就出在 while 循环的条件里,每次过滤参数,这里直接就把第一个返回参数body=xxx 给过滤掉了,一旦我加上 body=xxx 变成完整的签名参数,生成的MD5签名就能对上。我百思不得其解的时候去查了PHP的文档,根据 each 方法说明,每调用一次游标就会发生改变,而首次调用之前没有调用 reset() 的话,就很可能被之前调用过这个数组的 each() 给弄错游标。而每次代码中每次都是从第二个参数开始,说明数组可能已经被其他程序调用过了(这个数组实际上是系统变量 $_GET ,但我实在没在CI框架代码中找到哪里调用的)。所以我想说的是: 好!好!写!个! foreach !循环会死么! 修改后的代码如下:

function paraFilter($para) {
// 增加这一行
reset($para);
$para_filter = array();
while (list ($key, $val) = each ($para)) {
if($key == "sign" || $key == "sign_type" || $val == "")continue;
else $para_filter[$key] = $para[$key];
}
return $para_filter;
}

这才算解决了签名不正确的问题。

另外,看了SDK源码才发现,支付宝的PHP程序员英文真是烂,各种拼写错误,比如:verify写成veryfy,sign写成sgin……实在是无力吐槽。

好了,我把修改过的SDK包放在GitHub上了: https://github.com/mytharcher/alipay-php-sdk ,有需要请自取。

-EOF-

http://yanjunyi.com/blog/posts/alipay-integration-in-codeigniter.html?utm_source=tuicool

*CodeIgniter框架集成支付宝即时到账SDK的更多相关文章

  1. ***CodeIgniter框架集成支付宝即时到账支付SDK

    本文为CI集成支付宝即时到账支付接口 1.下载支付宝官方demo ;即时到账交易接口(create_direct_pay_by_user)(DEMO下载) 原文地址:https://doc.open. ...

  2. thinkphp框架对接支付宝即时到账接口回调的代码

    关于支付宝即时收款接口的对接过程,很简单,也有很多人发过,我这里就不在啰嗦了,对接完成后,在线支付成功后的回调,相对来说,是个难点,,我重点分享下我的经验. 我在开发二代旅游CMS(http://ww ...

  3. 实战 Spring MVC接入支付宝即时到账 (部分代码)

    下面就拿我项目中的部分代码来实践一下. 支付请求 首先,是提交表单 fund.jsp(这里我表单只需要用户填交易金额,其他的订单号之类的全部后台生成) <form id="deposi ...

  4. 支付宝即时到账DEMO配置与使用

    支付宝网页即时到账功能,可让用户在线向开发者的支付宝账号支付资金,交易资金即时到账,帮助开发者快速回笼资金. 当用户进行支付操作时候可以直接跳转到支付宝支付页面进行支付 1. 准备 关于支付宝签约即时 ...

  5. PHP九大接口视频教程( 支付宝,QQ,短信接口,微信接口开发, 支付宝即时到账接口开发三级分销全套)

    PHP九大接口视频教程(  支付宝,QQ,短信接口,微信接口开发, 支付宝即时到账接口开发三级分销全套) 需要的联系我:QQ: 1844912514 PHP九大接口视频教程(  支付宝,QQ,短信接口 ...

  6. PHP实现支付宝即时到账功能

    本文实例为大家分享了PHP支付宝即时到账功能的实现代码,供大家参考,具体内容如下 首先需要下载即时到账交易接口,传送门https://doc.open.alipay.com/doc2/detail?t ...

  7. PHP 接入支付宝即时到账功能

    首先请到支付宝那边申请一个及时到账的接口账户,需要提交相关材料申请.然后根据即时到账的API文档进行接入.API文档提供了各种语言版本的demo,我这里是下的php版demo,然后再进行相关修改操作. ...

  8. tp框架集成支付宝,中转页变成gbk编码

    tp框架中集成支付宝的功能,将支付宝的demo例子存在到下图位置\Extend\Vendor\Alipay 生成支付订单 /** * 支付订单 */ public function pay() { h ...

  9. ThinkPHP 3.2 支付宝即时到账接口开发

    前言: 一.支付流程 构造请求参数 向支付宝网关发送请求 生成支付宝页面 支付宝交易结果 二.构建支付类 1.官方即时到账文档地址: https://doc.open.alipay.com/doc2/ ...

随机推荐

  1. 可能是全网最全的http面试答案

    HTTP有哪些方法? HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法 HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNE ...

  2. 链接进入react二级路由,引发的子组件二次挂载

    这个问题很怪,我两个二级路由从链接进入的时候,会挂载两次子组件. 从链接进入,是因为新页面在新标签页打开的. 有子组件是因为公共组件提取 同样的操作,有一些简单的二级路由页面,就不会挂载两次. 讲道理 ...

  3. HttpClient 源码阅读

    在项目中常用的HttpClient,与我们非常的亲密,为了能处理遇到的Http问题,我们应该去了解里面的机制和实现. 官方文档:http://hc.apache.org/httpcomponents- ...

  4. Oracle笔记(七) 数据更新、事务处理、数据伪列

    一.数据的更新操作 DML操作语法之中,除了查询之外还有数据的库的更新操作,数据的更新操作主要指的是:增加.修改.删除数据,但是考虑到emp表以后还要继续使用,所以下面先将emp表复制一份,输入如下指 ...

  5. 解决Chrome无法安装CRX离线插件

    解释说明: 谷歌浏览器Chrome,版本号67.0.3396.99,自这个版本后的Chrome,手动拖放插件文件crx到谷歌浏览器,这种安装插件的方式,一定会失败,它会提示“无法从该网站添加应用,扩展 ...

  6. python学习-数据类型

    计算机处理的数据不单纯的指数字,计算机可以处理数字.文本.音频.视频等等各种数据,下面描述的是Python中可以直接使用和处理的基本数据类型.     整数 Python可以处理任意大小的整数,跟ja ...

  7. STM32WB SRAM2

    SRAM2存储: 1.挂接总线及地址大小 2.地址镜像 3.RDP(read protection)等级 4.不同等级下的访问状态 5.声明位于SRAM2区中的数据 1)在icf文件中定义region ...

  8. [ZOJ 4025] King of Karaoke

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5766 求两个序列的相对元素的差出现次数最多的,最低出现一次. AC代 ...

  9. Git学习笔记(2)-Eclipse中Git插件使用

    目前我使用的Eclipse luna版本中已经集成了git插件,这里就不介绍如何安装Git插件了,不懂可以看其他的博客. 上篇笔记介绍了Git的基本指令,实际开发中我基本都使用eclipse插件进行代 ...

  10. mongo批量插入问题(insert_many,bulk_write),spark df转json传入mongo

    https://blog.csdn.net/nihaoxiaocui/article/details/95060906 https://xuexiyuan.cn/article/detail/173. ...