Gravatar头像玩独立博客的人都非常熟悉。如果在Gravatar的服务器上放置了你自己的头像,那么在任何支持Gravatar的网站留言时,只要提供你与这个头像关联的email地址,就能够显示出你的Gravatar头像来。

但是,其访问速度却非常鸡肋,即便用上cdn方案,也差强人意,很久以前有人提供过本地缓存的方案,但是实用性并不好,无法解决留言时加载慢的问题。于是就有了下面的方案。

特点:

1,甄别QQ邮箱和其他邮箱,优先显示QQ头像,毕竟QQ头像家在还是非常快的。
2,利用比较快的cdn及时显示当前评论者的头像。
3,利用popen异步实现缓存头像到本地。
4,为什么要异步?因为:如果不异步那么访客首次评论是仍要忍受龟速。

代码:

<?php
/*
 * [函数16-0] isValImg
 * 判断一个链接是否为可用图片链接
 */

function isValImg($url){
    $url = str_replace('s=160&r=G&d=identicon','?d=404',$url);//尝试将后缀替换为?d=404用于检测是否有非默认头像
    // 创建一个cURL资源
    $ch = curl_init();
    // 设置URL和相应的选项
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    curl_setopt($ch, CURLOPT_NOBODY,true);
    $content = curl_exec($ch);//抓取URL并把它传递给浏览器
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);  //curl的httpcode
    $http_type = curl_getinfo($ch,CURLINFO_CONTENT_TYPE); //获取type
    curl_close($ch);// 关闭cURL资源,并且释放系统资源

    $img_type = explode("/",$http_type); //将'Content-Type: image/jpeg'中的值用/分隔开
    if ($http_code == 200 && strtolower($img_type[0]) == 'image') {
        $url = str_replace('?d=404','s=160&r=G&d=identicon',$url);//是图像则替换回后缀后输出
    } else {
        $url = Typecho_Widget::widget('Widget_Options')->themeUrl. '/assets/img/avatar/'.rand(1,38).'.jpg';//不是图像,输出默认
    }
    return $url;
}

/*
 * [函数16-1] isValImgEasy
 * 判断一个链接是否为可用图片链接
 * 优点:简洁
 */

function isValImgEasy($url){
    $url = str_replace('s=160&r=G&d=identicon','?d=404',$url);
    $url_headers = implode(get_headers($url));
    $is_200 = preg_match("|200|", $url_headers);
    $is_img = preg_match("|image|", $url_headers);
    if ($is_200 && $is_img) {
        $url = str_replace('?d=404','s=160&r=G&d=identicon',$url);
    } else {
        $url = Typecho_Widget::widget('Widget_Options')->themeUrl. '/assets/img/avatar/'.rand(1,38).'.jpg';
    }
    return $url;
}

/*
 * [函数16] localAvatar 
 * 
 * 功能:实现gravatar头像本地缓存
 * 逻辑:本地 > QQ > Gravatar && 默认头像用本地随机(并缓存)
 */
function localAvatar($mail){
    $mail_hash = md5(strtolower(trim($mail)));
    $time = 1209600*14; //缓存过期时间(*天)
    $avatar_doc = __TYPECHO_ROOT_DIR__ . '/usr/uploads/avatar/'.$mail_hash.'.jpg'; //头像绝对路径
    $local_url = Typecho_Widget::widget('Widget_Options')->siteUrl.'usr/uploads/avatar/'.$mail_hash.'.jpg'; //头像网络地址

    preg_match_all('/((\d)*)@qq.com/', $mail, $is_qq_mail);//正则匹配QQ邮箱

    if (is_file($avatar_doc) && ((time() - filemtime($avatar_doc)) < $time) && filesize($avatar_doc)>900){
        $url = $local_url;
    }else{
        if ($is_qq_mail[1][0]){
            $url = 'https://q1.qlogo.cn/g?b=qq&nk='.$is_qq_mail[1][0].'&s=160';
        }else{
            $url = Helper::options()->gravatar . $mail_hash . 's=160&r=G&d=identicon';
        }
        
    //已经得到了头像的url,不过有些人的qq邮箱是瞎编的,有些人是没有gravatar头像的(默认头像),要把$url传参给上面的is_val_img进行判断处理。
    $url = isValImg($url);

    //执行异步缓存:因为是异步执行的所以下面可以直接返回$url,缓存的建立不会被察觉(但要避免同时大量缓存文件的建立,服务器会卡)
    $cmd = "php ".__THEME_DIR__."ic/AsynAvatar.php  '$url' '$avatar_doc'>/dev/null 2>&1 ";
    pclose(popen($cmd.'&', 'r'));
    }
    return  $url;
}

中间反反复复修改了好多个版本,到这里就已经非常成熟好用了,删掉中间过程,贴上这些代码。

完结!