<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>微信 on 阿珏酱のBlog</title>
    <link>https://zh.moejue.cn/tags/%E5%BE%AE%E4%BF%A1/</link>
    <description>Recent content from 阿珏酱のBlog</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    
    <managingEditor>xxx@example.com (MoeJue)</managingEditor>
    <webMaster>xxx@example.com (MoeJue)</webMaster>
    
    <copyright>本博客所有文章除特别声明外，均采用 BY-NC-SA 许可协议。转载请注明出处！</copyright>
    
    <lastBuildDate>Fri, 17 May 2019 06:59:47 +0000</lastBuildDate>
    
    
    <atom:link href="https://zh.moejue.cn/tags/%E5%BE%AE%E4%BF%A1/index.xml" rel="self" type="application/rss&#43;xml" />
    

    
    

    <item>
      <title>小程序架构</title>
      <link>https://zh.moejue.cn/posts/92/</link>
      <pubDate>Fri, 17 May 2019 06:59:47 &#43;0000</pubDate>
      <author>xxx@example.com (MoeJue)</author>
      <guid>https://zh.moejue.cn/posts/92/</guid>
      <description>
        <![CDATA[<h1>小程序架构</h1><p>作者：MoeJue（xxx@example.com）</p>
        
          <p>不知道大家们写小程序是怎么个写法的，前几个月在写微信小程序，自己整的一种架构，或者叫框架<br>
微信原生的架构是这样子的</p>
<p>├── app.js
├── app.json
├── app.wxss
├── pages
│   │── index
│   │   ├── index.wxml
│   │   ├── index.js
│   │   ├── index.json
│   │   └── index.wxss
│   └── logs
│       ├── logs.wxml
│       └── logs.js
└── utils</p>
<p>为什么不用微信原生的写法呢？<br>
小程序就类似手机APP，都会有一个tabBar栏对吧，微信官方的tabBar栏是在app.json中进行的全局配置。做一般的开发是没有任何问题的，但涉及到一个复杂的tabBar栏时 ，使用官方原生的就无法实现，也无法动态加载，比如某视频app中间的拍照录像功能<br>
这意味着，我们不能使用官方给我们提供的tabBar栏，需要我们自个写<br>
最开始我的做法还是跟保持原生的结构，只是自己写tabBar栏，所以页面代码都写在一个文件中，默认显示第一屏，其他的都隐藏起来，切换页面的时候在把相应的页面显示，其他的隐藏起来，并且动态渲染数据上去。但是有个问题是，你要是小项目到没啥大问题，但是如果是大项目代码量很庞大，都写在一个文件中，后期难以维护，所以这个方法最后被pass掉</p>
<p>再后来将切换页面的方式改为跳转（wx.switchTab等），把不同页面的代码放到了不同的文件，但是还有一个问题，切换也会闪，每次切换页面就是等于重新打开一个网页一样，tabBar都被重新渲染，所以会闪。pass</p>
<p>由此就有了现在的全新架构方式：<br>
将/pages/index/下的文件全部定义为入口文件，js入口，css入口，视图入口，不同页面的文件还是放到不同的位置去，为了好管理，新建了一个template的文件夹，用于放不同页面间的代码，结构和官方的但页面结构是一样的<br>
根目录下的app.js用于存放全局函数，其他页面调用只需getApp()即可<br>
js的入口文件</p>
<p>const app = getApp();
var index_js = require(&quot;../../template/index/index.js&quot;);
var types_js = require(&quot;../../template/types/types.js&quot;);
var Global_Data = [];
Page({
data: {
active: 0,
show: {
index: true,
types: false,
course: false,
user: false
}
},</p>
        
        <hr><p>本文2019-05-17首发于<a href='https://zh.moejue.cn/'>阿珏酱のBlog</a>，最后修改于2019-05-17</p>]]>
      </description>
      
        <category>折腾代码</category>
      
    </item>
    
    

    <item>
      <title>微信授权登录</title>
      <link>https://zh.moejue.cn/posts/88/</link>
      <pubDate>Fri, 05 Apr 2019 09:29:45 &#43;0000</pubDate>
      <author>xxx@example.com (MoeJue)</author>
      <guid>https://zh.moejue.cn/posts/88/</guid>
      <description>
        <![CDATA[<h1>微信授权登录</h1><p>作者：MoeJue（xxx@example.com）</p>
        
          <p><img src="https://res.wx.qq.com/mpres/htmledition/weui-desktopSkin/svg/buildless/bg_logo_primary4247a9.svg" alt=""> 文档：<a href="https://mp.weixin.qq.com/wiki?t=resource/res_main&amp;id=mp1421135319">https://mp.weixin.qq.com/wiki?t=resource/res_main&amp;id=mp1421135319</a></p>
<p>微信的授权登录和QQ、新浪等平台的授权登录都大同小异，均采用OauthOAuth2.0鉴权方式。<br>
微信授权分为两种：</p>
<ol>
<li>静默授权</li>
<li>弹窗授权，需要用户手动同意</li>
</ol>
<p>两种scope的区别说明</p>
<ol>
<li>以snsapi_base为scope发起的网页授权，是用来获取进入页面的用户的openid的，并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页（往往是业务页面）</li>
<li>以snsapi_userinfo为scope发起的网页授权，是用来获取用户的基本信息的。但这种授权需要用户手动同意，并且由于用户同意过，所以无须关注，就可在授权后获取该用户的基本信息。</li>
</ol>
<p>用户管理类接口中的“获取用户基本信息接口”，是在用户和公众号产生消息交互或关注后事件推送后，才能根据用户OpenID来获取用户基本信息。这个接口，包括其他微信接口，都是需要该用户（即openid）关注了公众号后，才能调用成功的。</p>
<p>具体而言，网页授权流程分为四步：</p>
<ol>
<li>引导用户进入授权页面同意授权，获取code</li>
<li>通过code换取网页授权access_token（与基础支持中的access_token不同）</li>
<li>如果需要，开发者可以刷新网页授权access_token，避免过期</li>
<li>通过网页授权access_token和openid获取用户基本信息（支持UnionID机制）</li>
</ol>
<p>以下是封装的微信操作类，需要用到两个数据表，用于保存access_token、ticket，由于他们具有一定有效期，且每天请求数有上限，所以开发者需自行保存</p>
<?php
/\*\*
\*   微信操作表
\*   wxtoken 表结构
\*   id
\*   access\_token
\*   addtime
\*   wxticket 表结构
\*   id
\*   ticket
\*   addtime
\*/
class WX {
	private $appid;
	private $appserect;
	private $curl;
	private $msg;
	protected $errs = array(
		'-1' => '系统繁忙，此时请开发者稍候再试',
		'0' => '请求成功',
		'40001' => 'AppSecret错误或者AppSecret不属于这个公众号，请开发者确认AppSecret的正确性',
		'40002' => '请确保grant\_type字段值为client\_credential',
		'40164' => '调用接口的IP地址不在白名单中，请在接口IP白名单中进行设置。',
	);
	function \_\_construct($appid, $appserect) {
		$this->appid = $appid;
		$this->appserect = $appserect;
		$this->curl = new Curl();
	}
	/\*
	微信网页授权登录  需要在公众号设置 - 功能设置 - 网页授权域名
	第一步：用户同意授权，获取code
	scope : snsapi\_base 只能获取openid 直接跳转
	snsapi\_userinfo
	\*/
	public function getCode($redirect\_uri, $scope = 'snsapi\_userinfo',$state = '1') {
		$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appid}&redirect\_uri={$redirect\_uri}&response\_type=code&scope={$scope}&state={$state}#wechat\_redirect";
		header("Location:{$url}");
		exit;
	}
	/\*
	第二步：通过code换取网页授权access\_token
	\*/
	public function getAccessTokenByCode($code) {
		$url = "https://api.weixin.qq.com/sns/oauth2/access\_token?appid={$this->appid}&secret={$this->appserect}&code={$code}&grant\_type=authorization\_code";
		// exit($url);
		// $curl = new Curl();
		$result = $this->curl->doGet($url);
		if (!$result) {
			// $this->curl->getError()
			$this->msg = "获取token失败";
			return false;
		}
		$result = json\_decode($result, true);
		if ($result\['errcode'\]) {
			$this->msg = $result\['errmsg'\];
			return false;
		}
		return $result;
	}
	// 第三步：刷新access\_token（如果需要） 通过code 获取openid $type 0静默授权 1弹窗授权
	public function getUserInfo($code, $type = 0, $lang = 'zh\_CN ') {
		$result = $this->getAccessTokenByCode($code);
			if (!$result) {
			return false;
		}
		$member = C::t(PT\_USER)->getByOpenid($result\['openid'\]);
	if ($member) {
		return $member;
	} else {
		if ($type) {
			$url = "https://api.weixin.qq.com/sns/userinfo?access\_token={$result\['access\_token'\]}&openid={$result\['openid'\]}&lang={$lang}";
			// $return = $this->curl->doGet($url);
			// 这接口有病 强制显示文件头
			$return = file\_get\_contents($url);
			if (!$return) {
				$this->msg = '获取用户信息失败';
				return false;
			}
			$return = json\_decode($return, true);
			if (!$return) {
				$this->msg = '获取用户信息返回失败';
				return false;
			}
			// file\_put\_contents('ccc.txt',print\_r($return,true),FILE\_APPEND);
			$data = array(
				'openid' => $return\['openid'\],
				'name' => $return\['nickname'\],
				'sex' => $return\['sex'\],
				'province' => $return\['province'\],
				'city' => $return\['city'\],
				'country' => $return\['country'\],
				'img' => $return\['headimgurl'\],
				'bindtel' => 0,
			);
		} else {
			$data = array(
				'openid' => $result\['openid'\],
				'username' => "微信用户\_" . random(6,1)
			);
		}
		$name = rand(100000, 1000000000);
		$e = $name . "@qq.com";
		$password = $e;
		$id = UserAddEdit(0, $data\['username'\], $password, $e,10,0,"", $msg);
		if ($id <= 0) {
			$this->msg = $msg;
			return false;
		}
		C::t(PT\_USER)->update($data, $id);
		$member = C::t(PT\_USER)->get($id);
		return $member;
		}
	}
	/\*
	公众号 安全中心 设置IP白名单
	公众号的全局唯一接口调用凭据，公众号调用各接口时都需使用access\_token。开发者需要进行妥善保存。access\_token的存储至少要保留512个字符空间。access\_token的有效期目前为2个小时，需定时刷新，重复获取将导致上次获取的access\_token失效。
	\*/
	public function getAccessToken($type) {
		$addtime = TIMESTAMP - 7200;
		$url = "https://api.weixin.qq.com/cgi-bin/token?grant\_type=client\_credential&appid={$this->appid}&secret={$this->appserect}";
		$row = C::t(PT\_WXTOKEN)->getNew($addtime, $type);
		if ($row) {
			return $row\['access\_token'\];
		} else {
			$result = $this->curl->doGet($url);
			if (!$result) {
				$this->msg = "无法获取令牌内容";
				return false;
			}
			$result = json\_decode($result, true);
			if (!$result) {
				$this->msg = "解析令牌内容失败";
				return false;
			}
			if ($result\['access\_token'\]) {
				C::t(PT\_WXTOKEN)->addToken($result\['access\_token'\], $type);
				return $result\['access\_token'\];
			} else {
				$this->msg = "获取令牌失败";
				return false;
			}
		}
	}
	// 获取js票据  需要在公众号设置 - 功能设置 - JS接口安全域名设置
	public function getJsTicket() {
		$addtime = TIMESTAMP - 7200;
		$row = C::t(PT\_WXTICKET)->getNew($addtime);
		if ($row) {
			return $row\['ticket'\];
		} else {
			$token = $this->getAccessToken();
			if (!$token) {
				return false;
			}
			$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access\_token={$token}&type=jsapi";
			$result = $this->curl->doGet($url);
			if (!$result) {
				$this->msg = "无法获取js票据";
				return false;
			}
			$result = json\_decode($result, true);
			if (!$result) {
				$this->msg = "解析js票据内容失败";
				return false;
			}
			if ($result\['ticket'\]) {
				C::t(PT\_WXTICKET)->addTicket($result\['ticket'\]);
				return $result\['ticket'\];
			} else {
				$this->msg = "获取js票据失败";
				return false;
			}
		}
	}
	// js sdk 票据签名 当前网页的URL，不包含#及其后面部分
	public function jsSign($data) {
		// 1.所有待签名参数按照字段名的ASCII 码从小到大排序（字典序）
		ksort($data);
		// 2.URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串string1 采用原始值，不进行URL 转义
		$string1 = $this->ToUrlParams($data);
		// echo "string1:{$string1}<br/>";
		// 3.对string1做sha1加密
		$sign = sha1($string1);
		// echo "signature:{$sign}<br/>";
		return $sign;
	}
	// 获取消息内容
	public function getMsg() {
		return $this->msg;
	}
	/\*\*
	\* 格式化参数格式化成url参数
	\*/
	public function ToUrlParams($data) {
		$buff = "";
		foreach ($data as $k => $v) {
			if ($k != "sign" && $v != "" && !is\_array($v)) {
				$buff .= $k . "=" . $v . "&";
			}
		}
		$buff = trim($buff, "&");
		return $buff;
	}
}
?>
<p>// 微信登录
function wxlogin() {
global $_G,$identifier,$config,$wx;
if (!$_G[&lsquo;uid&rsquo;]) {
if ($_GET[&lsquo;state&rsquo;]) {
//回调
$member = $wx-&gt;getUserInfo($_GET[&lsquo;code&rsquo;]);
if (!$member) {
exit($wx-&gt;getMsg());
}
if (!function_exists(&ldquo;setloginstatus&rdquo;)) {
include_once libfile(&lsquo;function/member&rsquo;);
}
// 设置登录状态$wx
setloginstatus($member, 2592000);
checkfollowfeed();
$_G[&lsquo;uid&rsquo;] = $member[&lsquo;uid&rsquo;];
$_G[&lsquo;member&rsquo;] = $member;
} else {
//请求授权 对参数编码
$redirect = urlencode(getProtocol() . $_SERVER[&lsquo;HTTP_HOST&rsquo;] . $_SERVER[&lsquo;REQUEST_URI&rsquo;]);
$wx-&gt;getCode($redirect, &lsquo;snsapi_base&rsquo;);
}
}
}
function getProtocol() {
return is_HTTPS() ? &lsquo;https://&rsquo; : &lsquo;http://&rsquo;;
}
function is_HTTPS() {  if ($_SERVER[&lsquo;HTTPS&rsquo;] === 1 || $_SERVER[&lsquo;HTTPS&rsquo;] === &lsquo;on&rsquo; || $_SERVER[&lsquo;SERVER_PORT&rsquo;] == 443) {
return true;
}
return false;
}</p>
        
        <hr><p>本文2019-04-05首发于<a href='https://zh.moejue.cn/'>阿珏酱のBlog</a>，最后修改于2019-04-05</p>]]>
      </description>
      
        <category>折腾代码</category>
      
    </item>
    
    

    <item>
      <title>微信JSAPI支付</title>
      <link>https://zh.moejue.cn/posts/89/</link>
      <pubDate>Sat, 30 Mar 2019 09:30:21 &#43;0000</pubDate>
      <author>xxx@example.com (MoeJue)</author>
      <guid>https://zh.moejue.cn/posts/89/</guid>
      <description>
        <![CDATA[<h1>微信JSAPI支付</h1><p>作者：MoeJue（xxx@example.com）</p>
        
          <p><img src="https://gh-proxy.com/github.com/iAJue/MoeJueBlogPic/blob/master/Images/2019/03/30/0072Vf1pgy1g1l3k211blj30ia04x74e.jpg" alt=""> 前段时间一直在做微信相关的业务，虽说不是什么新技术，但之前一直没有机会接触到，然后踩了些坑，抽空整理记录下。<br>
微信支付一共分为7种，分为是：付款码支付、JSAPI支付、Native支付、APP支付、H5支付、小程序支付、人脸支付。<br>
此次业务中使用到的是微信JSAPI支付：用户通过微信扫码、关注公众号等方式进入商家H5页面,并在<strong>微信内</strong>调用 JSSDK完成支付</p>
<p>文档：<a href="https://pay.weixin.qq.com/wiki/doc/api/index.html">https://pay.weixin.qq.com/wiki/doc/api/index.html</a></p>
<p>SDK：[https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1</p>
<p>](<a href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1%29JSAPI">https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1)JSAPI</a>支付需要在微信中的浏览器打开才能唤起微信支付，效果如下图<br>
<img src="https://gh-proxy.com/github.com/iAJue/MoeJueBlogPic/blob/master/Images/2019/03/30/0072Vf1pgy1g1l36yn1sej30p91hc40b.jpg" alt=""><br>
附上界面代码<br>
代码中使用了模板引擎<br>
html：</p>
<div class="am-modal-bd">
	<img src="{$competition\['avatar'\]}" alt=""><br>
	<span style="font-size: 13px;color: #72c6ef">{$competition\['username'\]}</span><br>
	<span id="tips" style="font-size: 13px"></span>
  <ul class="ul\_box">
	<li>
		<div></div>
		<div class="label\_box">
			<label>
				<input type="radio" name="price" value="{$prices\[0\]}" checked="">
				<div class="active"><span class="am-icon-diamond"></span> {$prices\[0\]}钻</div>
			</label>
			<label>
				<input type="radio" name="price" value="{$prices\[1\]}">
				<div><span class="am-icon-diamond"></span> {$prices\[1\]}钻</div>
			</label>
			<label>
				<input type="radio" name="price" value="{$prices\[2\]}">
				<div><span class="am-icon-diamond"></span> {$prices\[2\]}钻</div>
			</label>
		</div>
	</li>
	<li>
		<div></div>
		<div class="label\_box">
			<label>
				<input type="radio" name="price" value="{$prices\[3\]}">
				<div><span class="am-icon-diamond"></span> {$prices\[3\]}钻</div>
			</label>
			<label>
				<input type="radio" name="price" value="{$prices\[4\]}">
				<div><span class="am-icon-diamond"></span> {$prices\[4\]}钻</div>
			</label>
			<label>
				<input type="number" name="price" id="price" class="input" placeholder="自定义">
			</label>
		</div>
	</li>
  </ul>
  <span style="font-size: 13px">注：1钻=1元，1钻={$activity\['offset'\]}票</span><br>
  <button type="button" class="am-btn am-btn-primary  am-radius" onclick="callpay()" style="margin-top: 5px;">立即微信支付</button>
</div>
<p>JavaScript：</p>
<p>// 投票
var offset = {$activity[&lsquo;offset&rsquo;]};
$(&rsquo;#tips&rsquo;).html(&lsquo;正在给{$competition[&lsquo;code&rsquo;]}号赠送{$prices[0]}钻=&rsquo;+({$prices[0]}*offset)+&lsquo;票&rsquo;);
$(&rsquo;#vote&rsquo;).click(function(){
$.post(&rsquo;/index/index/detailed.html?cid={$cid}&amp;aid={$aid}&rsquo;,{
formhash :&rsquo;{FORMHASH}&rsquo;,
submit:&lsquo;1&rsquo;,
type:1,
openid:&rsquo;{$_G[&lsquo;member&rsquo;][&lsquo;openid&rsquo;]}&rsquo;
},function(res){
alert(res.msg);
if (res.code == 0) {
$(&rsquo;.box-1 span&rsquo;).text(res.data.all);
$(&rsquo;.box-2 span&rsquo;).text(res.data.rank);
$(&rsquo;.box-3 span&rsquo;).text(res.data.up + &lsquo;票&rsquo;);
}
});
})
/* jQuery对象级别插件扩展 */
$.fn.extend({
/* 单选框 */
hlRadio:function () {
var radioEl=$(this);
radioEl.click(function () {
var price = 0;
price = $(&lsquo;input:radio:checked&rsquo;).val();
$(&rsquo;#price&rsquo;).val(&rsquo;&rsquo;);
$(&rsquo;#tips&rsquo;).html(&lsquo;正在给{$competition[&lsquo;code&rsquo;]}号赠送&rsquo;+price+&lsquo;钻=&rsquo;+(price*offset)+&lsquo;票&rsquo;);
radioEl.siblings(&ldquo;div&rdquo;).removeClass(&ldquo;active&rdquo;);
$(this).siblings(&ldquo;div&rdquo;).addClass(&ldquo;active&rdquo;);
});
},
});
$(&ldquo;input[name=&lsquo;price&rsquo;]&rdquo;).hlRadio();
$(&rsquo;#price&rsquo;).bind(&lsquo;input propertychange&rsquo;, function(){
var price = 0;
price = $(&rsquo;#price&rsquo;).val();
$(&rsquo;#tips&rsquo;).html(&lsquo;正在给{$competition[&lsquo;code&rsquo;]}号赠送&rsquo;+price+&lsquo;钻=&rsquo;+(price*offset)+&lsquo;票&rsquo;);
})</p>
        
        <hr><p>本文2019-03-30首发于<a href='https://zh.moejue.cn/'>阿珏酱のBlog</a>，最后修改于2019-03-30</p>]]>
      </description>
      
        <category>折腾代码</category>
      
    </item>
    
  </channel>
</rss>
