system/core/URI.php 中的 _fetch_uri_string() 是 CodeIgniter 解析當前請求 URI 的核心私有方法,支援 5 種偵測策略 (AUTO、PATH_INFO、QUERY_STRING、REQUEST_URI、ORIG_PATH_INFO)。本文詳細剖析其流程、各策略適用場景與常見配置陷阱。
$config['uri_protocol']$config['uri_protocol'] = 'AUTO'; // 預設 // 可選值: // 'AUTO' → 依序嘗試下列 4 種 // 'PATH_INFO' → $_SERVER['PATH_INFO'] // 'QUERY_STRING' → $_SERVER['QUERY_STRING'] // 'REQUEST_URI' → $_SERVER['REQUEST_URI'] // 'ORIG_PATH_INFO' → $_SERVER['ORIG_PATH_INFO'] (IIS/特定 CGI)
protected function _fetch_uri_string() {
$protocol = $this->config->item('uri_protocol');
// 1. CLI 模式專屬處理
if (php_sapi_name() === 'cli') {
return $this->_parse_cli_args();
}
// 2. 非 AUTO:直接呼叫對應策略
if ($protocol !== 'AUTO') {
return $this->_detect_uri($protocol);
}
// 3. AUTO 模式:依優先序輪詢
$methods = ['REQUEST_URI', 'PATH_INFO', 'QUERY_STRING', 'ORIG_PATH_INFO'];
foreach ($methods as $method) {
$uri = $this->_detect_uri($method);
if ($uri !== '') return $uri;
}
return '';
}
_detect_uri()$uri = $_SERVER['REQUEST_URI'];
// 移除 query string
if (($pos = strpos($uri, '?')) !== FALSE) {
$uri = substr($uri, 0, $pos);
}
// 移除前導 /index.php (若存在)
$uri = preg_replace('~^' . preg_quote($this->config->item('index_page'), '~') . '~', '', $uri);
return $uri;
適用: 幾乎所有現代 PHP-FPM + Nginx/Apache 環境。
$path = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
if (trim($path, '/') !== '' && $path !== '/' . SELF) {
return $path;
}
注意: 需 Web Server 設定 cgi.fix_pathinfo=1。
$path = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
if (trim($path, '/') !== '') {
return $path;
}
對應網址:example.com/?/controller/method 或 example.com/index.php?/controller/method。
$path = isset($_SERVER['ORIG_PATH_INFO']) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO');
// 同 PATH_INFO 處理
_parse_cli_args()$args = array_slice($_SERVER['argv'], 1); // 移除 script name
return $args ? '/' . implode('/', $args) : '';
執行 php index.php controller method arg1 arg2 → /controller/method/arg1/arg2。
| 現象 | 原因 | 解決 |
|---|---|---|
URL 顯示 index.php 且 404 | Nginx 未正確 rewrite、uri_protocol 不匹配 | 設定 REQUEST_URI + 正確 rewrite 規則 |
參數包含 ?、& 導致路由錯誤 | QUERY_STRING 策略將完整 query string 當 URI | 改用 REQUEST_URI 或 PATH_INFO |
| 子目錄部署 (example.com/sub/) | REQUEST_URI 含 /sub/ 前綴 | 在 config.php 設定 $config['base_url']、$config['index_page'] = '' |
| IIS 環境 404 | PATH_INFO 未啟用 | 設定 uri_protocol = 'ORIG_PATH_INFO' 或啟用 IIS URL Rewrite |
AUTO,明確設定 $config['uri_protocol'] = 'REQUEST_URI'; 避免輪詢開銷與歧義。location / {
try_files $uri $uri/ /index.php$is_args$args;
}
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
$config['base_url'] = 'https://example.com/sub/'; $config['uri_protocol'] = 'REQUEST_URI';。log_message('debug', 'URI: ' . $this->uri->uri_string()); 觀察實際解析結果。| 屬性 | 用途 |
|---|---|
| $this->uri_string | 原始 URI 字串 (如 controller/method/arg) |
| $this->segments | 分段陣列 (索引從 1 開始) |
| $this->rsegments | 重新索引陣列 (從 0 開始,供路由使用) |
| $this->keyval | URI 參數快取 |