PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/a10/lib/yii-1.1.10/web/CHttpRequest.php

http://chenjin.googlecode.com/
PHP | 1064 lines | 858 code | 22 blank | 184 comment | 39 complexity | ebbe337c482afc1c6fc467f3211d0259 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * CHttpRequest and CCookieCollection class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright Copyright &copy; 2008-2011 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CHttpRequest encapsulates the $_SERVER variable and resolves its inconsistency among different Web servers.
  12. *
  13. * CHttpRequest also manages the cookies sent from and sent to the user.
  14. * By setting {@link enableCookieValidation} to true,
  15. * cookies sent from the user will be validated to see if they are tampered.
  16. * The property {@link getCookies cookies} returns the collection of cookies.
  17. * For more details, see {@link CCookieCollection}.
  18. *
  19. * CHttpRequest is a default application component loaded by {@link CWebApplication}. It can be
  20. * accessed via {@link CWebApplication::getRequest()}.
  21. *
  22. * @property string $url Part of the request URL after the host info.
  23. * @property string $hostInfo Schema and hostname part (with port number if needed) of the request URL (e.g. http://www.yiiframework.com).
  24. * @property string $baseUrl The relative URL for the application.
  25. * @property string $scriptUrl The relative URL of the entry script.
  26. * @property string $pathInfo Part of the request URL that is after the entry script and before the question mark.
  27. * Note, the returned pathinfo is decoded starting from 1.1.4.
  28. * Prior to 1.1.4, whether it is decoded or not depends on the server configuration
  29. * (in most cases it is not decoded).
  30. * @property string $requestUri The request URI portion for the currently requested URL.
  31. * @property string $queryString Part of the request URL that is after the question mark.
  32. * @property boolean $isSecureConnection If the request is sent via secure channel (https).
  33. * @property string $requestType Request type, such as GET, POST, HEAD, PUT, DELETE.
  34. * @property boolean $isPostRequest Whether this is a POST request.
  35. * @property boolean $isDeleteRequest Whether this is a DELETE request.
  36. * @property boolean $isPutRequest Whether this is a PUT request.
  37. * @property boolean $isAjaxRequest Whether this is an AJAX (XMLHttpRequest) request.
  38. * @property string $serverName Server name.
  39. * @property integer $serverPort Server port number.
  40. * @property string $urlReferrer URL referrer, null if not present.
  41. * @property string $userAgent User agent, null if not present.
  42. * @property string $userHostAddress User IP address.
  43. * @property string $userHost User host name, null if cannot be determined.
  44. * @property string $scriptFile Entry script file path (processed w/ realpath()).
  45. * @property array $browser User browser capabilities.
  46. * @property string $acceptTypes User browser accept types, null if not present.
  47. * @property integer $port Port number for insecure requests.
  48. * @property integer $securePort Port number for secure requests.
  49. * @property CCookieCollection $cookies The cookie collection.
  50. * @property string $preferredLanguage The user preferred language.
  51. * @property string $csrfToken The random token for CSRF validation.
  52. *
  53. * @author Qiang Xue <qiang.xue@gmail.com>
  54. * @version $Id: CHttpRequest.php 242 2012-03-29 15:18:01Z mole1230 $
  55. * @package system.web
  56. * @since 1.0
  57. */
  58. class CHttpRequest extends CApplicationComponent
  59. {
  60. /**
  61. * @var boolean whether cookies should be validated to ensure they are not tampered. Defaults to false.
  62. */
  63. public $enableCookieValidation=false;
  64. /**
  65. * @var boolean whether to enable CSRF (Cross-Site Request Forgery) validation. Defaults to false.
  66. * By setting this property to true, forms submitted to an Yii Web application must be originated
  67. * from the same application. If not, a 400 HTTP exception will be raised.
  68. * Note, this feature requires that the user client accepts cookie.
  69. * You also need to use {@link CHtml::form} or {@link CHtml::statefulForm} to generate
  70. * the needed HTML forms in your pages.
  71. * @see http://seclab.stanford.edu/websec/csrf/csrf.pdf
  72. */
  73. public $enableCsrfValidation=false;
  74. /**
  75. * @var string the name of the token used to prevent CSRF. Defaults to 'YII_CSRF_TOKEN'.
  76. * This property is effectively only when {@link enableCsrfValidation} is true.
  77. */
  78. public $csrfTokenName='YII_CSRF_TOKEN';
  79. /**
  80. * @var array the property values (in name-value pairs) used to initialize the CSRF cookie.
  81. * Any property of {@link CHttpCookie} may be initialized.
  82. * This property is effective only when {@link enableCsrfValidation} is true.
  83. */
  84. public $csrfCookie;
  85. private $_requestUri;
  86. private $_pathInfo;
  87. private $_scriptFile;
  88. private $_scriptUrl;
  89. private $_hostInfo;
  90. private $_baseUrl;
  91. private $_cookies;
  92. private $_preferredLanguage;
  93. private $_csrfToken;
  94. private $_deleteParams;
  95. private $_putParams;
  96. /**
  97. * Initializes the application component.
  98. * This method overrides the parent implementation by preprocessing
  99. * the user request data.
  100. */
  101. public function init()
  102. {
  103. parent::init();
  104. $this->normalizeRequest();
  105. }
  106. /**
  107. * Normalizes the request data.
  108. * This method strips off slashes in request data if get_magic_quotes_gpc() returns true.
  109. * It also performs CSRF validation if {@link enableCsrfValidation} is true.
  110. */
  111. protected function normalizeRequest()
  112. {
  113. // normalize request
  114. if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())
  115. {
  116. if(isset($_GET))
  117. $_GET=$this->stripSlashes($_GET);
  118. if(isset($_POST))
  119. $_POST=$this->stripSlashes($_POST);
  120. if(isset($_REQUEST))
  121. $_REQUEST=$this->stripSlashes($_REQUEST);
  122. if(isset($_COOKIE))
  123. $_COOKIE=$this->stripSlashes($_COOKIE);
  124. }
  125. if($this->enableCsrfValidation)
  126. Yii::app()->attachEventHandler('onBeginRequest',array($this,'validateCsrfToken'));
  127. }
  128. /**
  129. * Strips slashes from input data.
  130. * This method is applied when magic quotes is enabled.
  131. * @param mixed $data input data to be processed
  132. * @return mixed processed data
  133. */
  134. public function stripSlashes(&$data)
  135. {
  136. return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
  137. }
  138. /**
  139. * Returns the named GET or POST parameter value.
  140. * If the GET or POST parameter does not exist, the second parameter to this method will be returned.
  141. * If both GET and POST contains such a named parameter, the GET parameter takes precedence.
  142. * @param string $name the GET parameter name
  143. * @param mixed $defaultValue the default parameter value if the GET parameter does not exist.
  144. * @return mixed the GET parameter value
  145. * @see getQuery
  146. * @see getPost
  147. */
  148. public function getParam($name,$defaultValue=null)
  149. {
  150. return isset($_GET[$name]) ? $_GET[$name] : (isset($_POST[$name]) ? $_POST[$name] : $defaultValue);
  151. }
  152. /**
  153. * Returns the named GET parameter value.
  154. * If the GET parameter does not exist, the second parameter to this method will be returned.
  155. * @param string $name the GET parameter name
  156. * @param mixed $defaultValue the default parameter value if the GET parameter does not exist.
  157. * @return mixed the GET parameter value
  158. * @see getPost
  159. * @see getParam
  160. */
  161. public function getQuery($name,$defaultValue=null)
  162. {
  163. return isset($_GET[$name]) ? $_GET[$name] : $defaultValue;
  164. }
  165. /**
  166. * Returns the named POST parameter value.
  167. * If the POST parameter does not exist, the second parameter to this method will be returned.
  168. * @param string $name the POST parameter name
  169. * @param mixed $defaultValue the default parameter value if the POST parameter does not exist.
  170. * @return mixed the POST parameter value
  171. * @see getParam
  172. * @see getQuery
  173. */
  174. public function getPost($name,$defaultValue=null)
  175. {
  176. return isset($_POST[$name]) ? $_POST[$name] : $defaultValue;
  177. }
  178. /**
  179. * Returns the named DELETE parameter value.
  180. * If the DELETE parameter does not exist or if the current request is not a DELETE request,
  181. * the second parameter to this method will be returned.
  182. * @param string $name the DELETE parameter name
  183. * @param mixed $defaultValue the default parameter value if the DELETE parameter does not exist.
  184. * @return mixed the DELETE parameter value
  185. * @since 1.1.7
  186. */
  187. public function getDelete($name,$defaultValue=null)
  188. {
  189. if($this->_deleteParams===null)
  190. $this->_deleteParams=$this->getIsDeleteRequest() ? $this->getRestParams() : array();
  191. return isset($this->_deleteParams[$name]) ? $this->_deleteParams[$name] : $defaultValue;
  192. }
  193. /**
  194. * Returns the named PUT parameter value.
  195. * If the PUT parameter does not exist or if the current request is not a PUT request,
  196. * the second parameter to this method will be returned.
  197. * @param string $name the PUT parameter name
  198. * @param mixed $defaultValue the default parameter value if the PUT parameter does not exist.
  199. * @return mixed the PUT parameter value
  200. * @since 1.1.7
  201. */
  202. public function getPut($name,$defaultValue=null)
  203. {
  204. if($this->_putParams===null)
  205. $this->_putParams=$this->getIsPutRequest() ? $this->getRestParams() : array();
  206. return isset($this->_putParams[$name]) ? $this->_putParams[$name] : $defaultValue;
  207. }
  208. /**
  209. * Returns the PUT or DELETE request parameters.
  210. * @return array the request parameters
  211. * @since 1.1.7
  212. */
  213. protected function getRestParams()
  214. {
  215. $result=array();
  216. if(function_exists('mb_parse_str'))
  217. mb_parse_str(file_get_contents('php://input'), $result);
  218. else
  219. parse_str(file_get_contents('php://input'), $result);
  220. return $result;
  221. }
  222. /**
  223. * Returns the currently requested URL.
  224. * This is the same as {@link getRequestUri}.
  225. * @return string part of the request URL after the host info.
  226. */
  227. public function getUrl()
  228. {
  229. return $this->getRequestUri();
  230. }
  231. /**
  232. * Returns the schema and host part of the application URL.
  233. * The returned URL does not have an ending slash.
  234. * By default this is determined based on the user request information.
  235. * You may explicitly specify it by setting the {@link setHostInfo hostInfo} property.
  236. * @param string $schema schema to use (e.g. http, https). If empty, the schema used for the current request will be used.
  237. * @return string schema and hostname part (with port number if needed) of the request URL (e.g. http://www.yiiframework.com)
  238. * @see setHostInfo
  239. */
  240. public function getHostInfo($schema='')
  241. {
  242. if($this->_hostInfo===null)
  243. {
  244. if($secure=$this->getIsSecureConnection())
  245. $http='https';
  246. else
  247. $http='http';
  248. if(isset($_SERVER['HTTP_HOST']))
  249. $this->_hostInfo=$http.'://'.$_SERVER['HTTP_HOST'];
  250. else
  251. {
  252. $this->_hostInfo=$http.'://'.$_SERVER['SERVER_NAME'];
  253. $port=$secure ? $this->getSecurePort() : $this->getPort();
  254. if(($port!==80 && !$secure) || ($port!==443 && $secure))
  255. $this->_hostInfo.=':'.$port;
  256. }
  257. }
  258. if($schema!=='')
  259. {
  260. $secure=$this->getIsSecureConnection();
  261. if($secure && $schema==='https' || !$secure && $schema==='http')
  262. return $this->_hostInfo;
  263. $port=$schema==='https' ? $this->getSecurePort() : $this->getPort();
  264. if($port!==80 && $schema==='http' || $port!==443 && $schema==='https')
  265. $port=':'.$port;
  266. else
  267. $port='';
  268. $pos=strpos($this->_hostInfo,':');
  269. return $schema.substr($this->_hostInfo,$pos,strcspn($this->_hostInfo,':',$pos+1)+1).$port;
  270. }
  271. else
  272. return $this->_hostInfo;
  273. }
  274. /**
  275. * Sets the schema and host part of the application URL.
  276. * This setter is provided in case the schema and hostname cannot be determined
  277. * on certain Web servers.
  278. * @param string $value the schema and host part of the application URL.
  279. */
  280. public function setHostInfo($value)
  281. {
  282. $this->_hostInfo=rtrim($value,'/');
  283. }
  284. /**
  285. * Returns the relative URL for the application.
  286. * This is similar to {@link getScriptUrl scriptUrl} except that
  287. * it does not have the script file name, and the ending slashes are stripped off.
  288. * @param boolean $absolute whether to return an absolute URL. Defaults to false, meaning returning a relative one.
  289. * @return string the relative URL for the application
  290. * @see setScriptUrl
  291. */
  292. public function getBaseUrl($absolute=false)
  293. {
  294. if($this->_baseUrl===null)
  295. $this->_baseUrl=rtrim(dirname($this->getScriptUrl()),'\\/');
  296. return $absolute ? $this->getHostInfo() . $this->_baseUrl : $this->_baseUrl;
  297. }
  298. /**
  299. * Sets the relative URL for the application.
  300. * By default the URL is determined based on the entry script URL.
  301. * This setter is provided in case you want to change this behavior.
  302. * @param string $value the relative URL for the application
  303. */
  304. public function setBaseUrl($value)
  305. {
  306. $this->_baseUrl=$value;
  307. }
  308. /**
  309. * Returns the relative URL of the entry script.
  310. * The implementation of this method referenced Zend_Controller_Request_Http in Zend Framework.
  311. * @return string the relative URL of the entry script.
  312. */
  313. public function getScriptUrl()
  314. {
  315. if($this->_scriptUrl===null)
  316. {
  317. $scriptName=basename($_SERVER['SCRIPT_FILENAME']);
  318. if(basename($_SERVER['SCRIPT_NAME'])===$scriptName)
  319. $this->_scriptUrl=$_SERVER['SCRIPT_NAME'];
  320. else if(basename($_SERVER['PHP_SELF'])===$scriptName)
  321. $this->_scriptUrl=$_SERVER['PHP_SELF'];
  322. else if(isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME'])===$scriptName)
  323. $this->_scriptUrl=$_SERVER['ORIG_SCRIPT_NAME'];
  324. else if(($pos=strpos($_SERVER['PHP_SELF'],'/'.$scriptName))!==false)
  325. $this->_scriptUrl=substr($_SERVER['SCRIPT_NAME'],0,$pos).'/'.$scriptName;
  326. else if(isset($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['SCRIPT_FILENAME'],$_SERVER['DOCUMENT_ROOT'])===0)
  327. $this->_scriptUrl=str_replace('\\','/',str_replace($_SERVER['DOCUMENT_ROOT'],'',$_SERVER['SCRIPT_FILENAME']));
  328. else
  329. throw new CException(Yii::t('yii','CHttpRequest is unable to determine the entry script URL.'));
  330. }
  331. return $this->_scriptUrl;
  332. }
  333. /**
  334. * Sets the relative URL for the application entry script.
  335. * This setter is provided in case the entry script URL cannot be determined
  336. * on certain Web servers.
  337. * @param string $value the relative URL for the application entry script.
  338. */
  339. public function setScriptUrl($value)
  340. {
  341. $this->_scriptUrl='/'.trim($value,'/');
  342. }
  343. /**
  344. * Returns the path info of the currently requested URL.
  345. * This refers to the part that is after the entry script and before the question mark.
  346. * The starting and ending slashes are stripped off.
  347. * @return string part of the request URL that is after the entry script and before the question mark.
  348. * Note, the returned pathinfo is decoded starting from 1.1.4.
  349. * Prior to 1.1.4, whether it is decoded or not depends on the server configuration
  350. * (in most cases it is not decoded).
  351. * @throws CException if the request URI cannot be determined due to improper server configuration
  352. */
  353. public function getPathInfo()
  354. {
  355. if($this->_pathInfo===null)
  356. {
  357. $pathInfo=$this->getRequestUri();
  358. if(($pos=strpos($pathInfo,'?'))!==false)
  359. $pathInfo=substr($pathInfo,0,$pos);
  360. $pathInfo=$this->decodePathInfo($pathInfo);
  361. $scriptUrl=$this->getScriptUrl();
  362. $baseUrl=$this->getBaseUrl();
  363. if(strpos($pathInfo,$scriptUrl)===0)
  364. $pathInfo=substr($pathInfo,strlen($scriptUrl));
  365. else if($baseUrl==='' || strpos($pathInfo,$baseUrl)===0)
  366. $pathInfo=substr($pathInfo,strlen($baseUrl));
  367. else if(strpos($_SERVER['PHP_SELF'],$scriptUrl)===0)
  368. $pathInfo=substr($_SERVER['PHP_SELF'],strlen($scriptUrl));
  369. else
  370. throw new CException(Yii::t('yii','CHttpRequest is unable to determine the path info of the request.'));
  371. $this->_pathInfo=trim($pathInfo,'/');
  372. }
  373. return $this->_pathInfo;
  374. }
  375. /**
  376. * Decodes the path info.
  377. * This method is an improved variant of the native urldecode() function and used in {@link getPathInfo getPathInfo()} to
  378. * decode the path part of the request URI. You may override this method to change the way the path info is being decoded.
  379. * @param string $pathInfo encoded path info
  380. * @return string decoded path info
  381. * @since 1.1.10
  382. */
  383. protected function decodePathInfo($pathInfo)
  384. {
  385. $pathInfo = urldecode($pathInfo);
  386. // is it UTF-8?
  387. // http://w3.org/International/questions/qa-forms-utf-8.html
  388. if(preg_match('%^(?:
  389. [\x09\x0A\x0D\x20-\x7E] # ASCII
  390. | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
  391. | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
  392. | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
  393. | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
  394. | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
  395. | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
  396. | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
  397. )*$%xs', $pathInfo))
  398. {
  399. return $pathInfo;
  400. }
  401. else
  402. {
  403. return utf8_encode($pathInfo);
  404. }
  405. }
  406. /**
  407. * Returns the request URI portion for the currently requested URL.
  408. * This refers to the portion that is after the {@link hostInfo host info} part.
  409. * It includes the {@link queryString query string} part if any.
  410. * The implementation of this method referenced Zend_Controller_Request_Http in Zend Framework.
  411. * @return string the request URI portion for the currently requested URL.
  412. * @throws CException if the request URI cannot be determined due to improper server configuration
  413. */
  414. public function getRequestUri()
  415. {
  416. if($this->_requestUri===null)
  417. {
  418. if(isset($_SERVER['HTTP_X_REWRITE_URL'])) // IIS
  419. $this->_requestUri=$_SERVER['HTTP_X_REWRITE_URL'];
  420. else if(isset($_SERVER['REQUEST_URI']))
  421. {
  422. $this->_requestUri=$_SERVER['REQUEST_URI'];
  423. if(!empty($_SERVER['HTTP_HOST']))
  424. {
  425. if(strpos($this->_requestUri,$_SERVER['HTTP_HOST'])!==false)
  426. $this->_requestUri=preg_replace('/^\w+:\/\/[^\/]+/','',$this->_requestUri);
  427. }
  428. else
  429. $this->_requestUri=preg_replace('/^(http|https):\/\/[^\/]+/i','',$this->_requestUri);
  430. }
  431. else if(isset($_SERVER['ORIG_PATH_INFO'])) // IIS 5.0 CGI
  432. {
  433. $this->_requestUri=$_SERVER['ORIG_PATH_INFO'];
  434. if(!empty($_SERVER['QUERY_STRING']))
  435. $this->_requestUri.='?'.$_SERVER['QUERY_STRING'];
  436. }
  437. else
  438. throw new CException(Yii::t('yii','CHttpRequest is unable to determine the request URI.'));
  439. }
  440. return $this->_requestUri;
  441. }
  442. /**
  443. * Returns part of the request URL that is after the question mark.
  444. * @return string part of the request URL that is after the question mark
  445. */
  446. public function getQueryString()
  447. {
  448. return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:'';
  449. }
  450. /**
  451. * Return if the request is sent via secure channel (https).
  452. * @return boolean if the request is sent via secure channel (https)
  453. */
  454. public function getIsSecureConnection()
  455. {
  456. return isset($_SERVER['HTTPS']) && !strcasecmp($_SERVER['HTTPS'],'on');
  457. }
  458. /**
  459. * Returns the request type, such as GET, POST, HEAD, PUT, DELETE.
  460. * @return string request type, such as GET, POST, HEAD, PUT, DELETE.
  461. */
  462. public function getRequestType()
  463. {
  464. return strtoupper(isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:'GET');
  465. }
  466. /**
  467. * Returns whether this is a POST request.
  468. * @return boolean whether this is a POST request.
  469. */
  470. public function getIsPostRequest()
  471. {
  472. return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'],'POST');
  473. }
  474. /**
  475. * Returns whether this is a DELETE request.
  476. * @return boolean whether this is a DELETE request.
  477. * @since 1.1.7
  478. */
  479. public function getIsDeleteRequest()
  480. {
  481. return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'],'DELETE');
  482. }
  483. /**
  484. * Returns whether this is a PUT request.
  485. * @return boolean whether this is a PUT request.
  486. * @since 1.1.7
  487. */
  488. public function getIsPutRequest()
  489. {
  490. return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'],'PUT');
  491. }
  492. /**
  493. * Returns whether this is an AJAX (XMLHttpRequest) request.
  494. * @return boolean whether this is an AJAX (XMLHttpRequest) request.
  495. */
  496. public function getIsAjaxRequest()
  497. {
  498. return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest';
  499. }
  500. /**
  501. * Returns the server name.
  502. * @return string server name
  503. */
  504. public function getServerName()
  505. {
  506. return $_SERVER['SERVER_NAME'];
  507. }
  508. /**
  509. * Returns the server port number.
  510. * @return integer server port number
  511. */
  512. public function getServerPort()
  513. {
  514. return $_SERVER['SERVER_PORT'];
  515. }
  516. /**
  517. * Returns the URL referrer, null if not present
  518. * @return string URL referrer, null if not present
  519. */
  520. public function getUrlReferrer()
  521. {
  522. return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
  523. }
  524. /**
  525. * Returns the user agent, null if not present.
  526. * @return string user agent, null if not present
  527. */
  528. public function getUserAgent()
  529. {
  530. return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
  531. }
  532. /**
  533. * Returns the user IP address.
  534. * @return string user IP address
  535. */
  536. public function getUserHostAddress()
  537. {
  538. return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:'127.0.0.1';
  539. }
  540. /**
  541. * Returns the user host name, null if it cannot be determined.
  542. * @return string user host name, null if cannot be determined
  543. */
  544. public function getUserHost()
  545. {
  546. return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
  547. }
  548. /**
  549. * Returns entry script file path.
  550. * @return string entry script file path (processed w/ realpath())
  551. */
  552. public function getScriptFile()
  553. {
  554. if($this->_scriptFile!==null)
  555. return $this->_scriptFile;
  556. else
  557. return $this->_scriptFile=realpath($_SERVER['SCRIPT_FILENAME']);
  558. }
  559. /**
  560. * Returns information about the capabilities of user browser.
  561. * @param string $userAgent the user agent to be analyzed. Defaults to null, meaning using the
  562. * current User-Agent HTTP header information.
  563. * @return array user browser capabilities.
  564. * @see http://www.php.net/manual/en/function.get-browser.php
  565. */
  566. public function getBrowser($userAgent=null)
  567. {
  568. return get_browser($userAgent,true);
  569. }
  570. /**
  571. * Returns user browser accept types, null if not present.
  572. * @return string user browser accept types, null if not present
  573. */
  574. public function getAcceptTypes()
  575. {
  576. return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
  577. }
  578. private $_port;
  579. /**
  580. * Returns the port to use for insecure requests.
  581. * Defaults to 80, or the port specified by the server if the current
  582. * request is insecure.
  583. * You may explicitly specify it by setting the {@link setPort port} property.
  584. * @return integer port number for insecure requests.
  585. * @see setPort
  586. * @since 1.1.3
  587. */
  588. public function getPort()
  589. {
  590. if($this->_port===null)
  591. $this->_port=!$this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 80;
  592. return $this->_port;
  593. }
  594. /**
  595. * Sets the port to use for insecure requests.
  596. * This setter is provided in case a custom port is necessary for certain
  597. * server configurations.
  598. * @param integer $value port number.
  599. * @since 1.1.3
  600. */
  601. public function setPort($value)
  602. {
  603. $this->_port=(int)$value;
  604. $this->_hostInfo=null;
  605. }
  606. private $_securePort;
  607. /**
  608. * Returns the port to use for secure requests.
  609. * Defaults to 443, or the port specified by the server if the current
  610. * request is secure.
  611. * You may explicitly specify it by setting the {@link setSecurePort securePort} property.
  612. * @return integer port number for secure requests.
  613. * @see setSecurePort
  614. * @since 1.1.3
  615. */
  616. public function getSecurePort()
  617. {
  618. if($this->_securePort===null)
  619. $this->_securePort=$this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 443;
  620. return $this->_securePort;
  621. }
  622. /**
  623. * Sets the port to use for secure requests.
  624. * This setter is provided in case a custom port is necessary for certain
  625. * server configurations.
  626. * @param integer $value port number.
  627. * @since 1.1.3
  628. */
  629. public function setSecurePort($value)
  630. {
  631. $this->_securePort=(int)$value;
  632. $this->_hostInfo=null;
  633. }
  634. /**
  635. * Returns the cookie collection.
  636. * The result can be used like an associative array. Adding {@link CHttpCookie} objects
  637. * to the collection will send the cookies to the client; and removing the objects
  638. * from the collection will delete those cookies on the client.
  639. * @return CCookieCollection the cookie collection.
  640. */
  641. public function getCookies()
  642. {
  643. if($this->_cookies!==null)
  644. return $this->_cookies;
  645. else
  646. return $this->_cookies=new CCookieCollection($this);
  647. }
  648. /**
  649. * Redirects the browser to the specified URL.
  650. * @param string $url URL to be redirected to. If the URL is a relative one, the base URL of
  651. * the application will be inserted at the beginning.
  652. * @param boolean $terminate whether to terminate the current application
  653. * @param integer $statusCode the HTTP status code. Defaults to 302. See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html}
  654. * for details about HTTP status code.
  655. */
  656. public function redirect($url,$terminate=true,$statusCode=302)
  657. {
  658. if(strpos($url,'/')===0)
  659. $url=$this->getHostInfo().$url;
  660. header('Location: '.$url, true, $statusCode);
  661. if($terminate)
  662. Yii::app()->end();
  663. }
  664. /**
  665. * Returns the user preferred language.
  666. * The returned language ID will be canonicalized using {@link CLocale::getCanonicalID}.
  667. * This method returns false if the user does not have language preference.
  668. * @return string the user preferred language.
  669. */
  670. public function getPreferredLanguage()
  671. {
  672. if($this->_preferredLanguage===null)
  673. {
  674. if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && ($n=preg_match_all('/([\w\-_]+)\s*(;\s*q\s*=\s*(\d*\.\d*))?/',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches))>0)
  675. {
  676. $languages=array();
  677. for($i=0;$i<$n;++$i)
  678. $languages[$matches[1][$i]]=empty($matches[3][$i]) ? 1.0 : floatval($matches[3][$i]);
  679. arsort($languages);
  680. foreach($languages as $language=>$pref)
  681. return $this->_preferredLanguage=CLocale::getCanonicalID($language);
  682. }
  683. return $this->_preferredLanguage=false;
  684. }
  685. return $this->_preferredLanguage;
  686. }
  687. /**
  688. * Sends a file to user.
  689. * @param string $fileName file name
  690. * @param string $content content to be set.
  691. * @param string $mimeType mime type of the content. If null, it will be guessed automatically based on the given file name.
  692. * @param boolean $terminate whether to terminate the current application after calling this method
  693. */
  694. public function sendFile($fileName,$content,$mimeType=null,$terminate=true)
  695. {
  696. if($mimeType===null)
  697. {
  698. if(($mimeType=CFileHelper::getMimeTypeByExtension($fileName))===null)
  699. $mimeType='text/plain';
  700. }
  701. header('Pragma: public');
  702. header('Expires: 0');
  703. header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
  704. header("Content-type: $mimeType");
  705. if(ob_get_length()===false)
  706. header('Content-Length: '.(function_exists('mb_strlen') ? mb_strlen($content,'8bit') : strlen($content)));
  707. header("Content-Disposition: attachment; filename=\"$fileName\"");
  708. header('Content-Transfer-Encoding: binary');
  709. if($terminate)
  710. {
  711. // clean up the application first because the file downloading could take long time
  712. // which may cause timeout of some resources (such as DB connection)
  713. Yii::app()->end(0,false);
  714. echo $content;
  715. exit(0);
  716. }
  717. else
  718. echo $content;
  719. }
  720. /**
  721. * Sends existing file to a browser as a download using x-sendfile.
  722. *
  723. * X-Sendfile is a feature allowing a web application to redirect the request for a file to the webserver
  724. * that in turn processes the request, this way eliminating the need to perform tasks like reading the file
  725. * and sending it to the user. When dealing with a lot of files (or very big files) this can lead to a great
  726. * increase in performance as the web application is allowed to terminate earlier while the webserver is
  727. * handling the request.
  728. *
  729. * The request is sent to the server through a special non-standard HTTP-header.
  730. * When the web server encounters the presence of such header it will discard all output and send the file
  731. * specified by that header using web server internals including all optimizations like caching-headers.
  732. *
  733. * As this header directive is non-standard different directives exists for different web servers applications:
  734. * <ul>
  735. * <li>Apache: {@link http://tn123.org/mod_xsendfile X-Sendfile}</li>
  736. * <li>Lighttpd v1.4: {@link http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file X-LIGHTTPD-send-file}</li>
  737. * <li>Lighttpd v1.5: {@link http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file X-Sendfile}</li>
  738. * <li>Nginx: {@link http://wiki.nginx.org/XSendfile X-Accel-Redirect}</li>
  739. * <li>Cherokee: {@link http://www.cherokee-project.com/doc/other_goodies.html#x-sendfile X-Sendfile and X-Accel-Redirect}</li>
  740. * </ul>
  741. * So for this method to work the X-SENDFILE option/module should be enabled by the web server and
  742. * a proper xHeader should be sent.
  743. *
  744. * <b>Note:</b>
  745. * This option allows to download files that are not under web folders, and even files that are otherwise protected (deny from all) like .htaccess
  746. *
  747. * <b>Side effects</b>:
  748. * If this option is disabled by the web server, when this method is called a download configuration dialog
  749. * will open but the downloaded file will have 0 bytes.
  750. *
  751. * <b>Example</b>:
  752. * <pre>
  753. * <?php
  754. * Yii::app()->request->xSendFile('/home/user/Pictures/picture1.jpg',array(
  755. * 'saveName'=>'image1.jpg',
  756. * 'mimeType'=>'image/jpeg',
  757. * 'terminate'=>false,
  758. * ));
  759. * ?>
  760. * </pre>
  761. * @param string $filePath file name with full path
  762. * @param array $options additional options:
  763. * <ul>
  764. * <li>saveName: file name shown to the user, if not set real file name will be used</li>
  765. * <li>mimeType: mime type of the file, if not set it will be guessed automatically based on the file name, if set to null no content-type header will be sent.</li>
  766. * <li>xHeader: appropriate x-sendfile header, defaults to "X-Sendfile"</li>
  767. * <li>terminate: whether to terminate the current application after calling this method, defaults to true</li>
  768. * <li>forceDownload: specifies whether the file will be downloaded or shown inline, defaults to true. (Since version 1.1.9.)</li>
  769. * <li>addHeaders: an array of additional http headers in header-value pairs (available since version 1.1.10)</li>
  770. * </ul>
  771. */
  772. public function xSendFile($filePath, $options=array())
  773. {
  774. if(!isset($options['forceDownload']) || $options['forceDownload'])
  775. $disposition='attachment';
  776. else
  777. $disposition='inline';
  778. if(!isset($options['saveName']))
  779. $options['saveName']=basename($filePath);
  780. if(!isset($options['mimeType']))
  781. {
  782. if(($options['mimeType']=CFileHelper::getMimeTypeByExtension($filePath))===null)
  783. $options['mimeType']='text/plain';
  784. }
  785. if(!isset($options['xHeader']))
  786. $options['xHeader']='X-Sendfile';
  787. if($options['mimeType'] !== null)
  788. header('Content-type: '.$options['mimeType']);
  789. header('Content-Disposition: '.$disposition.'; filename="'.$options['saveName'].'"');
  790. if(isset($options['addHeaders']))
  791. {
  792. foreach($options['addHeaders'] as $header=>$value)
  793. header($header.': '.$value);
  794. }
  795. header(trim($options['xHeader']).': '.$filePath);
  796. if(!isset($options['terminate']) || $options['terminate'])
  797. Yii::app()->end();
  798. }
  799. /**
  800. * Returns the random token used to perform CSRF validation.
  801. * The token will be read from cookie first. If not found, a new token
  802. * will be generated.
  803. * @return string the random token for CSRF validation.
  804. * @see enableCsrfValidation
  805. */
  806. public function getCsrfToken()
  807. {
  808. if($this->_csrfToken===null)
  809. {
  810. $cookie=$this->getCookies()->itemAt($this->csrfTokenName);
  811. if(!$cookie || ($this->_csrfToken=$cookie->value)==null)
  812. {
  813. $cookie=$this->createCsrfCookie();
  814. $this->_csrfToken=$cookie->value;
  815. $this->getCookies()->add($cookie->name,$cookie);
  816. }
  817. }
  818. return $this->_csrfToken;
  819. }
  820. /**
  821. * Creates a cookie with a randomly generated CSRF token.
  822. * Initial values specified in {@link csrfCookie} will be applied
  823. * to the generated cookie.
  824. * @return CHttpCookie the generated cookie
  825. * @see enableCsrfValidation
  826. */
  827. protected function createCsrfCookie()
  828. {
  829. $cookie=new CHttpCookie($this->csrfTokenName,sha1(uniqid(mt_rand(),true)));
  830. if(is_array($this->csrfCookie))
  831. {
  832. foreach($this->csrfCookie as $name=>$value)
  833. $cookie->$name=$value;
  834. }
  835. return $cookie;
  836. }
  837. /**
  838. * Performs the CSRF validation.
  839. * This is the event handler responding to {@link CApplication::onBeginRequest}.
  840. * The default implementation will compare the CSRF token obtained
  841. * from a cookie and from a POST field. If they are different, a CSRF attack is detected.
  842. * @param CEvent $event event parameter
  843. * @throws CHttpException if the validation fails
  844. */
  845. public function validateCsrfToken($event)
  846. {
  847. if($this->getIsPostRequest())
  848. {
  849. // only validate POST requests
  850. $cookies=$this->getCookies();
  851. if($cookies->contains($this->csrfTokenName) && isset($_POST[$this->csrfTokenName]))
  852. {
  853. $tokenFromCookie=$cookies->itemAt($this->csrfTokenName)->value;
  854. $tokenFromPost=$_POST[$this->csrfTokenName];
  855. $valid=$tokenFromCookie===$tokenFromPost;
  856. }
  857. else
  858. $valid=false;
  859. if(!$valid)
  860. throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.'));
  861. }
  862. }
  863. }
  864. /**
  865. * CCookieCollection implements a collection class to store cookies.
  866. *
  867. * You normally access it via {@link CHttpRequest::getCookies()}.
  868. *
  869. * Since CCookieCollection extends from {@link CMap}, it can be used
  870. * like an associative array as follows:
  871. * <pre>
  872. * $cookies[$name]=new CHttpCookie($name,$value); // sends a cookie
  873. * $value=$cookies[$name]->value; // reads a cookie value
  874. * unset($cookies[$name]); // removes a cookie
  875. * </pre>
  876. *
  877. * @author Qiang Xue <qiang.xue@gmail.com>
  878. * @version $Id: CHttpRequest.php 242 2012-03-29 15:18:01Z mole1230 $
  879. * @package system.web
  880. * @since 1.0
  881. */
  882. class CCookieCollection extends CMap
  883. {
  884. private $_request;
  885. private $_initialized=false;
  886. /**
  887. * Constructor.
  888. * @param CHttpRequest $request owner of this collection.
  889. */
  890. public function __construct(CHttpRequest $request)
  891. {
  892. $this->_request=$request;
  893. $this->copyfrom($this->getCookies());
  894. $this->_initialized=true;
  895. }
  896. /**
  897. * @return CHttpRequest the request instance
  898. */
  899. public function getRequest()
  900. {
  901. return $this->_request;
  902. }
  903. /**
  904. * @return array list of validated cookies
  905. */
  906. protected function getCookies()
  907. {
  908. $cookies=array();
  909. if($this->_request->enableCookieValidation)
  910. {
  911. $sm=Yii::app()->getSecurityManager();
  912. foreach($_COOKIE as $name=>$value)
  913. {
  914. if(is_string($value) && ($value=$sm->validateData($value))!==false)
  915. $cookies[$name]=new CHttpCookie($name,@unserialize($value));
  916. }
  917. }
  918. else
  919. {
  920. foreach($_COOKIE as $name=>$value)
  921. $cookies[$name]=new CHttpCookie($name,$value);
  922. }
  923. return $cookies;
  924. }
  925. /**
  926. * Adds a cookie with the specified name.
  927. * This overrides the parent implementation by performing additional
  928. * operations for each newly added CHttpCookie object.
  929. * @param mixed $name Cookie name.
  930. * @param CHttpCookie $cookie Cookie object.
  931. * @throws CException if the item to be inserted is not a CHttpCookie object.
  932. */
  933. public function add($name,$cookie)
  934. {
  935. if($cookie instanceof CHttpCookie)
  936. {
  937. $this->remove($name);
  938. parent::add($name,$cookie);
  939. if($this->_initialized)
  940. $this->addCookie($cookie);
  941. }
  942. else
  943. throw new CException(Yii::t('yii','CHttpCookieCollection can only hold CHttpCookie objects.'));
  944. }
  945. /**
  946. * Removes a cookie with the specified name.
  947. * This overrides the parent implementation by performing additional
  948. * cleanup work when removing a CHttpCookie object.
  949. * @param mixed $name Cookie name.
  950. * @return CHttpCookie The removed cookie object.
  951. */
  952. public function remove($name)
  953. {
  954. if(($cookie=parent::remove($name))!==null)
  955. {
  956. if($this->_initialized)
  957. $this->removeCookie($cookie);
  958. }
  959. return $cookie;
  960. }
  961. /**
  962. * Sends a cookie.
  963. * @param CHttpCookie $cookie cookie to be sent
  964. */
  965. protected function addCookie($cookie)
  966. {
  967. $value=$cookie->value;
  968. if($this->_request->enableCookieValidation)
  969. $value=Yii::app()->getSecurityManager()->hashData(serialize($value));
  970. if(version_compare(PHP_VERSION,'5.2.0','>='))
  971. setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly);
  972. else
  973. setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure);
  974. }
  975. /**
  976. * Deletes a cookie.
  977. * @param CHttpCookie $cookie cookie to be deleted
  978. */
  979. protected function removeCookie($cookie)
  980. {
  981. if(version_compare(PHP_VERSION,'5.2.0','>='))
  982. setcookie($cookie->name,null,0,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly);
  983. else
  984. setcookie($cookie->name,null,0,$cookie->path,$cookie->domain,$cookie->secure);
  985. }
  986. }