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集成环境中,配置如下:
2 | # DirectoryIndex: sets the file that Apache will serve if a directory is requested. |
5 | DirectoryIndex index.php index.pl index.cgi index.asp index.shtml index.html index.htm \ |
6 | default.php default.pl default.cgi default.asp default.shtml default.html default.htm \ |
7 | home.php home.pl home.cgi home.asp home.shtml home.html home.htm |
那这个列表和我们的Wordpress文件列表相比对,大家也许马上就确认wp/index.php文件会首先加载。另外,我们也可以打开http://127.0.0.1/wp/index.php来验证一下,你有木有发现和前一个连接显示的内容是一样的?!。使用文本编辑器打开wp/index.php文件,内如如下:
14 | define( 'WP_USE_THEMES' , true); |
17 | require ( './wp-blog-header.php' ); |
从这个文件开始的注释中可以看出,这个文件只是用来加载wp/wp-blog-header.php文件的。我们就顺藤摸瓜,打开这个文件去看个究竟。
08 | if ( !isset( $wp_did_header ) ) { |
10 | $wp_did_header = true; |
12 | require_once ( dirname( __FILE__ ) . '/wp-load.php' ); |
16 | require_once ( ABSPATH . WPINC . '/template-loader.php' ); |
这个文件还是没有什么内容,不过这个文件的作用在注释中说的很清楚:加载Wordpress配置信息和模板。目前,我们暂时把注意力集中在第十二行上,也前一个文件一样,是require_once函数,即把文件引入进来。下面,我们接着看看这个文件wp/wp-load.php:
22 | define( 'ABSPATH' , dirname( __FILE__ ) . '/' ); |
24 | 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 ); |
26 | if ( file_exists ( ABSPATH . 'wp-config.php' ) ) { |
29 | require_once ( ABSPATH . 'wp-config.php' ); |
31 | } elseif ( file_exists ( dirname(ABSPATH) . '/wp-config.php' ) && ! file_exists ( dirname(ABSPATH) . '/wp-settings.php' ) ) { |
34 | require_once ( dirname(ABSPATH) . '/wp-config.php' ); |
41 | if ( strpos ( $_SERVER [ 'PHP_SELF' ], 'wp-admin' ) !== false ) |
42 | $path = 'setup-config.php' ; |
44 | $path = 'wp-admin/setup-config.php' ; |
46 | define( 'WPINC' , 'wp-includes' ); |
47 | define( 'WP_CONTENT_DIR' , ABSPATH . 'wp-content' ); |
48 | require_once ( ABSPATH . WPINC . '/load.php' ); |
49 | require_once ( ABSPATH . WPINC . '/version.php' ); |
51 | wp_check_php_mysql_versions(); |
52 | wp_load_translations_early(); |
54 | require_once ( ABSPATH . WPINC . '/functions.php' ); |
57 | $die = __( "There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started." ) . '</p>'; |
59 | $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>'; |
60 | $die .= '<p><a href="' . $path . '" class="button">' . __( "Create a Configuration File" ) . '</a>' ; |
62 | 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?怎么跳转了呢?下面我们截取一些
41 | if ( strpos ( $_SERVER [ 'PHP_SELF' ], 'wp-admin' ) !== false ) |
42 | $path = 'setup-config.php' ; |
44 | $path = 'wp-admin/setup-config.php' ; |
46 | define( 'WPINC' , 'wp-includes' ); |
47 | define( 'WP_CONTENT_DIR' , ABSPATH . 'wp-content' ); |
48 | require_once ( ABSPATH . WPINC . '/load.php' ); |
49 | require_once ( ABSPATH . WPINC . '/version.php' ); |
51 | wp_check_php_mysql_versions(); |
52 | wp_load_translations_early(); |
54 | require_once ( ABSPATH . WPINC . '/functions.php' ); |
57 | $die = __( "There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started." ) . '</p>'; |
59 | $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>'; |
60 | $die .= '<p><a href="' . $path . '" class="button">' . __( "Create a Configuration File" ) . '</a>' ; |
62 | 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配对的?>结尾。这是为什么?
- 在一个文件中定义了常量,必须导入到其他文件中才能再次使用吗?
参考资料
- 维基百科中对Wordpress的介绍
- Apache 2.2中文参考手册
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引入之后,才会发生关