超简单使用elementUI的表单验证,看不懂官方文档的看这里

复杂的官方文档

大家好,编写elementUI时,看到新的element-plus的表单验证部分写的如此的复杂,我下面复制官方文档的表单验证部分的代码。

<template>
  <el-form
    ref="ruleFormRef"
    :model="ruleForm"
    :rules="rules"
    label-width="120px"
    class="demo-ruleForm"
    :size="formSize"
  >
    <el-form-item label="Activity name" prop="name">
      <el-input v-model="ruleForm.name" />
    </el-form-item>
    <el-form-item label="Activity zone" prop="region">
      <el-select v-model="ruleForm.region" placeholder="Activity zone">
        <el-option label="Zone one" value="shanghai" />
        <el-option label="Zone two" value="beijing" />
      </el-select>
    </el-form-item>
    <el-form-item label="Activity time" required>
      <el-col :span="11">
        <el-form-item prop="date1">
          <el-date-picker
            v-model="ruleForm.date1"
            type="date"
            placeholder="Pick a date"
            style="width: 100%"
          />
        </el-form-item>
      </el-col>
      <el-col class="text-center" :span="2">
        <span class="text-gray-500">-</span>
      </el-col>
      <el-col :span="11">
        <el-form-item prop="date2">
          <el-time-picker
            v-model="ruleForm.date2"
            placeholder="Pick a time"
            style="width: 100%"
          />
        </el-form-item>
      </el-col>
    </el-form-item>
    <el-form-item label="Instant delivery" prop="delivery">
      <el-switch v-model="ruleForm.delivery" />
    </el-form-item>
    <el-form-item label="Activity type" prop="type">
      <el-checkbox-group v-model="ruleForm.type">
        <el-checkbox label="Online activities" name="type" />
        <el-checkbox label="Promotion activities" name="type" />
        <el-checkbox label="Offline activities" name="type" />
        <el-checkbox label="Simple brand exposure" name="type" />
      </el-checkbox-group>
    </el-form-item>
    <el-form-item label="Resources" prop="resource">
      <el-radio-group v-model="ruleForm.resource">
        <el-radio label="Sponsorship" />
        <el-radio label="Venue" />
      </el-radio-group>
    </el-form-item>
    <el-form-item label="Activity form" prop="desc">
      <el-input v-model="ruleForm.desc" type="textarea" />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm(ruleFormRef)"
        >Create</el-button
      >
      <el-button @click="resetForm(ruleFormRef)">Reset</el-button>
    </el-form-item>
  </el-form>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'

const formSize = ref('default')
const ruleFormRef = ref<FormInstance>()
const ruleForm = reactive({
  name: 'Hello',
  region: '',
  date1: '',
  date2: '',
  delivery: false,
  type: [],
  resource: '',
  desc: '',
})

const rules = reactive<FormRules>({
  name: [
    { required: true, message: 'Please input Activity name', trigger: 'blur' },
    { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
  ],
  region: [
    {
      required: true,
      message: 'Please select Activity zone',
      trigger: 'change',
    },
  ],
  date1: [
    {
      type: 'date',
      required: true,
      message: 'Please pick a date',
      trigger: 'change',
    },
  ],
  date2: [
    {
      type: 'date',
      required: true,
      message: 'Please pick a time',
      trigger: 'change',
    },
  ],
  type: [
    {
      type: 'array',
      required: true,
      message: 'Please select at least one activity type',
      trigger: 'change',
    },
  ],
  resource: [
    {
      required: true,
      message: 'Please select activity resource',
      trigger: 'change',
    },
  ],
  desc: [
    { required: true, message: 'Please input activity form', trigger: 'blur' },
  ],
})

const submitForm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return
  await formEl.validate((valid, fields) => {
    if (valid) {
      console.log('submit!')
    } else {
      console.log('error submit!', fields)
    }
  })
}

const resetForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.resetFields()
}
</script>

一个简单的表单验证写的这么啰嗦,我就想校验一下登录账号和密码,需要这么麻烦吗?

其实只需要FormInstance就可以实现了。

超简单的写法

对于简单的表单验证,完全不需要上面那么啰嗦。

其实验证是很简单的,只需要写一个验证的数组(rules),并赋值给el-form组件的rule参数即可,如下

<el-form ref="formRef" :model="loginForm" :rules="rules" label-position="top"></el-form>

rules长这样

const rules = ref({
      phone: [
        {required: true, message: '必须输入手机号码', trigger: 'blur'},
        {pattern: /^1[3456789]\d{9}$/, message: '手机号码格式不正确', trigger: 'blur'},
      ],
      password: [
        {required: true, message: '必须输入密码', trigger: 'blur'},
        {min: 6, max: 20, message: '密码长度在 6 到 20 个字符', trigger: 'blur'},
      ]
    })

那你可能会问了,ref是干啥用的啊?

告诉你,ref的目的是为了在提交或者什么操作的时候,手动验证表单,如下。

比如我们有个登录按钮,和登录的方法onLogin()

<el-button type="primary" @click="onLogin(formRef)">登录</el-button>
const onLogin = (form) => {
      form.validate((valid, fields) => {
        if (valid) {
          console.log('登录成功')
        } else {
          console.log('error submit!', fields)
        }
      })
    }

相信小伙伴们已经看明白什么意思了。

简单来说,就是在登录方法里传参传这个ref进去,然后这个ref有validate()方法,通过这个方法就校验了。上面的if else是固定写法。

那么ref这个值是哪来的呢?其实是开头说的FormInstance定义出来的,定义如下:

// 引用
import {FormInstance} from "element-plus"

// 这个是写在setup()里的!!
const formRef = ref<FormInstance>('')

 

 

怎么样,是不是比官方那啰里啰嗦一大串舒服多了?

【分享】词达人做题神器:词达人Lib

有群友在群里推了这个网站,试过之后效果还是不错的。

鉴于我已经不用做词达人了,就发出来分享给有需要的同学。

地址:https://www.cdrlib.xyz/

这个平台不是完全免费的,首次登录会赠送套餐包。所以具体用不用就是各位同学斟酌的事情了。

我测试了几个任务,正确率和分数还是可以接受的,如果是自己选词的任务平台会选择所有词。

下面是我测试的截图,速度挺快,分数也可以接受。

【Java】创建 maven maven-archetype-quickstart 项目报错解决方法

同学们好,没错,因为工作需要,我要开始入坑java了, 希望这次能学会。

创建项目开局就报错,挺离谱的。还好找到了解决办法

1、首先打开maven目录下的conf文件夹里的setting.xml,在其中添加如下仓库位置url(因为默认的是在国外,在这里我们添加阿里云的国内镜像)

直接把以下内容加到</settings>下面就行了

<mirror>
        <id>aliyun-public</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun public</name>
        <url>https://maven.aliyun.com/repository/public</url>
    </mirror>

    <mirror>
        <id>aliyun-central</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun central</name>
        <url>https://maven.aliyun.com/repository/central</url>
    </mirror>

    <mirror>
        <id>aliyun-spring</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun spring</name>
        <url>https://maven.aliyun.com/repository/spring</url>
    </mirror>

    <mirror>
        <id>aliyun-spring-plugin</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun spring-plugin</name>
        <url>https://maven.aliyun.com/repository/spring-plugin</url>
    </mirror>

    <mirror>
        <id>aliyun-apache-snapshots</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun apache-snapshots</name>
        <url>https://maven.aliyun.com/repository/apache-snapshots</url>
    </mirror>

    <mirror>
        <id>aliyun-google</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun google</name>
        <url>https://maven.aliyun.com/repository/google</url>
    </mirror>

    <mirror>
        <id>aliyun-gradle-plugin</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun gradle-plugin</name>
        <url>https://maven.aliyun.com/repository/gradle-plugin</url>
    </mirror>

    <mirror>
        <id>aliyun-jcenter</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun jcenter</name>
        <url>https://maven.aliyun.com/repository/jcenter</url>
    </mirror>

    <mirror>
        <id>aliyun-releases</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun releases</name>
        <url>https://maven.aliyun.com/repository/releases</url>
    </mirror>

    <mirror>
        <id>aliyun-snapshots</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun snapshots</name>
        <url>https://maven.aliyun.com/repository/snapshots</url>
    </mirror>

    <mirror>
        <id>aliyun-grails-core</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun grails-core</name>
        <url>https://maven.aliyun.com/repository/grails-core</url>
    </mirror>

    <mirror>
        <id>aliyun-mapr-public</id>
        <mirrorOf>*</mirrorOf>
        <name>aliyun mapr-public</name>
        <url>https://maven.aliyun.com/repository/mapr-public</url>
    </mirror>

2、在IDEA中依次按照路径file-setting找到maven配置选项(如下图),将如下两项修改:第一项修改为maven解压目录下的conf文件夹里的setting.xml,第二项会自动读取setting.xml文件里的仓库地址(如果未自动读取,检查下自己是否写错了),也可以手动更改。更改完成之后点击Apply-OK。

在下图所示进入Maven->Runner(中文是 运行程序) 然后将下面内容复制粘贴到VM Options(VM选项)当中保存即可。

-Dmaven.multiModuleProjectDirectory=$MAVEN_HOME

-Dmaven.wagon.http.ssl.insecure=true

-Dmaven.wagon.http.ssl.allowall=true

-Dmaven.wagon.http.ssl.ignore.validity.dates=true

 

至此,问题解决。

人生中第一个java项目创建完毕。

转载:https://blog.csdn.net/shyc126/article/details/105822059

Vue3.x 控制台警告 [Violation] Added non-passive event listener to a scroll-blocking ‘touchmove’ event. Consider marking event handler as ‘passive’ to make the page more responsive.

控制台警告信息

[admonition]

[Violation] Added non-passive event listener to a scroll-blocking ‘touchmove’ event. Consider marking event handler as ‘passive’ to make the page more responsive.

[/admonition]

情况说明

以下说明引用至https://stackoverflow.com/questions/39152877/consider-marking-event-handler-as-passive-to-make-the-page-more-responsive/62639220

想了解更多关于这个的问题可以点上面链接进去看原文

For those receiving this warning for the first time, it is due to a bleeding edge feature called Passive Event Listeners that has been implemented in browsers fairly recently (summer 2016). From https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md:

Passive event listeners are a new feature in the DOM spec that enable developers to opt-in to better scroll performance by eliminating the need for scrolling to block on touch and wheel event listeners. Developers can annotate touch and wheel listeners with {passive: true} to indicate that they will never invoke preventDefault. This feature shipped in Chrome 51, Firefox 49 and landed in WebKit. For full official explanation read more here.

其实说白了就是个新特性,似乎是用来提高移动端页面滚动效率的?

我也整不太明白,这也不是个错误,只是个警告。

解决方法非常简单,看下面

解决方法

有两种方法,我倾向于第二种

1、在鼠标滚动方法上加上passive,如下所示

@mouseleave.passive="leave"

2、安装扩展,一劳永逸

npm i default-passive-events -S

安装后,在main.js里引入即可

import 'default-passive-events'

 

(转载)一劳永逸解决Vue sass-loader node-sass node的安装问题

node-sass代码库地址:https://github.com/sass/node-sass

吐槽

我已经被sass这个sb玩意折磨了无数次了,直接npm i sass-loader 就会报错,之前碰巧降版本解决了问题,但是这几天发现降版本也不管用了,百度直接搜错误信息甚至都找不到一个有用的答案。

查了N多资料无果之后我换了种方法,因为要实现sass需要同时有 sass-loader  node-sass   而node-sass一看就和node有关系,我以此为切入点搜索,终于让我找到一个大佬总结的文章。

为了以后不再被这sb玩意折磨,我决定转载一下这个文章。如果能帮到各位,请去给原作者点赞!

见过的错误

1、安装sass-loader后报 TypeError: this.getOptions is not a function

2、安装sass-loader 低版本后报 Syntax Error: Error: PostCSS received undefined instead of CSS string

3、安装node-sass时报 Install fail! RunScriptError: post install error, please remove node_modules before retry!

也许还有其他错误,但是这几个我几乎每次都能遇到。

万能无错版本

大佬总结了一套万能无错版本,但是经过我测试,以下版本对应是最完美的!

重要提醒:一定要先看node版本是不是符合要求,不符合的用下面的方法修改,不然装不上。版本一定得对应!

node 12.x
sass-loader 7.3.1
node-sass 4.14.1

node 16.x
sass-loader 10.0.1
node-sass 6.0.1

node版本对应的node-sass

NodeJS Supported node-sass version Node Module
Node 17 7.0+ 102
Node 16 6.0+ 93
Node 15 5.0+, <7.0 88
Node 14 4.14+ 83
Node 13 4.13+, <5.0 79
Node 12 4.12+, <8.0 72
Node 11 4.10+, <5.0 67
Node 10 4.9+, <6.0 64
Node 8 4.5.3+, <5.0 57
Node <8 <5.0 <57

下面是node-sass和sass-loader推荐对应版本

sass-loader@^4.1.1,node-sass@^4.3.0
sass-loader@^7.0.3,node-sass@^4.7.2
sass-loader@^7.3.1,node-sass@^4.7.2
sass-loader@^7.3.1,node-sass@^4.14.1

安装node-sass和sass-loader的方法

// 以下管理器任选一种,推荐cnpm
npm i node-sass@^4.14.1
cnpm i node-sass@^4.14.1
yarn add node-sass@^4.14.1

npm i sass-loader@^7.3.1
cnpm i sass-loader@^7.3.1
yarn add sass-loader@^7.3.1

查看 node 版本的方法

node -v

修改 node 版本的方法

// 首先安装node版本管理器n
sudo npm install n -g

// 自定义版本号安装
sudo n 版本号  //例如:sudo n 10.16.0 ; 本文推荐 sudo n 12

// 安装稳定版
sudo n stable

// 安装最新版
sudo n latest

简单的CSS3贪吃豆动画

无聊透顶,看到B站有个这动画感觉挺有趣的,自己实现了一下。

没有动力码字了,直接上代码吧,就几句话你们自己粘贴一下马上就能用。

HTML:

<div>
  <div class="dot-up">
  </div>
  <div class="dot-down">
  </div>
</div>

CSS:

.dot-up {
  background-color: #800080;
  width: 100px;
  height: 50px;
  border-radius: 50px 50px 0 0;
  animation: eat-haha-up 1s infinite;
  transform-origin: center bottom;
}

.dot-down {
  background-color: #800080;
  width: 100px;
  height: 50px;
  border-radius: 0 0 50px 50px;
  animation: eat-haha-down 1s infinite;
  transform-origin: center top;
}

@keyframes eat-haha-up {
  0% {
    transform: rotate(0)
  }

  25% {
    transform: rotate(-45deg)
  }

  50% {
    transform: rotate(0)
  }

  75% {
    transform: rotate(-45deg)
  }

  to {
    transform: rotate(0)
  }
}

@keyframes eat-haha-down {
  0% {
    transform: rotate(0)
  }

  25% {
    transform: rotate(45deg)
  }

  50% {
    transform: rotate(0)
  }

  75% {
    transform: rotate(45deg)
  }

  to {
    transform: rotate(0)
  }
}

效果:

 

[python] openpyxl 的一些使用上的小问题记录一下

1、获取sheet直接使用数组形式:

sheet = work_book['Sheet0']

2、取单元格值是value

some_value = sheet.cell(row=1, column=1).value

3、遍历行 列的方法

# 这个的索引是从1开始的,最后max+1是为了最后一行可以匹配到

# 遍历行
for row in range(begin_row_index, sheet.max_row + 1):
 # some code
 break

# 遍历列

# 遍历行
for column in range(begin_column_index, sheet.max_column + 1):
 # some code
 break

4、填充,字体等设置方法

# 设置颜色 具体函数内容请阅读文档
sheet.cell(row=1, column=1).font = Font(color='FF0000')

# 设置填充
sheet.cell(row=1, column=1).fill = PatternFill(patternType='solid', fgColor='FF0000')

 

2021年河南省大学生国家安全知识竞赛一键满分脚本

欢迎

欢迎同学们再次来到紫旭Blog,本次给大家带来的是河南省大学生国家安全知识竞赛一键满分脚本。

警告

基于兴趣免费共享,禁止倒卖,我当然看不到你是不是在倒卖,但是作者在此立下诅咒:倒卖的户口本10天内挨个死。

使用方法

只需要修改最后一行的内容即可,如下所示

guoan.do(学校ID, '学号', '密码')

我会在下面将学校ID列表公布。

源码

注意:52pojie和本站发布的均为同一作者:紫旭网络

# -*- coding: utf-8 -*-

import requests
import random
import json
import time


class GuoAn(object):
    def __init__(self):
        self.s = requests.session()

    def do(self, school_id, student_id, password):
        self.login(school_id, student_id, password)

    def login(self, school_id, student_id, password):
        url = 'http://gjaqzsjs.haedu.cn/Login/auth'
        data = {
            'unit_code': school_id,
            'student_id': student_id,
            'password': password
        }

        result = self.s.post(url=url, data=data)
        result = json.loads(result.text)
        if result['code'] == 2000:
            print(f'{result["data"]["name"]},登录成功!')
            time.sleep(1)
            print(f'{result["data"]["name"]},即将提交答案!')
            time.sleep(1)
            self.submitAnswer()
            # 继续
        else:
            print(f'登录失败,{result["msg"]}')
            exit()

    def submitAnswer(self):
        url = 'http://gjaqzsjs.haedu.cn/Answer/submitAnswer'
        data = f'answer=%5B%7B%22number%22%3A%22383%22%2C%22answer%22%3A%22C%22%7D%2C%7B%22number%22%3A%227%22%2C%22answer%22%3A%22D%22%7D%2C%7B%22number%22%3A%2273%22%2C%22answer%22%3A%22B%22%7D%2C%7B%22number%22%3A%22127%22%2C%22answer%22%3A%22A%22%7D%2C%7B%22number%22%3A%22251%22%2C%22answer%22%3A%22C%22%7D%2C%7B%22number%22%3A%2247%22%2C%22answer%22%3A%22C%22%7D%2C%7B%22number%22%3A%22443%22%2C%22answer%22%3A%22A%22%7D%2C%7B%22number%22%3A%22515%22%2C%22answer%22%3A%22ABCD%22%7D%2C%7B%22number%22%3A%22638%22%2C%22answer%22%3A%22ABC%22%7D%2C%7B%22number%22%3A%22722%22%2C%22answer%22%3A%22BCD%22%7D%2C%7B%22number%22%3A%22609%22%2C%22answer%22%3A%22ABC%22%7D%2C%7B%22number%22%3A%22524%22%2C%22answer%22%3A%22ABCD%22%7D%2C%7B%22number%22%3A%22520%22%2C%22answer%22%3A%22ABCD%22%7D%2C%7B%22number%22%3A%22832%22%2C%22answer%22%3A%22B%22%7D%2C%7B%22number%22%3A%22996%22%2C%22answer%22%3A%22B%22%7D%2C%7B%22number%22%3A%22791%22%2C%22answer%22%3A%22B%22%7D%2C%7B%22number%22%3A%22796%22%2C%22answer%22%3A%22B%22%7D%2C%7B%22number%22%3A%221000%22%2C%22answer%22%3A%22A%22%7D%2C%7B%22number%22%3A%22883%22%2C%22answer%22%3A%22B%22%7D%2C%7B%22number%22%3A%221048%22%2C%22answer%22%3A%22B%22%7D%5D&use_time={random.randint(60, 180)}'
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        }

        result = self.s.post(url=url, data=data, headers=headers)
        # print(result.text)
        result = json.loads(result.text)
        if result['code'] == 4600:
            print(f'答题完成!')
            exit()
        else:
            print(f'答题失败,{result["msg"]}')
            exit()


if __name__ == '__main__':
    guoan = GuoAn()
    guoan.do(7, 'test0006', '123456')

学校ID列表

可以用Ctrl + F查找你的学校,你学校对应的code即为学校ID

[{
"code": "1",
"char": "安阳工学院",
"type": "1",
"type_char": "本科"
}, {
"code": "2",
"char": "安阳师范学院",
"type": "1",
"type_char": "本科"
}, {
"code": "3",
"char": "安阳学院",
"type": "1",
"type_char": "本科"
}, {
"code": "4",
"char": "河南财经政法大学",
"type": "1",
"type_char": "本科"
}, {
"code": "5",
"char": "河南财政金融学院",
"type": "1",
"type_char": "本科"
}, {
"code": "6",
"char": "河南城建学院",
"type": "1",
"type_char": "本科"
}, {
"code": "7",
"char": "河南大学",
"type": "1",
"type_char": "本科"
}, {
"code": "8",
"char": "河南工程学院",
"type": "1",
"type_char": "本科"
}, {
"code": "9",
"char": "河南工学院",
"type": "1",
"type_char": "本科"
}, {
"code": "10",
"char": "河南工业大学",
"type": "1",
"type_char": "本科"
}, {
"code": "11",
"char": "河南警察学院",
"type": "1",
"type_char": "本科"
}, {
"code": "12",
"char": "河南开封科技传媒学院",
"type": "1",
"type_char": "本科"
}, {
"code": "13",
"char": "河南科技大学",
"type": "1",
"type_char": "本科"
}, {
"code": "14",
"char": "河南科技学院",
"type": "1",
"type_char": "本科"
}, {
"code": "15",
"char": "河南科技学院新科学院",
"type": "1",
"type_char": "本科"
}, {
"code": "16",
"char": "河南科技职业大学",
"type": "1",
"type_char": "本科"
}, {
"code": "17",
"char": "河南理工大学",
"type": "1",
"type_char": "本科"
}, {
"code": "18",
"char": "河南牧业经济学院",
"type": "1",
"type_char": "本科"
}, {
"code": "19",
"char": "河南农业大学",
"type": "1",
"type_char": "本科"
}, {
"code": "20",
"char": "河南师范大学",
"type": "1",
"type_char": "本科"
}, {
"code": "21",
"char": "河南中医药大学",
"type": "1",
"type_char": "本科"
}, {
"code": "22",
"char": "华北水利水电大学",
"type": "1",
"type_char": "本科"
}, {
"code": "23",
"char": "黄河交通学院",
"type": "1",
"type_char": "本科"
}, {
"code": "24",
"char": "黄河科技学院",
"type": "1",
"type_char": "本科"
}, {
"code": "25",
"char": "黄淮学院",
"type": "1",
"type_char": "本科"
}, {
"code": "26",
"char": "洛阳理工学院",
"type": "1",
"type_char": "本科"
}, {
"code": "27",
"char": "洛阳师范学院",
"type": "1",
"type_char": "本科"
}, {
"code": "28",
"char": "南阳理工学院",
"type": "1",
"type_char": "本科"
}, {
"code": "29",
"char": "南阳师范学院",
"type": "1",
"type_char": "本科"
}, {
"code": "30",
"char": "平顶山学院",
"type": "1",
"type_char": "本科"
}, {
"code": "31",
"char": "商丘工学院",
"type": "1",
"type_char": "本科"
}, {
"code": "32",
"char": "商丘师范学院",
"type": "1",
"type_char": "本科"
}, {
"code": "33",
"char": "商丘学院",
"type": "1",
"type_char": "本科"
}, {
"code": "34",
"char": "新乡学院",
"type": "1",
"type_char": "本科"
}, {
"code": "35",
"char": "新乡医学院",
"type": "1",
"type_char": "本科"
}, {
"code": "36",
"char": "新乡医学院三全学院",
"type": "1",
"type_char": "本科"
}, {
"code": "37",
"char": "信阳农林学院",
"type": "1",
"type_char": "本科"
}, {
"code": "38",
"char": "信阳师范学院",
"type": "1",
"type_char": "本科"
}, {
"code": "39",
"char": "信阳学院",
"type": "1",
"type_char": "本科"
}, {
"code": "40",
"char": "许昌学院",
"type": "1",
"type_char": "本科"
}, {
"code": "41",
"char": "郑州财经学院",
"type": "1",
"type_char": "本科"
}, {
"code": "42",
"char": "郑州大学",
"type": "1",
"type_char": "本科"
}, {
"code": "43",
"char": "郑州工程技术学院",
"type": "1",
"type_char": "本科"
}, {
"code": "44",
"char": "郑州工商学院",
"type": "1",
"type_char": "本科"
}, {
"code": "45",
"char": "郑州工业应用技术学院",
"type": "1",
"type_char": "本科"
}, {
"code": "46",
"char": "郑州航空工业管理学院",
"type": "1",
"type_char": "本科"
}, {
"code": "47",
"char": "郑州经贸学院",
"type": "1",
"type_char": "本科"
}, {
"code": "48",
"char": "郑州科技学院",
"type": "1",
"type_char": "本科"
}, {
"code": "49",
"char": "郑州轻工业大学",
"type": "1",
"type_char": "本科"
}, {
"code": "50",
"char": "郑州商学院",
"type": "1",
"type_char": "本科"
}, {
"code": "51",
"char": "郑州升达经贸管理学院",
"type": "1",
"type_char": "本科"
}, {
"code": "52",
"char": "郑州师范学院",
"type": "1",
"type_char": "本科"
}, {
"code": "53",
"char": "郑州西亚斯学院",
"type": "1",
"type_char": "本科"
}, {
"code": "54",
"char": "中原工学院",
"type": "1",
"type_char": "本科"
}, {
"code": "55",
"char": "中原科技学院",
"type": "1",
"type_char": "本科"
}, {
"code": "56",
"char": "周口师范学院",
"type": "1",
"type_char": "本科"
}, {
"code": "57",
"char": "安阳幼儿师范高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "58",
"char": "安阳职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "59",
"char": "长垣烹饪职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "60",
"char": "河南测绘职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "61",
"char": "河南地矿职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "62",
"char": "河南对外经济贸易职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "63",
"char": "河南工业和信息化职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "64",
"char": "河南工业贸易职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "65",
"char": "河南工业职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "66",
"char": "河南护理职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "67",
"char": "河南机电职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "68",
"char": "河南检察职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "69",
"char": "河南建筑职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "70",
"char": "河南交通职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "71",
"char": "河南经贸职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "72",
"char": "河南林业职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "73",
"char": "河南农业职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "74",
"char": "河南女子职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "75",
"char": "河南轻工职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "76",
"char": "河南水利与环境职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "77",
"char": "河南司法警官职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "78",
"char": "河南推拿职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "79",
"char": "河南物流职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "80",
"char": "河南信息统计职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "81",
"char": "河南医学高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "82",
"char": "河南艺术职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "83",
"char": "河南应用技术职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "84",
"char": "河南职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "85",
"char": "河南质量工程职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "86",
"char": "鹤壁能源化工职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "87",
"char": "鹤壁汽车工程职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "88",
"char": "鹤壁职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "89",
"char": "黄河水利职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "90",
"char": "济源职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "91",
"char": "焦作大学",
"type": "2",
"type_char": "专科"
}, {
"code": "92",
"char": "焦作工贸职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "93",
"char": "焦作师范高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "94",
"char": "开封大学",
"type": "2",
"type_char": "专科"
}, {
"code": "95",
"char": "开封文化艺术职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "96",
"char": "兰考三农职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "97",
"char": "林州建筑职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "98",
"char": "洛阳科技职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "99",
"char": "洛阳职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "100",
"char": "漯河食品职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "101",
"char": "漯河医学高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "102",
"char": "漯河职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "103",
"char": "南阳科技职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "104",
"char": "南阳农业职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "105",
"char": "南阳医学高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "106",
"char": "南阳职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "107",
"char": "平顶山工业职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "108",
"char": "平顶山职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "109",
"char": "濮阳石油化工职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "110",
"char": "濮阳医学高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "111",
"char": "濮阳职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "112",
"char": "汝州职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "113",
"char": "三门峡社会管理职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "114",
"char": "三门峡职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "115",
"char": "商丘医学高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "116",
"char": "商丘职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "117",
"char": "嵩山少林武术职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "118",
"char": "新乡职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "119",
"char": "信阳航空职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "120",
"char": "信阳涉外职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "121",
"char": "信阳职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "122",
"char": "许昌电气职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "123",
"char": "许昌陶瓷职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "124",
"char": "许昌职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "125",
"char": "永城职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "126",
"char": "郑州财税金融职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "127",
"char": "郑州城市职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "128",
"char": "郑州电力高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "129",
"char": "郑州电力职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "130",
"char": "郑州电子商务职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "131",
"char": "郑州电子信息职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "132",
"char": "郑州工业安全职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "133",
"char": "郑州轨道工程职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "134",
"char": "郑州黄河护理职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "135",
"char": "郑州理工职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "136",
"char": "郑州旅游职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "137",
"char": "郑州商贸旅游职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "138",
"char": "郑州澍青医学高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "139",
"char": "郑州体育职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "140",
"char": "郑州铁路职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "141",
"char": "郑州卫生健康职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "142",
"char": "郑州信息工程职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "143",
"char": "郑州信息科技职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "144",
"char": "郑州亚欧交通职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "145",
"char": "郑州幼儿师范高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "146",
"char": "郑州职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "147",
"char": "周口职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "148",
"char": "驻马店幼儿师范高等专科学校",
"type": "2",
"type_char": "专科"
}, {
"code": "149",
"char": "驻马店职业技术学院",
"type": "2",
"type_char": "专科"
}, {
"code": "150",
"char": "信阳艺术职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "151",
"char": "周口文理职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "152",
"char": "洛阳文化旅游职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "153",
"char": "郑州城建职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "154",
"char": "郑州医药健康职业学院",
"type": "2",
"type_char": "专科"
}, {
"code": "155",
"char": "铁道警察学院",
"type": "2",
"type_char": "专科"
}, {
"code": "156",
"char": "郑州大学体育学院",
"type": "2",
"type_char": "专科"
}]

 

河南宗教知识竞赛加密算法分析(第二篇)

上回说到

请先看第一回:https://blog.zixutech.cn/archives/664

本回

由于官方2天更新了7次,尤其是今天更新了4次,我人直接裂开,官方没有采用我的强加密手段,而是继续乱jb加密,但是更新频次如此之快,我也懒得搞了,本篇文章主要是分享一下期间几次更新的加解密算法,别说还挺有创意的。

算法代码

我已添加了详细的注释供读者们阅读学习,对代码有疑问可以评论提出。

// 宗教答题第2~5次更新的加密函数
        function encrypt(content) {
            // content 是要加密的值,宗教里就是题号 如1000065

            // 随机字符串 + # + 题号,拼接后进行base64编码
            content = window.btoa('1688106372619ddf853ddce845744766#' + content)
            // code是要穿插在上述content里的内容,其内容是用户ID(需经过base64解码)和csmpagerid(不知道这到底是啥)
            let code = window.atob(memberusercode) + csmpagerid;
            // 开始将code穿插进content进行混淆
            for (let i = 0; i < code.length; i++) {
                // 在1 3 5 7 9 ··· 索引位置逐位插入code的内容
                content = content.slice(0, 2 * i + 1) + code.slice(i, i + 1) + content.slice(2 * i + 1);
            }
            // 因为content是经过base64编码的,所以其最后可能会出现=== == =这样的,如果有则替换为特定的字符串,这里是O0O0OO0O0O
            // 如果没有,则直接在后面加上这个O0O0OO0O0O
            if (content.indexOf('===') == -1 && content.indexOf('==') == -1 && content.indexOf('=') == -1) {
                content += 'O0O0OO0O0O';
            } else {
                content = content.replace('===', 'O0O0OO0O0O');
                content = content.replace('==', 'O0O0OO0O0O');
                content = content.replace('=', 'O0O0OO0O0O');
            }
            // 加密完成,返回数据
            // console.log(content)
            return content;
        }

        // 宗教答题第2~5次更新的解密函数
        function decrypt(content) {
            // content 要解密的内容,一般是题号,解密前的样子大概是
            // M1T0A000N6j0I844N3j2c1y4M1T9Y8x8O5W9R8j0N6W1I9xdOcG5Qbx1N8zcIc4dM4z1I045M3j4Q240N7T1IjMTAwMDAwOQO0O0OO0O0O

            // 设计一个新的字符串用来当做解密后的字符串
            let newStr = ''
            // 逐位循环去除混淆
            for (let i = 0; i < content.length; i++) {
                // 42的意思是,用户ID的长度和csmpagerid的长度一共是42位,所以只需要去除42个字符即可
                if (i >= 42) {
                    // 循环次数大于等于42后,直接不再裁剪,而是拼接最后所有字符串
                    newStr += content.slice(2 * i)
                    break
                }
                // 裁剪字符串,把第0 2 4 6 8 10 ··· 位的混淆字符删掉
                newStr += content.slice(2 * i, 2 * i + 1)
            }
            // 将结果进行base64解码,至此解密完成
            newStr = window.atob(newStr)
            // console.log(newStr)
        }

结语

官方更新是好事,但是也请一次更新到位,用最好的技术来应对作弊,或者能给学生们一份题库用来背,也能达到学习的目的。

希望世上再无形式主义!

河南宗教知识竞赛加密算法分析

开头

我的博客因宗教插件而火,故在1400多人的强烈要求下今年还是更新了。这个东西确实没法说,要求满分不给题库,40分钟搜个锤子呢,这不是找着让大学生都去找代刷呢,能学了吗,达的到目的吗?

我的群一直讲究技术交流为主,资源分享为辅,和谐交流环境,禁商禁推广发现就踢。所以这次也算造福一下同学们了。

起因

2021年11月23日早上群友发现插件全部失效了,上班前看了一眼,发现题目结构和开始时间都被加密了,导致老的数据全部失效,因此今天晚上下班回来简单分析了一下,发现并不是那么难,下面把分析过程写在这篇文章里,以作为技术交流。

分析

首先看一下加密后的代码结构:

可观察到大部分的重复以及最后面那显眼的0000000

起初我并没看出这是什么算法,但因为知道之前没加密的时候是一串数字,如1000055这类的,可以看出编码算法应该是个通用算法。

首先想到的就是Base64,经过测试,发现和图中数据不一致,如下面所示

原文:1000143

Base64:MTAwMDE0Mw==

图中加密的:M1T0A0w8M6D0E001M3w2O0O0O0O0

可观察出有很多相似的地方。

尝试对比后,发现如下规律(图中是另一个用户下测试的)

发现被插入的数字是 1004901214 在网页源码中查找此数字,发现正是memberusercode的值

也就是说算法其实很简单,就是把原先的数据经过Base64编码,然后每隔一位将memberusercode的一位数插入进去,最后把 == 替换成那一堆O0,如果没有 == 则直接在后面加上 O0

至此,分析完毕。

算法实现

我用js来实现这个算法,非常简单,拿来直接可以用。以下是代码实现:

function encrypt(content) {
    let code = memberusercode;
    content = window.btoa(content);
    for (let i = 0; i < 10; i++) {
        content = content.slice(0, 2 * i + 1) + code.slice(i, i + 1) + content.slice(2 * i + 1);
    }
    if (content.indexOf('==') == -1) {
        content += 'O0O0OO0O0O';
    } else {
        content = content.replace('==', 'O0O0OO0O0O');
    }
    return content;
}

就不再写注释了,各位同学可以度读一下代码看看是如何实现的,非常简单。

需要注意的是,我们需要在中间插入,要考虑到插入后的文本长度,如下所示

原文:A B C D

1次插入:A X B C D

2次插入:A X B X C D

3次插入:A X B X C X D

……

所以我们插入的索引位置是1 3 5 7 9 ……

因此,for循环内的slice的长度使用的是等差数列公式2i + 1

帮一下官方

我非常明白官方想防作弊的决心,但是说句实话,这样的算法难不倒广大高材生,我并不是第一个解出来的。我愿意在此祝官方一臂之力!

下面我给官方提供一套我在用的自定义算法,非常好用,我用它来生成用户TOKEN。

密钥不泄露几乎不存在被反解密的情况。语言是PHP的。

function encryption($string, $operation)
{
    $key = md5(config('encryption_key')); // 这是密钥,可以写在数据库或配置文件内
    $key_length = strlen($key);
    $string = str_replace('_', '/', $string);
    $string = str_replace("-", '\\', $string);
    $string = str_replace("*", '+', $string);
    $string = $operation == 'D' ? base64_decode($string) : substr(md5($string . $key), 0, 8) . $string;
    $string_length = strlen($string);
    $rndkey = $box = array();
    $result = '';
    for ($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($key[$i % $key_length]);
        $box[$i] = $i;
    }
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    for ($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }
    if ($operation == 'D') {
        if (substr($result, 0, 8) == substr(md5(substr($result, 8) . $key), 0, 8)) {
            $result = substr($result, 8);
            return $result;
        } else {
            return '';
        }
    } else {
        $result = str_replace('=', '', base64_encode($result));
        $result = str_replace('/', '_', $result);
        $result = str_replace("\\", '-', $result);
        $result = str_replace("+", '*', $result);
        // 正斜杠 / 改为下划线 _ ; 反斜杠 \ 改为减号 - 。
        return $result;
    }
}

使用方法:

加密时:encryption(要加密的字符串, “E”)

解密时:encryption(要解密的字符串, “D”)

结语

希望官方可以改进让学生学习的措施办法,做好加密防护,给学生们个题库,他们真的会认真搜题学习,我群里已有很多将题库背下来的同学,他们不就达到了官方的目的了吗。