欢迎转载!转载时请注明出处:http://blog.csdn.net/nfer_zhuang/article/details/50316171

前言

WordPress自带的注册页面比较简陋,BuddyPress插件提供了一个比较丰富的注册页面,但是当我打开页面时却显示了“404 Not Found”(已打开WordPress的注册开关并设置了Buddypress的注册页面),本篇文章就是记录如何排查和解决该问题的。

问题截图


注:我是在WordPress4.3.1版本下进行的测试

排查问题

确认BuddyPress页面设置

通过截图,我们确认设置了使用BuddyPress的注册页面来替换原生页面。

确认页面是否可以直接打开

我们注意在每个设置的右边有一个view的按钮,那么直接点击这个按钮是否可以打开页面呢?

通过截图,我们确认直接打开页面是OK的,至少说明设置是有效的,且页面存在。
但是,我们发现了一个奇怪的地方,就是这两个页面的URL中都带有一个index.php,这是个什么东西呢?看上去完全不符合常理啊。

固定链接

通过查询资料,我们发现这个index.php是根据固定链接中的设置添加到URL中的。

那为什么WordPress会设置成/index.php/*这种反人类的方式呢?

源码分析

在wp-admin/includes/upgrade.php文件下有下述代码:

    /** The Permalink structures to attempt.** The first is designed for mod_rewrite or nginx rewriting.** The second is PATHINFO-based permalinks for web server configurations* without a true rewrite module enabled.*/$permalink_structures = array('/%year%/%monthnum%/%day%/%postname%/','/index.php/%year%/%monthnum%/%day%/%postname%/');foreach ( (array) $permalink_structures as $permalink_structure ) {$wp_rewrite->set_permalink_structure( $permalink_structure );/** Flush rules with the hard option to force refresh of the web-server's* rewrite config file (e.g. .htaccess or web.config).*/$wp_rewrite->flush_rules( true );// Test against a real WordPress Post, or if none were created, a random 404 page.$test_url = get_permalink( 1 );if ( ! $test_url ) {$test_url = home_url( '/wordpress-check-for-rewrites/' );}/** Send a request to the site, and check whether* the 'x-pingback' header is returned as expected.** Uses wp_remote_get() instead of wp_remote_head() because web servers* can block head requests.*/$response          = wp_remote_get( $test_url, array( 'timeout' => 5 ) );$x_pingback_header = wp_remote_retrieve_header( $response, 'x-pingback' );$pretty_permalinks = $x_pingback_header && $x_pingback_header === get_bloginfo( 'pingback_url' );if ( $pretty_permalinks ) {return true;}}

上述代码是在用户安装WordPress时候运行的代码片段,通过添加打印,我们确认上面的foreachloop在运行到'/index.php/%year%/%monthnum%/%day%/%postname%/'的时候才返回true。

回到上面permalink_structures数组的注释上:

    /** The Permalink structures to attempt.** The first is designed for mod_rewrite or nginx rewriting.** The second is PATHINFO-based permalinks for web server configurations* without a true rewrite module enabled.*/

我们了解到第一个固定链接格式是针对于支持mod_rewritenginx rewriting的,而第二个则是针对不支持rewrite的HTTP Server环境的。

我这里使用的是LAMP的环境,理论上是支持rewrite的,那么下一步我们就开始排查rewrite功能。

LAMP的rewrite功能

检查apache是否已经配置rewrite功能

通过搜索,确认在apache2中已经配置了rewrite功能

$ grep rewrite ./ -nR
./mods-available/rewrite.load:1:LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
./mods-enabled/rewrite.load:1:LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
$ ls /usr/lib/apache2/modules/mod_rewrite.so
/usr/lib/apache2/modules/mod_rewrite.so

我们发现在mods-enabled中已经包含rewrite.load,且mod_rewrite.so文件存在。

通过PHP检查rewrite功能是否已配置

stackoverflow中有一个回答中给出了一种方法:

in_array('mod_rewrite', apache_get_modules());

我们添加了一些打印信息:

<?php
if (in_array('mod_rewrite', apache_get_modules()))print "The apache module mod_rewrite is enabled.<br/>\n";
elseprint "The apache module mod_rewrite is NOT enabled.<br/>\n";

但是在cli下运行报错:

$ php apache_rewrite_check
PHP Fatal error:  Call to undefined function apache_get_modules() in /home/nfer/bak/apache_rewrite_check on line 2

我们尝试在浏览器中访问该文件,发现可以运行,且输出了The apache module mod_rewrite is enabled.信息,证明在apache运行环境下通过PHP确认是支持rewrite功能的。

通过shell命令行检查rewrite功能是否已配置

同样,在该篇回答中给出了一种在Ubuntu命令行下检查是否打开了rewrite功能的方法:

$ apachectl -M | grep rewriterewrite_module (shared)

通过PHP实际测试rewrite功能

按照stackoverflow给出的例子,我们创建了rewrite文件夹,并在该文件夹下创建了.htaccess和index.php文件,内容分别为:

$ cat .htaccess
RewriteEngine On
RewriteRule ^inc/.*$ index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
$ cat index.php
<?php
print "hello world.<br/>\n";

我们测试,通过http://localhost/rewrite/ 或 http://localhost/rewrite/123123 或 http://localhost/rewrite/hello 以及任何http://localhost/rewrite/ 前缀的地址都能正确输出hello world.,即PHP的rewrite功能是OK的。

WordPress的rewrite判断

我们重点来看一下foreach的处理:

        $wp_rewrite->set_permalink_structure( $permalink_structure );/** Flush rules with the hard option to force refresh of the web-server's* rewrite config file (e.g. .htaccess or web.config).*/$wp_rewrite->flush_rules( true );// Test against a real WordPress Post, or if none were created, a random 404 page.$test_url = get_permalink( 1 );if ( ! $test_url ) {$test_url = home_url( '/wordpress-check-for-rewrites/' );}/** Send a request to the site, and check whether* the 'x-pingback' header is returned as expected.** Uses wp_remote_get() instead of wp_remote_head() because web servers* can block head requests.*/$response          = wp_remote_get( $test_url, array( 'timeout' => 5 ) );$x_pingback_header = wp_remote_retrieve_header( $response, 'x-pingback' );$pretty_permalinks = $x_pingback_header && $x_pingback_header === get_bloginfo( 'pingback_url' );if ( $pretty_permalinks ) {return true;}

上面的测试主要包括以下几个步骤:
1. 设置固定链接格式
2. 将rewrite规则写入到文件中
3. 使用第一篇博客(id为1)来实际测试rewrite效果
4. 发送wp_remote_get请求并检测返回的header中是否包含x-pingback字段(URL可以访问的话,response中会包含x-pingback字段,否则不包含该字段)

注:更多关于x-pingback的资料请移步WordPress官方文档

flush_rules()

在上面的代码中有一处代码如下:

        /** Flush rules with the hard option to force refresh of the web-server's* rewrite config file (e.g. .htaccess or web.config).*/$wp_rewrite->flush_rules( true );

继续看flush_rules函数的实现:

    public function flush_rules( $hard = true ) {static $do_hard_later = null;// Prevent this action from running before everyone has registered their rewrites.if ( ! did_action( 'wp_loaded' ) ) {add_action( 'wp_loaded', array( $this, 'flush_rules' ) );$do_hard_later = ( isset( $do_hard_later ) ) ? $do_hard_later || $hard : $hard;return;}if ( isset( $do_hard_later ) ) {$hard = $do_hard_later;unset( $do_hard_later );}delete_option('rewrite_rules');$this->wp_rewrite_rules();/*** Filter whether a "hard" rewrite rule flush should be performed when requested.** A "hard" flush updates .htaccess (Apache) or web.config (IIS).** @since 3.7.0** @param bool $hard Whether to flush rewrite rules "hard". Default true.*/if ( ! $hard || ! apply_filters( 'flush_rewrite_rules_hard', true ) ) {return;}if ( function_exists( 'save_mod_rewrite_rules' ) )save_mod_rewrite_rules();if ( function_exists( 'iis7_save_url_rewrite_rules' ) )iis7_save_url_rewrite_rules();}

该函数包括以下流程:
1. 处理在wp_loaded之前的flush_rules请求
2. 更新rewrite_rules配置(到数据库中)
3. 更加环境不同,分别调用save_mod_rewrite_rules和iis7_save_url_rewrite_rules来写入rewrite规则到文件系统中

save_mod_rewrite_rules()

因为我使用的LAMP环境,因此在flush_rules()中实际作用的是save_mod_rewrite_rules()函数,实现如下:

function save_mod_rewrite_rules() {if ( is_multisite() )return;global $wp_rewrite;$home_path = get_home_path();$htaccess_file = $home_path.'.htaccess';/** If the file doesn't already exist check for write access to the directory* and whether we have some rules. Else check for write access to the file.*/if ((!file_exists($htaccess_file) && is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks()) || is_writable($htaccess_file)) {if ( got_mod_rewrite() ) {$rules = explode( "\n", $wp_rewrite->mod_rewrite_rules() );return insert_with_markers( $htaccess_file, 'WordPress', $rules );}}return false;
}

在上述代码中,有几处条件检查:
1. 判断htaccess_file文件是否不存在
2. 判断home_path目录是否可写
3. 判断htaccess_file文件是否可写

其实,看到这里我们需要检查是否在安装WordPress的时候WordPress程序不具有home_path目录和htaccess_file文件的写权限?

通过ls -l可以得到下述的列表:

/var/www/tag/WordPress_4_3_1$ ls -l ../
total 4
drwxrwxr-x 6 nfer nfer 4096 12月 15 17:38 WordPress_4_3_1

其中WordPress_4_3_1目录的读写权限是775,即当前用户和当前组均具有读写执行权限,其它用户只有读和执行权限并没有写入权限。我们再看一下apache进行的用户名:

/var/www/tag/WordPress_4_3_1$ ps auxf | grep apache
root      1071  0.0  0.2  38048  9024 ?        Ss   04:15   0:08 /usr/sbin/apache2 -k start
www-data  4695  0.0  1.0  73968 44636 ?        S    09:04   0:11  \_ /usr/sbin/apache2 -k start
www-data  4723  0.0  1.1  76304 46396 ?        S    09:14   0:10  \_ /usr/sbin/apache2 -k start

可以看到apache是通过root用户启动的,然后每个工作进程是使用www-data用户启动的。

修改文件拥有者并重新安装WordPress

通过下述命令,修改WordPress目录的拥有者为www-data:

/var/www/tag$ sudo chown www-data WordPress_4_3_1/ -R
[sudo] password for nfer:
/var/www/tag$ ls -l
total 4
drwxrwxr-x 6 www-data nfer 4096 12月 15 17:38 WordPress_4_3_1

删除并重新创建数据库,删除wp-config.php文件,重新打开WordPress安装程序,整个流程完成后,我们再打开”设置-固定链接”页面,发现固定链接格式为'/%year%/%monthnum%/%day%/%postname%/'

总结

该文章描述了我从最开始遇到WordPress+BuddyPress无法打开注册页面问题,到一步步的通过查询资料、阅读相关源码,并最终解决问题的过程。在实际解决问题的过程中,有一些地方并没有详细展开,一些遗留问题已附在下面。
解决问题后,再次打开注册页面,效果如下:

遗留问题

  1. 为什么在.htaccess无法写入的情况下,使用'/index.php/%year%/%monthnum%/%day%/%postname%/' rewrite规则?
  2. '/index.php/%year%/%monthnum%/%day%/%postname%/'是如何在.htaccess无法工作的情况下产生实际效果的?
  3. flush_rules函数中的wp_loaded逻辑是否有必要?

WordPress+BuddyPress注册页面404问题的解决相关推荐

  1. gii无法访问 yii2_YII2框架访问gii、debug页面404的错误解决方法

    之前在介绍Yii框架的时候就说过 Yii 支持 gii 功能, gii 去自动生成 Web 站点常用功能的代码,也就是我们经常说的 CURD 操作,增删改查.使用 gii 生成代码也是非常的简单,Gi ...

  2. Tomcat容器部署 浏览器访问服务器页面404 403错误 解决方法

    启动一个tomcat容器,注意:新版本tomcat镜像启动时必须映射端口(8080为默认容器端口) docker run -d --name tomcat -p 8080:8080 -v /mnt/e ...

  3. WordPress更改“固定链接”后 页面404原因及解决方法(Nginx版)

    网上盛传的方法是: 在 /etc/nginx/nginx.conf文件的 loction / {} 中添加 if (-f $request_filename/index.html){rewrite ( ...

  4. WordPress前台后台页面打开慢的解决方法

    写个人网站用WordPress程序是一个不错的选择,但是目前安装之后速度很慢,后台配置页面半天打不开,在网上查了一下原来是Google被墙导致,WordPress默认模板会加载谷歌的open-sans ...

  5. iis打开php网页404,遇到IIS7配置PHP出现403和404错误的解决办法

    服务器要配置PHP,总是出现403错误.服务器是新装的,操作系统是windows server 2008 R2,装的IIS7. IIS里PHP和本地服务器对比了好几遍,都没到出错的原因,后来通过cmd ...

  6. Linux 系统使用WordPress开启“固定链接设置”之后部分页面打不开(404)的解决办法...

    WordPress系统中我们设定了固定链接设置,选择了自定义结构:http://192.168.10.11/html/%postname%.html 注:%postname%文章标题的别名,文章标题是 ...

  7. 怎么返回404_seo如果出现404页面怎么办?如何解决?

    seo如果出现404页面怎么办?如何解决?很多人对于404页面都司空见惯了,但是要如何找出404错误呢?如何解决呢?下面聚名网小编就为大家介绍一下404页面对于seo是什么. seo如果出现404页面 ...

  8. 308 permanent redirect怎么解决_「网站」WordPress网站更改固定链接以后怎么解决404错误...

    细心的人可能会发现,这篇文章跟如何应公安备案要求将备案编号HTML代码和备案编号图标粘贴到网页的底部位置发布的时间相差并不长,因为我搞定一个问题又跑去搞另一个问题了,之后再一起写的文章 回到正题,Wo ...

  9. wp-login.php 404页面,WordPress网站如何设置404页面

    站长都知道网站搭建好,是需要进行404页面的设置,若没有设置404页面会导致网站流量的流失,那么,WordPress网站如何设置404页面?接下来就关于这个问题为大家进行分析. 404页面也就是客户端 ...

最新文章

  1. backup restore On Ubuntu
  2. 崔希凡javaWeb笔记day01~day03(2016年5月20日20:33:54)
  3. 详细解析SELECT模型
  4. Java总结:正则表达式
  5. 无法理解高等数学怎么办?
  6. 如何写好一个综述,以一个综述为例
  7. 用idea对git的merge进行撤销
  8. android看视频掉帧,玩游戏看视频经常卡顿不顺畅?你只需这几步
  9. EXCEL MATCH函数
  10. 七大行星排列图片_太阳系八大行星大小及排列顺序
  11. Unity 3D安装教程
  12. ARM7、ARM9、ARM11、ARM-Cortex的关系
  13. Python制作一个12306查票程序脚本(附完整代码,仅供学习参考)
  14. Java自学经验分享
  15. docker启动mysql失败(闪退)原因
  16. LaTeX 数学公式大全
  17. java吞食天地中武将_在FC吞食天地2里面,哪些武将的基础属性出乎玩家预料
  18. Android Jetpack之DataBinding+ViewModel+LiveData+Room
  19. 百度网盘不限速——pandownlode与BaiduPCS-Go
  20. 用matlab演奏周杰伦的《七里香》

热门文章

  1. Matlab一句话画三维应力云图
  2. 智能家居代码构建编写、简单工厂模式、树莓派摄像头视频监控功能实现
  3. 甘肃环县村民迁新居不弃良田 建“自乐班”融洽村邻
  4. win10彻底卸载52好压
  5. [Windows]_[系统内部版本号对照表]
  6. 权限维持之:SID History 域控权限维持
  7. Cinderella
  8. 适应iphone5 屏幕拉长的办法
  9. 探索 Android 网络优化方法
  10. STC8A单片机应用开发