搜索
首页后端开发php教程如何利用PHP实现 APP端微信支付功能
如何利用PHP实现 APP端微信支付功能Jun 22, 2018 am 09:30 AM
php微信支付

这篇文章主要介绍了PHP实现 APP端微信支付功能,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

前面已经写了手机APP支付宝支付,今天再把手机APP微信支付补上,前期的准备工作在这里就不多说了,可以参考微信支付开发文档,一定要仔细阅读开发文档,可以让你少踩点坑;准备工作完成后就是配置参数,调用统一下单接口,支付后异步回调三部曲啦;

1.我封装好的一个支付类文件,多余的东西都去除掉了,并且把配置参数放到了这个支付类中,只需要修改Weixinpayandroid方法内的几个参数就可以直接复制使用:

class Wxpayandroid
{
 //参数配置
 public $config = array(
    'appid' => "", /*微信开放平台上的应用id*/
    'mch_id' => "", /*微信申请成功之后邮件中的商户id*/
    'api_key' => "", /*在微信商户平台上自己设定的api密钥 32位*/
   );
 //服务器异步通知页面路径(必填)
 public $notify_url = '';
 //商户订单号(必填,商户网站订单系统中唯一订单号)
 public $out_trade_no = '';
 //商品描述(必填,不填则为商品名称)
 public $body = '';
 //付款金额(必填)
 public $total_fee = 0;
 //自定义超时(选填,支持dhmc)
 public $time_expire = '';
 private $WxPayHelper;
 public function Weixinpayandroid($total_fee,$tade_no)
 {
  $this->total_fee = intval($total_fee * 100);//订单的金额 1元
  $this->out_trade_no = $tade_no;// date('YmdHis') . substr(time(), - 5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));//订单号
  $this->body = 'wxpay';//支付描述信息
  $this->time_expire = date('YmdHis', time() + 86400);//订单支付的过期时间(eg:一天过期)
  $this->notify_url = "http://www.ceshi.com/notifyandroid";//异步通知URL(更改支付状态)
  //数据以JSON的形式返回给APP
  $app_response = $this->doPay(); 
  if (isset($app_response['return_code']) && $app_response['return_code'] == 'FAIL') {
   $errorCode = 100;
   $errorMsg = $app_response['return_msg'];
   $this->echoResult($errorCode, $errorMsg);
  } else {
   $errorCode = 0;
   $errorMsg = 'success';
   $responseData = array(
    'notify_url' => $this->notify_url,
    'app_response' => $app_response,
   );
   $this->echoResult($errorCode, $errorMsg, $responseData);
  }
 }
 //接口输出
 function echoResult($errorCode = 0, $errorMsg = 'success', $responseData = array())
 {
  $arr = array(
   'errorCode' => $errorCode,
   'errorMsg' => $errorMsg,
   'responseData' => $responseData,
  );
   exit(json_encode($arr));  //exit可以正常发送给APP json数据
  // return json_encode($arr); //在TP5中return这个json数据,APP接收到的是null,无法正常吊起微信支付
 }
 function getVerifySign($data, $key)
 {
  $String = $this->formatParameters($data, false);
  //签名步骤二:在string后加入KEY
  $String = $String . "&key=" . $key;
  //签名步骤三:MD5加密
  $String = md5($String);
  //签名步骤四:所有字符转为大写
  $result = strtoupper($String);
  return $result;
 }
 function formatParameters($paraMap, $urlencode)
 {
  $buff = "";
  ksort($paraMap);
  foreach ($paraMap as $k => $v) {
   if($k=="sign"){
    continue;
   }
   if ($urlencode) {
    $v = urlencode($v);
   }
   $buff .= $k . "=" . $v . "&";
  }
  $reqPar;
  if (strlen($buff) > 0) {
   $reqPar = substr($buff, 0, strlen($buff) - 1);
  }
  return $reqPar;
 }
 /**
  * 得到签名
  * @param object $obj
  * @param string $api_key
  * @return string
  */
 function getSign($obj, $api_key)
 {
  foreach ($obj as $k => $v)
  {
   $Parameters[strtolower($k)] = $v;
  }
  //签名步骤一:按字典序排序参数
  ksort($Parameters);
  $String = $this->formatBizQueryParaMap($Parameters, false);
  //签名步骤二:在string后加入KEY
  $String = $String."&key=".$api_key;
  //签名步骤三:MD5加密
  $result = strtoupper(md5($String));
  return $result;
 }
 /**
  * 获取指定长度的随机字符串
  * @param int $length
  * @return Ambigous <NULL, string>
  */
 function getRandChar($length){
  $str = null;
  $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
  $max = strlen($strPol)-1;
  for($i=0;$i<$length;$i++){
   $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
  }
  return $str;
 }
 /**
  * 数组转xml
  * @param array $arr
  * @return string
  */
 function arrayToXml($arr)
 {
  $xml = "<xml>";
  foreach ($arr as $key=>$val)
  {
    if (is_numeric($val))
    {
    $xml.="<".$key.">".$val."</".$key.">";
    }
    else
    $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; 
  }
  $xml.="</xml>";
  return $xml;
 }
 /**
  * 以post方式提交xml到对应的接口url
  *
  * @param string $xml 需要post的xml数据
  * @param string $url url
  * @param bool $useCert 是否需要证书,默认不需要
  * @param int $second url执行超时时间,默认30s
  * @throws WxPayException
  */
 function postXmlCurl($xml, $url, $second=30, $useCert=false, $sslcert_path=&#39;&#39;, $sslkey_path=&#39;&#39;)
 {
  $ch = curl_init();
  //设置超时
  curl_setopt($ch, CURLOPT_TIMEOUT, $second);
  curl_setopt($ch,CURLOPT_URL, $url);
  //设置header
  curl_setopt($ch, CURLOPT_HEADER, FALSE);
  //要求结果为字符串且输出到屏幕上
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
  curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
  if($useCert == true){
   curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
   curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
   //设置证书
   //使用证书:cert 与 key 分别属于两个.pem文件
   curl_setopt($ch,CURLOPT_SSLCERTTYPE,&#39;PEM&#39;);
   curl_setopt($ch,CURLOPT_SSLCERT, $sslcert_path);
   curl_setopt($ch,CURLOPT_SSLKEYTYPE,&#39;PEM&#39;);
   curl_setopt($ch,CURLOPT_SSLKEY, $sslkey_path);
  }
  //post提交方式
  curl_setopt($ch, CURLOPT_POST, TRUE);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
  //运行curl
  $data = curl_exec($ch);
  //返回结果
  if($data){
   curl_close($ch);
   return $data;
  } else {
   $error = curl_errno($ch);
   curl_close($ch);
   return false;
  }
 }
 /**
  * 获取当前服务器的IP
  * @return Ambigous <string, unknown>
  */
 function get_client_ip()
 {
  if (isset($_SERVER[&#39;REMOTE_ADDR&#39;])) {
   $cip = $_SERVER[&#39;REMOTE_ADDR&#39;];
  } elseif (getenv("REMOTE_ADDR")) {
   $cip = getenv("REMOTE_ADDR");
  } elseif (getenv("HTTP_CLIENT_IP")) {
   $cip = getenv("HTTP_CLIENT_IP");
  } else {
   $cip = "127.0.0.1";
  }
  return $cip;
 }
 /**
  * 将数组转成uri字符串
  * @param array $paraMap
  * @param bool $urlencode
  * @return string
  */
 function formatBizQueryParaMap($paraMap, $urlencode)
 {
  $buff = "";
  ksort($paraMap);
  foreach ($paraMap as $k => $v)
  {
   if($urlencode)
   {
    $v = urlencode($v);
   }
   $buff .= strtolower($k) . "=" . $v . "&";
  }
  $reqPar;
  if (strlen($buff) > 0)
  {
   $reqPar = substr($buff, 0, strlen($buff)-1);
  }
  return $reqPar;
 }
 /**
  * XML转数组
  * @param unknown $xml
  * @return mixed
  */
 function xmlToArray($xml)
 {
  //将XML转为array
  $array_data = json_decode(json_encode(simplexml_load_string($xml, &#39;SimpleXMLElement&#39;, LIBXML_NOCDATA)), true);
  return $array_data;
 }
 public function chkParam()
 {
  //用户网站订单号
  if (empty($this->out_trade_no)) {
   die(&#39;out_trade_no error&#39;);
  } 
  //商品描述
  if (empty($this->body)) {
   die(&#39;body error&#39;);
  }
  if (empty($this->time_expire)){
   die(&#39;time_expire error&#39;);
  }
  //检测支付金额
  if (empty($this->total_fee) || !is_numeric($this->total_fee)) {
   die(&#39;total_fee error&#39;);
  }
  //异步通知URL
  if (empty($this->notify_url)) {
   die(&#39;notify_url error&#39;);
  }
  if (!preg_match("#^http:\/\/#i", $this->notify_url)) {
   $this->notify_url = "http://" . $_SERVER[&#39;HTTP_HOST&#39;] . $this->notify_url;
  }
  return true;
 }
 /**
  * 生成支付(返回给APP)
  * @return boolean|mixed
  */
 public function doPay() {
  //检测构造参数
  $this->chkParam();
  return $this->createAppPara();
 }
 /**
  * APP统一下单
  */
 private function createAppPara()
 {
  $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
  $data["appid"]  = $this->config[&#39;appid&#39;];//微信开放平台审核通过的应用APPID
  $data["body"]   = $this->body;//商品或支付单简要描述
  $data["mch_id"]  = $this->config[&#39;mch_id&#39;];//商户号
  $data["nonce_str"] = $this->getRandChar(32);//随机字符串
  $data["notify_url"] = $this->notify_url;//通知地址
  $data["out_trade_no"] = $this->out_trade_no;//商户订单号
  $data["spbill_create_ip"] = $this->get_client_ip();//终端IP
  $data["total_fee"]  = $this->total_fee;//总金额
  $data["time_expire"]  = $this->time_expire;//交易结束时间
  $data["trade_type"]  = "APP";//交易类型
  $data["sign"]    = $this->getSign($data, $this->config[&#39;api_key&#39;]);//签名
  $xml  = $this->arrayToXml($data);
  $response = $this->postXmlCurl($xml, $url);
  //将微信返回的结果xml转成数组
  $responseArr = $this->xmlToArray($response);
  if(isset($responseArr["return_code"]) && $responseArr["return_code"]==&#39;SUCCESS&#39;){
   return $this->getOrder($responseArr[&#39;prepay_id&#39;]);
  }
  return $responseArr;
 }
 /**
  * 执行第二次签名,才能返回给客户端使用
  * @param int $prepayId:预支付交易会话标识
  * @return array
  */
 public function getOrder($prepayId)
 {
  $data["appid"]  = $this->config[&#39;appid&#39;];
  $data["noncestr"] = $this->getRandChar(32);
  $data["package"] = "Sign=WXPay";
  $data["partnerid"] = $this->config[&#39;mch_id&#39;];
  $data["prepayid"] = $prepayId;
  $data["timestamp"] = time();
  $data["sign"]  = $this->getSign($data, $this->config[&#39;api_key&#39;]);
  $data["packagestr"] = "Sign=WXPay";
  return $data;
 }
 /**
  * 异步通知信息验证
  * @return boolean|mixed
  */
 public function verifyNotify()
 {
  $xml = isset($GLOBALS[&#39;HTTP_RAW_POST_DATA&#39;]) ? $GLOBALS[&#39;HTTP_RAW_POST_DATA&#39;] : &#39;&#39;; 
  if(!$xml){
   return false;
  }
  $wx_back = $this->xmlToArray($xml);
  if(empty($wx_back)){
   return false;
  }
  $checkSign = $this->getVerifySign($wx_back, $this->config[&#39;api_key&#39;]); 
  if($checkSign=$wx_back[&#39;sign&#39;]){
   return $wx_back;
  }else{
   return false;
  } 
 }
}

2.创建控制器定义统一下单接口和支付后的异步回调接口:

//异步通知接口
 public function notifyandroid()
 {
  $wxpayandroid = new \Wxpayandroid;  //实例化微信支付类
  $verify_result = $wxpayandroid->verifyNotify();
  if ($verify_result[&#39;return_code&#39;]==&#39;SUCCESS&#39; && $verify_result[&#39;result_code&#39;]==&#39;SUCCESS&#39;) {
    //商户订单号
    $out_trade_no = $verify_result[&#39;out_trade_no&#39;];
    //交易号
    $trade_no  = $verify_result[&#39;transaction_id&#39;];
    //交易状态
    $trade_status = $verify_result[&#39;result_code&#39;];
    //支付金额
    $total_fee = $verify_result[&#39;total_fee&#39;]/100;
    //支付过期时间
    $pay_date  = $verify_result[&#39;time_end&#39;];
    $order = new Order();
    $ret = $order->getOrderN2($out_trade_no); //获取订单信息
    $total_amount=$ret[&#39;money&#39;];
    if ($total_amount==$total_fee) {
     // 验证成功 修改数据库的订单状态等 $result[&#39;out_trade_no&#39;]为订单号
     //此处写自己的逻辑代码
    }
   exit(&#39;<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>&#39;);
  }else{
   exit(&#39;<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>&#39;);
  }
 }
 
 //调用统一下单接口生成预支付订单并把数据返回给APP
 public function wxpayandroid(Request $request)
 {
  $param = $request->param(); //接收值
 
  $tade_no = $param[&#39;orderCode&#39;];
  $order = new Order(); //实例化订单
  $ret = $order->getOrderN2($tade_no); //查询订单信息
  $total_fee = $ret[&#39;money&#39;]; //订单总金额
  
  $wxpayandroid = new \Wxpayandroid;  //实例化微信支付类
  $res = $wxpayandroid->Weixinpayandroid($total_fee,$tade_no); //调用weixinpay方法
  
 }

封装一个支付类文件,并把配置参数放到支付类内,再定义控制器创建两个方法,这样两步就可以把手机APP微信支付搞定啦。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

php如何实现微信企业号支付个人

PHP实现微信公众平台企业号验证接口

以上是如何利用PHP实现 APP端微信支付功能的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
php怎么把负数转为正整数php怎么把负数转为正整数Apr 19, 2022 pm 08:59 PM

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

php怎么实现几秒后执行一个函数php怎么实现几秒后执行一个函数Apr 24, 2022 pm 01:12 PM

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php怎么除以100保留两位小数php怎么除以100保留两位小数Apr 22, 2022 pm 06:23 PM

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

php怎么根据年月日判断是一年的第几天php怎么根据年月日判断是一年的第几天Apr 22, 2022 pm 05:02 PM

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php怎么替换nbsp空格符php怎么替换nbsp空格符Apr 24, 2022 pm 02:55 PM

方法:1、用“str_replace("&nbsp;","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\&nbsp\;||\xc2\xa0)/","其他字符",$str)”语句。

php怎么判断有没有小数点php怎么判断有没有小数点Apr 20, 2022 pm 08:12 PM

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

php怎么设置implode没有分隔符php怎么设置implode没有分隔符Apr 18, 2022 pm 05:39 PM

在PHP中,可以利用implode()函数的第一个参数来设置没有分隔符,该函数的第一个参数用于规定数组元素之间放置的内容,默认是空字符串,也可将第一个参数设置为空,语法为“implode(数组)”或者“implode("",数组)”。

php字符串有没有下标php字符串有没有下标Apr 24, 2022 am 11:49 AM

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!