网站建设

Nginx-helper纯代码版,文章评论发布自动清理Fastcgi缓存

Jager · 10月15日 · 2016年 · · · 1110次已读

Nginx-Helper 这款插件主要用于 Nginx 的 Fastcgi 缓存或 Redis 缓存清理,用起来确实不错,堪称绝配!感兴趣可以翻看博客之前的分享:

Nginx 开启 fastcgi_cache 缓存加速,支持 html 伪静态页面

解决 Nginx Helper 插件一键清理缓存功能导致网站打不开问题

Nginx-helper纯代码版,文章评论发布自动清理Fastcgi缓存

最近,发现文章发布缓存清理不生效了,开启日志看了下,发现插件清理文章缓存的时候在文章地址后多加了一个斜杠,比如 https://zhang.ge/5111.html/ ,那这样肯定不行了,因为 fastcgi 缓存是和 url 密切相关的,多一个斜杠,自然就南辕北辙了。

想想可能是和我博客加了 “分类地址后面自动加斜杠” 的机制导致的吧!懒得研究如何解决,想起之前给有偿用户写过一个纯代码版本,解决 PHP 版本过低无法兼容 Nginx-Helper 插件的问题。这次正好拿来完善一下,而且还能消灭一个插件。

经过代码编写、测试验证,一个简单的 Nginx-Helper 纯代码原创版本就新鲜出炉了。

Ps:2016 年 12 月 11 日更新:修复了文章更新发布无法清理首页缓存问题,请重新拷贝如下代码。

/**
* WordPress Nginx FastCGI 缓存清理代码(Nginx-Helper 纯代码版) By 张戈博客
* 文章地址:https://zhang.ge/5112.html
* 转载请保留原文出处,谢谢合作!
*/

//初始化配置
$logSwitch  = 0;                  //配置日志开关,1 为开启,0 为关闭
$logFile    = '/tmp/purge.log';   //配置日志路径
$cache_path = '/tmp/wpcache';     //配置缓存路径

//清理所有缓存(仅管理员) 范例:http://www.domain.com/?purge=all
if ($_GET['purge'] == 'all' && is_user_logged_in()) {
    if( current_user_can( 'manage_options' )) 
    {
        delDirAndFile($cache_path, 0);
    }
}

//缓存清理选项
add_action('publish_post', 'Clean_By_Publish', 99);                   //文章发布、更新清理缓存
add_action('comment_post', 'Clean_By_Comments',99);                   //评论提交清理缓存(不需要可注释)
add_action('comment_unapproved_to_approved', 'Clean_By_Approved',99); //评论审核清理缓存(不需要可注释)

//文章发布清理缓存函数
function Clean_By_Publish($post_ID){
    $url = get_permalink($post_ID);

    cleanFastCGIcache($url);        //清理当前文章缓存
    cleanFastCGIcache(home_url().'/');  //清理首页缓存(不需要可注释此行)
        
    //清理文章所在分类缓存(不需要可注释以下 5 行)
    if ( $categories = wp_get_post_categories( $post_ID ) ) {
        foreach ( $categories as $category_id ) {
            cleanFastCGIcache(get_category_link( $category_id ));
        }
    }

    //清理文章相关标签页面缓存(不需要可注释以下 5 行)
    if ( $tags = get_the_tags( $post_ID ) ) {
        foreach ( $tags as $tag ) {
	    cleanFastCGIcache( get_tag_link( $tag->term_id ));
        }
    }
}

// 评论发布清理文章缓存
function Clean_By_Comments($comment_id){
    $comment  = get_comment($comment_id);
    $url      = get_permalink($comment->comment_post_ID);
    cleanFastCGIcache($url);
}

// 评论审核通过清理文章缓存
function Clean_By_Approved($comment)
{
    $url      = get_permalink($comment->comment_post_ID); 
    cleanFastCGIcache($url);
}

//日志记录
function purgeLog($msg)
{
    global $logFile, $logSwitch;
    if ($logSwitch == 0 ) return;
    date_default_timezone_set('Asia/Shanghai');
    file_put_contents($logFile, date('[Y-m-d H:i:s]: ') . $msg . PHP_EOL, FILE_APPEND);
    return $msg;
}

// 缓存文件删除函数
function cleanFastCGIcache($url) {
    $url_data  = parse_url($url);
    global $cache_path;
    if(!$url_data) {
        return purgeLog($url.' is a bad url!' );
    }

    $hash        = md5($url_data['scheme'].'GET'.$url_data['host'].$url_data['path']);
    $cache_path  = (substr($cache_path, -1) == '/') ? $cache_path : $cache_path.'/';
    $cached_file = $cache_path . substr($hash, -1) . '/' . substr($hash,-3,2) . '/' . $hash;
    
    if (!file_exists($cached_file)) {
        return purgeLog($url . " is currently not cached (checked for file: $cached_file)" );
    } else if (unlink($cached_file)) {
        return purgeLog( $url." *** CLeanUP *** (cache file: $cached_file)");
    } else {
        return purgeLog("- - An error occurred deleting the cache file. Check the server logs for a PHP warning." );
    }
}

/**
 * 删除目录及目录下所有文件或删除指定文件
 * 代码出自 ThinkPHP:http://www.thinkphp.cn/code/1470.html
 * @param str $path   待删除目录路径
 * @param int $delDir 是否删除目录,1 或 true 删除目录,0 或 false 则只删除文件保留目录(包含子目录)
 * @return bool 返回删除状态
 */
function delDirAndFile($path, $delDir = FALSE) {
    $handle = opendir($path);
    if ($handle) {
        while (false !== ( $item = readdir($handle) )) {
            if ($item != "." && $item != "..")
                is_dir("$path/$item") ? delDirAndFile("$path/$item", $delDir) : unlink("$path/$item");
        }
        closedir($handle);
        if ($delDir)
            return rmdir($path);
    }else {
        if (file_exists($path)) {
            return unlink($path);
        } else {
            return FALSE;
        }
    }
}

根据实际情况,修改代码中的缓存路径配置:

$cache_path = '/tmp/wpcache';     //配置缓存路径

Ps:这个路径其实就是 Nginx Fastcgi 缓存配置中的 fastcgi_cache_path 参数,详见前文分享

然后,将整段粘贴到 WordPress 主题函数模板文件 functions.php 当中即可。其他功能细项,在代码中都有详细的注释了,自行参考修改。

现在发布/更新文章、评论提交/审核,就会自动删除当前文章缓存了,发布/更新文章还会清理首页、分类以及相关标签页缓存(不需要可根据代码中的注释进行屏蔽)。

另外,如果想清理全部缓存,可在管理员登陆状态下访问首页+?purge=all 参数,比如:https://zhang.ge/?purge=all ,其他用户或访客访问这个地址则没有任何作用,如果还不放心也可以自行更改代码中的参数判断字符串。

?purge=all

经过测试,这种带参数的路径同样会被 Nginx 缓存,也就说?purge=all 只能用一次,第二次刷新就没效果了,因为被 Nginx 缓存了,要解决也很简单,在 fastcgi 缓存配置中排除这个路径即可:

#后台等特定页面不缓存(其他需求请自行添加即可)
if ($request_uri ~* "purge=all|/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
     set $skip_cache 1;
}

当然,如果是按照 Nginx-Helper 插件,那还能添加更多功能,比如清理订阅页面缓存什么的。但是我觉得并不需要,有以上基础功能已经足够了。有模仿能力、动手能力的站长朋友,完全可以在以上代码的基础上添加自己想要的功能,相信也是小菜一碟。

65 条回应
  1. 小鱼 2016-10-16 · 0:46

    请教一下,我使用了nginx fastcgi_cache,然而却出现了问题。缓存文件夹里会生成类似0 1 3 4 e f之类的文件夹和文件,点击后台 purge cache 缓存文件也会清空。并且网页源文件底部也有nginx helper缓存字样。但是后台查看nginx helper的log文件,里面是空的,而且浏览器访问网站,也没有x-cache:HIT From XX 和nginx-cache:HIT字样,却有Cache-Control:no-cache, must-revalidate, max-age=0不知道问题出在哪了?谢谢戈哥指点!

    • avatar
      Jager 2016-10-16 · 8:48
      #忽略一切nocache申明,避免不缓存伪静态等
      fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
      • 小鱼 2016-10-16 · 9:02

        已经加上这一条了,但是没有作用。以前也配置过一次,都是参考你的文章,上次没有问题,这次却出现这个问题。环境都是一样的,找了半天也没发现问题出在哪。。。

        • avatar
          Jager 2016-10-16 · 9:23

          你应该是设置了登录用户不缓存。可以尝试开启浏览器隐身模式去看HIT

          • 小鱼 2016-10-16 · 9:33

            这个也没有,谢谢戈哥解答。我再重新配置一次环境试试。要是还有同样的问题,那就得仔细看看了。。。

            • 我爱动感单车网 2016-10-21 · 13:08

              羡慕你们都使用上了服务器,咱还停留在廉价虚拟主机的阶段啊!

  2. 菊部 2016-10-16 · 12:52

    感谢分享

  3. 小萝博客 2016-10-16 · 21:01

    签到成功!签到时间:下午8:59:39,每日签到,生活更精彩哦~

  4. 小C博客 2016-10-17 · 9:53

    有时间弄上,又可以删一个插件了!

    • 今日秀 2016-11-3 · 9:53

      是咯 好东西

  5. 鸡排加盟网 2016-10-18 · 15:41

    不错666

  6. 诺言工作室 2016-10-18 · 22:18

    和博主学到不少

  7. 任务易 2016-10-19 · 14:44

    已经收藏了,目前还木有碰到这种情况,我相信以后或许会用到,谢谢博主分享

  8. 爱眼博客 2016-10-19 · 17:32

    好文章,欢迎回访

  9. 卢松松商城 2016-10-20 · 15:35

    好复杂好难懂。。

    • 路过的 2016-10-20 · 18:41

      怎么卢松松到处去留言评论,请了专门的人来做的吗

      • 我爱动感单车网 2016-10-21 · 13:07

        是啊,今年下半年来很多博客都能够看见卢松松的身影,怎么又重拾起了评论推广这个方式呢?

  10. 柒号淘金 2016-10-20 · 19:21

    学习中。。

  11. 苏城一只猫 2016-10-20 · 19:40

    测试了好几遍,只要是用七牛存储的,上传资源一直报E502报错....不知道咋回事。关闭这个换成就没事了。

  12. 灵异网站 2016-10-20 · 20:05

    迷迷糊糊的看着

  13. 励志语录 2016-10-21 · 8:33

    赞一个

  14. 蜜思私护 2016-10-21 · 13:00

    看起来好厉害的样子

  15. 蜜思私护 2016-10-21 · 13:01

    看起来好复杂啊!~

  16. 我爱动感单车网 2016-10-21 · 13:05

    咱用的是虚拟主机,虚拟主机又该怎么弄呢?

  17. 任务易 2016-10-21 · 13:27

    看的头晕眼花,可以直接复制粘贴的么

  18. 网赚博客 2016-10-22 · 9:18

    这个确实是很实用

  19. 路过 2016-10-23 · 17:19

    这篇文章中的设置已经失效:https://zhang.ge/5089.html

  20. 胡歌网摘 2016-10-24 · 11:32

    zg,现在用的是哪里cdn? 怎么也支持https?

    • avatar
      Jager 2016-11-11 · 10:02

      腾讯云CDN

  21. 胡歌网摘 2016-10-24 · 11:33

    你还用沃通证书啊,不换一下?

    • avatar
      Jager 2016-11-11 · 10:02

      3年的证书,省事不换了。前面申请的沃通是没有问题的。

  22. 张力博客 2016-11-10 · 21:49

    o(∩_∩)o 哈哈,不错,已经用上了,又删除了一个插件!

  23. nom 2016-11-14 · 3:17

    学习了1

  24. Biebb 2016-11-25 · 2:17

    终于又有东西能折腾了

  25. Qa 2016-12-5 · 0:31

    想请教下,nginx 通过cookie判断用户是否已登录经常失误是什么问题?

     if ($http_cookie ~* "wordpress_logged_in") 

    通过判断cookie,分开缓存登录用户和游客两份缓存。经常出现登录用户看到的是游客的缓存的情况。

    • avatar
      Jager 2016-12-5 · 9:36

      判断失误,可能是cookies异常吧,没拿到这个cookies。
      看了你的分享,分开游客和登陆用户,有点意思。不过没明白都是静态缓存,分开缓存的目的难道是因为游客和登陆用户界面上有些不同?
      不过,你这个思路很适合用于非自适应的网站,PC站和移动端的分开缓存。

      • Qa 2016-12-5 · 19:42

        登录用户和游客看到的页面是不一样的。如果不缓存起来,登录用户太多mysql查询爆炸。
        PS:今天这个打字效果真有意思。

        • avatar
          Jager 2016-12-8 · 17:10

          我觉得个人博客没必要开启注册,放弃一切登录态才是王道。
          如果是业务网站,毕竟有收入,配置也不是个人网站可以比的。
          对于登陆用户的mysql查询,可以使用memcached或redis来动态缓存,效果也是不错的。

      • Qa 2016-12-5 · 19:48

        我的博客就是PC和移动端是分开缓存的。

      • Qa 2016-12-6 · 23:02

        想通过前段判断用户是否登录和页面缓存是否错误,错误就发送请求刷新此页缓存。
        不知道该如何判断是否已登录,wordpress_logged_in这个cookie JS没法取。
        不知道Jager有什么建议?

        • avatar
          Jager 2016-12-8 · 17:11

          每个页面异步发起一个动态请求,应该可以查到是否具备登录态。

  26. 采觅随记 2016-12-14 · 21:30

    咦老张,突然发现你从360免费CDN转性能魔方了。 :grin:

  27. 首页不缓存 2017-1-1 · 3:18

    首页不缓存好像没效.
    输入 abc.com/index.php 它会自动跑为 abc.com, 后面的自动消失.
    所以被缓存了, 除非已经登录状态.
    怎么设置才行呢?

  28. 刘曌博客 2017-2-12 · 15:37

    博主网站特效很给力签到成功!签到时间:下午3:33:13,每日签到,生活更精彩哦~

  29. 大海 2017-2-13 · 12:40

    博主,请问你,生成的缓存目录里的文件名是怎么命名的?我的目录里感觉乱七八糟的有数字 有英文,
    还有个很严重的问题,使用了这个缓存模块,我的博客有时能打开有时打不开,有的浏览器还打不开,比如电脑能访问,手机就是打不开,无法加载,回复评论 也没感觉到清理缓存了,反而回复后网站直接挂了。。折腾坏了 :!: ,感觉折腾不来,还耽误事,请问博主,如果不使用这个nginx缓存模块,对wp来说使用哪个插件或者手动缓存方案比较好,谢谢

    • avatar
      Jager 2017-2-13 · 18:59

      你还是老是用插件把,比如 wp-super-cache

  30. 小C博客 2017-2-15 · 10:03

    张哥,使用后网站无法打开了。

    • avatar
      Jager 2017-2-15 · 10:10

      原来的插件没有停掉么?报错信息是什么?

  31. 小C博客 2017-3-1 · 15:28

    插件已经停用,访问https://www.domain.com/?purge=all 后无法打开,并且后台也无法打开,能否指导下,谢谢!

    • avatar
      Jager 2017-9-1 · 22:03

      。。我个人基本不用这个删除all的功能, 直接上服务器删除比较靠谱

  32. 刘某某博客 2017-8-31 · 17:11

    /tmp/wpcache的属组给了www,然后再重启了php一下,问题解决。但是把$delDir设置为1,还是不能删除目录,只能删除文件。

    • avatar
      Jager 2017-9-1 · 22:02

      删除目录没啥意义,清理里面所有文件即可。这里只是为了保留函数完整性。

  33. banxia 2017-12-17 · 9:45

    请问我安装了 nginx helper ,然后上传主题,启用就打不开网站了是怎么回事?
    页面显示
    ?????????????????????????????????

    • avatar
      Jager 2018-1-30 · 13:26

      本文说的是纯代码版。。不是插件,插件报错可能是函数冲突

      • banxia 2018-1-30 · 13:40

        不会折腾。还是算了吧?

  34. Tommy Li 2018-3-12 · 16:52

    发现有一个问题
    如果文章所属的分类是二级分类目录,触发清理规则的时候只会清理二级分类目录,不会清除上级分类。

  35. 高老四 2019-5-24 · 18:01

    Jager您好,希望您看到我这条评论.我遇到的问题是这样,nginx_fastcgi_cache已经按照您的教程配置成功,亲自测试了可以实现hit、bypass以及miss,但是对于清除缓存无论如何我都不能实现。我用了四款wp中的插件均无法实现。实用您本文的这段代码也无法实现。效果就是缓存目录没有任何变化,被这个问题折磨三天了,现在实在找不到相关的原因,请求指教一下。环境是lnmp,nginx1.16和php7.3

    • avatar
      Jager 2019-5-25 · 17:08

      把代码中的 $logSwitch = 1 配置为1,打开日志,然后触发缓存更新,最后看下 /tmp/purge.log 内容是啥?

      • 高老四 2019-5-26 · 16:07

        谢谢Jager的教程。我的原因找到了,是因为我安装的 php 对 /tmp 目录进行了硬链接保护,所以导致不论插件还是你的代码在 functions.php 的代码都会让缓存检查失效,因为 file_exist 函数会直接返回 false,我换个缓存目录就好了,插件也是好用的,再次感谢。希望其他人看到也对他们有帮助。

  36. Aron 2019-7-27 · 23:36

    使用后 直接报错500

  37. 淡缕凝风 2019-8-22 · 20:01

    能不能预先缓存呢?

  38. google voice 2020-2-12 · 22:22

    大佬抽空开发个从purge地址清楚的插件,供PROXY CAHCE用啊。

    让反代CDN加速清空代理更为方便。

  39. 萌新 2020-7-6 · 11:09

    如果文章所属的分类是二级分类目录,触发清理规则的时候只会清理二级分类目录,不会清除上级分类。
    这种有办法可以清理吗

    • avatar
      Jager 2020-8-2 · 16:57

      改代码应该可以实现,建议读一下代码逻辑。

  40. 王二 2020-12-21 · 14:31

    感觉如果使用了mencached + 动静分离 + cdn ,nginx 缓存用处不大。

  41. gnepre 2022-1-10 · 1:33

    代码版也用了,还是没清除掉成功,奇了怪了

  42. 无名 2022-2-10 · 23:05

    ?purge=all
    执行这个清理后 返回到不带?purge=all的页面 发现并没有清理原来的缓存
    查看日志后 执行?purge=all后提示的是
    currently not cached (checked for file:*****