toDB() - 'intval' - converts to an integer - 'image' - checks image for size - 'avatar' - checks an image in the avatars directory 'stripTags' - strips HTML tags from the value (not an error if there are some) 'minLength' - minimum length (in utf-8 characters) for the string 'maxLength' - minimum length (in utf-8 characters) for the string 'longTrim' - if set, and the string exceeds maxLength, its trimmed 'enablePref' - value is processed only if the named $pref evaluates to true; otherwise any input is discarded without error */ $this->userVettingInfo = array( 'user_name' => array('niceName'=> LAN_USER_01, 'fieldType' => 'string', 'vetMethod' => '1,2', 'vetParam' => 'signup_disallow_text', 'srcName' => 'username', 'stripTags' => TRUE, 'stripChars' => '/ |\#|\=|\$/', fixedBlock => 'anonymous', 'minLength' => 2, 'maxLength' => varset($pref['displayname_maxlength'],15)), // Display name 'user_loginname' => array('niceName'=> LAN_USER_02, 'fieldType' => 'string', 'vetMethod' => '1', 'vetParam' => '', 'srcName' => 'loginname', 'stripTags' => TRUE, 'stripChars' => '/ |\#|\=|\$/', 'minLength' => 2, 'maxLength' => varset($pref['loginname_maxlength'],30)), // User name 'user_login' => array('niceName'=> LAN_USER_03, 'fieldType' => 'string', 'vetMethod' => '0', 'vetParam' => '', 'srcName' => 'realname', 'dbClean' => 'toDB'), // Real name (no real vetting) 'user_customtitle' => array('niceName'=> LAN_USER_04, 'fieldType' => 'string', 'vetMethod' => '0', 'vetParam' => '', 'srcName' => 'customtitle', 'dbClean' => 'toDB', 'enablePref' => 'signup_option_customtitle'), // No real vetting 'user_password' => array('niceName'=> LAN_USER_05, 'fieldType' => 'string', 'vetMethod' => '0', 'vetParam' => '', 'srcName' => 'password1', 'dataType' => 2, 'minLength' => varset($pref['signup_pass_len'],1)), 'user_sess' => array('niceName'=> LAN_USER_06, 'fieldType' => 'string', 'vetMethod' => '0', 'vetParam' => '', 'stripChars' => "#\"|'|(|)#", 'dbClean' => 'image', 'imagePath' => e_FILE.'public/avatars/', 'maxHeight' => varset($pref['im_height'], 100), 'maxWidth' => varset($pref['im_width'], 120)), // Photo 'user_image' => array('niceName'=> LAN_USER_07, 'fieldType' => 'string', 'vetMethod' => '0', 'vetParam' => '', 'srcName' => 'image', 'stripChars' => "#\"|'|(|)#", 'dbClean' => 'avatar', 'maxHeight' => varset($pref['im_height'], 100), 'maxWidth' => varset($pref['im_width'], 120)), // Avatar 'user_email' => array('niceName'=> LAN_USER_08, 'fieldType' => 'string', 'vetMethod' => '1,3', 'vetParam' => '', 'fieldOptional' => varset($pref['disable_emailcheck'],0), 'srcName' => 'email', 'dbClean' => 'toDB'), 'user_signature' => array('niceName'=> LAN_USER_09, 'fieldType' => 'string', 'vetMethod' => '0', 'vetParam' => '', 'srcName' => 'signature', 'dbClean' => 'toDB'), 'user_hideemail' => array('niceName'=> LAN_USER_10, 'fieldType' => 'int', 'vetMethod' => '0', 'vetParam' => '', 'srcName' => 'hideemail', 'dbClean' => 'intval'), 'user_xup' => array('niceName'=> LAN_USER_11, 'fieldType' => 'string', 'vetMethod' => '0', 'vetParam' => '', 'srcName' => 'user_xup', 'dbClean' => 'toDB'), 'user_class' => array('niceName'=> LAN_USER_12, 'fieldType' => 'string', 'vetMethod' => '0', 'vetParam' => '', 'srcName' => 'class', 'dataType' => '1') ); $this->otherFields = array( 'user_join' => LAN_USER_14, 'user_lastvisit' => LAN_USER_15, 'user_currentvisit' => LAN_USER_16, 'user_comments' => LAN_USER_17, 'user_ip' => LAN_USER_18, 'user_ban' => LAN_USER_19, 'user_prefs' => LAN_USER_20, 'user_visits' => LAN_USER_21, 'user_admin' => LAN_USER_22, 'user_perms' => LAN_USER_23, 'user_pwchange' => LAN_USER_24 // user_chats int(10) unsigned NOT NULL default '0', ); $this->otherFieldTypes = array( 'user_join' => 'int', 'user_lastvisit' => 'int', 'user_currentvisit' => 'int', 'user_comments' => 'int', 'user_ip' => 'string', 'user_ban' => 'int', 'user_prefs' => 'string', 'user_visits' => 'int', 'user_admin' => 'int', 'user_perms' => 'string', 'user_pwchange' => 'int' ); $this->passwordOpts = varset($pref['passwordEncoding'],0); $this->passwordEmail = varset($pref['allowEmailLogin'],FALSE); switch ($this->passwordOpts) { case 1 : case 2 : $this->preferred = PASSWORD_E107_SALT; break; case 0 : default : $this->preferred = PASSWORD_E107_MD5; $this->passwordOpts = 0; // In case it got set to some stupid value break; } return FALSE; } // Given plaintext password and login name, generate password string to store in DB function HashPassword($password, $login_name, $force='') { if ($force == '') $force = $this->preferred; switch ($force) { case PASSWORD_E107_MD5 : return md5($password); case PASSWORD_E107_SALT : return PASSWORD_E107_ID.md5(md5($password).$login_name); break; } return FALSE; } // Verify existing plaintext password against a stored hash value (which defines the encoding format and any 'salt') // Return PASSWORD_INVALID if invalid password // Return PASSWORD_VALID if valid password // Return a new hash to store if valid password but non-preferred encoding function CheckPassword($password, $login_name, $stored_hash) { if (strlen(trim($password)) == 0) return PASSWORD_INVALID; if (($this->passwordOpts <= 1) && (strlen($stored_hash) == 32)) { // Its simple md5 encoding if (md5($password) !== $stored_hash) return PASSWORD_INVALID; if ($this->preferred == PASSWORD_E107_MD5) return PASSWORD_VALID; return $this->HashPassword($password); // Valid password, but non-preferred encoding; return the new hash } // Allow the salted password even if disabled - for those that do try to go back! // if (($this->passwordOpts >= 1) && (strlen($stored_hash) == 35) && (substr($stored_hash,0,3) == PASSWORD_E107_ID)) if ((strlen($stored_hash) == 35) && (substr($stored_hash,0,3) == PASSWORD_E107_ID)) { // Its the standard E107 salted hash $hash = $this->HashPassword($password, $login_name, PASSWORD_E107_SALT); if ($hash === FALSE) return PASSWORD_INVALID; return ($hash == $stored_hash) ? PASSWORD_VALID : PASSWORD_INVALID; } return PASSWORD_INVALID; } // Verifies a standard response to a CHAP challenge function CheckCHAP($challenge, $response, $login_name, $stored_hash ) { if (strlen($challenge) != 40) return PASSWORD_INVALID; if (strlen($response) != 32) return PASSWORD_INVALID; $valid_ret = PASSWORD_VALID; if (strlen($stored_hash) == 32) { // Its simple md5 password storage $stored_hash = PASSWORD_E107_ID.md5($stored_hash.$login_name); // Convert to the salted format always used by CHAP if ($this->passwordOpts != PASSWORD_E107_MD5) $valid_ret = $stored_response; } $testval = md5(substr($stored_hash,strlen(PASSWORD_E107_ID)).$challenge); if ($testval == $response) return $valid_ret; return PASSWORD_INVALID; } // Checks whether the user has to validate a user setting change by entering password (basically, if that field affects the // stored password value) // Returns TRUE if change required, FALSE otherwise function isPasswordRequired($fieldName) { if ($this->preferred == PASSWORD_E107_MD5) return FALSE; switch ($fieldName) { case 'user_email' : return $this->passwordEmail; case 'user_loginname' : return TRUE; } return FALSE; } // Determines whether its necessary to store a separate password for email address validation function needEmailPassword() { if ($this->preferred == PASSWORD_E107_MD5) return FALSE; if ($this->passwordEmail) return TRUE; return FALSE; } // Checks whether the password value can be converted to the current default // Returns TRUE if conversion possible. // Returns FALSE if conversion not possible, or not needed function canConvert($password) { if ($this->preferred == PASSWORD_E107_MD5) return FALSE; if (strlen($password) == 32) return TRUE; // Can convert from md5 to salted return FALSE; } // Given md5-encoded password and login name, generate password string to store in DB function ConvertPassword($password, $login_name) { if ($this->canConvert($password) === FALSE) return $password; return PASSWORD_E107_ID.md5($password.$login_name); } // Generates a random user login name according to some pattern. // Checked for uniqueness. function generateUserLogin($pattern, $seed='') { $ul_sql = new db; if (strlen($pattern) < 6) $pattern = '##....'; do { $newname = $this->generateRandomString($pattern, $seed); } while ($ul_sql->db_Select('user','user_id',"`user_loginname`='{$newname}'")); return $newname; } // Generates a random string - for user login name, password etc, according to some pattern. // Checked for uniqueness. // Pattern format: // # - an alpha character // . - a numeric character // * - an alphanumeric character // ^ - next character from seed // alphanumerics are included 'as is' function generateRandomString($pattern, $seed = '') { if (strlen($pattern) < 6) $pattern = '##....'; $newname = ''; // Create alpha [A-Z][a-z] $alpha = ''; for($i = 65; $i < 91; $i++) { $alpha .= chr($i).chr($i+32); } $alphaLength = strlen($alpha) - 1; // Create digit [0-9] $digit = ''; for($i = 48; $i < 57; $i++) { $digit .= chr($i); } $digitLength = strlen($digit) - 1; // Create alpha numeric [A-Z][a-z] $alphaNum = $alpha.$digit; $alphaNumLength = strlen($alphaNum) - 1; // Next character of seed (if used) $seed_ptr = 0; for ($i = 0, $patternLength = strlen($pattern); $i < $patternLength; $i++) { $c = $pattern[$i]; switch ($c) { // Alpha only (upper and lower case) case '#' : $t = rand(0, $alphaLength); $newname .= $alpha[$t]; break; // Numeric only - [0-9] case '.' : $t = rand(0, $digitLength); $newname .= $digit[$t]; break; // Alphanumeric case '*' : $t = rand(0, $alphaNumLength); $newname .= $alphaNum[$t]; break; // Next character from seed case '^' : if ($seed_ptr < strlen($seed)) { $newname .= $seed[$seed_ptr]; $seed_ptr++; } break; // (else just ignore other characters in pattern) default : if (strrpos($alphaNum, $c) !== FALSE) { $newname .= $c; } /* else { $t = rand(0, $alphaNumLength); $newname .= $alphaNum[$t]; } */ } } return $newname; } // Split up an email address to check for banned domains. // Return false if invalid address. Otherwise returns a set of values to check function make_email_query($email, $fieldname = 'banlist_ip') { global $tp; $tmp = strtolower($tp -> toDB(trim(substr($email, strrpos($email, "@")+1)))); // Pull out the domain name if ($tmp == '') return FALSE; if (strpos($tmp,'.') === FALSE) return FALSE; $em = array_reverse(explode('.',$tmp)); $line = ''; $out = array(); foreach ($em as $e) { $line = '.'.$e.$line; $out[] = '`'.$fieldname."`='*{$line}'"; } return implode(' OR ',$out); } function makeUserCookie($lode,$autologin = FALSE) { global $pref; $cookieval = $lode['user_id'].".".md5($lode['user_password']); // (Use extra md5 on cookie value to obscure hashed value for password) if ($pref['user_tracking'] == "session") { $_SESSION[$pref['cookie_name']] = $cookieval; } else { if ($autologin == 1) { // Cookie valid for up to 30 days cookie($pref['cookie_name'], $cookieval, (time() + 3600 * 24 * 30)); } else { cookie($pref['cookie_name'], $cookieval); } } } // Generate an array of all the basic classes a user belongs to // if $asArray TRUE, returns results in an array; else as a comma-separated string // If $incInherited is TRUE, includes inherited classes function addCommonClasses($userData, $asArray = FALSE, $incInherited = FALSE) { if ($incInherited) { $classList = array(); global $e_userclass; if (!isset($e_userclass) && !is_object($e_userclass)) { require_once(e_HANDLER."userclass_class.php"); $e_userclass = new user_class; } $classList = $e_userclass->get_all_user_classes($var['user_class']); } else { if ($userData['user_class'] != '') $classList = explode(',',$userData['user_class']); } foreach (array(e_UC_MEMBER, e_UC_READONLY, e_UC_PUBLIC) as $c) { if (!in_array($c,$classList)) { $classList[] = $c; } } if ((varset($userData['user_admin'],0) == 1) && strlen($userData['user_perms'])) { $classList[] = e_UC_ADMIN; if (strpos($userData['user_perms'],'0') === 0) { $classList[] = e_UC_MAINADMIN; } } if ($asArray) return $classList; return implode(',',$classList); } // Return an array of descriptive names for each field in the user DB. If $all is false, just returns the modifiable ones. Else returns all function getNiceNames($all = FALSE) { // $ret = array('user_id' => LAN_USER_13); foreach ($this->userVettingInfo as $k => $v) { $ret[$k] = $v['niceName']; } if ($all) { $ret = array_merge($ret, $this->otherFields); } return $ret; } //=================================================== // User Field validation //=================================================== /* $_POST field names: DB signup usersettings quick add function ------------------------------------------------------------------------------ user_id - user_id - Unique user ID user_name name$ username username Display name user_loginname loginname loginname loginname User name (login name) user_customtitle - customtitle - Custom title user_password password1 password1 password1 Password (prior to encoding) password2 password2 password1 (Check password field) user_sess * - Photo (file on server) user_email email email email Email address email_confirm user_signature signature signature - User signature user_image image image* - Avatar (may be external URL or file on server) user_hideemail hideemail hideemail - Flag to hide user's email address user_login realname realname realname User Real name user_xup xupexist$ user_xup - XUP file link user_class class class userclass User class (array on form) user_loginname may be auto-generated * avatar (user_image) and photo (user_sess) may be uploaded files $changed to match the majority vote Following fields auto-filled in code as required: user_join user_lastvisit user_currentvisit user_chats user_comments user_forums user_ip user_ban user_prefs user_viewed user_visits user_admin user_perms user_pwchange */ // Function does validation specific to user data. Updates the $targetData array as appropriate. // Returns TRUE if nothing updated; FALSE if errors found (only checks data previously passed as good) function userValidation(&$targetData) { global $e107, $pref; $u_sql = new db; $ret = TRUE; $errMsg = ''; if (isset($targetData['data']['user_email'])) { $v = trim($targetData['data']['user_email']); // Always check email address if its entered if ($v == '') { if (!varsettrue($pref['disable_emailcheck'])) { $errMsg = ERR_MISSING_VALUE; } } elseif (!check_email($v)) { $errMsg = ERR_INVALID_EMAIL; } elseif ($u_sql->db_Count('user', '(*)', "WHERE `user_email`='".$v."' AND `user_ban`=1 ")) { $errMsg = ERR_BANNED_USER; } else { // See if email address banned $wc = $this->make_email_query($v); // Generate the query for the ban list if ($wc) { $wc = "`banlist_ip`='{$v}' OR ".$wc; } if (($wc === FALSE) || !$e107->check_ban($wc, FALSE, TRUE)) { // echo "Email banned
"; $errMsg = ERR_BANNED_EMAIL; } } if ($errMsg) { unset($targetData['data']['user_email']); // Remove the valid entry } } else { if (!isset($targetData['errors']['user_email']) && !varset($pref['disable_emailcheck'],FALSE)) { // We may have already picked up an error on the email address - or it may be allowed to be empty $errMsg = ERR_MISSING_VALUE; } } if ($errMsg) { // Update the error $targetData['errors']['user_email'] = $errMsg; $targetData['failed']['user_email'] = $v; $ret = FALSE; } return $ret; } // Given an array of user data intended to be written to the DB, adds empty strings (or other default value) for any field which doesn't have a default in the SQL definition. // (Avoids problems with MySQL in STRICT mode.). // Returns TRUE if additions made, FALSE if no change. function addNonDefaulted(&$userInfo) { // $nonDefaulted = array('user_signature' => '', 'user_prefs' => '', 'user_class' => '', 'user_perms' => ''); $nonDefaulted = array('user_signature' => '', 'user_prefs' => '', 'user_class' => '', 'user_perms' => '', 'user_realm' => ''); // Delete when McFly finished $ret = FALSE; foreach ($nonDefaulted as $k => $v) { if (!isset($userInfo[$k])) { $userInfo[$k] = $v; $ret = TRUE; } } return $ret; } // Delete time-expired partial registrations from the user DB, clean up user_extended table function deleteExpired($force = FALSE) { global $pref, $sql; $temp1 = 0; if (isset($pref['del_unv']) && $pref['del_unv'] && $pref['user_reg_veri'] != 2) { $threshold= intval(time() - ($pref['del_unv'] * 60)); if (($temp1 = $sql->db_Delete('user', 'user_ban = 2 AND user_join < '.$threshold)) > 0) { $force = TRUE; } } if ($force) { // Remove 'orphaned' extended user field records $sql->db_Select_gen("DELETE `#user_extended` FROM `#user_extended` LEFT JOIN `#user` ON `#user_extended`.`user_extended_id` = `#user`.`user_id` WHERE `#user`.`user_id` IS NULL"); } return $temp1; } // Called to update initial user classes, probationary user class etc function userClassUpdate(&$user, $event='userveri') { global $pref, $tp; $initClasses = array(); $doClasses = FALSE; $doProbation = FALSE; $ret = FALSE; switch ($event) { case 'userall' : $doClasses = TRUE; $doProbation = TRUE; break; case 'userfull' : // A 'fully fledged' user if (!$pref['user_reg_veri'] || ($pref['init_class_stage'] == '2')) { $doClasses = TRUE; } $doProbation = TRUE; break; case 'userpartial' : if ($pref['init_class_stage'] == '1') { // Set initial classes if to be done on partial signup, or if selected to add them now $doClasses = TRUE; } $doProbation = TRUE; break; } if ($doClasses) { if (isset($pref['initial_user_classes'])) { $initClasses = explode(',',$pref['initial_user_classes']); } // Any initial user classes to be set at some stage if ($doProbation && (varset($pref['user_new_period'], 0) > 0)) { $initClasses[] = e_UC_NEWUSER; // Probationary user class } if (count($initClasses)) { // Update the user classes if ($user['user_class']) { $initClasses = array_unique(array_merge($initClasses, explode(',',$user['user_class']))); } $user['user_class'] = $tp->toDB(implode(',',$initClasses)); $ret = TRUE; } } } } ?>