用cookie记住用户信息后ajax实现实时显示Gravatar头像并实时缓存到本地
编辑:狂族晨曦 来源:经验杂笔 日期:2016-04-18 阅读: 4,759 次 9 条评论 » 百度已收录
首先说一点,本文的内容是先森研究了几天的成果,并且还导致了网站几天没有更新。
先森之前遇到了开启CDN后网站会连先森登录之后的显示样式一起缓存的问题。想想还是很危险的,要是文章页第一次是被已知用户访问,那么其他所有人访问后就是他看到的样子,那样说不定连他的邮箱地址都被暴露了。
这个问题很容易解决,通过张戈博客的cookie记住用户信息的方法,再加上让所有人访问网站都是未登录状态,这个问题就OK了。再加上一些优化用户体验的操作,也没有花先森多少时间,但是gravatar头像的事情,却一直横在了先森心中,先森的强迫症就又犯了。
关于过往研究的历程,先森已经分享过了,如果没有看的最好可以去看看,本文是建在之前的基础之上的:
预期效果
先森想实现的显示Gravatar的方式,并不是简单的用多说或者Gravatar中国的服务器的那种。先森之前就用的是将头像本地缓存,用以提高加载速度。
所以先森想实现的是:
1.用户是已知用户的时候,页面打开时自动加载缓存在本地服务器的其邮箱对应的Gravatar头像。
2.如果用户修改或填写邮箱的时候,则自动将其对应的Gravatar缓存到本地服务器,再显示出来。
如果服务器不使用本地服务器的话,上面的两条很容易实现。因为不用缓存,而Gravatar的头像链接又是固定的http://www.gravatar.com/avatar/xxxx(xxxx为邮箱的md5加密值),只要获取到邮箱,将邮箱通过哈希算法变为md5加密值,将这段MD5值填入链接中,就是用户的头像了。但难就难在先森想要将头像同时本地缓存。
不过,经过几天的努力,绕了很大的圈子,总算是搞定了。
效果实现
相信很多WordPress站长的评论源代码,是由comments.php、comments-ajax.php、comments-ajax.js三个文件构成。如果是则很会很方便,不是也没有多大差别。
1.将Gravatar头像缓存到本地服务器
这个教程早就已经烂大街了,为了本文内容先森不得不重提一遍。为什么要缓存到本地服务器?
因为Gravatar是国外服务器的,很容易被墙,且容易访问超时,导致网页加载速度变慢。缓存到本地服务器就可以有效的解决这个尴尬。当然,你也可以直接把头像缓存到七牛云储存,也就没有本文这么麻烦了。为什么先森要选择麻烦的方法?爱折腾呗~
将Gravatar头像缓存到本地服务器的方法就是,在你的functions.php中加入以下代码:
//本地缓存gravatar头像
function fa_cache_avatar($avatar, $id_or_email, $size, $default, $alt)
{
$avatar = str_replace(array("www.gravatar.com", "0.gravatar.com", "1.gravatar.com", "2.gravatar.com"), "gravatar.duoshuo.com", $avatar);
$tmp = strpos($avatar, 'http');
$url = get_avatar_url( $id_or_email, $size ) ;
$url = str_replace(array("www.gravatar.com", "0.gravatar.com", "1.gravatar.com", "2.gravatar.com"), "gravatar.duoshuo.com", $url);
$avatar2x = get_avatar_url( $id_or_email, ( $size * 2 ) ) ;
$avatar2x = str_replace(array("www.gravatar.com", "0.gravatar.com", "1.gravatar.com", "2.gravatar.com"), "gravatar.duoshuo.com", $avatar2x);
$g = substr($avatar, $tmp, strpos($avatar, "'", $tmp) - $tmp);
$tmp = strpos($g, 'avatar/') + 7;
$f = substr($g, $tmp, strpos($g, "?", $tmp) - $tmp);
$w = home_url();
$e = ABSPATH .'avatar/'. $size . '*'. $f .'.jpg';
$e2x = ABSPATH .'avatar/'. ( $size * 2 ) . '*'. $f .'.jpg';
$t = 1209600; //缓存更新时间
if ( (!is_file($e) || (time() - filemtime($e)) > $t) && (!is_file($e2x) || (time() - filemtime($e2x)) > $t ) ) {
copy(htmlspecialchars_decode($g), $e);
copy(htmlspecialchars_decode($avatar2x), $e2x);
} else { $avatar = $w.'/avatar/'. $size . '*'.$f.'.jpg';
$avatar2x = $w.'/avatar/'. ( $size * 2) . '*'.$f.'.jpg';
if (filesize($e) < 1000) copy($w.'/avatar/default.jpg', $e);
if (filesize($e2x) < 1000) copy($w.'/avatar/default.jpg', $e2x);
$avatar = "<img alt='{$alt}' src='{$avatar}' srcset='{$avatar2x}' class='avatar avatar-{$size} photo' id='real-time-gravatar' height='{$size}' width='{$size}' />";
}
return $avatar;
}
add_filter('get_avatar', 'fa_cache_avatar',1,5);
如果你的网站已经实现则忽略,没有的话就先添加备用。
2.新建gravatar.php
上面的代码是修改了WordPress的get_acatar函数。而我们想要实时的缓存Gravatar邮箱,则需要将邮箱的MD5值传递给get_acatar函数。上面的代码最后会有输出,而我们并不需要它的输出,只要它将头像缓存即可。
所以我们需要新建一个gravatar.php文件,将ajax传递过来的邮箱MD5值接收,并让get_acatar函数将对应的头像缓存。gravatar.php的代码如下:
<?php //缓存头像
if ( 'POST' != $_SERVER['REQUEST_METHOD'] ) {
header('Allow: POST');
header('HTTP/1.1 405 Method Not Allowed');
header('Content-Type: text/plain');
echo "请不要直接访问该页面";
exit;
}
require( dirname(__FILE__) . '/../../../wp-load.php' );//使用 WordPress自带函数进行数据提交
$email = $_POST['email'];//获取邮箱md5值
get_avatar( $email, $size = '48' ); //将头像缓存
?>
其中,下面这段代码很重要:
require( dirname(__FILE__) . '/../../../wp-load.php' );
如果不加上的话会导致数据存入失败,POST访问也会返回错误500。这也是挡住了先森研究很久的一个问题。之前代码中之后最后的两句,获取和缓存,结果一直显示不成功。

访问错误500
后来在百度找原因一直没找到,却意外看到了一篇写用ajax提交评论的优点的文章中有一句“使用wordpress自带的admin-ajax.php进行数据提交”,先森感觉脑子一炸,将comments-ajax.php中一句不起眼的代码(即上面那句)复制过来。一尝试。OK返回成功。
3.ajax动态刷新
ajax是一种在不刷新整个页面,与服务器实现数据交换的网页开发技术。
这个技术被称为称为“艺术”,但先森是不懂艺术的,所以这几天花的最多的时间就是在这里了。先森还专门跑去w3school学了一下ajax方面的教程,结果也没懂个啥,仅仅是对概念更清楚了些。
这个技术在本文的担当是,动态的将邮箱md5值提交给服务器,服务器将头像缓存。
我们的ajax代码,可以加入到comments-ajax.js中,也可以自己新建一个js文件。
首先,我们需要将Gravater邮箱地址变换为MD5值,需要用到一串复杂的算法,将以下代码加入js中:
因为比较长,所以提供下载,不直接将代码贴出来了。
接下来将下面的代码加入comments-ajax.js或你准备好的js文件中:
/*
*张戈博客原创
*成航先森修改
* //www.capjsj.cn/ycookiejzyhxxhsxssxsgravatartxbsshcdbd.html
*/
var Umail = decodeURIComponent(GetCookie('email'));//通过cookie获取用户邮箱,并解码
var Uname = decodeURIComponent(GetCookie('author'));
var Umail_md5 = "";
if (Umail != "null" && Umail != "" && Umail != null) {//如果邮箱有内容,则赋值
var Umail_md5 = hex_md5(Umail);
}
if (Umail_md5 != "" && Umail_md5 != null && Umail_md5 != "null") {//如果邮箱哈希后存在内容
jQuery(document).ready(function($) {
jQuery('#comment-author-info').hide();//隐藏信息填写框
});
/*下面的real-avatar是包裹着头像的div*/
document.getElementById('real-avatar').innerHTML = "<img src='//cos.capjsj.cn/avatar/96*" + Umail_md5 + ".jpg' width='48' height='48' alt='avatar' class='avatar avatar-48 photo' id='real-time-gravatar'>";
var changeMsg = '修改信息';
var closeMsg = '关闭';
function toggleCommentAuthorInfo() {
jQuery('#comment-author-info').slideToggle('slow', function() {
if (jQuery('#comment-author-info').css('display') == 'none') {//如果信息填写框被隐藏
jQuery('.switch-author').text(changeMsg);//改变标签内容为“修改信息”
} else {
jQuery('.switch-author').text(closeMsg);//改变标签内容为"关闭"
}
});
}
}
var gar_img = document.getElementById("real-time-gravatar");/*头像img标签*/
var U_email = document.getElementById("email");
var textarea = document.getElementById("comment");/*评论输入框*/
var KaK = navigator.userAgent.toLowerCase();/*获取浏览器信息*/
var chrome = KaK.indexOf('webkit') != -1;
function changeGravatar() {
email_value = U_email.value;
email_md5 = hex_md5(email_value);
php_url=js_url.replace('comments-ajax.js','gravatar.php');//替换js链接中的文件名
$.ajax({
type:'POST',
data:{
"email": email_value,
},
//ajax对象文件:gavater.php
url:php_url,
cache: false,
});
new_ga = "//cos.capjsj.cn/avatar/48*" + email_md5 +".jpg";
newGravatar(new_ga);/*启动下面的脚本*/
};
function newGravatar(new_ga) {
gar_img.setAttribute('src', new_ga);/*将图片链接换成新的链接*/
};
if (chrome) {
U_email.onblur = changeGravatar;/*鼠标离开输入框时执行 JavaScript 代码*/
} else {
U_email.onchange = changeGravatar;/*在内容改变的时候执行*/
};
textarea.onmouseover = changeGravatar;/*在鼠标指针移动到元素上时触发行 JavaScript 代码
代码是从张戈博客那里扒来的,因为张戈实现的是Nginx自动将Gravatar头像本地缓存,所以他不用担心先森的这种缓存问题。所以先森将张哥的代码稍作修改,增加了ajax代码,既可以满足先森的要求了。
上面的代码中,ajax代码是下面这串:
$.ajax({
type:'POST',
data:{
"email": email_value,
},
//ajax对象文件:gavater.php
url:php_url,
cache: false,
});
如果你需要调试,可以将代码缓存下面这样,根据弹窗信息确认是否成功:
$.ajax({
type:'POST',
data:{
"email": email_value,
},
//ajax对象文件:gavater.php
url:php_url,
cache: false,
error: function(){
alert('发生意外错误!'); //弹窗显示
return false;
},
success:function(){
alert('缓存成功');
}
});
应网友要求,先贴出comments.php中form标签的内容,以供参考。
<form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" id="commentform">
<div class="comt-title" id="comt-title">
<div class="comt-avatar pull-left" id="real-avatar">
<?php //输入评论上的头像
global $current_user;
get_currentuserinfo();
if ( is_user_logged_in() ) //$current_user->user_email获取邮箱
echo get_avatar( $current_user->user_email, $size = '48' ,'');//如果是管理员
elseif( !is_user_logged_in() && get_option('require_name_email') && $comment_author_email=='' )
echo get_avatar( $current_user->user_email, $size = '48','');//没有登录,但是是已知用户
elseif( !is_user_logged_in() && get_option('require_name_email') && $comment_author_email!=='' )
echo get_avatar( $comment->comment_author_email, $size = '48','');//, $touxiang
else
echo get_avatar( $comment->comment_author_email, $size = '48' ,'');//, $touxiang
?>
</div>
<div class="comt-author" id="switch-author">
<?php
if ( is_user_logged_in() ) {//判断登录
printf('<b id="nickname">'.$user_identity.'</b><span>发表我的评论</span>');
}else{
if( get_option('require_name_email') && !empty($comment_author_email) ){//如果没登录,但是是已知用户
printf('<b id="nickname">'.$comment_author.'</b><span>欢迎回来</span> <b>【<a class="switch-author" href="javascript:toggleCommentAuthorInfo();" data-type="switch-author" style="font-size:15px;">修改信息</a>】</b>');
}else{//如果是未知用户
printf('<b id="nickname"></b><span id="huilai">欢迎发表评论</span>');
}
}
?>
<?php //如果关闭了WP Super Cache中的让已知用户匿名,则要删除下面的<b>标签?>
<b id="switch-author" style="display:none">【<a class="switch-author" href="javascript:;" data-type="switch-author" style="font-size:15px;">修改信息</a>】</b>
</div>
<a id="cancel-comment-reply-link" class="pull-right" href="javascript:;">取消评论</a>
</div>
<div class="comt">
<div class="comt-box">
<textarea placeholder="说点什么吧,您的回复是对先森最大的支持!" class="input-block-level comt-area" name="comment" id="comment" cols="50%" rows="3" tabindex="1" onkeydown="if(event.ctrlKey&&event.keyCode==13){document.getElementById('submit').click();return false};"></textarea>
<div class="comt-ctrl">
<button class="btn btn-primary pull-right" type="submit" name="submit" id="submit" tabindex="5"><i class="fa fa-check-square-o"></i> 提交评论</button>
<div class="comt-tips pull-right"><?php comment_id_fields(); do_action('comment_form', $post->ID); ?></div>
<span class="muted comt-mailme"><?php deel_add_checkbox() ?></span>
<span data-type="comment-insert-smilie" class="muted comt-smilie"><i class="fa fa-smile-o"></i> 表情</span>
<div id="comment-smilies" class="hide" style="display:"><?php include(TEMPLATEPATH . '/smiley.php'); ?></div>
</div>
</div>
<?php if ( !is_user_logged_in() ) { ?>
<?php if( get_option('require_name_email') ){ ?>
<div class="comt-comterinfo" id="comment-author-info"<?php if ( !empty($comment_author) ) echo 'style="display:none"';else echo 'style="display:block"'; ?>>
<h4>Hi,您需要填写昵称和邮箱!</h4>
<ul>
<li class="form-inline"><label class="hide" for="author">昵称</label><input class="ipt" type="text" name="author" id="author" value="<?php echo esc_attr($comment_author); ?>" tabindex="2" placeholder="昵称"><span class="help-inline">昵称 (必填)</span></li>
<li class="form-inline"><label class="hide" for="email">邮箱</label><input class="ipt" type="text" name="email" id="email" value="<?php echo esc_attr($comment_author_email); ?>" tabindex="3" placeholder="邮箱"><span class="help-inline">邮箱 (必填)</span></li>
<li class="form-inline"><label class="hide" for="url">网址</label><input class="ipt" type="text" name="url" id="url" value="<?php echo esc_attr($comment_author_url); ?>" tabindex="4" placeholder="网址"><span class="help-inline">网址</span></li>
</ul>
</div>
<?php } ?>
<?php } ?>
</div>
</form>
总结
文中的代码涉及到了很多标签的ID,请参考本站的设置情况进行对应修改。
因为代码逐行执行的速度比服务器缓存的速度快,所以当刚修改邮箱的时候,可能图片会显示404,但再次触发更换头像链接函数的时候,相关的头像已经被缓存成功就会显示出来了。先森目前没有想到解决的办法,所以最后有一个经过评论输入框的时候也会触发函数。这样增加触发,头像就能很好的显示出来了,目前先这样,等以后想到解决办法再说。
这样设置后的好处还有一点,就是默认头像始终都是你设置本地缓存中的那个默认头像。
转载请注明出处来自https://www.capjsj.cn/ycookiejzyhxxhsxssxsgravatartxbsshcdbd.html

川公网安备 51011202000104号
非常不错!!
@破浪无忧Blog: 嘿嘿,谢谢支持~
真的不错!!!
我所使用的“欲思1.0主题”,虽然原本也自带了头像缓存到本地功能,但发现代码乱七八糟一大堆、以及速度依然慢的很。很想换个好用的缓存到本地的方法,但限于自个技术小白一枚,一直没能实现,实在是纠结、郁闷啊!
hi,大哥,您好,这几天看到你这篇教程也想学着改一下。依葫芦画瓢设置了一些,但是老是没有效果。可能有些ID没有设置好。不知道能否贴一份comment的form里html代码结构呢,这样可能更理解具体是如何操作的。多谢啊。
@黑狼: 已经贴出来了,如果缓存还没有刷新,访问网页的时候在链接后面加?1234就可以看到最新更新的内容了。
辛苦博主了
学习了,顺利巴拉使用上了。