wordpress url index.php,WordPress对URL的路由解析过程详解
本文說明WP 對URL rewrite并生成當(dāng)前請求的過程. 實際內(nèi)容并不復(fù)雜, 說的比較啰嗦啦…
關(guān)于Query Vars
這是Wordpress全部代碼中最重要的變量,所謂的query vars是一系列變量集合. WP通過解析URL設(shè)定query vars, 并通過分析query vars值決定顯示那些文章,設(shè)定標(biāo)志位等.所謂標(biāo)志位是WP_Query類中一系列$is_xxx形式布爾成員變量,所有的is_xxx()形式template tag實際上都是返回$wp_query里對應(yīng)成員變量值.??舉例而言,如果當(dāng)前頁面是單篇文章, 則p這個Query Var(以下簡稱變量)值不為空.(在WP類里空的query var根本不存在,而WP_Query類里如果對應(yīng)name的query var沒有設(shè)置,$wp_query->query_vars[‘varname’]被填充為空值), 如果當(dāng)前為搜索頁, s變量值則為搜索關(guān)鍵字. 如果p和page兩個變量都不為空值, 則當(dāng)前為單篇文章分頁頁面, 依次類推. Query Vars在WP類($wp)里根據(jù)WP_Rewrite里的rewrite規(guī)則生成, 在WP_Query($wp_query)類里這些變量被用來建立主循環(huán).
WP和WP_Query類里都有query_vars成員變量,鍵值為query vars里的varname. 具體的query vars包括’m’, ‘p’, ‘posts’, ‘w’, ‘cat’, ‘withcomments’, ‘withoutcomments’, ‘s’, ‘search’, ‘exact’, ‘sentence’, ‘debug’, ‘calendar’, ‘page’, ‘paged’, ‘more’, ‘tb’, ‘pb’, ‘a(chǎn)uthor’, ‘order’, ‘orderby’, ‘year’, ‘monthnum’, ‘day’, ‘hour’, ‘minute’, ‘second’, ‘name’, ‘category_name’, ‘tag’, ‘feed’, ‘a(chǎn)uthor_name’, ‘static’, ‘pagename’, ‘page_id’, ‘error’, ‘comments_popup’, ‘a(chǎn)ttachment’, ‘a(chǎn)ttachment_id’, ‘subpost’, ‘subpost_id’, ‘preview’, ‘robots’, ‘taxonomy’, ‘term’, ‘cpage’等公開變量,以及一些private變量. private變量不能由rewrite/GET等方式生成, 所以我們這里說的都指公開變量(public query vars)
準(zhǔn)備知識:WP初始化過程:
基本過程是index.php??->wp-blog.header.php ->wp-load.php .
通過wp-load.php 先后包含了wp-config.php, wp-setting.php,classes.php,fucntions.php query.php等文件,并建立了三個全局變量,$wp_the_query,$wp_rewrite和$wp ,分別為WP_Query,WP_Rewrite和WP類的實例,另外建立了一個$wp_query=&$wp_the_query, (之所以這樣做是為了通過query_posts等方式新建自定義查詢時不會損壞WP主循環(huán),在自定義查詢結(jié)束后可以調(diào)用wp_reset_query把$wp_query還原為$wp_the-query引用). 然后,wp-blog-header執(zhí)行wp()函數(shù),并通過其調(diào)用$wp所屬WP類的main方法,這個方法又調(diào)用一系列方法,但最重要的是parse_request方法, WP從這里開始解析URL并建立主循環(huán).
我們假設(shè)使用了友好的permalink,并且通過Apache下.htaccess實現(xiàn). 那么 ,WP類的parse_request方法建立一個$request變量,這個變量值是$_SERVER[‘REUEST_URI’]或$_SERVER[‘PATH_INFO’]經(jīng)過處理后的值, 是request_uri還是path_info取決于當(dāng)前是否URL是否pathinfo類型請求. 處理過程包括,移除request_uri和path_info里?以后部分(即所有GET參數(shù)). 去除request url開始的/ ,??如果你WP安裝在子目錄(如wordpress/目錄), 從(request_uri和pathinfo)開頭去除wordpress/ , 去除末尾的’/’ , 對request_uri進行rawurldecode等. ($_SERVER[‘PATH_INFO’]的值已經(jīng)是decode過的了,所以無需由wp處理).當(dāng)一切完成后, $request就是一個規(guī)范化的當(dāng)前請求filename, 形如 post-slug, date/YYYY/mm, tag/tag-slug之類 , 接下來,WP根據(jù)rewrite規(guī)則逐條對$request進行匹配(preg_match), 如果找到一個匹配, 建立相關(guān)的變量(query vars);如果沒有任何匹配,則為404
所謂的Rewrite規(guī)則就是關(guān)聯(lián)數(shù)組, 鍵值為用來匹配$request的正則表達式, 值為解析的變量, 如'([0-9]+)(/[0-9]+)?/?$’ => ‘index.php?p=$matches[1]&page=$matches[2]’ 就是一條規(guī)則. 具體解析過程稍后會有介紹.在WP類里會調(diào)用$wp_rewrite的wp_rewrite_rules方法獲取rewrite規(guī)則.注意Rewrite規(guī)則有緩存的, 保存在數(shù)據(jù)庫wp_option表,option name為rewrite_rules.如果數(shù)據(jù)庫里這個option值為空,wp_rewrite_rules()會根據(jù)你的permalink structure重新生成rewrite規(guī)則, 并保存到數(shù)據(jù)庫中.在后臺更改永久鏈接結(jié)構(gòu)時也會重新生成rewrite規(guī)則并保存到數(shù)據(jù)庫中.
具體的過程,舉例說明,如果你使用了 /%post_id% 形式的permalink, 當(dāng)前URL是?http://domain.com/18.?解析出來的$request則是18 . WP對rewrite數(shù)組里每條規(guī)則$match用preg_match(“!^$match!”, $request, $matches)語句嘗試匹配, 發(fā)現(xiàn)$request與 ‘([0-9]+)(/[0-9]+)?/?$’ => ‘index.php?p=$matches[1]&page=$matches[2]’ 這條規(guī)則匹配, preg_match把 ’18’ 和空值保存到$matches數(shù)組里, 然后WP提取出匹配項值?后部分’p=$matches[1]&page=$matches[2]’,對這個字符串$query執(zhí)行 eval(“@$query = “” . addslashes($query) . “”;”);語句, 這句的目的是把$matches[1]替換為18, 把 $matches[2]替換為空. 所以$query值變?yōu)椤痯=671&page=’, 然后執(zhí)行parse_str($query, $perma_query_vars); 這樣現(xiàn)在$perma_query_vars數(shù)組里就有鍵值’為p’和’page’的值.??但這還不是最終的query vars, 最終生成的query vars是$GLOBALS, $_POST, $GET和$perma_query_vars里鍵值為變量名項集合.依次判斷. 如果 $_POST[‘varname’]存在,則varname這個query var值為$_POST[‘varname’], 而不再繼續(xù)判斷$_GET[‘varname’]和$perma_query_vars[‘varname’]是否存在, 如此類推. 最后生成的query vars保存在 $wp->query_vars里.
如果使用的是默認(rèn)的/?p=123 permalink形式,那么上面過程簡單的多,只會從$GLOBALS, $_POST, $GET里提取query vars變量值,而不會解析REQUEST_URI和PATH_INFO.
上面過程完成后會執(zhí)行parse_request這個Action,然后執(zhí)行$wp的query_posts方法,這個方法把$wp->query_vars傳給$wp_the_query的query方法,開始建立主循環(huán),設(shè)定標(biāo)志位(is_home, is_page …)等.接下來就是載入模板顯示頁面內(nèi)容了.
下面分析一些問題:
1. 假設(shè)permalink設(shè)置為/%post_id%, 數(shù)據(jù)庫中有id為 10和11的兩篇文章, 訪問http://domain.com/10/?p=11?,顯示什么內(nèi)容?- –
答案是會顯示id為11的文章,因為上面說的, $_GET里變量優(yōu)先級高于rewrite rules里解析出來的變量($perma_query_vars),所以最后的p變量值為11.但這時WP通常會把當(dāng)前頁重定向到http://domain.com/11, 因為WP有canoninol機制(wp-includes/canonical.php),能夠301重定向一些不規(guī)范地址到規(guī)范url, 典型的如把其他域名重定向到后臺HOME和SITEURL里設(shè)定的域名里頁面.但WP的canonical機制并不完善, 個人推薦使用permalink validator插件,這個插件判斷當(dāng)前URL與官方URL是否完全匹配,如果不匹配要么重定向,要么set 404,..
2. 假設(shè)permalink設(shè)置為/%post_name%, 訪問http://domain.com/index.php/%post_name%結(jié)果如何?
如果對應(yīng)slug的post存在的話, 不會是404. 因為雖然你permalink沒有設(shè)置為index.php形式的path info permalink,但如上面所說,WP在解析URL時并不判斷后臺設(shè)定的永久鏈接結(jié)構(gòu)是path info還是request uri類型或者甚至是默認(rèn)/?p=123類型. 不過這時通常會重定向到http://domain.com/%post_name%?, 同樣因為canonical機制.
3. 關(guān)于URL末尾的 ‘/’
URL末尾是否有/對rewrite沒有影響, 如上所述, WP類在生成$request時會去除requset_uri和path_info末尾/ ,另外,你注意到所有WP生成的rewrite規(guī)則, 鍵值正則式的末尾均為??/?$ ,表示URL末尾可選 / .??不過wp會判斷當(dāng)前URL末尾是否有/ 以及后臺設(shè)置的permalink末尾是否有/, 如果不一致則301重定向, 還是因為canonical代碼. 請注意WP的 canonical代碼在template_redirect這個action處執(zhí)行,這時WP實際上已經(jīng)解析完query vars, 主循環(huán)也設(shè)置好了, 即將載入模板..
4. 假設(shè)permalink設(shè)置為/%post_name%,數(shù)據(jù)庫里兩個有slug都為’about’的post和page,訪問http://domain.com/about, 顯示哪個?
這種情況由rewrite規(guī)則數(shù)組順序決定, 通常wp生成的rewrite規(guī)則里 ‘(.+?)(/[0-9]+)?/?$’ => ‘index.php?pagename=$matches[1]&page=$matches[2]’ 這條規(guī)則是最后一個, 所以這時會顯示post而不是page.
5. 有人使用”古怪”的permalink結(jié)構(gòu),如/?p=%post_id%.html, 然后發(fā)現(xiàn)所有分類/tag頁全部顯示最新文章= =
原因是在這種古怪的permalink結(jié)構(gòu)下,WP根本無法正確獲取query vars變量,無論從GET還是url rewrite,因為如上面所說,wp rewrite 的第一步就是去除request_uri和path_info里?以后部分.事實上在這種情況下單篇文章頁能夠正常顯示也僅僅因為有一個通過GET傳遞的p變量,值為 18.html這樣形式,然后php 的 (int) 或intval() 把它變成了18 = =
6 .關(guān)于Verbose rewrite
以Apache為例,wp默認(rèn)生成的.htaccess里mod_rewrite規(guī)則非常簡單:
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
如果當(dāng)前請求不為文件或目錄,把URL請求里第一個字符重寫到index.php并停止繼續(xù)rewrite.然后WP會通過request_uri或path_info解析query vars, 如上面所述.??WP還提供一種non verbose rewrite rules, 但并沒有提供前臺接口. 在wp-include/rewrite.php里把WP_Rewrite里var $use_verbose_rules = true; 這句賦值改為false, 后臺重新保存一下permalink,你會發(fā)現(xiàn).htaccess里內(nèi)容已經(jīng)變了:
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^robots.txt$ /index.php?robots=1 [QSA,L]
RewriteRule ^.*wp-atom.php$ /index.php?feed=atom [QSA,L]
RewriteRule ^.*wp-rdf.php$ /index.php?feed=rdf [QSA,L]
RewriteRule ^.*wp-rss.php$ /index.php?feed=rss [QSA,L]
RewriteRule ^.*wp-rss2.php$ /index.php?feed=rss2 [QSA,L]
RewriteRule ^.*wp-feed.php$ /index.php?feed=feed [QSA,L]
RewriteRule ^.*wp-commentsrss2.php$ /index.php?feed=rss2&withcomments=1 [QSA,L]
RewriteRule ^feed/(feed|rdf|rss|rss2|atom)/?$ /index.php?&feed=$1 [QSA,L]
RewriteRule ^(feed|rdf|rss|rss2|atom)/?$ /index.php?&feed=$1 [QSA,L]
.....
RewriteRule ^(.+)/page/?([0-9]{1,})/?$ /index.php?pagename=$1&paged=$2 [QSA,L]
RewriteRule ^(.+)/comment-page-([0-9]{1,})/?$ /index.php?pagename=$1&cpage=$2 [QSA,L]
RewriteRule ^(.+)(/[0-9]+)?/?$ /index.php?pagename=$1&page=$2 [QSA,L]
# END WordPress
你可能對這種rewrite規(guī)則更為熟悉,國內(nèi)的程序基本上都是用這種Rewrite. 請注意這時WP的內(nèi)部過程完全不同. 在這種情況下, WP 的query vars值均來源于$_GET (Apache直接rewrite生成的), 但Request_uri或Path_Info仍會被解析并且生成的$perma_query_vars完全正確,! 只是不會被用于query vars而已. 因為$_GET優(yōu)先級高于對url rewrite獲得的值. 有人在windows下IIS的httpd.ini里加入rewrite規(guī)則,后臺permalink設(shè)置為默認(rèn)后rewrite后友好地址仍可以訪問, 就是這個原因.
如果你能看懂(或早已知道)上面內(nèi)容, 那么, 我相信對所有關(guān)于Wordpress rewrite/permalink方面的問題,你都能夠解決,或者至少找到思路.至少,我是這樣的.XT.
總結(jié)
以上是生活随笔為你收集整理的wordpress url index.php,WordPress对URL的路由解析过程详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一篇博客读懂设计模式之---委派模式
- 下一篇: php登陆项目,ThinkPHP6项目基