CodeIgniter源碼分析[4]——地址解析類URI.php

在CI框架中完成地址解析的是URI.php文件,地址解析是CI框架為了識(shí)別不同風(fēng)格的URL進(jìn)行的配置和預(yù)處理類谨履,針對(duì)配置信息對(duì)URL進(jìn)行預(yù)處理然后進(jìn)行路由。

用戶配置

配置類中影響地址解析的配置項(xiàng)包括
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-‘绍载,取值用正則表達(dá)式表示URL字符串中允許出現(xiàn)的字符葛峻,不允許出現(xiàn)的字符會(huì)被過(guò)濾;
$config['url_surfix']表示URL后綴刁赖,定義次配置搁痛,CI框架會(huì)在展示給用戶的URL上添加后綴长搀,當(dāng)然在地址解析時(shí)就需要去掉后綴宇弛;
$config['enable_query_strings’],表示是否允許查詢字符串形式的URL源请,其取值為True或False枪芒。
CI默認(rèn)用戶使用搜索引擎友好的URL格式,比如example.com/who/what/where,但是也允許用戶選擇查詢query_string形式的URL谁尸,比如example.com?who=me&what=something&where=here開(kāi)啟條件是將$config['enable_query_strings’]的值設(shè)置為True舅踪,此時(shí)URI類將不做任何處理,ROUTER類也只會(huì)根據(jù)查詢字符串來(lái)匹配目錄良蛮、控制器抽碌、方法。

下面分析$config['enable_query_strings’]取值為False的情況决瞳,此時(shí)$config['uri_protocol’]配置型也會(huì)影響對(duì)URL的解析方法货徙。
$config['uri_protocol’],其取值范為REQUEST_URI皮胡,QUERT_STRING痴颊,PATH_INFO
這項(xiàng)配置是為了應(yīng)對(duì)用戶的不同的URL風(fēng)格,對(duì)服務(wù)器的影響是選擇取回URL字符串的方式不同屡贺,具體信息如下所示:

  • REQUEST_URI 使用的是$_SERVER['REQUEST_URI’] 蠢棱,返回的是用戶訪問(wèn)地址,即被訪問(wèn)的文件之后的所有URI段 [包括path_info和query_string]甩栈。
  • QUERY_STRING 使用的是$_SERVER['QUERY_STRING’]泻仙,返回查詢字符串即符號(hào)?之后的URL部分。
  • PATH_INFO 使用的是$_SERVER['PATH_INFO’]量没,返回真實(shí)腳本文件之后和查詢字符串之前的URL部分玉转。
    有關(guān)$_SERVER的知識(shí)不清楚建議查閱PHP手冊(cè)或相關(guān)博文

至此,我們已經(jīng)清楚了鉤子的開(kāi)啟和配置方法允蜈,下面我們開(kāi)始分析CI_URI類的代碼冤吨,由于方法比較多且具部分方法比較簡(jiǎn)單并且也只在該類的其他方法中使用,因此本文只就個(gè)人理解的重點(diǎn)方法進(jìn)行介紹饶套。

屬性概覽

屬性名稱 注釋
public $keyval = array() 用緩存保存的URL字符列表
public $uri_string = '' 當(dāng)前的URL字符
public $segments = array() 保存URL字符列表漩蟆,數(shù)組下標(biāo)從1開(kāi)始
public $rsegments = array() 保存路由的URL字符列表
protected $_permitted_uri_chars 保存允許的URL字符集合

方法概覽

方法名稱 注釋
__construct() 構(gòu)造函數(shù)
_set_uri_string($str) 保存解析后的uri并設(shè)置segements數(shù)組
_parse_request_uri() request_uri配置下的解析方法
_parse_query_string() query_string配置下的解析方法
_parse_argv() cli模式下參數(shù)處理方法
_remove_relative_directory($uri) 去除相對(duì)路徑和多個(gè)斜線
filter_uri(&$str) 安全處理過(guò)濾不允許的字符
segment($n, $no_result = NULL)
rsegment($n, $no_result = NULL)
uri_to_assoc($n = 3, $default = array())
ruri_to_assoc($n = 3, $default = array())
_uri_to_assoc($n = 3, $default = array(), $which = 'segment')
assoc_to_uri($array)
slash_segment($n, $where = 'trailing')
slash_rsegment($n, $where = 'trailing')
_slash_segment($n, $where = 'trailing', $which = 'segment')
segment_array()
rsegment_array()
total_segments()
total_rsegments()
uri_string()
ruri_string()

構(gòu)造函數(shù)__construct

public function __construct()
{
   $this->config =& load_class('Config', 'core');
   //如果配置項(xiàng)中config['enable_query_string']取值為True,我們不需要處理當(dāng)前的URL
   //但是這項(xiàng)配置在CLI模式下不生效妓蛮,因此要處理CLI模式和不允許query_string的情況
   if (is_cli() OR $this->config->item('enable_query_strings') !== TRUE)
   {
       //從配置項(xiàng)中獲取允許字符集合的正則
      $this->_permitted_uri_chars = $this->config->item('permitted_uri_chars');
      //如果是CLI模式忽略配置怠李,將參數(shù)拼接城argv1/argv2的形式
      if (is_cli())
      {
         $uri = $this->_parse_argv();
      }
      else
      {
          //不允許query_string時(shí),根據(jù)配置的uri_protocol選擇取回的字符串,默認(rèn)為REQUEST_URI
         $protocol = $this->config->item('uri_protocol');
         empty($protocol) && $protocol = 'REQUEST_URI';
         //根據(jù)配置項(xiàng)的不同捺癞,選擇不同的函數(shù)處理URL
         switch ($protocol)
         {
            case 'AUTO': // For BC purposes only
            case 'REQUEST_URI':
               $uri = $this->_parse_request_uri();
               break;
            case 'QUERY_STRING':
               $uri = $this->_parse_query_string();
               break;
            case 'PATH_INFO':
            default:
               $uri = isset($_SERVER[$protocol])
                  ? $_SERVER[$protocol]
                  : $this->_parse_request_uri();
               break;
         }
      }
      //保存解析后的uri夷蚊,并設(shè)置segements數(shù)組
      $this->_set_uri_string($uri);
   }

   log_message('info', 'URI Class Initialized');
}

REQUEST_URI配置的解析_prase_request_uri

 protected function _parse_request_uri()
{
   if ( ! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))

   {
      return '';
   }
   //如果不提供host,函數(shù)parse_url()會(huì)返回false
   //從憑借的uri中獲取get請(qǐng)求參數(shù)$query和請(qǐng)求的路徑$url
   $uri = parse_url('[http://dummy](http://dummy/)'.$_SERVER['REQUEST_URI']);
   $query = isset($uri['query']) ? $uri['query'] : '';
   $uri = isset($uri['path']) ? $uri['path'] : '';
   //去掉$uri中包含的$_SERVER['SCRIPT_NAME']
   //Q:當(dāng)前的uri已經(jīng)是取path得到的不應(yīng)該再包含腳本名稱髓介,應(yīng)該是為了防止惡意的URL引起的解析錯(cuò)誤
   if (isset($_SERVER['SCRIPT_NAME'][0]))
   {
      if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
      {
         $uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME']));
      }
      elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
      {
         $uri = (string) substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
      }
   }
   //對(duì)于服務(wù)器請(qǐng)求的uri的處理惕鼓,保證再服務(wù)器下也能正確解析uri
   // 并且修復(fù)了QUERY_STRING和$_GET的值.
   if (trim($uri, '/') === '' && strncmp($query, '/', 1) === 0)
   {
      $query = explode('?', $query, 2);
      $uri = $query[0];
      $_SERVER['QUERY_STRING'] = isset($query[1]) ? $query[1] : '';
   }
   else
   {
      $_SERVER['QUERY_STRING'] = $query;
   }
   //將字符串解析為多個(gè)變量存入$_GET中
   parse_str($_SERVER['QUERY_STRING'], $_GET);
   if ($uri === '/' OR $uri === '')
   {
      return '/';
   }
   //去除相對(duì)路徑"../"和多余的斜線"http:///"并返回
   return $this->_remove_relative_directory($uri);
}

QUERY_STRING配置的解析

protected function _parse_query_string()
{
   $uri = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
   //如果去掉斜線之后$uri為空返回空串
   if (trim($uri, '/') === '')
   {
      return '';
   }
   elseif (strncmp($uri, '/', 1) === 0)
   {
       //根據(jù)?分割$uri并修復(fù)$_SERVER['QUERY_STRING']的值
      $uri = explode('?', $uri, 2);
      $_SERVER['QUERY_STRING'] = isset($uri[1]) ? $uri[1] : '';
      $uri = $uri[0];
   }
   parse_str($_SERVER['QUERY_STRING'], $_GET);
       //去除相對(duì)路徑"../"和多個(gè)斜線"http:///",然后返回
   return $this->_remove_relative_directory($uri);
}

設(shè)置uri_string的值_set_uri_string($str)

protected function _set_uri_string($str)
{
   //將處理過(guò)的$str經(jīng)過(guò)去除不可見(jiàn)字符和trim之后保存在屬性$uri_string中
   $this->uri_string = trim(remove_invisible_characters($str, FALSE), '/');

   if ($this->uri_string !== '')
   {
      //如果定義了url后綴且當(dāng)前存在就移除后綴
      if (($suffix = (string) $this->config->item('url_suffix')) !== '')
      {
         $slen = strlen($suffix);

         if (substr($this->uri_string, -$slen) === $suffix)
         {
            $this->uri_string = substr($this->uri_string, 0, -$slen);
         }
      }

      $this->segments[0] = NULL;
      //以"/"分割url_string用來(lái)填充segments數(shù)組
      foreach (explode('/', trim($this->uri_string, '/')) as $val)
      {
         $val = trim($val);
         //安全處理唐础,過(guò)濾$val
         $this->filter_uri($val);

         if ($val !== '')
         {
            $this->segments[] = $val;
         }
      }
           //由于這一步箱歧,實(shí)際有用的數(shù)據(jù)從segments的下標(biāo)1開(kāi)始
      unset($this->segments[0]);
   }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市一膨,隨后出現(xiàn)的幾起案子呀邢,更是在濱河造成了極大的恐慌,老刑警劉巖豹绪,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件价淌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡瞒津,警方通過(guò)查閱死者的電腦和手機(jī)蝉衣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仲智,“玉大人买乃,你說(shuō)我怎么就攤上這事〉隽荆” “怎么了剪验?”我有些...
    開(kāi)封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)前联。 經(jīng)常有香客問(wèn)我功戚,道長(zhǎng),這世上最難降的妖魔是什么似嗤? 我笑而不...
    開(kāi)封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任啸臀,我火速辦了婚禮,結(jié)果婚禮上烁落,老公的妹妹穿的比我還像新娘乘粒。我一直安慰自己,他們只是感情好伤塌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布灯萍。 她就那樣靜靜地躺著,像睡著了一般每聪。 火紅的嫁衣襯著肌膚如雪旦棉。 梳的紋絲不亂的頭發(fā)上齿风,一...
    開(kāi)封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音绑洛,去河邊找鬼救斑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛真屯,可吹牛的內(nèi)容都是我干的脸候。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼讨跟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼纪他!你這毒婦竟也來(lái)了鄙煤?” 一聲冷哼從身側(cè)響起晾匠,我...
    開(kāi)封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梯刚,沒(méi)想到半個(gè)月后凉馆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亡资,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年澜共,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锥腻。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗦董,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瘦黑,到底是詐尸還是另有隱情京革,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布幸斥,位于F島的核電站匹摇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏甲葬。R本人自食惡果不足惜廊勃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望经窖。 院中可真熱鬧坡垫,春花似錦、人聲如沸画侣。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)棉钧。三九已至屿脐,卻和暖如春涕蚤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背的诵。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工万栅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人西疤。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓烦粒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親代赁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子扰她,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)芭碍,斷路器徒役,智...
    卡卡羅2017閱讀 134,629評(píng)論 18 139
  • 上一節(jié)我們說(shuō)url的請(qǐng)求本質(zhì)上是調(diào)用控制器的方法,我們分析了下確實(shí)也是如此窖壕,最終是在CodeIgniter.php...
    鈍感165閱讀 653評(píng)論 0 0
  • 文章圖片上傳不正常忧勿,如需文檔,可聯(lián)系微信:1017429387 目錄 1 安裝... 4 1.1 配置探針... ...
    Mrhappy_a7eb閱讀 6,287評(píng)論 0 5
  • 今天,1月9日速勇,小程序正式對(duì)外發(fā)布晌砾。 張小龍選擇這個(gè)10年前蘋果發(fā)布初代iphone的日子發(fā)布小程序,至少透露出兩...
    六更讀書閱讀 680評(píng)論 0 2
  • 夕陽(yáng)的光線照進(jìn)房間是真美乖寒,卻透出荒涼與落寞,連帶著時(shí)光都變得老舊了院溺。 在這稍縱即逝的景象光影中楣嘁,仿佛看到人至暮年。...
    心玥Lotus閱讀 325評(píng)論 0 0