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