forked from dedemao/weixinPay
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,273 @@ | ||
<?php | ||
/** | ||
* 关于微信现金红包的说明 | ||
* 1.微信现金红包要求必传证书,需要到https://pay.weixin.qq.com 账户中心->账户设置->API安全->下载证书,证书路径在第214行和217行修改 | ||
* 2.默认的使用场景是抽奖(即scene_id参数为PRODUCT_2),额度是1-200元,所以测试时的最低金额是1元。如需修改在产品中心->产品大全->现金红包->产品设置中修改 | ||
* 3.错误码参照 :https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3 | ||
*/ | ||
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; //红包金额,单位:元 | ||
$sendName = '织梦猫'; //红包发送者名称 | ||
$wishing = '感谢您参加猜灯谜活动,祝您元宵节快乐!'; //红包祝福语 | ||
$act_name='猜灯谜抢红包活动'; //活动名称 | ||
$result = $wxPay->createJsBizPackage($openId,$payAmount,$outTradeNo,$sendName,$wishing,$act_name); | ||
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 $wishing 祝福语 | ||
* @param string $actName 互动名称 | ||
* @return string | ||
*/ | ||
public function createJsBizPackage($openid, $totalFee, $outTradeNo, $sendName,$wishing,$actName) | ||
{ | ||
$config = array( | ||
'mch_id' => $this->mchid, | ||
'appid' => $this->appid, | ||
'key' => $this->apiKey, | ||
); | ||
$unified = array( | ||
'wxappid' => $config['appid'], | ||
'send_name' => $sendName, | ||
'mch_id' => $config['mch_id'], | ||
'nonce_str' => self::createNonceStr(), | ||
're_openid' => $openid, | ||
'mch_billno' => $outTradeNo, | ||
'client_ip' => '127.0.0.1', | ||
'total_amount' => intval($totalFee * 100), //单位 转为分 | ||
'total_num'=>1, //红包发放总人数 | ||
'wishing'=>$wishing, //红包祝福语 | ||
'act_name'=>$actName, //活动名称 | ||
'remark'=>'remark', //备注信息,如为中文注意转为UTF8编码 | ||
'scene_id'=>'PRODUCT_2', //发放红包使用场景,红包金额大于200时必传。https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3 | ||
); | ||
$unified['sign'] = self::getSign($unified, $config['key']); | ||
$responseXml = $this->curlPost('https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack', 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; | ||
} | ||
} | ||
?> |