您的位置:首页 > 运维架构 > 网站架构

支付宝手机网站即时交易 自己封装的类

2015-06-18 15:20 537 查看
<?php
/*
支付宝封装类
采用 rsa 生成签名模式
*/
class Alipay {
private $_config                     = array();
private $_alipay_gateway_new         = 'https://mapi.alipay.com/gateway.do?'; //支付宝网关地址(新)
private $_https_verify_url             = 'https://mapi.alipay.com/gateway.do?service=notify_verify&'; //校验用到
private $_fix_config                   = array();

public function __construct() {
$this->_makeFixconfig();
}

//读取固定参数
private function _makeFixconfig() {
$this->_fix_config             = array(
'service'                 => 'alipay.wap.create.direct.pay.by.user',
'_input_charset'         => 'utf-8',
'sign_type'             => 'RSA',
'seller_id'             => '',
'private_key_path'         => VENDOR_PATH . '/Alipay/rsa_private_key.pem',//私密key
'ali_public_key_path'     => VENDOR_PATH . '/Alipay/alipay_public_key.pem',//公开key
'cacert'                 => VENDOR_PATH . '/Alipay/cacert.pem',//https请求用到验证
'transport'             => 'http',
'payment_type'             => 1,//固定参数
);
}

/*
config 需要参数
partner                         //合作身份者id,以2088开头的16位纯数字
notify_url                         //阿里处理后,异步处理url地址,http开头
return_url                         //阿里处理后,同步处理url地址

out_trade_no                     //订单号
subject                         //商品名称
total_fee                         //商品金额

*/
//生成配置文件,并请求
public function run($config) {
foreach ($config as $value) {
if(empty($value))
exit('缺少必要参数');
}

$this->_fix_config['seller_id']         = $config['partner'];

$this->_config                             = array_merge($this->_fix_config,$config);

//签名,请求
$this->_makeSign();
}

//生成签名信息,并发送请求
private function _makeSign() {
//获取签名需要的参数
$param                 = array(
'_input_charset'    => trim($this->_config['_input_charset']),
'service'             => trim($this->_config['service']),
'partner'             => trim($this->_config['partner']),
'seller_id'            => trim($this->_config['seller_id']),
'payment_type'        => trim($this->_config['payment_type']),
'notify_url'        => trim($this->_config['notify_url']),
'return_url'        => trim($this->_config['return_url']),
'out_trade_no'        => trim($this->_config['out_trade_no']),
'subject'            => trim($this->_config['subject']),
'total_fee'            => trim($this->_config['total_fee']),
);

//对数组进行排序
ksort($param);
reset($param);

//读取pem信息,生成key
if(!file_exists($this->_config['private_key_path']) || !file_exists($this->_config['ali_public_key_path']))
exit('缺少pem必要参数,请检查');

if(!function_exists('openssl_pkey_get_private'))
exit('不支持openssl');

$query_string         = '';
$query_string         = $this->_makeSignString($param);

$private_key_info    = file_get_contents($this->_config['private_key_path']);

$private_key_res     = openssl_pkey_get_private($private_key_info);

$sign                 = '';
openssl_sign($query_string, $sign, $private_key_res);

openssl_free_key($private_key_res);

//base64编码
$param['sign']                 = base64_encode($sign);

//验证签名
// $this->_checkSign($query_string,$param['sign']);

$param['sign_type']            = trim($this->_config['sign_type']);

//触发表单请求,使用get模拟请求会失败
$this->_formPush($param,'确认');
}

/*
--不能用模拟请求
发送get请求
$url         请求url地址
*/
private function _makeGetHttp($url) {
$curl                 = curl_init($url);

// curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
curl_setopt($curl, CURLOPT_CAINFO,$this->_fix_config['cacert']);//证书地址
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl,    CURLOPT_USERAGENT,"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)");

$result             = curl_exec($curl);

$httpCode             = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$curlErrNo             = curl_errno($curl);
$curlErr             = curl_error($curl);

curl_close($curl);

if ($httpCode == "0")
die("Curl error number:" . $curlErrNo . " , Curl error details:" . $curlErr . "\r\n");
else if ($httpCode != "200")
die("Http code:" . $httpCode .  " details:" . $result . "\r\n");

return $result;
}

/*
采用表单提交
*/
private function _formPush($para_temp,$button_name) {
$sHtml         = '<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>支付宝通信中...</title><link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css"></head><body>';

$sHtml         .= '<div class="container-fluid"><div class="row" style="margin-top:200px;"><div class="col-xs-10 col-md-10 col-xs-offset-1 col-md-offset-1"><span class="btn btn-success btn-block">请稍后,连接支付宝...</span></div></div></div>';

$sHtml         .= "<div style='display:none;'><form id='alipaysubmit' name='alipaysubmit' action='".$this->_alipay_gateway_new."_input_charset=".trim(strtolower($this->_config['_input_charset']))."' method='get'>";
while (list ($key, $val) = each ($para_temp)) {
$sHtml    .= "<input type='hidden' name='".$key."' value='".$val."'/>";
}

//submit按钮控件请不要含有name属性
$sHtml         = $sHtml."<input type='submit' value='".$button_name."'></form></div></body></html>";

$sHtml         = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";

echo $sHtml;
}

/*
构造签名字符串
*/
private function _makeSignString($arr,$type=false) {
$tmp_str             = '';
foreach ($arr as $key => $value) {
if($key == 'sign' || $key == 'sign_type')
continue;
$tmp_str         .= $key . '=' . $value . '&';
}

return trim($tmp_str,'&');
}

/*
验证rsa签名
@param         $data 返回的get或者post的总数组,
$sign get['sign'] 或者 post['sign']
@return     bool
*/
public function checkSign($data,$sign) {

//处理数据
$new_data                     = array();
foreach ($data as $key => $value) {
if($key == 'sign' || $key == 'sign_type' || $key == '_URL_' || $value == '')
continue;
$new_data[$key]             = $value;
}

ksort($new_data);
reset($new_data);

$new_data_str                 = '';
$new_data_str                 = $this->_makeSignString($new_data);

$ali_public_key_info         = file_get_contents($this->_fix_config['ali_public_key_path']);
$ali_public_key_res         = openssl_pkey_get_public($ali_public_key_info);

$ali_public_key_verify        = openssl_verify($new_data_str, base64_decode($sign), $ali_public_key_res);
openssl_free_key($ali_public_key_res);

if(!$ali_public_key_verify)
return false;
return true;
}

/*
验证url来源是否为支付宝
@param             partner 合作账号
notify_id get|post返回的
*/
public function checkUrlFrom($partner,$notify_id) {
$url             = $this->_https_verify_url . 'partner=' . $partner . '¬ify_id=' . $notify_id;
return $this->_makeGetHttp($url);
}

}


调用案例:

  通知页面不能有阻拦,比如说要登录才能进入之类的

/*
测试支付宝
*/
public function test_alipay() {
//引入
Vendor('Alipay.Alipay');

//生成参数
$param                 = array(
'partner'         => C('PARTENR'),//2088开头的支付宝信息
'notify_url'     => 'http://' . $_SERVER['HTTP_HOST'] . U('Leasegoods/alipay_notify_url'),//异步通知页面
'return_url'     => 'http://' . $_SERVER['HTTP_HOST'] . U('Leasegoods/alipay_return_url'),//同步通知页面
'out_trade_no'     => $this->_dealOrderNum(),//订单号
'subject'         => 'lxd',//商品名称
'total_fee'     => '0.01',//商品价格

);

$alipay_obj         = new Alipay();
$alipay_obj->run($param);
}


通知页面验证:

  同步异步都类似,第一 校验签名;第二 校验来源;其余的就是业务之类的东西了

public function alipay_return_url() {
$info                 = serialize($_GET);

$data                 = array();
//判断状态
if(isset($_GET) && $_GET['is_success'] == 'T') {
$order_index         = $_GET['out_trade_no'];

//校验签名
Vendor('Alipay.Alipay');
$alipay_obj         = new Alipay();
$res                 = $alipay_obj->checkSign($_GET,$_GET['sign']);

if(!$res){
$data['type']     = 'error';
$data['info']   = '警告:服务器校验数据失败';
$this->assign('data',$data);
$this->display('info');die;
}

//校验来源
$res                 = null;
$res                 = $alipay_obj->checkUrlFrom(C('PARTENR'),$_GET['notify_id']);
if($res == 'false'){
$data['type']     = 'error';
$data['info']   = '错误:服务器校验来源错误';
$this->assign('data',$data);
$this->display('info');die;
}

//记录流水
$alipay_log_model     = M('alipay_log');
$insert_res         = $alipay_log_model->add(array('order_index' => $order_index,'type' => 'return','info' => $info));
if(!$insert_res){
$data['type']     = 'error';
$data['info']   = '警告:用户支付成功,服务器流水记录失败';
$this->assign('data',$data);
$this->display('info');die;
}

//接口请求成功
if($_GET['trade_status'] == 'TRADE_FINISHED' || $_GET['trade_status'] == 'TRADE_SUCCESS') {

//交易成功
$data['type']     = 'success';
$data['info']   = '成功:交易成功,请返回';
}else {

//交易失败
$data['type']     = 'error';
$data['info']   = '失败:支付失败,请重试';
}
}else {
//接口请求失败
$data['type']     = 'error';
$data['info']   = '失败:服务器调用支付宝失败';
}
$this->assign('data',$data);
$this->display('info');
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: