资讯动态

PHP五笔字根查询系统源码拆解:从数据库到AJAX的完整实践

发布时间:2026/9/15 18:28:01 来源:尧图企业网站定制
简介这是一份面向PHP入门与进阶学习者的完整实例源码围绕五笔字根编码查询场景演示了从数据库设计到Web交互的整套开发流程。资源共12个文件、2.57MB包含php后端逻辑、sql建表语句、html页面、css样式、js前端交互及png/jpg截图和说明文档目录结构清晰便于逐个模块对照学习方便本地部署与二次开发。核心实现以wubi_codes表存储汉字、字根与编码通过GET/POST接收查询关键词使用预处理SQL语句检索并返回JSON结果同时涵盖输入过滤、结果缓存等安全与性能优化细节。借助该资源读者可系统掌握PHP与MySQL联动、HTTP请求处理、前后端数据解析及基础防注入写法还能借助截图和文档快速验证运行效果。目前已有64人学习适合用于课程设计、毕业设计或PHP实战练手是理解常见查询类Web应用的实用参考。1. 一套 PHP 五笔查询系统源码拆开前先想清楚的问题还在用五笔输入法的人几乎都遇到过「这个字我居然不会拆」的瞬间。尘烟五笔字根编码查询系统解决的正是这个问题输入一个汉字返回它的字根拆解和五笔编码。这份 PHP 源码压缩包zip里只有 index.html、doIt.php、wubi.sql、style.css 和 jquery-1.7.2.min.js没有框架也没有构建步骤解压就能跑。单看体量它是新手项目但细看会发现一个合格的 PHP 接口所需的东西——数据库表设计、预处理查询、JSON 返回、前端 AJAX、字符集处理——它全都占了。我拆这份源码时最大的感受是与其找那些动辄上万行的 PHP 项目不如先把这个小系统从头到尾吃透边界问题反而更集中。目录不复杂wubi.sql 负责把数据导入 MySQLdoIt.php 是唯一的后端入口接收查询参数、查库、返回 JSONindex.html 负责展示查询逻辑用 jQuery 1.7.2 发起异步请求。接下来我会按照「数据库 → 后端 → 前端 → 部署」的顺序把这份源码里值得抄的代码和容易踩的坑都过一遍。2. 字根数据从哪来wubi.sql 的表设计与导入细节任何查询系统的第一步都是把数据组织好五笔查询也不例外。这套源码里的 wubi.sql 是初始化脚本里面既包含了建表语句也包含了常用汉字的字根和编码数据。直接导入就能用但如果你要拿它改成自己的工具必须先搞清楚这张表是怎么设计的否则后续加数据、加字段都会很被动。2.1 表结构设计为什么不要直接用 char 当字段名我拆过的五笔类 PHP 源码里绝大多数会建成一张类似wubi_codes的表核心字段就三个汉字、字根拆解、五笔编码。摘要把字段名写成了char但真实建表时我不建议这么做因为char是 MySQL 数据类型的关键字虽然用反引号也能建但很多图形化工具里会高亮成类型给后来维护的人造成误导还是换成hanzi更清楚。CREATE TABLE wubi_codes ( id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键, hanzi VARCHAR(4) NOT NULL COMMENT 汉字单字存储, radicals VARCHAR(16) NOT NULL COMMENT 字根拆解多个字根用空格分隔, code VARCHAR(4) NOT NULL COMMENT 五笔编码简码或全码, level TINYINT NOT NULL DEFAULT 1 COMMENT 1单字 2键名 3成字字根, PRIMARY KEY (id), KEY idx_hanzi (hanzi), KEY idx_code (code) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT五笔字根编码表;几个字段值得说一下。hanzi用VARCHAR(4)而不是CHAR(1)是因为有些查询系统会顺带存词组比如「中华人民共和国」这种长度放宽一点以后不用改表结构。code用VARCHAR(4)因为五笔单字编码最长 4 位但同一个字往往有简码和全码比如「一」的简码是g全码是gggg所以hanzi不能设唯一索引否则重码数据插不进去。我给hanzi和code分别建了普通索引查询时走idx_hanzi反向按编码查字时走idx_code。数据插入的格式大概是这样INSERT INTO wubi_codes (hanzi, radicals, code, level) VALUES (一, 一, g, 3), (丁, 丁, sgh, 3), (下, 一 卜, gh, 1);radicals字段是给人看的拆字结果code字段才是真正拿去输入法的编码。查询时优先返回level值最小的一条也就是最常用的编码。如果同一汉字有多条记录前端可以把所有结果都列出来让用户自己选择用简码还是全码。2.2 数据导入命令行、phpMyAdmin 与 utf8mb4 坑拿到 wubi.sql 之后最直接的导入方式是在命令行里先建库再导入文件mysql -uroot -p -e CREATE DATABASE IF NOT EXISTS wubi DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; mysql -uroot -p wubi wubi.sql第一条命令的-e参数直接执行建库 SQLDEFAULT CHARACTER SET utf8mb4确保新库使用四字节 UTF-8否则像「」这类扩展 B 区汉字存进去会变成乱码。第二条命令把 SQL 文件导入wubi库注意文件路径要写对Windows 下用source wubi.sql;也可以mysql use wubi; mysql source /path/to/wubi.sql;导入完成后我习惯先做三件事看表结构、看总行数、抽查几条数据。这里给你一个可以直接抄的检查清单检查目的执行语句查看表使用的字符集SHOW CREATE TABLE wubi_codes;转换已有表字符集ALTER TABLE wubi_codes CONVERT TO CHARACTER SET utf8mb4;验证数据量SELECT COUNT(*) FROM wubi_codes;抽查某个字的编码SELECT hanzi, radicals, code FROM wubi_codes WHERE hanzi 下;如果导入后浏览器里查出来中文是「锟斤拷」或者「問号」基本可以判定是 SQL 文件本身的字符集和表字符集不一致。常见的套路是先把表转成 utf8mb4再重新导入数据。还有一点很多老 SQL 文件里会写TYPEMyISAM在 MySQL 5.5 之后这不报错但会有警告最佳实践是改成ENGINEInnoDB因为 InnoDB 支持事务和行级锁查询系统的数据更新不会那么频繁但插入多条重码记录时 InnoDB 更稳。3. doIt.php 的核心链路接收参数、查库、回 JSON后端文件只有 doIt.php 一个但它把 PHP 接口最基础的链路完整串起来了接收 HTTP 参数连接数据库执行 SQL把结果转成 JSON 返回。源码里用的是短标签还是?php不重要重要的是查询逻辑怎么写才能兼顾性能和安全性。3.1 用 PDO 预处理做查询老教程里最常见的写法是mysql_query(SELECT ... WHERE hanzi$char)这套函数在 PHP 7.0 已经被移除现在的环境跑会直接 Fatal error。所以拆这份源码时我会第一时间把连接层换成 PDO。?php header(Content-Type: application/json; charsetutf-8); $config [ host 127.0.0.1, db wubi, user root, pass , charset utf8mb4 ]; try { $pdo new PDO( sprintf(mysql:host%s;dbname%s;charset%s, $config[host], $config[db], $config[charset]), $config[user], $config[pass], [ PDO::ATTR_ERRMODE PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES false ] ); } catch (PDOException $e) { echo json_encode([status error, msg 数据库连接失败], JSON_UNESCAPED_UNICODE); exit; } $char isset($_GET[c]) ? trim($_GET[c]) : ; if ($char ) { echo json_encode([status error, msg 参数不能为空], JSON_UNESCAPED_UNICODE); exit; } $stmt $pdo-prepare(SELECT hanzi, radicals, code FROM wubi_codes WHERE hanzi :hanzi LIMIT 1); $stmt-execute([:hanzi $char]); $row $stmt-fetch(); if ($row) { echo json_encode([status success, data $row], JSON_UNESCAPED_UNICODE); } else { echo json_encode([status empty, msg 没有该字的五笔编码], JSON_UNESCAPED_UNICODE); }这里有几个点值得展开。PDO::ATTR_EMULATE_PREPARES false是让 PDO 关闭本地模拟预处理直接把语句发给 MySQL 做真正的预处理配合:hanzi占位符可以避免拼 SQL 带来的注入问题。json_encode第二个参数JSON_UNESCAPED_UNICODE保证返回的汉字不是\u4e00这种原始转义前端拿到的就是可直接展示的中文。isset($_GET[c])先检查参数是否存在再trim这样可以过滤掉用户误输入的空格。3.2 JSON 返回结构与异常分支接口返回结构我建议统一成「状态 数据 提示」三段式不要只返回一个裸字符串。这样前端拿到res.status就能判断走哪个分支不需要在 JS 里做字符串匹配。三种典型返回如下{status:success,data:{hanzi:下,radicals:一 卜,code:gh}}{status:empty,msg:没有该字的五笔编码}{status:error,msg:参数不能为空}status 字段取值可以按场景扩展比如数据库异常时返回error数据存在时返回success数据不存在时返回empty。注意error和empty在前端处理逻辑上不一样error需要提示用户稍后重试empty只是提示没查到不必弹错误框。status 值含义前端处理success查询成功data 有值渲染编码和字根empty查询成功但库中没有该字提示未收录error参数错误或系统异常给出可读错误信息在这个系统里doIt.php不需要输出 HTML只需要输出 JSON所以全文件不出现任何html标签。PHP 接口返回数组对象时关键是保持字段名稳定hanzi、radicals、code这三个 key 不要随意变更前端 JS 已经按它们取值了。3.3 参数校验与安全边界PHP 运算符的细节参数处理是这份源码里最容易被忽略的部分。很多初学者会直接写$char $_GET[c];然后就去拼 SQL一旦用户没有传c参数PHP 会报未定义索引的 notice。正确顺序是先isset判断存在再trim去空格最后判断是否为空字符串。$char isset($_GET[c]) ? trim($_GET[c]) : ;如果你的 PHP 版本在 7.0 以上也可以用??运算符简化成$char trim($_GET[c] ?? );。注意??和?:的区别??判断的是变量是否存在且不为 null?:判断的是布尔值为假。对于0这个输入??会保留?:会替换成默认值在处理编码查询这类场景时必须用??。安全方面最基础的一条就是不要用字符串拼接 SQL$sql SELECT code FROM wubi_codes WHERE hanzi {$char};这种写法一旦$char包含单引号语句结构就可能被破坏。我见过把doIt.php直接暴露到公网的练习项目用户提交 OR 11这种输入就可以把整张表拉出来。用前面例子里的预处理绑定参数PHP 会把输入和 SQL 结构分开传输从语法层面杜绝注入这是现代 PHP 开发的红线。4. index.html 的前端交互jQuery 1.7.2 也能做得很顺手index.html 是这套系统的脸面表面上只有一个输入框、一个按钮、一个结果区但查询体验的差异全在 AJAX 细节里。源码里引入的是 jquery-1.7.2.min.js这个版本在 2012 年前后很流行API 风格和现在的 jQuery 3.x 差别不大.on()方法从 1.7 开始支持所以事件绑定可以直接用。4.1 AJAX 请求与 URL 编码先看一段对应 doIt.php 的前端请求代码input typetext idcharInput maxlength1 placeholder请输入汉字 button idbtnQuery查询/button pre idresult/pre script srcjquery-1.7.2.min.js/script script $(function() { $(#btnQuery).on(click, function() { var c $.trim($(#charInput).val()); if (!c) { $(#result).text(请输入汉字); return; } $.getJSON(doIt.php, { c: c }, function(res) { if (res.status success) { var d res.data; $(#result).text(d.hanzi 的编码是 d.code 字根 d.radicals); } else { $(#result).text(res.msg || 未查到该字); } }).fail(function() { $(#result).text(请求失败请检查网络或 PHP 服务); }); }); }); /script$.getJSON是 jQuery 对$.ajax的封装会自动把 URL 参数做 encodeURIComponent 编码所以汉字传到后台时不会乱码。但如果你是自己拼 URL比如doIt.php?c 变量就必须先调用encodeURIComponent(c)否则遇到生僻字或特殊符号时 URL 会解析异常。有一点需要注意这个查询接口设计成 GET 请求语义上是对的。查询操作不修改数据GET 可以被浏览器缓存也能直接在地址栏访问doIt.php?c下做调试。如果后面要加「用户提交生僻字纠错」这种写操作才需要换成 POST。4.2 渲染结果与请求防抖实际用过就会发现用户输入汉字后经常会连续敲多次查询按钮或者输入法上屏后马上回车。每点击一次就发一次 AJAX数据库压力小问题不大但如果后续把查询接口接到远程服务器请求频率过高会占用 PHP-FPM 的 worker 进程。常见的做法是加一个 300ms 的防抖用户停止输入后才发起请求。var timer null; $(#charInput).on(keyup, function() { clearTimeout(timer); var c $.trim(this.value); timer setTimeout(function() { if (c) { $(#btnQuery).trigger(click); } }, 300); });这段代码监听输入框的keyup每敲一个键就清掉上一次定时器只有在 300 毫秒内没有新输入时才触发按钮点击。这样即使用户手速很快请求数也会大幅下降。防抖延时不建议设太大否则查询反馈会迟钝300ms 是输入类查询的均衡值。4.3 老版本 jQuery 的注意点jquery-1.7.2 放在今天已经算是古董版本它对 IE6/7/8 的兼容代码占了很大体积而且存在已知的 XSS 漏洞。如果这份源码只在内网用浏览器都是 Chrome/Edge可以考虑用原生 fetch 替换掉整个 jQuery 依赖fetch(doIt.php?c encodeURIComponent(c)) .then(function(res) { return res.json(); }) .then(function(json) { // 渲染逻辑 });替换之后 index.html 里可以删掉 jquery-1.7.2.min.js 的引用减少一个请求。但对于教程类源码保留 jQuery 反而更容易让新手理解 AJAX 的流程因为它把底层细节藏得很好。我的建议是学习阶段按源码方式来真正部署时再考虑去掉。5. 把这份 php 源码部署成可维护的内部查询工具源码解压后不能直接扔到生产环境完事。这一章聊的是部署会踩的坑以及如何在不改变原有逻辑的前提下把它变成一个真正能长期用的内部小工具。5.1 本地运行与 Nginx 下的坑开发调试最简单的方式是用 PHP 内置服务器在项目目录下执行php -S 0.0.0.0:8080然后浏览器访问http://localhost:8080/index.html。内置服务器会按请求路径去找对应 php 文件doIt.php 不需要任何 rewrite 配置。如果页面可以打开但查询时报数据库连接失败先用php -m | grep pdo_mysql确认 PDO 扩展存在很多 Windows 环境默认没开这个扩展需要在 php.ini 里取消;extensionpdo_mysql的注释。部署到 Nginx 时这份源码没有使用 URL 重写location /直接指向目录即可。唯一要处理的是 PHP 解析server { listen 80; server_name wubi.local; root /var/www/wubi; index index.html; location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass 127.0.0.1:9000; } }注意fastcgi_pass的地址要和 php-fpm 的监听一致监听的是 socket 就用unix:/run/php/php7.4-fpm.sock。如果部署后 HTML 能打开但 doIt.php 返回 404多半是 fastcgi 的 SCRIPT_FILENAME 没配对。另外生产环境务必在 php.ini 里设置display_errors Off否则数据库密码等敏感信息可能跟着 SQL 错误暴露在 JSON 里。5.2 查询日志与数据热更新内部工具用久了之后你会发现用户经常查一些生僻字而 wubi.sql 里没有收录。这时候可以在 doIt.php 里把查询记录追加到日志文件观察哪些字是高频缺失的file_put_contents( query.log, date(Y-m-d H:i:s) . \t . $char . \n, FILE_APPEND | LOCK_EX );日志量大了以后建议建一张query_log表代替文件写入便于统计CREATE TABLE query_log ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, hanzi VARCHAR(4) NOT NULL, hit TINYINT NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_hanzi (hanzi) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;找到高频缺字后直接往wubi_codes表里补数据不需要改代码。热更新数据时要注意如果前端之前加了缓存补数据后要清理浏览器缓存或给 AJAX 请求加一个版本参数?v20240601否则用户看到的还是旧结果。5.3 从五笔查询改造成其他编码查询这份源码的查询逻辑是「汉字 → 编码」但表里同时有code索引天然支持反向查询「编码 → 汉字」。五笔用户遇到不会拆的字时更常见的需求是先输入编码打出字再回看字根拆法所以反向查询比想象中更实用。if (isset($_GET[k]) $_GET[k] ! ) { $stmt $pdo-prepare(SELECT hanzi, radicals FROM wubi_codes WHERE code :code LIMIT 20); $stmt-execute([:code trim($_GET[k])]); $rows $stmt-fetchAll(); echo json_encode([status success, data $rows], JSON_UNESCAPED_UNICODE); }改造时先把参数名换成k再调整 SQL 的 WHERE 条件就可以做成编码联想工具。如果之后想改成拼音查询也只需要把radicals字段换成pinyin把code换成拼音字母其余链路完全复用。这些手册性质的改动恰好是这套 PHP 源码最有价值的工程实践接口边界清楚数据表独立前端只认 JSON 字段给了后来人足够的替换空间。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价