Loading... # 背景 对建站有研究的朋友,应该知道这个网站是基于PHP和Typecho搭建的。问题起因是我今年年初~~手贱~~将Typecho更新到nightly版本,我发现更新完之后页面自定义的头图全部加载失败,这严重影响了浏览体验。考虑到头图懒加载功能是Miracles主题实现的,所以我先将网站主题切换到了其他主题,但总体来讲我还是最喜欢Miracles,网站用这个主题好几年了,实在不忍心换掉。 也是年底了,终于有空打理一下这个网站,细看了一下代码才发现这个问题其实是一个非常抽象的bug导致的,也不知道为什么头图懒加载逻辑里面会有这么明显的低级错误。 # 捉虫 简单读了一下源代码,发现页面头图的实现如下([访问源代码](https://github.com/BigCoke233/miracles/blob/master/archive.php#L17)): ``` <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);` ([访问源代码](https://github.com/BigCoke233/miracles/blob/master/libs/Utils.php#L188)) ,得到: ``` /** * 缩略图 */ 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 完稿于福州 最后修改:2025 年 01 月 15 日 © 允许规范转载 赞 如果这对你有用,我乐意之至。