|
eZ Publish
[4.1]
|
00001 <?php 00002 // 00003 // Definition of eZUser class 00004 // 00005 // Created on: <10-Jun-2002 17:03:15 bf> 00006 // 00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00008 // SOFTWARE NAME: eZ Publish 00009 // SOFTWARE RELEASE: 4.1.x 00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2009 eZ Systems AS 00011 // SOFTWARE LICENSE: GNU General Public License v2.0 00012 // NOTICE: > 00013 // This program is free software; you can redistribute it and/or 00014 // modify it under the terms of version 2.0 of the GNU General 00015 // Public License as published by the Free Software Foundation. 00016 // 00017 // This program is distributed in the hope that it will be useful, 00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 // GNU General Public License for more details. 00021 // 00022 // You should have received a copy of version 2.0 of the GNU General 00023 // Public License along with this program; if not, write to the Free 00024 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00025 // MA 02110-1301, USA. 00026 // 00027 // 00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00029 // 00030 00031 /*! 00032 \class eZUser ezuser.php 00033 \brief eZUser handles eZ Publish user accounts 00034 \ingroup eZDatatype 00035 00036 */ 00037 00038 class eZUser extends eZPersistentObject 00039 { 00040 /// MD5 of password 00041 const PASSWORD_HASH_MD5_PASSWORD = 1; 00042 /// MD5 of user and password 00043 const PASSWORD_HASH_MD5_USER = 2; 00044 /// MD5 of site, user and password 00045 const PASSWORD_HASH_MD5_SITE = 3; 00046 /// Legacy support for mysql hashed passwords 00047 const PASSWORD_HASH_MYSQL = 4; 00048 /// Passwords in plaintext, should not be used for real sites 00049 const PASSWORD_HASH_PLAINTEXT = 5; 00050 // Crypted passwords 00051 const PASSWORD_HASH_CRYPT = 6; 00052 00053 /// Authenticate by matching the login field 00054 const AUTHENTICATE_LOGIN = 1; 00055 /// Authenticate by matching the email field 00056 const AUTHENTICATE_EMAIL = 2; 00057 00058 const AUTHENTICATE_ALL = 3; //EZ_USER_AUTHENTICATE_LOGIN | EZ_USER_AUTHENTICATE_EMAIL; 00059 00060 protected static $anonymousId = null; 00061 00062 function eZUser( $row ) 00063 { 00064 $this->eZPersistentObject( $row ); 00065 $this->OriginalPassword = false; 00066 $this->OriginalPasswordConfirm = false; 00067 } 00068 00069 static function definition() 00070 { 00071 return array( 'fields' => array( 'contentobject_id' => array( 'name' => 'ContentObjectID', 00072 'datatype' => 'integer', 00073 'default' => 0, 00074 'required' => true, 00075 'foreign_class' => 'eZContentObject', 00076 'foreign_attribute' => 'id', 00077 'multiplicity' => '0..1' ), 00078 'login' => array( 'name' => 'Login', 00079 'datatype' => 'string', 00080 'default' => '', 00081 'required' => true ), 00082 'email' => array( 'name' => 'Email', 00083 'datatype' => 'string', 00084 'default' => '', 00085 'required' => true ), 00086 'password_hash' => array( 'name' => 'PasswordHash', 00087 'datatype' => 'string', 00088 'default' => '', 00089 'required' => true ), 00090 'password_hash_type' => array( 'name' => 'PasswordHashType', 00091 'datatype' => 'integer', 00092 'default' => 1, 00093 'required' => true ) ), 00094 'keys' => array( 'contentobject_id' ), 00095 'sort' => array( 'contentobject_id' => 'asc' ), 00096 'function_attributes' => array( 'contentobject' => 'contentObject', 00097 'groups' => 'groups', 00098 'has_stored_login' => 'hasStoredLogin', 00099 'original_password' => 'originalPassword', 00100 'original_password_confirm' => 'originalPasswordConfirm', 00101 'roles' => 'roles', 00102 'role_id_list' => 'roleIDList', 00103 'limited_assignment_value_list' => 'limitValueList', 00104 'is_logged_in' => 'isLoggedIn', 00105 'is_enabled' => 'isEnabled', 00106 'is_locked' => 'isLocked', 00107 'last_visit' => 'lastVisit', 00108 'login_count' => 'loginCount', 00109 'has_manage_locations' => 'hasManageLocations' ), 00110 'relations' => array( 'contentobject_id' => array( 'class' => 'ezcontentobject', 00111 'field' => 'id' ) ), 00112 'class_name' => 'eZUser', 00113 'name' => 'ezuser' ); 00114 } 00115 00116 /*! 00117 \return a textual identifier for the hash type $id 00118 */ 00119 static function passwordHashTypeName( $id ) 00120 { 00121 switch ( $id ) 00122 { 00123 case self::PASSWORD_HASH_MD5_PASSWORD: 00124 { 00125 return 'md5_password'; 00126 } break; 00127 case self::PASSWORD_HASH_MD5_USER: 00128 { 00129 return 'md5_user'; 00130 } break; 00131 case self::PASSWORD_HASH_MD5_SITE: 00132 { 00133 return 'md5_site'; 00134 } break; 00135 case self::PASSWORD_HASH_MYSQL: 00136 { 00137 return 'mysql'; 00138 } break; 00139 case self::PASSWORD_HASH_PLAINTEXT: 00140 { 00141 return 'plaintext'; 00142 } break; 00143 case self::PASSWORD_HASH_CRYPT: 00144 { 00145 return 'crypt'; 00146 } break; 00147 } 00148 } 00149 00150 /*! 00151 \return the hash type for the textual identifier $identifier 00152 */ 00153 static function passwordHashTypeID( $identifier ) 00154 { 00155 switch ( $identifier ) 00156 { 00157 case 'md5_password': 00158 { 00159 return self::PASSWORD_HASH_MD5_PASSWORD; 00160 } break; 00161 default: 00162 case 'md5_user': 00163 { 00164 return self::PASSWORD_HASH_MD5_USER; 00165 } break; 00166 case 'md5_site': 00167 { 00168 return self::PASSWORD_HASH_MD5_SITE; 00169 } break; 00170 case 'mysql': 00171 { 00172 return self::PASSWORD_HASH_MYSQL; 00173 } break; 00174 case 'plaintext': 00175 { 00176 return self::PASSWORD_HASH_PLAINTEXT; 00177 } break; 00178 case 'crypt': 00179 { 00180 return self::PASSWORD_HASH_CRYPT; 00181 } break; 00182 } 00183 } 00184 00185 /*! 00186 Check if current user has "content/manage_locations" access 00187 */ 00188 function hasManageLocations() 00189 { 00190 $accessResult = $this->hasAccessTo( 'content', 'manage_locations' ); 00191 if ( $accessResult['accessWord'] != 'no' ) 00192 { 00193 return true; 00194 } 00195 00196 return false; 00197 } 00198 00199 static function create( $contentObjectID ) 00200 { 00201 $row = array( 00202 'contentobject_id' => $contentObjectID, 00203 'login' => null, 00204 'email' => null, 00205 'password_hash' => null, 00206 'password_hash_type' => null 00207 ); 00208 return new eZUser( $row ); 00209 } 00210 00211 function store( $fieldFilters = null ) 00212 { 00213 $this->Email = trim( $this->Email ); 00214 eZExpiryHandler::registerShutdownFunction(); 00215 $handler = eZExpiryHandler::instance(); 00216 $handler->setTimestamp( 'user-info-cache', time() ); 00217 $handler->setTimestamp( 'user-groups-cache', time() ); 00218 $handler->setTimestamp( 'user-access-cache', time() ); 00219 $handler->store(); 00220 $userID = $this->attribute( 'contentobject_id' ); 00221 // Clear memory cache 00222 unset( $GLOBALS['eZUserObject_' . $userID] ); 00223 $GLOBALS['eZUserObject_' . $userID] = $this; 00224 eZPersistentObject::store( $fieldFilters ); 00225 } 00226 00227 function originalPassword() 00228 { 00229 return $this->OriginalPassword; 00230 } 00231 00232 function setOriginalPassword( $password ) 00233 { 00234 $this->OriginalPassword = $password; 00235 } 00236 00237 function originalPasswordConfirm() 00238 { 00239 return $this->OriginalPasswordConfirm; 00240 } 00241 00242 function setOriginalPasswordConfirm( $password ) 00243 { 00244 $this->OriginalPasswordConfirm = $password; 00245 } 00246 00247 function hasStoredLogin() 00248 { 00249 $db = eZDB::instance(); 00250 $contentObjectID = $this->attribute( 'contentobject_id' ); 00251 $sql = "SELECT * FROM ezuser WHERE contentobject_id='$contentObjectID' AND LENGTH( login ) > 0"; 00252 $rows = $db->arrayQuery( $sql ); 00253 return count( $rows ) > 0; 00254 } 00255 00256 /*! 00257 Fills in the \a $id, \a $login, \a $email and \a $password for the user 00258 and creates the proper password hash. 00259 */ 00260 function setInformation( $id, $login, $email, $password, $passwordConfirm = false ) 00261 { 00262 $this->setAttribute( "contentobject_id", $id ); 00263 $this->setAttribute( "email", $email ); 00264 $this->setAttribute( "login", $login ); 00265 if ( eZUser::validatePassword( $password ) and 00266 $password == $passwordConfirm ) // Cannot change login or password_hash without login and password 00267 { 00268 $this->setAttribute( "password_hash", eZUser::createHash( $login, $password, eZUser::site(), 00269 eZUser::hashType() ) ); 00270 $this->setAttribute( "password_hash_type", eZUser::hashType() ); 00271 } 00272 else 00273 { 00274 $this->setOriginalPassword( $password ); 00275 $this->setOriginalPasswordConfirm( $passwordConfirm ); 00276 } 00277 } 00278 00279 static function fetch( $id, $asObject = true ) 00280 { 00281 if ( !$id ) 00282 return null; 00283 return eZPersistentObject::fetchObject( eZUser::definition(), 00284 null, 00285 array( 'contentobject_id' => $id ), 00286 $asObject ); 00287 } 00288 00289 static function fetchByName( $login, $asObject = true ) 00290 { 00291 return eZPersistentObject::fetchObject( eZUser::definition(), 00292 null, 00293 array( 'LOWER( login )' => strtolower( $login ) ), 00294 $asObject ); 00295 } 00296 00297 static function fetchByEmail( $email, $asObject = true ) 00298 { 00299 return eZPersistentObject::fetchObject( eZUser::definition(), 00300 null, 00301 array( 'LOWER( email )' => strtolower( $email ) ), 00302 $asObject ); 00303 } 00304 00305 /*! 00306 \static 00307 \return a list of the logged in users. 00308 \param $asObject If false it will return a list with only the names of the users as elements and user ID as key, 00309 otherwise each entry is a eZUser object. 00310 \sa fetchLoggedInCount 00311 */ 00312 static function fetchLoggedInList( $asObject = false, $offset = false, $limit = false, $sortBy = false ) 00313 { 00314 $db = eZDB::instance(); 00315 $time = time(); 00316 $ini = eZINI::instance(); 00317 $activityTimeout = $ini->variable( 'Session', 'ActivityTimeout' ); 00318 $sessionTimeout = $ini->variable( 'Session', 'SessionTimeout' ); 00319 $time = $time + $sessionTimeout - $activityTimeout; 00320 00321 $parameters = array(); 00322 if ( $offset ) 00323 $parameters['offset'] =(int) $offset; 00324 if ( $limit ) 00325 $parameters['limit'] =(int) $limit; 00326 $sortText = ''; 00327 if ( $asObject ) 00328 { 00329 $selectArray = array( "distinct ezuser.*" ); 00330 } 00331 else 00332 { 00333 $selectArray = array( "ezuser.contentobject_id as user_id", "ezcontentobject.name" ); 00334 } 00335 if ( $sortBy !== false ) 00336 { 00337 $sortElements = array(); 00338 if ( !is_array( $sortBy ) ) 00339 { 00340 $sortBy = array( array( $sortBy, true ) ); 00341 } 00342 else if ( !is_array( $sortBy[0] ) ) 00343 $sortBy = array( $sortBy ); 00344 $sortColumns = array(); 00345 foreach ( $sortBy as $sortElements ) 00346 { 00347 $sortColumn = $sortElements[0]; 00348 $sortOrder = $sortElements[1]; 00349 $orderText = $sortOrder ? 'asc' : 'desc'; 00350 switch ( $sortColumn ) 00351 { 00352 case 'user_id': 00353 { 00354 $sortColumn = "ezuser.contentobject_id $orderText"; 00355 } break; 00356 00357 case 'login': 00358 { 00359 $sortColumn = "ezuser.login $orderText"; 00360 } break; 00361 00362 case 'activity': 00363 { 00364 $selectArray[] = "( ezsession.expiration_time - " . ( $sessionTimeout - $activityTimeout ) . " ) AS activity"; 00365 $sortColumn = "activity $orderText"; 00366 } break; 00367 00368 case 'email': 00369 { 00370 $sortColumn = "ezuser.email $orderText"; 00371 } break; 00372 00373 default: 00374 { 00375 eZDebug::writeError( "Unkown sort column '$sortColumn'", 'eZUser::fetchLoggedInList' ); 00376 $sortColumn = false; 00377 } break; 00378 } 00379 if ( $sortColumn ) 00380 $sortColumns[] = $sortColumn; 00381 } 00382 if ( count( $sortColumns ) > 0 ) 00383 $sortText = "ORDER BY " . implode( ', ', $sortColumns ); 00384 } 00385 if ( $asObject ) 00386 { 00387 $selectText = implode( ', ', $selectArray ); 00388 $sql = "SELECT $selectText 00389 FROM ezsession, ezuser 00390 WHERE ezsession.user_id != '" . self::anonymousId() . "' AND 00391 ezsession.expiration_time > '$time' AND 00392 ezuser.contentobject_id = ezsession.user_id 00393 $sortText"; 00394 $rows = $db->arrayQuery( $sql, $parameters ); 00395 $list = array(); 00396 foreach ( $rows as $row ) 00397 { 00398 $list[] = new eZUser( $row ); 00399 } 00400 } 00401 else 00402 { 00403 $selectText = implode( ', ', $selectArray ); 00404 $sql = "SELECT $selectText 00405 FROM ezsession, ezuser, ezcontentobject 00406 WHERE ezsession.user_id != '" . self::anonymousId() . "' AND 00407 ezsession.expiration_time > '$time' AND 00408 ezuser.contentobject_id = ezsession.user_id AND 00409 ezcontentobject.id = ezuser.contentobject_id 00410 $sortText"; 00411 $rows = $db->arrayQuery( $sql, $parameters ); 00412 $list = array(); 00413 foreach ( $rows as $row ) 00414 { 00415 $list[$row['user_id']] = $row['name']; 00416 } 00417 } 00418 return $list; 00419 } 00420 00421 /*! 00422 \return the number of logged in users in the system. 00423 \note The count will be cached for the current page if caching is allowed. 00424 \sa fetchAnonymousCount 00425 */ 00426 static function fetchLoggedInCount() 00427 { 00428 if ( isset( $GLOBALS['eZSiteBasics']['no-cache-adviced'] ) and 00429 !$GLOBALS['eZSiteBasics']['no-cache-adviced'] and 00430 isset( $GLOBALS['eZUserLoggedInCount'] ) ) 00431 return $GLOBALS['eZUserLoggedInCount']; 00432 $db = eZDB::instance(); 00433 $time = time(); 00434 $ini = eZINI::instance(); 00435 $activityTimeout = $ini->variable( 'Session', 'ActivityTimeout' ); 00436 $sessionTimeout = $ini->variable( 'Session', 'SessionTimeout' ); 00437 $time = $time + $sessionTimeout - $activityTimeout; 00438 00439 $sql = "SELECT count( DISTINCT user_id ) as count 00440 FROM ezsession 00441 WHERE user_id != '" . self::anonymousId() . "' AND 00442 user_id > 0 AND 00443 expiration_time > '$time'"; 00444 $rows = $db->arrayQuery( $sql ); 00445 $count = ( count( $rows ) > 0 ) ? $rows[0]['count'] : 0; 00446 $GLOBALS['eZUserLoggedInCount'] = $count; 00447 return $count; 00448 } 00449 00450 /*! 00451 \static 00452 \return the number of anonymous users in the system. 00453 \sa fetchLoggedInCount 00454 */ 00455 static function fetchAnonymousCount() 00456 { 00457 if ( isset( $GLOBALS['eZSiteBasics']['no-cache-adviced'] ) and 00458 !$GLOBALS['eZSiteBasics']['no-cache-adviced'] and 00459 isset( $GLOBALS['eZUserAnonymousCount'] ) ) 00460 return $GLOBALS['eZUserAnonymousCount']; 00461 $db = eZDB::instance(); 00462 $time = time(); 00463 $ini = eZINI::instance(); 00464 $activityTimeout = $ini->variable( 'Session', 'ActivityTimeout' ); 00465 $sessionTimeout = $ini->variable( 'Session', 'SessionTimeout' ); 00466 $time = $time + $sessionTimeout - $activityTimeout; 00467 00468 $sql = "SELECT count( session_key ) as count 00469 FROM ezsession 00470 WHERE user_id = '" . self::anonymousId() . "' AND 00471 expiration_time > '$time'"; 00472 $rows = $db->arrayQuery( $sql ); 00473 $count = ( count( $rows ) > 0 ) ? $rows[0]['count'] : 0; 00474 $GLOBALS['eZUserAnonymousCount'] = $count; 00475 return $count; 00476 } 00477 00478 /*! 00479 \static 00480 \return true if the user with ID $userID is currently logged into the system. 00481 \note The information will be cached for the current page if caching is allowed. 00482 \sa fetchLoggedInList 00483 */ 00484 static function isUserLoggedIn( $userID ) 00485 { 00486 $userID = (int)$userID; 00487 if ( isset( $GLOBALS['eZSiteBasics']['no-cache-adviced'] ) and 00488 !$GLOBALS['eZSiteBasics']['no-cache-adviced'] and 00489 isset( $GLOBALS['eZUserLoggedInMap'][$userID] ) ) 00490 return $GLOBALS['eZUserLoggedInMap'][$userID]; 00491 $db = eZDB::instance(); 00492 $time = time(); 00493 $ini = eZINI::instance(); 00494 $activityTimeout = $ini->variable( 'Session', 'ActivityTimeout' ); 00495 $sessionTimeout = $ini->variable( 'Session', 'SessionTimeout' ); 00496 $time = $time + $sessionTimeout - $activityTimeout; 00497 00498 $sql = "SELECT DISTINCT user_id 00499 FROM ezsession 00500 WHERE user_id = '" . $userID . "' AND 00501 expiration_time > '$time'"; 00502 $rows = $db->arrayQuery( $sql, array( 'limit' => 2 ) ); 00503 $isLoggedIn = count( $rows ) > 0; 00504 $GLOBALS['eZUserLoggedInMap'][$userID] = $isLoggedIn; 00505 return $isLoggedIn; 00506 } 00507 00508 /*! 00509 \static 00510 Removes any cached session information, this is: 00511 - logged in user count 00512 - anonymous user count 00513 - logged in user map 00514 */ 00515 static function clearSessionCache() 00516 { 00517 unset( $GLOBALS['eZUserLoggedInCount'] ); 00518 unset( $GLOBALS['eZUserAnonymousCount'] ); 00519 unset( $GLOBALS['eZUserLoggedInMap'] ); 00520 } 00521 00522 /*! 00523 \static 00524 Remove session data for user \a $userID. 00525 */ 00526 static function removeSessionData( $userID ) 00527 { 00528 eZUser::clearSessionCache(); 00529 $db = eZDB::instance(); 00530 $userID = (int)$userID; 00531 $db->query( 'DELETE FROM ezsession WHERE user_id = \'' . $userID . '\'' ); 00532 } 00533 00534 /*! 00535 Removes the user from the ezuser table. 00536 \note Will also remove any notifications and session related to the user. 00537 */ 00538 static function removeUser( $userID ) 00539 { 00540 $user = eZUser::fetch( $userID ); 00541 if ( !$user ) 00542 { 00543 eZDebug::writeError( "unable to find user with ID $userID", 'eZUser::removeUser()' ); 00544 return false; 00545 } 00546 00547 eZUser::removeSessionData( $userID ); 00548 00549 eZSubtreeNotificationRule::removeByUserID( $userID ); 00550 eZCollaborationNotificationRule::removeByUserID( $userID ); 00551 eZUserSetting::removeByUserID( $userID ); 00552 eZUserAccountKey::removeByUserID( $userID ); 00553 eZForgotPassword::removeByUserID( $userID ); 00554 eZWishList::removeByUserID( $userID ); 00555 00556 // only remove general digest setting if there are no other users with the same e-mail 00557 $email = $user->attribute( 'email' ); 00558 $usersWithEmailCount = eZPersistentObject::count( eZUser::definition(), array( 'email' => $email ) ); 00559 if ( $usersWithEmailCount == 1 ) 00560 { 00561 eZGeneralDigestUserSettings::removeByAddress( $email ); 00562 } 00563 00564 eZPersistentObject::removeObject( eZUser::definition(), 00565 array( 'contentobject_id' => $userID ) ); 00566 return true; 00567 } 00568 00569 /*! 00570 \return a list of valid and enabled users, the data returned is an array 00571 with ezcontentobject database data. 00572 */ 00573 static function fetchContentList() 00574 { 00575 $contentObjectStatus = eZContentObject::STATUS_PUBLISHED; 00576 $query = "SELECT ezcontentobject.* 00577 FROM ezuser, ezcontentobject, ezuser_setting 00578 WHERE ezcontentobject.status = '$contentObjectStatus' AND 00579 ezuser_setting.is_enabled = 1 AND 00580 ezcontentobject.id = ezuser.contentobject_id AND 00581 ezuser_setting.user_id = ezuser.contentobject_id"; 00582 $db = eZDB::instance(); 00583 $rows = $db->arrayQuery( $query ); 00584 return $rows; 00585 } 00586 00587 /*! 00588 \static 00589 \return the default hash type which is specified in UserSettings/HashType in site.ini 00590 */ 00591 static function hashType() 00592 { 00593 $ini = eZINI::instance(); 00594 $type = strtolower( $ini->variable( 'UserSettings', 'HashType' ) ); 00595 if ( $type == 'md5_site' ) 00596 return self::PASSWORD_HASH_MD5_SITE; 00597 else if ( $type == 'md5_user' ) 00598 return self::PASSWORD_HASH_MD5_USER; 00599 else if ( $type == 'plaintext' ) 00600 return self::PASSWORD_HASH_PLAINTEXT; 00601 else if ( $type == 'crypt' ) 00602 return self::PASSWORD_HASH_CRYPT; 00603 else 00604 return self::PASSWORD_HASH_MD5_PASSWORD; 00605 } 00606 00607 /*! 00608 \static 00609 \return the site name used in password hashing. 00610 */ 00611 static function site() 00612 { 00613 $ini = eZINI::instance(); 00614 return $ini->variable( 'UserSettings', 'SiteName' ); 00615 } 00616 00617 /*! 00618 Fetches a builtin user and returns it, this helps avoid special cases where 00619 user is not logged in. 00620 */ 00621 static function fetchBuiltin( $id ) 00622 { 00623 if ( !in_array( $id, $GLOBALS['eZUserBuiltins'] ) ) 00624 $id = self::anonymousId(); 00625 if ( empty( $GLOBALS["eZUserBuilitinInstance-$id"] ) ) 00626 { 00627 $GLOBALS["eZUserBuilitinInstance-$id"] = eZUser::fetch( self::anonymousId() ); 00628 } 00629 return $GLOBALS["eZUserBuilitinInstance-$id"]; 00630 } 00631 00632 00633 /*! 00634 \return the user id. 00635 */ 00636 function id() 00637 { 00638 return $this->ContentObjectID; 00639 } 00640 00641 /*! 00642 \return a bitfield which decides the authenticate methods. 00643 */ 00644 static function authenticationMatch() 00645 { 00646 $ini = eZINI::instance(); 00647 $matchArray = $ini->variableArray( 'UserSettings', 'AuthenticateMatch' ); 00648 $match = 0; 00649 foreach ( $matchArray as $matchItem ) 00650 { 00651 switch ( $matchItem ) 00652 { 00653 case "login": 00654 { 00655 $match = ( $match | self::AUTHENTICATE_LOGIN ); 00656 } break; 00657 case "email": 00658 { 00659 $match = ( $match | self::AUTHENTICATE_EMAIL ); 00660 } break; 00661 } 00662 } 00663 return $match; 00664 } 00665 00666 /*! 00667 \return \c true if there can only be one instance of an email address on the site. 00668 */ 00669 static function requireUniqueEmail() 00670 { 00671 $ini = eZINI::instance(); 00672 return $ini->variable( 'UserSettings', 'RequireUniqueEmail' ) == 'true'; 00673 } 00674 00675 /** 00676 * Logs in the user if applied username and password is valid. 00677 * 00678 * @param string $login 00679 * @param string $password 00680 * @param bool $authenticationMatch 00681 * @return mixed eZUser on success, bool false on failure 00682 */ 00683 public static function loginUser( $login, $password, $authenticationMatch = false ) 00684 { 00685 $user = self::_loginUser( $login, $password, $authenticationMatch ); 00686 00687 if ( is_object( $user ) ) 00688 { 00689 self::loginSucceeded( $user ); 00690 return $user; 00691 } 00692 else 00693 { 00694 self::loginFailed( $user, $login ); 00695 return false; 00696 } 00697 } 00698 00699 /** 00700 * Does some house keeping work once a log in has succeeded. 00701 * 00702 * @param eZUser $user 00703 */ 00704 protected static function loginSucceeded( $user ) 00705 { 00706 $userID = $user->attribute( 'contentobject_id' ); 00707 00708 // if audit is enabled logins should be logged 00709 eZAudit::writeAudit( 'user-login', array( 'User id' => $userID, 'User login' => $user->attribute( 'login' ) ) ); 00710 00711 eZUser::updateLastVisit( $userID, true ); 00712 eZUser::setCurrentlyLoggedInUser( $user, $userID ); 00713 00714 // Reset number of failed login attempts 00715 eZUser::setFailedLoginAttempts( $userID, 0 ); 00716 } 00717 00718 /** 00719 * Does some house keeping work when a log in has failed. 00720 * 00721 * @param mixed $userID 00722 * @param string $login 00723 */ 00724 protected static function loginFailed( $userID = false, $login ) 00725 { 00726 $loginEscaped = eZDB::instance()->escapeString( $login ); 00727 00728 // Failed login attempts should be logged 00729 eZAudit::writeAudit( 'user-failed-login', array( 'User login' => $loginEscaped, 00730 'Comment' => 'Failed login attempt: eZUser::loginUser()' ) ); 00731 00732 // Increase number of failed login attempts. 00733 if ( $userID ) 00734 eZUser::setFailedLoginAttempts( $userID ); 00735 } 00736 00737 /** 00738 * Logs in an user if applied login and password is valid. 00739 * 00740 * This method does not do any house keeping work anymore (writing audits, etc). 00741 * When you call this method make sure to call loginSucceeded() or loginFailed() 00742 * depending on the success of the login. 00743 * 00744 * @param string $login 00745 * @param string $password 00746 * @param bool $authenticationMatch 00747 * @return mixed eZUser object on log in success, int userID if the username 00748 * exists but log in failed, or false if the username doesn't exists. 00749 */ 00750 protected static function _loginUser( $login, $password, $authenticationMatch = false ) 00751 { 00752 $http = eZHTTPTool::instance(); 00753 $db = eZDB::instance(); 00754 00755 if ( $authenticationMatch === false ) 00756 $authenticationMatch = eZUser::authenticationMatch(); 00757 00758 $loginEscaped = $db->escapeString( $login ); 00759 $passwordEscaped = $db->escapeString( $password ); 00760 00761 $loginArray = array(); 00762 if ( $authenticationMatch & self::AUTHENTICATE_LOGIN ) 00763 $loginArray[] = "login='$loginEscaped'"; 00764 if ( $authenticationMatch & self::AUTHENTICATE_EMAIL ) 00765 { 00766 if ( eZMail::validate( $login ) ) 00767 { 00768 $loginArray[] = "email='$loginEscaped'"; 00769 } 00770 } 00771 if ( count( $loginArray ) == 0 ) 00772 $loginArray[] = "login='$loginEscaped'"; 00773 $loginText = implode( ' OR ', $loginArray ); 00774 00775 $contentObjectStatus = eZContentObject::STATUS_PUBLISHED; 00776 00777 $ini = eZINI::instance(); 00778 $databaseName = $db->databaseName(); 00779 // if mysql 00780 if ( $databaseName === 'mysql' ) 00781 { 00782 $query = "SELECT contentobject_id, password_hash, password_hash_type, email, login 00783 FROM ezuser, ezcontentobject 00784 WHERE ( $loginText ) AND 00785 ezcontentobject.status='$contentObjectStatus' AND 00786 ezcontentobject.id=contentobject_id AND 00787 ( ( password_hash_type!=4 ) OR 00788 ( password_hash_type=4 AND 00789 ( $loginText ) AND 00790 password_hash=PASSWORD('$passwordEscaped') ) )"; 00791 } 00792 else 00793 { 00794 $query = "SELECT contentobject_id, password_hash, 00795 password_hash_type, email, login 00796 FROM ezuser, ezcontentobject 00797 WHERE ( $loginText ) 00798 AND ezcontentobject.status='$contentObjectStatus' 00799 AND ezcontentobject.id=contentobject_id"; 00800 } 00801 00802 $users = $db->arrayQuery( $query ); 00803 $exists = false; 00804 if ( $users !== false and count( $users ) >= 1 ) 00805 { 00806 $ini = eZINI::instance(); 00807 foreach ( $users as $userRow ) 00808 { 00809 $userID = $userRow['contentobject_id']; 00810 $hashType = $userRow['password_hash_type']; 00811 $hash = $userRow['password_hash']; 00812 $exists = eZUser::authenticateHash( $userRow['login'], $password, eZUser::site(), 00813 $hashType, 00814 $hash ); 00815 00816 // If hash type is MySql 00817 if ( $hashType == self::PASSWORD_HASH_MYSQL and $databaseName === 'mysql' ) 00818 { 00819 $queryMysqlUser = "SELECT contentobject_id, password_hash, password_hash_type, email, login 00820 FROM ezuser, ezcontentobject 00821 WHERE ezcontentobject.status='$contentObjectStatus' AND 00822 password_hash_type=4 AND ( $loginText ) AND password_hash=PASSWORD('$passwordEscaped') "; 00823 $mysqlUsers = $db->arrayQuery( $queryMysqlUser ); 00824 if ( count( $mysqlUsers ) >= 1 ) 00825 $exists = true; 00826 00827 } 00828 00829 eZDebugSetting::writeDebug( 'kernel-user', eZUser::createHash( $userRow['login'], $password, eZUser::site(), 00830 $hashType, $hash ), "check hash" ); 00831 eZDebugSetting::writeDebug( 'kernel-user', $hash, "stored hash" ); 00832 // If current user has been disabled after a few failed login attempts. 00833 $canLogin = eZUser::isEnabledAfterFailedLogin( $userID ); 00834 00835 if ( $exists ) 00836 { 00837 // We should store userID for warning message. 00838 $GLOBALS['eZFailedLoginAttemptUserID'] = $userID; 00839 00840 $userSetting = eZUserSetting::fetch( $userID ); 00841 $isEnabled = $userSetting->attribute( "is_enabled" ); 00842 if ( $hashType != eZUser::hashType() and 00843 strtolower( $ini->variable( 'UserSettings', 'UpdateHash' ) ) == 'true' ) 00844 { 00845 $hashType = eZUser::hashType(); 00846 $hash = eZUser::createHash( $userRow['login'], $password, eZUser::site(), 00847 $hashType ); 00848 $db->query( "UPDATE ezuser SET password_hash='$hash', password_hash_type='$hashType' WHERE contentobject_id='$userID'" ); 00849 } 00850 break; 00851 } 00852 } 00853 } 00854 00855 if ( $exists and $isEnabled and $canLogin ) 00856 { 00857 return new eZUser( $userRow ); 00858 } 00859 else 00860 { 00861 return isset( $userID ) ? $userID : false; 00862 } 00863 } 00864 00865 /*! 00866 \static 00867 Checks if IP address of current user is in \a $ipList. 00868 */ 00869 static function isUserIPInList( $ipList ) 00870 { 00871 $ipAddress = eZSys::serverVariable( 'REMOTE_ADDR', true ); 00872 if ( $ipAddress ) 00873 { 00874 $result = false; 00875 foreach( $ipList as $itemToMatch ) 00876 { 00877 if ( preg_match("/^(([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+))(\/([0-9]+)$|$)/", $itemToMatch, $matches ) ) 00878 { 00879 if ( $matches[6] ) 00880 { 00881 if ( eZDebug::isIPInNet( $ipAddress, $matches[1], $matches[7] ) ) 00882 { 00883 $result = true; 00884 break; 00885 } 00886 } 00887 else 00888 { 00889 if ( $matches[1] == $ipAddress ) 00890 { 00891 $result = true; 00892 break; 00893 } 00894 } 00895 } 00896 } 00897 } 00898 else 00899 { 00900 $result = ( 00901 in_array( 'commandline', $ipList ) && 00902 ( php_sapi_name() == 'cli' ) 00903 ); 00904 } 00905 return $result; 00906 } 00907 00908 /*! 00909 \static 00910 Returns true if current user is trusted user. 00911 */ 00912 static function isTrusted() 00913 { 00914 $ini = eZINI::instance(); 00915 00916 // Check if current user is trusted user. 00917 $trustedIPs = $ini->hasVariable( 'UserSettings', 'TrustedIPList' ) ? $ini->variable( 'UserSettings', 'TrustedIPList' ) : array(); 00918 00919 // Check if IP address of current user is in $trustedIPs array. 00920 $trustedUser = eZUser::isUserIPInList( $trustedIPs ); 00921 if ( $trustedUser ) 00922 return true; 00923 00924 return false; 00925 } 00926 00927 /*! 00928 \static 00929 Returns max number of failed login attempts. 00930 */ 00931 static function maxNumberOfFailedLogin() 00932 { 00933 $ini = eZINI::instance(); 00934 00935 $maxNumberOfFailedLogin = $ini->hasVariable( 'UserSettings', 'MaxNumberOfFailedLogin' ) ? $ini->variable( 'UserSettings', 'MaxNumberOfFailedLogin' ) : '0'; 00936 return $maxNumberOfFailedLogin; 00937 } 00938 00939 /* 00940 \static 00941 Returns true if the user can login 00942 If user has number of failed login attempts more than eZUser::maxNumberOfFailedLogin() 00943 and user is not trusted 00944 the user will not be allowed to login. 00945 */ 00946 static function isEnabledAfterFailedLogin( $userID, $ignoreTrusted = false ) 00947 { 00948 if ( !is_numeric( $userID ) ) 00949 return true; 00950 00951 $userObject = eZUser::fetch( $userID ); 00952 if ( !$userObject ) 00953 return true; 00954 00955 $trustedUser = eZUser::isTrusted(); 00956 // If user is trusted we should stop processing 00957 if ( $trustedUser and !$ignoreTrusted ) 00958 return true; 00959 00960 $maxNumberOfFailedLogin = eZUser::maxNumberOfFailedLogin(); 00961 00962 if ( $maxNumberOfFailedLogin == '0' ) 00963 return true; 00964 00965 $failedLoginAttempts = $userObject->failedLoginAttempts(); 00966 if ( $failedLoginAttempts > $maxNumberOfFailedLogin ) 00967 return false; 00968 00969 return true; 00970 } 00971 00972 /*! 00973 \protected 00974 Makes sure the user \a $user is set as the currently logged in user by 00975 updating the session and setting the necessary global variables. 00976 00977 All login handlers should use this function to ensure that the process 00978 is executed properly. 00979 */ 00980 static function setCurrentlyLoggedInUser( $user, $userID ) 00981 { 00982 $http = eZHTTPTool::instance(); 00983 00984 $GLOBALS["eZUserGlobalInstance_$userID"] = $user; 00985 // Set/overwrite the global user, this will be accessed from 00986 // instance() when there is no ID passed to the function. 00987 $GLOBALS["eZUserGlobalInstance_"] = $user; 00988 eZSession::setUserID( $userID ); 00989 $http->setSessionVariable( 'eZUserLoggedInID', $userID ); 00990 self::cleanup(); 00991 eZSession::regenerate(); 00992 } 00993 00994 /*! 00995 \virtual 00996 Used by login handler to clean up session variables 00997 */ 00998 function sessionCleanup() 00999 { 01000 } 01001 01002 /*! 01003 \static 01004 Cleans up any cache or session variables that are set. 01005 This at least called on login and logout but can be used other places 01006 where you must ensure that the cache user values are refetched. 01007 \param deprecated 01008 */ 01009 static function cleanup() 01010 { 01011 $http = eZHTTPTool::instance(); 01012 $http->setSessionVariable( 'eZUserGroupsCache_Timestamp', false ); 01013 $http->removeSessionVariable( 'eZUserGroupsCache' ); 01014 01015 $http->removeSessionVariable( 'eZUserInfoCache' ); 01016 01017 $http->removeSessionVariable( 'AccessArray' ); 01018 $http->removeSessionVariable( 'CanInstantiateClassesCachedForUser' ); 01019 $http->removeSessionVariable( 'CanInstantiateClassList' ); 01020 $http->removeSessionVariable( 'ClassesCachedForUser' ); 01021 $http->removeSessionVariable( 'eZRoleIDList' ); 01022 $http->setSessionVariable( 'eZRoleIDList_Timestamp', 0 ); 01023 $http->removeSessionVariable( 'eZRoleLimitationValueList' ); 01024 $http->setSessionVariable( 'eZRoleLimitationValueList_Timestamp', 0 ); 01025 01026 // Note: This must be done more generic with an internal 01027 // callback system. 01028 eZPreferences::sessionCleanup(); 01029 } 01030 01031 /*! 01032 \return logs in the current user object 01033 */ 01034 function loginCurrent() 01035 { 01036 $this->setCurrentlyLoggedInUser( $this, $this->ContentObjectID ); 01037 } 01038 01039 /*! 01040 \static 01041 Logs out the current user 01042 */ 01043 static function logoutCurrent() 01044 { 01045 $http = eZHTTPTool::instance(); 01046 $id = false; 01047 $GLOBALS["eZUserGlobalInstance_$id"] = false; 01048 $contentObjectID = $http->sessionVariable( 'eZUserLoggedInID' ); 01049 01050 // reset session data 01051 $newUserID = self::anonymousId(); 01052 eZSession::setUserID( $newUserID ); 01053 $http->setSessionVariable( 'eZUserLoggedInID', $newUserID ); 01054 01055 // Clear current basket if necessary 01056 $db = eZDB::instance(); 01057 $db->begin(); 01058 eZBasket::cleanupCurrentBasket(); 01059 $db->commit(); 01060 01061 if ( $contentObjectID ) 01062 eZUser::cleanup(); 01063 01064 // give user new session id 01065 eZSession::regenerate(); 01066 01067 // set the property used to prevent SSO from running again 01068 self::$userHasLoggedOut = true; 01069 } 01070 01071 /*! 01072 Finds the user with the id \a $id and returns the unique instance of it. 01073 If the user instance is not created yet it tries to either fetch it from the 01074 database with eZUser::fetch(). If $id is false or the user was not found, the 01075 default user is returned. This is a site.ini setting under UserSettings:AnonymousUserID. 01076 The instance is then returned. 01077 If \a $id is false then the current user is fetched. 01078 */ 01079 static function instance( $id = false ) 01080 { 01081 if ( !empty( $GLOBALS["eZUserGlobalInstance_$id"] ) ) 01082 { 01083 return $GLOBALS["eZUserGlobalInstance_$id"]; 01084 } 01085 01086 $userId = $id; 01087 $currentUser = null; 01088 $http = eZHTTPTool::instance(); 01089 // If not specified get the current user 01090 if ( $userId === false ) 01091 { 01092 $userId = $http->sessionVariable( 'eZUserLoggedInID' ); 01093 01094 if ( !is_numeric( $userId ) ) 01095 { 01096 $userId = self::anonymousId(); 01097 eZSession::setUserID( $userId ); 01098 $http->setSessionVariable( 'eZUserLoggedInID', $userId ); 01099 } 01100 } 01101 01102 $fetchFromDB = true; 01103 01104 // Check session cache 01105 eZExpiryHandler::registerShutdownFunction(); 01106 $handler = eZExpiryHandler::instance(); 01107 $expiredTimeStamp = 0; 01108 if ( $handler->hasTimestamp( 'user-info-cache' ) ) 01109 $expiredTimeStamp = $handler->timestamp( 'user-info-cache' ); 01110 01111 $userArrayTimestamp = $http->sessionVariable( 'eZUserInfoCache_Timestamp' ); 01112 01113 if ( $userArrayTimestamp > $expiredTimeStamp ) 01114 { 01115 $userInfo = array(); 01116 if ( $http->hasSessionVariable( 'eZUserInfoCache' ) ) 01117 $userInfo = $http->sessionVariable( 'eZUserInfoCache' ); 01118 01119 if ( isset( $userInfo[$userId] ) ) 01120 { 01121 $userArray = $userInfo[$userId]; 01122 01123 if ( is_numeric( $userArray['contentobject_id'] ) ) 01124 { 01125 $currentUser = new eZUser( $userArray ); 01126 $fetchFromDB = false; 01127 } 01128 } 01129 } 01130 01131 if ( $fetchFromDB == true ) 01132 { 01133 $currentUser = eZUser::fetch( $userId ); 01134 01135 if ( $currentUser ) 01136 { 01137 $userInfo = array(); 01138 $userInfo[$userId] = array( 'contentobject_id' => $currentUser->attribute( 'contentobject_id' ), 01139 'login' => $currentUser->attribute( 'login' ), 01140 'email' => $currentUser->attribute( 'email' ), 01141 'password_hash' => $currentUser->attribute( 'password_hash' ), 01142 'password_hash_type' => $currentUser->attribute( 'password_hash_type' ) 01143 ); 01144 eZSession::setUserID( $userId ); 01145 $http->setSessionVariable( 'eZUserInfoCache', $userInfo ); 01146 $http->setSessionVariable( 'eZUserInfoCache_Timestamp', time() ); 01147 } 01148 } 01149 01150 $ini = eZINI::instance(); 01151 01152 // Check if: 01153 // - the user has not logged out, 01154 // - the user is not logged in, 01155 // - and if a automatic single sign on plugin is enabled. 01156 if ( !self::$userHasLoggedOut and is_object( $currentUser ) and !$currentUser->isLoggedIn() ) 01157 { 01158 $ssoHandlerArray = $ini->variable( 'UserSettings', 'SingleSignOnHandlerArray' ); 01159 if ( count( $ssoHandlerArray ) > 0 ) 01160 { 01161 $ssoUser = false; 01162 foreach ( $ssoHandlerArray as $ssoHandler ) 01163 { 01164 // Load handler 01165 $handlerFile = 'kernel/classes/ssohandlers/ez' . strtolower( $ssoHandler ) . 'ssohandler.php'; 01166 if ( file_exists( $handlerFile ) ) 01167 { 01168 include_once( $handlerFile ); 01169 $className = 'eZ' . $ssoHandler . 'SSOHandler'; 01170 $impl = new $className(); 01171 $ssoUser = $impl->handleSSOLogin(); 01172 } 01173 else // check in extensions 01174 { 01175 $ini = eZINI::instance(); 01176 $extensionDirectories = $ini->variable( 'UserSettings', 'ExtensionDirectory' ); 01177 $directoryList = eZExtension::expandedPathList( $extensionDirectories, 'sso_handler' ); 01178 foreach( $directoryList as $directory ) 01179 { 01180 $handlerFile = $directory . '/ez' . strtolower( $ssoHandler ) . 'ssohandler.php'; 01181 if ( file_exists( $handlerFile ) ) 01182 { 01183 include_once( $handlerFile ); 01184 $className = 'eZ' . $ssoHandler . 'SSOHandler'; 01185 $impl = new $className(); 01186 $ssoUser = $impl->handleSSOLogin(); 01187 } 01188 } 01189 } 01190 } 01191 // If a user was found via SSO, then use it 01192 if ( $ssoUser !== false ) 01193 { 01194 $currentUser = $ssoUser; 01195 01196 $userInfo = array(); 01197 $userInfo[$userId] = array( 'contentobject_id' => $currentUser->attribute( 'contentobject_id' ), 01198 'login' => $currentUser->attribute( 'login' ), 01199 'email' => $currentUser->attribute( 'email' ), 01200 'password_hash' => $currentUser->attribute( 'password_hash' ), 01201 'password_hash_type' => $currentUser->attribute( 'password_hash_type' ) 01202 ); 01203 eZSession::setUserID( $userId ); 01204 $http->setSessionVariable( 'eZUserInfoCache', $userInfo ); 01205 $http->setSessionVariable( 'eZUserInfoCache_Timestamp', time() ); 01206 $http->setSessionVariable( 'eZUserLoggedInID', $userId ); 01207 01208 eZUser::updateLastVisit( $currentUser->attribute( 'contentobject_id' ) ); 01209 eZUser::setCurrentlyLoggedInUser( $currentUser, $currentUser->attribute( 'contentobject_id' ) ); 01210 eZHTTPTool::redirect( eZSys::wwwDir() . eZSys::indexFile( false ) . eZSys::requestURI(), array(), 302 ); 01211 01212 } 01213 } 01214 } 01215 01216 $anonymousUserID = self::anonymousId(); 01217 if ( $userId <> $anonymousUserID ) 01218 { 01219 $sessionInactivityTimeout = $ini->variable( 'Session', 'ActivityTimeout' ); 01220 if ( !isset( $GLOBALS['eZSessionIdleTime'] ) ) 01221 { 01222 eZUser::updateLastVisit( $userId ); 01223 } 01224 else 01225 { 01226 $sessionIdle = $GLOBALS['eZSessionIdleTime']; 01227 if ( $sessionIdle > $sessionInactivityTimeout ) 01228 { 01229 eZUser::updateLastVisit( $userId ); 01230 } 01231 } 01232 } 01233 01234 if ( !$currentUser ) 01235 { 01236 $currentUser = eZUser::fetch( self::anonymousId() ); 01237 eZDebug::writeWarning( 'User not found, returning anonymous' ); 01238 } 01239 01240 if ( !$currentUser ) 01241 { 01242 $currentUser = new eZUser( array( 'id' => -1, 'login' => 'NoUser' ) ); 01243 01244 eZDebug::writeWarning( 'Anonymous user not found, returning NoUser' ); 01245 } 01246 01247 $GLOBALS["eZUserGlobalInstance_$id"] = $currentUser; 01248 return $currentUser; 01249 } 01250 01251 /*! 01252 Updates the user's last visit timestamp 01253 Optionally updates user login count by setting $updateLoginCount to true 01254 */ 01255 static function updateLastVisit( $userID, $updateLoginCount = false ) 01256 { 01257 if ( isset( $GLOBALS['eZUserUpdatedLastVisit'] ) ) 01258 return; 01259 $db = eZDB::instance(); 01260 $userID = (int) $userID; 01261 $userVisitArray = $db->arrayQuery( "SELECT 1 FROM ezuservisit WHERE user_id=$userID" ); 01262 $time = time(); 01263 01264 if ( count( $userVisitArray ) == 1 ) 01265 { 01266 $loginCountSQL = $updateLoginCount ? ', login_count=login_count+1' : ''; 01267 $db->query( "UPDATE ezuservisit SET last_visit_timestamp=current_visit_timestamp, current_visit_timestamp=$time$loginCountSQL WHERE user_id=$userID" ); 01268 } 01269 else 01270 { 01271 $intialLoginCount = $updateLoginCount ? 1 : 0; 01272 $db->query( "INSERT INTO ezuservisit ( current_visit_timestamp, last_visit_timestamp, user_id, login_count ) VALUES ( $time, $time, $userID, $intialLoginCount )" ); 01273 } 01274 $GLOBALS['eZUserUpdatedLastVisit'] = true; 01275 } 01276 01277 /*! 01278 Returns the last visit timestamp to the current user. 01279 */ 01280 function lastVisit() 01281 { 01282 $db = eZDB::instance(); 01283 01284 $userVisitArray = $db->arrayQuery( "SELECT last_visit_timestamp FROM ezuservisit WHERE user_id=$this->ContentObjectID" ); 01285 if ( count( $userVisitArray ) == 1 ) 01286 { 01287 return $userVisitArray[0]['last_visit_timestamp']; 01288 } 01289 else 01290 { 01291 return time(); 01292 } 01293 } 01294 01295 /** 01296 * Returns the login count for the current user. 01297 * 01298 * @since Version 4.1 01299 * @return int Login count for current user. 01300 */ 01301 function loginCount() 01302 { 01303 $db = eZDB::instance(); 01304 $userVisitArray = $db->arrayQuery( "SELECT login_count FROM ezuservisit WHERE user_id=$this->ContentObjectID" ); 01305 if ( count( $userVisitArray ) == 1 ) 01306 { 01307 return $userVisitArray[0]['login_count']; 01308 } 01309 else 01310 { 01311 return 0; 01312 } 01313 } 01314 01315 /*! 01316 If \a $value is false will increase the user's number of failed login attempts 01317 otherwise failed_login_attempts will be updated by $value. 01318 \a $setByForce if true checking for trusting or max number of failed login attempts will be ignored. 01319 */ 01320 static function setFailedLoginAttempts( $userID, $value = false, $setByForce = false ) 01321 { 01322 $trustedUser = eZUser::isTrusted(); 01323 // If user is trusted we should stop processing 01324 if ( $trustedUser and !$setByForce ) 01325 return true; 01326 01327 $maxNumberOfFailedLogin = eZUser::maxNumberOfFailedLogin(); 01328 01329 if ( $maxNumberOfFailedLogin == '0' and !$setByForce ) 01330 return true; 01331 01332 $userID = (int) $userID; 01333 $userObject = eZUser::fetch( $userID ); 01334 if ( !$userObject ) 01335 return true; 01336 01337 $isEnabled = $userObject->isEnabled(); 01338 // If current user is disabled we should not continue 01339 if ( !$isEnabled and !$setByForce ) 01340 return true; 01341 01342 $db = eZDB::instance(); 01343 $db->begin(); 01344 01345 $userVisitArray = $db->arrayQuery( "SELECT 1 FROM ezuservisit WHERE user_id=$userID" ); 01346 01347 if ( count( $userVisitArray ) == 1 ) 01348 { 01349 if ( $value === false ) 01350 { 01351 $failedLoginAttempts = $userObject->failedLoginAttempts(); 01352 $failedLoginAttempts += 1; 01353 } 01354 else 01355 $failedLoginAttempts = (int) $value; 01356 01357 $db->query( "UPDATE ezuservisit SET failed_login_attempts=$failedLoginAttempts WHERE user_id=$userID" ); 01358 } 01359 else 01360 { 01361 if ( $value === false ) 01362 { 01363 $failedLoginAttempts = 1; 01364 } 01365 else 01366 $failedLoginAttempts = (int) $value; 01367 01368 $db->query( "INSERT INTO ezuservisit ( failed_login_attempts, user_id ) VALUES ( $failedLoginAttempts, $userID )" ); 01369 } 01370 $db->commit(); 01371 01372 eZContentCacheManager::clearContentCacheIfNeeded( $userID ); 01373 eZContentCacheManager::generateObjectViewCache( $userID ); 01374 } 01375 01376 /*! 01377 Returns the current user's number of failed login attempts. 01378 */ 01379 function failedLoginAttempts() 01380 { 01381 return eZUser::failedLoginAttemptsByUserID( $this->attribute( 'contentobject_id' ) ); 01382 } 01383 01384 /*! 01385 Returns the current user's number of failed login attempts. 01386 */ 01387 static function failedLoginAttemptsByUserID( $userID ) 01388 { 01389 $db = eZDB::instance(); 01390 $contentObjectID = (int) $userID; 01391 01392 $userVisitArray = $db->arrayQuery( "SELECT failed_login_attempts FROM ezuservisit WHERE user_id=$contentObjectID" ); 01393 01394 $failedLoginAttempts = count( $userVisitArray ) == 1 ? $userVisitArray[0]['failed_login_attempts'] : 0; 01395 return $failedLoginAttempts; 01396 } 01397 01398 /*! 01399 \return \c true if the user is locked (is enabled after failed login) and can be logged on the site. 01400 */ 01401 function isLocked() 01402 { 01403 $userID = $this->attribute( 'contentobject_id' ); 01404 $isNotLocked = eZUser::isEnabledAfterFailedLogin( $userID, true ); 01405 return !$isNotLocked; 01406 } 01407 01408 /*! 01409 \return \c true if the user is enabled and can be used on the site. 01410 */ 01411 function isEnabled() 01412 { 01413 if ( $this == eZUser::currentUser() ) 01414 { 01415 return true; 01416 } 01417 01418 $setting = eZUserSetting::fetch( $this->attribute( 'contentobject_id' ) ); 01419 if ( $setting and !$setting->attribute( 'is_enabled' ) ) 01420 { 01421 return false; 01422 } 01423 return true; 01424 } 01425 01426 /*! 01427 \return \c true if the user is the anonymous user. 01428 */ 01429 function isAnonymous() 01430 { 01431 if ( $this->attribute( 'contentobject_id' ) != self::anonymousId() ) 01432 { 01433 return false; 01434 } 01435 return true; 01436 } 01437 01438 /*! 01439 \static 01440 Returns the currently logged in user. 01441 */ 01442 static function currentUser() 01443 { 01444 $user = eZUser::instance(); 01445 return $user; 01446 } 01447 01448 /*! 01449 \static 01450 Returns the ID of the currently logged in user. 01451 */ 01452 static function currentUserID() 01453 { 01454 $user = eZUser::instance(); 01455 if ( !$user ) 01456 return 0; 01457 return $user->attribute( 'contentobject_id' ); 01458 } 01459 01460 /*! 01461 \static 01462 Creates a hash out of \a $user, \a $password and \a $site according to the type \a $type. 01463 \return true if the generated hash is equal to the supplied hash \a $hash. 01464 */ 01465 static function authenticateHash( $user, $password, $site, $type, $hash ) 01466 { 01467 return eZUser::createHash( $user, $password, $site, $type, $hash ) === (string) $hash; 01468 } 01469 01470 /*! 01471 \static 01472 \return an array with characters which are allowed in password. 01473 */ 01474 static function passwordCharacterTable() 01475 { 01476 if ( !empty( $GLOBALS['eZUserPasswordCharacterTable'] ) ) 01477 { 01478 return $GLOBALS['eZUserPasswordCharacterTable']; 01479 } 01480 $table = array_merge( range( 'a', 'z' ), range( 'A', 'Z' ), range( 0, 9 ) ); 01481 01482 $ini = eZINI::instance(); 01483 if ( $ini->variable( 'UserSettings', 'UseSpecialCharacters' ) == 'true' ) 01484 { 01485 $specialCharacters = '!#%&{[]}+?;:*'; 01486 $table = array_merge( $table, preg_split( '//', $specialCharacters, -1, PREG_SPLIT_NO_EMPTY ) ); 01487 } 01488 // Remove some characters that are too similar visually 01489 $table = array_diff( $table, array( 'I', 'l', 'o', 'O', '0' ) ); 01490 $tableTmp = $table; 01491 $table = array(); 01492 foreach ( $tableTmp as $item ) 01493 { 01494 $table[] = $item; 01495 } 01496 01497 return $GLOBALS['eZUserPasswordCharacterTable'] = $table; 01498 } 01499 01500 /*! 01501 Checks if the supplied content object is a user object ( contains ezuser datatype ) 01502 01503 \param ContentObject 01504 01505 \return true or false 01506 */ 01507 static function isUserObject( $contentObject ) 01508 { 01509 if ( !$contentObject ) 01510 { 01511 return false; 01512 } 01513 01514 eZDataType::loadAndRegisterType( 'ezuser' ); 01515 01516 $contentClass = $contentObject->attribute( 'content_class' ); 01517 $classAttributeList = $contentClass->fetchAttributes(); 01518 foreach( $classAttributeList as $classAttribute ) 01519 { 01520 if ( $classAttribute->attribute( 'data_type_string' ) == eZUserType::DATA_TYPE_STRING ) 01521 return true; 01522 } 01523 01524 return false; 01525 } 01526 01527 /*! 01528 \static 01529 Creates a password with number of characters equal to \a $passwordLength and returns it. 01530 If you want pass a value in \a $seed it will be used as basis for the password, if not 01531 it will use the current time value as seed. 01532 \note If \a $passwordLength exceeds 16 it will need to generate new seed for the remaining 01533 characters. 01534 */ 01535 static function createPassword( $passwordLength, $seed = false ) 01536 { 01537 $chars = 0; 01538 $password = ''; 01539 if ( $passwordLength < 1 ) 01540 $passwordLength = 1; 01541 $decimal = 0; 01542 while ( $chars < $passwordLength ) 01543 { 01544 if ( $seed == false ) 01545 $seed = time() . ":" . mt_rand(); 01546 $text = md5( $seed ); 01547 $characterTable = eZUser::passwordCharacterTable(); 01548 $tableCount = count( $characterTable ); 01549 for ( $i = 0; ( $chars < $passwordLength ) and $i < 32; ++$chars, $i += 2 ) 01550 { 01551 $decimal += hexdec( substr( $text, $i, 2 ) ); 01552 $index = ( $decimal % $tableCount ); 01553 $character = $characterTable[$index]; 01554 $password .= $character; 01555 } 01556 $seed = false; 01557 } 01558 return $password; 01559 } 01560 01561 /*! 01562 \static 01563 Will create a hash of the given string. This is used to store the passwords in the database. 01564 */ 01565 static function createHash( $user, $password, $site, $type, $hash = false ) 01566 { 01567 $str = ''; 01568 if( $type == self::PASSWORD_HASH_MD5_USER ) 01569 { 01570 $str = md5( "$user\n$password" ); 01571 } 01572 else if ( $type == self::PASSWORD_HASH_MD5_SITE ) 01573 { 01574 $str = md5( "$user\n$password\n$site" ); 01575 } 01576 else if ( $type == self::PASSWORD_HASH_MYSQL ) 01577 { 01578 $db = eZDB::instance(); 01579 $hash = $db->escapeString( $password ); 01580 01581 $str = $db->arrayQuery( "SELECT PASSWORD( '$hash' )" ); 01582 $hashes = array_values( $str[0] ); 01583 $str = $hashes[0]; 01584 } 01585 else if ( $type == self::PASSWORD_HASH_PLAINTEXT ) 01586 { 01587 $str = $password; 01588 } 01589 else if ( $type == self::PASSWORD_HASH_CRYPT ) 01590 { 01591 if ( $hash ) 01592 { 01593 $str = crypt( $password, $hash ); 01594 } 01595 else 01596 { 01597 $str = crypt( $password ); 01598 } 01599 } 01600 else // self::PASSWORD_HASH_MD5_PASSWORD 01601 { 01602 $str = md5( $password ); 01603 } 01604 eZDebugSetting::writeDebug( 'kernel-user', $str, "ezuser($type)" ); 01605 return $str; 01606 } 01607 01608 /*! 01609 Check if user has got access to the specified module and function 01610 01611 \param module name 01612 \param funtion name 01613 01614 \return Array containg result. 01615 Array elements : 'accessWord', yes - access allowed 01616 no - access denied 01617 limited - access array describing access included 01618 'policies', array containing the policy limitations 01619 'accessList', array describing missing access rights 01620 */ 01621 function hasAccessTo( $module, $function = false ) 01622 { 01623 $accessArray = $this->accessArray(); 01624 01625 $functionArray = array(); 01626 if ( isset( $accessArray['*']['*'] ) ) 01627 { 01628 $functionArray = $accessArray['*']['*']; 01629 } 01630 if ( isset( $accessArray[$module] ) ) 01631 { 01632 if ( isset( $accessArray[$module]['*'] ) ) 01633 { 01634 $functionArray = array_merge_recursive( $functionArray, $accessArray[$module]['*'] ); 01635 } 01636 if ( $function and isset( $accessArray[$module][$function] ) and $function != '*' ) 01637 { 01638 $functionArray = array_merge_recursive( $functionArray, $accessArray[$module][$function] ); 01639 } 01640 } 01641 01642 if ( !$functionArray ) 01643 { 01644 return array( 'accessWord' => 'no', 01645 'accessList' => array( 'FunctionRequired' => array ( 'Module' => $module, 01646 'Function' => $function, 01647 'ClassID' => '', 01648 'MainNodeID' => '' ), 01649 'PolicyList' => array() ) 01650 ); 01651 } 01652 01653 if ( isset( $functionArray['*'] ) && 01654 ( $functionArray['*'] == '*' || in_array( '*', $functionArray['*'] ) ) ) 01655 { 01656 return array( 'accessWord' => 'yes' ); 01657 } 01658 01659 return array( 'accessWord' => 'limited', 'policies' => $functionArray ); 01660 } 01661 01662 /* 01663 \private 01664 Returns either cached or newly generated accessArray for the user. 01665 */ 01666 function accessArray() 01667 { 01668 if ( !isset( $this->AccessArray ) ) 01669 { 01670 $ini = eZINI::instance(); 01671 $isRoleCachingEnabled = ( $ini->variable( 'RoleSettings', 'EnableCaching' ) == 'true' ); 01672 01673 $userID = $this->attribute( 'contentobject_id' ); 01674 $currentUserID = eZUser::currentUserID(); 01675 01676 $accessArray = false; 01677 01678 if ( $isRoleCachingEnabled ) 01679 { 01680 if ( $userID == $currentUserID ) 01681 { 01682 $http = eZHTTPTool::instance(); 01683 if ( $http->hasSessionVariable( 'AccessArray' ) and 01684 $http->hasSessionVariable( 'AccessArrayTimestamp' ) ) 01685 { 01686 $expiredTimestamp = $this->userInfoExpiry(); 01687 $userAccessTimestamp = $http->sessionVariable( 'AccessArrayTimestamp' ); 01688 if ( $userAccessTimestamp > $expiredTimestamp ) 01689 { 01690 $accessArray = $http->sessionVariable( 'AccessArray' ); 01691 } 01692 } 01693 } 01694 01695 if ( !$accessArray ) 01696 { 01697 $cacheFilePath = eZUser::getCacheFilename( $userID ); 01698 if ( $cacheFilePath ) 01699 { 01700 $cacheFile = eZClusterFileHandler::instance( $cacheFilePath ); 01701 $accessArray = $cacheFile->processCache( array( $this, 'retrieveAccessArrayFromCache' ), 01702 array( $this, 'generateAccessArrayForCache' ), 01703 null, 01704 $this->userInfoExpiry(), 01705 $userID ); 01706 if ( $userID == $currentUserID ) 01707 { 01708 // here is no need to get $http instance again because it is initialized 01709 // already above by the same condition's case ( userID == currentUserID ). 01710 $http->setSessionVariable( 'AccessArray', $accessArray ); 01711 $http->setSessionVariable( 'AccessArrayTimestamp', time() ); 01712 } 01713 } 01714 else 01715 { 01716 // if there is no cache file and no access array was fetched from 01717 // the current session then generate access array on-the-fly. 01718 $accessArray = $this->generateAccessArray(); 01719 } 01720 } 01721 } 01722 else 01723 { 01724 // if role caching is disabled then generate access array on-the-fly. 01725 $accessArray = $this->generateAccessArray(); 01726 } 01727 01728 $this->AccessArray = $accessArray; 01729 } 01730 return $this->AccessArray; 01731 } 01732 01733 /* 01734 \private 01735 Generates the accessArray for the user (for $this). 01736 */ 01737 function generateAccessArray() 01738 { 01739 $idList = $this->groups(); 01740 $idList[] = $this->attribute( 'contentobject_id' ); 01741 01742 $accessArray = eZRole::accessArrayByUserID( $idList ); 01743 01744 $ini = eZINI::instance( 'module.ini' ); 01745 $modules = $ini->variable( 'ModuleSettings', 'ModuleList' ); 01746 01747 // evaluate module and function wildcards in the access array 01748 01749 foreach ( $accessArray as $moduleName => $assignedFunctions ) 01750 { 01751 if ( $moduleName != '*' && isset( $assignedFunctions['*'] ) ) 01752 { 01753 $limitations = $assignedFunctions['*']; 01754 01755 $mod = eZModule::exists( $moduleName ); 01756 01757 if ( !$mod ) 01758 { 01759 continue; 01760 } 01761 01762 $functions = $mod->attribute( 'available_functions' ); 01763 01764 if ( count( $functions ) > 0 ) 01765 { 01766 // remove wildcard 01767 unset( $accessArray[$moduleName]['*'] ); 01768 01769 // and add evaluated wildcard instead 01770 foreach ( $functions as $functionName => $functionValue ) 01771 { 01772 $accessArray = array_merge_recursive( $accessArray, array( $moduleName => array( $functionName => $limitations ) ) ); 01773 } 01774 } 01775 } 01776 } 01777 01778 if ( isset( $accessArray['*'] ) ) 01779 { 01780 $limitations = $accessArray['*']['*']; 01781 01782 // remove wildcard 01783 unset( $accessArray['*'] ); 01784 01785 // add evaluated wildcard instead 01786 foreach ( $modules as $moduleName ) 01787 { 01788 $mod = eZModule::exists( $moduleName ); 01789 01790 if ( !$mod ) 01791 { 01792 continue; 01793 } 01794 01795 $functions = $mod->attribute( 'available_functions' ); 01796 01797 if ( count( $functions ) == 0 ) 01798 { 01799 $functions = array( '*' => array() ); 01800 } 01801 01802 foreach ( $functions as $functionName => $functionValue ) 01803 { 01804 $accessArray = array_merge_recursive( $accessArray, array( $moduleName => array( $functionName => $limitations ) ) ); 01805 } 01806 } 01807 } 01808 01809 // add implicit system policy limitations 01810 $lockGroup = eZContentObjectStateGroup::fetchByIdentifier( 'ez_lock' ); 01811 01812 if ( $lockGroup ) 01813 { 01814 $lockStates = $lockGroup->states(); 01815 if ( count( $lockStates ) > 0 ) 01816 { 01817 $defaultLockState = $lockStates[0]; 01818 01819 $implicitLimitations = array( 'StateGroup_ez_lock' => array( $defaultLockState->attribute( 'id' ) ) ); 01820 foreach ( array( 'content' => array( 'edit', 'remove' ) ) as $moduleName => $functions ) 01821 { 01822 if ( !isset( $accessArray[$moduleName] ) ) 01823 { 01824 continue; 01825 } 01826 01827 foreach ( $functions as $functionName ) 01828 { 01829 if ( isset( $accessArray[$moduleName][$functionName] ) ) 01830 { 01831 foreach( $accessArray[$moduleName][$functionName] as $key => $limitations ) 01832 { 01833 $accessArray[$moduleName][$functionName][$key] = is_array( $limitations ) ? 01834 array_merge( $limitations, $implicitLimitations ) : $implicitLimitations; 01835 } 01836 } 01837 } 01838 } 01839 } 01840 } 01841 01842 return $accessArray; 01843 } 01844 01845 /*! 01846 \private 01847 \static 01848 Callback which figures out global expiry and returns it. 01849 */ 01850 function userInfoExpiry() 01851 { 01852 /* Figure out when the last update was done */ 01853 eZExpiryHandler::registerShutdownFunction(); 01854 $handler = eZExpiryHandler::instance(); 01855 if ( $handler->hasTimestamp( 'user-access-cache' ) ) 01856 { 01857 $expiredTimestamp = $handler->timestamp( 'user-access-cache' ); 01858 } 01859 else 01860 { 01861 $expiredTimestamp = time(); 01862 $handler->setTimestamp( 'user-access-cache', $expiredTimestamp ); 01863 } 01864 01865 return $expiredTimestamp; 01866 } 01867 01868 /*! 01869 \private 01870 \static 01871 Callback which fetches access array from local file. 01872 */ 01873 function retrieveAccessArrayFromCache( $filePath, $mtime, $userID ) 01874 { 01875 return include( $filePath ); 01876 } 01877 01878 /*! 01879 \private 01880 Callback which generates the accessarray for the current user. 01881 */ 01882 function generateAccessArrayForCache( $filePath, $userID ) 01883 { 01884 return array( 'content' => $this->generateAccessArray(), 01885 'scope' => 'user-info-cache', 01886 'datatype' => 'php', 01887 'store' => true ); 01888 } 01889 01890 01891 /* 01892 Returns list of sections which are allowed to assign to the given content object by the user. 01893 */ 01894 function canAssignToObjectSectionList( $contentObject ) 01895 { 01896 $access = $this->hasAccessTo( 'section', 'assign' ); 01897 01898 if ( $access['accessWord'] == 'yes' ) 01899 { 01900 return array( '*' ); 01901 } 01902 else if ( $access['accessWord'] == 'limited' ) 01903 { 01904 $userID = $this->attribute( 'contentobject_id' ); 01905 $classID = $contentObject->attribute( 'contentclass_id' ); 01906 $ownerID = $contentObject->attribute( 'owner_id' ); 01907 $sectionID = $contentObject->attribute( 'section_id' ); 01908 01909 $allowedSectionIDList = array(); 01910 foreach ( $access['policies'] as $policy ) 01911 { 01912 if ( ( isset( $policy['Class'] ) and !in_array( $classID, $policy['Class'] ) ) or 01913 ( isset( $policy['Owner'] ) and in_array( 1, $policy['Owner'] ) and $userID != $ownerID ) or 01914 ( isset( $policy['Section'] ) and !in_array( $sectionID, $policy['Section'] ) ) ) 01915 { 01916 continue; 01917 } 01918 if ( isset( $policy['NewSection'] ) and count( $policy['NewSection'] > 0 ) ) 01919 { 01920 $allowedSectionIDList = array_merge( $allowedSectionIDList, $policy['NewSection'] ); 01921 } 01922 else 01923 { 01924 return array( '*' ); 01925 } 01926 } 01927 $allowedSectionIDList = array_unique( $allowedSectionIDList ); 01928 return $allowedSectionIDList; 01929 } 01930 return array(); 01931 } 01932 01933 /* 01934 Checks whether user can assign the section to the given content object or not. 01935 */ 01936 function canAssignSectionToObject( $checkSectionID, $contentObject ) 01937 { 01938 $access = $this->hasAccessTo( 'section', 'assign' ); 01939 01940 if ( $access['accessWord'] == 'yes' ) 01941 { 01942 return true; 01943 } 01944 else if ( $access['accessWord'] == 'limited' ) 01945 { 01946 $hasSubtreeLimitation = false; 01947 $subtreeLimitationResult = false; 01948 01949 // Trying first to discover if a subtree limitation exists. 01950 // Only the main node of the object is considered! 01951 foreach ( $access['policies'] as $policy ) 01952 { 01953 if ( isset( $policy['User_Subtree'] ) ) 01954 { 01955 $hasSubtreeLimitation = true; 01956 $nodePath = $contentObject->mainNode()->PathString; 01957 01958 foreach ( $policy['User_Subtree'] as $path ) 01959 { 01960 if ( strpos( $nodePath, $path ) !== false ) 01961 { 01962 $subtreeLimitationResult = true; 01963 } 01964 } 01965 continue; 01966 } 01967 } 01968 01969 // If a subtree limitation exists and none of the path corresponds then the user have not enough rights. 01970 if ( $hasSubtreeLimitation && !$subtreeLimitationResult ) 01971 { 01972 return false; 01973 } 01974 01975 unset( $hasSubtreeLimitation, $subtreeLimitationResult, $nodePath ); 01976 01977 $userID = $this->attribute( 'contentobject_id' ); 01978 $classID = $contentObject->attribute( 'contentclass_id' ); 01979 $ownerID = $contentObject->attribute( 'owner_id' ); 01980 $sectionID = $contentObject->attribute( 'section_id' ); 01981 01982 foreach ( $access['policies'] as $policy ) 01983 { 01984 if ( ( isset( $policy['Class'] ) and !in_array( $classID, $policy['Class'] ) ) or 01985 ( isset( $policy['Owner'] ) and in_array( 1, $policy['Owner'] ) and $userID != $ownerID ) or 01986 ( isset( $policy['Section'] ) and !in_array( $sectionID, $policy['Section'] ) ) ) 01987 { 01988 continue; 01989 } 01990 if ( isset( $policy['NewSection'] ) ) 01991 { 01992 if ( is_array( $policy['NewSection'] ) and in_array( $checkSectionID, $policy['NewSection'] ) ) 01993 { 01994 return true; 01995 } 01996 } 01997 else 01998 { 01999 return true; 02000 } 02001 } 02002 } 02003 return false; 02004 } 02005 02006 /* 02007 Checks whether user has privileges to assign the section or not at all. 02008 */ 02009 function canAssignSection( $checkSectionID ) 02010 { 02011 $access = $this->hasAccessTo( 'section', 'assign' ); 02012 02013 if ( $access['accessWord'] == 'yes' ) 02014 { 02015 return true; 02016 } 02017 else if ( $access['accessWord'] == 'limited' ) 02018 { 02019 foreach ( $access['policies'] as $policy ) 02020 { 02021 if ( isset( $policy['NewSection'] ) ) 02022 { 02023 if ( in_array( $checkSectionID, $policy['NewSection'] ) ) 02024 { 02025 return true; 02026 } 02027 } 02028 else 02029 { 02030 return true; 02031 } 02032 } 02033 } 02034 return false; 02035 } 02036 02037 /* 02038 Returns list of sections allowed to assign for the user. 02039 */ 02040 function canAssignSectionList() 02041 { 02042 $access = $this->hasAccessTo( 'section', 'assign' ); 02043 02044 if ( $access['accessWord'] == 'yes' ) 02045 { 02046 return array( '*' ); 02047 } 02048 else if ( $access['accessWord'] == 'limited' ) 02049 { 02050 $allowedSectionIDList = array(); 02051 foreach ( $access['policies'] as $policy ) 02052 { 02053 if ( isset( $policy['NewSection'] ) ) 02054 { 02055 if ( is_array( $policy['NewSection'] ) and count( $policy['NewSection'] ) > 0 ) 02056 { 02057 $allowedSectionIDList = array_merge( $allowedSectionIDList, $policy['NewSection'] ); 02058 } 02059 } 02060 else 02061 { 02062 return array( '*' ); 02063 } 02064 } 02065 $allowedSectionIDList = array_unique( $allowedSectionIDList ); 02066 return $allowedSectionIDList; 02067 } 02068 return array(); 02069 } 02070 02071 /* 02072 Returns list of classes allowed to assign to the given section for the user. 02073 */ 02074 function canAssignSectionToClassList( $checkSectionID ) 02075 { 02076 $access = $this->hasAccessTo( 'section', 'assign' ); 02077 02078 if ( $access['accessWord'] == 'yes' ) 02079 { 02080 return array( '*' ); 02081 } 02082 else if ( $access['accessWord'] == 'limited' ) 02083 { 02084 $allowedClassList = array(); 02085 foreach ( $access['policies'] as $policy ) 02086 { 02087 if ( !isset( $policy['NewSection'] ) or in_array( $checkSectionID, $policy['NewSection'] ) ) 02088 { 02089 if ( isset( $policy['Class'] ) ) 02090 { 02091 $allowedClassList = array_merge( $allowedClassList, $policy['Class'] ); 02092 } 02093 else 02094 { 02095 return array( '*' ); 02096 } 02097 } 02098 } 02099 02100 if ( count( $allowedClassList ) > 0 ) 02101 { 02102 // Now we are trying to fetch classes by collected ids list to return 02103 // class list consisting of existing classes's identifiers only. 02104 $allowedClassList = array_unique( $allowedClassList ); 02105 // include_once( 'kernel/classes/ezcontentclass.php' ); 02106 $classList = eZContentClass::fetchList( eZContentClass::VERSION_STATUS_DEFINED, false, false, null, null, $allowedClassList ); 02107 if ( is_array( $classList ) and count( $classList ) > 0 ) 02108 { 02109 $classIdentifierList = array(); 02110 foreach( $classList as $class ) 02111 { 02112 $classIdentifierList[] = $class['identifier']; 02113 } 02114 return $classIdentifierList; 02115 } 02116 } 02117 } 02118 return array(); 02119 } 02120 02121 /* 02122 Evaluates if $this user has access to the view $viewName based on its policy functions and 02123 checks if the assigned to the view functions expression is valid and handles errors if it is not. 02124 Returns true if access is allowed, false if access is denied. 02125 */ 02126 function hasAccessToView( $module, $viewName, &$params ) 02127 { 02128 $validView = false; 02129 $accessAllowed = false; 02130 if ( $module->singleFunction() ) 02131 { 02132 $info = $module->attribute( 'info' ); 02133 if ( isset( $info['function'] ) ) 02134 { 02135 $validView = true; 02136 if ( isset( $info['function']['functions'] ) && !empty( $info['function']['functions'] ) ) 02137 { 02138 $functions = $info['function']['functions']; 02139 } 02140 } 02141 } 02142 else 02143 { 02144 $views = $module->attribute( 'views' ); 02145 if ( isset( $views[$viewName] ) ) 02146 { 02147 $view = $views[$viewName]; 02148 $validView = true; 02149 if ( isset( $view['functions'] ) && !empty( $view['functions'] ) ) 02150 { 02151 $functions = $view['functions']; 02152 } 02153 } 02154 } 02155 02156 02157 if ( $validView ) 02158 { 02159 if ( isset( $functions ) ) 02160 { 02161 if ( is_array( $functions ) ) 02162 { 02163 $funcExpression = false; 02164 $accessAllowed = true; 02165 foreach ( $functions as $function ) 02166 { 02167 if ( empty( $function ) ) 02168 { 02169 $funcExpression = false; 02170 $accessAllowed = false; 02171 break; 02172 } 02173 else if ( is_string( $function ) ) 02174 { 02175 if ( $funcExpression ) 02176 { 02177 $funcExpression .= ' and '; 02178 } 02179 $funcExpression .= '( ' . $function . ' )'; 02180 } 02181 } 02182 } 02183 else if ( is_string( $functions ) ) 02184 { 02185 $funcExpression = $functions; 02186 } 02187 else 02188 { 02189 $funcExpression = false; 02190 $accessAllowed = true; 02191 } 02192 02193 if ( $funcExpression ) 02194 { 02195 // Validate and evaluate functions expression. 02196 // Lets construct functions's expression ready for evaluating first. 02197 $pS = '/(?<=\b)'; 02198 $pE = '(?=\b)/'; 02199 02200 $moduleName = $module->attribute( 'name' ); 02201 $availableFunctions = $module->attribute( 'available_functions' ); 02202 if ( is_array( $availableFunctions ) and 02203 count( $availableFunctions ) > 0 ) 02204 { 02205 $pattern = $pS . '(' . implode( '|', array_keys( $availableFunctions ) ) . ')' . $pE; 02206 $matches = array(); 02207 if ( preg_match_all( $pattern, ' ' . $funcExpression . ' ', $matches ) > 0 ) 02208 { 02209 $patterns = array(); 02210 $replacements = array(); 02211 $matches = array_unique( $matches[1] ); 02212 foreach ( $matches as $match ) 02213 { 02214 if ( !isset( $replacements[$match] ) ) 02215 { 02216 $accessResult = $this->hasAccessTo( $moduleName, $match ); 02217 if ( $accessResult['accessWord'] == 'no' ) 02218 { 02219 $replacements[$match] = 'false'; 02220 $params['accessList'] = $accessResult['accessList']; 02221 } 02222 else 02223 { 02224 $replacements[$match] = 'true'; 02225 if ( $accessResult['accessWord'] == 'limited' ) 02226 { 02227 $params['Limitation'] = $accessResult['policies']; 02228 $GLOBALS['ezpolicylimitation_list'][$this->ContentObjectID][$moduleName][$match] = $params['Limitation']; 02229 } 02230 } 02231 $patterns[$match] = $pS . $match . $pE; 02232 } 02233 } 02234 $funcExpression = preg_replace( $patterns, $replacements, ' ' . $funcExpression . ' ' ); 02235 } 02236 } 02237 $funcExpressionForEval = $funcExpression; 02238 02239 // continue to validate expression 02240 $words = array(); 02241 $words[] = $pS . 'and' . $pE; 02242 $words[] = $pS . 'or' . $pE; 02243 $words[] = $pS . 'true' . $pE; 02244 $words[] = $pS . 'false' . $pE; 02245 $pS = '/(?<=[^&|])'; 02246 $pE = '(?=[^&|])/'; 02247 $words[] = $pS . '\|\|' . $pE; 02248 $words[] = $pS . '&&' . $pE; 02249 $words[] = '/[\(\)]/'; 02250 02251 $replacement = ''; 02252 $funcExpression = preg_replace( $words, $replacement, ' ' . $funcExpression . ' ' ); 02253 02254 $funcExpression = trim( $funcExpression ); 02255 02256 if ( empty( $funcExpression ) ) 02257 { 02258 // if expression is valid then evaluate value of the $functionsToEvaluate string 02259 ob_start(); 02260 $ret = eval( "\$accessAllowed = ( bool ) ( $funcExpressionForEval );" ); 02261 $buffer = ob_get_contents(); 02262 ob_end_clean(); 02263 02264 // if we get any error while evaluating then set result to false 02265 if ( !empty( $buffer ) or $ret === false ) 02266 { 02267 eZDebug::writeError( "There was an error while evaluating the policy functions value of the '$moduleName/$viewName' view. " . 02268 "Please check the '$moduleName/module.php' file." ); 02269 $accessAllowed = false; 02270 } 02271 } 02272 else 02273 { 02274 eZDebug::writeError( "There is a mistake in the functions array data of the '$moduleName/$viewName' view. " . 02275 "Please check the '$moduleName/module.php' file." ); 02276 $accessAllowed = false; 02277 } 02278 } 02279 } 02280 else 02281 { 02282 $moduleName = $module->attribute( 'name' ); 02283 $accessResult = $this->hasAccessTo( $moduleName ); 02284 if ( $accessResult['accessWord'] == 'no' ) 02285 { 02286 $params['accessList'] = $accessResult['accessList']; 02287 $accessAllowed = false; 02288 } 02289 else 02290 { 02291 $accessAllowed = true; 02292 if ( $accessResult['accessWord'] == 'limited' ) 02293 { 02294 $params['Limitation'] = $accessResult['policies']; 02295 $GLOBALS['ezpolicylimitation_list'][$this->ContentObjectID][$moduleName]['*'] = $params['Limitation']; 02296 } 02297 } 02298 } 02299 } 02300 02301 return $accessAllowed; 02302 } 02303 02304 /*! 02305 \return an array of roles which the user is assigned to 02306 */ 02307 function roles() 02308 { 02309 $groups = $this->attribute( 'groups' ); 02310 $groups[] = $this->attribute( 'contentobject_id' ); 02311 return eZRole::fetchByUser( $groups ); 02312 } 02313 02314 /*! 02315 \return an array of role ids which the user is assigned to 02316 */ 02317 function roleIDList() 02318 { 02319 $http = eZHTTPTool::instance(); 02320 02321 // If the user object is not the currently logged in user we cannot use the session cache 02322 $useCache = ( $this->ContentObjectID == $http->sessionVariable( 'eZUserLoggedInID' ) ); 02323 02324 if ( $useCache ) 02325 { 02326 eZExpiryHandler::registerShutdownFunction(); 02327 $handler = eZExpiryHandler::instance(); 02328 $expiredTimeStamp = 0; 02329 $roleIDListTimestamp = $http->sessionVariable( 'eZRoleIDList_Timestamp' ); 02330 if ( $handler->hasTimestamp( 'user-info-cache' ) ) 02331 $expiredTimeStamp = $handler->timestamp( 'user-info-cache' ); 02332 02333 if ( $roleIDListTimestamp > $expiredTimeStamp ) 02334 { 02335 if ( $http->hasSessionVariable( 'eZRoleIDList' ) ) 02336 { 02337 return $http->sessionVariable( 'eZRoleIDList' ); 02338 } 02339 } 02340 } 02341 02342 $groups = $this->attribute( 'groups' ); 02343 $groups[] = $this->attribute( 'contentobject_id' ); 02344 $roleList = eZRole::fetchIDListByUser( $groups ); 02345 02346 if ( $useCache ) 02347 { 02348 $http->setSessionVariable( 'eZRoleIDList', $roleList ); 02349 $http->setSessionVariable( 'eZRoleIDList_Timestamp', time() ); 02350 } 02351 return $roleList; 02352 } 02353 02354 /*! 02355 \return an array of limited assignments 02356 */ 02357 function limitList() 02358 { 02359 $groups = $this->groups( false ); 02360 $groups[] = $this->attribute( 'contentobject_id' ); 02361 $groups = implode( ', ', $groups ); 02362 02363 $db = eZDB::instance(); 02364 02365 $limitationsArray = $db->arrayQuery( "SELECT DISTINCT limit_identifier, limit_value 02366 FROM ezuser_role 02367 WHERE contentobject_id IN ( $groups )" ); 02368 02369 return $limitationsArray; 02370 } 02371 02372 /*! 02373 \return an array of values of limited assignments 02374 */ 02375 function limitValueList() 02376 { 02377 $limitValueList = array(); 02378 02379 $http = eZHTTPTool::instance(); 02380 02381 // If the user object is not the currently logged in user we cannot use the session cache 02382 $useCache = ( $this->ContentObjectID == $http->sessionVariable( 'eZUserLoggedInID' ) ); 02383 02384 if ( $useCache ) 02385 { 02386 eZExpiryHandler::registerShutdownFunction(); 02387 $handler = eZExpiryHandler::instance(); 02388 $expiredTimeStamp = 0; 02389 $roleLimitationValueListTimeStamp = $http->sessionVariable( 'eZRoleLimitationValueList_Timestamp' ); 02390 if ( $handler->hasTimestamp( 'user-info-cache' ) ) 02391 { 02392 $expiredTimeStamp = $handler->timestamp( 'user-info-cache' ); 02393 } 02394 02395 if ( $roleLimitationValueListTimeStamp > $expiredTimeStamp && 02396 $http->hasSessionVariable( 'eZRoleLimitationValueList' ) ) 02397 { 02398 return $http->sessionVariable( 'eZRoleLimitationValueList' ); 02399 } 02400 } 02401 02402 $limitList = $this->limitList(); 02403 foreach ( $limitList as $limit ) 02404 { 02405 $limitValueList[] = $limit['limit_value']; 02406 } 02407 02408 if ( $useCache ) 02409 { 02410 $http->setSessionVariable( 'eZRoleLimitationValueList', $limitValueList ); 02411 $http->setSessionVariable( 'eZRoleLimitationValueList_Timestamp', time() ); 02412 } 02413 02414 return $limitValueList; 02415 } 02416 02417 function contentObject() 02418 { 02419 if ( isset( $this->ContentObjectID ) and $this->ContentObjectID ) 02420 { 02421 return eZContentObject::fetch( $this->ContentObjectID ); 02422 } 02423 return null; 02424 } 02425 02426 /*! 02427 Returns true if it's a real user which is logged in. False if the user 02428 is the default user or the fallback buildtin user. 02429 */ 02430 function isLoggedIn() 02431 { 02432 if ( $this->ContentObjectID == self::anonymousId() or 02433 $this->ContentObjectID == -1 ) 02434 { 02435 return false; 02436 } 02437 return true; 02438 } 02439 02440 /*! 02441 \return an array of id's with all the groups the user belongs to. 02442 */ 02443 function groups( $asObject = false ) 02444 { 02445 $db = eZDB::instance(); 02446 $http = eZHTTPTool::instance(); 02447 02448 if ( $asObject == true ) 02449 { 02450 $this->Groups = array(); 02451 if ( !isset( $this->GroupsAsObjects ) ) 02452 { 02453 $contentobjectID = $this->attribute( 'contentobject_id' ); 02454 $userGroups = $db->arrayQuery( "SELECT d.*, c.path_string 02455 FROM ezcontentobject_tree b, 02456 ezcontentobject_tree c, 02457 ezcontentobject d 02458 WHERE b.contentobject_id='$contentobjectID' AND 02459 b.parent_node_id = c.node_id AND 02460 d.id = c.contentobject_id 02461 ORDER BY c.contentobject_id "); 02462 $userGroupArray = array(); 02463 $pathArray = array(); 02464 foreach ( $userGroups as $group ) 02465 { 02466 $pathItems = explode( '/', $group["path_string"] ); 02467 array_pop( $pathItems ); 02468 array_pop( $pathItems ); 02469 foreach ( $pathItems as $pathItem ) 02470 { 02471 if ( $pathItem != '' && $pathItem > 1 ) 02472 $pathArray[] = $pathItem; 02473 } 02474 $userGroupArray[] = new eZContentObject( $group ); 02475 } 02476 $pathArray = array_unique( $pathArray ); 02477 02478 if ( count( $pathArray ) != 0 ) 02479 { 02480 $extraGroups = $db->arrayQuery( "SELECT d.* 02481 FROM ezcontentobject_tree c, 02482 ezcontentobject d 02483 WHERE c.node_id in ( " . implode( ', ', $pathArray ) . " ) AND 02484 d.id = c.contentobject_id 02485 ORDER BY c.contentobject_id "); 02486 foreach ( $extraGroups as $group ) 02487 { 02488 $userGroupArray[] = new eZContentObject( $group ); 02489 } 02490 } 02491 02492 $this->GroupsAsObjects = $userGroupArray; 02493 } 02494 return $this->GroupsAsObjects; 02495 } 02496 else 02497 { 02498 if ( !isset( $this->Groups ) ) 02499 { 02500 // If the user object is not the currently logged in user we cannot use the session cache 02501 $useCache = ( $this->ContentObjectID == $http->sessionVariable( 'eZUserLoggedInID' ) ); 02502 02503 if ( $useCache ) 02504 { 02505 $userGroupTimestamp = $http->sessionVariable( 'eZUserGroupsCache_Timestamp' ); 02506 02507 eZExpiryHandler::registerShutdownFunction(); 02508 $handler = eZExpiryHandler::instance(); 02509 $expiredTimeStamp = 0; 02510 if ( $handler->hasTimestamp( 'user-info-cache' ) ) 02511 $expiredTimeStamp = $handler->timestamp( 'user-info-cache' ); 02512 02513 if ( $userGroupTimestamp > $expiredTimeStamp ) 02514 { 02515 if ( $http->hasSessionVariable( 'eZUserGroupsCache' ) ) 02516 { 02517 $this->Groups = $http->sessionVariable( 'eZUserGroupsCache' ); 02518 return $this->Groups; 02519 } 02520 } 02521 } 02522 02523 $contentobjectID = $this->attribute( 'contentobject_id' ); 02524 02525 $userGroups = false; 02526 02527 $userGroups = $db->arrayQuery( "SELECT c.contentobject_id as id,c.path_string 02528 FROM ezcontentobject_tree b, 02529 ezcontentobject_tree c 02530 WHERE b.contentobject_id='$contentobjectID' AND 02531 b.parent_node_id = c.node_id 02532 ORDER BY c.contentobject_id "); 02533 $userGroupArray = array(); 02534 02535 $pathArray = array(); 02536 foreach ( $userGroups as $group ) 02537 { 02538 $pathItems = explode( '/', $group["path_string"] ); 02539 array_pop( $pathItems ); 02540 array_pop( $pathItems ); 02541 foreach ( $pathItems as $pathItem ) 02542 { 02543 if ( $pathItem != '' && $pathItem > 1 ) 02544 $pathArray[] = $pathItem; 02545 } 02546 $userGroupArray[] = $group['id']; 02547 } 02548 02549 if ( count( $pathArray ) > 0 ) 02550 { 02551 $pathArray = array_unique ($pathArray); 02552 $extraGroups = $db->arrayQuery( "SELECT c.contentobject_id as id 02553 FROM ezcontentobject_tree c, 02554 ezcontentobject d 02555 WHERE c.node_id in ( " . implode( ', ', $pathArray ) . " ) AND 02556 d.id = c.contentobject_id 02557 ORDER BY c.contentobject_id "); 02558 foreach ( $extraGroups as $group ) 02559 { 02560 $userGroupArray[] = $group['id']; 02561 } 02562 } 02563 02564 if ( $useCache ) 02565 { 02566 $http->setSessionVariable( 'eZUserGroupsCache', $userGroupArray ); 02567 $http->setSessionVariable( 'eZUserGroupsCache_Timestamp', time() ); 02568 } 02569 $this->Groups = $userGroupArray; 02570 } 02571 return $this->Groups; 02572 } 02573 } 02574 02575 /*! 02576 Checks if user is logged in, if not and the site requires user login for access 02577 a module redirect is returned. 02578 02579 \return null, user login not required. 02580 */ 02581 function checkUser( &$siteBasics, $uri ) 02582 { 02583 $ini = eZINI::instance(); 02584 $http = eZHTTPTool::instance(); 02585 $check = array( "module" => "user", 02586 "function" => "login" ); 02587 if ( $http->hasSessionVariable( "eZUserLoggedInID" ) and 02588 $http->sessionVariable( "eZUserLoggedInID" ) != '' and 02589 $http->sessionVariable( "eZUserLoggedInID" ) != $ini->variable( 'UserSettings', 'AnonymousUserID' ) ) 02590 { 02591 $currentUser = eZUser::currentUser(); 02592 if ( !$currentUser->isEnabled() ) 02593 { 02594 eZUser::logoutCurrent(); 02595 $currentUser = eZUser::currentUser(); 02596 } 02597 else 02598 { 02599 return null; 02600 } 02601 } 02602 02603 $moduleName = $uri->element(); 02604 $viewName = $uri->element( 1 ); 02605 $anonymousAccessList = $ini->variable( "SiteAccessSettings", "AnonymousAccessList" ); 02606 foreach ( $anonymousAccessList as $anonymousAccess ) 02607 { 02608 $elements = explode( '/', $anonymousAccess ); 02609 if ( count( $elements ) == 1 ) 02610 { 02611 if ( $moduleName == $elements[0] ) 02612 { 02613 return null; 02614 } 02615 } 02616 else 02617 { 02618 if ( $moduleName == $elements[0] and 02619 $viewName == $elements[1] ) 02620 { 02621 return null; 02622 } 02623 } 02624 } 02625 02626 return $check; 02627 } 02628 02629 /*! 02630 Funtion performed before user login info is collected. 02631 It's optional to implement this function in new login handler. 02632 02633 \return @see eZUserLoginHandler::checkUser() 02634 */ 02635 function preCollectUserInfo() 02636 { 02637 return array( 'module' => 'user', 'function' => 'login' ); 02638 } 02639 02640 /*! 02641 Function performed after user login info has been collected. 02642 Store login data as array: 02643 array( 'login' => <username>, 02644 'password' = <password> ) 02645 to session variable EZ_LOGIN_HANDLER_USER_INFO for automatic processing of login data. 02646 02647 \return @see eZUserLoginHandler::checkUser() 02648 */ 02649 function postCollectUserInfo() 02650 { 02651 return true; 02652 } 02653 02654 /*! 02655 Check if login handler require special login URI 02656 02657 \return Special login uri. If false, use system standard login uri. 02658 */ 02659 function loginURI() 02660 { 02661 return false; 02662 } 02663 02664 /*! 02665 Check if login handler require forced login at user check. 02666 02667 \return true if force login on user check, false if not. 02668 */ 02669 function forceLogin() 02670 { 02671 return false; 02672 } 02673 02674 /*! 02675 Creates the cache path if it doesn't exist, and returns the cache 02676 directory. The $id parameter is used to create multi-level directory names 02677 \static 02678 \return filename of the cachefile 02679 */ 02680 static function getCacheDir( $id = 0 ) 02681 { 02682 $sys = eZSys::instance(); 02683 $dir = $sys->cacheDirectory() . '/user-info' . eZDir::createMultilevelPath( $id, 2 ); 02684 02685 if ( !is_dir( $dir ) ) 02686 { 02687 eZDir::mkdir( $dir, false, true ); 02688 // var_dump("MADE DIRECTORY $dir"); 02689 } 02690 return $dir; 02691 } 02692 02693 static function cleanupCache() 02694 { 02695 eZExpiryHandler::registerShutdownFunction(); 02696 $handler = eZExpiryHandler::instance(); 02697 $handler->setTimestamp( 'user-access-cache', time() ); 02698 $handler->setTimestamp( 'user-info-cache', time() ); 02699 $handler->store(); 02700 } 02701 02702 /*! 02703 Returns the filename for a cache file with user information 02704 \static 02705 \return filename of the cachefile, or false when the user should not be cached 02706 */ 02707 static function getCacheFilename( $id ) 02708 { 02709 $ini = eZINI::instance(); 02710 $cacheUserPolicies = $ini->variable( 'RoleSettings', 'UserPolicyCache' ); 02711 if ( $cacheUserPolicies == 'enabled' ) 02712 { 02713 // var_dump("BUILD FILENAME FOR $id"); 02714 return eZUser::getCacheDir( $id ). '/user-'. $id . '.cache.php'; 02715 } 02716 else if ( $cacheUserPolicies != 'disabled' ) 02717 { 02718 $cachableIDs = explode( ',', $cacheUserPolicies ); 02719 if ( in_array( $id, $cachableIDs ) ) 02720 { 02721 // var_dump("BUILD FILENAME FOR $id"); 02722 return eZUser::getCacheDir( $id ). '/user-'. $id . '.cache.php'; 02723 } 02724 } 02725 // var_dump("NO CACHE FOR $id"); 02726 return false; 02727 } 02728 02729 static function fetchUserClassList( $asObject = false, $fields = false ) 02730 { 02731 // Get names of user classes 02732 if ( !$asObject and 02733 is_array( $fields ) and 02734 count( $fields ) > 0 ) 02735 { 02736 $fieldsFilter = ''; 02737 $i = 0; 02738 foreach ( $fields as $fieldName ) 02739 { 02740 if ( $i > 0 ) 02741 $fieldsFilter .= ', '; 02742 $fieldsFilter .= 'ezcontentclass.' . $fieldName; 02743 $i++; 02744 } 02745 } 02746 else 02747 { 02748 $fieldsFilter = 'ezcontentclass.*'; 02749 } 02750 $db = eZDB::instance(); 02751 $userClasses = $db->arrayQuery( "SELECT $fieldsFilter 02752 FROM ezcontentclass, ezcontentclass_attribute 02753 WHERE ezcontentclass.id = ezcontentclass_attribute.contentclass_id AND 02754 ezcontentclass.version = " . eZContentClass::VERSION_STATUS_DEFINED ." AND 02755 ezcontentclass_attribute.version = 0 AND 02756 ezcontentclass_attribute.data_type_string = 'ezuser'" ); 02757 02758 return eZPersistentObject::handleRows( $userClasses, "eZContentClass", $asObject ); 02759 } 02760 02761 static function fetchUserClassNames() 02762 { 02763 $userClassNames = array(); 02764 $userClasses = eZUser::fetchUserClassList( false, array( 'identifier' ) ); 02765 foreach ( $userClasses as $class ) 02766 { 02767 $userClassNames[] = $class[ 'identifier' ]; 02768 } 02769 return $userClassNames; 02770 } 02771 02772 static function fetchUserGroupClassNames() 02773 { 02774 // Get names of user classes 02775 $userClassNames = array(); 02776 $userClasses = eZUser::fetchUserClassList( false, array( 'identifier' ) ); 02777 foreach ( $userClasses as $class ) 02778 { 02779 $userClassNames[] = $class[ 'identifier' ]; 02780 } 02781 02782 // Get names of all allowed content-classes for the Users subtree 02783 $contentIni = eZINI::instance( "content.ini" ); 02784 $userGroupClassNames = array(); 02785 if ( $contentIni->hasVariable( 'ClassGroupIDs', 'Users' ) and 02786 is_numeric( $usersClassGroupID = $contentIni->variable( 'ClassGroupIDs', 'Users' ) ) and 02787 count( $usersClassList = eZContentClassClassGroup::fetchClassList( eZContentClass::VERSION_STATUS_DEFINED, $usersClassGroupID ) ) > 0 ) 02788 { 02789 foreach ( $usersClassList as $userClass ) 02790 { 02791 $userGroupClassNames[] = $userClass->attribute( 'identifier' ); 02792 } 02793 } 02794 02795 // Get names of user-group classes 02796 $groupClassNames = array_diff( $userGroupClassNames, $userClassNames ); 02797 return $groupClassNames; 02798 } 02799 02800 /*! 02801 Checks the password for validity 02802 \static 02803 \return true when password is valid by length and not empty, false if not 02804 */ 02805 static function validatePassword( $password ) 02806 { 02807 $ini = eZINI::instance(); 02808 $minPasswordLength = $ini->hasVariable( 'UserSettings', 'MinPasswordLength' ) ? $ini->variable( 'UserSettings', 'MinPasswordLength' ) : 3; 02809 if ( $password !== false and 02810 $password !== null and 02811 strlen( $password ) >= (int) $minPasswordLength ) 02812 { 02813 return true; 02814 } 02815 02816 return false; 02817 } 02818 02819 /** 02820 * Validates user login name using site.ini[UserSettings]UserNameValidationRegex[] 02821 * 02822 * @static 02823 * @since Version 4.1 02824 * @param string $loginName that we want to validate. 02825 * @param string $errorText by reference for details if validation fails. 02826 * @return bool Indicates if validation failed (false) or not (true). 02827 */ 02828 static function validateLoginName( $loginName, &$errorText ) 02829 { 02830 $ini = eZINI::instance(); 02831 $regexList = $ini->variable( 'UserSettings', 'UserNameValidationRegex' ); 02832 $errorTextList = $ini->variable( 'UserSettings', 'UserNameValidationErrorText' ); 02833 foreach ( $regexList as $key => $regex ) 02834 { 02835 if( preg_match( $regex, $loginName) ) 02836 { 02837 if ( isset( $errorTextList[$key] ) ) 02838 $errorText = $errorTextList[$key]; 02839 else 02840 $errorText = $ini->variable( 'UserSettings', 'DefaultUserNameValidationErrorText' ); 02841 return false; 02842 } 02843 } 02844 return true; 02845 } 02846 02847 /** 02848 * Gets the id of the anonymous user. 02849 * 02850 * @static 02851 * @return int User id of anonymous user. 02852 */ 02853 public static function anonymousId() 02854 { 02855 if ( self::$anonymousId === null ) 02856 { 02857 $ini = eZINI::instance(); 02858 self::$anonymousId = (int)$ini->variable( 'UserSettings', 'AnonymousUserID' ); 02859 $GLOBALS['eZUserBuiltins'] = array( self::$anonymousId ); 02860 } 02861 return self::$anonymousId; 02862 } 02863 02864 /*! 02865 Returns the IDs of content classes that contain user accounts 02866 */ 02867 public static function contentClassIDs() 02868 { 02869 $userContentClassIDs = array(); 02870 02871 $ini = eZINI::instance( 'content.ini' ); 02872 $userDatatypes = $ini->variable( "DataTypeSettings", "UserDataTypes" ); 02873 02874 $userContentClassIDs = array(); 02875 foreach ( $userDatatypes as $datatypeIdentifier ) 02876 { 02877 $userContentClassIDs = array_merge( $userContentClassIDs, eZContentClass::fetchIDListContainingDatatype( $datatypeIdentifier ) ); 02878 } 02879 02880 return $userContentClassIDs; 02881 } 02882 02883 public function canLoginToSiteAccess( $access ) 02884 { 02885 $siteAccessResult = $this->hasAccessTo( 'user', 'login' ); 02886 $hasAccessToSite = false; 02887 02888 if ( $siteAccessResult[ 'accessWord' ] == 'limited' ) 02889 { 02890 $siteNameCRC = eZSys::ezcrc32( $access[ 'name' ] ); 02891 $policyChecked = false; 02892 foreach ( $siteAccessResult['policies'] as $policy ) 02893 { 02894 if ( isset( $policy['SiteAccess'] ) ) 02895 { 02896 $policyChecked = true; 02897 if ( in_array( $siteNameCRC, $policy['SiteAccess'] ) ) 02898 { 02899 $hasAccessToSite = true; 02900 break; 02901 } 02902 } 02903 } 02904 02905 if ( !$policyChecked ) 02906 { 02907 $hasAccessToSite = true; 02908 } 02909 } 02910 else if ( $siteAccessResult[ 'accessWord' ] == 'yes' ) 02911 { 02912 $hasAccessToSite = true; 02913 } 02914 02915 return $hasAccessToSite; 02916 } 02917 02918 /// \privatesection 02919 public $Login; 02920 public $Email; 02921 public $PasswordHash; 02922 public $PasswordHashType; 02923 public $Groups; 02924 public $OriginalPassword; 02925 public $OriginalPasswordConfirm; 02926 02927 /** 02928 * Used to keep track that a logout was performed, and therefore prevent 02929 * auto-login from happening if an SSO is used 02930 * @var bool 02931 * @since 4.3 02932 **/ 02933 protected static $userHasLoggedOut = false; 02934 } 02935 02936 ?>