WordPress源码分析(一):安装过程中页面的加载顺序
WordPress 是一个功能非常强大的博客系统,插件众多,易于扩充功能。安装和使用都非常方便。 WordPress 已经成为主流的 Blog 搭建平台。吹嘘到此为止。(●⌒◡⌒●)所以,D瓜哥也是使用的Wordpress搭建我的博客:“地瓜哥”博客网。
前两天,一个非常要好的朋友让帮忙做个网站,以前没整过这种东西。头一次整,觉得挺头大的!首先,第一个问题就是网站的安装过程怎么处理?配置文件如何生成?可是,这两个问题该如何解决呢?
D瓜哥首先想到的就是Wordpress的安装过程:过程简单,配置清晰,只需配置一下数据库连接信息和博客的基本信息,Wordpress立马就能跑起来。非常好的“山寨”对象。整好可以借此机会,研究一下Wordpress的源代码,既可以学习一下PHP,又能深入了解一下Wordpress的实现细节,方便以后定制;还能解决我的问题。真是一箭三雕,何乐而不为?
程序下载
Wordpress是由PHP开发的,而且是开源的,所以,只要把Wordpress的压缩包下载下来,解压后就是Wordpress的源代码,非常方便。Wordpress目前最新版是 3.5.1。D瓜哥认为“大版本”刚刚推出来,肯定还有不少的Bug。所以,为了稳定起见,还是3.4.2版比较靠谱。所以,下面的分析师针对3.4.2版的。另外,Wordpress的下载页面是:WordPress下载页面。
安装过程中页面的加载顺序
下载Wordpress 3.4.2版,将下载的压缩包,解压到本机的Web服务器的相应目录下,将文件夹名称修改为wp。先声明一下,在下文中,D瓜哥假设Wordpress的根目录是wp。打开wp文件夹,里面躺着一堆PHP文件和三个文件夹,犹如很多性感多姿的美女,是不是已经“蠢蠢欲动”?
老虎吃天无处下爪!这么多美女,我们该从哪个开始下手呢?!也许我们能从Wordpress的安装过程看出一些端倪。启动Web服务器,我们打开http://127.0.0.1/wp/,请观察浏览器地址栏中的地址,你是不是惊讶为啥没有指定文件名,但是浏览器缺正常显示了?但是显示的是哪个文件内容呢?
这里就要先了解一下Apache服务器的配置:DirectoryIndex。DirectoryIndex指令用于设置当客户端在请求的目录名的末尾刻意添加一个”/”以表示请求该目录的索引时,服务器需要寻找的资源列表。也就是说,当用户访问某个文件夹下时,服务器会默认加载哪个文件来显示。在D瓜哥个人电脑上使用的XAMPP集成环境中,配置如下:
# # DirectoryIndex: sets the file that Apache will serve if a directory is requested. # <IfModule dir_module> DirectoryIndex index.php index.pl index.cgi index.asp index.shtml index.html index.htm \ default.php default.pl default.cgi default.asp default.shtml default.html default.htm \ home.php home.pl home.cgi home.asp home.shtml home.html home.htm </IfModule>
那这个列表和我们的Wordpress文件列表相比对,大家也许马上就确认wp/index.php文件会首先加载。另外,我们也可以打开http://127.0.0.1/wp/index.php来验证一下,你有木有发现和前一个连接显示的内容是一样的?!。使用文本编辑器打开wp/index.php文件,内如如下:
<?php /** * Front to the WordPress application. This file doesn't do anything, but loads * wp-blog-header.php which does and tells WordPress to load the theme. * * @package WordPress */ /** * Tells WordPress to load the WordPress theme and output it. * * @var bool */ define('WP_USE_THEMES', true); /** Loads the WordPress Environment and Template */ require('./wp-blog-header.php');
从这个文件开始的注释中可以看出,这个文件只是用来加载wp/wp-blog-header.php文件的。我们就顺藤摸瓜,打开这个文件去看个究竟。
<?php /** * Loads the WordPress environment and template. * * @package WordPress */ if ( !isset($wp_did_header) ) { $wp_did_header = true; require_once( dirname(__FILE__) . '/wp-load.php' ); wp(); require_once( ABSPATH . WPINC . '/template-loader.php' ); }
这个文件还是没有什么内容,不过这个文件的作用在注释中说的很清楚:加载Wordpress配置信息和模板。目前,我们暂时把注意力集中在第十二行上,也前一个文件一样,是require_once函数,即把文件引入进来。下面,我们接着看看这个文件wp/wp-load.php:
<?php /** * Bootstrap file for setting the ABSPATH constant * and loading the wp-config.php file. The wp-config.php * file will then load the wp-settings.php file, which * will then set up the WordPress environment. * * If the wp-config.php file is not found then an error * will be displayed asking the visitor to set up the * wp-config.php file. * * Will also search for wp-config.php in WordPress' parent * directory to allow the WordPress directory to remain * untouched. * * @internal This file must be parsable by PHP4. * * @package WordPress */ /** Define ABSPATH as this file's directory */ define( 'ABSPATH', dirname(__FILE__) . '/' ); error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR ); if ( file_exists( ABSPATH . 'wp-config.php') ) { /** The config file resides in ABSPATH */ require_once( ABSPATH . 'wp-config.php' ); } elseif ( file_exists( dirname(ABSPATH) . '/wp-config.php' ) && ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) { /** The config file resides one level above ABSPATH but is not part of another install */ require_once( dirname(ABSPATH) . '/wp-config.php' ); } else { // A config file doesn't exist // Set a path for the link to the installer if ( strpos($_SERVER['PHP_SELF'], 'wp-admin') !== false ) $path = 'setup-config.php'; else $path = 'wp-admin/setup-config.php'; define( 'WPINC', 'wp-includes' ); define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' ); require_once( ABSPATH . WPINC . '/load.php' ); require_once( ABSPATH . WPINC . '/version.php' ); wp_check_php_mysql_versions(); wp_load_translations_early(); require_once( ABSPATH . WPINC . '/functions.php' ); // Die with an error message $die = __( "There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started." ) . '</p>'; $die .= '<p>' . __( "Need more help? <a href='http://codex.wordpress.org/Editing_wp-config.php'>We got it</a>." ) . '</p>'; $die .= '<p>' . __( "You can create a <code>wp-config.php</code> file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file." ) . '</p>'; $die .= '<p><a href="' . $path . '" class="button">' . __( "Create a Configuration File" ) . '</a>'; wp_die( $die, __( 'WordPress › Error' ) ); }
直接看高亮部分的代码,第26行是判断是否有wp/wp-config.php文件;第31行是在wp/wp-config.php文件存在的情况下,判断wp/wp-settings.php是不是不存在。我们可以查看我们刚刚解压开的代码,没有wp/wp-config.php文件,则执行第38到62行的内容,你仔细看一下代码,有木有发现很熟悉,是不是页面上的内容(或者相关翻译)?
这时,请查看一下浏览器中的地址,是不是http://127.0.0.1/wp/index.php或者http://127.0.0.1/wp/?从这里可以看出,使用require_once函数,可以将另外一个文件的内容直接导入到本文件中。这是服务端发生的,对于客户端来说是透明的。
继续关注浏览器的网址!现在,点击页面的“创建配置文件”按钮,再次查看浏览器中网址,是不是变成了http://127.0.0.1/wp/wp-admin/setup-config.php?怎么跳转了呢?下面我们截取一些
// A config file doesn't exist // Set a path for the link to the installer if ( strpos($_SERVER['PHP_SELF'], 'wp-admin') !== false ) $path = 'setup-config.php'; else $path = 'wp-admin/setup-config.php'; define( 'WPINC', 'wp-includes' ); define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' ); require_once( ABSPATH . WPINC . '/load.php' ); require_once( ABSPATH . WPINC . '/version.php' ); wp_check_php_mysql_versions(); wp_load_translations_early(); require_once( ABSPATH . WPINC . '/functions.php' ); // Die with an error message $die = __( "There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started." ) . '</p>'; $die .= '<p>' . __( "Need more help? <a href='http://codex.wordpress.org/Editing_wp-config.php'>We got it</a>." ) . '</p>'; $die .= '<p>' . __( "You can create a <code>wp-config.php</code> file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file." ) . '</p>'; $die .= '<p><a href="' . $path . '" class="button">' . __( "Create a Configuration File" ) . '</a>'; wp_die( $die, __( 'WordPress › Error' ) );
从上往下往下看代码,我们首先会注意到,文件还导入了wp/wp-includes/load.php和wp/wp-includes/version.php两个文件。在wp/wp-includes/load.php中,定义了一下函数,比如下面紧接着执行的两个函数,wp_check_php_mysql_versions()检查PHP环境和MySQL的版本和可用性;而wp_load_translations_early()则是加载本地化文件。在wp/wp-includes/version.php文件中只是则是定义了一些常量。这不是我们的主线,不过多介绍!
再往下看,发现有一个<a>标签。另外我们从浏览器中可以看出浏览器做了一次跳转,而且跳转的页面是wp/wp-admin/setup-config.php。现在我们让我们暂时把代码,放一边,点击一下页面上的“现在就开始!”按钮,再次查看一下页面的链接,是不是变成了http://127.0.0.1/wp/wp-admin/setup-config.php?step=1?页面是不是显示要配置数据库连接信息的表单?不用管,这些配置信息是否正确,直接点击“提交”按钮。注意浏览器的地址栏,网址是不是变成了http://127.0.0.1/wp/wp-admin/setup-config.php?step=2?啊,页面报错了!没事,点击一下“重试”按钮,重新开始。页面有跳转到了:http://127.0.0.1/wp/wp-admin/setup-config.php?step=1……
从上面的来回跳转,D瓜哥猜测配置信息的处理就在wp/wp-admin/setup-config.php来完成的。所以,下一篇D瓜哥集中精力来分析配置信息的提交和配置文件的生成。
一些问题
在这个分析过程中还发现了一些问题,希望熟悉PHP的朋友能帮忙解答一下。问题列表如下:
- index.php等文件中,没用使用和<?php配对的?>结尾。这是为什么?
- 在一个文件中定义了常量,必须导入到其他文件中才能再次使用吗?
参考资料
原文链接:https://wordpress.diguage.com/archives/98.html
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。
index.php等文件中,没用使用和结尾。这是为什么?
在php,如果整个.php文件内容都是php代码,可以忽略掉?>结尾标签。
在一个文件中定义了常量,必须导入到其他文件中才能再次使用吗?
是的。文件与文件直接并没有直接的关联,只有require和include引入之后,才会发生关系。
楼主说得不错啊 厉害
发现了个错误,第31行不是在判断“wp/wp-config.php文件存在的情况下,判断wp/wp-settings.php是不是不存在”。dirname()函数如果参数是文件的话,结果就是该文件的绝对路径,如果参数是目录的话给出的是该目录的上一级目录。那么dirname(ABSPATH)应该是wp的上一级目录。这应该是一种安全机制吧,wp-config.php包含了数据库的信息,如果直接放在网站根目录下会有安全隐患,因此可以放到网站根目录的上一级目录。我试过,将wp-config.php移到上一级目录网站可以照常访问。
如果整个.php文件内容都是php代码,可以忽略掉?>结尾标签。
在一个文件中定义了常量,必须导入到其他文件中才能再次使用吗?
是的。文件与文件直接并没有直接的关联,只有require和include引入之后,才会发生关