欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

yaf路由解析错误一次问题记录

程序员文章站 2024-02-15 19:30:46
...

问题描述

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;有待尝试!