yaf路由解析錯誤一次問題記錄

問題描述

nginx服務器,部分配置如下:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php($|/) {
    fastcgi_pass  127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    fastcgi_param  PATH_INFO $fastcgi_path_info; #打開PATH_INFO模式
    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include     fastcgi_params;
}

然後yaf的所有請求路由解析之後均默認指向了index控制器index方法,即爲默認方法;
當把PATH_INFO模式關閉,即註釋掉之後,則yaf的路由解析正常;

問題分析

PATH_INFO是一個CGI的標準,可以用來做爲傳參載體。
PAHT_INFO模式的url是這樣的:
http://localhost/index.php/home/user/login?var=value其中home/user/login就是PATH_INFO的值,var=value是參數;
而且當開啓nginx的PATH_INFO模式的時候,PHP中預定義變量$_SERVER[‘PATH_INFO’]是有值的,是被nginx賦值的,如果關閉nginx的PATH_INFO模式,$_SERVER[‘PATH_INFO’]沒有被定義(是沒有這個key,不是爲空值);

通過以下例子來分析:

開啓PATH_INFO模式

訪問 http://yaf.com/index.php/index/test(PAHT_INFO模式url)
結果:
$_SERVER[“PATH_INFO”]=>string(11) “/index/test”
$_SERVER[“REQUEST_URI”]=>string(25) “/index.php/index/test?a=b”
解析正常,路由解析到index/test

訪問 http://yaf.com/index/test(無index.php的url)
結果:
$_SERVER[“PATH_INFO”]=>string(0) “”
$_SERVER[“REQUEST_URI”]=>string(11) “/index/test”
解析錯誤,路由解析到index/index

關閉PATH_INFO模式

訪問 http://yaf.com/index.php/index/test(PAHT_INFO模式url)
結果:
$_SERVER[“PATH_INFO”] undefined
$_SERVER[“REQUEST_URI”]=>string(11) “/index/test”
解析正常,路由解析到index/test

訪問 http://yaf.com/index/test(無index.php的url)
結果:
$_SERVER[“PATH_INFO”] undefined
$_SERVER[“REQUEST_URI”]=>string(11) “/index/test”
解析正常,路由解析到index/test

因爲我們想要的實現的訪問路徑是不帶index.php的,我們用nginx隱藏了index.php,所以我們出問題的就是上面例子中開啓PATH_INFO模式的第二個例子;正常訪問就是上面例子中關閉PATH_INFO模式的第二個例子;
從上面例子中得知,當有PATH_INFO這個值的時候,使用無index.php的url訪問,會解析錯誤;而當沒有PATH_INFO這個值得時候,使用無index.php的url訪問,解析正常;所以我們猜想,yaf的路由解析肯定優先解析PATH_INFO的值,然後纔會去解析REQUEST_URI的值;

問題原因

yaf的源碼:https://github.com/laruence/yaf/blob/6f67e9c68077542e54d149046c77d5c55efeaf90/requests/yaf_request_http.c
其中關於PAHT_INFO和REQUEST_URI的解析順序相關的代碼:

do {
    ...
    # 解析PATH_INFO
    uri = yaf_request_query_str(YAF_GLOBAL_VARS_SERVER, "PATH_INFO", sizeof("PATH_INFO") - 1);
    if (uri) {
        if (EXPECTED(Z_TYPE_P(uri) == IS_STRING)) {
            settled_uri = zend_string_copy(Z_STR_P(uri));
            break; #直接斷開
        }
    }
    # 解析REQUEST_URI
    uri = yaf_request_query_str(YAF_GLOBAL_VARS_SERVER, "REQUEST_URI", sizeof("REQUEST_URI") - 1);
    if (uri) {
        if (EXPECTED(Z_TYPE_P(uri) == IS_STRING)) {
            /* Http proxy reqs setup request uri with scheme and host [and port] + the url path,
             * only use url path */
            if (strncasecmp(Z_STRVAL_P(uri), "http", sizeof("http") - 1) == 0) {
                php_url *url_info = php_url_parse(Z_STRVAL_P(uri));
                if (url_info && url_info->path) {
                    settled_uri = zend_string_init(url_info->path, strlen(url_info->path), 0);
                }
                php_url_free(url_info);
            } else {
                char *pos = NULL;
                if ((pos = strstr(Z_STRVAL_P(uri), "?"))) {
                    settled_uri = zend_string_init(Z_STRVAL_P(uri), pos - Z_STRVAL_P(uri), 0);
                } else {
                    settled_uri = zend_string_copy(Z_STR_P(uri));
                }
            }
            break;
        }
    }
    ...
} while (0);

可以看到,只要PATH_INFO存在,那麼yaf會優先解析PATH_INFO,否則解析REQUEST_URI;

不知道用rewrite模式是否可以同時開啓PATH_INFO模式,並且同時還能隱藏index.php;有待嘗試!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章