CWebUser.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. <?php
  2. /**
  3. * CWebUser class file
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright 2008-2013 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CWebUser represents the persistent state for a Web application user.
  12. *
  13. * CWebUser is used as an application component whose ID is 'user'.
  14. * Therefore, at any place one can access the user state via
  15. * <code>Yii::app()->user</code>.
  16. *
  17. * CWebUser should be used together with an {@link IUserIdentity identity}
  18. * which implements the actual authentication algorithm.
  19. *
  20. * A typical authentication process using CWebUser is as follows:
  21. * <ol>
  22. * <li>The user provides information needed for authentication.</li>
  23. * <li>An {@link IUserIdentity identity instance} is created with the user-provided information.</li>
  24. * <li>Call {@link IUserIdentity::authenticate} to check if the identity is valid.</li>
  25. * <li>If valid, call {@link CWebUser::login} to login the user, and
  26. * Redirect the user browser to {@link returnUrl}.</li>
  27. * <li>If not valid, retrieve the error code or message from the identity
  28. * instance and display it.</li>
  29. * </ol>
  30. *
  31. * The property {@link id} and {@link name} are both identifiers
  32. * for the user. The former is mainly used internally (e.g. primary key), while
  33. * the latter is for display purpose (e.g. username). The {@link id} property
  34. * is a unique identifier for a user that is persistent
  35. * during the whole user session. It can be a username, or something else,
  36. * depending on the implementation of the {@link IUserIdentity identity class}.
  37. *
  38. * Both {@link id} and {@link name} are persistent during the user session.
  39. * Besides, an identity may have additional persistent data which can
  40. * be accessed by calling {@link getState}.
  41. * Note, when {@link allowAutoLogin cookie-based authentication} is enabled,
  42. * all these persistent data will be stored in cookie. Therefore, do not
  43. * store password or other sensitive data in the persistent storage. Instead,
  44. * you should store them directly in session on the server side if needed.
  45. *
  46. * @property boolean $isGuest Whether the current application user is a guest.
  47. * @property mixed $id The unique identifier for the user. If null, it means the user is a guest.
  48. * @property string $name The user name. If the user is not logged in, this will be {@link guestName}.
  49. * @property string $returnUrl The URL that the user should be redirected to after login.
  50. * @property string $stateKeyPrefix A prefix for the name of the session variables storing user session data.
  51. * @property array $flashes Flash messages (key => message).
  52. *
  53. * @author Qiang Xue <qiang.xue@gmail.com>
  54. * @package system.web.auth
  55. * @since 1.0
  56. */
  57. class CWebUser extends CApplicationComponent implements IWebUser
  58. {
  59. const FLASH_KEY_PREFIX='Yii.CWebUser.flash.';
  60. const FLASH_COUNTERS='Yii.CWebUser.flashcounters';
  61. const STATES_VAR='__states';
  62. const AUTH_TIMEOUT_VAR='__timeout';
  63. const AUTH_ABSOLUTE_TIMEOUT_VAR='__absolute_timeout';
  64. /**
  65. * @var boolean whether to enable cookie-based login. Defaults to false.
  66. */
  67. public $allowAutoLogin=false;
  68. /**
  69. * @var string the name for a guest user. Defaults to 'Guest'.
  70. * This is used by {@link getName} when the current user is a guest (not authenticated).
  71. */
  72. public $guestName='Guest';
  73. /**
  74. * @var string|array the URL for login. If using array, the first element should be
  75. * the route to the login action, and the rest name-value pairs are GET parameters
  76. * to construct the login URL (e.g. array('/site/login')). If this property is null,
  77. * a 403 HTTP exception will be raised instead.
  78. * @see CController::createUrl
  79. */
  80. public $loginUrl=array('/site/login');
  81. /**
  82. * @var array the property values (in name-value pairs) used to initialize the identity cookie.
  83. * Any property of {@link CHttpCookie} may be initialized.
  84. * This property is effective only when {@link allowAutoLogin} is true.
  85. */
  86. public $identityCookie;
  87. /**
  88. * @var integer timeout in seconds after which user is logged out if inactive.
  89. * If this property is not set, the user will be logged out after the current session expires
  90. * (c.f. {@link CHttpSession::timeout}).
  91. * @since 1.1.7
  92. */
  93. public $authTimeout;
  94. /**
  95. * @var integer timeout in seconds after which user is logged out regardless of activity.
  96. * @since 1.1.14
  97. */
  98. public $absoluteAuthTimeout;
  99. /**
  100. * @var boolean whether to automatically renew the identity cookie each time a page is requested.
  101. * Defaults to false. This property is effective only when {@link allowAutoLogin} is true.
  102. * When this is false, the identity cookie will expire after the specified duration since the user
  103. * is initially logged in. When this is true, the identity cookie will expire after the specified duration
  104. * since the user visits the site the last time.
  105. * @see allowAutoLogin
  106. * @since 1.1.0
  107. */
  108. public $autoRenewCookie=false;
  109. /**
  110. * @var boolean whether to automatically update the validity of flash messages.
  111. * Defaults to true, meaning flash messages will be valid only in the current and the next requests.
  112. * If this is set false, you will be responsible for ensuring a flash message is deleted after usage.
  113. * (This can be achieved by calling {@link getFlash} with the 3rd parameter being true).
  114. * @since 1.1.7
  115. */
  116. public $autoUpdateFlash=true;
  117. /**
  118. * @var string value that will be echoed in case that user session has expired during an ajax call.
  119. * When a request is made and user session has expired, {@link loginRequired} redirects to {@link loginUrl} for login.
  120. * If that happens during an ajax call, the complete HTML login page is returned as the result of that ajax call. That could be
  121. * a problem if the ajax call expects the result to be a json array or a predefined string, as the login page is ignored in that case.
  122. * To solve this, set this property to the desired return value.
  123. *
  124. * If this property is set, this value will be returned as the result of the ajax call in case that the user session has expired.
  125. * @since 1.1.9
  126. * @see loginRequired
  127. */
  128. public $loginRequiredAjaxResponse;
  129. private $_keyPrefix = "session_";
  130. private $_access=array();
  131. /**
  132. * PHP magic method.
  133. * This method is overriden so that persistent states can be accessed like properties.
  134. * @param string $name property name
  135. * @return mixed property value
  136. */
  137. public function __get($name)
  138. {
  139. if($this->hasState($name))
  140. return $this->getState($name);
  141. else
  142. return parent::__get($name);
  143. }
  144. /**
  145. * PHP magic method.
  146. * This method is overriden so that persistent states can be set like properties.
  147. * @param string $name property name
  148. * @param mixed $value property value
  149. */
  150. public function __set($name,$value)
  151. {
  152. if($this->hasState($name))
  153. $this->setState($name,$value);
  154. else
  155. parent::__set($name,$value);
  156. }
  157. /**
  158. * PHP magic method.
  159. * This method is overriden so that persistent states can also be checked for null value.
  160. * @param string $name property name
  161. * @return boolean
  162. */
  163. public function __isset($name)
  164. {
  165. if($this->hasState($name))
  166. return $this->getState($name)!==null;
  167. else
  168. return parent::__isset($name);
  169. }
  170. /**
  171. * PHP magic method.
  172. * This method is overriden so that persistent states can also be unset.
  173. * @param string $name property name
  174. * @throws CException if the property is read only.
  175. */
  176. public function __unset($name)
  177. {
  178. if($this->hasState($name))
  179. $this->setState($name,null);
  180. else
  181. parent::__unset($name);
  182. }
  183. /**
  184. * Initializes the application component.
  185. * This method overrides the parent implementation by starting session,
  186. * performing cookie-based authentication if enabled, and updating the flash variables.
  187. */
  188. public function init()
  189. {
  190. parent::init();
  191. Yii::app()->getSession()->open();
  192. if($this->getIsGuest() && $this->allowAutoLogin)
  193. $this->restoreFromCookie();
  194. elseif($this->autoRenewCookie && $this->allowAutoLogin)
  195. $this->renewCookie();
  196. if($this->autoUpdateFlash)
  197. $this->updateFlash();
  198. $this->updateAuthStatus();
  199. }
  200. /**
  201. * Logs in a user.
  202. *
  203. * The user identity information will be saved in storage that is
  204. * persistent during the user session. By default, the storage is simply
  205. * the session storage. If the duration parameter is greater than 0,
  206. * a cookie will be sent to prepare for cookie-based login in future.
  207. *
  208. * Note, you have to set {@link allowAutoLogin} to true
  209. * if you want to allow user to be authenticated based on the cookie information.
  210. *
  211. * @param IUserIdentity $identity the user identity (which should already be authenticated)
  212. * @param integer $duration number of seconds that the user can remain in logged-in status. Defaults to 0, meaning login till the user closes the browser.
  213. * If greater than 0, cookie-based login will be used. In this case, {@link allowAutoLogin}
  214. * must be set true, otherwise an exception will be thrown.
  215. * @return boolean whether the user is logged in
  216. */
  217. public function login($identity,$duration=0)
  218. {
  219. $id=$identity->getId();
  220. $states=$identity->getPersistentStates();
  221. if($this->beforeLogin($id,$states,false))
  222. {
  223. $this->changeIdentity($id,$identity->getName(),$states);
  224. if($duration>0)
  225. {
  226. if($this->allowAutoLogin)
  227. $this->saveToCookie($duration);
  228. else
  229. throw new CException(Yii::t('yii','{class}.allowAutoLogin must be set true in order to use cookie-based authentication.',
  230. array('{class}'=>get_class($this))));
  231. }
  232. if ($this->absoluteAuthTimeout)
  233. $this->setState(self::AUTH_ABSOLUTE_TIMEOUT_VAR, time()+$this->absoluteAuthTimeout);
  234. $this->afterLogin(false);
  235. }
  236. return !$this->getIsGuest();
  237. }
  238. /**
  239. * Logs out the current user.
  240. * This will remove authentication-related session data.
  241. * If the parameter is true, the whole session will be destroyed as well.
  242. * @param boolean $destroySession whether to destroy the whole session. Defaults to true. If false,
  243. * then {@link clearStates} will be called, which removes only the data stored via {@link setState}.
  244. */
  245. public function logout($destroySession=true)
  246. {
  247. if($this->beforeLogout())
  248. {
  249. if($this->allowAutoLogin)
  250. {
  251. Yii::app()->getRequest()->getCookies()->remove($this->getStateKeyPrefix());
  252. if($this->identityCookie!==null)
  253. {
  254. $cookie=$this->createIdentityCookie($this->getStateKeyPrefix());
  255. $cookie->value=null;
  256. $cookie->expire=0;
  257. Yii::app()->getRequest()->getCookies()->add($cookie->name,$cookie);
  258. }
  259. }
  260. if($destroySession)
  261. Yii::app()->getSession()->destroy();
  262. else
  263. $this->clearStates();
  264. $this->_access=array();
  265. $this->afterLogout();
  266. }
  267. }
  268. /**
  269. * Returns a value indicating whether the user is a guest (not authenticated).
  270. * @return boolean whether the current application user is a guest.
  271. */
  272. public function getIsGuest()
  273. {
  274. return $this->getState('__id')===null;
  275. }
  276. /**
  277. * Returns a value that uniquely represents the user.
  278. * @return mixed the unique identifier for the user. If null, it means the user is a guest.
  279. */
  280. public function getId()
  281. {
  282. return $this->getState('__id');
  283. }
  284. /**
  285. * @param mixed $value the unique identifier for the user. If null, it means the user is a guest.
  286. */
  287. public function setId($value)
  288. {
  289. $this->setState('__id',$value);
  290. }
  291. /**
  292. * Returns the unique identifier for the user (e.g. username).
  293. * This is the unique identifier that is mainly used for display purpose.
  294. * @return string the user name. If the user is not logged in, this will be {@link guestName}.
  295. */
  296. public function getName()
  297. {
  298. if(($name=$this->getState('__name'))!==null)
  299. return $name;
  300. else
  301. return $this->guestName;
  302. }
  303. /**
  304. * Sets the unique identifier for the user (e.g. username).
  305. * @param string $value the user name.
  306. * @see getName
  307. */
  308. public function setName($value)
  309. {
  310. $this->setState('__name',$value);
  311. }
  312. /**
  313. * Returns the URL that the user should be redirected to after successful login.
  314. * This property is usually used by the login action. If the login is successful,
  315. * the action should read this property and use it to redirect the user browser.
  316. * @param string $defaultUrl the default return URL in case it was not set previously. If this is null,
  317. * the application entry URL will be considered as the default return URL.
  318. * @return string the URL that the user should be redirected to after login.
  319. * @see loginRequired
  320. */
  321. public function getReturnUrl($defaultUrl=null)
  322. {
  323. if($defaultUrl===null)
  324. {
  325. $defaultReturnUrl=Yii::app()->getUrlManager()->showScriptName ? Yii::app()->getRequest()->getScriptUrl() : Yii::app()->getRequest()->getBaseUrl().'/';
  326. }
  327. else
  328. {
  329. $defaultReturnUrl=CHtml::normalizeUrl($defaultUrl);
  330. }
  331. return $this->getState('__returnUrl',$defaultReturnUrl);
  332. }
  333. /**
  334. * @param string $value the URL that the user should be redirected to after login.
  335. */
  336. public function setReturnUrl($value)
  337. {
  338. $this->setState('__returnUrl',$value);
  339. }
  340. /**
  341. * Redirects the user browser to the login page.
  342. * Before the redirection, the current URL (if it's not an AJAX url) will be
  343. * kept in {@link returnUrl} so that the user browser may be redirected back
  344. * to the current page after successful login. Make sure you set {@link loginUrl}
  345. * so that the user browser can be redirected to the specified login URL after
  346. * calling this method.
  347. * After calling this method, the current request processing will be terminated.
  348. */
  349. public function loginRequired()
  350. {
  351. $app=Yii::app();
  352. $request=$app->getRequest();
  353. if(!$request->getIsAjaxRequest())
  354. {
  355. $this->setReturnUrl($request->getUrl());
  356. if(($url=$this->loginUrl)!==null)
  357. {
  358. if(is_array($url))
  359. {
  360. $route=isset($url[0]) ? $url[0] : $app->defaultController;
  361. $url=$app->createUrl($route,array_splice($url,1));
  362. }
  363. $request->redirect($url);
  364. }
  365. }
  366. elseif(isset($this->loginRequiredAjaxResponse))
  367. {
  368. echo $this->loginRequiredAjaxResponse;
  369. Yii::app()->end();
  370. }
  371. throw new CHttpException(403,Yii::t('yii','Login Required'));
  372. }
  373. /**
  374. * This method is called before logging in a user.
  375. * You may override this method to provide additional security check.
  376. * For example, when the login is cookie-based, you may want to verify
  377. * that the user ID together with a random token in the states can be found
  378. * in the database. This will prevent hackers from faking arbitrary
  379. * identity cookies even if they crack down the server private key.
  380. * @param mixed $id the user ID. This is the same as returned by {@link getId()}.
  381. * @param array $states a set of name-value pairs that are provided by the user identity.
  382. * @param boolean $fromCookie whether the login is based on cookie
  383. * @return boolean whether the user should be logged in
  384. * @since 1.1.3
  385. */
  386. protected function beforeLogin($id,$states,$fromCookie)
  387. {
  388. return true;
  389. }
  390. /**
  391. * This method is called after the user is successfully logged in.
  392. * You may override this method to do some postprocessing (e.g. log the user
  393. * login IP and time; load the user permission information).
  394. * @param boolean $fromCookie whether the login is based on cookie.
  395. * @since 1.1.3
  396. */
  397. protected function afterLogin($fromCookie)
  398. {
  399. }
  400. /**
  401. * This method is invoked when calling {@link logout} to log out a user.
  402. * If this method return false, the logout action will be cancelled.
  403. * You may override this method to provide additional check before
  404. * logging out a user.
  405. * @return boolean whether to log out the user
  406. * @since 1.1.3
  407. */
  408. protected function beforeLogout()
  409. {
  410. return true;
  411. }
  412. /**
  413. * This method is invoked right after a user is logged out.
  414. * You may override this method to do some extra cleanup work for the user.
  415. * @since 1.1.3
  416. */
  417. protected function afterLogout()
  418. {
  419. }
  420. /**
  421. * Populates the current user object with the information obtained from cookie.
  422. * This method is used when automatic login ({@link allowAutoLogin}) is enabled.
  423. * The user identity information is recovered from cookie.
  424. * Sufficient security measures are used to prevent cookie data from being tampered.
  425. * @see saveToCookie
  426. */
  427. protected function restoreFromCookie()
  428. {
  429. $app=Yii::app();
  430. $request=$app->getRequest();
  431. $cookie=$request->getCookies()->itemAt($this->getStateKeyPrefix());
  432. if($cookie && !empty($cookie->value) && is_string($cookie->value) && ($data=$app->getSecurityManager()->validateData($cookie->value))!==false)
  433. {
  434. $data=@unserialize($data);
  435. if(is_array($data) && isset($data[0],$data[1],$data[2],$data[3]))
  436. {
  437. list($id,$name,$duration,$states)=$data;
  438. if($this->beforeLogin($id,$states,true))
  439. {
  440. $this->changeIdentity($id,$name,$states);
  441. if($this->autoRenewCookie)
  442. {
  443. $this->saveToCookie($duration);
  444. }
  445. $this->afterLogin(true);
  446. }
  447. }
  448. }
  449. }
  450. /**
  451. * Renews the identity cookie.
  452. * This method will set the expiration time of the identity cookie to be the current time
  453. * plus the originally specified cookie duration.
  454. * @since 1.1.3
  455. */
  456. protected function renewCookie()
  457. {
  458. $request=Yii::app()->getRequest();
  459. $cookies=$request->getCookies();
  460. $cookie=$cookies->itemAt($this->getStateKeyPrefix());
  461. if($cookie && !empty($cookie->value) && ($data=Yii::app()->getSecurityManager()->validateData($cookie->value))!==false)
  462. {
  463. $data=@unserialize($data);
  464. if(is_array($data) && isset($data[0],$data[1],$data[2],$data[3]))
  465. {
  466. $this->saveToCookie($data[2]);
  467. }
  468. }
  469. }
  470. /**
  471. * Saves necessary user data into a cookie.
  472. * This method is used when automatic login ({@link allowAutoLogin}) is enabled.
  473. * This method saves user ID, username, other identity states and a validation key to cookie.
  474. * These information are used to do authentication next time when user visits the application.
  475. * @param integer $duration number of seconds that the user can remain in logged-in status. Defaults to 0, meaning login till the user closes the browser.
  476. * @see restoreFromCookie
  477. */
  478. protected function saveToCookie($duration)
  479. {
  480. $app=Yii::app();
  481. $cookie=$this->createIdentityCookie($this->getStateKeyPrefix());
  482. $cookie->expire=time()+$duration;
  483. $data=array(
  484. $this->getId(),
  485. $this->getName(),
  486. $duration,
  487. $this->saveIdentityStates(),
  488. );
  489. $cookie->value=$app->getSecurityManager()->hashData(serialize($data));
  490. $app->getRequest()->getCookies()->add($cookie->name,$cookie);
  491. }
  492. /**
  493. * Creates a cookie to store identity information.
  494. * @param string $name the cookie name
  495. * @return CHttpCookie the cookie used to store identity information
  496. */
  497. protected function createIdentityCookie($name)
  498. {
  499. $cookie=new CHttpCookie($name,'');
  500. if(is_array($this->identityCookie))
  501. {
  502. foreach($this->identityCookie as $name=>$value)
  503. $cookie->$name=$value;
  504. }
  505. return $cookie;
  506. }
  507. /**
  508. * @return string a prefix for the name of the session variables storing user session data.
  509. */
  510. public function getStateKeyPrefix()
  511. {
  512. if($this->_keyPrefix!==null)
  513. return $this->_keyPrefix;
  514. else
  515. return $this->_keyPrefix=md5('Yii.'.get_class($this).'.'.Yii::app()->getId());
  516. }
  517. /**
  518. * @param string $value a prefix for the name of the session variables storing user session data.
  519. */
  520. public function setStateKeyPrefix($value)
  521. {
  522. $this->_keyPrefix=$value;
  523. }
  524. /**
  525. * Returns the value of a variable that is stored in user session.
  526. *
  527. * This function is designed to be used by CWebUser descendant classes
  528. * who want to store additional user information in user session.
  529. * A variable, if stored in user session using {@link setState} can be
  530. * retrieved back using this function.
  531. *
  532. * @param string $key variable name
  533. * @param mixed $defaultValue default value
  534. * @return mixed the value of the variable. If it doesn't exist in the session,
  535. * the provided default value will be returned
  536. * @see setState
  537. */
  538. public function getState($key,$defaultValue=null)
  539. {
  540. $key=$this->getStateKeyPrefix().$key;
  541. return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue;
  542. }
  543. /**
  544. * Stores a variable in user session.
  545. *
  546. * This function is designed to be used by CWebUser descendant classes
  547. * who want to store additional user information in user session.
  548. * By storing a variable using this function, the variable may be retrieved
  549. * back later using {@link getState}. The variable will be persistent
  550. * across page requests during a user session.
  551. *
  552. * @param string $key variable name
  553. * @param mixed $value variable value
  554. * @param mixed $defaultValue default value. If $value===$defaultValue, the variable will be
  555. * removed from the session
  556. * @see getState
  557. */
  558. public function setState($key,$value,$defaultValue=null)
  559. {
  560. $key=$this->getStateKeyPrefix().$key;
  561. if($value===$defaultValue)
  562. unset($_SESSION[$key]);
  563. else
  564. $_SESSION[$key]=$value;
  565. }
  566. /**
  567. * Returns a value indicating whether there is a state of the specified name.
  568. * @param string $key state name
  569. * @return boolean whether there is a state of the specified name.
  570. */
  571. public function hasState($key)
  572. {
  573. $key=$this->getStateKeyPrefix().$key;
  574. return isset($_SESSION[$key]);
  575. }
  576. /**
  577. * Clears all user identity information from persistent storage.
  578. * This will remove the data stored via {@link setState}.
  579. */
  580. public function clearStates()
  581. {
  582. $keys=array_keys($_SESSION);
  583. $prefix=$this->getStateKeyPrefix();
  584. $n=strlen($prefix);
  585. foreach($keys as $key)
  586. {
  587. if(!strncmp($key,$prefix,$n))
  588. unset($_SESSION[$key]);
  589. }
  590. }
  591. /**
  592. * Returns all flash messages.
  593. * This method is similar to {@link getFlash} except that it returns all
  594. * currently available flash messages.
  595. * @param boolean $delete whether to delete the flash messages after calling this method.
  596. * @return array flash messages (key => message).
  597. * @since 1.1.3
  598. */
  599. public function getFlashes($delete=true)
  600. {
  601. $flashes=array();
  602. $prefix=$this->getStateKeyPrefix().self::FLASH_KEY_PREFIX;
  603. $keys=array_keys($_SESSION);
  604. $n=strlen($prefix);
  605. foreach($keys as $key)
  606. {
  607. if(!strncmp($key,$prefix,$n))
  608. {
  609. $flashes[substr($key,$n)]=$_SESSION[$key];
  610. if($delete)
  611. unset($_SESSION[$key]);
  612. }
  613. }
  614. if($delete)
  615. $this->setState(self::FLASH_COUNTERS,array());
  616. return $flashes;
  617. }
  618. /**
  619. * Returns a flash message.
  620. * A flash message is available only in the current and the next requests.
  621. * @param string $key key identifying the flash message
  622. * @param mixed $defaultValue value to be returned if the flash message is not available.
  623. * @param boolean $delete whether to delete this flash message after accessing it.
  624. * Defaults to true.
  625. * @return mixed the message message
  626. */
  627. public function getFlash($key,$defaultValue=null,$delete=true)
  628. {
  629. $value=$this->getState(self::FLASH_KEY_PREFIX.$key,$defaultValue);
  630. if($delete)
  631. $this->setFlash($key,null);
  632. return $value;
  633. }
  634. /**
  635. * Stores a flash message.
  636. * A flash message is available only in the current and the next requests.
  637. * @param string $key key identifying the flash message
  638. * @param mixed $value flash message
  639. * @param mixed $defaultValue if this value is the same as the flash message, the flash message
  640. * will be removed. (Therefore, you can use setFlash('key',null) to remove a flash message.)
  641. */
  642. public function setFlash($key,$value,$defaultValue=null)
  643. {
  644. $this->setState(self::FLASH_KEY_PREFIX.$key,$value,$defaultValue);
  645. $counters=$this->getState(self::FLASH_COUNTERS,array());
  646. if($value===$defaultValue)
  647. unset($counters[$key]);
  648. else
  649. $counters[$key]=0;
  650. $this->setState(self::FLASH_COUNTERS,$counters,array());
  651. }
  652. /**
  653. * @param string $key key identifying the flash message
  654. * @return boolean whether the specified flash message exists
  655. */
  656. public function hasFlash($key)
  657. {
  658. return $this->getFlash($key, null, false)!==null;
  659. }
  660. /**
  661. * Changes the current user with the specified identity information.
  662. * This method is called by {@link login} and {@link restoreFromCookie}
  663. * when the current user needs to be populated with the corresponding
  664. * identity information. Derived classes may override this method
  665. * by retrieving additional user-related information. Make sure the
  666. * parent implementation is called first.
  667. * @param mixed $id a unique identifier for the user
  668. * @param string $name the display name for the user
  669. * @param array $states identity states
  670. */
  671. protected function changeIdentity($id,$name,$states)
  672. {
  673. Yii::app()->getSession()->regenerateID(true);
  674. $this->setId($id);
  675. $this->setName($name);
  676. $this->loadIdentityStates($states);
  677. }
  678. /**
  679. * Retrieves identity states from persistent storage and saves them as an array.
  680. * @return array the identity states
  681. */
  682. protected function saveIdentityStates()
  683. {
  684. $states=array();
  685. foreach($this->getState(self::STATES_VAR,array()) as $name=>$dummy)
  686. $states[$name]=$this->getState($name);
  687. return $states;
  688. }
  689. /**
  690. * Loads identity states from an array and saves them to persistent storage.
  691. * @param array $states the identity states
  692. */
  693. protected function loadIdentityStates($states)
  694. {
  695. $names=array();
  696. if(is_array($states))
  697. {
  698. foreach($states as $name=>$value)
  699. {
  700. $this->setState($name,$value);
  701. $names[$name]=true;
  702. }
  703. }
  704. $this->setState(self::STATES_VAR,$names);
  705. }
  706. /**
  707. * Updates the internal counters for flash messages.
  708. * This method is internally used by {@link CWebApplication}
  709. * to maintain the availability of flash messages.
  710. */
  711. protected function updateFlash()
  712. {
  713. $counters=$this->getState(self::FLASH_COUNTERS);
  714. if(!is_array($counters))
  715. return;
  716. foreach($counters as $key=>$count)
  717. {
  718. if($count)
  719. {
  720. unset($counters[$key]);
  721. $this->setState(self::FLASH_KEY_PREFIX.$key,null);
  722. }
  723. else
  724. $counters[$key]++;
  725. }
  726. $this->setState(self::FLASH_COUNTERS,$counters,array());
  727. }
  728. /**
  729. * Updates the authentication status according to {@link authTimeout}.
  730. * If the user has been inactive for {@link authTimeout} seconds, or {link absoluteAuthTimeout} has passed,
  731. * he will be automatically logged out.
  732. * @since 1.1.7
  733. */
  734. protected function updateAuthStatus()
  735. {
  736. if(($this->authTimeout!==null || $this->absoluteAuthTimeout!==null) && !$this->getIsGuest())
  737. {
  738. $expires=$this->getState(self::AUTH_TIMEOUT_VAR);
  739. $expiresAbsolute=$this->getState(self::AUTH_ABSOLUTE_TIMEOUT_VAR);
  740. if ($expires!==null && $expires < time() || $expiresAbsolute!==null && $expiresAbsolute < time())
  741. $this->logout(false);
  742. else
  743. $this->setState(self::AUTH_TIMEOUT_VAR,time()+$this->authTimeout);
  744. }
  745. }
  746. /**
  747. * Performs access check for this user.
  748. * @param string $operation the name of the operation that need access check.
  749. * @param array $params name-value pairs that would be passed to business rules associated
  750. * with the tasks and roles assigned to the user.
  751. * Since version 1.1.11 a param with name 'userId' is added to this array, which holds the value of
  752. * {@link getId()} when {@link CDbAuthManager} or {@link CPhpAuthManager} is used.
  753. * @param boolean $allowCaching whether to allow caching the result of access check.
  754. * When this parameter
  755. * is true (default), if the access check of an operation was performed before,
  756. * its result will be directly returned when calling this method to check the same operation.
  757. * If this parameter is false, this method will always call {@link CAuthManager::checkAccess}
  758. * to obtain the up-to-date access result. Note that this caching is effective
  759. * only within the same request and only works when <code>$params=array()</code>.
  760. * @return boolean whether the operations can be performed by this user.
  761. */
  762. public function checkAccess($operation,$params=array(),$allowCaching=true)
  763. {
  764. if($allowCaching && $params===array() && isset($this->_access[$operation]))
  765. return $this->_access[$operation];
  766. $access=Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params);
  767. if($allowCaching && $params===array())
  768. $this->_access[$operation]=$access;
  769. return $access;
  770. }
  771. }