199 lines
7.1 KiB
Python
Executable File
199 lines
7.1 KiB
Python
Executable File
import re
|
|
import textwrap
|
|
import random
|
|
import string
|
|
from datetime import datetime
|
|
from django.conf import settings
|
|
import base64
|
|
import requests
|
|
from io import BytesIO
|
|
from rest_framework.serializers import ValidationError
|
|
|
|
|
|
def singleton(cls):
|
|
_instance = {}
|
|
|
|
def inner():
|
|
if cls not in _instance:
|
|
_instance[cls] = cls()
|
|
return _instance[cls]
|
|
return inner
|
|
|
|
|
|
def print_roundtrip(response, *args, **kwargs):
|
|
def format_headers(d): return '\n'.join(f'{k}: {v}' for k, v in d.items())
|
|
print(textwrap.dedent('''
|
|
---------------- request ----------------
|
|
{req.method} {req.url}
|
|
{reqhdrs}
|
|
|
|
{req.body}
|
|
---------------- response ----------------
|
|
{res.status_code} {res.reason} {res.url}
|
|
{reshdrs}
|
|
|
|
{res.text}
|
|
''').format(
|
|
req=response.request,
|
|
res=response,
|
|
reqhdrs=format_headers(response.request.headers),
|
|
reshdrs=format_headers(response.headers),
|
|
))
|
|
|
|
|
|
def ranstr(num):
|
|
salt = ''.join(random.sample(string.ascii_lowercase + string.digits, num))
|
|
return salt
|
|
|
|
|
|
def rannum(num):
|
|
salt = ''.join(random.sample(string.digits, num))
|
|
return salt
|
|
|
|
|
|
def timestamp_to_time(millis):
|
|
"""10位时间戳转换为日期格式字符串"""
|
|
return datetime.fromtimestamp(millis)
|
|
|
|
|
|
def convert_to_base64(path: str):
|
|
"""给定图片转base64
|
|
|
|
Args:
|
|
path (str): 图片地址
|
|
"""
|
|
if path.startswith('http'): # 如果是网络图片
|
|
return str(base64.b64encode(BytesIO(requests.get(url=path).content).read()), 'utf-8')
|
|
else:
|
|
with open(settings.BASE_DIR + path, 'rb') as f:
|
|
return str(base64.b64encode(f.read()), 'utf-8')
|
|
|
|
|
|
def p_in_poly(p, poly):
|
|
px = p['x']
|
|
py = p['y']
|
|
flag = False
|
|
|
|
i = 0
|
|
l = len(poly)
|
|
j = l - 1
|
|
# for(i = 0, l = poly.length, j = l - 1; i < l; j = i, i++):
|
|
while i < l:
|
|
sx = poly[i]['x']
|
|
sy = poly[i]['y']
|
|
tx = poly[j]['x']
|
|
ty = poly[j]['y']
|
|
|
|
# 点与多边形顶点重合
|
|
if (sx == px and sy == py) or (tx == px and ty == py):
|
|
return (px, py)
|
|
|
|
# 判断线段两端点是否在射线两侧
|
|
if (sy < py and ty >= py) or (sy >= py and ty < py):
|
|
# 线段上与射线 Y 坐标相同的点的 X 坐标
|
|
x = sx + (py - sy) * (tx - sx) / (ty - sy)
|
|
# 点在多边形的边上
|
|
if x == px:
|
|
return (px, py)
|
|
# 射线穿过多边形的边界
|
|
if x > px:
|
|
flag = not flag
|
|
j = i
|
|
i += 1
|
|
|
|
# 射线穿过多边形边界的次数为奇数时点在多边形内
|
|
return (px, py) if flag else 'out'
|
|
|
|
|
|
def check_id_number_e(val):
|
|
re_s = r'^[1-9]\d{5}(18|19|20|(3\d))\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$'
|
|
if not re.match(re_s, val):
|
|
raise ValidationError('身份证号校验错误')
|
|
return val
|
|
|
|
|
|
def get_info_from_id(val):
|
|
birth = val[6:14]
|
|
birth_year = birth[0:4]
|
|
age = datetime.now().year - int(birth_year)
|
|
sex = int(val[-2])
|
|
gender = '女'
|
|
if sex % 2:
|
|
gender = '男'
|
|
return dict(age=age, gender=gender)
|
|
|
|
|
|
def check_id_number(idcard):
|
|
"""校验身份证号
|
|
|
|
Args:
|
|
id_number (_type_): 身份证号
|
|
"""
|
|
Errors = ['身份证号码位数不对!', '身份证号码出生日期超出范围或含有非法字符!', '身份证号码校验错误!', '身份证地区非法!']
|
|
area = {"11": "北京", "12": "天津", "13": "河北", "14": "山西", "15": "内蒙古", "21": "辽宁", "22": "吉林", "23": "黑龙江",
|
|
"31": "上海", "32": "江苏", "33": "浙江", "34": "安徽", "35": "福建", "36": "江西", "37": "山东", "41": "河南", "42": "湖北",
|
|
"43": "湖南", "44": "广东", "45": "广西", "46": "海南", "50": "重庆", "51": "四川", "52": "贵州", "53": "云南", "54": "西藏",
|
|
"61": "陕西", "62": "甘肃", "63": "青海", "64": "宁夏", "65": "新疆", "71": "台湾", "81": "香港", "82": "澳门", "91": "国外"}
|
|
idcard = str(idcard)
|
|
idcard = idcard.strip()
|
|
idcard_list = list(idcard)
|
|
|
|
# 地区校验
|
|
if str(idcard[0:2]) not in area:
|
|
return False, Errors[3]
|
|
|
|
# 15位身份号码检测
|
|
if len(idcard) == 15:
|
|
if ((int(idcard[6:8]) + 1900) % 4 == 0 or (
|
|
(int(idcard[6:8]) + 1900) % 100 == 0 and (int(idcard[6:8]) + 1900) % 4 == 0)):
|
|
ereg = re.compile(
|
|
'[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$') # //测试出生日期的合法性
|
|
else:
|
|
ereg = re.compile(
|
|
'[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$') # //测试出生日期的合法性
|
|
if re.match(ereg, idcard):
|
|
return True, ''
|
|
else:
|
|
return False, Errors[1]
|
|
# 18位身份号码检测
|
|
elif len(idcard) == 18:
|
|
# 出生日期的合法性检查
|
|
# 闰年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))
|
|
# 平年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))
|
|
if (int(idcard[6:10]) % 4 == 0 or (int(idcard[6:10]) % 100 == 0 and int(idcard[6:10]) % 4 == 0)):
|
|
# 闰年出生日期的合法性正则表达式
|
|
ereg = re.compile(
|
|
'[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$')
|
|
else:
|
|
# 平年出生日期的合法性正则表达式
|
|
ereg = re.compile(
|
|
'[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$')
|
|
# 测试出生日期的合法性
|
|
if re.match(ereg, idcard):
|
|
# 计算校验位
|
|
S = (int(idcard_list[0]) + int(idcard_list[10])) * 7 + (int(idcard_list[1]) + int(idcard_list[11])) * 9 + (
|
|
int(idcard_list[2]) + int(idcard_list[12])) * 10 + (
|
|
int(idcard_list[3]) + int(idcard_list[13])) * 5 + (
|
|
int(idcard_list[4]) + int(idcard_list[14])) * 8 + (
|
|
int(idcard_list[5]) + int(idcard_list[15])) * 4 + (
|
|
int(idcard_list[6]) + int(idcard_list[16])) * 2 + int(idcard_list[7]) * 1 + int(
|
|
idcard_list[8]) * 6 + int(idcard_list[9]) * 3
|
|
Y = S % 11
|
|
M = "F"
|
|
JYM = "10X98765432"
|
|
M = JYM[Y] # 判断校验位
|
|
if M == idcard_list[17]: # 检测ID的校验位
|
|
return True, ''
|
|
else:
|
|
return False, Errors[2]
|
|
else:
|
|
return False, Errors[1]
|
|
else:
|
|
return False, Errors[0]
|
|
|
|
|
|
def check_phone_e(phone):
|
|
re_phone = r'^1\d{10}$'
|
|
if not re.match(re_phone, phone):
|
|
raise ValidationError('手机号格式错误')
|
|
return phone |