PHP_支付宝境外支付接口

文档地址:https://global.alipay.com/service/app_cn/1

1.配置文件,本地生成公钥私钥对,把本地的公钥提交给支付宝,换取支付宝公钥,私钥保留本地

<?php
/* *
 * 配置文件
 * 版本:1.0
 * 日期:2016-06-06
 * 说明:
 * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
 
//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//合作身份者ID,签约账号,以2088开头由16位纯数字组成的字符串,查看地址:https://openhome.alipay.com/platform/keyManage.htm?keyType=partner
$alipay_config['partner']       = '20887215xxxxxxxx';

//商户的私钥,此处填写原始私钥去头去尾,RSA公私钥生成:https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.nBDxfy&treeId=58&articleId=103242&docType=1
$alipay_config['private_key']   = '-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCcstHVkCeNFDoEY/mArNkBiktYrlVYECjuugk5a01mCCY/Ts6S
gRWryoRiMUASBHgVmYAKm2sxu+0HoDhqH+/tcURo/86NgOBECC+Y0GyKX2AcFS1T
D89GzMAcnmygbpwTMQzTd3tQWy70hQ3PjOd2lhIxPTzUn1jbvSAIHTTu2QIDAQAB
AoGAK2iSHnJXsopW5B554L6BQx73bnKk68dWP4PDyGdEQq6hQcpoCUe/JB7u+3Cf
Sh540ar7QHT7hgSETieBWUzNnu9Y3pLkuP5J5/KY7FeoEJ1C7fjq+WQQ6cVmbX2y
vzJVjnekyGiU8zi/mx1K/oU+Ijc8jHRsetobhxdiP1X3RwECQQDIaB8+E/egbd9M
yN87HhNqHW4R2L7sUS2inbiYFYGccTsAeAX2WQ0feprAKde+jW4Hu/U5XTGLjTCJ
eanbk7thAkEAyCrCmpvq9fdRgWus1493LdbcmqzNkhSydswuEsYb+LG4r44wUVO7
IvXEJZ7Vm7h5XwvM+MNY0HHfP8H3p+weeQJBAKoBQfecYqUyb4oooM36noeXPadg
Ed5QowDfARfqro+yslWce5pWQr6geCRpmn4oZd2jwcwO1ZfHhxQoJEKD2SECQQCf
zhOjn8tMJ/F4Y+CQEEfT3vAsxL0yXTfFxGkcL/Hw8OJDtj85DqIe3RuF9XMQaYzs
pt0z1bG4aNEVc+QmuknxAkEAnZ6BKuIIXDYE2h6gO5pAykExovmW5wBjgmB6y7gg
LLJVuMctgLiJl6zxJ7qe7DgLboHYgJGRB20GhS2xb9n3Qw==
-----END RSA PRIVATE KEY-----';

//支付宝的公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm?keyType=partner
$alipay_config['alipay_public_key']= 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRAFljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQEB/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5KsiNG9zpgmLCUYuLkxpLQIDAQAB';

//异步通知接口
$alipay_config['service']= 'mobile.securitypay.pay';
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

//签名方式 不需修改
$alipay_config['sign_type']    = strtoupper('RSA');

//字符编码格式 目前支持 gbk 或 utf-8
$alipay_config['input_charset']= strtolower('utf-8');

//ca证书路径地址,用于curl中ssl校验
//请保证cacert.pem文件在当前文件夹目录中
$alipay_config['cacert']    = getcwd().'/cacert.pem';


//访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
$alipay_config['transport']    = 'http';
?>

2.拼接参数字段,调用签名方法进行签名,拼接完整支付链接接口

<?php
/*
 * 积分接口
*/

namespace Apis\Controller;

use Common\Controller\AppframeController;

class ZfbController extends AppframeController {

    protected $order_model;
    
    public function _initialize() {
        parent::_initialize();
        $this->order_model = D("Common/Order");
    }

    // 积分主页
    public function index() {
        $return = array();
        $oid = sp_checkparam("oid", true, 'int', "缺少订单号");
        $info = $this->order_model
        ->where("id='{$oid}'")
        ->find();
        
        if (!$info) {
            sp_error("获取失败");
        }
        $prolist = sp_projson($info['projson']);
        
        $array_query = array();
        $array_query['service'] = "\"mobile.securitypay.pay\"";
        $array_query['partner'] = "\"2088721528654455\"";
        $array_query['_input_charset'] = "\"utf-8\"";
        $array_query['notify_url'] = "\"http://".$_SERVER['HTTP_HOST']."/zfb/notify_url.php\"";
        $array_query['out_trade_no'] = "\"".$info['sn']."\"";
        $array_query['subject'] = "\"".$prolist[0]['product_name']."\"";
        $array_query['payment_type'] = "\"1\"";
        $array_query['seller_id'] = "\"careline_ting@hotmail.com\"";
        $array_query['total_fee'] = "\"".$info['total']."\"";
        $array_query['currency'] = "\"AUD\"";
        $array_query['body'] = "\"".$prolist[0]['product_name']."\"";
        $array_query['forex_biz'] = "\"FP\"";
        $array_query['it_b_pay'] = "\"30m\"";
        
        $url = "http://aus.palmtrends.com/zfb/signatures_url.php";
        $sign = sp_file_get_contents_safe($url,$array_query,'POST');
        sp_api($sign);
    }
}

3.支付链接拼接

<?php
/* *
 * 功能:支付宝移动支付服务端签名页面
 * 版本:1.0
 * 日期:2016-06-06
 * 说明:
 * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要编写。
 * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。

 *************************页面功能说明*************************
 * 本页面代码示例用于处理客户端使用http(s) post传输到此服务端的移动支付请求参数待签名字符串。
 * 本页面代码示例采用客户端创建订单待签名的请求字符串传输到服务端的这里进行签名操作并返回。
 */

require_once("alipay.config.php");
require_once("lib/alipay_notify.class.php");
require_once("lib/alipay_rsa.function.php");
require_once("lib/alipay_core.function.php");

//确认PID和接口名称是否匹配。
date_default_timezone_set("PRC");

if (str_replace('"','',$_POST['partner'])==$alipay_config['partner']&&str_replace('"','',$_POST['service'])==$alipay_config['service']) {

    //将post接收到的数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串。
        $data=createLinkstring($_POST);
        
        //打印待签名字符串。工程目录下的log文件夹中的log.txt。
    //logResult($data);
        //将待签名字符串使用私钥签名,且做urlencode. 注意:请求到支付宝只需要做一次urlencode.
    $rsa_sign=urlencode(rsaSign($data, $alipay_config['private_key']));
        
        //把签名得到的sign和签名类型sign_type拼接在待签名字符串后面。
    $data = $data.'&sign='.'"'.$rsa_sign.'"'.'&sign_type='.'"'.$alipay_config['sign_type'].'"';
        //返回给客户端,建议在客户端使用私钥对应的公钥做一次验签,保证不是他人传输。
        
        echo $data;
        //echo $rsa_sign;
}
else{
    echo "不匹配或为空!";
    logResult(createLinkstring($_POST));
}
?>

4.签名方法rsa

/**
 * RSA签名
 * @param $data 待签名数据
 * @param $private_key 商户私钥字符串
 * return 签名结果
 */
function rsaSign($data, $private_key) {
    //以下为了初始化私钥,保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
    //$private_key=str_replace("-----BEGIN RSA PRIVATE KEY-----","",$private_key);
    //$private_key=str_replace("-----END RSA PRIVATE KEY-----","",$private_key);
    //$private_key=str_replace("\n","",$private_key);
    //$private_key="-----BEGIN RSA PRIVATE KEY-----".PHP_EOL .wordwrap($private_key, 64, "\n", true). PHP_EOL."-----END RSA PRIVATE KEY-----";
    
    $res=openssl_get_privatekey($private_key);
    if($res)
    {
        openssl_sign($data, $sign,$res);
    }
    else {
        echo "您的私钥格式不正确!"."<br/>"."The format of your private_key is incorrect!";
        exit();
    }
    openssl_free_key($res);
    //base64编码
    $sign = base64_encode($sign);
    return $sign;
}

5.回调函数验证签名,处理数据

<?php

/* *
 * 功能:支付宝服务器异步通知页面
 * 版本:1.0
 * 日期:2016-06-06
 * 说明:
 * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。


 * ************************页面功能说明*************************
 * 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格。
 * 该页面不能在本机电脑测试,请到服务器上做测试。请确保外部可以访问该页面。
 * 该页面调试工具请使用写文本函数logResult,该函数已被默认关闭,见alipay_notify_class.php中的函数verifyNotify
 * 如果没有收到该页面返回的 success 信息,支付宝会在24小时内按一定的时间策略重发通知
 */

require_once("alipay.config.php");
require_once("lib/alipay_notify.class.php");
require_once("lib/alipay_rsa.function.php");
require_once("lib/alipay_core.function.php");


$mysql_server_name='localhost'; //改成自己的mysql数据库服务器
$mysql_username='root'; //改成自己的mysql数据库用户名
$mysql_password='Pa1mtrends'; //改成自己的mysql数据库密码
$mysql_database='daigou'; //
$conn=mysql_connect($mysql_server_name,$mysql_username,$mysql_password) or die("error connecting") ; //连接数据库
mysql_query("set names 'utf8'"); //数据库输出编码 应该与你的数据库编码保持一致.南昌网站建设公司百恒网络PHP工程师建议用UTF-8 国际标准编码.
mysql_select_db($mysql_database); //打开数据库

//$_POST['notify_type'] = "trade_status_sync";
//$_POST['trade_no'] = "2017082821001003060249667133";
//$_POST['total_fee'] = "0.01";
//$_POST['out_trade_no'] = "201708281352125846";
//$_POST['notify_time'] = "2017-08-28 13:52:38";
//$_POST['currency'] = "AUD";
//$_POST['trade_status'] = "TRADE_FINISHED";
//$_POST['sign_type'] = "RSA";
//$_POST['notify_id'] = "8d0b75dad481c9ca1d925d316ef433eggq";
//$_POST['sign'] = "dgjUACWxfC96+1ZbG8gBiP7LitEoP048lOhsfvyEsL4pQ0b90vr2q+SQ5Ggeq5jWngCOcfirOVcFwsCXc8Ey2b8k7LoL/4M403tbV4wulO1ROOIzfsA0ZU7MoAVoGkPiyofghSSAMDeNz+GXmLto4mCz8ahRre9Nh3gDmGfcayE=";

//计算得出通知验证结果
$alipayNotify = new AlipayNotify($alipay_config);
if ($alipayNotify->getResponse($_POST['notify_id'])) {//判断成功之后使用getResponse方法判断是否是支付宝发来的异步通知。
    
    
    if ($alipayNotify->getSignVeryfy($_POST, $_POST['sign'])) {//使用支付宝公钥验签
        //——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
        //获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表
        //商户订单号
        $out_trade_no = $_POST['out_trade_no'];

        //支付宝交易号
        $trade_no = $_POST['trade_no'];

        //交易状态
        $trade_status = $_POST['trade_status'];

        if ($_POST['trade_status'] == 'TRADE_FINISHED') {
            
            //判断该笔订单是否在商户网站中已经做过处理
            //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
            //如果有做过处理,不执行商户的业务程序
            //注意:
            //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
            //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
            $time = time();
            $sql = "update cmf_order set payway=1,zfb_trade_no='{$trade_no}',status=1,paytime='{$time}' where sn='{$out_trade_no}'";
            $res = mysql_query($sql,$conn);
            
            $has = "select id from cmf_order_zfb where out_trade_no='{$_POST['out_trade_no']}'";
            $r = mysql_query($has,$conn);
            $has_res = mysql_fetch_array($r);
            if (!$has_res) {
                //插入记录表
                $ins = array();
                $ins['notify_type'] = $_POST['notify_type'];
                $ins['trade_no'] = $_POST['trade_no'];
                $ins['total_fee'] = $_POST['total_fee'];
                $ins['out_trade_no'] = $_POST['out_trade_no'];
                $ins['currency'] = $_POST['currency'];
                $ins['sign_type'] = $_POST['sign_type'];
                $ins['addtime'] = time();
                $ins['notify_time'] = $_POST['notify_time'];
                $sql_ins = "insert into cmf_order_zfb (notify_type,trade_no,total_fee,out_trade_no,currency,sign_type,addtime,notify_time) values('{$ins['notify_type']}','{$ins['trade_no']}','{$ins['total_fee']}','{$ins['out_trade_no']}','{$ins['currency']}','{$ins['sign_type']}','{$ins['addtime']}','{$ins['notify_time']}')";
                mysql_query($sql_ins,$conn);
            }
        } else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
            //判断该笔订单是否在商户网站中已经做过处理
            //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
            //如果有做过处理,不执行商户的业务程序
            //注意:
            //付款完成后,支付宝系统发送该交易状态通知
            //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
            
            $time = time();
            $sql = "update cmf_order set payway=1,zfb_trade_no='{$trade_no}',status=1,paytime='{$time}' where sn='{$out_trade_no}'";
            $res = mysql_query($sql,$conn);
            
            $has = "select id from cmf_order_zfb where out_trade_no='{$_POST['out_trade_no']}'";
            $r = mysql_query($has,$conn);
            $has_res = mysql_fetch_array($r);
            if (!$has_res) {
                //插入记录表
                $ins = array();
                $ins['notify_type'] = $_POST['notify_type'];
                $ins['trade_no'] = $_POST['trade_no'];
                $ins['total_fee'] = $_POST['total_fee'];
                $ins['out_trade_no'] = $_POST['out_trade_no'];
                $ins['currency'] = $_POST['currency'];
                $ins['sign_type'] = $_POST['sign_type'];
                $ins['addtime'] = time();
                $ins['notify_time'] = $_POST['notify_time'];
                $sql_ins = "insert into cmf_order_zfb (notify_type,trade_no,total_fee,out_trade_no,currency,sign_type,addtime,notify_time) values('{$ins['notify_type']}','{$ins['trade_no']}','{$ins['total_fee']}','{$ins['out_trade_no']}','{$ins['currency']}','{$ins['sign_type']}','{$ins['addtime']}','{$ins['notify_time']}')";
                mysql_query($sql_ins,$conn);
            }
        }
        //——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
        echo "success";  //请不要修改或删除
    } else { //验证签名失败
        echo "sign fail";
    }
} else { //验证是否来自支付宝的通知失败
    echo "response fail";
}
?>

6.验签函数

/**
     * 获取返回时的签名验证结果
     * @param $para_temp 通知返回来的参数数组
     * @param $sign 返回的签名结果
     * @return 签名验证结果
     */
    function getSignVeryfy($para_temp, $sign) {
        //除去待签名参数数组中的空值和签名参数
        $para_filter = paraFilter($para_temp);

        //对待签名参数数组排序
        $para_sort = argSort($para_filter);

        //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
        $prestr = createLinkstring($para_sort);

        $isSgin = false;
        switch (strtoupper(trim($this->alipay_config['sign_type']))) {
            case "RSA" :
                $isSgin = rsaVerify($prestr, trim($this->alipay_config['alipay_public_key']), $sign);
                break;
            default :
                $isSgin = false;
        }
        return $isSgin;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容