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