fetchAll("SELECT * FROM ".Piwik::prefixTable("user")." ORDER BY login ASC"); return $users; } /** * Returns the list of all the users login * * @return array the list of all the users login */ static public function getUsersLogin() { Piwik::checkUserHasSomeAdminAccess(); $db = Zend_Registry::get('db'); $users = $db->fetchAll("SELECT login FROM ".Piwik::prefixTable("user")." ORDER BY login ASC"); $return = array(); foreach($users as $login) { $return[] = $login['login']; } return $return; } /** * For each user, returns the list of website IDs where the user has the supplied $access level. * If a user doesn't have the given $access to any website IDs, * the user will not be in the returned array. * * @param string Access can have the following values : 'view' or 'admin' * * @return array The returned array has the format * array( * login1 => array ( idsite1,idsite2), * login2 => array(idsite2), * ... * ) * */ static public function getUsersSitesFromAccess( $access ) { Piwik::checkUserIsSuperUser(); self::checkAccessType($access); $db = Zend_Registry::get('db'); $users = $db->fetchAll("SELECT login,idsite FROM ".Piwik::prefixTable("access") ." WHERE access = ?", $access); $return = array(); foreach($users as $user) { $return[$user['login']][] = $user['idsite']; } return $return; } /** * For each user, returns his access level for the given $idSite. * If a user doesn't have any access to the $idSite ('noaccess'), * the user will not be in the returned array. * * @param string website ID * * @return array The returned array has the format * array( * login1 => 'view', * login2 => 'admin', * login3 => 'view', * ... * ) */ static public function getUsersAccessFromSite( $idSite ) { Piwik::checkUserHasAdminAccess( $idSite ); $db = Zend_Registry::get('db'); $users = $db->fetchAll("SELECT login,access FROM ".Piwik::prefixTable("access") ." WHERE idsite = ?", $idSite); $return = array(); foreach($users as $user) { $return[$user['login']] = $user['access']; } return $return; } /** * For each website ID, returns the access level of the given $userLogin. * If the user doesn't have any access to a website ('noaccess'), * this website will not be in the returned array. * If the user doesn't have any access, the returned array will be an empty array. * * @param string User that has to be valid * * @return array The returned array has the format * array( * idsite1 => 'view', * idsite2 => 'admin', * idsite3 => 'view', * ... * ) */ static public function getSitesAccessFromUser( $userLogin ) { Piwik::checkUserIsSuperUser(); self::checkUserExists($userLogin); self::checkUserIsNotSuperUser($userLogin); $db = Zend_Registry::get('db'); $users = $db->fetchAll("SELECT idsite,access FROM ".Piwik::prefixTable("access") ." WHERE login = ?", $userLogin); $return = array(); foreach($users as $user) { $return[] = array( 'site' => $user['idsite'], 'access' => $user['access'], ); } return $return; } /** * Returns the user information (login, password md5, alias, email, date_registered, etc.) * * @param string the user login * * @return array the user information */ static public function getUser( $userLogin ) { Piwik::checkUserIsSuperUser(); self::checkUserExists($userLogin); self::checkUserIsNotSuperUser($userLogin); $db = Zend_Registry::get('db'); $user = $db->fetchRow("SELECT * FROM ".Piwik::prefixTable("user") ." WHERE login = ?", $userLogin); return $user; } /** * Returns the user information (login, password md5, alias, email, date_registered, etc.) * * @param string the user email * * @return array the user information */ static public function getUserByEmail( $userEmail ) { Piwik::checkUserIsSuperUser(); self::checkUserEmailExists($userEmail); $db = Zend_Registry::get('db'); $user = $db->fetchRow("SELECT * FROM ".Piwik::prefixTable("user") ." WHERE email = ?", $userEmail); return $user; } static private function checkLogin($userLogin) { if(self::userExists($userLogin)) { throw new Exception(Piwik_TranslateException('UsersManager_ExceptionLoginExists', $userLogin)); } $loginMinimumLength = 3; $loginMaximumLength = 100; $l = strlen($userLogin); if(!($l >= $loginMinimumLength && $l <= $loginMaximumLength && (preg_match('/^[A-Za-z0-9_.-]*$/', $userLogin) > 0)) ) { throw new Exception(Piwik_TranslateException('UsersManager_ExceptionInvalidLoginFormat', array($loginMinimumLength, $loginMaximumLength))); } } static private function checkPassword($password) { if(!self::isValidPasswordString($password)) { throw new Exception(Piwik_TranslateException('UsersManager_ExceptionInvalidPassword')); } } static private function checkEmail($email) { if(self::userEmailExists($email)) { throw new Exception(Piwik_TranslateException('UsersManager_ExceptionEmailExists', $email)); } if(!Piwik::isValidEmailString($email)) { throw new Exception(Piwik_TranslateException('UsersManager_ExceptionInvalidEmail')); } } static private function getCleanAlias($alias,$userLogin) { if(empty($alias)) { $alias = $userLogin; } return $alias; } static private function getCleanPassword($password) { // if change here, should also edit the installation process // to change how the root pwd is saved in the config file return md5($password); } /** * Add a user in the database. * A user is defined by * - a login that has to be unique and valid * - a password that has to be valid * - an alias * - an email that has to be in a correct format * * @see userExists() * @see isValidLoginString() * @see isValidPasswordString() * @see isValidEmailString() * * @exception in case of an invalid parameter */ static public function addUser( $userLogin, $password, $email, $alias = false ) { Piwik::checkUserIsSuperUser(); self::checkLogin($userLogin); self::checkUserIsNotSuperUser($userLogin); self::checkPassword($password); self::checkEmail($email); $alias = self::getCleanAlias($alias,$userLogin); $passwordTransformed = self::getCleanPassword($password); $token_auth = self::getTokenAuth($userLogin, $passwordTransformed); $db = Zend_Registry::get('db'); $db->insert( Piwik::prefixTable("user"), array( 'login' => $userLogin, 'password' => $passwordTransformed, 'alias' => $alias, 'email' => $email, 'token_auth' => $token_auth, ) ); // we reload the access list which doesn't yet take in consideration this new user Zend_Registry::get('access')->reloadAccess(); } /** * Updates a user in the database. * Only login and password are required (case when we update the password). * When the password changes, the key token for this user will change, which could break * its API calls. * * @see addUser() for all the parameters */ static public function updateUser( $userLogin, $password = false, $email = false, $alias = false ) { Piwik::checkUserIsSuperUserOrTheUser($userLogin); self::checkUserIsNotAnonymous( $userLogin ); self::checkUserIsNotSuperUser($userLogin); $userInfo = self::getUser($userLogin); if(empty($password)) { $password = $userInfo['password']; } else { self::checkPassword($password); $password = self::getCleanPassword($password); } if(empty($alias)) { $alias = $userInfo['alias']; } if(empty($email)) { $email = $userInfo['email']; } if($email != $userInfo['email']) { self::checkEmail($email); } $alias = self::getCleanAlias($alias,$userLogin); $token_auth = self::getTokenAuth($userLogin,$password); $db = Zend_Registry::get('db'); $db->update( Piwik::prefixTable("user"), array( 'password' => $password, 'alias' => $alias, 'email' => $email, 'token_auth' => $token_auth, ), "login = '$userLogin'" ); } /** * Delete a user and all its access, given its login. * * @param string the user login. * * @exception if the user doesn't exist * * @return bool true on success */ static public function deleteUser( $userLogin ) { Piwik::checkUserIsSuperUser(); self::checkUserIsNotAnonymous( $userLogin ); self::checkUserIsNotSuperUser($userLogin); if(!self::userExists($userLogin)) { throw new Exception(Piwik_TranslateException("UsersManager_ExceptionDeleteDoesNotExist", $userLogin)); } self::deleteUserOnly( $userLogin ); self::deleteUserAccess( $userLogin ); } /** * Returns true if the given userLogin is known in the database * * @return bool true if the user is known */ static public function userExists( $userLogin ) { Piwik::checkUserHasSomeAdminAccess(); $count = Piwik_FetchOne("SELECT count(*) FROM ".Piwik::prefixTable("user"). " WHERE login = ?", $userLogin); return $count != 0; } /** * Returns true if user with given email (userEmail) is known in the database * * @return bool true if the user is known */ static public function userEmailExists( $userEmail ) { Piwik::checkUserHasSomeAdminAccess(); $count = Piwik_FetchOne("SELECT count(*) FROM ".Piwik::prefixTable("user"). " WHERE email = ?", $userEmail); return $count != 0; } /** * Set an access level to a given user for a list of websites ID. * * If access = 'noaccess' the current access (if any) will be deleted. * If access = 'view' or 'admin' the current access level is deleted and updated with the new value. * * @param string Access to grant. Must have one of the following value : noaccess, view, admin * @param string The user login * @param int|array The array of idSites on which to apply the access level for the user. * If the value is "all" then we apply the access level to all the websites ID for which the current authentificated user has an 'admin' access. * * @exception if the user doesn't exist * @exception if the access parameter doesn't have a correct value * @exception if any of the given website ID doesn't exist * * @return bool true on success */ static public function setUserAccess( $userLogin, $access, $idSites) { self::checkAccessType( $access ); self::checkUserExists( $userLogin); self::checkUserIsNotSuperUser($userLogin); if($userLogin == 'anonymous' && $access == 'admin') { throw new Exception(Piwik_TranslateException("UsersManager_ExceptionAdminAnonymous")); } // in case idSites is null we grant access to all the websites on which the current connected user // has an 'admin' access if($idSites === 'all') { $idSites = Piwik_SitesManager_API::getSitesIdWithAdminAccess(); } // in case the idSites is an integer we build an array elseif(!is_array($idSites)) { $idSites = Piwik_Site::getIdSitesFromIdSitesString($idSites); } // it is possible to set user access on websites only for the websites admin // basically an admin can give the view or the admin access to any user for the websites he manages Piwik::checkUserHasAdminAccess( $idSites ); self::deleteUserAccess( $userLogin, $idSites); // delete UserAccess $db = Zend_Registry::get('db'); // if the access is noaccess then we don't save it as this is the default value // when no access are specified if($access != 'noaccess') { foreach($idSites as $idsite) { $db->insert( Piwik::prefixTable("access"), array( "idsite" => $idsite, "login" => $userLogin, "access" => $access) ); } } // we reload the access list which doesn't yet take in consideration this new user access Zend_Registry::get('access')->reloadAccess(); } /** * Throws an exception is the user login doesn't exist * * @param string user login * @exception if the user doesn't exist */ static private function checkUserExists( $userLogin ) { if(!self::userExists($userLogin)) { throw new Exception(Piwik_TranslateException("UsersManager_ExceptionUserDoesNotExist", $userLogin)); } } /** * Throws an exception is the user email cannot be found * * @param string user email * @exception if the user doesn't exist */ static private function checkUserEmailExists( $userEmail ) { if(!self::userEmailExists($userEmail)) { throw new Exception(Piwik_TranslateException("UsersManager_ExceptionUserDoesNotExist", $userEmail)); } } static private function checkUserIsNotAnonymous( $userLogin ) { if($userLogin == 'anonymous') { throw new Exception(Piwik_TranslateException("UsersManager_ExceptionEditAnonymous")); } } static private function checkUserIsNotSuperUser( $userLogin ) { if($userLogin == Zend_Registry::get('config')->superuser->login) { throw new Exception(Piwik_TranslateException("UsersManager_ExceptionSuperUser")); } } static private function checkAccessType($access) { $accessList = Piwik_Access::getListAccess(); // do not allow to set the superUser access unset($accessList[array_search("superuser", $accessList)]); if(!in_array($access,$accessList)) { throw new Exception(Piwik_TranslateException("UsersManager_ExceptionAccessValues", implode(", ", $accessList))); } } /** * Delete a user given its login. * The user's access are not deleted. * * @param string the user login. * */ static private function deleteUserOnly( $userLogin ) { $db = Zend_Registry::get('db'); $db->query("DELETE FROM ".Piwik::prefixTable("user")." WHERE login = ?", $userLogin); } /** * Delete the user access for the given websites. * The array of idsite must be either null OR the values must have been checked before for their validity! * * @param string the user login * @param array array of idsites on which to delete the access. If null then delete all the access for this user. * * @return bool true on success */ static private function deleteUserAccess( $userLogin, $idSites = null ) { $db = Zend_Registry::get('db'); if(is_null($idSites)) { $db->query( "DELETE FROM ".Piwik::prefixTable("access"). " WHERE login = ?", array( $userLogin) ); } else { foreach($idSites as $idsite) { $db->query( "DELETE FROM ".Piwik::prefixTable("access"). " WHERE idsite = ? AND login = ?", array($idsite, $userLogin) ); } } } /** * Generates a unique MD5 for the given login & password * * @param string Login * @param string MD5ied string of the password */ static public function getTokenAuth($userLogin, $md5Password) { if(strlen($md5Password) != 32) { throw new Exception("UsersManager.getTokenAuth is expecting a MD5-hashed password (32 chars long string). Please call the md5() function on the password before calling this method."); } return md5($userLogin . $md5Password ); } /** * Returns true if the password is complex enough (at least 6 characters and max 26 characters) * * @param string email * @return bool */ static private function isValidPasswordString( $input ) { $l = strlen($input); return $l >= 6 && $l <= 26; } }