未解之谜
百度搜索算法规范详解https://zy.baidu.com/act/guide?isResponsible=1
百度搜索优化知识大全https://zy.baidu.com/act/seo?isResponsible=1
阿里云开发者课堂 https://edu.aliyun.com/
spark-md5.js 计算文件md5值 :https://github.com/satazor/js-spark-md5
一个提供用户脚本的网站
https://greasyfork.org/zh-CN
用户脚本管理器:Tampermonkey中文文档
https://www.cnblogs.com/grubber/p/12560522.html
Js上传插件 Plupload
drupal
嵌入式WEB开发
CSRF 漏洞
fopen漏洞
Python
阿里云大学PYTHON学习路线
https://edu.aliyun.com/roadmap/python
ThinkPHP list_to_tree、tree_to_list、list_search
vue.js
C盘可以删除的临时文件,也可以用系统自带的磁盘清理程序清除
C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Temp
C:\Windows\SoftwareDistribution\Download
https://support.microsoft.com/zh-cn/windows?ui=zh-CN&rs=zh-CN&ad=CN
https://support.microsoft.com/zh-cn/windows/%E9%87%8A%E6%94%BE-windows-10-%E4%B8%AD%E7%9A%84%E9%A9%B1%E5%8A%A8%E5%99%A8%E7%A9%BA%E9%97%B4-85529ccb-c365-490d-b548-831022bc9b32
JSON 网络令牌JWT(JSON Web Token)
参考:https://zhuanlan.zhihu.com/p/12876076909
1、什么是JWT?
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间以 JSON 格式安全地传输信息。它通常用于身份验证和授权流程中,特别是在无状态的 RESTful API 和现代 Web 应用中。
2、什么时候应该使用 JSON Web Token?
以下是 JSON Web Token (JWT) 的一些适用场景:
授权(Authorization): 这是 JWT 最常见的用途。用户登录后,后续的每个请求都会携带 JWT,从而允许用户访问该令牌所授权的路由、服务和资源。单点登录(Single Sign On)是当前广泛使用 JWT 的一个功能,因为它具有较小的开销,并且可以轻松跨不同域名使用。
信息交换(Information Exchange): JWT 是在各方之间安全传输信息的一种好方式。由于 JWT 可以签名(例如,使用公钥/私钥对),你可以确认发送者的身份。此外,由于签名是基于头部(header)和负载(payload)计算得出的,你还可以验证内容是否被篡改。
3、JSON Web Token 的结构是什么?
在紧凑形式中,JSON Web Token(JWT)由三部分组成,各部分之间通过点号(.)分隔:
头部(Header)
负载(Payload)
签名(Signature)
PHP生成和验证jwt
// 自定义 Base64Url 编码函数(处理 URL 安全字符)
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
//生成JWT令牌
function jwt_create($userId, $secretKey){
// 定义 Header、Payload 和密钥
$header = array('alg' => 'HS256');
$payload = array(
'username' => 'zhangsan',
'userid' => '101',
);
// 编码 Header 和 Payload
$headerEncoded = base64url_encode(json_encode($header));
$payloadEncoded = base64url_encode(json_encode($payload));
// 生成签名(HMAC-SHA256)
$signatureInput = "$headerEncoded.$payloadEncoded";
$signature = hash_hmac('sha256', $signatureInput, $secretKey, true);
$signatureEncoded = base64url_encode($signature);
// 组合完整 JWT
$jwt = "$headerEncoded.$payloadEncoded.$signatureEncoded";
return $jwt;
}
//验证JWT令牌
function jwt_verify($jwt,$secretKey){
// 提取已生成的 JWT 各部分
list($header, $payload, $signature) = explode('.', $jwt);
// 重新计算签名
$recomputedSignature = base64url_encode(
hash_hmac('sha256', "$header.$payload", $secretKey, true)
);
// 比较签名
return $signature === $recomputedSignature;
}
html跨平台在线预览pdf
PDFObject.js
官网:https://pdfobject.com/
相关博客:
https://blog.csdn.net/i_dont_know_a/article/details/80707963
https://blog.csdn.net/qappleh/article/details/80250492
https://www.jq22.com/yanshi649
pdf.js
官网:https://mozilla.github.io/pdf.js/getting_started/
相关博客:
https://blog.csdn.net/weixin_42400643/article/details/152602790
https://blog.csdn.net/weixin_31800911/article/details/148820919
https://www.jb51.net/javascript/338851frl.htm
移动端h5常用的几款插件
演示地址:https://www.jq22.com/yanshi10850
2、日期选择插件——rolldate.js
演示地址:https://weijhfly.github.io/rolldate-index.html
下载地址:https://www.jq22.com/jquery-info19834
3、图片裁剪插件——cropper.js
下载地址:https://github.com/fengyuanchen/cropperjs
4、底部滑动选择插件——mobileSelect.js
下载地址:https://www.jq22.com/jquery-info14679
演示地址:https://www.jq22.com/yanshi14679
php获取指定目录的所有子孙目录
方法一:scandir + 递归
function getAllSubdirectories($path) {
$subdirs = [];
$items = scandir($path);
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$fullPath = $path . DIRECTORY_SEPARATOR . $item;
if (is_dir($fullPath)) {
// 添加当前目录
$subdirs[] = $fullPath;
// 递归获取子目录的子目录
$subdirs = array_merge($subdirs, getAllSubdirectories($fullPath));
}
}
return $subdirs;
}
// 使用示例
$allSubdirs = getAllSubdirectories('/path/to/directory');
print_r($allSubdirs);
方法二:使用 RecursiveDirectoryIterator(推荐)
function getAllSubdirectoriesIterator($path) {
$subdirs = [];
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $fileinfo) {
if ($fileinfo->isDir()) {
$subdirs[] = $fileinfo->getPathname();
}
}
return $subdirs;
}
// 使用示例
$allSubdirs = getAllSubdirectoriesIterator('/path/to/directory');
print_r($allSubdirs);
layui.prompt 监听回车键来触发确认操作
layer.prompt({
title: '请输入密码:',
formType: 1,
success: function(layero, index){
$(layero).find('.layui-layer-input').prop('autocomplete','new-password').on('keydown',function(e){
if(e.which === 13){
$(layero).find('.layui-layer-btn0').trigger('click');
}
});
},
yes: function(index, layero){
let elem=$(layero).find('.layui-layer-input'), value=elem.val();
if(value==='123456'){
layer.close(index);
layer.msg('密码正确');
}else{
elem.focus();
layer.tips(value===''?'请输入':'密码错误',elem,{tips:1,time:2e3});
}
}
});
传统prompt方法无法监听输入
layer.prompt({
title: '请输入密码:',
formType: 1,
},function(value, index, elem){
console.log(value);
layer.close(index);
});
mysql两表组合查询的一种优化方法
表tab_class为产品与分类对照表,一个产品可能属于多个分类
首页要确保 tab_class 表有 classid和productid 的复合索引
ALTER TABLE tab_class ADD INDEX idx_classid_productid (classid, productid);
JOIN 组合查询:
SELECT `tab_product`.* FROM `tab_product` JOIN `tab_class` ON `tab_product`.`id`=`tab_class`.`productid` WHERE `tab_class`.`classid` IN(3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606) GROUP BY `tab_product`.`id` ORDER BY `id` DESC LIMIT 10;
EXISTS 查询:
SELECT *
FROM `tab_product`
WHERE `id` IN(
SELECT DISTINCT(productid)
FROM tab_class
WHERE classid IN(3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606)
)
ORDER BY `id` DESC LIMIT 10;在CodeIgniter中的写法:
$class_ids = [3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606];
$this->db->from('tab_product');
$this->db->where_in('id', "
SELECT DISTINCT(productid)
FROM tab_class
WHERE classid IN (".implode(',', $class_ids).")
");
$this->db->order_by('id', 'DESC');
$this->db->limit(10);
$query = $this->db->get();SELECT DISTINCT(productid) 中的 DISTINCT 可以省略,因为外层的 IN 会自动去重复。但如果结果集比较大还是建议加上。
也可以使用 EXPLAIN 查询两种方法的性能,择优使用
layui多图带预览的上传
<div class="layui-form-item">
<label class="layui-form-label">图片上传</label>
<div class="layui-input-block">
<button type="button" class="layui-btn layui-btn-primary layui-border-blue" id="js-btn-upload"><i class="layui-icon layui-icon-upload"></i> 上传图片</button>
</div>
</div>
<div class="layui-form-item">
<ul id="upload-list" class="upload-list"></ul>
</div>
<script type="text/html" id="upload-tpl">
<li id="js-image-{{ d.index }}">
<div class="layui-progress" lay-filter="progress-{{ d.index }}"><div class="layui-progress-bar" lay-percent=""></div></div>
<em><img src="{{ d.url }}"><a class="layui-btn layui-btn-xs layui-bg-red js-reupload">重新上传</a></em>
<div class="layui-btn-group">
<a class="layui-btn layui-btn-primary layui-btn-sm layui-border-blue js-left"><i class="layui-icon layui-icon-left"></i></a>
<a class="layui-btn layui-btn-primary layui-btn-sm layui-border-red js-delete"><i class="layui-icon layui-icon-delete"></i></a>
<a class="layui-btn layui-btn-primary layui-btn-sm layui-border-blue js-right"><i class="layui-icon layui-icon-right"></i></a>
</div>
<input type="hidden" name="imglist[]">
</li>
</script>
<script>
//上传图片
var uploadInst = layui.upload.render({
elem: '#js-btn-upload', //绑定元素
elemList: $('#upload-list'), // 列表元素对象
url: '<?=site_url('kindeditor/uploadjson?type=image&dir=product')?>',
acceptMime: 'image/jpeg, image/png',
exts: 'jpg|png',
size: 1024,
field: 'imgFile',
multiple: true,
number: 6,
auto: false,
choose: function(obj){
uploadInst.config.elem.next()[0].value = '';
var pics=this.elemList.find('li').length;
if(pics>=this.number || pics+Object.keys(obj.getChooseFiles()).length>this.number){
layer.msg('最多上传6张图片');
return false;
}
// 读取本地文件
var that = this;
obj.preview(function(index, file, result){
var li=$(laytpl($('#upload-tpl').html()).render({index:index,url:result}));
li.find('.layui-progress').show();
li.find('.js-reupload').on('click', function(){
obj.upload(index, file);
$(this).hide();
element.progress('progress-'+ index, '0%');
});
that.elemList.append(li);
element.render('progress'); // 渲染新加的进度条组件
obj.upload(index, file);
});
},
done: function(res, index, upload){ // 成功的回调
var that = this;
if(res.error == 0){ // 上传成功
var li = that.elemList.find('li#js-image-'+ index)
li.find('.layui-progress').remove();
li.find('input').val(res.url);
return;
}
this.error(index, upload);
},
error: function(index, upload){ // 错误回调
var that = this;
var li = that.elemList.find('li#js-image-'+ index);
//显示重传
li.find('.js-reupload').show();
layer.msg('上传失败',{icon:5});
},
progress: function(n, elem, e, index){ // 注意:index 参数为 layui 2.6.6 新增
element.progress('progress-'+ index, n + '%'); // 执行进度条。n 即为返回的进度百分比
}
});
</script>
windows指定图片使用照片查看器打开
常见图片格式在右键》属性》打开方式中即可设置。
如果打开方式中没有"照片查看器",可以在注册表如下路径:
计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations
新建字符串值,名称如:.webp,数值:PhotoViewer.FileAssoc.Tiff
注意:用Windows照片查看器浏览 webp格式 的图片可能会出现较大色差。
