全依靠跳转

  我们都知道,基于WordPress的博客,页面是动态生成的。比方说你访问http://abc.com/about.html页面,这个页面实际上是由WordPress的程序调用存放在数据库(WordPress用的是MySQL数据库)里的header、footer和sidebar等数据实时生成的,about.html这个文件在服务器上并不存在。

  那么WordPress是怎么实现的呢?首先你输入网址,向服务器请求某个URL(比如上面提到的http://abc.com/about.html)。服务器上的WordPress程序接到请求后,根据你提供的URL,从数据库里调出所有相关的记录,实时生成一个页面,然后把这个页面的数据传送回你。从你输入网址到网页显示完全,自始至终服务器上都不曾出现这个叫about.html的文件。

  然后问题就来了。当你自己写网站程序的时候就会发现:如果about.html这个页面在服务器上不存在,你访问了,就会看到一条“页面不存在”的提示(404错误)。那WordPress是怎么把你的URL请求与数据库中的记录联系起来的呢?我也是直到最近才想明白。

  在讲原理之前,你需要知道URL里的查询(Query)是怎么回事。通常,一个带有查询字符串(query string)的URL是这样的:http://abc.com/index.php?req=about.html。查询都是由问号(?)起头;其中req是查询的字段(field),在这里是英文单词请求(request)的缩写,你也可以自己命名;about.html则是查询的值(value);查询的字段和值靠等号连接(=)。这样,我们只需要在index.php里加一行php代码就能很方便地通过查询的字段获取查询的值了。虽然URL里有查询字符串,但我们实际上访问的还是index.php这个页面,所以不会出现“页面不存在”的问题,而index.php通常只是个脚本,没有HTML代码,它只负责把根据查询的值从数据库里调取的HTML代码拼接到一起发送给你的浏览器。

  回到正题,要避免那个“页面不存在”错误的出现,可以把所有的URL请求都跳转到根目录下的index.php上,并且把文件的相对路径作为查询字符串添加到index.php后面。这样的话,浏览器里显示的还是你请求的地址,如http://abc.com/about.html,但是对服务器来说,URL却变成了http://abc.com/index.php?req=about.html。我们只需要在index.php里获取URL里查询的值就可以去数据库里找出相关的记录(通常存放的是HTML代码),然后index.php会把这些HTML代码传回给浏览器,页面就显示出来了。

  事实上,WordPress也是通过index.php来处理请求的,但不同的是WordPress没有用到查询字符串。那怎么判断请求的是什么呢?WordPress通过用户请求的URL(即http://abc.com/about.html)信息来判断,而我上面所说的方法是通过跳转之后的URL(http://abc.com/index.php?req=about.html)来判断的。后面有两种方法的代码对比,涉及两个文件:根目录下的.htaccess和index.php。

  代码我测试过了,没问题。你输入不同的URL,页面里就会显示文件的相对路径。假设你的域名是abc.com,在地址栏里输入abc.com/hello.html并按回车,页面里就会显示hello.html(第一种方法),或者/hello.html(第二种方法,也就是WordPress的方法)。如果用第一种方法,请确保URL里不包含问号(?),否则第一个问号后面的内容全都会丢失;而如果用第二种方法,就没有这个问题。
  如果做了跳转,准备写网页了,则还需要做两件事:一是在跳转规则里排除已经存在的文件、目录和链接的地址(见缩进的那三行代码);二是将HTML代码里所有的链接都改成绝对路径的。最后,没有弄出来的朋友请确认你们的空间支持php、htaccess和url rewrite。还有,.htaccess是个隐藏文件,有些ftp,如FileZilla,默认不显示隐藏文件,需要自己设置。

方法一

.htaccess
# rewrites all requests to index.php using url query parameters
RewriteCond %{REQUEST_URI} !=/index.php [NC]
	#never rewrite for existing files, directories and links
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*) /index.php?req=$1 [L]
index.php

<?php echo $_GET["req"]; ?>


方法二(WordPress的方法)


.htaccess
# rewrites all requests to index.php using server information
RewriteCond %{REQUEST_URI} !=/index.php [NC]
	#never rewrite for existing files, directories and links
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*) /index.php [L]
index.php

<?php echo $_SERVER["REQUEST_URI"]; ?>


参考资料

http://en.wikipedia.org/wiki/Query_string
http://php.net/manual/en/function.include.php
http://php.net/manual/en/reserved.variables.server.php
http://httpd.apache.org/docs/current/rewrite/intro.html
http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
http://httpd.apache.org/docs/current/mod/mod_rewrite.html
http://httpd.apache.org/docs/current/rewrite/flags.html
http://www.build-your-website.co.uk/Blogging/Wordpress-htaccess.htm
http://stackoverflow.com/questions/2820723/how-to-get-base-url-with-php
http://stackoverflow.com/questions/3701881/how-do-i-exclude-css-js-jpg-gif-files-from-mod-rewrite-rules
http://www.codingforums.com/archive/index.php/t-163456.html

引用与转载

本文链接:http://freelancejoe.com/using-php-to-handle-url-requests?ver=1
注:这是第1稿的链接,如果您希望链接到最新的那一稿,删掉链接里问号和问号后面的部分即可。