wp-postviews 插件更新配置失败的解决方法

也许是老外太淡定,WordPress 从出世之初就没提供统计阅读量的功能,只给了个评论数。但这个虽然简单的统计数字对喜欢被关注的人却是不可或缺的。所以,wp-postviews 插件几乎成为 WordPress 的必备插件。

我前前后后也弄了 2、3 个 WordPress 博客了,但这次却在使用 wp-postviews 插件时遇到了问题。

首先说一下问题症状

搜索安装插件还算顺利的。中间有个小波折。在搜索 wp-postviews 插件的时候看到了一个叫 wp-postviews plus 的插件,原以为是 wp-postviews 的升级版,安装了之后却发现不是那回事。于是卸载了后又重新安装的 wp-postviews

安装好插件要先设置一下不是,然后问题出现了。点击 Save Changes 竟然跳转到了登录页面。输入密码登录,然后更改设置,再点 Save Changes 又跳到了登录界面。如是者三。没脾气了。

于是又想到了刚才误用了的 wp-postviews plus ,它应该没问题了吧?于是又把它找到,安装。晕,竟然和 wp-postviews 冲突!卸载 wp-postviews ,安装 wp-postviews plus 。配置项很少,没啥要设置的。随便改了一个,保存,竟然成功了。于是按着惯例,在对应于post下脚位置的代码处加入这一句 <?php if(function_exists('the_views')) {the_views();} ?> 。保存,刷新,等待着令人向往的数字的出现。什么?没有出现?再刷新。还是没有。缓存的问题?清缓存。再刷新。还是没有。

中间省略波折无数,终于找到了问题所在,那就是 function_exists('the_views')) 返回为假。问题是找到了,但已经没心情去追踪原因了。有那时间还不如看看wp-postviews到底是啥状况。好,wp-postviews plus 的问题就先到这,有兴趣的同学继续研究吧。

发现问题所在

于是乎,又换回了 wp-postviews ,开始在网上搜这个问题的解决办法。搜了大半天好像没人遇到我这种情况。最终一篇博客提醒了我。是子目录的问题!

先说一下我这个博客所在空间的组织结构。我现在用的是bluehost的空间,刚买的时候很快的,这半年速度越来月不尽人意了。但有个好处就是什么都不限制,不限容量、不限带宽、不限流量、最多100个数据库(好像)、ssh、ftp、不限域名挂靠……反正价格便宜量又足!有图为证:(点击下图购买空间有优惠哦)

Bluehost

于是我在这个空间里同时弄了好几个网站。一个非常简单的静态页面网站、一个论坛、还有这个博客。所以为了更好地组织文件,我为每个网站建了一个子目录,然后用 .htaccess 把各个域名重定向到相应的子目录里去。比如,/ 是我的空间的根目录,我现在把我的网站放到了目录 /mysite 下,然后在 /.htaccess 里用 Rewrite 规则把我的域名 http://www.cbug.org 重新定向到 /mysite 下,这样我就可以通过域名直接访问我的网站了。

然后我又在 /mysite 下建了个 blog 目录来安装我的博客。并在 /mysite 下的 index.php文件里使用重定向,转到了 blog 目录下。这样用户在浏览我的网站时,就直接被带到了我的博客。同样的道理,可以直接通过域名 http://www.xiaomoer.org 来访问我的论坛。这样就可以实现多个网站公用一个空间了。具体细节可以找我讨论。不过这不是本文所关注的。

就是这子目录,导致了 wp-postviews 保存配置失败。来看一下 wp-postviews 保存配置的源码( postviews-options.php:136,259 ):

<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>?page=<?php echo plugin_basename(__FILE__); ?>">

请看 $_SERVER['PHP_SELF'] 。其中,$_SERVER 是 PHP 的全局预定义变量,是一个包含诸如头部(headers)、路径(paths)和脚本位置(script locations)的数组。而其元素 PHP_SELF 则是当前正在执行脚本的文件名,与 document root 相关。举例来说,在URL地址为 http://example.com/test.php/foo.bar 的脚本中使用 $_SERVER['PHP_SELF'] (一般)将会得到 /test.php/foo.bar 这个结果。

下划线部分是从网上复制来的一段话,其中红色的“一般”两字是我加上的。加这两个字的原因就是今天的问题是属于“不一般”的。一般情况下,在 wp-postviews 中的 $_SERVER['PHP_SELF'] 返回的值应该是 /blog/wp-admin/options-general.php 。因为是相对于网站根目录的,所以加上域名应该就是 http://www.cbug.org/blog/wp-admin/options-general.php 。这样应该是正确的。

但现在不是“一般”情况。实际上 $_SERVER['PHP_SELF'] 返回的值却是 /mysite/blog/wp-admin/options-general.php 。加上域名就成了 http://www.cbug.org/mysite/blog/wp-admin/options-general.php 。前面说了,我的博客是在空间的子目录 /mysite 下的。但我已通过 .htaccess 将域名重定向到了 mysite 目录下,所以 http://www.cbug.org/mysite 这个 URL 是不存在的。这就是问题所在了。至于为什么碰到不存在的 URL 请求,WordPress 就跳转到登录界面,我就不知道了。

得到这样的值也不能说是 PHP 的错,也不是 $_SERVER['PHP_SELF'] 的错。但对于我现在这种情况肯定是有人错了的。那错的是谁呢?是 GaMerZ( wp-postviews 的作者)的错。因为 $_SERVER['PHP_SELF'] 这种用法是一种众所周知的风险漏洞,很容易被人利用进行跨站脚本攻击。这里有两篇从网上搜到的讲这个问题的文章,一中一英,英文的还讲了替换方案:

解决办法

找到问题所在了,就可以对症下药了。上面的英文文章里提到了 $_SERVER['PHP_SELF'] 的替换方案,可作为解决问题的办法。那就是 #了。是的,把上面的获取当前脚本的代码简单地替换为 # 就行了,如下:

<form method="post" action="#?page=<?php echo plugin_basename(__FILE__); ?>">

那篇文章中还提到了这种方法的缺陷,就是在使用 <base> 标签的时候这种方法会失效。此时,你可以用那篇文章中提到的解决办法,也可以继续往下看,我会给出 WordPress 本身的解决方法。

更好的解决办法

安装过 WordPress 的人都知道,在安装完博客程序后,会进行简单的几步设置。其中在“常规”一栏里可以设置两个参赛:“站点地址(URL)”和“WordPress 地址(URL)”。前者是站点的网址,后者是 WordPress 博客程序的安装地址。比如我现在的博客,站点地址为 http://www.cbug.org ,WordPress 地址为 http://www.cbug.org/blog 。那如果通过某种方式得到 WordPress 的这两个参数,并且这两个参数又可自定义,那不就可以准确地找到文件 options-general.php 了么?

是时候祭出 WordPress 提供的函数了,那就是 get_bloginfo 函数。该函数返回用户博客的相关信息。该函数的详细参数及用法,可以看这篇文章:

现在我们要用到的参数是 wpurl 。使用此参数时,函数 get_bloginfo 返回的就是 WordPress 的安装地址。然后再加上亘古不变的相对路径 /wp-admin/options-general.php 即可得到正确的 URL。下面就是最终的代码了:

<form method="post" action="<?php echo get_bloginfo("wpurl"); ?>/wp-admin/options-general.php?page=<?php echo plugin_basename(__FILE__); ?>">

用上面的代码替换掉 /wp-admin/options-general.php 文件中第 136 和 259 行的代码,保存。然后进入配置页面更改配置项,点击 Save Changes ,显示 Post Views Options Updated ,搞定!

完美的解决办法就是这样的了。

后记

正所谓“无折腾,不博客。”遇到问题是比较郁闷滴,但解决了问题是比较爽滴。问题解决了,本想马上写博与大家分享,怎奈每天上下班得两个小时,回答到家中已是八、九点,吃完饭就到了洗洗睡的时间了。这不,今天熬到凌晨 3 点终于可以把作业教了。

这次没有在网页上写博客,而是用了微软的 Live Writer ,感觉还不错,就是样式还是有点少。比如,我想加个引用框,就没有。预览功能不错的。还有插件。最重要的是可以随时保存,不怕丢哈。一会发布了再看看效果吧。

Creative Commons License Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 4.0 International license .