数码控科技猎奇Iphone动漫星座游戏电竞lolcosplay王者荣耀攻略allcnewsBLOGNEWSBLOGASKBLOGBLOGZSK全部技术问答问答技术问答it问答代码软件新闻开发博客电脑/网络手机/数码笔记本电脑互联网操作系统软件硬件编程开发360产品资源分享电脑知识文档中心IT全部全部分类全部分类技术牛文全部分类教程最新网页制作cms教程平面设计媒体动画操作系统网站运营网络安全服务器教程数据库工具网络安全软件教学vbscript正则表达式javascript批处理更多»编程更新教程更新游戏更新allitnewsJava新闻网络医疗信息化安全创业站长电商科技访谈域名会议专栏创业动态融资创投创业学院 / 产品经理创业公司人物访谈营销开发数据库服务器系统虚拟化云计算嵌入式移动开发作业作业1常见软件all电脑网络手机数码生活游戏体育运动明星影音休闲爱好文化艺术社会民生教育科学医疗健康金融管理情感社交地区其他电脑互联网软件硬件编程开发360相关产品手机平板其他电子产品摄影器材360硬件通讯智能设备购物时尚生活常识美容塑身服装服饰出行旅游交通汽车购房置业家居装修美食烹饪单机电脑游戏网页游戏电视游戏桌游棋牌游戏手机游戏小游戏掌机游戏客户端游戏集体游戏其他游戏体育赛事篮球足球其他运动球类运动赛车健身运动运动用品影视娱乐人物音乐动漫摄影摄像收藏宠物幽默搞笑起名花鸟鱼虫茶艺彩票星座占卜书画美术舞蹈小说图书器乐声乐小品相声戏剧戏曲手工艺品历史话题时事政治就业职场军事国防节日风俗法律法规宗教礼仪礼节自然灾害360维权社会人物升学入学人文社科外语资格考试公务员留学出国家庭教育学习方法语文物理生物工程学农业数学化学健康知识心理健康孕育早教内科外科妇产科儿科皮肤科五官科男科整形中医药品传染科其他疾病医院两性肿瘤科创业投资企业管理财务税务银行股票金融理财基金债券保险贸易商务文书国民经济爱情婚姻家庭烦恼北京上海重庆天津黑龙江吉林辽宁河北内蒙古山西陕西宁夏甘肃青海新疆西藏四川贵州云南河南湖北湖南山东江苏浙江安徽江西福建广东广西海南香港澳门台湾海外地区

PHP 实现手机端APP支付宝支付功能

来源:脚本之家  责任编辑:小易  

最近应业务需求,做了支付宝支付和微信支付,今天分享一下手机端app支付宝支付对接流程,实际开发过程是前后端分离,前端调用后端API接口,实现功能返回数据,我所用的跨挤啊为TP5,大致可以分为四步:

       1.在蚂蚁金服开放平台创建应用,签约商户,生成应用公钥和私钥;

       2.配置统一下单支付参数;

       3.整合支付宝demo类文件;

       4.创建Alipay支付类,类内创建两个方法(alipay_app:统一下单方法和alipay_notify:支付成功异步回调方法);

       第一步主要是在蚂蚁金服开放平台登录你的支付宝账号,接入支付功能,个人就选个人,服务商就选服务商,需要填写一些材料,如手机号,邮箱等,完成后就可以创建应用啦,创建应用完成后需要进行签约,只有签约之后你应用里面开放的支付功能才会生效,签约也需要填一堆信息,签约需要审核,成功后你会拿到一个2088开头partner值,这个第三步配置参数的时候需要用到,之后还要为你的应用生成公钥和私钥,这点在开放平台开发文档中有详细描述,下载生成秘钥工具,选择对应的秘钥类型,秘钥和公钥一定要保存好,这里就不多做赘述啦,到此开放平台的准备工作就结束了。

       第二步就是整合支付宝demo文件了,我这里已经整合好了,直接把代码复制到两个文件中就可以了,一个为支付类,一个为通知类:

/*此为支付类*/
class AlipayApp{
 /**
  * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  * @param $para 需要拼接的数组
  * return 拼接完成以后的字符串
  */
 function createLinkstring($para,$showQuotes = false) {
  // $arg = "";
  // while (list ($key, $val) = each ($para)) {
  // $arg.=$key."=".$val."&";
  // }
  ////去掉最后一个&字符
  // $arg = substr($arg,0,count($arg)-2);
  ////如果存在转义字符,那么去掉转义
  // if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
  // return $arg;
  $arg = "";
  $quotes = '';
  if($showQuotes){
   $quotes = '"';
  }
  foreach ($para as $key => $val) {
   if($arg == ''){
    $arg = $key.'='.$quotes.$val.$quotes;
   }else{
    $arg = $arg.'&'.$key.'='.$quotes.$val.$quotes;
   }
  }
  if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
  return $arg;
 }
 /**
  * 对数组排序
  * @param $para 排序前的数组
  * return 排序后的数组
  */
 function argSort($para) {
  ksort($para);
  reset($para);
  return $para;
 }
 /**
  * 除去数组中的空值和签名参数
  * @param $para 签名参数组
  * return 去掉空值与签名参数后的新签名参数组
  */
 function paraFilter($para) {
  $para_filter = array();
  while (list ($key, $val) = each ($para)) {
   if($key == "sign" || $key == "sign_type" || $val == "")continue;
   else$para_filter[$key] = $para[$key];
  }
  return $para_filter;
 }
 function query_timestamp() {
  $url = $this->alipay_gateway_new."service=query_timestamp&partner=".trim(strtolower($this->alipay_config['partner']))."&_input_charset=".trim(strtolower($this->alipay_config['input_charset']));
  $encrypt_key = "";
  $doc = new DOMDocument();
  $doc->load($url);
  $itemEncrypt_key = $doc->getElementsByTagName( "encrypt_key" );
  $encrypt_key = $itemEncrypt_key->item(0)->nodeValue;
  return $encrypt_key;
 }
 /**
  * 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
  * 注意:服务器需要开通fopen配置
  * @param $word 要写入日志里的文本内容 默认值:空值
  */
 function logResult($word='') {
  date_default_timezone_set("PRC");
  $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);
 }
 /**
  * 远程获取数据,POST模式
  * 注意:
  * 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
  * 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
  * @param $url 指定URL完整路径地址
  * @param $cacert_url 指定当前工作目录绝对路径
  * @param $para 请求的数据
  * @param $input_charset 编码格式。默认值:空值
  * return 远程输出的数据
  */
 function getHttpResponsePOST($url, $cacert_url, $para, $input_charset = '') {
  if (trim($input_charset) != '') {
   $url = $url."_input_charset=".$input_charset;
  }
  $curl = curl_init($url);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
  curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
  curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
  curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
  curl_setopt($curl,CURLOPT_POST,true); // post传输数据
  curl_setopt($curl,CURLOPT_POSTFIELDS,$para);// post传输数据
  $responseText = curl_exec($curl);
  //var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
  curl_close($curl);
  return $responseText;
 }
 /**
  * 远程获取数据,GET模式
  * 注意:
  * 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
  * 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
  * @param $url 指定URL完整路径地址
  * @param $cacert_url 指定当前工作目录绝对路径
  * return 远程输出的数据
  */
 function getHttpResponseGET($url,$cacert_url) {
  $curl = curl_init($url);
  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,$cacert_url);//证书地址
  $responseText = curl_exec($curl);
  //var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
  curl_close($curl);
  return $responseText;
 }
 /**
  * 实现多种字符编码方式
  * @param $input 需要编码的字符串
  * @param $_output_charset 输出的编码格式
  * @param $_input_charset 输入的编码格式
  * return 编码后的字符串
  */
 function charsetEncode($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;
 }
 /**
  * 实现多种字符解码方式
  * @param $input 需要解码的字符串
  * @param $_output_charset 输出的解码格式
  * @param $_input_charset 输入的解码格式
  * return 解码后的字符串
  */
 function charsetDecode($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;
 }
 /**
  * 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;
 }
 /**
  * RSA验签
  * @param $data 待签名数据
  * @param $alipay_public_key 支付宝的公钥字符串
  * @param $sign 要校对的的签名结果
  * return 验证结果
  */
 function rsaVerify($data, $alipay_public_key, $sign) {
  //以下为了初始化私钥,保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
  $alipay_public_key=str_replace("-----BEGIN PUBLIC KEY-----","",$alipay_public_key);
  $alipay_public_key=str_replace("-----END PUBLIC KEY-----","",$alipay_public_key);
  $alipay_public_key=str_replace("\n","",$alipay_public_key);
  $alipay_public_key='-----BEGIN PUBLIC KEY-----'.PHP_EOL.wordwrap($alipay_public_key, 64, "\n", true) .PHP_EOL.'-----END PUBLIC KEY-----';
  $res=openssl_get_publickey($alipay_public_key);
  if($res)
  {
   $result = (bool)openssl_verify($data, base64_decode($sign), $res);
  }
  else {
   echo "您的支付宝公钥格式不正确!"."<br/>"."The format of your alipay_public_key is incorrect!";
   exit();
  }
  openssl_free_key($res);
  return $result;
 }
}
  
/* *
 * 类名:AlipayNotify
 * 功能:支付宝通知处理类
 * 详细:处理支付宝各接口通知返回
 * 版本:1.0
 * 日期:2016-06-06
 * 说明:
 * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考
 *************************注意*************************
 * 调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常
 */
class AlipayNotify {
 /**
  * HTTPS形式消息验证地址
  */
 var $https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&';
 /**
  * HTTP形式消息验证地址
  */
 var $http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?';
 var $alipay_config;
 function __construct($alipay_config){
  $this->alipay_config = $alipay_config;
 }
 function AlipayNotify($alipay_config) {
  $this->__construct($alipay_config);
 }
 /**
  * 获取返回时的签名验证结果
  * @param $para_temp 通知返回来的参数数组
  * @param $sign 返回的签名结果
  * @return 签名验证结果
  */
 function getSignVeryfy($para_temp, $sign) {
  $alipayapp = new \Alipayapp();
  //除去待签名参数数组中的空值和签名参数
  $para_filter = $alipayapp->paraFilter($para_temp);
  //对待签名参数数组排序
  $para_sort = $alipayapp->argSort($para_filter);
  //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  $prestr = $alipayapp->createLinkstring($para_sort);
  $isSgin = false;
  switch (strtoupper(trim($this->alipay_config['sign_type']))) {
   case "RSA" :
    $isSgin = $alipayapp->rsaVerify($prestr, trim($this->alipay_config['alipay_public_key']), $sign);
    break;
   default :
    $isSgin = false;
  }
  return $isSgin;
 }
 /**
  * 获取远程服务器ATN结果,验证返回URL
  * @param $notify_id 通知校验ID
  * @return 服务器ATN结果
  * 验证结果集:
  * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
  * true 返回正确信息
  * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
  */
 function getResponse($notify_id) {
  $alipayapp = new \Alipayapp();
  $transport = strtolower(trim($this->alipay_config['transport']));
  $partner = trim($this->alipay_config['partner']);
  $veryfy_url = '';
  if($transport == 'https') {
   $veryfy_url = $this->https_verify_url;
  }
  else {
   $veryfy_url = $this->http_verify_url;
  }
  $veryfy_url = $veryfy_url."partner=" . $partner . "¬ify_id=" . $notify_id;
  $responseTxt = $alipayapp->getHttpResponseGET($veryfy_url, $this->alipay_config['cacert']);
  return $responseTxt;
 }
}

       第三步配置参数:

//配置参数
public $alipay_config = array(
 //2088开头
 'partner' => '',
 //商户的私钥,此处填写原始私钥去头去尾,RSA公私钥生成:https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.nBDxfy&treeId=58&articleId=103242&docType=1
 'private_key' => '',
 //支付宝的公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm?keyType=partner
 'alipay_public_key' => '',
 //异步通知接口
 'service'=> 'mobile.securitypay.pay',
 //字符编码格式 目前支持 gbk 或 utf-8
 'input_charset' => 'utf-8',
 //签名方式 不需修改
 'sign_type' => 'RSA',
 //ca证书路径地址,用于curl中ssl校验
 //请保证cacert.pem文件在当前文件夹目录中
 'cacert' => '/cacert.pem',
 //访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http
 'transport' => 'http',
);

创建$alipa_config属性,可以放到你的配置文件中方便引入,也可以直接放到Alipay类中,里面只要前三项需要自己填写,其余不变就好啦。

        第四步就是创建Alipay类,类内定义两个方法,一个是alipay_app(统一下单),alipay_app中的一些参数需要自己补全,参数介绍点我,另一个是alipay_notify(支付成功后的异步回调)并引入第二步创建的两个类文件,本人开发用的是TP5框架,支付类放在第三方类库vendor目录下面,可以直接在控制器中用vendor()函数引入文件,例:vendor('Alipayapp.lib.alipay_notify');

//调用统一下单接口生成预支付订单并把数据返回给APP
public function alipay_app(Request $request)
{
 vendor('Alipayapp.lib.AlipayApp');
 $param = $request->param();
 $tade_no = $param['orderCode'];//订单号 调用统一下单接口需要提供一个订单号
 $order = new Order(); //实例化订单
 $ret = $order->getOrderN2($tade_no); //查询订单信息 此处为我自己的查询订单信息方法,可以替换为你自己的
 $strOrg['partner']=$this->alipay_config['partner']; // 配置的partner
 $strOrg['seller_id']=$this->alipay_config['partner']; // 此处和partner值一样即可
 $strOrg['out_trade_no']=$tade_no; // 订单号
 $strOrg['subject']=""; // 商品的标题
 $strOrg['body']="";//商品名
 $strOrg['total_fee']=$ret['money'];// 金额
 $strOrg['notify_url']="";//回调地址,填写回调方法的绝对路径
 $strOrg['service']=$this->alipay_config['service'];
 $strOrg['payment_type']="1";
 $strOrg['_input_charset']="utf-8";
 $strOrg['it_b_pay']="30m";
 $alipay = new \Alipayapp();
 //将post接收到的数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串。
 $data=$alipay->createLinkstring($strOrg,true);//,true
 //将待签名字符串使用私钥签名,且做urlencode. 注意:请求到支付宝只需要做一次urlencode.
 $rsa_sign=urlencode($alipay->rsaSign($data, $this->alipay_config['private_key']));
 //把签名得到的sign和签名类型sign_type拼接在待签名字符串后面。
 $data = $data.'&sign='.'"'.$rsa_sign.'"'.'&sign_type='.'"'.$this->alipay_config['sign_type'].'"';
 //返回给客户端,建议在客户端使用私钥对应的公钥做一次验签,保证不是他人传输。
 $datajson['mdata']=$data;
 echo json_encode($datajson);
}

//支付成功后的回调方法
public function alipay_notify()
{
 vendor('Alipayapp.lib.alipay_notify');//引入支付通知类文件
 $alipayNotify = new \AlipayNotify($this->alipay_config);
 $order = new Order(); //实例化订单
 if($alipayNotify->getResponse($_POST['notify_id'])) //判断成功之后使用getResponse方法判断是否是支付宝发来的异步通知。
 {
  if($alipayNotify->getSignVeryfy($_POST, $_POST['sign'])) {//使用支付宝公钥验签
   //获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表
   //商户订单号
   $out_trade_no = $_POST['out_trade_no'];
   $ret = $order->getOrderN2($out_trade_no); //查询订单信息
   $total_amount=$ret['money']; //订单金额
   $total_fee = $_POST['total_fee']; //支付宝返回金额
   if($_POST['trade_status'] == 'TRADE_FINISHED') {
    //判断该笔订单是否在商户网站中已经做过处理
    //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
    //如果有做过处理,不执行商户的业务程序
    //注意:
    //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
    //请务必判断请求时的out_trade_no、total_fee、seller_id与通知时获取的out_trade_no、total_fee、seller_id为一致的
    if($total_amount==$total_fee){
     //这里进行数据库操作,比如修改订单状态等
    }
   }else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
    //判断该笔订单是否在商户网站中已经做过处理,如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程
    //如果有做过处理,不执行商户的业务程序
    //注意:
    //付款完成后,支付宝系统发送该交易状态通知
    //请务必判断请求时的out_trade_no、total_fee、seller_id与通知时获取的out_trade_no、total_fee、seller_id为一致的
    if($total_amount==$total_fee){
     //这里进行数据库操作,比如修改订单状态等
    }
   }
   echo "success"; //请不要修改或删除
  }else{ //验证签名失败
   echo "sign fail";
  }
 }else{ //验证是否来自支付宝的通知失败
  echo "response fail";
 }
}

       上述getOrderN2方法是我查询订单信息用的,需要替换成你自己的查询订单方法,以上四步完成正常的话支付宝支付功能就可以实现了,需要注意的是支付功能简单的在本地测试是不可以的,需要在服务器上测试,也有说用花生壳什么的...这个我没有研究,如果没有成功查看报错提示,在对接支付时有很多坑,遇到报错不要急,逐步解决一定可以实现支付功能的,如果自己实在解决不了的可以找支付宝技术人员,如果你想查看支付宝异步通知时的返回值,可以用 file_put_contents() 函数打印返回的参数,会在你指定的路径生成一个文件,里面就是返回的值啦。

总结

以上所述是小编给大家介绍的PHP 实现手机端APP支付宝支付功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

您可能感兴趣的文章:


  • 本文相关:
  • thinkphp框架对接支付宝即时到账接口回调操作示例
  • php支付宝在线支付接口开发教程
  • php 接入支付宝即时到账功能
  • 支付宝服务窗api接口开发php版本
  • 纯php代码实现支付宝批量付款
  • php支付宝手机网页支付类实例
  • php支付宝接口用法分析
  • php进行支付宝开发中return_url和notify_url的区别分析
  • thinkphp实现支付宝接口功能实例
  • 支付宝 接口开发帮助(asp,php,asp.net,jsp)
  • php spl标准库之接口(interface)详解
  • php 的opcache加速的使用方法
  • 用php写的mysql数据库用户认证系统代码
  • php 获取远程网页内容的代码(fopen,curl已测)
  • thinkphp5.0框架引入traits功能实例分析
  • phpmailer使用qq邮箱实现邮件发送功能
  • 基于swoole实现多人聊天室
  • phpmyadmin下载、安装、配置教程
  • thinkphp简单使用memcache缓存的方法
  • php操作memcache缓存方法分享
  • 免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved