阅读视图

发现新文章,点击刷新页面。
🔲 ☆

告别古法编程黄金时代:AI 时代不会再有新编程语言诞生的土壤

本文永久链接 – https://tonybai.com/2026/03/24/no-soil-for-new-programming-languages-in-ai-era

大家好,我是Tony Bai。

如果你回望过去十五年的软件工程史,那无疑是编程语言百花齐放的黄金时代。

为了对抗日益膨胀的系统复杂度,人类绞尽脑汁地发明新的“咒语”:

Google 推出了 Go 语言,用极简的 Goroutine 拯救了深陷并发地狱的后端工程师;

Mozilla 孕育了 Rust,用严苛的所有权机制向内存泄漏和数据竞争宣战;

苹果用 Swift 埋葬了晦涩的 Objective-C;

JetBrains 用 Kotlin 为笨重的 Java的使用者提供了一个更优雅的选择;

微软用 TypeScript 彻底规范了狂野的 JavaScript 生态。

每一次新语言的诞生,都伴随着开发者们的狂欢。我们热衷于讨论语法糖、对比编译速度、争论哪种范式更优雅。我们在各大论坛上为自己喜爱的语言摇旗呐喊。

但这已经是最后的余晖了。

站在 2026 年的节点上,当你看着 Claude Code、Cursor 或各类 Coding Agent 在几秒钟内倾泻出数千行逻辑严密的代码时,一个残酷的真相正在浮出水面:

大模型(LLM)的爆发,彻底抽干了孕育下一代通用编程语言的土壤。属于人类的“造语言”游戏,结束了。

这不是危言耸听,而是基于技术演进第一性原理的必然推演。

语料霸权:新语言无法跨越的“生态死局”

在 AI 时代,一门编程语言的生命力不再取决于它的语法有多么优雅,而取决于它在 AI 模型中的“语料权重”

现存的主流语言(Python, Java, JavaScript, Go, C/C++等)在 GitHub 上积累了数年甚至十余年的海量开源代码。这些代码构成了大模型训练的底座,赋予了 AI 极高的“代码智商”。

当你用 Python 或 Go 提问时,AI 能够瞬间理解你的意图,补全复杂的逻辑,甚至自动发现隐藏的 Bug,因为它的“脑子”里装着上千万个成熟的 Python/Go 示例。

但对于一门新语言来说,这是绝对的死局。

假设明天某个天才发布了一门名为 Nova 的新语言,号称性能超越 C,安全性超越 Rust,语法如 Python 般简洁。

结果会怎样?

  • AI 不会写:因为训练语料里没有 Nova 的代码,大模型对它一无所知,无法提供智能补全。
  • 人类不会用:在“没有 AI 辅助就感觉不会写代码”的今天,一个习惯了口述意图,让AI Coding Agent 自动生成全量代码的程序员,绝不可能去碰一门必须纯手工敲击、AI 无法帮他编写和Debug的语言。

这就形成了一个无解的马太效应

没人写就没有语料 -> 没有语料 AI 就不会写 -> AI 不会写人类就不想学 -> 更没人写。

现存的主流语言通过“语料霸权”,彻底锁死了新语言上升的通道。

需求降维:为什么我们不再需要“更好写”的语言?

人类发明新语言的根本动力,是“人脑的带宽有限”

C++ 太容易写出内存泄漏,人脑排查太痛苦,所以我们发明了 Rust,让编译器做“真理警察”。

Java 处理异步回调太繁琐(Callback Hell),所以我们发明了各种新的语法糖。

我们一直在努力打造更锋利、更安全的斧头,因为那是人类自己要挥舞的斧头。

但在 Agentic Coding(智能体编程)时代,挥舞斧头的不再是人,而是不知疲倦的 AI。

当你可以用自然语言对 Agent 说:“用 C++ 实现一个高并发的 HTTP 服务器,并严格检查所有内存泄漏风险,写出 100% 覆盖率的测试用例。”

只要 AI 的推理能力足够强,加上自动化的沙箱验证(Eval),它完全可以写出极度安全、高效的 C++ 代码。

如果 AI 能够不知疲倦地处理最繁琐的语法、填补最冗长的样板代码(Boilerplate),并且不出错,那么“语言本身是否易读、是否好写” 似乎就变得不再重要了。

因为代码根本不是给人看的,也不是人写的。当“人脑带宽”不再是瓶颈,发明一种“让人类写得更舒服”的新语言,就失去了最大的现实动机。

语言的两极化:自然语言与“AI 中间码”

如果不再有新的面向人类的通用编程语言,未来的代码世界会变成什么样?

答案是:极端的两极分化。

上层:英语(或自然语言)成为终极编程语言。

Andrej Karpathy 的预言正在成为现实(Software 3.0)。人类不需要学习晦涩的语法,人类只需要学习如何清晰、严谨地表达意图,编写能够精准约束 AI 的 Spec(规格说明书)。我们与机器的接口,退回到了人类最擅长的媒介。

底层:只有机器能读懂的“AI 专属语言”。

如果你是大模型厂商(比如 OpenAI 或 Google),当你发现 90% 的代码都是你的模型生成的,你还会让模型生成冗长、为了兼顾人类可读性而充满妥协的 Java 或 Python 代码吗?

不会的。巨头们极有可能会研发一种专门面向 AI 优化的中间表示语言(Intermediate Representation, IR)

这种语言对人类来说如同天书,但对于模型来说:

  • Token 效率极高:原本需要 1000 个 Token 表达的逻辑,这种语言只要 50 个 Token,极大节省推理成本和上下文窗口。
  • 逻辑高度压缩:天生适合并行计算和智能体之间的状态传递。

AI 会将人类的自然语言直接“编译”成这种中间码,然后运行。

在这个过程中,介于自然语言和机器码之间、那种专门为了“让人类勉强能懂又能让机器执行”而存在的传统编程语言,其生存空间将被彻底抽空。

小结:致敬“古法编程”的黄金时代

这听起来有些感伤,但这就是技术演进的无情车轮。

就像今天,依然有人沉迷于机械表的齿轮咬合,依然有人热爱在暗房里冲洗胶卷。

“纯手工编写代码(Handcrafted Code)”——这种我们曾引以为傲的工业生产方式,未来可能也会退化成一种个人的“艺术爱好”或“思维体操”。我们称之为“古法编程”

在某个安静的周末,你或许依然会打开编辑器,为了兴趣手撸一段优雅的 Go 并发或者 Rust 生命周期,享受那种久违的、直接控制机器的“心流”多巴胺。

但在残酷的商业战场上,古法编程即将落幕。

不要再为语法糖而争论不休,不要再期待下一个能拯救你的新语言。

去锻炼你的系统思维吧,去学着用自然语言精准地描绘你的蓝图。因为在下一个时代,定义目标的造物主,永远比精通语法的泥瓦匠更稀缺。


你还在坚持“古法编程”吗?

面对 AI 现场生成代码的冲击,你是否还会为了某种语言的“优雅语法”而兴奋?在你的理想中,未来的“AI 专用中间码”应该长什么样?你是更享受亲自掌控每一行代码,还是更向往定义目标的“造物主”角色?

欢迎在评论区留下你对“古法编程”时代的最后致敬!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!

我们致力于打造一个高品质的 Go 语言深度学习AI 应用探索 平台。在这里,你将获得:

  • 体系化 Go 核心进阶内容: 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏,夯实你的 Go 内功。
  • 前沿 Go+AI 实战赋能: 紧跟时代步伐,学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等,掌握 AI 时代新技能。
  • 星主 Tony Bai 亲自答疑: 遇到难题?星主第一时间为你深度解析,扫清学习障碍。
  • 高活跃 Gopher 交流圈: 与众多优秀 Gopher 分享心得、讨论技术,碰撞思想火花。
  • 独家资源与内容首发: 技术文章、课程更新、精选资源,第一时间触达。

衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

img{512x368}


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ☆

HMAC 签名编码的坑:Go 和 PHP 的不同处理方式

在开发过程中,我们经常使用 HMAC(散列消息认证码)对数据进行签名,以确保数据完整性和身份验证。

然而,不同编程语言在对签名数据进行编码时可能会有所不同,导致相同的 HMAC 计算在不同语言中产生不同的结果。

这篇文章也是因为我直接将 PHP 的签名算法扔给 ChatGPT 生成,并没有实际测试,导致客户反馈签名计算失败,测试后才发现的。

本文将以 Go 和 PHP 为例,探讨为什么直接对 HMAC 签名进行 Base64 编码与先转换为 16 进制字符串再编码的结果不同。

代码示例

Go 代码

package main

import (
    "crypto/hmac"
    "crypto/sha1"
    "encoding/base64"
    "encoding/hex"
    "fmt"
)

func main() {
    data := "hello"
    password := "123456"
    h := hmac.New(sha1.New, []byte(password))
    h.Write([]byte(data))
    signatureBytes := h.Sum(nil)

    // 直接对 HMAC 结果进行 Base64 编码
    base64Signature := base64.StdEncoding.EncodeToString(signatureBytes)
    fmt.Println(base64Signature) // 输出:NYSQUfYBHG0EZ6pU+r+Iw4CvPIQ=

    // 先转换成 16 进制字符串,再进行 Base64 编码
    hexString := hex.EncodeToString(signatureBytes)
    base64OfHex := base64.StdEncoding.EncodeToString([]byte(hexString))
    fmt.Println(base64OfHex) // 输出:MzU4NDkwNTFmNjAxMWM2ZDA0NjdhYTU0ZmFiZjg4YzM4MGFmM2M4NA==
}

PHP 代码

<?php
$data = "hello";
$password = "123456";

// 直接对 HMAC 结果进行 Base64 编码
echo base64_encode(hash_hmac('sha1', $data, $password, true));
// 输出:NYSQUfYBHG0EZ6pU+r+Iw4CvPIQ=

echo "\n";

// 先转换成 16 进制字符串,再进行 Base64 编码
echo base64_encode(hash_hmac('sha1', $data, $password));
// 输出:MzU4NDkwNTFmNjAxMWM2ZDA0NjdhYTU0ZmFiZjg4YzM4MGFmM2M4NA==
?>

为什么结果不同?

表面上看,Go 和 PHP 代码的逻辑是相同的,但它们的 Base64 结果却不同。

其根本原因在于编码前的输入数据不同。

PHP 参数定义文档

hash_hmac(
    string $algo,
    string $data,
    #[\SensitiveParameter] string $key,
    bool $binary = false
): string

PHP 手册中也提到了:当 binary 设置为 true 输出原始二进制数据,设置为 false 输出小写 16 进制字符串。

原始二进制 vs. 16 进制字符串

  1. 原始二进制数据
    • 在 Go 代码中,signatureBytes 是 HMAC 计算出的二进制数据。
    • 在 PHP 代码中,hash_hmac('sha1', $data, $password, true) 也返回二进制数据。
    • 直接对这些二进制数据进行 Base64 编码,输出的是编码后的 HMAC 结果。
  2. 16 进制字符串转换
    • 在 PHP 中,hash_hmac('sha1', $data, $password) 默认返回 16 进制字符串,每个字节被转换成 2 个字符。
    • 在 Go 中,hex.EncodeToString(signatureBytes) 也会将二进制数据转换为 16 进制字符串。
    • 由于 16 进制字符串的长度是原始二进制数据的 2 倍,在进行 Base64 编码时,最终结果也会完全不同。

Base64 编码的作用

Base64 编码的主要作用是将二进制数据转换为文本格式,便于在 URL 或 JSON 等环境中传输。

它不会改变数据的内容,而是按照固定的方式将每 3 个字节转换为 4 个可打印字符。

因此,输入数据的不同会直接影响最终的编码结果。

如何保证一致性?

如果希望跨语言 HMAC 计算保持一致,建议:

  • 确保 Base64 编码前的数据格式一致,统一使用二进制数据进行编码。
  • 在 PHP 中,使用 hash_hmac('sha1', $data, $password, true) 以获取二进制结果。
  • 在 Go 中,直接使用 base64.StdEncoding.EncodeToString(signatureBytes),避免中间转换为 16 进制字符串。

结论

  • 直接对 HMAC 结果进行 Base64 编码,能保持原始数据格式,保证数据可还原。
  • 先转换为 16 进制字符串再进行 Base64 编码,会导致数据翻倍,最终的编码结果不同。
  • 在不同语言间使用 HMAC 签名时,务必保证编码方式的一致性,以避免验证失败。

希望这篇文章能帮助你理解 HMAC 签名在不同语言中的编码差异,并在开发中避免类似的问题!

🔲 ☆

MySQL 字符集与大小写敏感性解析

在 MySQL 数据库中,UTF-8 及其变体是最常用的字符集。

不同的 UTF-8 编码可能对大小写敏感性产生影响,主要包括以下几种:

  • utf8:MySQL 早期的 UTF-8 实现,最多支持 3 字节,无法存储部分 Emoji 字符。
  • utf8mb4:MySQL 5.5+ 版本推荐使用的 UTF-8 编码,最多支持 4 字节,能够完整存储所有 Unicode 字符。

字符集与排序规则(Collation)

MySQL 字符集搭配不同的排序规则(Collation)可能会影响查询的大小写敏感性。

常见的排序规则包括:

  • utf8_general_ci / utf8mb4_general_ci:不区分大小写(Case Insensitive,ci 代表 Case Insensitive)。
  • utf8_bin / utf8mb4_bin:区分大小写(Binary,bin 代表按二进制存储,严格区分大小写)。
  • utf8_unicode_ci / utf8mb4_unicode_ci:更符合 Unicode 规范的排序方式,不区分大小写。

默认情况下,utf8_general_ciutf8mb4_general_ci 在搜索时是不区分大小写的。

MySQL 大小写搜索问题

当 MySQL 表的字符集设置为 utf8_general_ciutf8mb4_general_ci 时,使用 LIKE= 进行查询时,默认是不区分大小写的。

例如:

SELECT * FROM users WHERE username = 'admin';

如果数据库中存储了 AdminADMIN 等,查询会返回这些所有匹配项。

如果需要执行区分大小写的查询,则需要:

  1. 修改排序规则(Collation)
ALTER TABLE users MODIFY username VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;

这样查询就会严格区分 adminAdmin

  1. 使用 BINARY 关键字
SELECT * FROM users WHERE BINARY username = 'admin';

这样 admin 只会匹配完全相同的字符串,而不会匹配 AdminADMIN 等。

在 ThinkPHP 框架中使用 whereRaw 进行原生查询

在 ThinkPHP 框架中,默认的 where 方法不支持直接使用 BINARY 进行查询,但可以通过 whereRaw 方法执行 MySQL 原生查询。

$result = Db::table('users')
    ->whereRaw("BINARY username = ?", ['admin'])
    ->find();

$result = Db::table('users')
    ->whereRaw("BINARY username LIKE ?", ['%admin%'])
    ->select();

这种方法可以避免默认的大小写不敏感查询,让 MySQL 进行更严格的匹配。

总结

  • MySQL 的 utf8_general_ciutf8mb4_general_ci 默认不区分大小写。
  • 需要区分大小写时,可以修改排序规则(Collation)或使用 BINARY 关键字。
  • 在 ThinkPHP 框架中,可以使用 whereRaw 方法执行 MySQL 原生查询,确保大小写敏感匹配。

这样,你就可以在 ThinkPHP 框架中更灵活地处理 MySQL 字符集大小写敏感的问题。

🔲 ☆

PHP 中生成带毫秒的时间戳

今天在对接一个 API 的时候,发现需要生成高精度的时间戳,格式为yyyyMMddHH24mmssSSS

本文将介绍两种常见的实现方式,并讨论它们的优缺点。

时间格式解析

格式 yyyyMMddHH24mmssSSS 的含义如下:

  • yyyy:四位数的年份(例如:2025)。
  • MM:两位数的月份(01-12)。
  • dd:两位数的日期(01-31)。
  • HH24:两位数的小时(24 小时制,00-23)。
  • mm:两位数的分钟(00-59)。
  • ss:两位数的秒(00-59)。
  • SSS:三位数的毫秒(000-999)。

例如,时间 2025-01-02 11:30:45.123 的格式化结果为:20250102113045123

使用 DateTime 类实现

以下是使用 DateTime 类生成毫秒时间戳的代码示例:

<?php
$dateTime = new DateTime();
// 获取当前时间的微秒数并计算为毫秒
$milliseconds = intval($dateTime->format('u') / 1000);
// 格式化时间
$formattedTime = $dateTime->format("YmdHi") . $dateTime->format("s") . sprintf("%03d", $milliseconds);
echo $formattedTime;

代码解析

  1. $dateTime->format('u') 返回当前时间的微秒(6 位数,例如 123456)。
  2. intval($dateTime->format('u') / 1000) 将微秒转换为毫秒(3 位数,例如 123)。
  3. 使用 sprintf("%03d", $milliseconds) 确保毫秒部分始终为 3 位数(不足时补零)。

示例输出

假设当前时间为 2025-01-02 11:30:45.123456,输出结果为:

20250102113045123

使用 microtime 函数实现

另一种方法是结合 microtime()date() 函数:

<?php
$microtime = microtime(true);
// 格式化时间到秒
$formattedDate = date('YmdHis', floor($microtime));
// 获取毫秒部分
$milliseconds = sprintf('%03d', ($microtime - floor($microtime)) * 1000);
// 拼接毫秒
$formattedDate .= $milliseconds;
echo $formattedDate;

代码解析

  1. microtime(true) 返回当前 Unix 时间戳,包含秒和小数部分。
  2. floor($microtime) 获取整数秒部分。
  3. ($microtime - floor($microtime)) * 1000 提取小数部分并转换为毫秒。
  4. 最终拼接秒部分和毫秒部分,生成完整的时间戳。

示例输出

假设当前时间为 2025-01-02 15:30:45.123456,输出结果为:

20250102153045123

对比分析

特性 使用 DateTime 使用 microtime()
代码简洁性 更加现代化,语义清晰 较为传统,需要手动处理毫秒
精度 取决于系统支持的时间精度 依赖 microtime() 的实现
扩展性 更容易与其他 DateTime 操作结合 适合处理与 Unix 时间戳相关的逻辑

统一验证输出

为了验证两种方法的输出是否一致,可以添加以下代码:

if ($formattedTime === $formattedDate) {
    echo "两种方法的输出一致:$formattedTime\n";
} else {
    echo "两种方法的输出不一致:\n第一种方法:$formattedTime\n第二种方法:$formattedDate\n";
}

总结

  • 如果你的项目主要使用 DateTime 类,建议采用第一种方法,代码语义更加清晰。
  • 如果需要与 microtime() 或 Unix 时间戳直接交互,可以选择第二种方法。

选择哪种方式主要取决于项目需求和代码风格偏好。希望本文对你在生成带毫秒的时间戳方面有所帮助!

🔲 ☆

开源项目目录📇

部分开源项目源码。

PHP8 探针项目(包含WP插件)

专业的服务器监控和管理工具,提供实时系统监控、性能测试、数据库检测等功能。本项目包含两个版本:独立PHP探针和WordPress插件版本。

 项目结构

php8-probe/
├── phpprobe.php              # 独立PHP探针(可直接访问)
├── php-probe-widget/         # WordPress插件版本
│   ├── php-probe-widget.php  # 主插件文件
│   ├── includes/             # 小组件类
│   ├── css/                  # 前端样式
│   ├── js/                   # 前端脚本
│   └── README.md             # 插件详细文档
├── LICENSE                   # 许可证
└── README.md                 # 本文件

🚀 快速开始

方式一:独立PHP探针

  1. 将 phpprobe.php 上传到您的Web服务器
  2. 通过浏览器访问该文件即可查看服务器信息
  3. 支持实时监控、性能测试、数据库检测等功能

特点:

  • ✅ 无需安装,直接使用
  • ✅ 单文件部署,简单方便
  • ✅ 支持多平台(Linux、Windows、macOS、FreeBSD)
  • ✅ 实时系统监控

方式二:WordPress插件

  1. 将 php-probe-widget 文件夹复制到 wp-content/plugins/ 目录
  2. 在WordPress后台激活”服务器监控探针”插件
  3. 进入 外观 > 小组件 页面
  4. 将”服务器监控探针”小组件拖拽到侧边栏
  5. 配置显示选项和主题设置

https://gitee.com/obaby/php8-probe


结巴分词HTTP服务

基于Flask和jieba的本地HTTP分词服务。

https://gitee.com/obaby/baby-jb-server


WordPress 博客数据分析工具

这是一个用于分析 WordPress 博客数据的 Python 工具,可以通过 WordPress REST API 获取并分析博客的文章和评论数据。

功能特性

  • 📝 统计指定年份发布的文章数量(按月统计)
  • 💬 统计指定年份的评论数量
  • 🏆 分析评论用户的评论数排行
  • 💾 将分析结果保存为 JSON 文件

https://gitee.com/obaby/baby-wp-data-analysis-tool


微信双开脚本 (WeChat Dual Launch Script)

一个用于 macOS 系统的微信双开自动化脚本,通过复制微信应用并修改 Bundle ID 实现真正的微信双开功能。

📋 功能特性

  • ✅ 一键双开 – 自动完成所有设置步骤
  • ✅ 智能检测 – 自动检测已存在的 WeChat2.app
  • ✅ 安全可靠 – 完善的错误处理和权限检查
  • ✅ 彩色输出 – 友好的命令行界面
  • ✅ 进程管理 – 查看和管理微信进程
  • ✅ 自动化设置 – 无需手动执行复杂命令

https://github.com/obaby/baby-wechat


Baby 足迹地图

 

简介:

 

基于百度地图的足迹地图。
启动服务之后,先去后台 地图 key 设置页面,添加百度地图浏览器端 ak!
启动服务之后,先去后台 地图 key 设置页面,添加百度地图浏览器端 ak!
启动服务之后,先去后台 地图 key 设置页面,添加百度地图浏览器端 ak!

为了防止 js 地址解析受限,需要同时添加服务端 ak!
为了防止 js 地址解析受限,需要同时添加服务端 ak!
为了防止 js 地址解析受限,需要同时添加服务端 ak!

添加之后,访问: http://127.0.0.1:10099/api/location/process-my-location/ 地址刷新数据库的地点坐标信息,后续无需再通过 js 接口进行解析!

https://github.com/obaby/BabyFootprintV2


Simple microblogging

Add a microblog to your site; display the microposts in a widget or using a shortcode. 
增强版优化页面显示,增加分页功能。wp微博插件。

 

https://github.com/obaby/Simple-microblogging-wordpress-plugin


Baby WP 评论强化拦截插件

 

一个强大的WordPress评论过滤插件,支持字数限制、中文检测、关键词过滤等功能。

插件信息

 

  • 插件名称: Baby WP 评论强化拦截插件
  • 版本: 1.0.5
  • 作者: obaby
  • 作者网址https://h4ck.org.cn
  • 许可证: GPL v2 or later

功能特性

 

🛡 评论过滤功能

 

  • 字数限制: 设置评论的最少和最多字数
  • 中文检测: 要求评论必须包含中文字符
  • 关键词过滤: 支持自定义关键词和WordPress设置的关键词
  • 正则表达式支持: 支持使用正则表达式进行高级匹配

⚙ 管理功能

 

  • 简单设置界面: 直观的管理后台设置页面
  • 错误消息自定义: 可以自定义各种错误提示消息和标题
  • 统计信息: 记录评论过滤统计信息,支持重置功能
  • WordPress集成: 与WordPress讨论设置完美集成,支持实时预览
  • 设置验证: 完整的输入验证和数据清理机制

🔧 技术特性

 

  • 简单架构: 采用简单的面向对象架构,易于维护
  • 性能优化: 高效的过滤算法,不影响网站性能
  • 兼容性: 支持WordPress 5.0+版本,PHP 7.4+
  • 多语言: 支持多语言环境
  • 数据安全: 完整的输入验证和清理机制
  • 错误处理: 完善的错误处理和日志记录

https://github.com/obaby/baby-wp-comment-filter


WinRAR-Keygen

 

1. What is WinRAR?

 

  • WinRAR is a trialware file archiver utility for Windows, developed by Eugene Roshal of win.rar GmbH.

  • It can create and view archives in RAR or ZIP file formats and unpack numerous archive file formats.

  • WinRAR is not a free software. If you want to use it, you should pay to RARLAB and then you will get a license file named "rarreg.key".

  • This repository will tell you how WinRAR license file "rarreg.key" is generated.

2. How is “rarreg.key” generated?

 

  • WinRAR uses a signature algorithm, which is a variant of Chinese SM2 digital signature algorithm, to process the user’s name and the license type he/she got. Save the result to “rarreg.key” and add some header info, then a license file is generated.

https://github.com/obaby/winrar-keygen


Baby Device Manager

 

一个功能强大的WordPress设备管理系统插件,支持设备分组管理、设备信息管理、自定义排序、状态跟踪等功能。

功能特点

 

  • 设备分组管理
    • 创建和管理设备分组
    • 自定义分组排序
    • 分组描述信息
  • 设备管理
    • 添加/编辑/删除设备
    • 设备状态管理(在售、停售、已售出、维修中、已报废)
    • 设备图片和产品链接
    • 自定义设备排序
    • 设备描述信息
  • 前端展示
    • 响应式布局
    • 按分组分类显示
    • 支持多种排序方式
    • 美观的界面设计
    • 支持自定义每行显示设备数量(1-6个)
  • 其他功能
    • 图片管理:支持设备图片上传和显示
    • 产品链接:支持添加产品详情页链接
    • 状态跟踪:支持多种设备状态管理
    • 自定义排序:支持设备分组和设备的自定义排序

https://github.com/obaby/Baby-Device-Manager


RSS Beauty

 

为 WordPress RSS Feed 提供美观的网页展示样式(基于 RSS.Beauty 的 Pink 主题)。

项目功能

 

  • RSS 样式化:在 Feed 中注入 XSL 样式表,浏览器打开 feed 地址时以 HTML 页面形式展示,而非原始 XML。
  • Feed Content-Type:将 feed 的 Content-Type 设为 application/xml,使浏览器按 XML 解析并应用 xml-stylesheet
  • XSL 地址:样式表使用插件目录下的静态文件 pink.xsl。需在 OpenResty/Nginx 中为 .xsl 配置正确的 Content-Type(见下方配置说明),否则浏览器可能不按 XSL 解析。
  • 主题:内置淡粉色(light pink)页面背景与适配的文字颜色。

https://cnb.cool/oba.by/rss-beauty


WP-UserAgent

 

Contributors: obaby
Donate Link: https://oba.by
Tags: useragent, user-agent, user agent, web, browser, web browser, operating system, platform, os, mac, apple, windows, win, linux, phone
Requires at least: 2.0
Tested up to: 6.3
Stable tag: 16.06.99

IP 查询方式(归属地)

 

插件支持四种 IP 查询方式,可在 设置 → WP-UserAgent 中选择:

方式 说明
IP2Location 使用 IP2Location 数据库(需将 BIN 文件放入 show-useragent/ip2location_db/db/),依赖 Composer
CZDB 使用纯真 CZDB 数据库(需授权与 db 文件放入 show-useragent/czdb/db/),依赖 Composer
ip2region 使用 ip2region xdb(仅内置 ip2reginapi,不依赖 Composer)。需将 xdb 文件放入 show-useragent/ip2region_db/,文件名:ip2region_v4.xdbip2region_v6.xdb
纯真QQWRY 使用 qqwry_api(qqwry.dat + ipv6wry.db),无需 Composer。数据文件放入 show-useragent/qqwry_api/ipdata/

选择 ip2region 或 纯真QQWRY 时不会加载 vendor/autoload.php。若选择 IP2Location 或 CZDB 时 vendor 加载失败,插件会自动回退为 ip2region 模式,避免站点白屏。

Description

 

WP-UserAgent is a simple plugin that allows you to display details about a computer’s operating system or web browser that your visitors comment from.

It uses the comment->agent property to access the User-Agent string. Through a series of regular expressions, this plugin is able to detect the operating system and browser which can be integrated in comments or placed in custom places through your template(s).

I’m adding new web browsers and operating systems frequently, as well as updating and optimizing the source code. Your feedback is very important, new features have been added by request, so if there’s something you would like to see in WP-UserAgentleave a comment, and I’ll see what I can do.

WP-UserAgent was written with Geany – http://www.geany.org/
Images created with The Gimp – http://www.gimp.org/

注意:

  • 使用 CZDB 时:若更新替换纯真数据库,请同步更新 show-useragent/ip2c-text.php 中的 $key = 'n2pf2+PrE1y9I55MjdpLpg==';
  • 使用 ip2region 时:将 xdb 文件放入 show-useragent/ip2region_db/ip2region_v4.xdbip2region_v6.xdb),无需 Composer。

https://cnb.cool/oba.by/wp-useragent

 

 

🔲 ☆

PHP 8.5 新特性

PHP 8.5 于 2025年11月20日 正式发布。本次更新包含管道运算符、clone with 语法、全新 URI 解析器等多项功能。
元素周期表抱枕
🔲 ☆

PHP 2025 现状报告

《2025 PHP现状报告》 深入剖析开发者如何使用、偏好及依赖PHP,展现这一经典网络语言如何通过新型框架、增强工具及AI辅助工作流持续实现现代化转型。
元素周期表抱枕
🔲 ☆

告:当前本站即将尝试更新主题代码以适配PHP8

在当前的Wordpress 6.8.2版本,WordPress官方已经将曾经主要支持的php7.4作为了非建议版本

目前WordPress官方建议的版本为PHP 8.3

那么,在近期也将会在生产环境中进行适配工作,以确保主题能够在PHP8.3的情况下正常工作,且将PHP重新编译更新

如果在访问时产生意料之外的错误页面,属于正常现象,请不必惊慌

🔲 ☆

介绍下laravel herd工具

herd是在使用过了valet之后,又一款laravel出品的好用的工具,之前使用valet可以把laravel应用的本地域名解析和https加密等都处理好,是个非常不错的工具。
但是在我的使用场景里还有一个比较头疼的问题就是多版本php的切换,虽然php在大型网站,

🔲 ⭐

Alibaba Cloud Linux 3 yum 安装 PHP8.1

一、安装源

rpm -ivh --nodeps https://rpms.remirepo.net/enterprise/remi-release-8.rpm
sed -i 's/PLATFORM_ID="platform:al8"/PLATFORM_ID="platform:el8"/g' /etc/os-release
## 安装 PHP8.1 
sed -i 's/PLATFORM_ID="platform:el8"/PLATFORM_ID="platform:al8"/g' /etc/os-release

二、安装 PHP8.1

yum install -y php81-php-fpm php81-php-cli php81-php-bcmath php81-php-gd php81-php-json php81-php-mbstring php81-php-mcrypt php81-php-mysqlnd php81-php-opcache php81-php-pdo php81-php-pecl-crypto php81-php-pecl-mcrypt php81-php-pecl-geoip php81-php-recode php81-php-snmp php81-php-soap php81-php-xml php81-php-pecl-redis php81-php-pecl-apcu 

The post Alibaba Cloud Linux 3 yum 安装 PHP8.1 first appeared on Lenix Blog.

🔲 ☆

[中文] Confusion Attacks: Exploiting Hidden Semantic Ambiguity in Apache HTTP Server!

Orange Tsai (@orange_8361) &nbsp;|&nbsp; 繁體中文版本 &nbsp;|&nbsp; English Version嗨,這是我今年發表在 Black Hat USA 2024 上針對 Apache HTTP Server 的研究。 此外,這份研究也將在 HITCON 和 OrangeCon 上發表,有興趣搶先了解可點此取得投影片: Confusion Attacks: Exploiting Hidden Semantic Ambiguity in Apache HTTP Server! 另外也謝謝來自 Akamai 的友善聯繫! 此份研究發表後第一時間他們也發佈了緩解措施 (詳情可參考 Akamai 的部落格)。TL;DR這篇文章探索了 Apache HTTP Server 中存在的架構問題,介紹了數個 Httpd 的架構債,包含 3 種不同的

🔲 ☆

PHP CGI Windows平台远程代码执行漏洞(CVE-2024-4577)分析与复现

在2024.6.6今天,@Orange在他的博客发布了他即将在2024年8月Black Hat USA公开的议题《Confusion Attacks: Exploiting Hidden Semantic Ambiguity in Apache HTTP Server!

伴随着议题的发布,今天在DEVCORE的官方博客发布了一个漏洞通报,也就是存在于windows特殊场景下的PHP CGI远程代码执行漏洞

接下来看看漏洞的详情

漏洞描述

CVE-2024-4577导致漏洞产生的本质其实是Windows系统内字符编码转换的Best-Fit特性导致的,相对来说PHP在这个漏洞里更像是一个受害者。

由于Windows系统内字符编码转换的Best-Fit特性导致PHP原本的安全限制被绕过,再加上一些特殊的PHP CGI环境配置导致了这个问题,最终导致漏洞利用的算是一些PHP的小技巧。

影响范围

这个漏洞理论上影响PHP的所有版本

  • PHP 8.3 < 8.3.8
  • PHP 8.2 < 8.2.20
  • PHP 8.1 < 8.1.29

除此之外的其他PHP版本官方已经不再维护了,包括PHP8.0、PHP7、PHP5在内,但是理论上来说他们都受到这个影响。

漏洞利用条件

Windows系统内字符编码转换的Best-Fit特性

前面提到过,这个漏洞的利用前提是由于Windows系统内字符编码转换的Best-Fit特性,所以第一个前提条件就是

  • 必须是Window环境

其次由于这个特性,windows必须使用以下其中之一的语言系统

  • 繁体中文 (字码页 950)
  • 简体中文 (字码页 936)
  • 日文 (字码页 932)

而且除了这3个以外,其他的语言也不能完全排除影响,凡是存在该特性的的系统都受到影响。

那什么是Best-Fit呢?或者说,为什么是Best-Fit?

说白了其实就是windows对于不同编码字符集之间转化的一个特性,可能大家对于Best-Fit很陌生,如果换一个词叫做宽字节,我想大家就会很熟悉了,说白了就是一些特殊字符在特殊字符集下转化就会转成一个正常的字符

而这里用到的就是%ad

img

而这个正常的字符就是-,我们可以结合php的源码来看,为什么这个-很重要

https://github.com/php/php-src/commit/4dd9a36c16#diff-680b80075cd2f8c1bbeb33b6ef6c41fb1f17ab98f28e5f87d12d82264ca99729R1798

img

在php的代码当中其实原本就过滤了-这个符号,在新的commit当中还加入了对0x80以上的所有字符的限制来修复这个问题。在代码的注释当中有这么一段话来解释这个问题

1
2
3
4
5
6
7
Something is wrong with the XAMPP installation :-(
Apache CGI will pass the query string to the command line if it doesn't contain a '='.
This can create an issue where a malicious request can pass command line arguments to
the executable. Ideally we skip argument parsing when we're in cgi or fastcgi mode,
but that breaks PHP scripts on Linux with a hashbang: `#!/php-cgi -d option=value`.
Therefore, this code only prevents passing arguments if the query string starts with a '-'.
Similarly, scripts spawned in subprocesses on Windows may have the same issue.

如果get发送的请求字符串中不包含”=”,那么Apache就会把请求传到命令行作为cgi的参数。但这会导致恶意请求就可以将命令行参数传递给php,如果直接处理传参,那么会影响到以独立脚本方式运行的PHP脚本。所以只有当开头是-的时候(跳过所有空白符号)才阻止传递参数

而这个漏洞在2012年的时候就被曝光出来,就是CVE-2012-1823

https://www.leavesongs.com/PENETRATION/php-cgi-cve-2012-1823.html

当我们用%ad来代替-之后,参数传递没有被阻止,就构成了参数注入

而PHP和Apache的环境就会更特殊一点儿,其实在2024年你很难找到类似的环境,但是很有趣的是,XAMPP For Windows的默认环境就受到这个漏洞的影响。

而相对更具体的受影响的场景有两个

以CGI模式运行的PHP环境

首先不得不说,这是一个非常非常少见的场景,在2024年你几乎没办法找到一个直接以CGI模式运行的PHP环境,而且也没人会去做这样的修改。

如果你想要改出类似的设定你需要加入以下的配置

1
2
AddHandler cgi-script .php
Action cgi-script "/cgi-bin/php-cgi.exe"

或者类似于

1
2
3
4
5
<FilesMatch "\.php$">
SetHandler application/x-httpd-php-cgi
</FilesMatch>

Action application/x-httpd-php-cgi "/php-cgi/php-cgi.exe"

在XMAPP的默认配置当中,这部分代码也是被注释的,如果你想要测试这种利用需要在httpd-xampp.conf中注释解开下面这段代码

1
2
3
4
5
6
7
8
9
#
# PHP-CGI setup
#
<FilesMatch "\.php$">
SetHandler application/x-httpd-php-cgi
</FilesMatch>
<IfModule actions_module>
Action application/x-httpd-php-cgi "/php-cgi/php-cgi.exe"
</IfModule>

上面这些配置处理的都是一个类似的场景,就是apache会把请求直接转发给php-cgi

结合上面的特性,你可以通过传%ad来传入一个-,这样在-之后的部分就会成为php-cgi的参数,构成参数注入

img

1
%add+allow_url_include%3don+%add+auto_prepend_file%3dphp://input

会变成

1
-d allow_url_include=on -d auto_prepend_file=php://input

构成参数注入导致最终的任意代码执行

将PHP的执行程序暴露在外 - XAMPP默认配置

这个场景要特别一些,相比直接把PHP的二进制直接放在web目录下,可能更常见的还是xampp的默认配置。

在httpd-xampp.conf中就可以找到这一串代码

1
2
3
4
5
6
7
8
9
ScriptAlias /php-cgi/ "D:/xampp/php/"
<Directory "D:/xampp/php">
AllowOverride None
Options None
Require all denied
<Files "php-cgi.exe">
Require all granted
</Files>
</Directory>

上面的配置是什么意思呢?

其实就是访问/php-cgi/路径的时候,会映射D:/xampp/php/下的文件,而这个目录下正好是php的整个目录

img

但这又有什么用呢,毕竟都denied了,只有php-cgi.exe是granted的,我们把视角还是回到php-cgi上。

如果我们直接访问调用php-cgi.exe,会怎么样呢?

答案是会有安全警告

img

那我们顺着这个思路去看下代码

https://github.com/php/php-src/blob/51379d66ec8732e506c43f6c7f1befc500117ae8/sapi/cgi/cgi_main.c#L1912

img

我们会发现我们遇到了一个新的概念叫做force_redirect,这其实算是PHP的一个自我保护机制。在P牛的知识星球里就有提过这个问题。

https://wx.zsxq.com/dweb2/index/topic_detail/15411452114282

说白了就是,PHP增加了一个配置叫做cgi.force_redirect=1开启了这个选项(默认开启)之后,只有经过重定向的规则请求才能执行,不能直接调用执行。那有什么办法绕过呢?

其实如果顺着逻辑到这里,就已经很清晰了,第一个办法也就是最直接的办法就是,既然前面已经实现了-d修改配置,那么你就正好-d再把cgi.force_redirect修改成0就行了,非常直白。

img

而第二个办法相对来说比较少见,我们继续回到源码当中可以发现,除了force_redirect的分支以外,其实如果能确保REDIRECT_STATUS或者HTTP_REDIRECT_STATUS存在值,也可以不进入到这个分支里。

image-20240611095958631

当然一般来说这种变量是不可控的,但是HTTP开头的变量一般来自于请求的头,那么我们就可以在请求头中加入Redirect-status: 1来设置这个变量,同样可以绕过

🔲 ⭐

PHP 使用 curl 访问获取 https 网站的内容

遇到一个 PHP 获取 https 网站内容的问题,这里整理成博文供搭建参考。 需求是目前自己搭建了一个国外的博文网站,打算使用国内的服务器进行加速访问。

查阅了 PHP 相关资料之后,发现 PHP 的 get_file_contents 和 curl 均可以实现。 get_file_contents 能实现简单的,考虑到要实现 Header 等内容的获取和传输, 于是使用了 curl 实现。编码完成之后发现报以下错误信息:

Exception 35: SSL connect error

面向搜索引擎解决 BUG,发现是因为 SSL 协议的问题,默认的情况下服务器端禁用了低版本的 SSL 协议, 于是我们需要指定 PHP 使用高版本的 SSL 协议请求服务器端(国外的博文网站)。

// 这是我的博客网站
$siteUrl = 'https://blog.xiaoi.me';

function httpGet($url) {
    try {
        $ch = curl_init();
    
        if (FALSE === $ch)
            throw new Exception('failed to initialize');
 
        curl_setopt($ch,CURLOPT_URL, $url);
        // 这里为关键代码,经过几次测试只有,发现需要调整到 6 以上,具体可参考博文底部链接
        curl_setopt($ch, CURLOPT_SSLVERSION, 6);
    
        $content = curl_exec($ch);
    
        if (FALSE === $content)
            throw new Exception(curl_error($ch), curl_errno($ch));
    
        var_dump($content);
    } catch(Exception $e) {
        echo 'Exception ' . $e->getCode() . ': ' . $e->getMessage();
    }
}

echo httpGet($siteUrl . $_GET['uri']);

通过使用以上的 PHP 代码即可完成基本的加速访问,原来使用 https://blog.xiaoi.me/a/b/c.html`` 访问的内容, 可以通过 PHP 加速访问,例如:proxy.php?uri=/a/b/c.html```

总结

低版本 SSL 协议安全性很低,建议将自己的网站等应用禁用低版本 SSL 协议,并且有类似本文这样的需求时, 同时也将客户端的 SSL 协议版本提高,这样保证数据安全以及代码可用性。

参考文献

版权

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
原创作者:10086@xiaoi.me 发表于 Xiaoi’s Blog:https://blog.xiaoi.me
原文链接:https://blog.xiaoi.me/2019/10/31/php-curl-ssl

扫码关注我,在线与我沟通、咨询 Xiaoi's Blog

转载请保留原文链接以及版权信息

🔲 ⭐

vuejs、php、caddy 与 docker —— web 期末大作业上云部署

这学期修了一门叫《用HTML5 和 PHP编写JavaScript,jQuery 和 AJAX脚本》的 web 课(对,听起来很奇怪的名字)。期末大作业是写一个影评系统,前端允许使用框架,后端仅允许使用 php,具体的作业要求如下

作业要求

(源码会在验收结束以后开源)

大作业写了得要有三个礼拜,工作时长加起来得有 30 个小时,想着验收之前上线一段时间积累一些评论数据,验收的时候也会更加顺利一些,于是就开始尝试在服务器上部署。部署的过程还是比较复杂的,所以写下这篇博客记录一下。

后端部分

早前有《PicUploader使用系列(一)——在Archlinux上使用Caddy部署PicUploader》的经验,便觉得使用 Caddy + php-fpm 部署的方式多少有点麻烦了,这次便尝试了使用 Docker 部署、Caddy 反代的方式。

Dockerfile 如下:

FROM php:8-apache
RUN docker-php-ext-install mysqli
RUN a2enmod rewrite
COPY . /var/www/html
EXPOSE 80

在后端的根目录下有一个 .htaccess 文件,将所有的请求都交给 index.php 来处理,这样就可以根据我的上一篇博客中所提到的方式去构建不使用任何 php 框架实现的简易 router 效果

RewriteEngine On
RewriteRule ^(.*) index.php [QSA,L]

构建 Docker 镜像时使用 docker build . -t mrs-php 命令,运行 docker 容器时使用命令

docker run -d \
    -p 7788:80 \
    --name mrs-php \
    -v /path/to/uploads:/var/www/html/uploads \
    --restart unless-stopped \
    mrs-php

这样,后端就在 7788 端口上开起来了,后续 Caddy 只要将打到 /api/*/uploads/* 的请求转发到 7788 端口即可,避免了使用 php-fpm 时需要的配置。uploads 目录是用来存放图片的,我将这个路径挂在在宿主机的目录下,方便备份导入等操作。

mysql 连接时的小插曲

需要注意的是,在 Docker 容器中运行的 php 如果想要访问宿主机上的 mysql,需要注意修改 mysql 服务器的 ip 地址,并允许 mysql 接收来自非本机的请求。

在宿主机中运行 ip -br a 命令可以看到 docker 所采用的虚拟网卡的 ip 地址

docker0          UP             172.17.0.1/16 fe80::42:eff:febf:b26c/64

我这边得到的 ip 地址是 172.17.0.1,所以在 php 那边访问的数据库 ip 地址就应该是 172.17.0.1,而非 localhost 或者 127.0.0.1

此外,需要允许宿主机的 mysql 接收来自 Docker 容器的请求

使用 docker network inspect bridge 命令可以查到 docker 容器的 ip 地址,接着需要去允许来自这个 ip 的请求。建议去网上自行搜索,因为 mysql 语句我自己也不熟悉。我使用的 mysql 版本是 8,语句似乎和以前的版本不兼容?我使用下面三个命令轮着输就好了(有时候报错,有时侯又不报错),有大佬懂的话评论区讲讲。

use mysql;
GRANT ALL ON *.* TO 'root'@'%';
update user set host='%' where user='root';
GRANT ALL ON *.* TO 'root'@'%';

前端部分

前端部分部署起来没什么难度

我使用的是 vite 开发的 vuejs 项目,直接使用 pnpm build 构建出静态文件,然后放入了 /var/www/mrs 目录,这部分没什么可说的

Caddy 配置

Caddy 配置如下

example.com {
    handle /api/* {
        reverse_proxy localhost:7788
    }

    handle /uploads/* {
        reverse_proxy localhost:7788
    }

    handle /* {
        root * /var/www/mrs
        file_server
        try_files {path} /
    }
}

将打到 /api/*/uploads/* 都交给 7788 端口的后端进行处理,前端部分要使用 try_files 将请求都指向 //index.html 交由 vue-router 处理,否则 caddy 就找不到对应的文件了。这里我尝试过使用 route 关键词代替 handle,但 try_files 的功能没有生效,这两者的区别官方文档中有提到,但我没看懂,等我以后看看有没有机会去折腾了。

参考:

使用Caddy配置同一域名下的前后分离

Caddy 2

❌