找到
48
篇与
技术文章
相关的结果
- 第 4 页
-
夏日php+mysql新闻管理系统 本程序是夏日php+mysql新闻管理系统,由夏日博客独立设计完成,前台页面美观,后台程序精简,整体源码结构非常简洁,可以进行后台独立管理。 本程序旨在帮助php新手用户进行研究学习使用,现最新版本为 v1.2,满足基本新闻系统的要求,所拥有新闻最基本的功能 :1,网站全局的设置 2,新闻无限分类增删改查 3,新闻系统的管理 4,内容页生成静态页面(批量及分段生成)。 5,单独管理系统单页。 本程序源码完全开源免费,程序你可以进行随意修改使用,但如果要进行商业用途,出现的一切后果由使用者负责! 使用说明:手动配置mysql数据库文件 include/config.php,导入根目录下phphtml.sql数据库。 后台管理:你的网址/新闻系统目录/admin/AdminLogin.php 用户名:admin,密码:admin,正常使用时建议更改后台登陆地址。 luamm5ii.png图片 下载地址:https://neictop-1256272185.cos.ap-guangzhou.myqcloud.com/2024/03/28/1711593601.ra 提取码: -
新骆驼IPTV完美版源码附加超详细的搭建教程 适合于安卓端+电视盒子端的电视直播软件一直很火,这里就弄一个比较详细的文字教程吧,源码也会奉上,包含后端源码+前端APP源码,在文末查看即可。 这里分享的新骆驼IPTV是完美版本的,EPG、会员管理、套餐管理、天气之类的统统都有,不是网上流传的那种不完整版,这个是亲测可用的,余生的云梦TV就是用这套源码搭建的。 liaf1f4c.png图片 后台搭建 首先登录宝塔面板,将骆驼IPTV的后端源码上传至服务器并进行解压。(iptv.zip文件即为后端源码) liaf1z9n.png图片 添加域名并将其根目录绑定到iptv后端源码的文件夹,数据库选择MySQL,PHP版本我这里选择的是7.1。 liaf2ph2.png图片 接着直接修改 config.php 里的数据库信息,修改里面的数据库名、数据库密码、数据库账号。 liaf3112.png图片 接着上传数据库文件,在宝塔面板中点击数据库 --- 导入 --- 本地上传 --- 选择数据库文件上传 --- 上传完成后点击导入即可。(iptv.sql即为数据库文件) liaf3901.png图片 这些都配置完成后就可以输入域名访问iptv管理系统的后台了,安全码默认为:123456,用户名默认为:admin,密码默认为:123456。 这个数据库文件直接用的是 云梦TV的,用户、直播源之类的数据都存在,不过用户数据没什么用,大家直接在后台删除就是了。 liaf3nzh.png图片 APP设置 既然后台搭建完后,就准备修改APP了,在修改APP之前,先在后台设置一下。 点击 系统管理 --- APP设置 ---将里面的 应用名 和 应用包名改成自己的,这里到时候需要和APP中填写一致,否则APP无法正常使用。 应用名这里我改成了 极梦TV,应用包名改成了 cn.jmtv.new,这里大家自行修改即可。 liaf3z2c.png图片 接下来就是对接APP了,首先需要在手机上安装 MT管理器 ,然后对 APP 进行一个修改。 第一步:用 MT管理器 打开指定的 APK 文件。(即:云梦TV的安装包) liaf4bc1.png图片 主要修改的有三个文件 AndriondManifest.xml、classes.dex、ressources.arsc。 第二步:首先先在 AndriondManifest.xml 中修改应用包名,将 云梦TV 默认的 cn.ymtv.new 修改成你在后台 系统设置 --- APP设置中自定义的那个应用包名。 操作步骤:点击 AndriondManifest.xml --- 点击 反编译 --- 然后修改里面的 cn.ymtv.new --- 修改完成后点击保存 --- 保存时选择在压缩文件中更新它。 liaf4r99.png图片 第三步:接着在 ressources.arsc 中修改APP的软件名,将 云梦TV 改成自定义的名称。 操作步骤:点击 ressources.arsc 选择 Arsc编辑器 --- 点击 字符常量池 --- 点击右上角的按钮选择过滤 --- 在里面输入 云梦TV 点击确定 --- 查找完成后将其修改成自定义的名称 --- 修改完成后 保存 即可。 liaf57a5.png图片 第四步:在 classes.dex 中修改对接的网址,将 tv.wuying521.cn 修改成自定义的网址。 操作步骤:点击 classes.dex 选择 Dex编辑器++ --- 点击搜索 --- 点击发起新搜索 --- 查找内容为:tv.wuying521.cn --- 查找完成后将其修改成自己的域名即可。 注:默认是http://,如果你是https://就需要进行修改。 liaf6r1h.png图片 第五步:修改APP图标,APP图标在 res文件夹下的 drawable-hdpi 文件夹中,那个 icon.png 文件即为图标文件,大家自行替换即可,这里我就不替换了。 liaf74rj.png图片 这样就完全修改完成了,如果在安装时提示签名不可用,可以通过 MT管理器将 APP 进行一个签名,点击APK文件 --- 点击功能 --- 点击 APK 签名 --- 然后点击确定 --- 签名完成后就会生成一个新的安装包。 liaf7qek.png图片 到这里就已经完全可以了,大家可以将自己修改的APP安装试一下是否可以和后端正常连接。 这种软件最重要的就是直播源,关于直播源本站也是会定期更新的,感兴趣的可以点击下方连接进行查看。http://jiexi.bulisite.top/tvlive.txt 源码教程下载:链接: https://pan.baidu.com/s/1Hbo554Bm-MmCQI5gBCE6iw?pwd=ay3e 提取码: ay3e -
推荐几个免费高质量的AI自动抠图工具网站 lgk6fw5y.png图片 1.BgSub 官网:https://bgsub.cn 消除或者替换图像背景,无需上传图像。 2.Photopea | Online Image Editor 官网:https://www.photopea.com 3.在线抠图软件_AI抠图证件照换底色 – 稿定抠图 官网:https://koutu.gaoding.com 4.Remove Background from Image – remove.bg 官网:https://www.remove.bg 5.比ps抠图更加智能的在线抠图软件 – 改图神器 官网:https://img.logosc.cn/remove-bg -
HTML5自适应全屏幕视频背景(背景跟随滚动) HTML5自适应全屏幕视频背景(背景跟随滚动) 演示运行地址:https://wow.techbrood.com/fiddle/89 https://wow.techbrood.com/fiddle/89 <!DOCTYPE html><!-- This web page is copied by "https://bazhan.wang" --><html><head><meta charset="utf-8"> <style> h1 { margin: 0; color: red; } video { position: fixed; right: 0; bottom: 0; min-width: 100%; min-height: 100%; width: auto; height: auto; z-index: -100; background-size: cover; } </style> </head> <body> <video src="./bg.mp4" autoplay loop muted ></video> </body></html> -
JS操作HTML页面内容 innerText:普通标签内容(自身文本与所有子标签文本) innerHTML:包含标签在内的内容(自身文本及子标签的所有) value:表单标签的内容 outerHTML:包含自身标签在内的内容(自身标签及往下的所有) <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>JS处理页面内容</title> <style> div { width: 100px; height: 100px; background-color: cyan; margin-top: 15px; } </style> </head> <body> <div class="d1">001</div> <div class="d2">002</div> <div class="d3">003</div> <div class="box"></div> </body> <script> // 先获取页面元素 var d1 = document.querySelector('.d1'); var d2 = document.querySelector('.d2'); var d3 = document.querySelector('.d3'); // ① 操作文本内容 var text = d1.innerText; // 获取内容 console.log(text); // 修改(删除)内容 d1.innerText = ""; d1.innerText = "修改后的文本内容"; // ② 操作子标签 // 获取 var html = d2.innerHTML; console.log(html) // 修改 d2.innerHTML = "<b>加粗的文本</b>"; // 可以解析html语法的代码 // d2.innerText = "<b>加粗的文本</b>"; // 了解 console.log(d2.innerHTML); // 只是标签内部的子标签与子内容 console.log(d2.outerHTML); // 不仅包含标签内部的子标签与子内容,还包含自身标签信息 // ③ 操作页面样式 // 获取 ?? var bgColor = d3.style.backgroundColor; // 只能获取行间式 console.log(bgColor); // 修改 d3.style.backgroundColor = "yellow"; // 只能修改行间式 // 问题: 那用内联外联设置的样式如何获取 // 内联与外联设置的样式叫: 计算后样式 // getComputedStyle(目标标签, 伪类(null填充)).具体的样式 bgColor = window.getComputedStyle(d3, null).backgroundColor; // 兼容性较差 console.log(bgColor); // 可以获取计算后样式, 也可以获取行间式, 但它为只读 bgColor = getComputedStyle(d3, null).getPropertyValue('background-color'); // 兼容性较好 console.log(bgColor); // 一些不常用的属性会出现浏览器之间的兼容问题, 通过添加前缀来处理 console.log(d3.style); // chrome: -webkit- // ie: -ms- // opera: -o- </script> <script> // 需求: box的颜色通过点击在cyan与red之间切换 var box = document.querySelector('.box'); box.onclick = function () { var bgColor = getComputedStyle(this, null).backgroundColor; console.log(bgColor); // 要注意计算后样式获取的结果, 以及结果具体的字符串格式 if (bgColor == 'rgb(0, 255, 255)') { this.style.backgroundColor = 'red'; } else { this.style.backgroundColor = 'cyan'; } } </script> </html>JS操作页面样式 读写style属性样式 div.style.backgroundColor = 'red'; 1.操作的为行间式 2.可读可写 3.具体属性名采用小驼峰命名法只读计算后样式 推荐 getComputedStyle(页面元素对象, 伪类).getPropertyValue('background-color'); 不推荐getComputedStyle(页面元素对象, 伪类).backgroundColor;// IE9以下 页面元素对象.currentStyle.getAttribute('background-color'); 页面元素对象.currentStyle.backgroundColor; 1.页面元素对象由JS选择器获取 2.伪类没有的情况下用null填充 3.计算后样式为只读 4.该方式依旧可以获取行间式样式 (获取逻辑最后的样式)结合 css 操作样式 页面元素对象.className = ""; // 清除类名 页面元素对象.className = "类名"; // 设置类名 页面元素对象.className += " 类名"; // 添加类名实例1,JS事件控制标题栏 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>js事件控制标题栏</title> <style> .part1 div { width: 100px; height: 30px; text-align: center; line-height: 30px; float: left; cursor: pointer; } .part1 { overflow: hidden; } h2 { height: 30px; background-color: cyan; } </style> </head> <body> <div class="part1"> <div class="b1">标题栏</div> <div class="b2">标题栏</div> <div class="b3">标题栏</div> <div class="b4">标题栏</div> </div> <h2></h2> </body> <script> /* var b1 = document.querySelector('.b1'); // 鼠标悬浮事件 b1.onmouseenter = function () { console.log("鼠标悬浮上了"); // 悬浮上后,该标签的字体颜色变化橘色 this.style.color = "#FF6700"; } // 需求并非为鼠标移走,去除颜色 b1.onmouseleave = function () { this.style.color = "#000"; } */ </script> <script> // 制作数据 var data = ["标题1", "标题2", "标题3", "标题4"]; var divs = document.querySelectorAll('.part1 div'); console.log(divs); // 循环绑定 => 会出现变量(i)污染 for (let i = 0; i < divs.length; i++) { divs[i].onmouseenter = function () { // 打印自身索引值 console.log(i); // 将自身颜色变为橘色,其他兄弟颜色变为黑色 // 就是i为橘色, 非i为黑色 changeColor(i); // 悬浮内容 changeContent(i) } } // console.log(i); // 自定义的修改颜色的方法 function changeColor(index) { for (let i = 0; i < divs.length; i++) { // 先不管三七二十一,全改成黑色 divs[i].style.color = "black"; // 如果是目标选中标签,它的颜色再重新设置为橘色 if (i == index) { divs[i].style.color = "#FF6700"; } } } var h2 = document.querySelector('h2'); // 修改内容 function changeContent(index) { h2.innerText = data[index]; } </script> </html>实例2,JS控制类名 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>js控制类名</title> <style> .y { width: 100px; height: 100px; background-color: red; border-radius: 50%; } .f { width: 100px; height: 100px; background-color: orange; } .g { display: none; } .ttt { } </style> </head> <body> <ul> <li class="l1">圆</li> <li class="l2">方</li> <li class="l3">滚</li> </ul> <div></div> </body> <script> var box = document.querySelector('div'); var l1 = document.querySelector('.l1'); l1.onclick = function () { box.className = 'y' } var l2 = document.querySelector('.l2'); l2.onclick = function () { box.className = 'f' } var l3 = document.querySelector('.l3'); l3.onclick = function () { box.className = 'g'; // box.className = ""; // 清除类名 // box.className = 'y f'; // box.className += " ttt"; } </script> </html> 事件的绑定与取消 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>事件的绑定与取消</title> <style> .box { width: 100px; height: 100px; background-color: orange; border-radius: 50%; } </style> </head> <body> <div class="box"></div> <div class="box"></div> <div class="box"></div> <div class="begin">开始</div> <div class="event_on1">事件的绑定1</div> <div class="event_on2">事件的绑定2</div> </body> <script> // 每一个box点击都会toggle颜色, 当颜色都变成黑色, 取消所有点击事件, // 点击开始, 重新获得点击事件(所有状态应该重置) var beginBtn = document.querySelector('.begin'); var boxs = document.querySelectorAll('.box'); // 定义一个count计算器,计黑的个数 var count = 0; // 启动服务 beginBtn.onclick = init; // 开始功能 // function beginAction() { // // 让所有box拥有点击事件 // } // box点击切换颜色 function toggleColor() { // console.log(this) if (this.style.backgroundColor == "orange") { this.style.backgroundColor = "black"; count++; } else { this.style.backgroundColor = "orange"; count--; } // 检测是否需要结束 count == 3 && overAction(); } // 结束功能, 取消所有box点击事件 function overAction() { for (var i = 0; i < boxs.length; i++) { boxs[i].onclick = null; } } // 重置功能, 并让所有box拥有点击事件 function init() { for (var i = 0; i < boxs.length; i++) { boxs[i].style.backgroundColor = "orange"; boxs[i].onclick = toggleColor; } // 计算器重置 count = 0; } // 启动服务 // init(); </script> <script> var event_on1 = document.querySelector('.event_on1'); // 事件绑定的第一种方式 event_on1.onclick = function () { console.log(1) }; event_on1.onclick = function () { console.log(2) } // 事件绑定的第二种方式 var event_on2 = document.querySelector('.event_on2'); // 可以为一个元素绑定多个事件, 按绑定顺序依次执行 event_on2.addEventListener('click', function () { console.log("a") }); var action = function () { console.log("b") } event_on2.addEventListener('click', action); // 如何取消事件 event_on2.removeEventListener('click', action) </script> </html> 复习总结并延伸 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>复习预习</title> <style> [key='value'] { color: #0f8209; } </style> </head> <body> <div class="ele" alert="OK">div div div</div> </body> <script> // 1.面向对象js // ES5 // 普通的单一对象 var obj = { // 普通对象的属性 key: "value", fn: function () { console.log("普通对象的方法") } }; console.log(obj.key); console.log(obj["key"]); // 1.key的类型为字符串类型 // 结论: // js支持的标识符可以省略引号, 反之不可以省略 // 不支持的标识符访问方式: 不可以采用.语法,需要采用[]语法,eg:obj["background-color"] var obj1 = { "name": "obj1", // key有时候会出现js不能直接支持的标识符书写方式 // 需求: obj1用来描述页面标签的各种颜色 color: "red", // "color": "red", "background-color": "yellow" } console.log(obj1.name); console.log(obj1["name"]); console.log(obj1.color); // obj1.background = 12; // color = 10; console.log(obj1["background-color"]); // 2. 对象可以任意添加或删除属性 var obj2 = { name: "obj2" }; console.log(obj2); // 删除属性 delete obj2.name; console.log(obj2); // 添加属性 obj2.age = 8; console.log(obj2); // 拓展: 获取的页面元素就是标签对象, 可以对其添加任意属性 var ele = document.querySelector('.ele'); console.log(ele.info); // 直接使用无值, 原因ele并没有添加该属性 ele.info = "添加的属性信息"; // 添加属性 console.log(ele.info); // 添加属性后就可以正常方式添加的属性值 delete ele.info; // 删除操作 console.log(ele.info); // 删除后属性又会消失 // 构造函数 function Perple(name, age) { this.name = name; this.age = age; this.fn = function () { console.log("fn") } } // 实例化对象 var p = new Perple("张三", 18); p.fn(); // ES6 class Student { constructor (name, age) { this.name = name; this.age = age; } fn () { console.log("fn") } } var s = new Student("张三", 18); s.fn(); </script> <script> // getElementById只能由document调用 var ele = document.getElementsByClassName("ele")[0]; console.log(ele); ele = document.querySelector(".ele"); console.log(ele); ele = document.querySelectorAll(".ele")[0]; console.log(ele); // 该添加属性的方式只映射到js代码中 ele.index = 123; console.log(ele.index); // js如何操作元素(页面标签)的全局属性, 映射到html代码中 ele = document.querySelector('[alert]'); // 通过全局属性获取元素 console.log(ele); // 获取全局属性值 var info = ele.getAttribute('alert'); console.log(info); // 修改全局属性值 ele.setAttribute('alert', 'no ok'); // 添加全局属性值(映射到html代码中) => 结合CSS来控制页面标签的样式 ele.setAttribute('key', 'value'); </script> </html> 小练习 开灯关灯封装 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>开灯关灯封装</title> <style type="text/css"> .wrap { width: 280px; height: 280px; margin: 100px auto; } .wrap div { width: 55px; height: 55px; margin: 1px 1px 0 0; /*background-image: url(img/off.png);*/ background-color: black; float: left; border-radius: 20%; } .begin { width: 80px; height: 35px; background-color: dodgerblue; font: normal 20px/ 35px "STSong"; text-align: center; color: white; margin: -50px auto; border-radius: 10px; cursor: pointer; } .begin:active { background-color: deepskyblue; } </style> </head> <body> <div class="wrap"> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> </div> <div class="begin" onclick="beginGame()">开始</div> </body> <script type="text/javascript"> // 设定运用到的全局变量 var divs = null; // 存放25盏灯 var count = 0; // 记录关闭的灯的盏数 // 游戏结束功能 function gameOver() { if (count == divs.length) { var timeout = setTimeout(function() { alert("游戏结束!"); // 清除定时器 clearTimeout(timeout); }, 10); } } // 初始化操作功能 function initGame() { divs = document.querySelectorAll('.wrap div'); count = 0; for (var i = 0; i < divs.length; i++) { // 1、设置背景颜色(设置灯初始状态) // divs[i].style.backgroundImage = 'url("img/on.png")'; divs[i].style.backgroundColor = "yellow"; // 2、给每盏灯按顺序编号 divs[i].index = i; // 3、给每盏灯绑定点击事件 divs[i].onclick = eleOnclick; } } // 点击事件功能 function eleOnclick() { // 保存但前被点击的索引,以便查找出周围的元素 var index = this.index; // 自身 changeBGImg(this); // 上 if (index >= 5) { changeBGImg(divs[index - 5]); } // 下 if (index < 20) { changeBGImg(divs[index + 5]); } // 左 if (index % 5 != 0) { changeBGImg(divs[index - 1]); } // 右 if (index % 5 != 4) { changeBGImg(divs[index + 1]); } // 点击结束后检查游戏是否结束 gameOver(); } // 切换背景图片功能 function changeBGImg(ele) { // var tempImg = ele.style.backgroundImage; var tempColor = ele.style.backgroundColor; if (tempColor == "yellow") { ele.style.backgroundColor = 'black'; count++; } else{ ele.style.backgroundColor = 'yellow'; count--; } } // 游戏开始功能 function beginGame() { initGame(); } </script> </html>小练习分析 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>事件高级</title> <style> .box { width: 350px; height: 350px; margin: 100px auto 0; } .box div { width: 70px; height: 70px; background-color: yellow; border-radius: 50%; float: left; } </style> </head> <body> <div class="box"> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> </div> </body> <script> var divs = document.querySelectorAll(".box div"); // 需要注意的点: 我们需要修改背景颜色, 背景颜色是计算后样式, // 那么getComputedStyle()获取颜色的格式需要手动处理, 而行间式不需要处理, // 且行间式不仅可以设置, 还可以修改 => 将原本计算后样式设置的更改为行间式 // 通过循环利用行间式将所有背景颜色重置 for (let i = 0; i < divs.length; i++) { divs[i].style.backgroundColor = "black"; } // 游戏的实现 for (let i = 0; i < divs.length; i++) { // 循环绑定 (问题: 变量污染) divs[i].onclick = function () { console.log(i) // toggle 颜色 => 抽离出toggle颜色的方法 // 修改自身 toggleBGColor(this); // 修改上下左右, 考虑问题, 不存在的兄弟方位 // 上, 关系i-5, 第一排没有上 i < 5 => 对立面 i >= 5均有上 if (i >= 5) { var topEle = divs[i - 5] toggleBGColor(topEle); } // 下, 关系i+5, 最后一排没有下, 对立面 i < 20 i < 20 && toggleBGColor(divs[i + 5]); // 左, 关系i-1, 第一列没有左, 对立面 i % 5 != 0 i % 5 != 0 && toggleBGColor(divs[i - 1]); // 右, 关系i+1, 最后一列没有右, 对立面 i % 5 != 4 i % 5 != 4 && toggleBGColor(divs[i + 1]); } } function toggleBGColor(ele) { var bgColor = ele.style.backgroundColor; if (bgColor == 'black') { ele.style.backgroundColor = "yellow"; } else { ele.style.backgroundColor = "black"; } } </script> </html> -
利用ESP8266-12E破解钉钉WIFI打卡 钉钉越来越普及,大量的公司都在采用钉钉,同时,使用钉钉的考勤方式。 钉钉打卡方式存在一个WIFI打卡模式,需要连接指定WIFI进行打卡,识别的方式是WIFI的名称和MAC地址, ESP8266-12E是安信可官方推出的wifi模组,可以自建AP,同时还可以修改mac地址,所以就试了试使用ESP8266自建的AP来破解打卡,完美破解。 下面试破解的代码,用的arduino开发的,arduino如何安装,可看我另外一篇文章: Arduino-IDE搭建ESP8266开发环境 Arduino-IDE搭建ESP8266开发环境 代码是复制的太极创客8266 AP模式的代码,增加了设置mac地址 #include <ESP8266WiFi.h> #define AP_ssid "XXXXXXXX" //这里改成公司的WIFI名称 #define password "XXXXXXXX" //密码随便,一样不一样都行 uint8_t macAddr[6] = {0x00,0x00,0x00,0x00,0x00,0x00}; //改成公司的路由器mac地址 bool flag; void setup() { // 启动串口通讯 Serial.begin(9600); Serial.println(); //设置为接入点模式 WiFi.mode(WIFI_AP); //启动AP,并设置账号和密码 Serial.printf("设置接入点中 ... "); //启动校验式网络(需要输入账号密码的网络) WiFi.softAP(AP_ssid, password); //监控状态变量result flag = WiFi.softAP(AP_ssid, password); if (flag) { Serial.println(""); // 通过串口监视器输出信息 Serial.print("当前工作模式:"); // 告知用户设备当前工作模式 Serial.println(WiFi.getMode()); Serial.print("接入点名字:"); Serial.println(AP_ssid); // 告知用户建立的接入点WiFi名 Serial.print("接入点密码:"); Serial.println(password); // 告知用户建立的接入点WiFi密码 Serial.println("接入点模式成功开启"); //不输入参数获取MAC地址 //Serial.printf("MAC地址为 %s\n", WiFi.softAPmacAddress().c_str()); //输入参数获取MAC地址 //WiFi.softAPmacAddress(macAddr); wifi_set_macaddr(SOFTAP_IF, macAddr); delay(1000); WiFi.softAPmacAddress(macAddr); Serial.printf("MAC地址为 %02x:%02x:%02x:%02x:%02x:%02x\n", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]); } else { //若没有开启成功 Serial.println("开启失败"); } Serial.println("初始化结束"); } void loop() {} -
利用ESP8266制作钉钉WIFI打卡神器升级版 之前研究的一版破解WiFi打卡的工具,但是WIFI名称、密码、MAC地址全部写死在程序里了,改动需要修改代码重新下载。升级了下网页配置功能 利用自己之前学的一点html知识,结合做前端朋友的帮助,写了一个配网页面,配置时,会对密码和MAC地址进行校验,密码长度必须超过8位或者不输入,MAC先进行格式校验,后对每两个数据进行十六进制校验,通过后,修改所有参数,通过EEPROM库将数据保存在flash。然后重启设备,重新启动后读取配置信息,开启AP并修改MAC地址 下面是最新版的代码,有需要的可以自己下载arduino,买个ESP8266-12F模块,下载进去即可使用 #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <EEPROM.h> //首页html const char* home_page_str = "<html>\n <head>\n <meta charset=\"utf-8\" name=\"viewport\" content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n <title>配置页面</title>\n <script src=\"config.html\" type=\"text/javascript\" charset=\"utf-8\"></script>\n <style>\n .formBox{\n width: 100%;\n float: left;\n margin: 0 auto\n }\n .formBox > form {\n width: 80%;\n margin: 0 auto;\n }\n form > input{\n width: 100%;\n height: 40px;\n }\n </style>\n </head>\n <body>\n <div align=\"center\">\n <h1>欢迎使用WIFI打卡神器</h1>\n \n </div><br><br>\n <div align=\"center\" class=\"formBox\">\n <form action=\"/result.html\">\n <h3>WIFI名称:</h3>\n <input type=\"text\" name=\"ssid\" value=\"\" required><br>\n <h3>WIFI密码:</h3>\n <input type=\"text\" name=\"password\" value=\"\"><br>\n <h3>MAC地址:</h3>\n <input type=\"text\" name=\"mac\" value=\"\" required><br>\n <input type=\"submit\" style=\"margin-top: 30px; font-size: 20px;\" value=\"配置\">\n </form> \n </div>\n </body>\n <script>\n \n let {mac,password,ssid} = config;\n document.getElementsByName('mac')[0].value = mac || '';\n document.getElementsByName('password')[0].value = password || '';\n document.getElementsByName('ssid')[0].value = ssid || '';\n \n \n </script>\n</html>"; //定义配置类型 typedef struct { unsigned char Default_Tag;//默认标记 char stassid[32];//定义WIFI名称 char stapsw[64];//定义WIFI密码 uint8_t mac[6]; //定义mac地址 }config_type; //定义默认配置 config_type const Default_Config = { .Default_Tag = 254, .stassid = "www.dzahz.cn\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", .stapsw = {'\0'}, .mac = {0x44,0x55,0xC4,0x37,0xB9,0xC0} }; config_type config; //配置信息 ESP8266WebServer server(80); void setup() { // 启动串口通讯 Serial.begin(115200); Serial.println(); Serial.printf("设置接入点中 ... "); //读取WIFI配置 loadConfig(); if(config.Default_Tag != Default_Config.Default_Tag) //判断是否初始化配置 { config = Default_Config; saveConfig(); } Serial.printf("ssid:%s\n",config.stassid); Serial.printf("pasword:%s\n",config.stapsw); Serial.printf("mac:%x:%x:%x:%x:%x:%x\n",config.mac[0],config.mac[1],config.mac[2],config.mac[3],config.mac[4],config.mac[5]); //启动AP delay(500); wifi_set_macaddr(SOFTAP_IF, config.mac); delay(500); WiFi.mode(WIFI_AP); if(config.stapsw[0] == '\0') WiFi.softAP(config.stassid, NULL); else WiFi.softAP(config.stassid, config.stapsw); //设置wedserver回调 server.on("/",HTTP_GET, homepage); server.on("/result.html",HTTP_GET, config_result); server.on("/config.html",HTTP_GET, query_par); server.onNotFound(handleNotFound); //启动服务 server.begin(); } //十六禁止格式判断,传输数据指针 bool hex_jud(char *str) { if((str[0] > '9') || (str[0] < '0')) //一个如果不是数字,则判断是否是A-F { if((str[0] > 'F') || (str[0] < 'A')) { if((str[0] > 'f') || (str[0] < 'a')) { return false; } } } if((str[1] > '9') || (str[1] < '0')) //一个如果不是数字,则判断是否是A-F { if((str[1] > 'F') || (str[1] < 'A')) { if((str[1] > 'f') || (str[1] < 'a')) { return false; } } } return true; } /**************************************** *函数名称:saveConfig *函数功能:保存配置信息 *输入参数:无 *输出参数:无 *备 注: *****************************************/ void saveConfig() //保存配置函数 { EEPROM.begin(1024); //申请1024的内存 配置保存在前256 uint8_t *p = (uint8_t *)(&config); for (int i = 0; i < sizeof(config); i++) { EEPROM.write(i, *(p + i)); } EEPROM.commit(); } /**************************************** *函数名称:loadConfig *函数功能:读取配置信息 *输入参数:无 *输出参数:无 *备 注: *****************************************/ void loadConfig() { EEPROM.begin(1024); uint8_t *p = (uint8_t *)(&config); for (int i = 0; i < sizeof(config); i++) { *(p + i) = EEPROM.read(i); } EEPROM.commit(); } //acsii转十六进制格式 uint8_t acsii_hes(char *str) { uint8_t h; uint8_t l; if((str[0] <= '9') && (str[0] >= '0')) h = str[0] - '0'; else if((str[0] <= 'F') && (str[0] >= 'A')) h = str[0] - 'A' + 10; else if((str[0] <= 'f') && (str[0] >= 'a')) h = str[0] - 'a' + 10; if((str[1] <= '9') && (str[1] >= '0')) l = str[1] - '0'; else if((str[1] <= 'F') && (str[1] >= 'A')) l = str[1] - 'A' + 10; else if((str[1] <= 'f') && (str[1] >= 'a')) l = str[1] - 'a' + 10; return (h << 4) | l; } //自定义主页访问处理函数 void homepage() { server.send(200, "text/html", home_page_str); Serial.println("用户访问了主页"); } //查SSID接口 void query_par() { char str[256]; sprintf(str,"const config = {\"ssid\":\"%s\",\"password\":\"%s\",\"mac\":\"%2X:%2X:%2X:%2X:%2X:%2X\"}",config.stassid,config.stapsw,config.mac[0],config.mac[1],config.mac[2],config.mac[3],config.mac[4],config.mac[5]); server.send(200, "text/html", str); } //查WIFI密码接口 void read_stapsw() { server.send(200, "text/plain", config.stapsw); } //查mac接口 void read_mac() { char str[50]; sprintf(str,"%2X:%2X:%2X:%2X:%2X:%2X",config.mac[0],config.mac[1],config.mac[2],config.mac[3],config.mac[4],config.mac[5]); server.send(200, "text/plain", str); } //配置接口 void config_result() { char ssid[32]; char password[64]; char mac[64]; char str[512]; int len; int i; //取出所有信息 sprintf(ssid,"%s",server.arg("ssid").c_str()); sprintf(password,"%s",server.arg("password").c_str()); sprintf(mac,"%s",server.arg("mac").c_str()); Serial.printf("ssid:%s\n",ssid); Serial.printf("pasword:%s\n",password); Serial.printf("mac:%s\n",mac); //校验密码长度 len = strlen(password); if((len < 8) && (len != 0)) { sprintf(str,"<html><meta charset=\"utf-8\"><body><p>密码长度错误,长度:%d<b></body></html>",len); server.send(200, "text/html",str); return; } //校验MAC格式 len = strlen(mac); Serial.printf("maclen:%d\n",len); if(len != 17) //校验总长度 { server.send(200, "text/html","<html><meta charset=\"utf-8\"><body><p>mac格式错误<b></body></html>"); return; } for(i = 0; i < 5; i++) //校验: { Serial.printf("mac:%d\n",mac[i*3+2]); if(mac[i*3+2] != ':') { server.send(200, "text/html","<html><meta charset=\"utf-8\"><body><p>mac格式错误<b></body></html>"); return; } } for(i = 0; i < 6; i++) //校验是否十六进制 { if(hex_jud(&mac[i*3]) == false) { server.send(200, "text/html","<html><meta charset=\"utf-8\"><body><p>mac格式错误<b></body></html>"); return; } } //保存信息 len = strlen(ssid); for(i = 0; i < 32; i++) //先清除原有配置 config.stassid[i] = 0; for(i = 0; i < len; i++) config.stassid[i] = ssid[i]; len = strlen(password); for(i = 0; i < 32; i++) //先清除原有配置 config.stapsw[i] = 0; for(i = 0; i < len; i++) config.stapsw[i] = password[i]; for(i = 0; i < 6; i++) //十六进制 { config.mac[i] = acsii_hes(&mac[i*3]); } saveConfig(); server.send(200, "text/html", "<html><meta charset=\"utf-8\"><body><p>设置成功,设备重启<b></body></html>"); delay(500); system_restart(); //复位 } // 设置处理404情况的函数'handleNotFound' void handleNotFound() { // 当浏览器请求的网络资源无法在服务器找到时, server.send(404, "text/plain", "404: Not found"); // NodeMCU将调用此函数。 } void loop() { //监听客户请求并处理 server.handleClient(); }