支付宝接口 生成支付链接,php代码,精简封装
支付宝接口代码,网上搜索出来的大部分都是样例代码,不是在实际开发中应用的,而且没有经过仔细封装,导致文件、变量、函数过于罗嗦,说实话,支付宝做得不怎么样,要生成支付链接代码,尽然还要加什么鸟签名,这个签名浪费了我很长时间去调试,而且没有sandbox测试,支付宝真该好好学学paypal,paypal只要一个静态的html表单就可以提交。支付宝不经过程序处理是无法生成链接代码的。
支付包给出的官方代码示例php版本,并不适合实际开发项目使用,以utf-8的php版本为例:官方示例分为3个文件,
alipay_function.php alipay_service.php alipay_config.php 主要有一下几点问题:1,函数太多,2,变量太多,3函数功能过于分散,4代码不符合w3c标准,5参数传入过于罗嗦,6文件太多,7代码写的跟小学生似的,支付宝怎么也是一个大公司,php示例代码是招的实习生写的吗?
基于以上几个原因,在参考了官方示例代码上,重写了一个支付宝支付链接生成代码。 先参照官方示例来分析一下要生成支付宝支付的细节。
alipay_config.php 内容如下:
$partner = ""; //合作身份者ID,以2088开头的16位纯数字
$key = ""; //安全检验码,以数字和字母组成的32位字符
$seller_email = ""; //签约支付宝账号或卖家支付宝帐户
//交易过程中服务器通知的页面 要用 http://格式的完整路径,不允许加?id=123这类自定义参数
$notify_url = "/js_php_utf8/notify_url.php"; //付完款后跳转的页面 要用 http://格式的完整路径,不允许加?id=123这类自定义参数
//return_url的域名不能写成
http://localhost/js_php_utf8/return_url.php ,否则会导致return_url执行无效
$return_url = "/js_php_utf8/return_url.php"; //网站商品的展示地址,不允许加?id=123这类自定义参数
$show_url = "";
//签名方式 不需修改
$sign_type = "MD5";
//字符编码格式 目前支持 GBK 或 utf-8
$_input_charset = "utf-8";
//访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
$transport = "http";
这里面的参数不用多说,不过有两个要注意,一,partner 和 key 是你在注册的商家里面能查询到的。
二,通知页面和返回页面 $notify_url和$return_url这两个参数是一个不含有查询字符串的网址,为什么不能含有?
可能是支付宝技术细节的问题了。这两个参数可以不提交,如果你的网站不需要返回的话。 再看第二部分:alipay_service.php 这个文件用来生成页面的提交按钮或者提交链接。 支付宝可以用三种方式来提交付款
1,一个a标签的链接,链接地址里包含支付信息
2,一个form表单,表单提交方式为get
3,一个form表单,表单提交方式为post。
2和3这两种方式是需要生成表单的,但有些不一样,一会儿详细阐述。
require_once("alipay_function.php"); // 包含一些通用函数,这个在支付宝的官方教程包里面有。
class alipay_service {
var $gateway; //网关地址
var $_key; //安全校验码
var $mysign; //签名结果
var $sign_type; //签名类型
var $parameter; //需要签名的参数数组
var $_input_charset; //字符编码格式
function alipay_service($parameter,$key,$sign_type) {
$this->gateway =
"https:///cooperate/gateway.do?";
$this->_key = $key; //传入key
$this->sign_type = $sign_type;
$this->parameter = para_filter($parameter);
// para_filter 这函数的的作用是:返回过滤掉键值为 sign 、sign_type、或者值为空的数组
//设定_input_charset的值,为空值的情况下默认为GBK
if($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);
//按照数组,将追加上的字符串生成签名。
}
// 构造表单代码
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 each)这样的循环遍历数组,是很不好的,perl的用法,php应该用foreach才是最好
while (list ($key, $val) = each ($this->parameter)) {
$sHtml.= "<input name='".$key."' type='hidden' value='".$val."' />";
}
$sHtml = $sHtml."<input name='sign' type='hidden' value='".$this->mysign."' />";
$sHtml = $sHtml."<input name='sign_type' type='hidden' value='".$this->sign_type."' />";
//submit按钮控件请不要含有name属性
$sHtml = $sHtml."<input type='submit' value='支付宝确认付款' />" ;
return $sHtml;
}
}
下面来分析,支付宝生成的参数方式。
支付宝允许提交的参数有以下:
array(
'_input_charset' => 'UTF-8' , //字符集,默认为GBK
'service' => "create_direct_pay_by_user", //交易类型,必填实物交易=trade_create_by_buyer(需要填写物流)
'partner'=>'', //合作商户号
'subjet'=>'虚拟商品', //商品标题
'body'=>'商品描述',
'show_url' => '',//商品相关网站
'seller_email' => 'test@test.com' ,//卖家邮箱,必填
'return_url' =>'', //同步返回
'notify_url' =>'', //异步返回
'logistics_fee'=>'0', //物流配送费用
'logistics_payment'=>'BUYER_PAY', //物流配送费用付款方式:BUYER_PAY(买家支付)
'logistics_type'=>'EXPRESS',// 物流配送方式:POST(平邮)、EMS(EMS)、EXPRESS(其他快递)
'payment_type'=>'1', // 默认为1,不需要修改
'quantity' => '1' //商品数量,必填
);
除去上面列出的,还有一些。具体可以参考支付宝的官方文档。
字符宝需要提供一个sign还有一个sign_type来做签名验证,这个签名验证到底是神马玩意? 现在以生成的a标签链接为示例,讲解签名生成步骤。当然了采用MD5验证方式,其他的
验证没有必要,
所以这里的 sign_type 为 MD5
1,构造一个支付宝能接受的参数数组,比如 $param,
$param = array( '_input_charset'=>'', ...... );
2,对$param参数的key进行 a..z排序,这时候只需要调用一个 ksort() 函数就可以。
3,把$param的键和值采用 key=val 的方式拼接成链接,中间用&符号分隔,结尾不要加&符号。
假如生成的变量为 $str
4,把链接好的字符串,再接上支付宝提供的key,然后,即 $sign = md5($str . $key )
5,把生成的签名追加到 $str 后面,再接上签名方式 sign_type=md5,生成最终的链接地址: return $url . '&=sign' . $sign . '&sign_type=MD5' ;
好,下面是我封装好的生成支付宝链接或form表单的类,这里并没有支付成功后的处理函数,
待以后再放出。
封装原则,第一,把支付宝的所有固定参数独立出来,做成$config数组变量。不再定义其他任何变量。
这个$config数组一般写在网站的配置文件中。因为不需要做什么改动。调用的时候传入 $param参数数组
用来覆盖$config参数里的对应键值。
$config['alipay'] = array(
'_input_charset' => 'UTF-8' , //字符集,默认为GBK
'service' => "create_direct_pay_by_user", //交易类型,必填实物交易=trade_create_by_buyer(需要填写物流)
'partner'=>'', //合作商户号
'key'=>'' , // 这里key 并不是支付宝可以接受的参数,但由于和支付宝相关,所以写在一个数组里,待生成的时候去掉该键。
'subjet'=>'虚拟商品', //商品标题
'body'=>'商品描述',
'show_url' => '',//商品相关网站
'seller_email' => 'test@test.com' ,//卖家邮箱,必填 'return_url' =>'', //同步返回
'notify_url' =>'', //异步返回
'payment_type'=>'1', // 默认为1,不需要修改
'quantity' => '1' //商品数量,必填
);
alipay的封装类。
class alipay_service {
var $gateway ;
var $param; //需要签名的参数数组
var $key ; // 签名key,由config数组中独立出来
function alipay_service($config, $param) {
$this->gateway =
"https:///cooperate/gateway.do";
$this->param = array_merge($config, $param) ; // 合并两个数组,相同的键,前者值会被后者覆盖
$this->key = $this->param['key']; // 获取支付宝的key值,并存入类变量里。
unset($this->param['key']) ; // 这里把key键值去掉,因为key不是支付宝能接受的参数,只是用来做签名用。
//获得签名结果
$this->alipay_sign();
}
// 数字签名
function alipay_sign() {
// 1,先排序
ksort($this->param);
reset($this->param);
// 2,过滤数组中的无关参数,这里采用 ===来过滤字符串值为空的项,防止误过滤变量值为 0 的项
$para = array();
foreach ( $this->param as $key=>$val ) {
if($key == "sign" || $key == "sign_type" || $val === '' ) continue;
$para[$key] = $val ;
}
// 3,将数组中的参数链接成一个支付串,并用&分隔。
$arg = "";
foreach ( $para as $key=>$val ) {
$arg .= "{$key}={$val}&";
}
$arg = trim($arg, '&'); //去掉最后一个&字符 ,支付宝官方尽然还用substr函数来去除,真是不怕麻烦。
// 3,替换签名字符串
$this->param['sign'] = md5( $arg . $this->key ) ; // 链接上商家的key,支付包给出,生成md5加密后的值
$this->param['sign_type'] = 'MD5'; // 签名类型为 md5加密 //到此,类的变量 $this->param包含了全部需要提交给支付宝的参数。下面如果需要,只要遍历出键值,链接成相应的字符串即可
}
function create_form($method='get') {
if(!in_array($method, array('get', 'post'))) $method = 'get'; $action = $this->gateway . ( 'post' ==
$method ? '?_input_charset=' . $this->param['_input_charset'] : '' ); // 这一步,如果是post提交,一定要在参数后面添加上字符串编码类型,否则,支付宝解析错误。
$html = '<form id="alipaysubmit" action="' . $action . '" method="'.$method.'">';
foreach ($this->param as $key=>$val) {
if($val==='') continue;
$html .= '<input name="'.$key.'" type="hidden"
value="'.$val.'" />';
}
//submit按钮控件请不要含有name属性
$html .= '<input type="submit" value="支付宝确认付款" /></form>';
return $html;
}
// 创建链接字符串
function create_link(){
$url = '' ;
foreach( $this->param as $key=>$val){
if($val==='') continue;
$url .= "{$key}={$val}&";
}
$url =$this->gateway . '?' . trim($url, '&') ;
return $url ;
}
}
调用方法:
require 'alipay.php';
$ali_param = array(
'subject'=>'商品标题',
'price'=>'10.00' , // 价格
'quantity'=>'1', // 数量
'out_trade_no'=> date('YmdHis') // 订单号,需要唯一,所以可以暂时用这样的
);
$alipay = new alipay_service($config['alipay'], $ali_param) ; $alipay_url = $alipay->create_link() ;
页面上直接写: <a href=" <?php echo $alipay_url; ?>">去支付宝支付</a>
这样就生成了支付的链接按钮,支付完成后,需要调用通知,并做相关处理,以后再放出封装后的代码