背景
对建站有研究的朋友,应该知道这个网站是基于PHP和Typecho搭建的。问题起因是我今年年初手贱将Typecho更新到nightly版本,我发现更新完之后页面自定义的头图全部加载失败,这严重影响了浏览体验。考虑到头图懒加载功能是Miracles主题实现的,所以我先将网站主题切换到了其他主题,但总体来讲我还是最喜欢Miracles,网站用这个主题好几年了,实在不忍心换掉。
也是年底了,终于有空打理一下这个网站,细看了一下代码才发现这个问题其实是一个非常抽象的bug导致的,也不知道为什么头图懒加载逻辑里面会有这么明显的低级错误。
捉虫
简单读了一下源代码,发现页面头图的实现如下(访问源代码):
<img src="<?php echo Utils::addLoadingImages($this->options->CDN, $this->options->loading_image, 'normal'); ?>" data-gisrc="<?php Utils::postBanner($this); ?>">
网站通过 data-gisrc
字段配合gazeimg.js实现前端图片懒加载,进一步追踪前端代码发现 data-gisrc
字段的赋值结果是字符串1。显然问题出在这个字段上,进一步追踪 Utils::postBanner($this);
(访问源代码) ,得到:
/**
* 缩略图
*/
public static function postBanner($post){
if($post->fields->banner && $post->fields->banner=!''):
$banner = $post->fields->banner;
else:
if($GLOBALS['miraclesOptions_randomBanner']==''){
$banner = '/usr/themes/Miracles/images/postbg/';
$banner .= srand(mb_strlen($post->title));
$banner .= mt_rand(1,15).'.jpg';
}
else{
$banner_url = explode(',', $GLOBALS['miraclesOptions_randomBanner']);
$banner = $banner_url[mt_rand(0,count($banner_url)-1)];
}
endif;
//使用 TimThumb 剪裁
if($GLOBALS['miraclesIfTimThumb']=='on') {
if($GLOBALS['miraclesIfTimThumbSize']=='regular'){
$banner_size = '&h=336&w=564';
}
elseif($GLOBALS['miraclesIfTimThumbSize']=='big'){
$banner_size = '&h=420&w=705';
}
elseif($GLOBALS['miraclesIfTimThumbSize']=='large'){
$banner_size = '&h=504&w=846';
}
elseif($GLOBALS['miraclesIfTimThumbSize']=='huge'){
$banner_size = '&h=560&w=940';
}
else{
//避免有憨憨打错单词,当成 big 来算
$banner_size = '&h=420&w=705';
}
$banner_url = '/usr/themes/Miracles/libs/TimThumb.php';
$banner = $banner_url.'?src='.$banner.$banner_size;
}
//不知道为什么会有奇怪的空格,所以这里用暴力的方法去掉
$banner = trim($banner);
echo $banner;
}
盯着这段代码看了许久,实在不明白为何执行结果严重不符预期,甚至连缩进排版都没有问题...直到外卖送到,我喝了一口豆浆,抬头猛然看见 $post->fields->banner && $post->fields->banner=!''
这个条件!
如果读者朋友有一定编程功底,应该能理解这个条件的用意是判断banner是否为空,但此刻右边这个'条件'事实上对post.fields.banner进行了赋值,这么干直接导致了函数返回值异常。正确的条件应该是 isset($post->fields->banner) && $post->fields->banner !== ''
。
这是一个令人啼笑皆非的问题,修正后该函数实现如下:
/**
* 缩略图
*/
public static function postBanner($post) {
// 初始化横幅变量
$banner = '';
// 检查$post对象的banner字段是否存在且不为空
if (isset($post->fields->banner) && $post->fields->banner !== '') {
$banner = $post->fields->banner;
} else {
// 检查是否有随机横幅选项
if (empty($GLOBALS['miraclesOptions_randomBanner'])) {
$bannerDir = '/usr/themes/Miracles/images/postbg/';
$bannerNumber = mt_rand(1, 15); // 生成1到15之间的随机数
$banner = $bannerDir . $bannerNumber . '.jpg';
} else {
// 如果有随机横幅选项,则从选项中随机选择一个
$bannerUrls = explode(',', $GLOBALS['miraclesOptions_randomBanner']);
$randomIndex = mt_rand(0, count($bannerUrls) - 1);
$banner = $bannerUrls[$randomIndex];
}
}
// 检查是否使用TimThumb进行图片处理
if ($GLOBALS['miraclesIfTimThumb'] === 'on') {
// 根据配置确定图片尺寸
switch ($GLOBALS['miraclesIfTimThumbSize']) {
case 'regular':
$bannerSize = '&h=336&w=564';
break;
case 'big':
$bannerSize = '&h=420&w=705';
break;
case 'large':
$bannerSize = '&h=504&w=846';
break;
case 'huge':
$bannerSize = '&h=560&w=940';
break;
default:
// 默认使用'big'尺寸
$bannerSize = '&h=420&w=705';
}
// 构造TimThumb处理后的URL
$timThumbUrl = '/usr/themes/Miracles/libs/TimThumb.php';
$banner = $timThumbUrl . '?src=' . urlencode($banner) . $bannerSize;
}
$banner = trim($banner);
echo $banner;
}
将更改上传至服务端,问题解决。
碎碎念
这么明显的问题,之前页面头图到底是怎么正确显示的?难道还有其他地方依赖这个bug运行吗?虽然修好了,但是我愈发感到不安...
对 对吗?
Q.E.D.
0xC4A1
2024-12-15 07:55 提笔于福州
2024-12-15 08:33 完稿于福州