本文使用的支付宝即时到账业务接口,API文档下载地址:支付宝即时到账接口文档
1. 集成支付宝的CI目录结构
├─config 配置文件目录
│ ├─alipay.php 支付宝配置文件
│ └─...
├─...
├─libraries 扩展类库目录
│ ├─MY_AlipayNotify.php 支付宝返回通知
│ ├─MY_AlipaySubmit.php 支付提交
│ ├─Payment 各种支付类库目录
│ │ ├─Alipaylib 支付宝类库包目录
│ │ │ ├─alipay_core.function.php
│ │ │ ├─alipay_md5.function.php
│ │ │ ├─alipay_submit.class.php
│ │ │ ├─alipay_notify.class.php
│ │ │ └─cacert.pem
│ │ ├─Wechatpay 微信支付类库目录
│ │ └─... 更多支付类库目录
│ └─... 更多第三方类库目录
└─...
2. alipay.php 支付宝配置文件
3. MY_AlipaySubmit.php 支付宝支付
_CI = & get_instance();
// 判断是否存在配置文件
if (empty($config)) {
// 加载 Alipay 配置文件
$this->_CI->load->config('alipay', TRUE);
$config = $this->_CI->config->item('alipay');
}
parent::__construct($config);
}
/**
* submit 支付提交
* @access public
* @param string $out_trade_no 商户订单号 商户网站订单系统中唯一订单号
* @param string $subject 订单名称
* @param float $total_fee 付款金额
* @param string $body 商品描述 可空
* @return void
* @author Mike Lee
*/
public function submit($order_code){
$this->_CI->load->model('order_model');
$order_info = $this->_CI->order_model->getOrderByID($order_code, true);
if ( ! is_array($order_info) || ! $order_info) return false;
$subject = 'XXXX订单';
$total_fee = $order_info['order_amount'];
$body = 'XXXX网站商品购买';
// 构造要请求的参数数组
$parameter = array(
"service" => $this->alipay_config['service'],
"partner" => $this->alipay_config['partner'],
"seller_id" => $this->alipay_config['seller_id'],
"payment_type" => $this->alipay_config['payment_type'],
"notify_url" => $this->alipay_config['notify_url'],
"return_url" => $this->alipay_config['return_url'],
"anti_phishing_key" => $this->alipay_config['anti_phishing_key'],
"exter_invoke_ip" => $this->alipay_config['exter_invoke_ip'],
"out_trade_no" => $order_code,
"subject" => $subject,
"total_fee" => $total_fee,
"body" => $body,
"_input_charset" => trim(strtolower($this->alipay_config['input_charset']))
);
$html_text = $this->buildRequestForm($parameter, 'get', '确认');
return $html_text;
}
}
/* End of file MY_AlipaySubmit.php */
/* Location: ./application/libraries/MY_AlipaySubmit.php */
?>
4. MY_AlipayReturn.php 支付宝返回通知
_CI = & get_instance();
// 判断是否存在配置文件
if (empty($config)) {
// 加载 Alipay 配置文件
$this->_CI->load->config('alipay', TRUE);
$config = $this->_CI->config->item('alipay');
}
parent::__construct($config);
}
/**
* asynNotify 异步通知
* @access public
* @param void
* @return void
* @author Mike Lee
*/
public function asynNotify(){
$verify_result = $this->verifyNotify();
if($verify_result) { //验证成功
$notify_data = $this->_CI->input->post(null, true);
//交易状态
$trade_status = $notify_data['trade_status'];
// 根据交易状态处理订单支付状态
if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {
// 更新订单支付信息
$this->updateOrderPay($notify_data);
}
echo 'success'; //请不要修改或删除
} else { //验证失败
echo 'fail'; //请不要修改或删除
}
}
/**
* syncReturn 页面跳转同步通知
* @access public
* @param void
* @return void
* @author Mike Lee
*/
public function syncReturn(){
$verify_result = $this->verifyReturn();
if($verify_result) { // 验证成功
$return_data = $this->_CI->input->get(null, true);
// 交易状态
$trade_status = $return_data['trade_status'];
if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {
// 更新订单支付信息
$this->updateOrderPay($return_data);
return true;
} else {
return false;
}
return true;
} else {
// 验证失败
return false;
}
}
/**
* updateOrderPay 更新订单支付信息
* @access private
* @param string $order_code
* @return mixed
* @author Mike Lee
*/
public function updateOrderPay($alipay_data){
$this->_CI->load->model('order_model');
// 根据订单号获取订单信息
$order_code = $alipay_data['out_trade_no'];
$order_info = $this->_CI->order_model->getOrderByID($order_code, true);
// 判断订单状态以及是否已经支付
if ($order_info['order_status'] == 0 && $order_info['pay_status'] != '1') {
// 更新订单的支付状态及支付方式
// pay_status => 1 表示支付成功
// pay_method => 3 表示支付方式为支付宝支付
$pay_info = array('pay_status' => '1', 'pay_method' => 3);
$pay_result = $this->_CI->order_model->updateOrderPayStatus($order_code, $pay_info, true);
// 添加订单支付信息
// user_id 用户ID
// order_id 订单ID
// total_fee 支付总额
// openid 用户支付宝ID buyer_id
$order_pay_info = array(
'user_id' => $order_info['user_id'],
'order_id' => $order_info['id'],
'total_fee' => $alipay_data['total_fee'],
#'total_fee' => $alipay_data['price'],
'buyer_id' => $alipay_data['buyer_id'],
'time' => time()
);
$this->_CI->order_model->addOrderPayLog($order_pay_info);
// 添加用户收支日志
// correlation_id 关联ID 这里为订单ID
// action_type => 1 表示为XXXX商品购买事件
// point_type => 5 表示为支付宝支付
$payment_log = array(
'user_id' => $order_info['user_id'],
'correlation_id' => $order_info['id'],
'action_type' => 1,
'pay_type' => 5,
'total_fee' => $alipay_data['total_fee'],
'remark' => 'XXX网站商品购买:支付宝支付'.$alipay_data['total_fee'],
'action_ip' => $_SERVER['REMOTE_ADDR'],
'add_time' => time()
);
$this->_CI->order_model->addUserPayLog($payment_log);
}
return true;
}
}
/* End of file MY_AlipayNotify.php */
/* Location: ./application/libraries/MY_AlipayNotify.php */
5. Pay.php 控制器
isNeedLogin = FALSE;
parent::__construct();
}
/**
* submitPaymentToAlipay 提交支付宝支付
* @access public
* @param string $order_code
* @return void
* @author Mike Lee
*/
public function submitPaymentToAlipay($order_code){
$this->load->library('MY_AlipaySubmit');
$result = $this->my_alipaysubmit->submit($order_code);
if ($result === false) {
// 无效订单跳转
// 请注意这里的跳转方法是自己写的
$this->jumpNoticePage('无订单信息!', $_SERVER['HTTP_REFERER'], 'ERROR');
}
$this->assign('html_text', $result);
$this->display('order/alipay.html');
}
/**
* aliPayNotify 支付宝异步回调
* notify_url http://www.xxxx.com/index.php/pay/alipaynotify
* @access public
* @param void
* @return void
* @author Mike Lee
*/
public function aliPayNotify(){
$this->load->library('MY_AlipayNotify');
$this->my_alipaynotify->asynNotify();
}
/**
* aliPayReturn 支付宝同步通知
* return_url http://www.xxxx.com/index.php/pay/alipayreturn
* @access public
* @param void
* @return void
* @author Mike Lee
*/
public function aliPayReturn(){
$this->load->library('MY_AlipayNotify');
if ($this->my_alipaynotify->syncReturn()) {
// 验证成功 这里可以执行你想要的跳转
$this->jumpNoticePage('订单支付成功!', site_url('order'));
} else {
// 验证失败跳转
$this->jumpNoticePage('订单支付失败!', site_url('order'), 'ERROR');
}
}
6. 小结
总体来说,支付宝支付的使用还是很简单的,目前支付宝即时到账有密退款DEMO还没有去研究,有时间肯定会继续更新的。另外我觉得支付宝即时到账DEMO中库文件太多,后期准备将这些库文件整理成一个文件一个类,这样可以让整个集成结构更加清晰。
在调用支付宝支付成功后支付宝的同步跳转中出现了一个不明原因的验证错误,经过调试发现,在执行verifyReturn验证方法的过程中有个去除空值及签名参数的函数paraFilter执行后会使得$_GET中的第一个参数丢失,比如$para_temp['body']为第一个参数且不为空,执行paraFilter($para_temp)后body丢失了,但这个函数本身是没有问题的,这就导致我至今还没有找到造成参数丢失的原因,只好按照支付宝技术支持的方法在丢失参数的地方手动加上这个参数,这才验证通过。