用cookie記住用戶信息后ajax實現實時顯示Gravatar頭像并實時緩存到本地
編輯:狂族晨曦 來源:經驗雜筆 日期:2016-04-18 閱讀: 4,739 次 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.cnidcc.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,但再次觸發更換頭像鏈接函數的時候,相關的頭像已經被緩存成功就會顯示出來了。先森目前沒有想到解決的辦法,所以最后有一個經過評論輸入框的時候也會觸發函數。這樣增加觸發,頭像就能很好的顯示出來了,目前先這樣,等以后想到解決辦法再說。
這樣設置后的好處還有一點,就是默認頭像始終都是你設置本地緩存中的那個默認頭像。
轉載請注明出處來自http://www.cnidcc.cn/ycookiejzyhxxhsxssxsgravatartxbsshcdbd.html

川公網安備 51011202000104號
非常不錯!!
@破浪無憂Blog: 嘿嘿,謝謝支持~
真的不錯!!!
我所使用的“欲思1.0主題”,雖然原本也自帶了頭像緩存到本地功能,但發現代碼亂七八糟一大堆、以及速度依然慢的很。很想換個好用的緩存到本地的方法,但限于自個技術小白一枚,一直沒能實現,實在是糾結、郁悶啊!
hi,大哥,您好,這幾天看到你這篇教程也想學著改一下。依葫蘆畫瓢設置了一些,但是老是沒有效果。可能有些ID沒有設置好。不知道能否貼一份comment的form里html代碼結構呢,這樣可能更理解具體是如何操作的。多謝啊。
@黑狼: 已經貼出來了,如果緩存還沒有刷新,訪問網頁的時候在鏈接后面加?1234就可以看到最新更新的內容了。
辛苦博主了
學習了,順利巴拉使用上了。