两双筷子 - 编码
type: channel
link: https://www.dbkuaizi.com/category/code/
items: 多用户 PassKey 认证插件
items: 1Panel 部署 FastAdmin 管理端访问 302 解决方案
items: 解析到本地127的神奇域名
items: Typecho 多吉云上传插件
items: 极简 Docker 入门笔记
items: SQLite + zstd：定时任务日志压缩优化实践
items: 离线授权码设计思路
items: Typecho 垃圾评论过滤插件
items: Vue3+TS 笔记
items: Yii2 学习笔记

多用户 PassKey 认证插件
type: item
date: 2026-03-08T09:15:00+00:00
description: 出于安全考虑，去年开发了一个 OTP 多因素认证插件，后面就一直想着开发通行密钥插件，这样就不需要输入密码了，点两下就能登录进来，于是就花了两个小时使用 GPT-5.3-Codx 写了这个插件，不得不说 AI 还是太好用了。功能支持多用户的 PassKey 插件（通行密钥、WebAuthn 说的都是它）,支持 Typecho 1.2.0 + 的版本。支持自定义通行密钥名称一个用户支持创建多个通行密钥使用安装插件后，去个人设置页面绑定一个通行密钥通行密钥绑定后 就可以在登录时使用下载去 CNB 下载这个插件https://cnb.cool/dbkuaizi/typecho/passkey/-/releases或者直接下载代码仓库：https://cnb.cool/dbkuaizi/typecho/passkey注意：releases 发布版本 中的 zip 包已经包含 PassKey 插件目录，如果是直接下载的代码仓库，需要自行创建 usr/plugins/PassKey 目录

1Panel 部署 FastAdmin 管理端访问 302 解决方案
type: item
date: 2025-12-28T12:52:23+00:00
description: 最近使用 1Panel 面板部署 FastAdmin 项目用于测试，站点的伪静态选择 thinkphp，在部署完成后发现用户端可以正常访问，而管理端则会无限制重定向到 login/index，最终提示 “重定向次数过多...” 如下图所示：经过排查 发现问题出现在 1Panel 自带的 fastcgi-php.conf 上这个文件上，如图 21 行:解决方案是注释掉这一行，然后使用 fastadmin 官方推荐的 fastcgi 配置，代码如下：location ~ [^/]\.php(/|$) { fastcgi_pass 127.0.0.1:9000; # include fastcgi-php.conf; # 注释掉这一行或者直接复制我的示例代码 include fastcgi_params; fastcgi_index index.php; fastcgi_split_path_info ^((?U).+\.php)(/?.+)$; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; }保存修改的配置后，fastadmin 管理端入口即可正常访问：使用版本为 1Panel 2.0.16, OpenResty 版本为 1.27.1.2-2-3-focal

解析到本地127的神奇域名
type: item
date: 2025-11-11T14:36:00+00:00
description: 前言作为一名 Web 开发者，我的日常工作就是在本地进行开发，实现各种功能。过去几年，我一直使用 127.0.0.1 作为本地服务的访问地址。当需要同时开发多个项目时，我会用不同端口来区分，例如：项目A：127.0.0.1:8080项目B：127.0.0.1:8081…以此类推当然，也可以用 localhost 代替 127.0.0.1。前段时间我在想，有没有办法让本地访问的地址看起来更“真实”一点？我知道可以通过配置 HOSTS 文件将任意域名解析到本地，但有没有本身就专门设计用于解析到本地的域名呢？最初，我尝试将 local.dbkuaizi.com 及其子域名解析到 127.0.0.1，这样访问 local.dbkuaizi.com 或 test.local.dbkuaizi.com 都能指向本地站点。但用了几天后发现一个问题：域名太长，输入不方便。于是我又想，不如自己注册一个短域名？但在域名注册网站找了半天，发现两位的短域名要么已被注册，要么价格不菲。后来我在网上搜索了一番，发现确实存在一些专门解析到本地的域名。现将整理结果汇总如下：本地解析域名localhostIETF（互联网工程任务组）在 RFC 6761 中明确规定：localhost 和 *.localhost 应始终解析为本地回环地址（即 127.0.0.1）。因此，以下地址都会被解析到 127.0.0.1，满足各种使用场景：域名说明http://localhost顶级域名http://dbkuaizi.localhost二级域名http://dbkuaizi.test.localhost三级域名需要注意的是，.localhost 解析到本地是应用层规范，Safari、Chrome、CURL 等主流工具都支持，但并非所有应用都遵循。由于这是官方硬性规定，该域名非常稳定且通用性强，在绝大多数情况下推荐使用。*.lvh.me该域名的持有者是 @levicook。自 2010 年起，该域名及其泛域名均解析到 127.0.0.1。2021 年 6 月，作者因认为使用人数不多、不愿继续承担域名费用而停止续费。随后，越来越多网友在其推特下留言表示愿意捐助，希望保留该域名。最终 @levicook 恢复了续费，并开启了捐款通道（但目前该捐款地址已返回 403）。以下地址都会被解析到 127.0.0.1：域名说明http://lvh.me顶级域名http://dbkuaizi.lvh.me二级域名http://dbkuaizi.test.lvh.me三级域名这是目前最短的可用域名，也是我日常开发的选择，体验良好。*.fbi.com这个域名…很有意思，虽然不清楚所有者是谁，但至少从 2022 年至今，它一直解析到本地回环地址。域名说明http://fbi.com顶级域名http://demo.fbi.com二级域名http://demo.test.fbi.com三级域名由于所有者不明，不推荐用于正式开发，当作一个趣闻即可。*.nip.ionip.io 和 sslip.io 是一种 DNS 服务，当查询包含嵌入 IP 地址的主机名时，会将域名解析为对应 IP。这两个服务已稳定运行十多年，每秒处理约 5000 次请求，甚至被 Google 引用在 Kubernetes 文档 中。举例说明：域名解析结果http://127.0.0.1.nip.io127.0.0.1http://app.192.168.0.10.nip.io192.168.0.10http://7f000101.nip.io127.0.0.1（十六进制表示）http://127-0-0-1.nip.io127.0.0.1（带破折号格式）需要注意的是，nip.io 和 sslip.io 本身不解析到 127.0.0.1。虽然该服务稳定，但我个人不太喜欢，因为域名中必须包含 IP，与我最初的目标不符。local.gd这是 nip.io 服务的一部分，该域名及其子域名均解析到 127.0.0.1，用法与其他本地域名相同：域名说明http://local.gd顶级域名http://dbkuaizi.local.gd二级域名http://dbkuaizi.test.local.gd三级域名local.dbkuaizi.com这是我个人持有的域名。对我而言，其稳定性仅次于 localhost。如果你有需要，也可以直接使用（至少在可预见的未来，该域名会持续解析到 127.0.0.1）。域名说明http://local.dbkuaizi.com二级域名http://demo.local.dbkuaizi.com三级域名http://demo.test.local.dbkuaizi.com四级域名其他我还收集了其他一些解析到 127…

Typecho 多吉云上传插件
type: item
date: 2025-10-16T13:19:00+00:00
description: 去年了解到多吉云这个CDN 厂商，感觉性价比很高，并且网友使用后的评价也很不错 @二丫讲梵。然后看了一眼现在使用的又拍云 CDN，还有一些余额没有用完。想着还是等用完了这些余额，再迁移到多吉云上去。直到今年十月前后，终于快用完了。但是迁移时发现 Typecho 没有支持多吉云的插件，有一个支持 S3 存储协议的插件，但是阅读完多吉云文档后发现，多吉云的 S3 文档与标准版 S3 规范有一些差异，不能直接使用，所以就有了这个插件。DogeUpload 插件Typecho 多吉云附件上传插件, 版本要求 Typecho >= 1.2.0 版本。直接上传附件到多吉云，且支持更新和删除附件。自定义加速域名。多吉云图片处理后缀支持。时间戳防盗链，支持自定义 Token 有效期。历史资源处理 （将 博客域名自动替换成 CDN 域名）。超轻量级设计，贯彻 Typecho 极简设计理念，插件体积仅 32 KB。代码结构简单、注释完善、使用命名空间，适合作为插件开发参考。2026-01-26 更新 插件 1.0.1 适配 Typecho 1.3.0 版本，解决因 Upload 基类传参调整导致上传报 “Server Error” 的问题，感谢 @曾墨 的反馈下载地址：https://cnb.cool/dbkuaizi/blog/-/tree/main/typecho_plugin下载 "DogeUpload.zip"安装方式：将压缩包中的文件夹 DogeUpload 上传至 Typecho 插件目录 typecho/usr/plugins 下 并在插件面板启用。配置页预览更高性价比的选择博客建立后一直使用又拍云的CDN 服务，去年发现了多吉云这个CDN厂商，了解后得知 多吉云其实是一个 "二道贩子"，他们底层使用 阿里云、腾讯云等国内大厂的 CDN 节点作为基础支撑，得益于量大的原因，他们可以给出比直接购买阿里云、腾讯云CDN 更加实惠的价格。因为我前期一直在使用 又拍云，所以对又拍云的计费规则比较了解，这里就对比一下 又拍云 和 多吉云的成本差异：注：这里以 2025年10月15日 各厂商官网价格为基础作比较，若需核算成本，请以官网价格为准。又拍云云存储：0.0043 元 / GB / 天 (注：可以以当天流量使用情况进行抵扣)CDN 国内流量：0.29 元 / GBHTTPS 请求：0.05 元 / 万次HTTPS 证书免费更新多吉云云存储：0.003 元 / GB / 日CDN 国内流量：0.11 元 / GB （每月前 20 GB 免费）HTTPS 请求：0.04 元 / 万次（每月前 200W 次免费，日流量或云存储超过2TB 可联系客服免除 HTTPS 费用）HTTPS 证书续订目前免费，但官方说后期会收费，默认证书厂商 1元/次，指定厂商2元/次（后面有免费方案）我这里以 月流量 100 GB、云存储 10 GB、HTTPS 月请求数量 60W 来计算两家使用成本的差异（注：如果考虑购买资源包，成本会更低）。费用项目又拍云多吉云备注1. 云存储费用 - 计算公式10GB × 0.0043元/天 × 30天10GB × 0.003元/天 × 30天 - 小计1.29 元0.9 元 2. CDN流量费用 - 计算公式100GB × 0.29元/GB(100GB - 20GB) × 0.11元/GB多吉云每月前20GB免费- 小计29 元8.8 元 3. HTTPS请求费用 - 计算公式60万次 × 0.05元/万次0 元多吉云每月前200万次免费，60万次在免费额度内- 小计3 元0 元 4. 费用抵扣 - 规则存储费可抵扣流量费无额外抵扣规则又拍云特色- 抵扣金额1.29 元 月度最终成本 - 计算公式(CDN费 - 抵扣额) + HTTPS费存储费 + CDN费 + HTTPS费 - 总计(29 - 1.29) + 3 = 30.71 元0.9 + 8.8 + 0 = 9.7 元 大家可以参考这个费用情况核算一下，更换为多吉云后可节省多少钱，基本上都能节省 2/3 左右。HTTPS 证书更新多吉云的 CDN HTTPS 证书与又拍云有些差异，又拍云提供免费与收费的证书，且免费的证书可以免费自动续签。多吉云本身提供免费的 HTTPS 证书，但自动申请证书的服务是收费的（更新成功 默认厂商 1元/次，指定厂商 2元/次），但目前处于公测阶段，限时免费 ，具体可见官方文档： https://docs.dogecloud.com/cdn/manual-config-auto-cert。 现阶段证书是免费更新的，但官方文档中说后续肯定是会收费的，那么每年的成本是多少？以多吉云证书自动更新规则来计算，证书有效期 90 天，到期前 10 天自动…

极简 Docker 入门笔记
type: item
date: 2025-09-18T14:06:00+00:00
description: 前言：本篇笔记内容来自于 B 站 《40分钟的Docker实战攻略，一期视频精通Docker》视频，博主 @技术爬爬虾，视频地址：https://www.bilibili.com/video/BV1THKyzBER6。Docker 核心概念Docker 容器Docker 简单来说就是通过容器化技术给应用程序封装一个独立的运行环境，每个运行环境就是一个容器，运行容器的计算机被称为 宿主机。与虚拟机最大的区别是：Docker 容器共享同一个系统内核，而每个虚拟机都包含一个完整的系统内核。所以 Docker 容器比虚拟机更轻量，启动速度更快。Docker 镜像镜像可以理解为是一个特殊的压缩包，容器就像是通过压缩包解压（创建）出来的文件，我们可以使用同一个压缩包，解压出很多份相同的文件，也可以将这个压缩包分享给他人，得到和我们一样的文件。这里所说的“文件”，就是上面提到的容器。我们也可以通过修改容器，并生成自己特定的 Docker 镜像，并将这些镜像分享给他人，其他人可以通过镜像，创建出和我们一样的容器环境。Docker 仓库Docker 仓库就是我们用来存储、分享镜像的地方。所有人都可以把自己的镜像上传到仓库里面，其他人就可以下载镜像并使用。Docker 的官方仓库是 Docker Hub (https://hub.docker.com)Docker 技术原理Docker 利用了 Linux 的两大原生功能，实现容器化：Cgroups 用来限制和隔离进程的资源使用。可以为每个容器设定 CPU、内存、网络带宽等资源的使用上限，确保容器的内存消耗不会影响到宿主机。Namespaces 用于隔离进程的资源视图，使得容器只能看到自己内部的进程ID、网络资源、文件目录，看不到宿主机的。容器本质上还是一个特殊的进程，但是当我们进入容器内部时，看起来就像是一个独立的操作系统Docker 安装Docker 是基于 Linux 的容器化技术，Windows 和 Mac 需要虚拟化一个 Linux 的子系统。所以 Docker最好的使用方式是使用 Linux系统的宿主机。Linux 系统Linux 系统可以通过包管理器安装 Docker，例如 Redhat 系可以使用 yum install docker 安装。 Alpine Linux 可以通过 apk add docker 安装Windows 安装打开 “Windows 功能”, 勾选上 Virtual Machine Paftform（虚拟机平台）、适用于 Linux 的 Windows 子系统，并重启电脑。管理员打开命令提示符，安装 wsl2wsl --set-default-version 2 wsl --update --web-download去 Docker 官网 或者 https://github.com/tech-shrimp/docker_installer/releases 下载符合自己系统的 Docker Desktop 安装包，并进行安装，安装成功后 可以在终端尝试一下：PS C:\Users\Administrator> docker --version Docker version 28.3.3, build 980b856在使用的过程中 Docker Desktop 需要一直开着，否则执行命令会出现这个报错。PS C:\Users\Administrator> docker ps error during connect: Get "http://%2F%2F.%2Fpipe%2FdockerDesktopLinuxEngine/v1.51/containers/json": open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified.Mac 安装直接在 Docker 官网下载安装包 安装就行。Docker 镜像下载镜像Docker Pull 命令用来从仓库下载镜像。docker pull docker.io/library/nginx:latest一个Docker 镜像下载地址包含 4 部分内容：docker.io: registry：仓库地址/注册表，如果是 Docker 官方仓库，则可以省略这个地址。library: 命名空间（镜像作者），为了防止不同用户上传同一个名字的镜像 发生冲突。“library" 是docker 官方仓库的命名空间，这个空间下的所有镜像都是由 Docker 官方维护。如果是官方的命名空间 则可以省略不写nginx: 镜像名latest: 标签名、版本号。写 "latest" 或者不写 表示获取最新版本的镜像。镜像库repository…

SQLite + zstd：定时任务日志压缩优化实践
type: item
date: 2025-08-04T14:52:00+00:00
description: 背景我们公司有大量的 PHP 和 Shell 脚本需要定时执行。起初使用 Linux 的 crontab 管理任务，但随着业务的增长，定时任务数量一度超过 50 个，管理成本迅速上升。为了方便线上操作，当时在 GitHub 上找到了 lisijie/webcron 这个项目。它功能简单，能满足基本的定时任务管理需求，我们便直接投入使用。遇到的问题随着时间推移，我们开始遇到以下两个关键问题：日志查询影响主业务性能 Webcron 默认使用 MySQL 存储任务和日志，与业务共用数据库。当日志量激增后，任务列表页面需要联表查询日志，页面加载时间常超过 30 秒，严重影响了主业务性能。日志数据膨胀，存储压力大部分任务执行频率高（如每 10 秒一次）；部分任务每次输出大量日志（3MB+）；日志需保留 6 个月。例如：项目月记录数MySQL .ibd 文件体积A 项目120 万条1.2 GBB 项目480 万条8.9 GB如果按照此增长速度保留半年，B 项目的日志将占用约 50GB 的磁盘空间。解决方案我们决定重构整个定时任务管理系统，重点优化三方面：1. 用 SQLite 替代 MySQL 存储日志MySQL 查询开销大、影响业务，我们将日志存储迁移到 SQLite。它无需额外服务，具备完整 SQL 支持，适合做独立日志存储方案，查询性能也更可控。2. 使用 zstd 压缩日志内容观察日志内容后发现，大量输出存在重复格式，非常适合压缩。我们评估了几种压缩算法：zstd（默认级别 / L7级别）zstd + 自训练字典gzip（Go 标准库实现）压缩对比如下：压缩方案A 项目（120 万）B 项目（480 万）MariaDB .ibd 文件1.2 GB8.9 GBSQLite 明文存储856 MB665 MBgzip（默认）212 MB405 MBzstd（无字典）198 MB335 MBzstd + B 项目字典149 MB192 MBzstd L7 + B 项目字典139 MB186 MBzstd + A 项目字典95.1 MB224 MB注：字典通过 zstd --train 命令生成，使用项目历史日志训练；字典在不同项目中交叉使用效果不一；字典需维护更新，综合考虑后未在最终方案中使用。最终策略是：当单条日志长度 > 150 字节时启用 zstd 压缩，否则直接存储明文。读取时自动判断并解压。3. 分月存储日志文件为了避免单文件过大并简化清理流程，我们将日志按月分别存储，每月 1 号新建一个 SQLite 日志库文件（如 2025-08.db）。这样带来两个好处：查询范围控制在单月文件，性能更稳定；清理历史数据只需删除 .db 文件即可，维护成本极低。实际效果经过重构后，系统在实际运行中表现稳定，存储与性能均有显著改善：压缩后磁盘占用：每 10 万条日志占用约 9~10 MB；查询性能：500 万条日志文件中，查询指定任务最近 20 条记录耗时 < 20ms；支持字段：支持根据任务 ID、执行状态、执行时间进行高效查询。技术实现细节开发语言：Go 1.24数据库引擎：GORM + SQLite（无 cgo 版本）压缩库：github.com/klauspost/compress为什么不用列式压缩？日志是按行追加写入的，若采用列式压缩，需要额外拆分压缩、整合再写入逻辑，开发成本较高，不适合高频日志场景。因此我们采用了“逐行压缩”策略，开发上更轻量。灵感来源与参考本项目思路部分参考了 V2EX 上的帖子：使用 SQLite 存日志 + zstd 压缩，但实际测试中压缩比与原贴略有差异。总体来说，该方案在中小型系统中表现优异，值得借鉴。后续优化方向✅ 探索 DuckDB 替代 SQLite：支持列式存储，可能带来更高压缩比与查询性能；✅ 动态字典优化：尝试用上月日志训练下月字典，实现自动演进，提高长期压缩效率；✅ 分布式合并查询支持：支持跨月日志合并检索，便于追溯问题全链路。小结这次定时任务系统重构，核心目标是“日志系统轻量化、可维护、低资源占用”。通过 SQLite + zstd 压缩 + 分月归档的组合，我们在不依赖额外服务的前提下，成功将海量日志压缩到可控范围，并提升了查询体验。如果你的系统也面临日志存储冗余、查询卡顿等问题，或许可以尝试这种“小数据库 + 压缩”的路线。文章内容由两双筷子原创，使用 ChatGPT 进行排版优化。

离线授权码设计思路
type: item
date: 2025-03-23T14:35:00+00:00
description: 对于自己的软件产品，希望别人付费、或者在我们授权的情况下才允许使用。那么我们应该如何去这个授权码 / 许可证的机制呢？前言离线授权的方案无非就是两种，一种是软件层面的授权，一种是硬件层面的授权。软件层面：我们向用户提供一串特定的字符串，用户在软件中输入我们提供的字符串，在使用端校验用户输入的授权码，即可完成软件的授权操作。硬件层面：我们向用户提供一个 USB Key（加密狗），用户在运行软件时我们可以通过硬件加密狗来判断授权信息，这种加密狗在网上 几块钱到十几块钱就能买一个，有的加密狗还内置独立时钟，可以杜绝用户进行时钟回拨等。这种加密狗可以用在对授权安全级别更高的场景中，但需要承受额外的成本：用户的使用成本，授权分发成本（加密狗+快递费+快递时间）。软件层面的加密方案使用起来更加灵活，硬件层面加密狗安全级别更高，本篇文章主要是探讨软件层面的授权方式。授权码要点那么设计一个相对安全的离线授权码，需要满足那些哪些特征呢？绑定性：每个授权码对应一台设备的授权，客户无法通过一个授权码激活多台设备。安全性：授权码应难以被伪造或篡改可验证：授权码应能被系统快速验证其合法性可复现：当客户授权码遗失时，我们可以根据客户的机器码重新生成授权码，避免用户无法使用软件的情况。时效性（可选）：授权码可包含授权有效期，限定授权使用时长。可扩展（可选）：可根据自己需求来灵活扩展授权码内容，以方便携带更多信息。你可以以任何形式生成一个满足上方条件的授权码，无需纠结生成的思路是否与我的思路一致唯一标识在离线授权场景中，我们需要确定授权设备的唯一标识，这个标识需要具有不可更改性质，在正常情况下该唯一标识都不会发生变化（例如重启软件、重启系统不会发生变化，但重装系统、更换硬件等行为会发生变化是可接受的）。在这种场景中，我们唯一标识一般采用 CPUID、主板 BIOS UUID、网卡 MAC 地址、或自定义算法来生成唯一ID，提醒一下 如果产品是服务器应用，不应使用 硬盘序列号作为唯一标识的组成部分，因为服务器硬盘都有明确的生命周期会定期更换。当更换后就会造成授权失效的情况。这个唯一标识没有明确的授权规定，大家可以根据自己的需求来选择，也可以通过现成的开源库来获取。例如我开发的主语言是 Golang，我一般会使用 github.com/denisbrodbeck/machineid 这个库来获取硬件ID，并且可以在各个系统下运转良好。授权码方案对称方案对称方案是指授权码的生成逻辑、校验逻辑完全一样。所谓校验就是客户端内部生成正确的授权码，然后和用户输入的授权码做对比，对比成功，则说明授权有效。以我个人习惯为例，授权码的字符串一般包含“机器码”、“项目名称”、“到期时间”、“盐值”，其中盐值用于增加授权码的复杂性，即使客户知道了授权码的生成方式，在不知道盐值的情况下，无法自行伪造授权码。生成过程我们先生成一个明文的字符串，然后通过特定分隔符拼接出明文的授权码，格式可以是: 机器码:项目名称:到期时间:盐值，例如：123456:tpamis:281231:abcdef123456：客户提供的机器码，这里以 123456 代替tpamis：授权项目名称，同一个机器上可能存在多个软件产品，可以加一个项目名称用于区分。281231：到期时间，这里取 2028-12-31 的后6位作为到期时间。这里也可以写成授权天数，先选定一个时间作为起始日期，然后在这个时间上叠加偏移时间，得到的最终时间作为授权到期时间。例如：我出生的时间是：1998-11-11，我以此作为起始时间。偏移时间：9628 天，得到授权到期时间为 2028-12-31。abcdef:盐值，可以防止彩虹表攻击，即使攻击者知道生成算法，也无法通过预计算破解授权码。接着，我们通过一个 MD5 算法（也可使用其他 HASH 摘要算法）得到一个签名 "cfb9fc32230fa1a19423ef8b6af63a61"，此签名就是一个授权码。但这时的授权码有一个问题，签名是不可逆的，所以我们无法在验证签名时通过签名得到授权到期时间，所以我们需要人为的拼接一下：直接拼接： cfb9fc32230fa1a19423ef8b6af63a61281231使用分隔字符： cfb9fc32230fa1a19423ef8b6af63a61-281231舍去后六位，以 UUID 的方式呈现： cfb9fc32-230f-a1a1-9423-ef8b6a281231掩藏到期时间这个时你会发现 后六位明晃晃的摆在那里，太容易被人猜到是到期时间了，虽然不会被篡改，但仍希望隐藏在授权码中，我们可以通过 十进制转十六进制来实现：281231 转十六进制为：44a8f，这时授权码变成：cfb9fc32-230f-a1a1-9423-ef8b6a44…

Typecho 垃圾评论过滤插件
type: item
date: 2025-01-27T15:18:00+00:00
description: 前言目前使用的垃圾评论过滤插件在添加词库时十分繁琐，需要进入插件的设置页面才能添加。但从操作的角度上来说，直接在评论管理页面进行操作是最符合直觉的，所以有了这款插件。功能兼容性要求：依赖 Typecho 1.2.0+ 版本，利用命名空间功能。无需修改数据库结构：通过插件配置表实现拦截功能，安全高效。便捷操作：支持直接在评论管理页面一键添加屏蔽词，操作直观。智能处理：当新增屏蔽关键词时，自动处理符合条件的待审评论，节省人工审核时间。属性联动拦截：插件可自动检测评论中被拉黑的属性。例如，若拉黑某个 IP 地址，可自动屏蔽该 IP 提交的所有评论内容，并将其加入屏蔽词库。详细统计：在插件管理页面显示以下统计信息：已定义的过滤规则总数累计拦截次数自动收集的屏蔽词数量适配移动端：注入拉黑操作按钮时，适配移动端小屏幕自定义提示：多种拦截提示可选，也可自定义提示内容界面评论管理页面拉黑操作插件配置页面下载去码云下载插件

Vue3+TS 笔记
type: item
date: 2024-12-01T12:31:00+00:00
description: 前言：本篇笔记内容来自于 B 站：《尚硅谷Vue3入门到实战，最新版vue3+TypeScript前端开发教程》系列视频链接地址： https://www.bilibili.com/video/BV1Za4y1r7KE/创建 Vue 工程NodeJS安装 18.3 + 的 NodeJS https://nodejs.org/初始化项目通过 Vite 初始化一个 Vue 项目 Vite 会在运行目录创建一个 项目同名的目录PS E:\code> npm create vue@latest > npx > create-vue Vue.js - The Progressive JavaScript Framework √ 请输入项目名称： ... test_vue3 √ 是否使用 TypeScript 语法？ ... 否 / 是 √ 是否启用 JSX 支持？ ... 否 / 是 √ 是否引入 Vue Router 进行单页面应用开发？ ... 否 / 是 √ 是否引入 Pinia 用于状态管理？ ... 否 / 是 √ 是否引入 Vitest 用于单元测试？ ... 否 / 是 √ 是否要引入一款端到端（End to End）测试工具？ » 不需要 √ 是否引入 ESLint 用于代码质量检测？ ... 否 / 是 ? 是否引入 Vue DevTools 7 扩展用于调试? (试验阶段) » 否 / 是之后通过 vscode 打开项目目录.运行项目运行前端项目要先看一下项目根目录的 package.json 文件，里面包含了一些项目的信息：{ "name": "test_vue3", "version": "0.0.0", "private": true, "type": "module", "scripts": { "dev": "vite", "build": "run-p type-check \"build-only {@}\" --", "preview": "vite preview", "build-only": "vite build", "type-check": "vue-tsc --build --force" }, "dependencies": { "vue": "^3.4.29" }, "devDependencies": { "@tsconfig/node20": "^20.1.4", "@types/node": "^20.14.5", "@vitejs/plugin-vue": "^5.0.5", "@vue/tsconfig": "^0.5.1", "npm-run-all2": "^6.2.0", "typescript": "~5.4.0", "vite": "^5.3.1", "vue-tsc": "^2.0.21" } }可以看到 scripts 目录下可以 通过的 dev 命令来启动项目，通过 build 来打包编译。我们使用 npm run dev 启动项目项目结构项目入口是根目录中的 index.html 文件，里面有两个核心操作，声明了 #app 容器，所有前端的内容渲染（挂载）到这个容器上，然后引入了 main.ts 文件main.ts 文件中引入了 Vue 组件，并创建了一个 App 的组件，挂载了节点为 App 的容器上。以根目录为例，代码如下：/index.html 入口文件 Vite App /src/main.ts 文件// 引入 createApp 用于创建应用 import {createApp} from 'vue' // 引入 App 根组件 import App from './App.vue' // 挂载 组件 createApp(App).mount('#app')/src/App.vue 文件 你好啊！ 总结Vite 项目中，index.html 是项目的入口文件，在项目最外层。加载index.html后，Vite 解析 src\App.vue 根文件 123 <Person /> 注：Vue3向下兼容Vue2语法，且Vue3中的模板中可以没有根标签。Vue3 核心语法OptionsAPI 和 CompositionAPIVue2 的 API 设计是 Options （配置、选项）风格的Vue3 的 API 设计是 Composition（组合、组件） 风格的Options API 弊端Options类型的 API，数据、方法、计算属性等，是分散在：data、methods、computed中的，若想新增或者修改一个需求，就需要分别修改：data、methods、computed，不便于维护和复用。setupsetup 概述setup 是 vue3 中…

Yii2 学习笔记
type: item
date: 2024-09-29T11:05:44+00:00
description: Yii 2 开发文档，主要参考 Yii 2.0 权威指南 两双筷子: https://www.dbkuaizi.comYii 2 安装Composercomposer create-project --prefer-dist yiisoft/yii2-app-basic basicdownload下载地址：https://www.yiiframework.com/download修改 config/web.php 文件，给 cookieValidationKey 配置项 添加一个密钥。（使用 Composre 安装自动完成该步骤）'cookieValidationKey' => '在此处输入你的密钥',内置服务器使用 serve 命令启动 php 内置服务器，启动后可通过：http://localhost:8080/ 访问php yii serve::: alert-info默认情况下会使用 8080 端口，如果需要手动指定端口可以 加上 --port 来指定:::php yii serve --port=8888基础目录结构有部分精简，主要列出核心的目录结构 ├── assets // 目录用于存放前端资源包PHP类 ├── codeception.yml ├── commands // 控制器 ├── config // 应用配置及其他配置 │ ├── console.php // 控制台应用配置信息 │ ├── db.php // 数据库配置文件 │ ├── params.php // 参数配置文件 │ ├── test.php │ ├── test_db.php │ └── web.php // Web 应用配置信息 ├── controllers // 用于存放控制器的文件夹 ├── mail // 与邮件相关的布局文件 ├── models // 模型文件夹 ├── runtime // 记录日志和缓存，要求权限 777 ├── tests // 用于存放一些测试类 ├── vendor // composer 包及 Yii 框架核心 ├── views // 视图目录 ├── web // web服务根目录（同public） │ ├── index.php // 入口文件 ├── widgets // 存放一些常用的小挂件的类文件 ├── yii // yii 控制台入口 （同 think 与 artisan ） └── yii.bat // 与 yii 文件 功能一致，运行时可省略开头的 php 框架请求流程用户向入口脚本 web/index.php 发起请求。入口脚本加载应用配置并创建一个应用 实例去处理请求。应用通过请求组件解析请求的 路由。应用创建一个控制器实例去处理请求。控制器创建一个动作实例并针对操作执行过滤器。如果任何一个过滤器返回失败，则动作取消。如果所有过滤器都通过，动作将被执行。动作会加载一个数据模型，或许是来自数据库。动作会渲染一个视图，把数据模型提供给它。渲染结果返回给响应组件。响应组件发送渲染结果给用户浏览器。模块模块是一个独立的软件单元，由 模型、视图、控制器和其他组件组成，终端用户可以访问应用主体中已安装的模块的控制器，模块应该当作小应用主体来看待，和应用主体不同的是，模块不能单独部署，必须属于某个应用主体。可以看作是 ThinkPHP 的多应用模式模块的目录结构modules // 模块目录 └── admin // admin 模块 ├── controllers // 控制器目录 │ └── DefaultController.php // 模块默认控制器 ├── models // 模型目录 ├── Module.php // 模块 └── views // 视图目录 └── default └── index.php模块构建有两种方法，一种是 使用 Gii 工具创建，另一种是手动创建。Gii 创建模块 参考：https://www.cnblogs.com/liuwanqiu/p/6815817.html以 Admin 模块为例创建模块类<?php modules/admin/Module.php namespace app\modules\admin; class Module extends \yii\base\Module { public $controllerNamespace = 'app\modules\admin\controllers'; public function init() { parent::init(); // 在这里可以引入模块自己的配置项 \Yii::configure($this, require __DIR__ . '/config.p…