/** * Delete the contents of a user variable. * * This can either be * - a variable stored in the users table or * - an attribute to the users table, either a new style sttribute or the old style user information * * Examples: * UserUtil::delVar('ublock'); // clears the recent users table entry for 'ublock' * UserUtil::delVar('_YOURAVATAR', 123), // removes a users avatar, old style (uid = 123) * UserUtil::delVar('avatar', 123); // removes a users avatar, new style (uid=123) * (internally both the new style and the old style clear the same attribute) * * It does not allow the deletion of uid, email, uname, pass (password), as these are mandatory * fields in the users table. * * @param string $name The name of the variable. * @param integer $uid The user to delete the variable for. * * @return boolen true on success, false on failure */ public static function delVar($name, $uid = -1) { // Prevent deletion of core fields (duh) if (empty($name) || $name == 'uid' || $name == 'email' || $name == 'pass' || $name == 'uname' || $name == 'activated') { return false; } if ($uid == -1) { $uid = SessionUtil::getVar('uid'); } if (empty($uid)) { return false; } // Special delete value for approved_by if ($name == 'approved_by') { return (bool) self::setVar($name, -1, $uid); } $isRegistration = self::isRegistration($uid); $origUserObj = self::getVars($uid, false, 'uid', $isRegistration); if (!$origUserObj) { // No such user record! return false; } $varIsDeleted = false; // Cannot delVar the user's uid or uname if ($name != 'uid' && $name != 'uname') { if (self::fieldAlias($name)) { // this value comes from the users table $obj = array('uid' => $uid, $name => ''); $oldValue = isset($origUserObj[$name]) ? $origUserObj[$name] : null; $varIsDeleted = (bool) DBUtil::updateObject($obj, 'users', '', 'uid'); } else { // Not a table field alias, not 'uid', and not 'uname'. Treat it as an attribute. $dudAttributeName = self::convertOldDynamicUserDataAlias($name); if ($dudAttributeName) { LogUtil::log(__f('Warning! User variable [%1$s] is deprecated. Please use [%2$s] instead.', array($name, $mappingarray[$name])), E_USER_DEPRECATED); // $name is a former DUD /old style user information now stored as an attribute $attributeName = $dudAttributeName; } else { // $name not in the users table and also not found in the mapping array and also not one of the // forbidden names, let's make an attribute out of it $attributeName = $name; } $oldValue = isset($origUserObj['__ATTRIBUTES__'][$attributeName]) ? $origUserObj['__ATTRIBUTES__'][$attributeName] : null; $varIsDeleted = (bool) ObjectUtil::deleteObjectSingleAttribute($uid, 'users', $attributeName); } // force loading of attributes from db $updatedUserObj = self::getVars($uid, true, '', $isRegistration); if (!$updatedUserObj) { // Should never get here! return false; } // Do not fire update event/hook unless the update happened, it was not a registration record, it was not // the password being updated, and the system is not currently being installed. if ($varIsDeleted && $name != 'pass' && !System::isInstalling()) { // Fire the event $eventArgs = array('action' => 'delVar', 'field' => isset($attributeName) ? null : $name, 'attribute' => isset($attributeName) ? $attributeName : null); $eventData = array('old_value' => $oldValue); if ($isRegistration) { $updateEvent = new Zikula_Event('user.registration.update', $updatedUserObj, $eventArgs, $eventData); } else { $updateEvent = new Zikula_Event('user.account.update', $updatedUserObj, $eventArgs, $eventData); } EventUtil::notify($updateEvent); } } return $varIsDeleted; }
/** * Creates a new users table record. * * This is an internal function that creates a new user. External calls to create either a new * registration record or a new users record are made to Users_Api_Registration#registerNewUser(), which * dispatches either this function or createRegistration(). Users_Api_Registration#registerNewUser() should be the * primary and exclusive function used to create either a user record or a registraion, as it knows how to * decide which gets created based on the system configuration and the data provided. * * ATTENTION: This is the proper place to fire an item-created hook for the user account * record, even though the physical database record may have been saved previously as a pending * registration. See the note in createRegistration(). * * @param array $reginfo Contains the data gathered about the user for the registration record. * @param bool $userNotification Whether the user should be notified of the new registration or not; * however if the user's password was created for him, then he will * receive at least that notification without regard to this setting. * @param bool $adminNotification Whether the configured administrator notification e-mail address should * be sent notification of the new registration. * @param string $passwordCreatedForUser The password that was created for the user either automatically or by * an administrator (but not by the user himself). * * @return array|bool The user info, as saved in the users table; false on error. * * @see Users_Api_Registration#registerNewUser() */ protected function createUser(array $reginfo, $userNotification = true, $adminNotification = true, $passwordCreatedForUser = '') { $currentUserIsAdminOrSubadmin = $this->currentUserIsAdminOrSubAdmin(); if (!isset($reginfo) || empty($reginfo)) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } // It is only considered 'created by admin' if the reginfo has no id. If it has an id, then the // registration record was created by an admin, but this is being created after a verification $createdByAdminOrSubAdmin = $currentUserIsAdminOrSubadmin && !isset($reginfo['uid']); // Protected method (not callable from the api), so assume that the data has been validated in registerNewUser(). // Just check some basic things we need directly in this function. if (!isset($reginfo['email']) || empty($reginfo['email'])) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } // Check to see if we are getting a record directly from the registration request process, or one // from a later step in the registration process (e.g., approval or verification) if (!isset($reginfo['uid']) || empty($reginfo['uid'])) { // This is a record directly from the registration request process (never been saved before) // Protected method (not callable from the api), so assume that the data has been validated in registerNewUser(). // Just check some basic things we need directly in this function. if (!isset($reginfo['isapproved']) || empty($reginfo['isapproved'])) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } // Ensure that no user gets created without a password, and that the password is reasonable (no spaces, salted) // If the user is being registered with an authentication method other than one from the Users module, then the // password will be the unsalted, unhashed string stored in Users_Constant::PWD_NO_USERS_AUTHENTICATION. $hasPassword = isset($reginfo['pass']) && is_string($reginfo['pass']) && !empty($reginfo['pass']); if ($reginfo['pass'] === Users_Constant::PWD_NO_USERS_AUTHENTICATION) { $hasSaltedPassword = false; $hasNoUsersAuthenticationPassword = true; } else { $hasSaltedPassord = $hasPassword && (strpos($reginfo['pass'], Users_Constant::SALT_DELIM) != strrpos($reginfo['pass'], Users_Constant::SALT_DELIM)); $hasNoUsersAuthenticationPassword = false; } if (!$hasPassword || (!$hasSaltedPassord && !$hasNoUsersAuthenticationPassword)) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } $reginfo['uname'] = mb_strtolower($reginfo['uname']); $reginfo['email'] = mb_strtolower($reginfo['email']); $nowUTC = new DateTime(null, new DateTimeZone('UTC')); $nowUTCStr = $nowUTC->format(Users_Constant::DATETIME_FORMAT); // Finally, save it, but first get rid of some pseudo-properties $userObj = $reginfo; // Remove some pseudo-properties if (isset($userObj['isapproved'])) { unset($userObj['isapproved']); } if (isset($userObj['isverified'])) { unset($userObj['isverified']); } if (isset($userObj['__ATTRIBUTES__']['_Users_isVerified'])) { unset($userObj['__ATTRIBUTES__']['_Users_isVerified']); } if (isset($userObj['verificationsent'])) { unset($userObj['verificationsent']); } $userObj = $this->cleanFieldsToAttributes($userObj); $userObj['user_regdate'] = $nowUTCStr; if ($createdByAdminOrSubAdmin) { // Current user is admin, so admin is creating this registration. // See below if moderation is off and user is self-approved $userObj['approved_by'] = UserUtil::getVar('uid'); } // Approved date is set no matter what approved_by will become. $userObj['approved_date'] = $nowUTCStr; // Set activated state as pending registration for now to prevent firing of update hooks after the insert until the // activated state is set properly further below. $userObj['activated'] = Users_Constant::ACTIVATED_PENDING_REG; // NOTE: See below for the firing of the item-create hook. $userObj = DBUtil::insertObject($userObj, 'users', 'uid'); if ($userObj) { if (!$createdByAdminOrSubAdmin) { // Current user is not admin, so moderation is off and user "self-approved" through the registration process // We couldn't do this above because we didn't know the uid. $userUpdateObj = array( 'uid' => $userObj['uid'], 'approved_by' => $userObj['uid'], ); // Use DBUtil so we don't get an update event. The create hasn't happened yet. DBUtil::updateObject($userUpdateObj, 'users', '', 'uid'); } $reginfo['uid'] = $userObj['uid']; } } else { // This is a record from intermediate step in the registration process (e.g. verification or approval) // Protected method (not callable from the api), so assume that the data has been validated in registerNewUser(). // Just check some basic things we need directly in this function. if (!isset($reginfo['approved_by']) || empty($reginfo['approved_by'])) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } $userObj = $reginfo; $reginfo['isapproved'] = true; // Use ObjectUtil so we don't get an update event. (Create hasn't happened yet.); ObjectUtil::deleteObjectSingleAttribute($reginfo['uid'], 'users', '_Users_isVerified'); // NOTE: See below for the firing of the item-create hook. } if ($userObj) { // Set appropriate activated status. Again, use DBUtil so we don't get an update event. (Create hasn't happened yet.) // Need to do this here so that it happens for both the case where $reginfo is coming in new, and the case where // $reginfo was already in the database. $userUpdateObj = array( 'uid' => $userObj['uid'], 'activated' => Users_Constant::ACTIVATED_ACTIVE, ); DBUtil::updateObject($userUpdateObj, 'users', '', 'uid'); $userObj['activated'] = Users_Constant::ACTIVATED_ACTIVE; // Add user to default group $defaultGroup = ModUtil::getVar('Groups', 'defaultgroup', false); if (!$defaultGroup) { $this->registerError($this->__('Warning! The user account was created, but there was a problem adding the account to the default group.')); } $groupAdded = ModUtil::apiFunc('Groups', 'user', 'adduser', array('gid' => $defaultGroup, 'uid' => $userObj['uid'])); if (!$groupAdded) { $this->registerError($this->__('Warning! The user account was created, but there was a problem adding the account to the default group.')); } // Force the reload of the user in the cache. $userObj = UserUtil::getVars($userObj['uid'], true); // ATTENTION: This is the proper place for the item-create hook, not when a pending // registration is created. It is not a "real" record until now, so it wasn't really // "created" until now. It is way down here so that the activated state can be properly // saved before the hook is fired. $createEvent = new Zikula_Event('user.account.create', $userObj); $this->eventManager->notify($createEvent); $regErrors = array(); if ($adminNotification || $userNotification || !empty($passwordCreatedForUser)) { $sitename = System::getVar('sitename'); $siteurl = System::getBaseUrl(); $approvalOrder = $this->getVar('moderation_order', Users_Constant::APPROVAL_BEFORE); $rendererArgs = array(); $rendererArgs['sitename'] = $sitename; $rendererArgs['siteurl'] = substr($siteurl, 0, strlen($siteurl)-1); $rendererArgs['reginfo'] = $reginfo; $rendererArgs['createdpassword'] = $passwordCreatedForUser; $rendererArgs['admincreated'] = $createdByAdminOrSubAdmin; $rendererArgs['approvalorder'] = $approvalOrder; if ($userNotification || !empty($passwordCreatedForUser)) { $notificationSent = ModUtil::apiFunc($this->name, 'user', 'sendNotification', array('toAddress' => $userObj['email'], 'notificationType' => 'welcome', 'templateArgs' => $rendererArgs)); if (!$notificationSent) { $loggedErrorMessages = $this->request->getSession()->getMessages(Zikula_Session::MESSAGE_ERROR); $this->request->getSession()->clearMessages(Zikula_Session::MESSAGE_ERROR); foreach ($loggedErrorMessages as $lem) { if (!in_array($lem, $regErrors)) { $regErrors[] = $lem; } $regErrors[] = $this->__('Warning! The welcoming email for the newly created user could not be sent.'); } } } if ($adminNotification) { // mail notify email to inform admin about registration $notificationEmail = $this->getVar('reg_notifyemail', ''); if (!empty($notificationEmail)) { $subject = $this->__f('New registration: %s', $userObj['uname']); $notificationSent = ModUtil::apiFunc($this->name, 'user', 'sendNotification', array('toAddress' => $notificationEmail, 'notificationType' => 'regadminnotify', 'templateArgs' => $rendererArgs, 'subject' => $subject)); if (!$notificationSent) { $loggedErrorMessages = $this->request->getSession()->getMessages(Zikula_Session::MESSAGE_ERROR); $this->request->getSession()->clearMessages(Zikula_Session::MESSAGE_ERROR); foreach ($loggedErrorMessages as $lem) { if (!in_array($lem, $regErrors)) { $regErrors[] = $lem; } $regErrors[] = $this->__('Warning! The notification email for the newly created user could not be sent.'); } } } } } $userObj['regErrors'] = $regErrors; return $userObj; } else { $this->registerError($this->__('Unable to store the new user registration record.')); return false; } }