php开发微信公众号收费模块
php开发微信公众号收费模块
如果您是本站会员;我们将提供技术支持!!!!!
如上图,一看就懂,就是一片公众号文章,点进去显示标题,作者,时间,公众号名称和部分内容,要想阅读所有内容,那就支付0.01元就可以阅读所有的内容,这就是付费阅读!!!当然金额可以自定义….其实这个开发原理很简单,无非就是在文章页面加一个微信支付的按钮,点击支付后把隐藏的部分给显示出来或者直接跳转到全文地址。当然了,这个文章界面也是模仿官方来写的,你可以查看官方的样式,然后模仿就可以了,这个没啥难度。主要是加个按钮在这个页面,下面是这个页面的代码:readpay.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
<?php header('Content-type:text/html; Charset=utf-8'); $mchid = '微信支付商户号'; //微信支付商户号 $appid = '微信支付申请对应的公众号的APPID'; //微信支付申请对应的公众号的APPID $appKey = '微信支付申请对应的公众号的APPSECRET'; //微信支付申请对应的公众号的APPSECRET $apiKey = 'API密钥'; //帐户设置-安全设置-API安全-API密钥-设置API密钥 //①、获取用户openid $wxPay = new WxpayService($mchid,$appid,$appKey,$apiKey); $openId = $wxPay->GetOpenid(); //获取openid if(!$openId) exit('获取openid失败'); //②、统一下单 $outTradeNo = uniqid(); //你自己的商品订单号 $payAmount = 0.01; //付款金额,单位:元 $orderName = 'test'; //订单标题 $notifyUrl = 'nofity.php'; //付款成功后的回调地址,一般放在本页面的同级目录即可 $payTime = time(); //付款时间 $jsApiParameters = $wxPay->createJsBizPackage($openId,$payAmount,$outTradeNo,$orderName,$notifyUrl,$payTime); $jsApiParameters = json_encode($jsApiParameters); ?> <!--下面就是木方官方微信文章页面--> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>新版微信支持双开,王利芬庆祝“茅侃侃去世”文阅读10w+被批人血馒头</title> <script type="text/javascript"> //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', <?php echo $jsApiParameters; ?>, function(res){ WeixinJSBridge.log(res.err_msg); //alert(res.err_code+res.err_desc+res.err_msg); if(res.err_msg == "get_brand_wcpay_request:ok"){ //支付成功跳转页面 window.location.href="这里填写支付成功后要跳转的查看全文文章地址"; }else{ //支付失败/或取消支付跳转页面,自己自定义开发页面 window.location.href="false.html"; } } ); } function callpay() { if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } } </script> <!--下面就是木方官方微信文章页面的CSS--> <style> #title{ margin-bottom:10px; line-height:1.4; font-weight:400; font-size:24px; width: 97%; margin:0 auto; } #meta_content .time{ color: #8C8C8C; font-family: "SimHei"; } .author{ color: #8C8C8C; font-family: "SimHei"; } .name{ color: #607fa6; } #con{ width:95%; font-size: 15px; margin:15px auto 25px; color: #595757; } </style> </head> <body> <br/> <!--文章标题--> <h2 id="title">新版微信支持双开,王利芬庆祝“茅侃侃去世”文阅读10w+被批人血馒头</h2> <div id="meta_content"> <!--发布时间、作者、公众号昵称--> <span class="time">2018-01-27</span> <span class="author">tanking</span> <span class="name">里客云</span> </div> <!--显示的部分内容,未支付前显示的内容--> <div id="con"> 这一周,公众号议论最多的有“周冲的影像声色”因洗稿被撕、80后创业者茅侃侃去世、刘亦菲分手......几乎每件事都能在朋友圈刷到相关报道。此外,视频大号“一条”又拿到了新一轮融资,你最关心哪一件事呢? </div> <!--支付按钮--> <div align="center"> <button style="width:180px; height:35px;background: none; border-radius: 5px;border:1px #1AAD19 solid; cursor: pointer; color:#1AAD19; font-size:15px;-webkit-tap-highlight-color:rgba(255,0,0,0);" type="button" >支付0.01阅读全文</button> </div> </body> </html> <!--下面是微信支付逻辑了--> <?php header("Content-Type:text/html; charset=utf-8"); class WxpayService { protected $mchid; protected $appid; protected $appKey; protected $apiKey; public $data = null; public function __construct($mchid, $appid, $appKey,$key) { $this->mchid = $mchid; //https://pay.weixin.qq.com 产品中心-开发配置-商户号 $this->appid = $appid; //微信支付申请对应的公众号的APPID $this->appKey = $appKey; //微信支付申请对应的公众号的APP Key $this->apiKey = $key; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥 } /** * 通过跳转获取用户的openid,跳转流程如下: * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code * [url=home.php?mod=space&uid=155549]@Return[/url] 用户的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, $orderName, $notifyUrl, $timestamp) { $config = array( 'mch_id' => $this->mchid, 'appid' => $this->appid, 'key' => $this->apiKey, ); $orderName = iconv('GBK','UTF-8',$orderName); $unified = array( 'appid' => $config['appid'], 'attach' => 'pay', //商家数据包,原样返回,如果填写中文,请注意转换为utf-8 'body' => $orderName, 'mch_id' => $config['mch_id'], 'nonce_str' => self::createNonceStr(), 'notify_url' => $notifyUrl, 'openid' => $openid, //rade_type=JSAPI,此参数必传 'out_trade_no' => $outTradeNo, 'spbill_create_ip' => '127.0.0.1', 'total_fee' => intval($totalFee * 100), //单位 转为分 'trade_type' => 'JSAPI', ); $unified['sign'] = self::getSign($unified, $config['key']); $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', 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); } $arr = array( "appId" => $config['appid'], "timeStamp" => "$timestamp", //这里是字符串的时间戳,不是int,所以需加引号 "nonceStr" => self::createNonceStr(), "package" => "prepay_id=" . $unifiedOrder->prepay_id, "signType" => 'MD5', ); $arr['paySign'] = self::getSign($arr, $config['key']); return $arr; } 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 static 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); $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; } } ?> |
下面是nofity.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
<?php /** * 原生支付(扫码支付)及公众号支付的异步回调通知 * 说明:需要在native.php或者jsapi.php中的填写回调地址。例如:http://www.xxx.com/wx/notify.php * 付款成功后,微信服务器会将付款结果通知到该页面 */ header('Content-type:text/html; Charset=utf-8'); $mchid = '微信支付商户号'; $appid = '公众号APPID'; $apiKey = 'API密钥'; $wxPay = new WxpayService($mchid,$appid,$apiKey); $result = $wxPay->notify(); if($result){ //完成你的逻辑 //例如连接数据库,获取付款金额$result['cash_fee'],获取订单号$result['out_trade_no'],修改数据库中的订单状态等; }else{ echo 'pay error'; } class WxpayService { protected $mchid; protected $appid; protected $apiKey; public function __construct($mchid, $appid, $key) { $this->mchid = $mchid; $this->appid = $appid; $this->apiKey = $key; } public function notify() { $config = array( 'mch_id' => $this->mchid, 'appid' => $this->appid, 'key' => $this->apiKey, ); $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); if ($postObj === false) { die('parse xml error'); } if ($postObj->return_code != 'SUCCESS') { die($postObj->return_msg); } if ($postObj->result_code != 'SUCCESS') { die($postObj->err_code); } $arr = (array)$postObj; unset($arr['sign']); if (self::getSign($arr, $config['key']) == $postObj->sign) { echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; return $arr; } } /** * 获取签名 */ 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; } } |