1、安装node.js地址:https://nodejs.org/zh-cn/
安装后在控制台输入:node -v
, 如果显示版本号则安装成功
2、安装npm
一般情况下nodejs安装好后自带npm
可以在控制台输入:npm -v
, 如果显示版本号则安装成功。
二、下载反编译脚本
https://gitee.com/moduo_412/wxappUnpacker
三、安装模拟器
下载夜神模拟器或其他模拟器安装RE文件管理器,使用解密工具可以不用安装模拟器,找到__APP__.wxapkg,不确定是哪个目录可以把当前目录删除,再重新打开小程序
四、在本地找到小程序源文件包
/data/data/com.tencent.mm/MicroMsg/一串32位的16进制字符串文件夹/appbrand/pkg/
小程序源文件包
这个目录下就是你的小程序源文件了,小程序格式就是wxapkg,根据时间找到源文件包压缩后发送到电脑
五、反编译解包
1、打开nodejs命令窗口
2、用cd命令进入反编译脚本根目录下
3、在node命令窗口中依次安装如下
// 安装
npm install
// 安装依赖
npm install esprima
npm install css-tree
npm install cssbeautify
npm install vm2
npm install uglify-es
npm install js-beautify
4、安装好依赖之后,就是最后一步了,反编译 .wxapkg 文件
在当前目录下输入命令:node wuWxapkg.js _163200311_32.wxapkg
_163200311_32.wxapkg是你需要反编译的源文件,输入前几个字符可以按tab键补全
在当前目录找到_163200311_32文件夹(如果不是想要的,请换一个.wxapkg文件):
5、报错处理
Cannot find module 'xxx'
模块未安装
运行命令:npm install xxx
如果这种
错误,请重新换一个.wxapkg文件
执行脚本中可能会出现以下报错
1、修改wuWxss.js文件31行
if (!importCnt[id]) importCnt[id] = 1, statistic(pureData[id]);
// 替换为
if(!importCnt[id]){
if(pureData){
importCnt[id]=1;
statistic(pureData[id]);
}
}
2、修改wuWxss.js文件243行
pureData = vm.run(code + "\n_C");
// 替换为
pureData = vm.run(code + "}");
]]>当一个组件上的事件被触发后,该事件会向父节点传递。
bind事件名
<text>事件的冒泡</text>
<view class="one" bindtap="handlerOne">one
<view class="two" bindtap="handlerTwo">two
<view class="three" bindtap="handlerThree">three</view>
</view>
</view>
catch事件名
<text>事件的冒泡</text>
<view class="one" bindtap="handlerOne">one
<view class="two" catchtap="handlerTwo">two
<view class="three" bindtap="handlerThree">three</view>
</view>
</view>
捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。需要在捕获阶段监听事件时,可以采用:
capture-bind:事件名
<view class="one" capture-bind:tap="handlerOne">one
<view class="two" capture-bind:tap="handlerTwo">two
<view class="three" capture-bind:tap="handlerThree">three</view>
</view>
</view>
capture-catch:事件名
capture-catch关键字,后者将中断捕获阶段和取消冒泡阶段。
<view class="one" capture-bind:tap="handlerOne">one
<view class="two" capture-catch:tap="handlerTwo">two
<view class="three" capture-bind:tap="handlerThree">three</view>
</view>
</view>
]]><view bindtouchstart="touchstart" bindtouchend="touchend">123456</view>
//touch start
touchstart: function(e) {
this.startTime = e.timeStamp;
console.log(this.startTime)
},
//touch end
touchend: function(e) {
this.endTime = e.timeStamp;
console.log(this.endTime)
console.log("endTime - startTime = " + (this.endTime-this.startTime));
if (this.endTime - this.startTime>600){
console.log('长按')
}
}
]]>pay.js
import util from '../../utils/util.js'
const md5 = require('../../utils/md5.js');
Page({
/**
* 页面的初始数据
*/
data: {
id: ''
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function () {
},
submit(){
this.setData({id: 1})
this.unitedPayRequest('openid')
},
/*统一支付接口*/
unitedPayRequest: function(openid){
var that = this;
//统一支付签名
var accountInfo = wx.getAccountInfoSync();
var appid = accountInfo.miniProgram.appId;//appid必填
var body = '';//商品名必填
var mch_id = '';//商户号必填
var key = ''; //商户key必填,在商户后台获得
var out_trade_no = '';//自定义订单号必填
var nonce_str = util.randomString();//随机字符串,不长于32位。
var total_fee = parseInt(0.01 * 100); //价格,这是一分钱
var notify_url = 'http://localhost/notify_url.php';//通知地址必填
var trade_type = "JSAPI";
var unifiedPayment = 'appid=' + appid + '&body=' + body + '&mch_id=' + mch_id + '&nonce_str=' + nonce_str + '¬ify_url=' + notify_url + '&openid=' + openid + '&out_trade_no=' + out_trade_no + '&total_fee=' + total_fee + '&trade_type=' + trade_type + '&key=' + key;
console.log("unifiedPayment", unifiedPayment);
var sign = md5.md5(unifiedPayment).toUpperCase();
console.log("签名md5", sign);
//封装统一支付xml参数
var formData = "<xml>";
formData += "<appid>" + appid + "</appid>";
formData += "<body>" + body + "</body>";
formData += "<mch_id>" + mch_id + "</mch_id>";
formData += "<nonce_str>" + nonce_str + "</nonce_str>";
formData += "<notify_url>" + notify_url + "</notify_url>";
formData += "<openid>" + openid + "</openid>";
formData += "<out_trade_no>" + out_trade_no + "</out_trade_no>";
formData += "<total_fee>" + total_fee + "</total_fee>";
formData += "<trade_type>" + trade_type + "</trade_type>";
formData += "<sign>" + sign + "</sign>";
formData += "</xml>";
console.log("formData", formData);
//统一支付
wx.request({
url: 'https://api.mch.weixin.qq.com/pay/unifiedorder',
method: 'POST',
head: 'application/x-www-form-urlencoded',
data: formData, //设置请求的 header
success: function (res) {
console.log("返回商户", res.data);
var resultCode = util.getXMLNodeValue('result_code', res.data.toString("utf-8"));
if (!resultCode || resultCode == 'FAIL') {
var errDes = util.getXMLNodeValue('err_code_des', res.data.toString("utf-8"));
var returnMsg = util.getXMLNodeValue('return_msg', res.data.toString("utf-8"));
wx.showToast({
title: errDes ? errDes : returnMsg,
icon: 'none'
})
} else {
//发起支付
var prepay_id = util.getXMLNodeValue('prepay_id', res.data.toString("utf-8"));
//签名
var timeStamp = util.timeStamp();
var nonceStr = util.randomString();
var stringSignTemp = "appId=" + appid + "&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + timeStamp + "&key=" + key;
console.log("签名字符串", stringSignTemp);
var sign = md5.md5(stringSignTemp).toUpperCase();
console.log("签名", sign);
var param = { "timeStamp": timeStamp, "package": 'prepay_id=' + prepay_id, "paySign": sign, "signType": "MD5", "nonceStr": nonceStr }
console.log("param小程序支付接口参数", param);
that.processPay(param);
}
},
})
},
/* 小程序支付 */
processPay: function (param) {
var thia = this;
wx.requestPayment({
timeStamp: param.timeStamp,
nonceStr: param.nonceStr,
package: param.package,
signType: param.signType,
paySign: param.paySign,
success: function (res) {
console.log("wx.requestPayment返回信息",res);
wx.showToast({
title: '支付成功',
icon: 'success'
})
setTimeout(function(){
wx.navigateTo({
url: '../storyDetails/storyDetails?id='+thia.data.id,
})
},1500)
},
fail: function () {
console.log("支付失败");
wx.showToast({
title: '支付失败',
icon: 'error'
})
setTimeout(function(){
wx.navigateTo({
url: '../storyDetails/storyDetails?id='+thia.data.id,
})
},1500)
},
complete: function () {
console.log("支付完成");
}
})
}
})
util.js
/* 时间戳产生函数 */
function timeStamp() {
return parseInt(new Date().getTime() / 1000) + ''
}
/* 随机数 */
function randomString() {
var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789';
var maxPos = chars.length;
var pwd = '';
for (var i = 0; i < 32; i++) {
pwd += chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
/* 获取XML节点信息 */
function getXMLNodeValue(node_name, xml) {
var str = '';
var tmp = xml.split("<" + node_name + ">");
if(!tmp[1]){
return;
}
var _tmp = tmp[1].split("</" + node_name + ">");
if(_tmp[0].indexOf('![CDATA[') != -1){
str = _tmp[0].split('[')[2].split(']')[0];
}else{
str = _tmp[0];
}
return str;
}
module.exports = {
randomString: randomString,
timeStamp: timeStamp,
getXMLNodeValue: getXMLNodeValue
}
notify_url.php
<?php
require 'common.php';
$param = xml_array(file_get_contents('php://input'));
// file_put_contents('1.txt',file_get_contents('php://input'));
if(!empty($param)){
$appid = $param['appid'];
$mch_id = $param['mch_id'];
$nonce_str = $param['nonce_str'];
$out_trade_no = $param['out_trade_no'];
$key = $config['payKey'];
$md5Arr = $param;
unset($md5Arr['sign']);
$md5Param = urldecode(http_build_query(arg_sort($md5Arr))).'&key='.$key;
// echo $md5Param;
$sign = md5($md5Param);
if(strtolower($sign) != strtolower($param['sign'])){
exit(array_xml(['return_code' => 'FAIL','return_msg' => '签名验证失败']));
}
$arrToXml = ['appid' => $appid,'mch_id' => $mch_id,'nonce_str' => $nonce_str,'out_trade_no' => $out_trade_no];
$sign2 = urldecode(http_build_query(arg_sort($arrToXml))).'&key='.$key;
$arrToXml['sign'] = md5($sign2);
$xml = array_xml($arrToXml);
$xml = get_curl("https://api.mch.weixin.qq.com/pay/orderquery",$xml);
$arr = xml_array($xml);
if($arr['return_code'] == 'SUCCESS' && $arr['result_code'] == 'SUCCESS' && $arr['trade_state'] == 'SUCCESS'){
$row = getOne("select id,money,status from order_list where order_number='{$out_trade_no}'");
if($row['status'] == 0 && $row['money'] == round(($arr['total_fee']/100),2)){
update('order_list',['status' => 1,'pay_time' => time()],'id='.$row['id']);
}
echo array_xml(['return_code' => 'SUCCESS']);
}else{
echo array_xml(['return_code' => 'FAIL','return_msg' => '验证失败']);
}
}else{
echo array_xml(['return_code' => 'FAIL','return_msg' => '请发起xml请求']);
}
// 以下测试用
/* $xml = file_get_contents('1.txt');
echo get_curl('https://域名/notify_url.php',$xml);*/
common.php
function get_curl($url, $post = '', $cookie = '', $referer = '', $proxy = '', $header = 0, $userAgent = '', $httpheader = [])
{
$curl = curl_init();
// 配置curl中的http协议->可配置的荐可以查PHP手册中的curl_
curl_setopt($curl, CURLOPT_URL, $url);
if ($post) {
// POST数据
curl_setopt($curl, CURLOPT_POST, 1);
// 把post的变量加上
if (is_array($post)) {
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post));
} else {
curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
}
if ($arr = @json_decode($post, true)) {
if (is_array($arr)) {
$httpheader[] = 'Content-Type: application/json; charset=utf-8';
$httpheader[] = 'Content-Length: ' . strlen($post);
}
}
}
if ($referer) {
$httpheader[] = 'Referer: ' . $referer; //模拟来路
$httpheader[] = 'Origin: ' . $referer;
} else {
$httpheader[] = 'Referer: ' . $url; //模拟来路
$httpheader[] = 'Origin: ' . $url;
}
if ($cookie) {
$httpheader[] = 'Cookie: ' . $cookie; //模拟cookie
}
if ($proxy) {
$proxy = explode(':', $proxy);
if (!empty($proxy[1])) {
curl_setopt($curl, CURLOPT_PROXY, $proxy[0]); //代理服务器地址
curl_setopt($curl, CURLOPT_PROXYPORT, $proxy[1]); //代理服务器端口
}
$httpheader[] = 'X-FORWARDED-FOR: ' . $proxy[0]; //模拟ip
$httpheader[] = 'CLIENT-IP: ' . $proxy[0]; //模拟ip
} else {
$httpheader[] = 'X-FORWARDED-FOR: ' . $_SERVER['REMOTE_ADDR']; //模拟ip
$httpheader[] = 'CLIENT-IP: ' . $_SERVER['REMOTE_ADDR']; //模拟ip
}
if ($header) {
curl_setopt($curl, CURLOPT_HEADER, TRUE); //获取响应头信息
}
if ($userAgent) {
$httpheader[] = 'User-Agent: ' . $userAgent; //模拟用户浏览器信息
} else {
$httpheader[] = 'User-Agent: ' . (!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36');
}
$httpheader[] = 'Host: ' . @parse_url($url)['host'];
curl_setopt($curl, CURLOPT_HTTPHEADER, $httpheader); //模拟请求头
curl_setopt($curl, CURLOPT_TIMEOUT, 10); //只需要设置一个秒的数量就可以
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //返回字符串,而非直接输出到屏幕上
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); //跟踪爬取重定向页面
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_ENCODING, ''); //解决网页乱码问题
// 执行这个请求
$ret = curl_exec($curl);
if ($header) {
$headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
$header = substr($ret, 0, $headerSize);
$body = substr($ret, $headerSize);
$ret = array();
$ret['header'] = $header;
$ret['body'] = $body;
}
curl_close($curl);
return $ret;
}
// xml转数组
function xml_array($xml)
{
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring), true);
return $val;
}
// 数组转xml
function array_xml($arr)
{
$xml = "<xml>";
foreach ($arr as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . array_xml($val) . "</" . $key . ">";
} else {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
// 对数组排序
function arg_sort($para) {
ksort($para);
reset($para);
return $para;
}
]]><button open-type="getUserProfile" bindtap="getUserProfile"> 获取头像昵称 </button>
<button bindtap='onLogin'>授权登录</button>
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button>
server.js
// 服务接口地址
const base = 'http://localhost/';
// 开放接口配置
export default{
apiUrl:base + 'api.php'
}
login.js
//加载公共api文件server.js
import API from '../../config/server.js'
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function () {
this.userLogin();
var uid = wx.getStorageSync('uid');
console.log(uid);
},
userLogin(){
if(!wx.getStorageSync('uid')){
onLogin()
}else{
wx.request({
url: API.apiUrl,
method: 'post',
data: {act: 'isUser',id: wx.getStorageSync('uid')},
success: function(res){
if(res.data.code == -1){
onLogin()
}else{
wx.checkSession({
success () {
//session_key 未过期,并且在本生命周期一直有效
console.log('已登录');
var pages = getCurrentPages() //获取加载的页面
var currentPage = pages[pages.length-1] //获取当前页面的对象
var url = currentPage.route //当前页面url
var options = currentPage.options //如果要获取url中所带的参数可以查看options
console.log(url)
if(url.indexOf('/login') != -1){
wx.navigateBack({
delta: 2
})
}
},
fail () {
// session_key 已经失效,需要重新执行登录流程
onLogin() //重新登录
console.log('未登录');
}
})
}
}
})
}
},
onLogin() {
wx.login({
success (res) {
if (res.code) {
//发起网络请求
wx.request({
url: API.apiUrl,
method: 'post',
data: {
act: 'onLogin',
code: res.code
},
success:function(res){
console.log(res.data)
if(res.data.code == 0){
wx.setStorage({key: 'uid',data: res.data.id})
}else{
wx.showToast({
title: '获取用户id失败',
icon: 'error'
})
setTimeout(() => {
this.onLogin();
}, 1500);
}
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
},
getUserProfile(e){
wx.getUserProfile({
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log(res.userInfo)
wx.setStorage({key: 'userInfo',data: res.userInfo})
}
})
},
getPhoneNumber (e) {
console.log(e.detail.code)
wx.request({
url: API.apiUrl,
method: 'post',
data: {
act: 'getPhone',
code: e.detail.code
},
success:function(res){
console.log(res.data)
if(res.data.code != 0){
wx.showToast({
title: res.data.msg,
icon: 'error'
})
}else{
wx.setStorage({key: 'phone',data: res.data.phone})
}
}
})
}
})
api.php
<?php
header('content-type: application/json;charset=utf-8');
require 'common.php';
$post = $_POST;
$data = ['code' => -1,'msg' => '获取失败'];
if(empty($post)){
$post = json_decode(file_get_contents('php://input'),true);
}
switch($post['act']){
case 'onLogin':
if(!preg_match('/\w/',$post['code'])){
$data['msg'] = 'code格式错误';
break;
}
$code2Session = get_curl("https://api.weixin.qq.com/sns/jscode2session?appid={$config['appId']}&secret={$config['appSecret']}&js_code={$post['code']}&grant_type=authorization_code");
$code2Session = json_decode($code2Session,true);
if(isset($code2Session['errcode']) && $code2Session['errcode'] != 0){
$data['msg'] = '登录失败';
}else{
$data = ['code' => 0,'msg' => '登录成功'];
$row = getOne("select id from userlist where openid='{$code2Session['openid']}'");
if($row){
$data['id'] = $row['id'];
}else{
$res = insert('userlist',['nickname' => '','avatar_url' => '','phone' => '','login_time' => time(),'openid' => $code2Session['openid']]);
$data['id'] = $res;
}
}
break;
case 'getPhone':
if(!preg_match('/\w/',$post['code'])){
$data['msg'] = 'code格式错误';
break;
}
$getAccessToken = get_curl("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$config['appId']}&secret={$config['appSecret']}");
$getAccessToken = json_decode($getAccessToken,true);
$getPhoneNumber = get_curl("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={$getAccessToken['access_token']}",json_encode(['code' => $post['code']]));
$getPhoneNumber = json_decode($getPhoneNumber,true);
if($getPhoneNumber['errcode'] == 0){
$data['phone'] = $getPhoneNumber['phone_info']['purePhoneNumber'];
}
break;
}
echo json_encode($data);
]]>index.wxml
<view>
<text>{{name}}</text>
</view>
index.js
onLoad:function(options){
//页面加载完成之后,发送请求获取json数据,options为页面跳转所带来的参数
var that = this;
wx.request({
url: '接口地址',
method: 'get',
dataType: 'json',
data: {id: 1},
success:function(res){
console.log(res.data);
that.setData({
name: res.data.name
})
},
fail:function(){
console.log('请求失败');
}
})
}
]]>薅羊毛拼团商城V2.7.5小程序功能模块,无授权,包更新,包含薅羊毛拼团分销插件、购买有小群,可以开源,这个是完整包!新版更新了:修复问题 无需更新小程序
测试环境:系统环境:CentOS Linux 7.6.1810 (Core)、运行环境:宝塔 Linux v7.0.3(专业版)、网站环境:Nginx 1.15.10 + MySQL 5.6.46 + PHP-7.1 / PHP-5.6、常见插件:ionCube ;fileinfo ; redis ; Swoole ; sg11
]]>1、什么是学法减分
“学法减分”是多个城市为了贯彻落实公安交通管理局“接受教育减免道路交通安全违法行为记分”改革的服务措施,提升机动车驾驶员交通安全意识所推广的一项重大措施。
机动车驾驶员参加公安机关交通管理部门组织的道路交通安全法律、法规和相关知识学习、考试或者交通安全公益活动,达到要求的,可以申请减免现有累计记分中的记分分值,最高减免6分。
2、网上学习考试
网上学习可以登录交管123进行查看,按照流程操作即可。如果在答题的过程中,有遇到不会的题目,可以搜索小程序“学法减分助手pro”进行辅助学习,拍照上传自动识别并返回对应的参考答案。
网上学习需要在3日内累计学习满30分钟,每次的学习时间必须连续满5分钟,完成学习后在7个工作日内申请参加考试,考试合格的,一次减免1分,一个记分周期内最高可减免6分。
网上学习考试时间最高为20分钟,每次答题时长是60秒。系统将随即从题库中抽取20道题作为考试题,题型有判断题、单项选择题、多项选择题。
答对18题以上即视为合格,答错或超时未答的题目数累计达3题的,系统自动判定为考试不合格并会退出考试,考试未通过的可以在24小时内申请补考,最多可补考2次。
当然,如果你担心考不过,你可以尝试今天上线的这款小程序,微信搜索 “学法减分助手PRO”权威题库,拍照搜题,全国通用。
]]>交管推出个学法减分,每个驾驶员可以把被扣的6分,以看视频答题的形式学习回来,然后答题这个一共二十道题每道题60秒,有好多人不会,用咱们的小程序就可以模拟练习强化练习,还有拍照识别题目找到正确答案!
点击12123 点击学法减分,之后申请学法减分网上学习,审核通过后开始30分钟的学习,学习通过后点击进入考试。
答题过程中注意题库选项的顺序和12123APP的选项顺序完全一致,提示答案是什么就选什么 ,无脑选
]]>