版本:CodeIgniter_2.0.1
最近使用CodeIgniter写商城系统的代码需要集成支付宝即时到账功能进去
看了下支付宝官方发布的代码主要包括2部分
第一部分:
支付宝外部服务接口控制类
alipay_service.php
付款过程中服务器通知类
alipay_notify.php
以及支付宝接口公用函数
alipay_function.php
第二部分:
支付宝主动通知调用页面(服务器异步通知页面)
notify_url.php
付完款后跳转的页面(页面跳转同步通知页面)
return_url.php
其次就是alipay的配置文件
上面代码意思是如果是在线支付就显示使用支付宝支付
application/libraries/alipay/Alipay_notify.php
application/libraries/alipay/alipay_function.php
application/models/alipay_model.php
最好别丢了配置文件了(自己按注释填好)
application/config/alipay.php
最近使用CodeIgniter写商城系统的代码需要集成支付宝即时到账功能进去
看了下支付宝官方发布的代码主要包括2部分
第一部分:
支付宝外部服务接口控制类
alipay_service.php
付款过程中服务器通知类
alipay_notify.php
以及支付宝接口公用函数
alipay_function.php
第二部分:
支付宝主动通知调用页面(服务器异步通知页面)
notify_url.php
付完款后跳转的页面(页面跳转同步通知页面)
return_url.php
其次就是alipay的配置文件
alipay_config.php
下面是我按codeigniter框架的思路构建:
1.创建自己的类库到codeigniter, 同样是两个类Alipay_service和Alipay_notify
2.创建alipay模型,主要功能是构建支付提交表单,通知函数,及数据库更新支付宝交易号功能
3.创建alipay配置文件
4.最后就是调用了,控制层调用alipay模型就可以了
使用示例:
控制层代码
application/controllers/product.php 代码片段
//生成在线支付链接
$this
->load->model(
'alipay_model'
);
$data
[
'alipay_form'
] =
$this
->alipay_model->build_form(
$data
[
'order_sn'
],
$data
[
'product_name'
],
$data
[
'total'
]);
$this
->load->view(
'product/quick_buy'
,
$data
);
上面代码的意思是给alipay_model的build_form函数传入参数订单号,产品名,金额
显示层代码
application/views/product/quick_buy.php 代码片段
<?php
if
(
'online'
==
$payment
) {
echo
$alipay_form
;
}?>
application/libraries/alipay/Alipay_service.php
<span style="font-size:14px;"><?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* Codeigiter的支付宝外部服务接口控制
* @author http://blog.runphp.net
* @version 0.1
*/
require_once("alipay_function.php");
class Alipay_service {
var $gateway; //网关地址
var $_key; //安全校验码
var $mysign; //签名结果
var $sign_type; //签名类型
var $parameter; //需要签名的参数数组
var $_input_charset; //字符编码格式
function __construct($parameter)
{
self::Alipay_service(
$parameter['parameter'],
$parameter['key'],
$parameter['sign_type']
);
}
/**
* 构造函数
* 从配置文件及入口文件中初始化变量
* @param array $parameter 需要签名的参数数组
* @param string $key 安全校验码
* @param string $sign_type 签名类型
*/
public function Alipay_service($parameter, $key, $sign_type)
{
$this->gateway = "https://www.alipay.com/cooperate/gateway.do?";
$this->_key = $key;
$this->sign_type = $sign_type;
$this->parameter = para_filter($parameter);
//设定_input_charset的值,为空值的情况下默认为GBK
if($this->parameter['_input_charset'] == '')
$this->parameter['_input_charset'] = 'GBK';
$this->_input_charset = $this->parameter['_input_charset'];
//获得签名结果
$sort_array = arg_sort($this->parameter); //得到从字母a到z排序后的签名参数数组
$this->mysign = build_mysign($sort_array,$this->_key,$this->sign_type);
}
/**
*
* Enter description here ...
*/
function build_form() {
//GET方式传递
$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$this->gateway."_input_charset=".$this->parameter['_input_charset']."' method='get'>";
//POST方式传递(GET与POST二必选一)
//$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$this->gateway."_input_charset=".$this->parameter['_input_charset']."' method='post'>";
while (list ($key, $val) = each ($this->parameter)) {
$sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>";
}
$sHtml = $sHtml."<input type='hidden' name='sign' value='".$this->mysign."'/>";
$sHtml = $sHtml."<input type='hidden' name='sign_type' value='".$this->sign_type."'/>";
//submit按钮控件请不要含有name属性
$sHtml = $sHtml."<input type='submit' value='支付宝确认付款'></form>";
//$sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";
return $sHtml;
}
}</span>
application/libraries/alipay/Alipay_notify.php
<span style="font-size:14px;"><?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* Codeigiter付款过程中服务器通知类
* @author http://blog.runphp.net
* @version 0.1
*/
require_once("alipay_function.php");
class Alipay_notify {
var $gateway; //网关地址
var $_key; //安全校验码
var $partner; //合作伙伴ID
var $sign_type; //签名方式 系统默认
var $mysign; //签名结果
var $_input_charset; //字符编码格式
var $transport; //访问模式
function __construct($parameter)
{
self::Alipay_notify(
$parameter['partner'],
$parameter['key'],
$parameter['sign_type'],
$parameter['_input_charset'],
$parameter['transport']
);
}
/**构造函数
*从配置文件中初始化变量
*$partner 合作身份者ID
*$key 安全校验码
*$sign_type 签名类型
*$_input_charset 字符编码格式
*$transport 访问模式
*/
function Alipay_notify($partner,$key,$sign_type,$_input_charset = "GBK",$transport= "https") {
$this->transport = $transport;
if($this->transport == "https") {
$this->gateway = "https://www.alipay.com/cooperate/gateway.do?";
}else {
$this->gateway = "http://notify.alipay.com/trade/notify_query.do?";
}
$this->partner = $partner;
$this->_key = $key;
$this->mysign = "";
$this->sign_type = $sign_type;
$this->_input_charset = $_input_charset;
}
/********************************************************************************/
/**对notify_url的认证
*返回的验证结果:true/false
*/
function notify_verify() {
//获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
if($this->transport == "https") {
$veryfy_url = $this->gateway. "service=notify_verify" ."&partner=" .$this->partner. "¬ify_id=".$_POST["notify_id"];
} else {
$veryfy_url = $this->gateway. "partner=".$this->partner."¬ify_id=".$_POST["notify_id"];
}
$veryfy_result = $this->get_verify($veryfy_url);
//生成签名结果
if(empty($_POST)) { //判断POST来的数组是否为空
return false;
}
else {
$post = para_filter($_POST); //对所有POST返回的参数去空
$sort_post = arg_sort($post); //对所有POST反馈回来的数据排序
$this->mysign = build_mysign($sort_post,$this->_key,$this->sign_type); //生成签名结果
//写日志记录
log_result("veryfy_result=".$veryfy_result."\n notify_url_log:sign=".$_POST["sign"]."&mysign=".$this->mysign.",".create_linkstring($sort_post));
//判断veryfy_result是否为ture,生成的签名结果mysign与获得的签名结果sign是否一致
//$veryfy_result的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//mysign与sign不等,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i",$veryfy_result) && $this->mysign == $_POST["sign"]) {
return true;
} else {
return false;
}
}
}
/********************************************************************************/
/**对return_url的认证
*return 验证结果:true/false
*/
function return_verify() {
//获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
if($this->transport == "https") {
$veryfy_url = $this->gateway. "service=notify_verify" ."&partner=" .$this->partner. "¬ify_id=".$_GET["notify_id"];
} else {
$veryfy_url = $this->gateway. "partner=".$this->partner."¬ify_id=".$_GET["notify_id"];
}
$veryfy_result = $this->get_verify($veryfy_url);
//生成签名结果
if(empty($_GET)) { //判断GET来的数组是否为空
return false;
}
else {
$get = para_filter($_GET); //对所有GET反馈回来的数据去空
$sort_get = arg_sort($get); //对所有GET反馈回来的数据排序
$this->mysign = build_mysign($sort_get,$this->_key,$this->sign_type); //生成签名结果
//写日志记录
//log_result("veryfy_result=".$veryfy_result."\n return_url_log:sign=".$_GET["sign"]."&mysign=".$this->mysign."&".create_linkstring($sort_get));
//判断veryfy_result是否为ture,生成的签名结果mysign与获得的签名结果sign是否一致
//$veryfy_result的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//mysign与sign不等,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i",$veryfy_result) && $this->mysign == $_GET["sign"]) {
return true;
}else {
return false;
}
}
}
/********************************************************************************/
/**获取远程服务器ATN结果
*$url 指定URL路径地址
*return 服务器ATN结果集
*/
function get_verify($url,$time_out = "60") {
$urlarr = parse_url($url);
$errno = "";
$errstr = "";
$transports = "";
if($urlarr["scheme"] == "https") {
$transports = "ssl://";
$urlarr["port"] = "443";
} else {
$transports = "tcp://";
$urlarr["port"] = "80";
}
$fp=@fsockopen($transports . $urlarr['host'],$urlarr['port'],$errno,$errstr,$time_out);
if(!$fp) {
die("ERROR: $errno - $errstr<br />\n");
} else {
fputs($fp, "POST ".$urlarr["path"]." HTTP/1.1\r\n");
fputs($fp, "Host: ".$urlarr["host"]."\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ".strlen($urlarr["query"])."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $urlarr["query"] . "\r\n\r\n");
while(!feof($fp)) {
$info[]=@fgets($fp, 1024);
}
fclose($fp);
$info = implode(",",$info);
return $info;
}
}
/********************************************************************************/
}
?></span>
application/libraries/alipay/alipay_function.php
<span style="font-size:14px;"><?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
*功能:支付宝接口公用函数
* @author http://blog.runphp.net
* @version 0.1
*/
/**生成签名结果
*$array要签名的数组
*return 签名结果字符串
*/
function build_mysign($sort_array,$key,$sign_type = "MD5") {
$prestr = create_linkstring($sort_array); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = $prestr.$key; //把拼接后的字符串再与安全校验码直接连接起来
$mysgin = sign($prestr,$sign_type); //把最终的字符串签名,获得签名结果
return $mysgin;
}
/********************************************************************************/
/**把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
*$array 需要拼接的数组
*return 拼接完成以后的字符串
*/
function create_linkstring($array) {
$arg = "";
while (list ($key, $val) = each ($array)) {
$arg.=$key."=".$val."&";
}
$arg = substr($arg,0,count($arg)-2); //去掉最后一个&字符
return $arg;
}
/********************************************************************************/
/**除去数组中的空值和签名参数
*$parameter 签名参数组
*return 去掉空值与签名参数后的新签名参数组
*/
function para_filter($parameter) {
$para = array();
while (list ($key, $val) = each ($parameter)) {
if($key == "sign" || $key == "sign_type" || $val == "")continue;
else $para[$key] = $parameter[$key];
}
return $para;
}
/********************************************************************************/
/**对数组排序
*$array 排序前的数组
*return 排序后的数组
*/
function arg_sort($array) {
ksort($array);
reset($array);
return $array;
}
/********************************************************************************/
/**签名字符串
*$prestr 需要签名的字符串
*return 签名结果
*/
function sign($prestr,$sign_type) {
$sign='';
if($sign_type == 'MD5') {
$sign = md5($prestr);
}elseif($sign_type =='DSA') {
//DSA 签名方法待后续开发
die("DSA 签名方法待后续开发,请先使用MD5签名方式");
}else {
die("支付宝暂不支持".$sign_type."类型的签名方式");
}
return $sign;
}
/********************************************************************************/
// 日志消息,把支付宝返回的参数记录下来
// 请注意服务器是否开通fopen配置
function log_result($word) {
$fp = fopen("log.txt","a");
flock($fp, LOCK_EX) ;
fwrite($fp,"执行日期:".strftime("%Y%m%d%H%M%S",time())."\n".$word."\n");
flock($fp, LOCK_UN);
fclose($fp);
}
/********************************************************************************/
/**实现多种字符编码方式
*$input 需要编码的字符串
*$_output_charset 输出的编码格式
*$_input_charset 输入的编码格式
*return 编码后的字符串
*/
function charset_encode($input,$_output_charset ,$_input_charset) {
$output = "";
if(!isset($_output_charset) )$_output_charset = $_input_charset;
if($_input_charset == $_output_charset || $input ==null ) {
$output = $input;
} elseif (function_exists("mb_convert_encoding")) {
$output = mb_convert_encoding($input,$_output_charset,$_input_charset);
} elseif(function_exists("iconv")) {
$output = iconv($_input_charset,$_output_charset,$input);
} else die("sorry, you have no libs support for charset change.");
return $output;
}
/********************************************************************************/
/**实现多种字符解码方式
*$input 需要解码的字符串
*$_output_charset 输出的解码格式
*$_input_charset 输入的解码格式
*return 解码后的字符串
*/
function charset_decode($input,$_input_charset ,$_output_charset) {
$output = "";
if(!isset($_input_charset) )$_input_charset = $_input_charset ;
if($_input_charset == $_output_charset || $input ==null ) {
$output = $input;
} elseif (function_exists("mb_convert_encoding")) {
$output = mb_convert_encoding($input,$_output_charset,$_input_charset);
} elseif(function_exists("iconv")) {
$output = iconv($_input_charset,$_output_charset,$input);
} else die("sorry, you have no libs support for charset changes.");
return $output;
}
/*********************************************************************************/
/**用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
注意:由于低版本的PHP配置环境不支持远程XML解析,因此必须服务器、本地电脑中装有支持DOMDocument、SSL的PHP配置环境。建议本地调试时使用PHP开发软件
*$partner 合作身份者ID
*return 时间戳字符串
*/
function query_timestamp($partner) {
$URL = "https://mapi.alipay.com/gateway.do?service=query_timestamp&partner=".$partner;
$encrypt_key = "";
//若要使用防钓鱼,请取消下面的4行注释
// $doc = new DOMDocument();
// $doc->load($URL);
// $itemEncrypt_key = $doc->getElementsByTagName( "encrypt_key" );
// $encrypt_key = $itemEncrypt_key->item(0)->nodeValue;
// return $encrypt_key;
}
?></span>
application/models/alipay_model.php
<span style="font-size:14px;"><?php
/**
* 支付宝模型
* @version 0.1
* @author http://blog.runphp.net
*
*/
class Alipay_model extends CI_Model{
var $alipay_config;
function __construct ()
{
parent::__construct();
$this->config->load('alipay', TRUE);
$this->alipay_config = $this->config->item('alipay');
}
/**
*
* 服务器异步通知
*/
function notify_verify ()
{
$tmp = array(
'partner' => $this->alipay_config['partner'],
'key' => $this->alipay_config['key'],
'sign_type' => $this->alipay_config['sign_type'],
'_input_charset' => $this->alipay_config['sign_type'],
'transport' => $this->alipay_config['transport'],
);
$this->load->library('alipay/alipay_notify', $tmp);
$verify_result = $this->alipay_notify->notify_verify();
if($verify_result) {
$dingdan = $_POST['out_trade_no']; //获取支付宝传递过来的订单号
$total = $_POST['total_fee']; //获取支付宝传递过来的总价格
if($_POST['trade_status'] == 'TRADE_FINISHED' ||$_POST['trade_status'] == 'TRADE_SUCCESS') { //交易成功结束
echo "success"; //请不要修改或删除
} else {
echo "success"; //其他状态判断。普通即时到帐中,其他状态不用判断,直接打印success。
}
self::update_status($_POST['trade_no'], $dingdan);
} else {
echo "fail";
}
}
/**
*
* 页面跳转同步通知
*/
function return_verify ()
{
$tmp = array(
'partner' => $this->alipay_config['partner'],
'key' => $this->alipay_config['key'],
'sign_type' => $this->alipay_config['sign_type'],
'_input_charset' => $this->alipay_config['sign_type'],
'transport' => $this->alipay_config['transport'],
);
$this->load->library('alipay/alipay_notify', $tmp);
$verify_result = $this->alipay_notify->return_verify();
if($verify_result) {//验证成功
$dingdan = $_GET['out_trade_no']; //获取订单号
$total_fee = $_GET['total_fee']; //获取总价格
if($_GET['trade_status'] == 'TRADE_FINISHED' || $_GET['trade_status'] == 'TRADE_SUCCESS') {
} else {
return $_GET['trade_status'];
}
self::update_status($_GET['trade_no'], $dingdan);
} else {
return "fail";
}
}
/**
*
* 更新订单状态(更新支付宝订单号)
* @param string $alipay_trade_no 支付宝订单号
* @param string $order_sn 商户订单号
*/
function update_status ($alipay_trade_no, $order_id)
{
//请在这里加上商户的业务逻辑程序代
$this->db->where('name', $order_id);
$this->db->update('sl_order', array('trade_no' => $alipay_trade_no));
}
/**
*
* 构造提交表单
* @param 订单编号 $order_id
* @param 订单名 $order_name
* @param 订单金额 $money
*/
function build_form ($order_id, $order_name, $money)
{
/*以下参数是需要通过下单时的订单数据传入进来获得*/
//必填参数
$out_trade_no = $order_id; //请与贵网站订单系统中的唯一订单号匹配
$subject = $order_name; //订单名称,显示在支付宝收银台里的“商品名称”里,显示在支付宝的交易管理的“商品名称”的列表里。
$body = ''; //订单描述、订单详细、订单备注,显示在支付宝收银台里的“商品描述”里
$total_fee = $money; //订单总金额,显示在支付宝收银台里的“应付总额”里
//扩展功能参数——默认支付方式
/*
$pay_mode = $_POST['pay_bank'];
if ($pay_mode == "directPay") {
$paymethod = "directPay"; //默认支付方式,四个值可选:bankPay(网银); cartoon(卡通); directPay(余额); CASH(网点支付)
$defaultbank = "";
}
else {
$paymethod = "bankPay"; //默认支付方式,四个值可选:bankPay(网银); cartoon(卡通); directPay(余额); CASH(网点支付)
$defaultbank = $pay_mode; //默认网银代号,代号列表见http://club.alipay.com/read.php?tid=8681379
}*/
$paymethod = "directPay";
$defaultbank = "";
//扩展功能参数——防钓鱼
//请慎重选择是否开启防钓鱼功能
//exter_invoke_ip、anti_phishing_key一旦被使用过,那么它们就会成为必填参数
//开启防钓鱼功能后,服务器、本机电脑必须支持远程XML解析,请配置好该环境。
//若要使用防钓鱼功能,请打开class文件夹中alipay_function.php文件,找到该文件最下方的query_timestamp函数,根据注释对该函数进行修改
//建议使用POST方式请求数据
$anti_phishing_key = ''; //防钓鱼时间戳
$exter_invoke_ip = $this->input->ip_address(); //获取客户端的IP地址,建议:编写获取客户端IP地址的程序
//如:
//$exter_invoke_ip = '202.1.1.1';
//$anti_phishing_key = query_timestamp($partner); //获取防钓鱼时间戳函数
//扩展功能参数——其他
$extra_common_param = ''; //自定义参数,可存放任何内容(除=、&等特殊字符外),不会显示在页面上
$buyer_email = ''; //默认买家支付宝账号
//扩展功能参数——分润(若要使用,请按照注释要求的格式赋值)
$royalty_type = ""; //提成类型,该值为固定值:10,不需要修改
$royalty_parameters = "";
//提成信息集,与需要结合商户网站自身情况动态获取每笔交易的各分润收款账号、各分润金额、各分润说明。最多只能设置10条
//各分润金额的总和须小于等于total_fee
//提成信息集格式为:收款方Email_1^金额1^备注1|收款方Email_2^金额2^备注2
//如:
//royalty_type = "10"
//royalty_parameters = "111@126.com^0.01^分润备注一|222@126.com^0.01^分润备注二"
//$alipay_config = $this->alipay_config;
$parameter = array(
"service" => "create_direct_pay_by_user", //接口名称,不需要修改
"payment_type" => "1", //交易类型,不需要修改
//获取配置文件中的值
"partner" => $this->alipay_config['partner'],
"seller_email" => $this->alipay_config['seller_email'],
"return_url" => $this->alipay_config['return_url'],
"notify_url" => $this->alipay_config['notify_url'],
"_input_charset" => $this->alipay_config['_input_charset'],
"show_url" => $this->alipay_config['show_url'],
//从订单数据中动态获取到的必填参数
"out_trade_no" => $out_trade_no,
"subject" => $subject,
"body" => $body,
"total_fee" => $total_fee,
//扩展功能参数——网银提前
"paymethod" => $paymethod,
"defaultbank" => $defaultbank,
//扩展功能参数——防钓鱼
"anti_phishing_key" => $anti_phishing_key,
"exter_invoke_ip" => $exter_invoke_ip,
//扩展功能参数——自定义参数
"buyer_email" => $buyer_email,
"extra_common_param"=> $extra_common_param,
//扩展功能参数——分润
"royalty_type" => $royalty_type,
"royalty_parameters"=> $royalty_parameters
);
$tmp = array('parameter' => $parameter, 'key' => $this->alipay_config['key'], 'sign_type' =>$this->alipay_config['sign_type']);
$this->load->library('alipay/alipay_service', $tmp);
return $this->alipay_service->build_form();
}
}</span>
最好别丢了配置文件了(自己按注释填好)
application/config/alipay.php
<span style="font-size:14px;"><?php
//合作身份者ID,以2088开头的16位纯数字
$config['partner'] = "";
//安全检验码,以数字和字母组成的32位字符
$config['key'] = "";
//签约支付宝账号或卖家支付宝帐户
$config['seller_email'] = "";
//交易过程中服务器通知的页面 要用 http://格式的完整路径,不允许加?id=123这类自定义参数
$config['notify_url'] = "";
//付完款后跳转的页面 要用 http://格式的完整路径,不允许加?id=123这类自定义参数
$config['return_url'] = "";
//网站商品的展示地址,不允许加?id=123这类自定义参数
$config['show_url'] = "http://blog.runphp.net";
//收款方名称,如:公司名称、网站名称、收款人姓名等
$config['mainname'] = "heui";
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
//$config['total_fee'] = 1; //订单总金额,显示在支付宝收银台里的“应付总额”里
//签名方式 不需修改
$config['sign_type'] = "MD5";
//字符编码格式 目前支持 GBK 或 utf-8
$config['_input_charset'] = "utf-8";
//访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
$config['transport'] = "http";
?></span>