php实现微信支付之企业付款


Posted in PHP onMay 30, 2018

网上的很多PHP微信支付接入教程都颇为复杂,且需要配置和引入较多的文件,本人通过整理后给出一个单文件版的,希望可以给各位想接入微信支付的带来些许帮助和借鉴意义。

直接运行该文件即可给指定的微信用户转账。

需要注意的事项:

1.微信企业付款到零钱要求必传证书,需要到这里账户中心->账户设置->API安全->下载证书,然后修改代码中的证书路径 
2.该文件需放到支付授权目录下,可以在微信支付商户平台->产品中心->开发配置中设置。
3.如提示签名错误可以通过微信支付签名验证工具进行验证:微信公众平台支付接口调试工具
4.错误码参照:参照地址

代码如下:

<?php
/**
 * 关于微信企业付款的说明
 * 1.微信企业付款要求必传证书,需要到https://pay.weixin.qq.com 账户中心->账户设置->API安全->下载证书,证书路径在第207行和210行修改
 * 2.错误码参照 :https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
 */
header('Content-type:text/html; Charset=utf-8');
$mchid = 'xxxxx';  //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
$appid = 'xxxxx'; //微信支付申请对应的公众号的APPID
$appKey = 'xxxxx'; //微信支付申请对应的公众号的APP Key
$apiKey = 'xxxxx'; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥

//①、获取当前访问页面的用户openid(如果给指定用户转账,则直接填写指定用户的openid)
$wxPay = new WxpayService($mchid,$appid,$appKey,$apiKey);
$openId = $wxPay->GetOpenid(); //获取openid
if(!$openId) exit('获取openid失败');
//②、付款
$outTradeNo = uniqid(); //订单号
$payAmount = 1;  //转账金额,单位:元。转账最小金额为1元
$trueName = '张三';  //收款人真实姓名
$result = $wxPay->createJsBizPackage($openId,$payAmount,$outTradeNo,$trueName);
echo 'success';
class WxpayService
{
 protected $mchid;
 protected $appid;
 protected $appKey;
 protected $apiKey;
 public $data = null;

 public function __construct($mchid, $appid, $appKey,$key)
 {
 $this->mchid = $mchid;
 $this->appid = $appid;
 $this->appKey = $appKey;
 $this->apiKey = $key;
 }

 /**
 * 通过跳转获取用户的openid,跳转流程如下:
 * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
 * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
 * @return 用户的openid
 */
 public function GetOpenid()
 {
 //通过code获得openid
 if (!isset($_GET['code'])){
  //触发微信返回code码
  $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
  $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
  $url = $this->__CreateOauthUrlForCode($baseUrl);
  Header("Location: $url");
  exit();
 } else {
  //获取code码,以获取openid
  $code = $_GET['code'];
  $openid = $this->getOpenidFromMp($code);
  return $openid;
 }
 }

 /**
 * 通过code从工作平台获取openid机器access_token
 * @param string $code 微信跳转回来带上的code
 * @return openid
 */
 public function GetOpenidFromMp($code)
 {
 $url = $this->__CreateOauthUrlForOpenid($code);
 $res = self::curlGet($url);
 //取出openid
 $data = json_decode($res,true);
 $this->data = $data;
 $openid = $data['openid'];
 return $openid;
 }

 /**
 * 构造获取open和access_toke的url地址
 * @param string $code,微信跳转带回的code
 * @return 请求的url
 */
 private function __CreateOauthUrlForOpenid($code)
 {
 $urlObj["appid"] = $this->appid;
 $urlObj["secret"] = $this->appKey;
 $urlObj["code"] = $code;
 $urlObj["grant_type"] = "authorization_code";
 $bizString = $this->ToUrlParams($urlObj);
 return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
 }

 /**
 * 构造获取code的url连接
 * @param string $redirectUrl 微信服务器回跳的url,需要url编码
 * @return 返回构造好的url
 */
 private function __CreateOauthUrlForCode($redirectUrl)
 {
 $urlObj["appid"] = $this->appid;
 $urlObj["redirect_uri"] = "$redirectUrl";
 $urlObj["response_type"] = "code";
 $urlObj["scope"] = "snsapi_base";
 $urlObj["state"] = "STATE"."#wechat_redirect";
 $bizString = $this->ToUrlParams($urlObj);
 return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
 }

 /**
 * 拼接签名字符串
 * @param array $urlObj
 * @return 返回已经拼接好的字符串
 */
 private function ToUrlParams($urlObj)
 {
 $buff = "";
 foreach ($urlObj as $k => $v)
 {
  if($k != "sign") $buff .= $k . "=" . $v . "&";
 }
 $buff = trim($buff, "&");
 return $buff;
 }

 /**
 * 企业付款
 * @param string $openid 调用【网页授权获取用户信息】接口获取到用户在该公众号下的Openid
 * @param float $totalFee 收款总费用 单位元
 * @param string $outTradeNo 唯一的订单号
 * @param string $orderName 订单名称
 * @param string $notifyUrl 支付结果通知url 不要有问号
 * @param string $timestamp 支付时间
 * @return string
 */
 public function createJsBizPackage($openid, $totalFee, $outTradeNo,$trueName)
 {
 $config = array(
  'mch_id' => $this->mchid,
  'appid' => $this->appid,
  'key' => $this->apiKey,
 );
 $unified = array(
  'mch_appid' => $config['appid'],
  'mchid' => $config['mch_id'],
  'nonce_str' => self::createNonceStr(),
  'openid' => $openid,
  'check_name'=>'FORCE_CHECK', //校验用户姓名选项。NO_CHECK:不校验真实姓名,FORCE_CHECK:强校验真实姓名
  're_user_name'=>$trueName,   //收款用户真实姓名(不支持给非实名用户打款)
  'partner_trade_no' => $outTradeNo,
  'spbill_create_ip' => '127.0.0.1',
  'amount' => intval($totalFee * 100), //单位 转为分
  'desc'=>'付款',  //企业付款操作说明信息
 );
 $unified['sign'] = self::getSign($unified, $config['key']);
 $responseXml = $this->curlPost('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', self::arrayToXml($unified));
 $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
 if ($unifiedOrder === false) {
  die('parse xml error');
 }
 if ($unifiedOrder->return_code != 'SUCCESS') {
  die($unifiedOrder->return_msg);
 }
 if ($unifiedOrder->result_code != 'SUCCESS') {
  die($unifiedOrder->err_code);
 }
 return true;
 }

 public static function curlGet($url = '', $options = array())
 {
 $ch = curl_init($url);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 curl_setopt($ch, CURLOPT_TIMEOUT, 30);
 if (!empty($options)) {
  curl_setopt_array($ch, $options);
 }
 //https请求 不验证证书和host
 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
 $data = curl_exec($ch);
 curl_close($ch);
 return $data;
 }

 public function curlPost($url = '', $postData = '', $options = array())
 {
 if (is_array($postData)) {
  $postData = http_build_query($postData);
 }
 $ch = curl_init();
 curl_setopt($ch, CURLOPT_URL, $url);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 curl_setopt($ch, CURLOPT_POST, 1);
 curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
 curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
 if (!empty($options)) {
  curl_setopt_array($ch, $options);
 }
 //https请求 不验证证书和host
 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

 //第一种方法,cert 与 key 分别属于两个.pem文件
 //默认格式为PEM,可以注释
 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
 curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/cert/apiclient_cert.pem');
 //默认格式为PEM,可以注释
 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
 curl_setopt($ch,CURLOPT_SSLKEY,getcwd().'/cert/apiclient_key.pem');
 //第二种方式,两个文件合成一个.pem文件
// curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
 $data = curl_exec($ch);
 curl_close($ch);
 return $data;
 }

 public static function createNonceStr($length = 16)
 {
 $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
 $str = '';
 for ($i = 0; $i < $length; $i++) {
  $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
 }
 return $str;
 }
 public static 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;
 }

 public static function getSign($params, $key)
 {
 ksort($params, SORT_STRING);
 $unSignParaString = self::formatQueryParaMap($params, false);
 $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
 return $signStr;
 }
 protected static function formatQueryParaMap($paraMap, $urlEncode = false)
 {
 $buff = "";
 ksort($paraMap);
 foreach ($paraMap as $k => $v) {
  if (null != $v && "null" != $v) {
  if ($urlEncode) {
   $v = urlencode($v);
  }
  $buff .= $k . "=" . $v . "&";
  }
 }
 $reqPar = '';
 if (strlen($buff) > 0) {
  $reqPar = substr($buff, 0, strlen($buff) - 1);
 }
 return $reqPar;
 }
}
?>

github下载地址

相关文章:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
一个PHP操作Access类(PHP+ODBC+Access)
Jan 02 PHP
FCKeditor的安装(PHP)
Jan 13 PHP
phpMyadmin 用户权限中英对照
Apr 02 PHP
PHP表单提交表单名称含有点号(.)则会被转化为下划线(_)
Dec 14 PHP
php后台多用户权限组思路与实现程序代码分享
Feb 13 PHP
精美漂亮的php分页类代码
Apr 02 PHP
二进制交叉权限微型php类分享
Feb 07 PHP
php的XML文件解释类应用实例
Sep 22 PHP
PHP读取汉字的点阵数据
Jun 22 PHP
解读PHP中的垃圾回收机制
Aug 10 PHP
PHP Laravel中的Trait使用方法
Jan 20 PHP
PHP调用全国天气预报数据接口查询天气示例
Feb 20 PHP
ThinkPHP5框架缓存查询操作分析
May 30 #PHP
PHP实现通过CURL上传文件功能示例
May 30 #PHP
php实现微信支付之现金红包
May 30 #PHP
php微信支付之公众号支付功能
May 30 #PHP
php实现微信原生支付(扫码支付)功能
May 30 #PHP
php实现支付宝当面付(扫码支付)功能
May 30 #PHP
PHP ADODB生成HTML表格函数rs2html功能【附错误处理函数用法】
May 29 #PHP
You might like
一个简单的自动发送邮件系统(一)
2006/10/09 PHP
PHP生成图像验证码的方法小结(2种方法)
2016/07/18 PHP
ANT 压缩(去掉空格/注释)JS文件可提高js运行速度
2013/04/15 Javascript
showModalDialog模态对话框的使用详解以及浏览器兼容
2014/01/11 Javascript
详谈JavaScript内存泄漏
2014/11/14 Javascript
基于JavaScript实现瀑布流布局(二)
2016/01/26 Javascript
js判断登陆用户名及密码是否为空的简单实例
2016/05/16 Javascript
原生JS:Date对象全面解析
2016/09/06 Javascript
详解基于webpack和vue.js搭建开发环境
2017/04/05 Javascript
JS实现合并json对象的方法
2017/10/10 Javascript
详解各版本React路由的跳转的方法
2018/05/10 Javascript
使用node搭建自动发图文微博机器人的方法
2019/03/22 Javascript
在Express中提供静态文件的实现方法
2019/10/17 Javascript
vue  elementUI 表单嵌套验证的实例代码
2019/11/06 Javascript
Python中MySQL数据迁移到MongoDB脚本的方法
2016/04/28 Python
qpython3 读取安卓lastpass Cookies
2016/06/19 Python
Python查询IP地址归属完整代码
2017/06/21 Python
pyqt5让图片自适应QLabel大小上以及移除已显示的图片方法
2019/06/21 Python
python pandas时序处理相关功能详解
2019/07/03 Python
基于python traceback实现异常的获取与处理
2019/12/13 Python
学会python自动收发邮件 代替你问候女友
2020/05/20 Python
详解使用scrapy进行模拟登陆三种方式
2021/02/21 Python
美国一家专业的太阳镜网上零售商:Solstice太阳镜
2016/07/25 全球购物
Saucony澳大利亚官网:美国跑鞋品牌,运动鞋中的劳斯莱斯
2018/05/05 全球购物
美体小铺波兰官方网站:The Body Shop波兰
2019/09/03 全球购物
优秀员工年终发言演讲稿
2014/01/01 职场文书
学校消防演习方案
2014/02/19 职场文书
浪费资源的建议书
2014/03/12 职场文书
会计岗位职责模板
2014/03/12 职场文书
林肯就职演讲稿
2014/05/19 职场文书
技术入股合作协议书
2014/10/07 职场文书
先进党组织事迹材料
2014/12/26 职场文书
2015年七一建党节活动方案
2015/05/05 职场文书
学校隐患排查制度
2015/08/05 职场文书
党员干部学习心得体会
2016/01/23 职场文书
如何用Python搭建gRPC服务
2021/06/30 Python