Typecho复选框无法选中问题(Handsome主题)
Bug描述
在博客handsome外观设置后台中,选中复选框后保存设置;然后刷新,此时复选框并不是选中状态,而且观察前台,正确选中复选框的操作并没有生效;
寻找Bug的思路
核心是看那一步出错了,当我们打开后台外观设置,然后选中复选框,之后保存设置,这期间到底发生了什么,一步步排查错误;
选中复选框之后,html标签会发生变化,复选框会被打上选中的标志;之后点击保存设置,浏览器会向服务器Post一个打包好的表单,表单中是各种设置的参数信息;服务器收到表单之后,会处理表单,处理好之后将数据保存在数据库的表中;前台中收到网页访问请求,在运行网站时从数据库的表中找到各种设置的参数,然后生成访问的网页;
所以我们可以从以下几个方向进行排查:
- 前端界面变化是否正确:在选中复选框后,确保HTML标签发生了相应变化,复选框被正确打上了选中的标志,同时前端代码中checked被设置为true。可以使用浏览器的开发者工具检查复选框的状态变化。
- 表单提交是否成功:在保存设置时,确保浏览器向服务器成功发送了POST请求,并且请求中包含了正确的设置内容。可以在浏览器的开发者工具中查看网络请求,确认POST请求是否包含了期待的数据。
- 服务器端数据处理是否正确:在服务器端处理表单数据时,确保数据被正确接收并保存到了数据库中。可以在服务器端的处理代码中添加日志或调试信息,以确保数据处理的逻辑正确执行。
- 前台页面加载逻辑是否正确:在前台页面加载时,确保从数据库中正确读取了设置参数,并且这些参数被正确应用到了生成的网页中。您可以检查前端代码,确认设置参数被正确地应用到了页面上。
排查Bug
前端界面变化是否正确
打开网页开发者工具(按下F12,如果进入debug模式则关闭debug模式后刷新页面)
找到复选框的html代码,看其checked参数:
可以看到checked参数为false,为未被选中;选中复选框;
选中之后,checked参数为true,说明前端界面变化正常;
表单是否正确提交
在选中几个复选框后,按下保存设置,然后看开发者设置中的网络,找到Post的内容;
找到使用POST方法的项目,发现返回码是302,代表重定向,而我们在保存设置之后会重定向到外观设置页面中,符合我们的预期;之后找到POST的具体表单信息:
可以看出我们选择的复选框的id确实被添加到了表单中(复选框对应的id可以在html看到,也可以到外观设置页面源代码中找到)
也就是当我们选中复选框后,浏览器确实把复选框被选中这一信息加入到表单中post到了服务器;
服务器端数据处理是否正确
服务器收到post的表单之后,首先进行数据处理,然后将处理过的数据保存在对应的数据库中;我们先排查数据库中是否保存了复选框选中的相关信息;
查找数据库
# 启动mysql
mysql -u root -p
# 进去mysql之后,查找所有数据库
SHOW DATABASES;
# 找到typecho使用的数据库,启动;
USE typecho_blog;
# 列出所有表;
SHOW TABLES;
# 我们发现有一张名为typecho_options的表,查看;
SELECT * FROM typecho_options;
找到indexsetup相关的项:
(如果没有处理之前,数据库中indexsetup为null,即说明数据库没有被写入;而其他非复选框项可以看到数据库中已经写入了,所以只有复选框没有被写入数据库中)
查看服务器接受的表单已经处理后的表单数据
找到文件\typecho\var\Widget\Themes\Edit.php
,打开找到处理POST的表单的相关项;
/**
* 配置外观
*
* @param string $theme 外观名
* @throws \Typecho\Db\Exception
*/
public function config(string $theme)
{
// 已经载入了外观函数
$form = Config::alloc()->config();
/** 验证表单 */
if (!Config::isExists() || $form->validate()) {
$this->response->goBack();
}
/** 处理表单数据到数据库中 */
$settings = $form->getAllRequest();
if (!$this->configHandle($settings, false)) {
if ($this->options->__get('theme:' . $theme)) {
$this->update(
['value' => serialize($settings)],
$this->db->sql()->where('name = ?', 'theme:' . $theme)
);
} else {
$this->insert([
'name' => 'theme:' . $theme,
'value' => serialize($settings),
'user' => 0
]);
}
}
/** 设置高亮 */
Notice::alloc()->highlight('theme-' . $theme);
/** 提示信息 */
Notice::alloc()->set(_t("外观设置已经保存"), 'success');
/** 转向原页 */
$this->response->redirect(Common::url('options-theme.php', $this->options->adminUrl));
}
我们可以从上面代码中看出首先程序验证表单数据form
的合法性,然后将form
中信息通过getAllRequest()
函数提取到settings
中,之后将settings
中信息分类并使用serialize()
序列化处理为字符串之后保存在数据库中;
加入输出调试信息的代码,即输出form
和settings
中的数据;
在$settings = $form->getAllRequest();
之后加入以下代码:
// 假设您已经有了$form对象,并调用了getAllRequest()方法获取了$settings数组
$formDump = print_r($form, true); // true参数使print_r返回信息而不是打印
$settingsDump = print_r($settings, true);
// 合并$form和$settings的内容
$combinedContent = "Form Object:\n" . $formDump . "\nSettings Array:\n" . $settingsDump;
// 保存内容到当前目录的bug.txt文件中,如果文件不存在会自动创建
// 指定绝对路径
$absolutePath = '/home/lighthouse/project/blog/typecho/var/Widget/Themes/bug.txt';
// 保存内容到指定目录的bug.txt文件中,如果文件不存在会自动创建
file_put_contents($absolutePath, $combinedContent);
然后在博客后台外观设置中勾选复选框之后,点击保存设置;查看/home/lighthouse/project/blog/typecho/var/Widget/Themes/bug.txt
文件,其中settings的内容如下:
Settings Array:
Array
(
[indexsetup] =>
[thumbStyle] => 0
[thumbArrangeStyle] => water_fall
[themetype] => 2
[themetypeEdit] =>
[BGtype] => 2
.........
[expert] => {
"first_screen_animate":true
}
[asideSetting] =>
[sidebarSetting] =>
)
可以看到indexsetup中的内容为空,也就是表单处理结束后复选框选中这一信息丢失了;(其余外观设置信息没有丢失!)
至于表单form转换为settings中为什么只有复选框信息丢失,笔者能力有限,没有找到;
但是可以确定settings已经错误了,导致数据库中没有复选框选中的相关信息;所以如果可以修改settings,至少可以保证之后数据库中数据正确,这样访问博客时从数据库中取数据就正确,外观设置也就可以如我们所愿。
修复Bug
在之前输出调试信息的地方手动设置settings的复选框相关项;
$settings = $form->getAllRequest();
// 假设您已经获取了settings数组,之后为新添加代码;
// $settings['featuresetup'] =
$settings['indexsetup'] = array( // 手动设置复选框被选中的项目的id到indexsetup中;
'notShowRightSideThumb',
'BigAvatar'
);
$settings['featuresetup'] = array( // 另一个复选框项目,也手动制定;
'isPjax',
'emailToQQ',
'hightlightcode',
'isPageAnimate',
"openCategory",
'FixedImageSize',
'tocThree',
'smoothscroll',
'mathJax'
);
复选框中项目的id可以在\typecho\usr\themes\handsome\functions_mine.php
中找到:
修改之后,点击外观设置,保存设置,然后打开博客前台,看设置是否生效(已生效)
同时,外观设置的前台中,我们手动设置的复选框项也已经被选中;(说明前台页面加载逻辑有效)
分别去bug.txt
中查看settings的输出信息以及在数据库中查看indexsetup项:
Settings Array:
Array
(
[indexsetup] => Array
(
[0] => notShowRightSideThumb
[1] => BigAvatar
)
[thumbStyle] => 0
[thumbArrangeStyle] => water_fall
.....
)
bug.txt
中的settings信息中,indexsetup已经非null;
数据库中信息也已经非null;
总结
虽然没有彻底解决复选框丢失的Bug,但是通过在代码中直接设定复选框对应项目有效,使得页面外观至少设置成功了;
在后台外观设置中复选框依旧没有用,如果想要选择复选框中内容,需要手动到代码中修改添加复选框的id到数组中;