PageRenderTime 56ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/kernel/classes/datatypes/ezuser/ezuser.php

http://github.com/ezsystems/ezpublish
PHP | 3017 lines | 2105 code | 284 blank | 628 comment | 302 complexity | 70d862ef20eea16617361d07d2bff458 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * File containing the eZUser class.
  4. *
  5. * @copyright Copyright (C) eZ Systems AS. All rights reserved.
  6. * @license For full copyright and license information view LICENSE file distributed with this source code.
  7. * @version //autogentag//
  8. * @package kernel
  9. */
  10. /*!
  11. \class eZUser ezuser.php
  12. \brief eZUser handles eZ Publish user accounts
  13. \ingroup eZDatatype
  14. */
  15. class eZUser extends eZPersistentObject
  16. {
  17. /// No hash, used by external handlers such as LDAP and TextFile
  18. const PASSWORD_HASH_EMPTY = 0;
  19. /// MD5 of password
  20. const PASSWORD_HASH_MD5_PASSWORD = 1;
  21. /// MD5 of user and password
  22. const PASSWORD_HASH_MD5_USER = 2;
  23. /// MD5 of site, user and password
  24. const PASSWORD_HASH_MD5_SITE = 3;
  25. /// Legacy support for mysql hashed passwords
  26. /// NB! Does not work as of MySQL 8.0 where this has been removed from MySQL.
  27. const PASSWORD_HASH_MYSQL = 4;
  28. /// Passwords in plaintext, should not be used for real sites
  29. const PASSWORD_HASH_PLAINTEXT = 5;
  30. /// Passwords in bcrypt format
  31. const PASSWORD_HASH_BCRYPT = 6;
  32. /// Passwords in PHP default format
  33. const PASSWORD_HASH_PHP_DEFAULT = 7;
  34. /// Default password hashing algorithm, used in case of invalid configuration or usage.
  35. /// Update this if support for better algorithms is added.
  36. const DEFAULT_PASSWORD_HASH = self::PASSWORD_HASH_PHP_DEFAULT;
  37. /**
  38. * Max length allowed for a login or a password
  39. *
  40. * @var string
  41. */
  42. const AUTH_STRING_MAX_LENGTH = 4096;
  43. /// Authenticate by matching the login field
  44. const AUTHENTICATE_LOGIN = 1;
  45. /// Authenticate by matching the email field
  46. const AUTHENTICATE_EMAIL = 2;
  47. const AUTHENTICATE_ALL = 3; //EZ_USER_AUTHENTICATE_LOGIN | EZ_USER_AUTHENTICATE_EMAIL;
  48. /**
  49. * Flag used to prevent session regeneration
  50. *
  51. * @var int
  52. * @see eZUser::setCurrentlyLoggedInUser()
  53. */
  54. const NO_SESSION_REGENERATE = 1;
  55. protected static $anonymousId = null;
  56. public function __construct( $row = array() )
  57. {
  58. parent::__construct( $row );
  59. $this->OriginalPassword = false;
  60. $this->OriginalPasswordConfirm = false;
  61. }
  62. /**
  63. * @deprecated Use eZUser::__construct() instead
  64. * @param array $row
  65. */
  66. function eZUser( $row = array() )
  67. {
  68. self::__construct( $row );
  69. }
  70. static function definition()
  71. {
  72. static $definition = array( 'fields' => array( 'contentobject_id' => array( 'name' => 'ContentObjectID',
  73. 'datatype' => 'integer',
  74. 'default' => 0,
  75. 'required' => true,
  76. 'foreign_class' => 'eZContentObject',
  77. 'foreign_attribute' => 'id',
  78. 'multiplicity' => '0..1' ),
  79. 'login' => array( 'name' => 'Login',
  80. 'datatype' => 'string',
  81. 'default' => '',
  82. 'required' => true ),
  83. 'email' => array( 'name' => 'Email',
  84. 'datatype' => 'string',
  85. 'default' => '',
  86. 'required' => true ),
  87. 'password_hash' => array( 'name' => 'PasswordHash',
  88. 'datatype' => 'string',
  89. 'default' => '',
  90. 'required' => true ),
  91. 'password_hash_type' => array( 'name' => 'PasswordHashType',
  92. 'datatype' => 'integer',
  93. 'default' => 1,
  94. 'required' => true ) ),
  95. 'keys' => array( 'contentobject_id' ),
  96. 'sort' => array( 'contentobject_id' => 'asc' ),
  97. 'function_attributes' => array( 'contentobject' => 'contentObject',
  98. 'account_key' => 'accountKey',
  99. 'groups' => 'groups',
  100. 'has_stored_login' => 'hasStoredLogin',
  101. 'original_password' => 'originalPassword',
  102. 'original_password_confirm' => 'originalPasswordConfirm',
  103. 'roles' => 'roles',
  104. 'role_id_list' => 'roleIDList',
  105. 'limited_assignment_value_list' => 'limitValueList',
  106. 'is_logged_in' => 'isRegistered',
  107. 'is_enabled' => 'isEnabled',
  108. 'is_locked' => 'isLocked',
  109. 'last_visit' => 'lastVisit',
  110. 'login_count' => 'loginCount',
  111. 'has_manage_locations' => 'hasManageLocations' ),
  112. 'relations' => array( 'contentobject_id' => array( 'class' => 'ezcontentobject',
  113. 'field' => 'id' ) ),
  114. 'class_name' => 'eZUser',
  115. 'name' => 'ezuser' );
  116. return $definition;
  117. }
  118. /*!
  119. \return a textual identifier for the hash type $id
  120. */
  121. static function passwordHashTypeName( $id )
  122. {
  123. switch ( $id )
  124. {
  125. case self::PASSWORD_HASH_EMPTY:
  126. {
  127. return 'empty';
  128. } break;
  129. case self::PASSWORD_HASH_MD5_PASSWORD:
  130. {
  131. return 'md5_password';
  132. } break;
  133. case self::PASSWORD_HASH_MD5_USER:
  134. {
  135. return 'md5_user';
  136. } break;
  137. case self::PASSWORD_HASH_MD5_SITE:
  138. {
  139. return 'md5_site';
  140. } break;
  141. case self::PASSWORD_HASH_MYSQL:
  142. {
  143. return 'mysql';
  144. } break;
  145. case self::PASSWORD_HASH_PLAINTEXT:
  146. {
  147. return 'plaintext';
  148. } break;
  149. case self::PASSWORD_HASH_BCRYPT:
  150. {
  151. return 'bcrypt';
  152. } break;
  153. case self::PASSWORD_HASH_PHP_DEFAULT:
  154. {
  155. return 'php_default';
  156. } break;
  157. }
  158. }
  159. /*!
  160. \return the hash type for the textual identifier $identifier
  161. */
  162. static function passwordHashTypeID( $identifier )
  163. {
  164. switch ( $identifier )
  165. {
  166. case 'empty':
  167. {
  168. return self::PASSWORD_HASH_EMPTY;
  169. } break;
  170. case 'md5_password':
  171. {
  172. return self::PASSWORD_HASH_MD5_PASSWORD;
  173. } break;
  174. case 'md5_user':
  175. {
  176. return self::PASSWORD_HASH_MD5_USER;
  177. } break;
  178. case 'md5_site':
  179. {
  180. return self::PASSWORD_HASH_MD5_SITE;
  181. } break;
  182. case 'mysql':
  183. {
  184. return self::PASSWORD_HASH_MYSQL;
  185. } break;
  186. case 'plaintext':
  187. {
  188. return self::PASSWORD_HASH_PLAINTEXT;
  189. } break;
  190. case 'bcrypt':
  191. {
  192. return self::PASSWORD_HASH_BCRYPT;
  193. } break;
  194. case 'php_default':
  195. {
  196. return self::PASSWORD_HASH_PHP_DEFAULT;
  197. } break;
  198. default:
  199. {
  200. eZDebug::writeError( "Password hash type identifier '$identifier' is not recognized. " .
  201. 'Check the site.ini [UserSettings] HashType setting. ' .
  202. 'Defaulting to ' . self::passwordHashTypeName( self::DEFAULT_PASSWORD_HASH ) );
  203. return self::DEFAULT_PASSWORD_HASH;
  204. }
  205. }
  206. }
  207. /*!
  208. Check if current user has "content/manage_locations" access
  209. */
  210. function hasManageLocations()
  211. {
  212. $accessResult = $this->hasAccessTo( 'content', 'manage_locations' );
  213. if ( $accessResult['accessWord'] != 'no' )
  214. {
  215. return true;
  216. }
  217. return false;
  218. }
  219. static function create( $contentObjectID )
  220. {
  221. $row = array(
  222. 'contentobject_id' => $contentObjectID,
  223. 'login' => null,
  224. 'email' => null,
  225. 'password_hash' => null,
  226. 'password_hash_type' => null
  227. );
  228. return new eZUser( $row );
  229. }
  230. /**
  231. * Only stores the entry if it has a Login value
  232. *
  233. * @param mixed|null $fieldFilters
  234. */
  235. public function store( $fieldFilters = null )
  236. {
  237. $this->Email = trim( $this->Email );
  238. $userID = $this->attribute( 'contentobject_id' );
  239. // Clear memory cache
  240. unset( $GLOBALS['eZUserObject_' . $userID] );
  241. $GLOBALS['eZUserObject_' . $userID] = $this;
  242. self::purgeUserCacheByUserId( $userID );
  243. if ( $this->Login )
  244. {
  245. parent::store( $fieldFilters );
  246. }
  247. }
  248. function originalPassword()
  249. {
  250. return $this->OriginalPassword;
  251. }
  252. function setOriginalPassword( $password )
  253. {
  254. $this->OriginalPassword = $password;
  255. }
  256. function originalPasswordConfirm()
  257. {
  258. return $this->OriginalPasswordConfirm;
  259. }
  260. function setOriginalPasswordConfirm( $password )
  261. {
  262. $this->OriginalPasswordConfirm = $password;
  263. }
  264. function hasStoredLogin()
  265. {
  266. $db = eZDB::instance();
  267. $contentObjectID = $this->attribute( 'contentobject_id' );
  268. $sql = "SELECT * FROM ezuser WHERE contentobject_id='$contentObjectID' AND LENGTH( login ) > 0";
  269. $rows = $db->arrayQuery( $sql );
  270. if ( !empty( $rows ) )
  271. {
  272. return true;
  273. }
  274. // If there are no stored logins, we look for a "draft" login before we give up
  275. $userObject = eZContentObject::fetch( $contentObjectID );
  276. if ( $userObject instanceof eZContentObject )
  277. {
  278. foreach ( $userObject->attribute( 'contentobject_attributes' ) as $contentObjectAttribute )
  279. {
  280. if ( $contentObjectAttribute->attribute( 'data_type_string' ) === 'ezuser' )
  281. {
  282. $serializedDraft = $contentObjectAttribute->attribute( 'data_text' );
  283. return !empty( $serializedDraft );
  284. }
  285. }
  286. }
  287. return false;
  288. }
  289. /*!
  290. Fills in the \a $id, \a $login, \a $email and \a $password for the user
  291. and creates the proper password hash.
  292. */
  293. function setInformation( $id, $login, $email, $password, $passwordConfirm = false )
  294. {
  295. $this->setAttribute( "contentobject_id", $id );
  296. $this->setAttribute( "email", $email );
  297. $this->setAttribute( "login", $login );
  298. if ( eZUser::validatePassword( $password ) and
  299. $password === $passwordConfirm ) // Cannot change login or password_hash without login and password
  300. {
  301. if ( eZUser::hashType() !== self::PASSWORD_HASH_EMPTY )
  302. {
  303. $this->setAttribute(
  304. "password_hash",
  305. eZUser::createHash( $login, $password, eZUser::site(), eZUser::hashType() )
  306. );
  307. }
  308. $this->setAttribute( "password_hash_type", eZUser::hashType() );
  309. }
  310. else
  311. {
  312. $this->setOriginalPassword( $password );
  313. $this->setOriginalPasswordConfirm( $passwordConfirm );
  314. }
  315. }
  316. /**
  317. * @param integer $id
  318. * @param bool $asObject
  319. * @return eZUser|null
  320. */
  321. static function fetch( $id, $asObject = true )
  322. {
  323. if ( !$id )
  324. return null;
  325. return eZPersistentObject::fetchObject( eZUser::definition(),
  326. null,
  327. array( 'contentobject_id' => $id ),
  328. $asObject );
  329. }
  330. static function fetchByName( $login, $asObject = true )
  331. {
  332. return eZPersistentObject::fetchObject( eZUser::definition(),
  333. null,
  334. array( 'LOWER( login )' => strtolower( $login ) ),
  335. $asObject );
  336. }
  337. static function fetchByEmail( $email, $asObject = true )
  338. {
  339. return eZPersistentObject::fetchObject( eZUser::definition(),
  340. null,
  341. array( 'LOWER( email )' => strtolower( $email ) ),
  342. $asObject );
  343. }
  344. /**
  345. * Return an array of unactivated eZUser object
  346. *
  347. * @param array|false|null An associative array of sorting conditions,
  348. * if set to false ignores settings in $def, if set to null uses
  349. * settingss in $def.
  350. * @param int $limit
  351. * @param int $offset
  352. * @return array( eZUser )
  353. */
  354. static public function fetchUnactivated( $sort = false, $limit = 10, $offset = 0 )
  355. {
  356. $accountDef = eZUserAccountKey::definition();
  357. $settingsDef = eZUserSetting::definition();
  358. return eZPersistentObject::fetchObjectList(
  359. eZUser::definition(), null, null, $sort,
  360. array(
  361. 'limit' => $limit,
  362. 'offset' => $offset
  363. ),
  364. true, false, null,
  365. array( $accountDef['name'], $settingsDef['name'] ),
  366. " WHERE contentobject_id = {$accountDef['name']}.user_id"
  367. . " AND {$settingsDef['name']}.user_id = contentobject_id"
  368. . " AND is_enabled = 0"
  369. );
  370. }
  371. /*!
  372. \static
  373. \return a list of the logged in users.
  374. \param $asObject If false it will return a list with only the names of the users as elements and user ID as key,
  375. otherwise each entry is a eZUser object.
  376. \sa fetchLoggedInCount
  377. */
  378. static function fetchLoggedInList( $asObject = false, $offset = false, $limit = false, $sortBy = false )
  379. {
  380. $db = eZDB::instance();
  381. $time = time() - eZINI::instance()->variable( 'Session', 'ActivityTimeout' );
  382. $parameters = array();
  383. if ( $offset )
  384. $parameters['offset'] =(int) $offset;
  385. if ( $limit )
  386. $parameters['limit'] =(int) $limit;
  387. $sortText = '';
  388. if ( $asObject )
  389. {
  390. $selectArray = array( "distinct ezuser.*" );
  391. }
  392. else
  393. {
  394. $selectArray = array( "ezuser.contentobject_id as user_id", "ezcontentobject.name" );
  395. }
  396. if ( $sortBy !== false )
  397. {
  398. $sortElements = array();
  399. if ( !is_array( $sortBy ) )
  400. {
  401. $sortBy = array( array( $sortBy, true ) );
  402. }
  403. else if ( !is_array( $sortBy[0] ) )
  404. $sortBy = array( $sortBy );
  405. $sortColumns = array();
  406. foreach ( $sortBy as $sortElements )
  407. {
  408. $sortColumn = $sortElements[0];
  409. $sortOrder = $sortElements[1];
  410. $orderText = $sortOrder ? 'asc' : 'desc';
  411. switch ( $sortColumn )
  412. {
  413. case 'user_id':
  414. {
  415. $sortColumn = "ezuser.contentobject_id $orderText";
  416. } break;
  417. case 'login':
  418. {
  419. $sortColumn = "ezuser.login $orderText";
  420. } break;
  421. case 'activity':
  422. {
  423. $selectArray[] = "ezuservisit.current_visit_timestamp AS activity";
  424. $sortColumn = "activity $orderText";
  425. } break;
  426. case 'email':
  427. {
  428. $sortColumn = "ezuser.email $orderText";
  429. } break;
  430. default:
  431. {
  432. eZDebug::writeError( "Unkown sort column '$sortColumn'", __METHOD__ );
  433. $sortColumn = false;
  434. } break;
  435. }
  436. if ( $sortColumn )
  437. $sortColumns[] = $sortColumn;
  438. }
  439. if ( !empty( $sortColumns ) )
  440. $sortText = "ORDER BY " . implode( ', ', $sortColumns );
  441. }
  442. if ( $asObject )
  443. {
  444. $selectText = implode( ', ', $selectArray );
  445. $sql = "SELECT $selectText
  446. FROM ezuservisit, ezuser
  447. WHERE ezuservisit.user_id != '" . self::anonymousId() . "' AND
  448. ezuservisit.current_visit_timestamp > '$time' AND
  449. ezuser.contentobject_id = ezuservisit.user_id
  450. $sortText";
  451. $rows = $db->arrayQuery( $sql, $parameters );
  452. $list = array();
  453. foreach ( $rows as $row )
  454. {
  455. $list[] = new eZUser( $row );
  456. }
  457. }
  458. else
  459. {
  460. $selectText = implode( ', ', $selectArray );
  461. $sql = "SELECT $selectText
  462. FROM ezuservisit, ezuser, ezcontentobject
  463. WHERE ezuservisit.user_id != '" . self::anonymousId() . "' AND
  464. ezuservisit.current_visit_timestamp > '$time' AND
  465. ezuser.contentobject_id = ezuservisit.user_id AND
  466. ezcontentobject.id = ezuser.contentobject_id
  467. $sortText";
  468. $rows = $db->arrayQuery( $sql, $parameters );
  469. $list = array();
  470. foreach ( $rows as $row )
  471. {
  472. $list[$row['user_id']] = $row['name'];
  473. }
  474. }
  475. return $list;
  476. }
  477. /*!
  478. \return the number of logged in users in the system.
  479. \note The count will be cached for the current page if caching is allowed.
  480. \sa fetchAnonymousCount
  481. */
  482. static function fetchLoggedInCount()
  483. {
  484. if ( isset( $GLOBALS['eZSiteBasics']['no-cache-adviced'] ) and
  485. !$GLOBALS['eZSiteBasics']['no-cache-adviced'] and
  486. isset( $GLOBALS['eZUserLoggedInCount'] ) )
  487. return $GLOBALS['eZUserLoggedInCount'];
  488. $db = eZDB::instance();
  489. $time = time() - eZINI::instance()->variable( 'Session', 'ActivityTimeout' );
  490. $sql = "SELECT count( DISTINCT user_id ) as count
  491. FROM ezuservisit
  492. WHERE user_id != '" . self::anonymousId() . "' AND
  493. user_id > 0 AND
  494. current_visit_timestamp > '$time'";
  495. $rows = $db->arrayQuery( $sql );
  496. $count = isset( $rows[0] ) ? $rows[0]['count'] : 0;
  497. $GLOBALS['eZUserLoggedInCount'] = $count;
  498. return $count;
  499. }
  500. /**
  501. * Return the number of anonymous users in the system.
  502. *
  503. * @deprecated As of 4.4 since default session handler does not support this.
  504. * @return int
  505. */
  506. static function fetchAnonymousCount()
  507. {
  508. if ( isset( $GLOBALS['eZSiteBasics']['no-cache-adviced'] ) and
  509. !$GLOBALS['eZSiteBasics']['no-cache-adviced'] and
  510. isset( $GLOBALS['eZUserAnonymousCount'] ) )
  511. return $GLOBALS['eZUserAnonymousCount'];
  512. $db = eZDB::instance();
  513. $time = time();
  514. $ini = eZINI::instance();
  515. $activityTimeout = $ini->variable( 'Session', 'ActivityTimeout' );
  516. $sessionTimeout = $ini->variable( 'Session', 'SessionTimeout' );
  517. $time = $time + $sessionTimeout - $activityTimeout;
  518. $sql = "SELECT count( session_key ) as count
  519. FROM ezsession
  520. WHERE user_id = '" . self::anonymousId() . "' AND
  521. expiration_time > '$time'";
  522. $rows = $db->arrayQuery( $sql );
  523. $count = isset( $rows[0] ) ? $rows[0]['count'] : 0;
  524. $GLOBALS['eZUserAnonymousCount'] = $count;
  525. return $count;
  526. }
  527. /*!
  528. \static
  529. \return true if the user with ID $userID is currently logged into the system.
  530. \note The information will be cached for the current page if caching is allowed.
  531. \sa fetchLoggedInList
  532. */
  533. static function isUserLoggedIn( $userID )
  534. {
  535. $userID = (int)$userID;
  536. if ( isset( $GLOBALS['eZSiteBasics']['no-cache-adviced'] ) and
  537. !$GLOBALS['eZSiteBasics']['no-cache-adviced'] and
  538. isset( $GLOBALS['eZUserLoggedInMap'][$userID] ) )
  539. return $GLOBALS['eZUserLoggedInMap'][$userID];
  540. $db = eZDB::instance();
  541. $time = time() - eZINI::instance()->variable( 'Session', 'ActivityTimeout' );
  542. $sql = "SELECT DISTINCT user_id
  543. FROM ezuservisit
  544. WHERE user_id = '" . $userID . "' AND
  545. current_visit_timestamp > '$time'";
  546. $rows = $db->arrayQuery( $sql, array( 'limit' => 2 ) );
  547. $isLoggedIn = isset( $rows[0] );
  548. $GLOBALS['eZUserLoggedInMap'][$userID] = $isLoggedIn;
  549. return $isLoggedIn;
  550. }
  551. /*!
  552. \static
  553. Removes any cached session information, this is:
  554. - logged in user count
  555. - anonymous user count
  556. - logged in user map
  557. */
  558. static function clearSessionCache()
  559. {
  560. unset( $GLOBALS['eZUserLoggedInCount'] );
  561. unset( $GLOBALS['eZUserAnonymousCount'] );
  562. unset( $GLOBALS['eZUserLoggedInMap'] );
  563. }
  564. /**
  565. * Remove session data for user \a $userID.
  566. * @todo should use eZSession api (needs to be created) so
  567. * callbacks (like preference / basket..) is cleared as well.
  568. *
  569. * @params int $userID
  570. */
  571. static function removeSessionData( $userID )
  572. {
  573. eZUser::clearSessionCache();
  574. eZSession::getHandlerInstance()->deleteByUserIDs( array( $userID ) );
  575. }
  576. /*!
  577. Removes the user from the ezuser table.
  578. \note Will also remove any notifications and session related to the user.
  579. */
  580. static function removeUser( $userID )
  581. {
  582. $user = eZUser::fetch( $userID );
  583. if ( !$user )
  584. {
  585. eZDebug::writeError( "unable to find user with ID $userID", __METHOD__ );
  586. return false;
  587. }
  588. eZUser::removeSessionData( $userID );
  589. eZSubtreeNotificationRule::removeByUserID( $userID );
  590. eZCollaborationNotificationRule::removeByUserID( $userID );
  591. eZUserSetting::removeByUserID( $userID );
  592. eZUserAccountKey::removeByUserID( $userID );
  593. eZForgotPassword::removeByUserID( $userID );
  594. eZWishList::removeByUserID( $userID );
  595. eZGeneralDigestUserSettings::removeByUserId( $userID );
  596. eZPersistentObject::removeObject( eZUser::definition(),
  597. array( 'contentobject_id' => $userID ) );
  598. return true;
  599. }
  600. /*!
  601. \return a list of valid and enabled users, the data returned is an array
  602. with ezcontentobject database data.
  603. */
  604. static function fetchContentList()
  605. {
  606. $contentObjectStatus = eZContentObject::STATUS_PUBLISHED;
  607. $query = "SELECT ezcontentobject.*
  608. FROM ezuser, ezcontentobject, ezuser_setting
  609. WHERE ezcontentobject.status = '$contentObjectStatus' AND
  610. ezuser_setting.is_enabled = 1 AND
  611. ezcontentobject.id = ezuser.contentobject_id AND
  612. ezuser_setting.user_id = ezuser.contentobject_id";
  613. $db = eZDB::instance();
  614. $rows = $db->arrayQuery( $query );
  615. return $rows;
  616. }
  617. /*!
  618. \static
  619. \return the default hash type which is specified in UserSettings/HashType in site.ini
  620. */
  621. static function hashType()
  622. {
  623. $ini = eZINI::instance();
  624. $type = strtolower( $ini->variable( 'UserSettings', 'HashType' ) );
  625. return self::passwordHashTypeID( $type );
  626. }
  627. /*!
  628. \static
  629. \return the site name used in password hashing.
  630. */
  631. static function site()
  632. {
  633. $ini = eZINI::instance();
  634. return $ini->variable( 'UserSettings', 'SiteName' );
  635. }
  636. /*!
  637. Fetches a builtin user and returns it, this helps avoid special cases where
  638. user is not logged in.
  639. */
  640. static function fetchBuiltin( $id )
  641. {
  642. if ( !in_array( $id, $GLOBALS['eZUserBuiltins'] ) )
  643. $id = self::anonymousId();
  644. if ( empty( $GLOBALS["eZUserBuilitinInstance-$id"] ) )
  645. {
  646. $GLOBALS["eZUserBuilitinInstance-$id"] = eZUser::fetch( self::anonymousId() );
  647. }
  648. return $GLOBALS["eZUserBuilitinInstance-$id"];
  649. }
  650. /*!
  651. \return the user id.
  652. */
  653. function id()
  654. {
  655. return $this->ContentObjectID;
  656. }
  657. /*!
  658. \return a bitfield which decides the authenticate methods.
  659. */
  660. static function authenticationMatch()
  661. {
  662. $ini = eZINI::instance();
  663. $matchArray = $ini->variableArray( 'UserSettings', 'AuthenticateMatch' );
  664. $match = 0;
  665. foreach ( $matchArray as $matchItem )
  666. {
  667. switch ( $matchItem )
  668. {
  669. case "login":
  670. {
  671. $match = ( $match | self::AUTHENTICATE_LOGIN );
  672. } break;
  673. case "email":
  674. {
  675. $match = ( $match | self::AUTHENTICATE_EMAIL );
  676. } break;
  677. }
  678. }
  679. return $match;
  680. }
  681. /*!
  682. \return \c true if there can only be one instance of an email address on the site.
  683. */
  684. static function requireUniqueEmail()
  685. {
  686. $ini = eZINI::instance();
  687. return $ini->variable( 'UserSettings', 'RequireUniqueEmail' ) == 'true';
  688. }
  689. /**
  690. * Logs in the user if applied username and password is valid.
  691. *
  692. * @param string $login
  693. * @param string $password
  694. * @param bool $authenticationMatch
  695. * @return mixed eZUser on success, bool false on failure
  696. */
  697. public static function loginUser( $login, $password, $authenticationMatch = false )
  698. {
  699. $user = self::_loginUser( $login, $password, $authenticationMatch );
  700. if ( is_object( $user ) )
  701. {
  702. self::loginSucceeded( $user );
  703. return $user;
  704. }
  705. else
  706. {
  707. self::loginFailed( $user, $login );
  708. return false;
  709. }
  710. }
  711. /**
  712. * Does some house keeping work once a log in has succeeded.
  713. *
  714. * @param eZUser $user
  715. */
  716. protected static function loginSucceeded( $user )
  717. {
  718. $userID = $user->attribute( 'contentobject_id' );
  719. // if audit is enabled logins should be logged
  720. eZAudit::writeAudit( 'user-login', array( 'User id' => $userID, 'User login' => $user->attribute( 'login' ) ) );
  721. eZUser::updateLastVisit( $userID, true );
  722. eZUser::setCurrentlyLoggedInUser( $user, $userID );
  723. // Reset number of failed login attempts
  724. eZUser::setFailedLoginAttempts( $userID, 0 );
  725. }
  726. /**
  727. * Does some house keeping work when a log in has failed.
  728. *
  729. * @param mixed $userID
  730. * @param string $login
  731. */
  732. protected static function loginFailed( $userID = false, $login )
  733. {
  734. $loginEscaped = eZDB::instance()->escapeString( $login );
  735. // Failed login attempts should be logged
  736. eZAudit::writeAudit( 'user-failed-login', array( 'User login' => $loginEscaped,
  737. 'Comment' => 'Failed login attempt: eZUser::loginUser()' ) );
  738. // Increase number of failed login attempts.
  739. if ( $userID )
  740. eZUser::setFailedLoginAttempts( $userID );
  741. }
  742. /**
  743. * Logs in an user if applied login and password is valid.
  744. *
  745. * This method does not do any house keeping work anymore (writing audits, etc).
  746. * When you call this method make sure to call loginSucceeded() or loginFailed()
  747. * depending on the success of the login.
  748. *
  749. * @param string $login
  750. * @param string $password
  751. * @param bool $authenticationMatch
  752. * @return mixed eZUser object on log in success, int userID if the username
  753. * exists but log in failed, or false if the username doesn't exists.
  754. */
  755. protected static function _loginUser( $login, $password, $authenticationMatch = false )
  756. {
  757. if ( $login == '' || $password == '' )
  758. {
  759. return false;
  760. }
  761. $http = eZHTTPTool::instance();
  762. $db = eZDB::instance();
  763. if ( $authenticationMatch === false )
  764. $authenticationMatch = eZUser::authenticationMatch();
  765. $login = self::trimAuthString( $login );
  766. $password = self::trimAuthString( $password );
  767. $loginEscaped = $db->escapeString( $login );
  768. $passwordEscaped = $db->escapeString( $password );
  769. $loginArray = array();
  770. if ( $authenticationMatch & self::AUTHENTICATE_LOGIN )
  771. $loginArray[] = "login='$loginEscaped'";
  772. if ( $authenticationMatch & self::AUTHENTICATE_EMAIL )
  773. {
  774. if ( eZMail::validate( $login ) )
  775. {
  776. $loginArray[] = "email='$loginEscaped'";
  777. }
  778. }
  779. if ( empty( $loginArray ) )
  780. $loginArray[] = "login='$loginEscaped'";
  781. $loginText = implode( ' OR ', $loginArray );
  782. $contentObjectStatus = eZContentObject::STATUS_PUBLISHED;
  783. // PASSWORD_HASH_MYSQL is handled further down as this inital SQL needs to work on MySQL 8.0 as well as PostgreSQL
  784. $query = "SELECT contentobject_id, password_hash, password_hash_type, email, login
  785. FROM ezuser, ezcontentobject
  786. WHERE ( $loginText )
  787. AND password_hash_type!=0
  788. AND ezcontentobject.status='$contentObjectStatus'
  789. AND ezcontentobject.id=contentobject_id";
  790. $users = $db->arrayQuery( $query );
  791. $exists = false;
  792. if ( $users !== false && isset( $users[0] ) )
  793. {
  794. $ini = eZINI::instance();
  795. foreach ( $users as $userRow )
  796. {
  797. $userID = $userRow['contentobject_id'];
  798. $hashType = $userRow['password_hash_type'];
  799. $hash = $userRow['password_hash'];
  800. $exists = eZUser::authenticateHash( $userRow['login'], $password, eZUser::site(),
  801. $hashType,
  802. $hash );
  803. $databaseName = $db->databaseName();
  804. // If hash type is MySql
  805. if ( $hashType == self::PASSWORD_HASH_MYSQL and $databaseName === 'mysql' )
  806. {
  807. $queryMysqlUser = "SELECT contentobject_id, password_hash, password_hash_type, email, login
  808. FROM ezuser, ezcontentobject
  809. WHERE ezcontentobject.status='$contentObjectStatus' AND
  810. password_hash_type=4 AND ( $loginText ) AND password_hash=PASSWORD('$passwordEscaped') ";
  811. $mysqlUsers = $db->arrayQuery( $queryMysqlUser );
  812. if ( isset( $mysqlUsers[0] ) )
  813. $exists = true;
  814. }
  815. // If current user has been disabled after a few failed login attempts.
  816. $canLogin = eZUser::isEnabledAfterFailedLogin( $userID );
  817. if ( $exists )
  818. {
  819. eZDebugSetting::writeDebug( 'kernel-user', eZUser::createHash( $userRow['login'], $password, eZUser::site(),
  820. $hashType, $hash ), "check hash" );
  821. eZDebugSetting::writeDebug( 'kernel-user', $hash, "stored hash" );
  822. // We should store userID for warning message.
  823. $GLOBALS['eZFailedLoginAttemptUserID'] = $userID;
  824. $userSetting = eZUserSetting::fetch( $userID );
  825. $isEnabled = $userSetting->attribute( "is_enabled" );
  826. if ( $hashType != eZUser::hashType() and
  827. strtolower( $ini->variable( 'UserSettings', 'UpdateHash' ) ) == 'true' )
  828. {
  829. $hashType = eZUser::hashType();
  830. $hash = eZUser::createHash( $userRow['login'], $password, eZUser::site(),
  831. $hashType );
  832. $db->query( "UPDATE ezuser SET password_hash='$hash', password_hash_type='$hashType' WHERE contentobject_id='$userID'" );
  833. }
  834. break;
  835. }
  836. }
  837. }
  838. if ( $exists and $isEnabled and $canLogin )
  839. {
  840. return new eZUser( $userRow );
  841. }
  842. else
  843. {
  844. return isset( $userID ) ? $userID : false;
  845. }
  846. }
  847. /*!
  848. \static
  849. Checks if IP address of current user is in \a $ipList.
  850. */
  851. static function isUserIPInList( $ipList )
  852. {
  853. $ipAddress = eZSys::clientIP();
  854. if ( $ipAddress )
  855. {
  856. $result = false;
  857. foreach( $ipList as $itemToMatch )
  858. {
  859. if ( preg_match("/^(([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+))(\/([0-9]+)$|$)/", $itemToMatch, $matches ) )
  860. {
  861. if ( $matches[6] )
  862. {
  863. if ( eZDebug::isIPInNet( $ipAddress, $matches[1], $matches[7] ) )
  864. {
  865. $result = true;
  866. break;
  867. }
  868. }
  869. else
  870. {
  871. if ( $matches[1] == $ipAddress )
  872. {
  873. $result = true;
  874. break;
  875. }
  876. }
  877. }
  878. }
  879. }
  880. else
  881. {
  882. $result = (
  883. in_array( 'commandline', $ipList ) &&
  884. ( php_sapi_name() == 'cli' )
  885. );
  886. }
  887. return $result;
  888. }
  889. /*!
  890. \static
  891. Returns true if current user is trusted user.
  892. */
  893. static function isTrusted()
  894. {
  895. $ini = eZINI::instance();
  896. // Check if current user is trusted user.
  897. $trustedIPs = $ini->hasVariable( 'UserSettings', 'TrustedIPList' ) ? $ini->variable( 'UserSettings', 'TrustedIPList' ) : array();
  898. // Check if IP address of current user is in $trustedIPs array.
  899. $trustedUser = eZUser::isUserIPInList( $trustedIPs );
  900. if ( $trustedUser )
  901. return true;
  902. return false;
  903. }
  904. /*!
  905. \static
  906. Returns max number of failed login attempts.
  907. */
  908. static function maxNumberOfFailedLogin()
  909. {
  910. $ini = eZINI::instance();
  911. $maxNumberOfFailedLogin = $ini->hasVariable( 'UserSettings', 'MaxNumberOfFailedLogin' ) ? $ini->variable( 'UserSettings', 'MaxNumberOfFailedLogin' ) : '0';
  912. return $maxNumberOfFailedLogin;
  913. }
  914. /*
  915. \static
  916. Returns true if the user can login
  917. If user has number of failed login attempts more than eZUser::maxNumberOfFailedLogin()
  918. and user is not trusted
  919. the user will not be allowed to login.
  920. */
  921. static function isEnabledAfterFailedLogin( $userID, $ignoreTrusted = false )
  922. {
  923. if ( !is_numeric( $userID ) )
  924. return true;
  925. $userObject = eZUser::fetch( $userID );
  926. if ( !$userObject )
  927. return true;
  928. $trustedUser = eZUser::isTrusted();
  929. // If user is trusted we should stop processing
  930. if ( $trustedUser and !$ignoreTrusted )
  931. return true;
  932. $maxNumberOfFailedLogin = eZUser::maxNumberOfFailedLogin();
  933. if ( $maxNumberOfFailedLogin == '0' )
  934. return true;
  935. $failedLoginAttempts = $userObject->failedLoginAttempts();
  936. if ( $failedLoginAttempts > $maxNumberOfFailedLogin )
  937. return false;
  938. return true;
  939. }
  940. /**
  941. * Makes sure the $user is set as the currently logged in user by
  942. * updating the session and setting the necessary global variables.
  943. *
  944. * All login handlers should use this function to ensure that the process
  945. * is executed properly.
  946. *
  947. * @access private
  948. *
  949. * @param eZUser $user User
  950. * @param int $userID User ID
  951. * @param int $flags Optional flag that can be set to:
  952. * eZUser::NO_SESSION_REGENERATE to avoid session to be regenerated
  953. */
  954. static function setCurrentlyLoggedInUser( $user, $userID, $flags = 0 )
  955. {
  956. $GLOBALS["eZUserGlobalInstance_$userID"] = $user;
  957. // Set/overwrite the global user, this will be accessed from
  958. // instance() when there is no ID passed to the function.
  959. $GLOBALS["eZUserGlobalInstance_"] = $user;
  960. eZSession::setUserID( $userID );
  961. if ( !( $flags & self::NO_SESSION_REGENERATE) )
  962. eZSession::regenerate();
  963. eZSession::set( 'eZUserLoggedInID', $userID );
  964. self::cleanup();
  965. }
  966. /*!
  967. \virtual
  968. Used by login handler to clean up session variables
  969. */
  970. function sessionCleanup()
  971. {
  972. }
  973. /**
  974. * Cleanup user related session values, for use by login / logout code
  975. *
  976. * @internal
  977. */
  978. static function cleanup()
  979. {
  980. $http = eZHTTPTool::instance();
  981. $http->removeSessionVariable( 'CanInstantiateClassList' );
  982. $http->removeSessionVariable( 'ClassesCachedForUser' );
  983. // Note: This must be done more generic with an internal
  984. // callback system.
  985. eZPreferences::sessionCleanup();
  986. }
  987. /*!
  988. \return logs in the current user object
  989. */
  990. function loginCurrent()
  991. {
  992. self::setCurrentlyLoggedInUser( $this, $this->ContentObjectID );
  993. }
  994. /*!
  995. \static
  996. Logs out the current user
  997. */
  998. static function logoutCurrent()
  999. {
  1000. $http = eZHTTPTool::instance();
  1001. $id = false;
  1002. $GLOBALS["eZUserGlobalInstance_$id"] = false;
  1003. $contentObjectID = $http->sessionVariable( 'eZUserLoggedInID' );
  1004. // reset session data
  1005. $newUserID = self::anonymousId();
  1006. eZSession::setUserID( $newUserID );
  1007. $http->setSessionVariable( 'eZUserLoggedInID', $newUserID );
  1008. // Clear current basket if necessary
  1009. $db = eZDB::instance();
  1010. $db->begin();
  1011. eZBasket::cleanupCurrentBasket();
  1012. $db->commit();
  1013. if ( $contentObjectID )
  1014. {
  1015. //set last visit to minus
  1016. self::updateLastVisitByLogout( $contentObjectID );
  1017. //clean up sessions
  1018. self::cleanup();
  1019. }
  1020. // give user new session id
  1021. eZSession::regenerate();
  1022. // set the property used to prevent SSO from running again
  1023. self::$userHasLoggedOut = true;
  1024. }
  1025. /**
  1026. * Update LastVisit When a user logout. Logout will set current_visit_timestamp to -current_visit_timestamp.
  1027. * If the user relogin, the last_visit_timestamp will get ABS(current_visit_timestamp).
  1028. * @static
  1029. * @param $userID
  1030. * @since 5.1
  1031. * @see eZUser::updateLastVisit
  1032. */
  1033. static function updateLastVisitByLogout( $userID )
  1034. {
  1035. $db = eZDB::instance();
  1036. $db->query( "UPDATE ezuservisit SET current_visit_timestamp=-ABS(current_visit_timestamp) WHERE user_id=$userID" );
  1037. }
  1038. /**
  1039. * Returns a shared instance of the eZUser class pr $id value.
  1040. * If user can not be fetched, then anonymous user is returned and
  1041. * a warning trown, if anonymous user can not be fetched, then NoUser
  1042. * is returned and another warning is thrown.
  1043. *
  1044. * @param int|false $id On false: Gets current user id from session
  1045. * or from {@link eZUser::anonymousId()} if not set.
  1046. * @return eZUser
  1047. */
  1048. static function instance( $id = false )
  1049. {
  1050. if ( !empty( $GLOBALS["eZUserGlobalInstance_$id"] ) )
  1051. {
  1052. return $GLOBALS["eZUserGlobalInstance_$id"];
  1053. }
  1054. $userId = $id;
  1055. $currentUser = null;
  1056. $http = eZHTTPTool::instance();
  1057. $anonymousUserID = self::anonymousId();
  1058. $sessionHasStarted = eZSession::hasStarted();
  1059. // If not specified get the current user
  1060. if ( $userId === false )
  1061. {
  1062. if ( $sessionHasStarted )
  1063. {
  1064. $userId = $http->sessionVariable( 'eZUserLoggedInID' );
  1065. if ( !is_numeric( $userId ) )
  1066. {
  1067. $userId = $anonymousUserID;
  1068. eZSession::setUserID( $userId );
  1069. $http->setSessionVariable( 'eZUserLoggedInID', $userId );
  1070. }
  1071. }
  1072. else
  1073. {
  1074. $userId = $anonymousUserID;
  1075. eZSession::setUserID( $userId );
  1076. }
  1077. }
  1078. // Check user cache (this effectivly fetches user from cache)
  1079. // user not found if !isset( isset( $userCache['info'][$userId] ) )
  1080. $userCache = self::getUserCacheByUserId( $userId );
  1081. if ( isset( $userCache['info'][$userId] ) )
  1082. {
  1083. $userArray = $userCache['info'][$userId];
  1084. if ( is_numeric( $userArray['contentobject_id'] ) )
  1085. {
  1086. $currentUser = new eZUser( $userArray );
  1087. $currentUser->setUserCache( $userCache );
  1088. }
  1089. }
  1090. $ini = eZINI::instance();
  1091. // Check if:
  1092. // - the user has not logged out,
  1093. // - the user is not logged in,
  1094. // - and if a automatic single sign on plugin is enabled.
  1095. if ( !self::$userHasLoggedOut && is_object( $currentUser ) && !$currentUser->isRegistered() )
  1096. {
  1097. $ssoHandlerArray = $ini->variable( 'UserSettings', 'SingleSignOnHandlerArray' );
  1098. if ( !empty( $ssoHandlerArray ) )
  1099. {
  1100. $ssoUser = false;
  1101. foreach ( $ssoHandlerArray as $ssoHandler )
  1102. {
  1103. $className = 'eZ' . $ssoHandler . 'SSOHandler';
  1104. if( class_exists( $className ) )
  1105. {
  1106. $impl = new $className();
  1107. $ssoUser = $impl->handleSSOLogin();
  1108. // If a user was found via SSO, then use it
  1109. if ( $ssoUser !== false )
  1110. {
  1111. $currentUser = $ssoUser;
  1112. $userId = $currentUser->attribute( 'contentobject_id' );
  1113. $userInfo = array();
  1114. $userInfo[$userId] = array(
  1115. 'contentobject_id' => $userId,
  1116. 'login' => $currentUser->attribute( 'login' ),
  1117. 'email' => $currentUser->attribute( 'email' ),
  1118. 'password_hash' => $currentUser->attribute( 'password_hash' ),
  1119. 'password_hash_type' => $currentUser->attribute( 'password_hash_type' )
  1120. );
  1121. eZSession::setUserID( $userId );
  1122. $http->setSessionVariable( 'eZUserLoggedInID', $userId );
  1123. eZUser::updateLastVisit( $userId );
  1124. eZUser::setCurrentlyLoggedInUser( $currentUser, $userId );
  1125. eZHTTPTool::redirect( eZSys::wwwDir() . eZSys::indexFile( false ) . eZSys::requestURI() . eZSys::queryString(), array(), 302 );
  1126. eZExecution::cleanExit();
  1127. }
  1128. }
  1129. else
  1130. {
  1131. eZDebug::writeError( "Undefined ssoHandler class: $className", __METHOD__ );
  1132. }
  1133. }
  1134. }
  1135. }
  1136. if ( $userId <> $anonymousUserID )
  1137. {
  1138. $sessionInactivityTimeout = $ini->variable( 'Session', 'ActivityTimeout' );
  1139. if ( !isset( $GLOBALS['eZSessionIdleTime'] ) )
  1140. {
  1141. eZUser::updateLastVisit( $userId );
  1142. }
  1143. else
  1144. {
  1145. $sessionIdle = $GLOBALS['eZSessionIdleTime'];
  1146. if ( $sessionIdle > $sessionInactivityTimeout )
  1147. {
  1148. eZUser::updateLastVisit( $userId );
  1149. }
  1150. }
  1151. }
  1152. if ( !$currentUser )
  1153. {
  1154. $currentUser = eZUser::fetch( self::anonymousId() );
  1155. eZDebug::writeWarning( 'User not found, returning anonymous' );
  1156. }
  1157. if ( !$currentUser )
  1158. {
  1159. $currentUser = new eZUser( array( 'id' => -1, 'login' => 'NoUser' ) );
  1160. eZDebug::writeWarning( 'Anonymous user not found, returning NoUser' );
  1161. }
  1162. $GLOBALS["eZUserGlobalInstance_$id"] = $currentUser;
  1163. return $currentUser;
  1164. }
  1165. /**
  1166. * Get User cache from cache file
  1167. *
  1168. * @since 4.4
  1169. * @return array( 'info' => array, 'groups' => array, 'roles' => array, 'role_limitations' => array, 'access_array' => array)
  1170. */
  1171. public function getUserCache()
  1172. {
  1173. if ( $this->UserCache === null )
  1174. {
  1175. $this->setUserCache( self::getUserCacheByUserId( $this->ContentObjectID ) );
  1176. }
  1177. return $this->UserCache;
  1178. }
  1179. /**
  1180. * Delete User cache from locale var and cache file for current user.
  1181. *
  1182. * @since 4.4
  1183. */
  1184. public function purgeUserCache()
  1185. {
  1186. $this->UserCache = null;
  1187. self::purgeUserCacheByUserId( $this->ContentObjectID );
  1188. }
  1189. /**
  1190. * Set User cache from cache file
  1191. * Needs to be in excact same format as {@link eZUser::getUserCache()}!
  1192. *
  1193. * @since 4.4
  1194. * @param array $userCache
  1195. */
  1196. public function setUserCache( array $userCache )
  1197. {
  1198. $this->UserCache = $userCache;
  1199. }
  1200. /**
  1201. * Delete User cache from cache file for Anonymous user(usefull for sessionless users)
  1202. *
  1203. * @since 4.4
  1204. * @see eZUser::purgeUserCacheByUserId()
  1205. */
  1206. static public function purgeUserCacheByAnonymousId()
  1207. {
  1208. self::purgeUserCacheByUserId( self::anonymousId() );
  1209. }
  1210. /**
  1211. * Delete User cache pr user
  1212. *
  1213. * @since 4.4
  1214. * @param int $userId
  1215. */
  1216. static public function purgeUserCacheByUserId( $userId )
  1217. {
  1218. if ( eZINI::instance()->variable( 'RoleSettings', 'EnableCaching' ) === 'true' )
  1219. {
  1220. $cacheFilePath = eZUser::getCacheDir( $userId ). "/user-data-{$userId}.cache.php" ;
  1221. eZClusterFileHandler::instance()->fileDelete( $cacheFilePath );
  1222. }
  1223. }
  1224. /**
  1225. * Get User cache from cache file for Anonymous user(usefull for sessionless users)
  1226. *
  1227. * @since 4.4
  1228. * @see eZUser::getUserCacheByUserId()
  1229. * @return array
  1230. */
  1231. static public function getUserCacheByAnonymousId()
  1232. {
  1233. return self::getUserCacheByUserId( self::anonymousId() );
  1234. }
  1235. /**
  1236. * Get User cache from cache file (usefull for sessionless users)
  1237. *
  1238. * @since 4.4
  1239. * @see eZUser::getUserCache()
  1240. * @param int $userId
  1241. * @return array
  1242. */
  1243. static protected function getUserCacheByUserId( $userId )
  1244. {
  1245. $userCache = null;
  1246. if ( eZINI::instance()->variable( 'RoleSettings', 'EnableCaching' ) === 'true' )
  1247. {
  1248. $cacheFilePath = eZUser::getCacheDir( $userId ) . "/user-data-{$userId}.cache.php";
  1249. $cacheFile = eZClusterFileHandler::instance( $cacheFilePath );
  1250. $userCache = $cacheFile->processCache( array( 'eZUser', 'retrieveUserCacheFromFile' ),
  1251. array( 'eZUser', 'generateUserCacheForFile' ),
  1252. null,
  1253. self::userInfoExpiry(),
  1254. $userId );
  1255. }
  1256. if ( $userCache === null || $userCache instanceof eZClusterFileFailure )
  1257. {
  1258. $userCache = self::generateUserCacheContent( $userId );
  1259. }
  1260. return $userCache;
  1261. }
  1262. /**
  1263. * Callback which fetches user cache from local file.
  1264. *
  1265. * @internal
  1266. * @since 4.4
  1267. * @see eZUser::getUserCacheByUserId()
  1268. */
  1269. static function retrieveUserCacheFromFile( $filePath, $mtime, $userId )
  1270. {
  1271. $userCache = include( $filePath );
  1272. // check that the returned array is not corrupted
  1273. if ( is_array( $userCache )
  1274. && isset( $userCache['info'] )
  1275. && isset( $userCache['info'][$userId] )
  1276. && is_numeric( $userCache['info'][$userId]['contentobject_id'] )
  1277. && isset( $userCache['groups'] )
  1278. && isset( $userCache['roles'] )
  1279. && isset( $userCache['role_limitations'] )
  1280. && isset( $userCache['access_array'] )
  1281. && isset( $userCache['discount_rules'] ) )
  1282. {
  1283. return $userCache;
  1284. }
  1285. eZDebug::writeError(

Large files files are truncated, but you can click here to view the full file