Source for file RoleUser.php
Documentation is available at RoleUser.php
* Lib for user administration, roles and permissions
* This lib uses pear so the constructor requieres
* Copyright (c) 2004 bitweaver.org
* Copyright (c) 2003 tikwiki.org
* Copyright (c) 2002-2003, Luis Argerich, Garland Foster, Eduardo Polidor, et. al.
* All Rights Reserved. See below for details and a complete list of authors.
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See http://www.gnu.org/copyleft/lesser.html for details
require_once( LIBERTY_PKG_PATH. 'LibertyMime.php' );
require_once( USERS_PKG_PATH. 'users_lib.php' );
define( 'AVATAR_TYPE_CENTRALIZED', 'c' );
define( 'AVATAR_TYPE_USER_DB', 'u' );
define( 'AVATAR_TYPE_LIBRARY', 'l' );
// Column sizes for users_users table
define( 'REAL_NAME_COL_SIZE', 64 );
define( 'BITUSER_CONTENT_TYPE_GUID', 'bituser' );
// some definitions for helping with authentication
define( "PASSWORD_INCORRECT", - 3 );
define( "USER_NOT_FOUND", - 5 );
define( "ACCOUNT_DISABLED", - 6 );
* Class that holds all information for a given user
* @author spider <spider@steelsun.com>
* Constructor - will automatically load all relevant data if passed a user string
* @author Christian Fowler <spider@viovio.com>
function BitUser( $pUserId= NULL, $pContentId= NULL ) {
'content_name' => 'User Information',
'content_name_plural' => 'User Information',
'handler_class' => 'BitUser',
'handler_package' => 'users',
'handler_file' => 'RoleUser.php',
'maintainer_url' => 'http://www.bitweaver.org'
$siteCookie = static::getSiteCookieName();
if( $this->isRegistered() && !empty( $_COOKIE[$siteCookie] ) ) {
return $_COOKIE[$siteCookie];
* Determines if a user object is cacheable. Out of paranoia, admin's are never cached.
* @return boolean if object can be cached
return parent::isCacheableObject() && !$this->isAdmin();
* Validate inbound sort_mode parameter
* @return array of fields which are valid sorts
$fields = parent::getSortModeFields();
$fields[] = 'map_position';
* load - loads all settings & preferences for this user
* @param boolean $pFull Load additional user data like
* @param string $pUserName User login name
* @author Chrstian Fowler <spider@steelsun.com>
function load( $pFull= FALSE, $pUserName= NULL ) {
$whereSql = "WHERE uu.`user_id`=?";
$bindVars = array( $this->mUserId );
$whereSql = "WHERE uu.`content_id`=?";
} elseif( !empty( $pUserName ) ) {
$whereSql = "WHERE uu.`login`=?";
$bindVars = array( $pUserName );
if( isset ( $whereSql ) ) {
$fullSelect = ' , lc.* ';
$fullJoin = " LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_content` lc ON ( uu.`content_id`=lc.`content_id` )";
$this->getServicesSql( 'content_load_sql_function', $fullSelect, $fullJoin, $whereSql, $bindVars );
// uu.`user_id` AS `uu_user_id` is last and aliases to avoid possible column name collisions
lf_ava.`file_name` AS `avatar_file_name`, la_ava.`attachment_id` AS `avatar_attachment_id`, lf_ava.`mime_type` AS `avatar_mime_type`,
lf_por.`file_name` AS `portrait_file_name`, ta_por.`attachment_id` AS `portrait_attachment_id`, lf_por.`mime_type` AS `portrait_mime_type`,
lf_logo.`file_name` AS `logo_file_name`, ta_logo.`attachment_id` AS `logo_attachment_id`, lf_logo.`mime_type` AS `logo_mime_type`
$fullSelect, uu.`user_id` AS `uu_user_id`
LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_attachments` la_ava ON ( uu.`avatar_attachment_id`=la_ava.`attachment_id` )
LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_files` lf_ava ON ( lf_ava.`file_id`=la_ava.`foreign_id` )
LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_attachments` ta_por ON ( uu.`portrait_attachment_id`=ta_por.`attachment_id` )
LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_files` lf_por ON ( lf_por.`file_id`=ta_por.`foreign_id` )
LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_attachments` ta_logo ON ( uu.`logo_attachment_id`=ta_logo.`attachment_id` )
LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_files` lf_logo ON ( lf_logo.`file_id`=ta_logo.`foreign_id` )
if(( $result = $this->mDb->query( $query, $bindVars )) && $result->numRows() ) {
$this->mInfo = $result->fetchRow();
$this->mInfo['user_id'] = $this->mInfo['uu_user_id'];
foreach( array( 'portrait', 'avatar', 'logo' ) as $img ) {
// break the real name into first and last name using the last space as the beginning of the last name
// for people who really want to use first and last name fields
// no spaces assign the real name to the first name
$this->mInfo['first_name'] = $this->mInfo['real_name'];
// a few random security conscious unset's - SPIDER
unset ( $this->mInfo['user_password'] );
unset ( $this->mInfo['hash'] );
$this->mInfo['display_name'] = (
( !empty( $this->mInfo['real_name'] ) ? $this->mInfo['real_name'] :
//print("displayName: ".$this->mInfo['display_name']);
if( !$gBitSystem->isFeatureActive( 'i18n_browser_languages' ) ) {
global $gBitLanguage, $gBitUser;
//change language only if if logged user is this user
//otherwise it's just logged user (lang A) watching other user's page (lang B) and don't change
$gBitLanguage->mLanguage = $this->getPreference( 'bitlanguage', $gBitLanguage->mLanguage );
} elseif( isset ( $_SESSION['bitlanguage'] )) {
// users not logged that change the preference
$gBitLanguage->mLanguage = $_SESSION['bitlanguage'];
* defaults set a default set of preferences in mPrefs for new users
global $gBitSystem, $gBitThemes, $gBitLanguage;
* site_display_timezone is not used for 'Local' time display so daylight saving offset is not available
* both of these should pick up the 'site default' values
if( !$this->getPreference( 'site_display_timezone' ) ) {
$this->setPreference( 'site_display_timezone', 'UTC' );
* @param array $pParamHash Data to be verified
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function verify( &$pParamHash ) {
// DO NOT REMOVE - to allow specific setting of the user_id during the first store.
// used by ROOT_USER_ID or ANONYMOUS_USER_ID during install.
if( @$this->verifyId( $pParamHash['user_id'] ) ) {
$pParamHash['user_store']['user_id'] = $pParamHash['user_id'];
if( !empty( $pParamHash['login'] ) && $pParamHash['login'] != $this->getField( 'login' ) ) {
$pParamHash['login'] = strip_tags($pParamHash['login']);
if( $this->userExists( array( 'login' => $pParamHash['login'] ) ) ) {
$this->mErrors['login'] = 'The username "'. $pParamHash['login']. '" is already in use';
} elseif( preg_match( '/[^A-Za-z0-9_.-]/', $pParamHash["login"] ) ) {
$this->mErrors['login'] = tra( "Your username can only contain numbers, characters, underscores and hyphens." );
$pParamHash['login'] = strtolower( $pParamHash['login'] );
$pParamHash['user_store']['login'] = $pParamHash['login'];
// some people really like using first and last names
// push them into real_name
if( !empty( $pParamHash['first_name'] ) ) {
$pParamHash['real_name'] = $pParamHash['first_name'];
if( !empty( $pParamHash['last_name'] ) ) {
$pParamHash['real_name'] = !empty( $pParamHash['real_name'] )? $pParamHash['real_name']. " ": '';
$pParamHash['real_name'] .= $pParamHash['last_name'];
if( !empty( $pParamHash['real_name'] ) ) {
$pParamHash['user_store']['real_name'] = substr( strip_tags($pParamHash['real_name']), 0, 64 );
if( !empty( $pParamHash['email'] ) ) {
$pParamHash['email'] = strtolower( $pParamHash['email'] );
$pParamHash['verified_email'] = ($emailResult === true);
// check some new user requirements
if( empty( $pParamHash['login'] ) ) {
// choose a login based on the username in the email
if( empty($pParamHash['email']) ){
// obviously if they didnt enter an email address we cant help them out
$this->mErrors['email'] = tra( 'You must enter your email address' );
$loginBase = preg_replace( '/[^A-Za-z0-9_]/', '', substr( $pParamHash['email'], 0, strpos( $pParamHash['email'], '@' ) ) );
if( $loginTaken = $this->userExists( array( 'login' => $login ) ) ) {
$login = $loginBase. rand(100,999);
$pParamHash['login'] = $login;
if( empty( $pParamHash['registration_date'] ) ) {
$pParamHash['registration_date'] = date( "U" );
$pParamHash['user_store']['registration_date'] = $pParamHash['registration_date'];
if( !empty( $pParamHash['email'] ) && empty($this->mErrors['email']) ) {
$pParamHash['user_store']['email'] = substr( $pParamHash['email'], 0, 200 ) ;
}elseif( empty($pParamHash['email']) ){
$this->mErrors['email'] = tra( 'You must enter your email address' );
if( $gBitSystem->isFeatureActive( 'users_validate_user' ) ) {
$pParamHash['pass_due'] = 0;
} elseif( empty( $pParamHash['password'] ) ) {
$this->mErrors['password'] = tra( 'Your password should be at least '. $gBitSystem->getConfig( 'users_min_pass_length', 4 ). ' characters long' );
// Prevent losing user info on save
if( empty( $pParamHash['edit'] ) ) {
$pParamHash['edit'] = $this->mInfo['data'];
if( isset ( $pParamHash['password'] ) ) {
if( isset ( $pParamHash["password2"] ) && $pParamHash["password"] != $pParamHash["password2"] ) {
$passwordErrors['password2'] = tra("The passwords didn't match");
$passwordErrors['password'] = $error;
if( !empty( $passwordErrors ) ) {
// Generate a unique hash
//$pParamHash['user_store']['hash'] = md5( strtolower( (!empty($pParamHash['login'])?$pParamHash['login']:'') ).$pPassword.$pParamHash['email'] );
$pParamHash['user_store']['hash'] = md5( $pParamHash['password'] );
$now = $gBitSystem->getUTCTime();
// if no pass_due and no user_pass_due value user will never have to update the password
if( empty( $pParamHash['pass_due'] ) && $gBitSystem->getConfig('users_pass_due') ) {
// renew password according to config value
$pParamHash['user_store']['pass_due'] = $now + (60 * 60 * 24 * $gBitSystem->getConfig('users_pass_due') );
} elseif( !empty( $pParamHash['pass_due'] ) ) {
// renew password only next half year ;)
$pParamHash['user_store']['pass_due'] = $now + (60 * 60 * 24 * $pParamHash['pass_due']);
if( $gBitSystem->isFeatureActive( 'users_clear_passwords' ) || !empty( $pParamHash['user_store']['provpass'] ) ) {
$pParamHash['user_store']['user_password'] = $pParamHash['password'];
// if we have an error we get them all by checking parent classes for additional errors
parent::verify( $pParamHash );
* Determine if the submitted answer for the captcha is valid
// novalidation is set to yes if a user confirms his email is correct after tiki fails to validate it
if( $gBitSystem->isFeatureActive( 'users_random_number_reg' ) ) {
if( ( empty( $pParamHash['novalidation'] ) || $pParamHash['novalidation'] != 'yes' )
&& ( !isset ( $_SESSION['captcha'] ) || $_SESSION['captcha'] != md5( $pParamHash['captcha'] ) ) )
$this->mErrors['captcha'] = "Wrong Answer";
if( $gBitSystem->isFeatureActive( 'users_register_recaptcha' ) && (empty( $pParamHash['novalidation'] ) || $pParamHash['novalidation'] != 'yes') ) {
if( !empty( $pParamHash["recaptcha_challenge_field"] ) && !empty( $pParamHash["recaptcha_response_field"] ) ) {
$resp = recaptcha_check_answer ( $gBitSystem->getConfig( 'users_register_recaptcha_private_key' ), $_SERVER["REMOTE_ADDR"], $pParamHash["recaptcha_challenge_field"], $pParamHash["recaptcha_response_field"] );
$this->mErrors['recaptcha'] = $resp->error;
$this->mErrors['recaptcha'] = 'Wrong Answer';
if( $gBitSystem->isFeatureActive( 'users_register_smcaptcha' ) && (empty( $pParamHash['novalidation'] ) || $pParamHash['novalidation'] != 'yes') ) {
if( !empty( $pParamHash['adcopy_challenge'] ) && !empty( $pParamHash['adcopy_response'] ) ) {
$solvemediaResponse = solvemedia_check_answer($gBitSystem->getConfig( 'users_register_smcaptcha_v_key' ), $_SERVER["REMOTE_ADDR"], $pParamHash["adcopy_challenge"], $pParamHash["adcopy_response"], $gBitSystem->getConfig( 'users_register_smcaptcha_h_key' ) );
if( !$solvemediaResponse->is_valid ) {
$this->mErrors['smcaptcha'] = $solvemediaResponse->error;
$this->mErrors['smcaptcha'] = 'Wrong Answer';
* A collection of values to verify before a user can register
* Separated from BitUser::verify so that import verification can
* be processed with less rigor than user submitted requests
if( $gBitSystem->isFeatureActive( 'users_register_require_passcode' ) ) {
if( $pParamHash["passcode"] != $gBitSystem->getConfig( "users_register_passcode",md5( $this->genPass() ) ) ) {
$this->mErrors['passcode'] = 'Wrong passcode! You need to know the passcode to register at this site';
* @param array $pPassword
* @param array $pPassword2
* @return FALSE on success, Error string on failure
$minPassword = $gBitSystem->getConfig( 'users_min_pass_length', 4 );
if( strlen( $pPassword ) < $minPassword ) {
return ( tra( 'Your password should be at least '. $minPassword. ' characters long' ));
if( !empty( $pPassword2 ) && $pPassword != $pPassword2 ) {
return( tra( 'The passwords do not match' ));
if( $gBitSystem->isFeatureActive( 'users_pass_chr_num' ) && ( !preg_match_all( "/[0-9]+/",$pPassword,$foo ) || !preg_match_all( "/[A-Za-z]+/",$pPassword,$foo ))) {
return ( tra( 'Password must contain both letters and numbers' ));
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
$work = fgets( $pConnect, 1024 );
* @return TRUE on success, FALSE on failure, or -1 if verifyMX had a connection failure - mErrors will contain reason for failure
// check for existing user first, so root@localhost doesn't get attempted to re-register
if( !empty( $this ) && is_object( $this ) && $this->userExists( array( 'email' => $pEmail ) ) ) {
$pErrors['email'] = 'The email address "'. $pEmail. '" has already been registered.';
// during install we have some <user>@localhost as email address. we won't cause problems on those
} elseif( $pEmail == 'root@localhost' || $pEmail == 'guest@localhost' ) {
$pErrors['email'] = 'The email address "'. $pEmail. '" is invalid.';
} elseif( $gBitSystem->isFeatureActive( 'users_validate_email' ) ) {
$ret = $this->verifyMX( $pEmail, $mxErrors ) ;
bit_error_log('INVALID EMAIL : '. $pEmail. ' by '. $_SERVER['REMOTE_ADDR'] . ' for '. $mxErrors['email']);
$ret = ( count( $pErrors ) == 0 ) ;
* @return TRUE on success, FALSE on failure, or -1 if verifyMX had a connection failure - mErrors will contain reason for failure
// check for existing user first, so root@localhost doesn't get attempted to re-register
if( $pEmail == 'root@localhost' || $pEmail == 'guest@localhost' ) {
$pErrors['email'] = 'The email address "'. $pEmail. '" is invalid.';
$ret = ( count( $pErrors ) == 0 ) ;
* @param array $pValidate
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function verifyMX( $pEmail, &$pErrors ) {
global $gBitSystem, $gDebug;
$HTTP_HOST= $_SERVER['SERVER_NAME'];
list ( $Username, $domain ) = preg_split ("/@/",$pEmail);
//checkdnsrr will check to see if there are any MX records for the domain
bitdebug( "Confirmation : MX record for {$domain} exists." );
getmxrr ( $domain, $MXHost, $MXWeights );
//create an array that combines the MXWeights with their associated hosts
for( $i = 0; $i < count( $MXHost ); $i++ ) {
$hosts[$MXHost[$i]] = $MXWeights[$i];
//sorts the hosts by weight
if( !empty($hosts)) { //hosts shouldn't be empty here, since we passed the checkdnsrr check, but the server COULD have died between the first and second check.
foreach ($hosts as $host=> $priority){
$Connect = @fsockopen ( $host, 25, $errNo, $errStr, 10 ); // 10 second timeout to open each MX server, seems adequate to me, increase as necessary
bitdebug( "Connection succeeded to {$host} SMTP." );
// Judgment is that a service preparing to begin a transaction will send a 220 string after a succesful handshake
// Inform client's reaching to server who connect.
if( $gBitSystem->hasValidSenderEmail() ) {
$senderEmail = $gBitSystem->getConfig( 'site_sender_email' );
fputs( $Connect, "HELO $HTTP_HOST\r\n" );
// Receive server's answering cord.
// Inform sender's address to server.
fputs ( $Connect, "MAIL FROM: <{$senderEmail}>\r\n" );
bitdebug( "Run : MAIL FROM: <{$senderEmail}>" );
// Receive server's answering cord.
// Inform listener's address to server.
fputs ( $Connect, "RCPT TO: <{$pEmail}>\r\n" );
bitdebug( "Run : RCPT TO: <{$pEmail}>" );
// Receive server's answering cord.
fputs( $Connect, "QUIT\r\n" );
//Checks if we received a 250 OK from the server. If we did not, the server is telling us that this address is not a valid mailbox.
$pErrors['email'] = $pEmail. " is not recognized by the mail server. Try double checking the address for typos." ;
bit_error_log("INVALID EMAIL : ". $pEmail. " SMTP FROM : ". $from. " SMTP TO: ". $to);
break; //break out of foreach and fall through to the end of function
$ret = true;//address has been verified by the server, no more checking necessary
// Yahoo has a bad, bad habit of issuing 420's
bit_error_log("UNKNOWN EMAIL : ". $pEmail. " SMTP response: ". $out);
$pErrors['email'] = 'Connection rejected by MX server';
bit_error_log("INVALID EMAIL : ". $pEmail. " SMTP response: ". $out);
if(!$gBitSystem->getConfig('users_validate_email_role')){ //will ONLY stuff mErrors if you have not set a default role for verifiable emails, otherwise this is not a game breaking case
$pErrors['email'] = "One or more mail servers not responding";
$ret = - 1; //-1 implies ambiguity, MX servers found, but unable to be reached.
$pErrors['email'] = "Mail server not found";
$pErrors['email'] = "Mail server not found";
$pErrors['email'] = "Invalid email syntax";
* register - will handle everything necessary for registering a user and sending appropriate emails, etc.
* @author Christian Fowler<spider@viovio.com>
* @return TRUE on success, FALSE on failure
function register( &$pParamHash, $pNotifyRegistrant= TRUE ) {
global $notificationlib, $gBitSmarty, $gBitSystem;
if( !empty( $_FILES['user_portrait_file'] ) && empty( $_FILES['user_avatar_file'] ) ) {
$pParamHash['user_auto_avatar'] = TRUE;
if( $this->verify( $pParamHash )) {
if( $instance && $instance->canManageAuth() ) {
if( $userId = $instance->createUser( $pParamHash )) {
if( !empty( $pParamHash['verified_email'] ) && $pParamHash['verified_email'] && $gBitSystem->getConfig('users_validate_email_role') ) {
$this->mLogs['register'] = 'New user registered.';
$this->load( FALSE, $pParamHash['login'] );
$notificationlib->post_new_user_event( $pParamHash['login'] );
// set local time zone as default when registering
if( !empty( $_REQUEST['CUSTOM'] ) ) {
foreach( $_REQUEST['CUSTOM'] as $field=> $value ) {
// Handle optional user preferences that may be collected during registration
if( !empty( $pParamHash['prefs'] ) ) {
foreach( array_keys( $pParamHash['prefs'] ) as $key ) {
if( $pNotifyRegistrant ) {
$siteName = $gBitSystem->getConfig('site_title', $_SERVER['HTTP_HOST'] );
$gBitSmarty->assign( 'siteName',$_SERVER["SERVER_NAME"] );
$gBitSmarty->assign( 'mail_site',$_SERVER["SERVER_NAME"] );
$gBitSmarty->assign( 'mail_user',$pParamHash['login'] );
if( $gBitSystem->isFeatureActive( 'users_validate_user' ) ) {
// $apass = addslashes(substr(md5($gBitSystem->genPass()),0,25));
$apass = $pParamHash['user_store']['provpass'];
$foo1 = str_replace( "register", "confirm", $foo["path"] );
$gBitSmarty->assign( 'msg',tra( 'You will receive an email with information to login for the first time into this site' ));
$gBitSmarty->assign( 'mail_machine',$machine );
$gBitSmarty->assign( 'mailUserId',$this->mUserId );
$gBitSmarty->assign( 'mailProvPass',$apass );
$mail_data = $gBitSmarty->fetch( 'bitpackage:users/user_validation_mail.tpl' );
mail( $pParamHash["email"], $siteName. ' - '. tra( 'Your registration information' ), $mail_data, "From: ". $gBitSystem->getConfig('site_sender_email'). "\nContent-type: text/plain;charset=utf-8\n" );
$gBitSmarty->assign( 'showmsg', 'y' );
$this->mLogs['confirm'] = 'Validation email sent.';
} elseif( $gBitSystem->isFeatureActive( 'send_welcome_email' ) ) {
$gBitSmarty->assign( 'mailPassword',$pParamHash['password'] );
$gBitSmarty->assign( 'mailEmail',$pParamHash['email'] );
$mail_data = $gBitSmarty->fetch( 'bitpackage:users/welcome_mail.tpl' );
mail( $pParamHash["email"], tra( 'Welcome to' ). ' '. $siteName, $mail_data, "From: ". $gBitSystem->getConfig( 'site_sender_email' ). "\nContent-type: text/plain;charset=utf-8\n" );
$this->mLogs['welcome'] = 'Welcome email sent.';
$logHash['action_log']['title'] = $pParamHash['login'];
* @return TRUE on success, FALSE on failure
if( $this->hasPermission( 'p_users_bypass_captcha' ) || ( !empty( $_SESSION['captcha_verified'] ) && $_SESSION['captcha_verified'] === TRUE ) ) {
if( empty( $pCaptcha ) || empty( $_SESSION['captcha'] ) || $_SESSION['captcha'] != md5( $pCaptcha ) ) {
$_SESSION['captcha_verified'] = TRUE;
* @param array $pParamHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function store( &$pParamHash ) {
if( $this->verify( $pParamHash ) ) {
$this->mDb->StartTrans();
if( !empty( $pParamHash['user_store'] ) && count( $pParamHash['user_store'] ) ) {
$userId = array ( "user_id" => $this->mUserId );
$result = $this->mDb->associateUpdate( BIT_DB_PREFIX. 'users_users', $pParamHash['user_store'], $userId );
if( empty( $pParamHash['user_store']['user_id'] ) ) {
$pParamHash['user_store']['user_id'] = $this->mDb->GenID( 'users_users_user_id_seq' );
$this->mUserId = $pParamHash['user_store']['user_id'];
$result = $this->mDb->associateInsert( BIT_DB_PREFIX. 'users_users', $pParamHash['user_store'] );
// Prevent liberty from assuming ANONYMOUS_USER_ID while storing
$pParamHash['user_id'] = $this->mUserId;
// Don't let LA snarf these now so we can do extra things.
$pParamHash['_files_override'] = array();
if( empty( $this->mInfo['content_id'] ) || ($pParamHash['content_id'] != $this->mInfo['content_id']) ) {
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `content_id`=? WHERE `user_id`=?";
$result = $this->mDb->query( $query, array( $pParamHash['content_id'], $this->mUserId ) );
$this->mInfo['content_id'] = $pParamHash['content_id'];
$this->mDb->CompleteTrans();
* Imports a user record from csv file
* This is a admin specific function
* @param $pParamHash an array with user data
* @return TRUE if import succeed
if( ! $gBitUser->hasPermission( 'p_users_admin' ) ) {
$this->mDb->StartTrans();
if( !empty( $pParamHash['user_store'] ) && count( $pParamHash['user_store'] ) ) {
// lookup and asign the default role for user
if( !empty( $defaultRoles ) ) {
$pParamHash['user_store']['default_role_id'] = key( $defaultRoles );
$userId = array ( "user_id" => $this->mUserId );
$result = $this->mDb->associateUpdate( BIT_DB_PREFIX. 'users_users', $pParamHash['user_store'], $userId );
if( empty( $pParamHash['user_store']['user_id'] ) ) {
$pParamHash['user_store']['user_id'] = $this->mDb->GenID( 'users_users_user_id_seq' );
$this->mUserId = $pParamHash['user_store']['user_id'];
$result = $this->mDb->associateInsert( BIT_DB_PREFIX. 'users_users', $pParamHash['user_store'] );
// make sure user is added into the default role map
if( !empty( $pParamHash['user_store']['default_role_id'] ) ) {
// Prevent liberty from assuming ANONYMOUS_USER_ID while storing
$pParamHash['user_id'] = $this->mUserId;
if( empty( $this->mInfo['content_id'] ) || $pParamHash['content_id'] != $this->mInfo['content_id'] ) {
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `content_id`=? WHERE `user_id`=?";
$result = $this->mDb->query( $query, array( $pParamHash['content_id'], $this->mUserId ) );
$this->mInfo['content_id'] = $pParamHash['content_id'];
$this->mDb->CompleteTrans();
// store any uploaded images
* Verify and validate the data when
* importing a user record from csv file
* This is a admin specific function
* @param $pParamHash an array with user data
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
global $gBitSystem, $gBitUser;
if( ! $gBitUser->hasPermission( 'p_users_admin' ) ) {
// perhaps someone is importing users and *knows* what they are doing
if( @$this->verifyId( $pParamHash['user_id'] ) ) {
// only import user_id if it doesn't exist or overwrite is set.
if( !$this->userExists( array( 'user_id' => $pParamHash['user_id'] ) ) || !empty( $_REQUEST['overwrite'] ) ) {
$pParamHash['user_store']['user_id'] = $pParamHash['user_id'];
unset ( $pParamHash['user_id'] );
if( !empty( $pParamHash['login'] ) ) {
$ret = $this->userExists( array( 'login' => $pParamHash['login'] ) );
// On batch import admin can overwrite existing user, so don't error if set
// however, prevent overwrite of a mix of user records
if( !empty( $_REQUEST['overwrite'] ) && (!isset ($pParamHash['user_store']['user_id']) || $pParamHash['user_store']['user_id'] == $ret ) ) {
$pParamHash['user_id'] = $ret;
$pParamHash['user_store']['user_id'] = $pParamHash['user_id'];
$this->mErrors['login'] = 'The username "'. $pParamHash['login']. '" is already in use';
} elseif( preg_match( '/[^A-Za-z0-9_.-]/', $pParamHash["login"] ) ) {
$this->mErrors['login'] = tra( "Your username can only contain numbers, characters, underscores and hyphens." );
if( !isset ($this->mErrors['login']) ) {
$pParamHash['login'] = strtolower($pParamHash['login']);
$pParamHash['user_store']['login'] = $pParamHash['login'];
$this->mErrors['login'] = 'Value for username is missing';
if( !empty( $pParamHash['real_name'] ) ) {
$pParamHash['user_store']['real_name'] = substr( $pParamHash['real_name'], 0, 64 );
if( !empty( $pParamHash['email'] ) ) {
// LOWER CASE all emails admin_verify_email
$pParamHash['email'] = strtolower( $pParamHash['email'] );
$ret = $this->userExists( array( 'email' => $pParamHash['email'] ) );
if( !empty( $_REQUEST['overwrite'] ) && (!isset ($pParamHash['user_store']['user_id']) || $pParamHash['user_store']['user_id'] == $ret ) ) {
$pParamHash['user_id'] = $ret;
$pParamHash['user_store']['user_id'] = $pParamHash['user_id'];
$this->mErrors['email'] = 'The email address "'. $pParamHash['email']. '" has already been registered.';
if( !empty( $_REQUEST['admin_verify_email'] ) ) {
if( !$this->verifyMX( $pParamHash['email'] ) ) {
$this->mErrors['email'] = 'Cannot find a valid mail server';
if( !isset ($this->mErrors['email']) ) {
$pParamHash['user_store']['email'] = strtolower( substr( $pParamHash['email'], 0, 200 ) );
$this->mErrors['email'] = 'The email address "'. $pParamHash['email']. '" has an invalid syntax.';
$this->mErrors['email'] = tra( 'You must enter your email address' );
// check some new user requirements
if( isset ($pParamHash['user_store']['user_id']) && !empty( $_REQUEST['overwrite'] ) ) {
$this->mUserId = $this->userExists( array( 'user_id' => $pParamHash['user_store']['user_id'] ) );
if( empty( $pParamHash['registration_date'] ) ) {
$pParamHash['registration_date'] = date( "U" );
$pParamHash['user_store']['registration_date'] = $pParamHash['registration_date'];
if( !empty($pParamHash['hash'] ) ) {
unset ( $pParamHash['password'] );
if($gBitSystem->isFeatureActive( 'users_clear_passwords' ) ) {
$this->mErrors['password'] = tra( 'You cannot import a password hash when setting to stor password in plan text is set.' );
} elseif( strlen( $pParamHash['hash'] ) <> 32 ) {
$this->mErrors['password'] = tra( 'When importing a MD5 password hash it needto have a length of 32 bytes.' );
if( !empty( $_REQUEST['admin_verify_user'] ) ) {
$pParamHash['user_store']['hash'] = '';
$pParamHash['pass_due'] = 0;
unset ( $pParamHash['password'] );
} elseif( empty($pParamHash['password'] ) ) {
$pParamHash['password'] = $gBitSystem->genPass();
// Prevent loosing user info on save
if( empty( $pParamHash['edit'] ) ) {
$pParamHash['edit'] = $this->mInfo['data'];
if( isset ( $pParamHash['password'] ) ) {
if (!$this->isValid() || isset ($pParamHash['password']) ) {
if( !empty( $passswordError ) ) {
$this->mErrors['password'] = $passswordError;
// Generate a unique hash
//$pParamHash['user_store']['hash'] = md5( strtolower( (!empty($pParamHash['login'])?$pParamHash['login']:'') ).$pPassword.$pParamHash['email'] );
$pParamHash['user_store']['hash'] = md5( $pParamHash['password'] );
$now = $gBitSystem->getUTCTime();
if( !isset ( $pParamHash['pass_due'] ) && $gBitSystem->getConfig('users_pass_due') ) {
$pParamHash['user_store']['pass_due'] = $now + (60 * 60 * 24 * $gBitSystem->getConfig('users_pass_due') );
} elseif( isset ( $pParamHash['pass_due'] ) ) {
// renew password only next half year ;)
$pParamHash['user_store']['pass_due'] = $now + (60 * 60 * 24 * $pParamHash['pass_due']);
if( $gBitSystem->isFeatureActive( 'users_clear_passwords' ) ) {
$pParamHash['user_store']['user_password'] = $pParamHash['password'];
$pParamHash['user_store']['user_password'] = '';
} elseif( !empty( $pParamHash['hash'] )) {
$pParamHash['user_store']['hash'] = $pParamHash['hash'];
$now = $gBitSystem->getUTCTime();
if( !isset ( $pParamHash['pass_due'] ) && $gBitSystem->getConfig( 'users_pass_due' )) {
$pParamHash['user_store']['pass_due'] = $now + ( 60 * 60 * 24 * $gBitSystem->getConfig( 'users_pass_due' ));
} elseif( isset ( $pParamHash['pass_due'] ) ) {
// renew password only next half year ;)
$pParamHash['user_store']['pass_due'] = $now + ( 60 * 60 * 24 * $pParamHash['pass_due'] );
* expunge removes user and associated private data
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function expunge( $pExpungeContent = NULL ) {
$this->mDb->StartTrans();
if( !empty( $pExpungeContent ) ) {
if( $pExpungeContent == 'all' ) {
if( $userContent = $this->mDb->getAssoc( "SELECT content_id, content_type_guid FROM `". BIT_DB_PREFIX. "liberty_content` WHERE `user_id`=? AND `content_type_guid` != 'bituser'", array( $this->mUserId ) ) ) {
foreach( $userContent as $contentId=> $contentTypeGuid ) {
foreach( $userTables as $table ) {
$query = "DELETE FROM `". BIT_DB_PREFIX. $table. "` WHERE `user_id` = ?";
$result = $this->mDb->query( $query, array( $this->mUserId ) );
$logHash['action_log']['title'] = $this->mInfo['login'];
$this->mLogs['user_del'] = 'User deleted';
$this->mDb->CompleteTrans();
$this->mDb->RollbackTrans();
$gBitSystem->fatalError( tra( 'The anonymous user cannot be deleted' ) );
// {{{ ==================== Sessions and logging in and out methods ====================
* @param array $pSessionId
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
global $gLightWeightScan;
global $gBitSystem, $gBitUser;
$update['last_get'] = $gBitSystem->getUTCTime();
$update['current_view'] = $_SERVER['SCRIPT_NAME'];
if( empty( $gLightWeightScan ) ) {
$row = $this->mDb->getRow( "SELECT `last_get`, `connect_time`, `get_count`, `user_agent`, `current_view` FROM `". BIT_DB_PREFIX. "users_cnxn` WHERE `cookie`=? ", array( $pSessionId ) );
if( $gBitUser->isRegistered() ) {
$update['user_id'] = $gBitUser->mUserId;
if( empty( $row['ip'] ) || $row['ip'] != $_SERVER['REMOTE_ADDR'] ) {
$update['ip'] = $_SERVER['REMOTE_ADDR'];
if( !empty( $_SERVER['HTTP_USER_AGENT'] ) && (empty( $row['user_agent'] ) || $row['user_agent'] != $_SERVER['HTTP_USER_AGENT']) ) {
$update['user_agent'] = (string) substr( $_SERVER['HTTP_USER_AGENT'], 0, 128 );
$update['get_count'] = $row['get_count'] + 1;
$ret = $this->mDb->associateUpdate( BIT_DB_PREFIX. 'users_cnxn', $update, array( 'cookie' => $pSessionId ) );
$update['user_id'] = $this->mUserId;
$update['ip'] = $_SERVER['REMOTE_ADDR'];
// truncate length & cast substr to (string) to prevent insert fatals if substr returns false
$update['user_agent'] = (string) substr( $_SERVER['HTTP_USER_AGENT'], 0, 128 );
$update['get_count'] = 1;
$update['connect_time'] = $update['last_get'];
$update['cookie'] = $pSessionId;
// Delete old connections nightly during the hour of 3 am
// This needs moving to an event that is known to happen
if( date( 'H' ) == '03' && date( 'i' ) > 0 && date( 'i' ) < 2 ) {
// Default to 30 days history
$oldy = $update['last_get'] - ($gBitSystem->getConfig( 'users_cnxn_history_days', 30 ) * 24 * 60 * 60);
$query = "DELETE from `". BIT_DB_PREFIX. "users_cnxn` where `connect_time` < ?";
$result = $this->mDb->query($query, array($oldy));
* @return count of sessions
$query .= " WHERE `cookie` IS NOT NULL";
return $this->mDb->getOne( $query,array() );
// ensure Guest default page is loaded if required
$this->mInfo['default_role_id'] = - 1;
$siteCookie = static::getSiteCookieName();
if( $pCookie === TRUE ) {
} elseif( $pCookie== FALSE ) {
$pCookie = ''; // unset the cookie, eg logout
if( !empty( $_COOKIE[$siteCookie] ) ) {
$this->mDb->query( "UPDATE `". BIT_DB_PREFIX. "users_cnxn` SET `cookie`=NULL WHERE `cookie`=?", array( $_COOKIE[$siteCookie] ) );
unset ( $_COOKIE[$siteCookie] );
if( !empty( $pCookie ) ) {
// Now if the remember me feature is on and the user checked the user_remember_me checkbox then ...
if( $gBitSystem->isFeatureActive( 'users_remember_me' ) && isset ( $_REQUEST['rme'] ) && $_REQUEST['rme'] == 'on' ) {
$cookieTime = (int) ( time() + (int) $gBitSystem->getConfig( 'users_remember_time', 86400 ));
$cookiePath = $gBitSystem->getConfig( 'cookie_path', $cookiePath );
$cookieDomain = $gBitSystem->getConfig( 'cookie_domain', $cookieDomain );
setcookie( $siteCookie, $pCookie, $cookieTime , $cookiePath, $cookieDomain );
$_COOKIE[$siteCookie] = $pCookie;
$cookie_site = strtolower( preg_replace( "/[^a-zA-Z0-9]/", "", $gBitSystem->getConfig( 'site_title', 'bitweaver' )));
return( 'bit-user-'. $cookie_site );
* @param array $pFatalOnError
* @param array $pForceCheck
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function verifyTicket( $pFatalOnError= TRUE, $pForceCheck= TRUE ) {
global $gBitSystem, $gBitUser;
if( $pForceCheck == TRUE || !empty( $_REQUEST['tk'] ) ) {
if( empty( $_REQUEST['tk'] ) || (!($ret = $_REQUEST['tk'] == $this->mTicket ) && $pFatalOnError) ) {
$userString = $gBitUser->isRegistered() ? "\nUSER ID: ". $gBitUser->mUserId. ' ( '. $gBitUser->getField( 'email' ). ' ) ' : '';
error_log( tra( "Security Violation" ). "$userString ". $_SERVER['REMOTE_ADDR']. "\nURI: $_SERVER[REQUEST_URI] \nREFERER: $_SERVER[HTTP_REFERER] " );
$gBitSystem->fatalError( tra( "Security Violation" ));
// {{{ ==================== Banning ====================
* ban sets the user account status to -201 suspended
* @return TRUE on success, Display error message on failure
$gBitSystem->fatalError( tra( 'You cannot ban the user' ). " ". $this->mInfo['login'] );
* @return TRUE on success
* genPass generate random password
* @param array $pLength Length of final password
function genPass( $pLength= NULL ) {
$vocales = "AaEeIiOoUu13580";
$consonantes = "BbCcDdFfGgHhJjKkLlMmNnPpQqRrSsTtVvWwXxYyZz24679";
if( empty( $pLength ) || !is_numeric( $pLength ) ) {
$pLength = $gBitSystem->getConfig( 'users_min_pass_length', 4 );
for( $i = 0; $i < $pLength; $i++ ) {
$ret .= $vocales{rand( 0, strlen( $vocales ) - 1 )};
$ret .= $consonantes{rand( 0, strlen( $consonantes ) - 1 )};
* @param array $pPassword
* @param array $pChallenge
* @param array $pResponse
* @return URL the user should be sent to after login
function login( $pLogin, $pPassword, $pChallenge= NULL, $pResponse= NULL ) {
$loginCol = strpos( $pLogin, '@' ) ? 'email' : 'login';
$this->mDb->StartTrans();
if( $this->validate( $pLogin, $pPassword, $pChallenge, $pResponse )) {
$userInfo = $this->getUserInfo( array( $loginCol => $pLogin ));
// If the password is valid but it is due then force the user to change the password by
// sending the user to the new password change screen without letting him use
// The user must re-nter the old password so no secutiry risk here
// Redirect the user to the screen where he must change his password.
// Note that the user is not logged in he's just validated to change his password
// The user must re-enter his old password so no secutiry risk involved
$url = USERS_PKG_URL. 'change_password.php?user_id='. $userInfo['user_id'];
// User is valid and not due to change pass..
$this->mUserId = $userInfo['user_id'];
// if role home is set for this user we get that
// default to general post-login
// @see BitSystem::getIndexPage
// getHomeRole is RolePermUser method
(( @$this->verifyId( $this->mInfo['default_role_id'] ) && ( $role_home = $this->getHomeRole( $this->mInfo['default_role_id'] ) ) ) ||
( $gBitSystem->getConfig( 'default_home_role' ) && ( $role_home = $this->getHomeRole( $gBitSystem->getConfig( 'default_home_role' ) ) ) )) ){
$indexType = 'role_home';
$url = isset ($_SESSION['loginfrom']) ? $_SESSION['loginfrom'] : $gBitSystem->getIndexPage( $indexType );
unset ( $_SESSION['loginfrom'] );
// before we give up lets see if the user exists and if the password is expired
$query = "select `email`, `user_id`, `user_password` from `". BIT_DB_PREFIX. "users_users` where " . $this->mDb->convertBinary(). " $loginCol = ?";
$result = $this->mDb->getRow( $query, array( $pLogin ) );
if( !empty( $result['user_id'] ) && $this->isPasswordDue( $result['user_id'] ) ) {
// user needs email password reset so send it and let them know
$url = USERS_PKG_URL. 'remind_password.php?remind=y&required=y&username='. $pLogin;
$this->mErrors['login'] = tra( 'Invalid username or password' );
$this->mDb->CompleteTrans();
// check for HTTPS mode and redirect back to non-ssl when not requested, or a SSL login was forced
if( isset ( $_SERVER['HTTPS'] ) && strtolower( $_SERVER['HTTPS'] ) == 'on' ) {
$refererSsl = isset ( $_SERVER['HTTP_REFERER'] ) && substr( $_SERVER['HTTP_REFERER'], 0, 5 ) == 'https';
if( ($gBitSystem->getConfig( 'site_https_login_required' ) && !$refererSsl) ) {
// start setting up the URL redirect without SSL
$prefix = 'http://' . $gBitSystem->getConfig( 'site_http_domain', $_SERVER['HTTP_HOST'] );
// add port to prefix if needed
$port = $gBitSystem->getConfig( 'site_http_port', 80 );
$prefix .= $gBitSystem->getConfig( 'site_http_prefix', BIT_ROOT_URL );
* @param array $pChallenge
* @param array $pResponse
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
* @todo rewrite this mess. this is horrible stuff. - xing - Thursday Oct 16, 2008 09:47:20 CEST
function validate( $pUser, $pPass, $pChallenge, $pResponse ) {
// these will help us keep tabs of what is going on
$authValid = $authPresent = FALSE;
$createAuth = ( $gBitSystem->getConfig( "users_create_user_auth", "n" ) == "y" );
$result = $instance->validate( $pUser, $pPass, $pChallenge, $pResponse );
// this mErrors assignment is CRUCIAL so that bit auth fails properly. DO NOT FUCK WITH THIS unless you know what you are doing and have checked with me first. XOXOX - spiderr
// This might have broken other auth, but at this point, bw auth was TOTALLY busted. If you need to fix, please come find me.
$this->mErrors['login'] = 'Password incorrect';
if( empty( $instance->mInfo['email'] )) {
$instance->mInfo['email'] = $pUser;
//If we're given a user_id then the user is already in the database:
if( !empty( $instance->mInfo['user_id'] )) {
$this->mUserId = $instance->mInfo['user_id'];
//Is the user already in the database:
} elseif( $this->mDb->getOne( "SELECT COUNT(*) FROM `". BIT_DB_PREFIX. "users_users` WHERE `login` = ?", array( $instance->mLogin )) > 0 ) {
'login' => $instance->mInfo['login'],
'password' => $instance->mInfo['password'],
'real_name' => $instance->mInfo['real_name'],
'email' => $instance->mInfo['email']
$userInfo = $this->getUserInfo( array( 'login' => $pUser ));
$this->mUserId = $userInfo['user_id'];
$this->store( $authUserInfo );
'login' => $instance->mInfo['login'],
'password' => $instance->mInfo['password'],
'real_name' => $instance->mInfo['real_name'],
'email' => $instance->mInfo['email']
// TODO somehow, mUserId gets set to -1 at this point - no idea how
// set to NULL to prevent overwriting Guest user - wolff_borg
$this->store( $authUserInfo );
if( $createAuth && $i > 0 ) {
// if the user was logged into this system and we should progate users down other auth methods
for( $j = $i; $i >= 0; $j-- ) {
$probMethodName = $gBitSystem->getConfig( "users_auth_method_$j", $default );
if( !empty( $probMethodName )) {
if( $probInstance && $probInstance->canManageAuth() ) {
$result = $probInstance->validate( $pUser, $pPass, $pChallenge, $pResponse );
// see if we can create a new account
$userattr = $instance->getUserData();
if( empty( $userattr['login'] )) {
$userattr['login'] = $pUser;
if( empty( $userattr['password'] )) {
$userattr['password'] = $pPass;
$probInstance->createUser( $userattr );
$this->mAuth = $instance;
//on first time login we run the users registation service
if( $this->mInfo['last_login'] == NULL ) {
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `last_login` = `current_login`, `current_login` = ? WHERE `user_id` = ?";
$result = $this->mDb->query( $query, array( $gBitSystem->getUTCTime(), $pUserId ));
* @param array $pProvpass
* @return registered user, empty array on failure
SELECT `user_id`, `provpass`, `user_password`, `login`, `email` FROM `". BIT_DB_PREFIX. "users_users`
WHERE `user_id`=? AND `provpass`=? AND ( `provpass_expires` IS NULL OR `provpass_expires` > ?)";
return( $this->mDb->getRow( $query, array( $pUserId, $pProvpass, $gBitSystem->getUTCTime() )));
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
$this->mErrors['bad_mail'] = tra( "The email address provided does not have recognised valid syntax." );
} elseif( $this->userExists( array( 'email' => $pEmail ))) {
$this->mErrors['duplicate_mail'] = tra( "The email address you selected already exists." );
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `email`=? WHERE `user_id`=?";
$result = $this->mDb->query( $query, array( $pEmail, $pUserId ) );
$query = "UPDATE `". BIT_DB_PREFIX. "users_watches` SET `email`=? WHERE `user_id`=?";
$result = $this->mDb->query( $query, array( $pEmail, $pUserId ) );
$this->mInfo['email'] = $pEmail;
* @param array $iHomepage
* @return user_id that can be used to point to users homepage
// iHomepage is the user_id for the user...
// force to proper integer to get things like "007." to properly query
$iHomepage = (integer) $iHomepage;
} elseif( substr( $iHomepage, 0, 7 ) == 'mailto:' ) {
// iHomepage is the email address of the user...
// iHomepage is the 'login' of the user...
$tmpUser = $this->getUserInfo( array( $key => $iHomepage ));
if( @$this->verifyId( $tmpUser['user_id'] )) {
$ret = $tmpUser['user_id'];
* @param array $pPrefName
* @param array $pPrefDefault
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
// Alternate to LibertyContent::getPreference when all you have is a user_id and a pref_name, and you need a value...
if( BitBase::verifyId( $pUserId ) ) {
SELECT lcp.`pref_value` FROM `". BIT_DB_PREFIX. "liberty_content_prefs` lcp INNER JOIN `". BIT_DB_PREFIX. "users_users` uu ON (lcp.`content_id`=uu.`content_id`)
WHERE uu.`user_id` = ? AND lcp.`pref_name` = ?";
if( !$ret = $gBitDb->getOne( $query, array( $pUserId, $pPrefName ))) {
* getUserInfo will fetch the user info of a given user
* @param array $pUserMixed hash key can be any column in users_users table e.g.: 'login', 'user_id', 'email', 'content_id'
* @return user info on success, NULL on failure
if( $val = current( $pUserMixed ) ) {
$col = "UPPER( uu.`". key( $pUserMixed ). "` ) ";
$col = " uu.`". key( $pUserMixed ). "` ";
if( $val > 0x1FFFFFFF ) {
// 32 bit overflow, set to zero to avoid fatal error in databases with 32 bit signed integer columns
$query = "SELECT uu.* FROM `". BIT_DB_PREFIX. "users_users` uu LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_content` lc ON (lc.`content_id`=uu.`content_id`) WHERE $col = ?";
$ret = $this->mDb->getRow( $query, array( $val ));
* isUserPublic Determine if an arbitrary user can be viewed by non-permissioned users.
* @param array $pUserId user_id of user to query visibility, if NULL will use this object
* @return boolean if user is publically visible
if( BitBase::verifyId( $pUserId ) ) {
} elseif( isset ( $this ) && $this->isValid() ) {
return $infoPref == 'private';
* getByHash get user from cookie hash
$query = "SELECT `user_id` FROM `". BIT_DB_PREFIX. "users_cnxn` WHERE `cookie` = ?";
return $this->mDb->getOne( $query, array( $pHash ));
* isPasswordDue work out if a user has to change their password
* @return TRUE when the password is due, FALSE if it isn't, NULL when no due time is set
* @note NULL password due means *no* expiration
if( !empty( $pUserId ) ){
// get user_id to avoid NULL and zero confusion
SELECT `user_id`, `pass_due`
WHERE `pass_due` IS NOT NULL AND `user_id`=? ";
$due = $this->mDb->getRow( $query, array( $pUserId ) );
if( @$this->verifyId( $due['user_id'] ) && !empty( $due['pass_due'] ) ) {
$ret = $due['pass_due'] <= $gBitSystem->getUTCTime();
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
$provpass = md5( $pass );
$loginCol = strpos( $pLogin, '@' ) ? 'email' : 'login';
#temp passwords good for 3 days -- prob should be an config option
$passDue = $gBitSystem->getUTCTime() + ( 60 * 60 * 24 * 3 );
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `provpass` = ?, `provpass_expires` = ? WHERE `". $loginCol. "` = ?";
$result = $this->mDb->query( $query, array( $provpass, $passDue, $pLogin ));
$ret = array( $pass, $provpass );
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
// if renew password config is set then set - otherwise set null to respect no pass due
if( $gBitSystem->getConfig('users_pass_due') ) {
$now = $gBitSystem->getUTCTime();;
// renew password according to config value
$passDue = $now + ( 60 * 60 * 24 * $gBitSystem->getConfig( 'users_pass_due' ));
if( !$gBitSystem->isFeatureActive( 'users_clear_passwords' )) {
$loginCol = strpos( $pLogin, '@' ) ? 'email' : 'login';
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `provpass`= NULL, `provpass_expires` = NULL,`hash`=? ,`user_password`=? ,`pass_due`=? WHERE `". $loginCol. "`=?";
$result = $this->mDb->query( $query, array( $hash, $pPass, $passDue, $pLogin ));
* @param array $pListHash
* @return array of users and what they have been up to
if( empty( $pListHash['sort_mode'] ) ) {
$pListHash['sort_mode'] = 'last_get_desc';
if( !empty( $pListHash['last_get'] ) ) {
$whereSql .= ' AND uc.`last_get` > ? ';
$bindVars[] = time() - $pListHash['last_get'];
if( @BitBase::verifyId( $pListHash['user_id'] ) ) {
$whereSql .= ' AND uc.`user_id` = ? ';
$bindVars[] = $pListHash['user_id'];
if( !empty( $pListHash['ip'] ) ) {
$ips = split( ',', $pListHash['ip'] );
$whereSql .= ' uc.`ip` = ? ';
if( !empty( $pListHash['online'] ) ) {
$whereSql .= ' AND uc.`cookie` IS NOT NULL ';
SELECT DISTINCT uc.`user_id`, `login`, `real_name`, `connect_time`, `ip`, `user_agent`, `last_get`, uu.`content_id`
INNER JOIN `". BIT_DB_PREFIX. "users_users` uu ON (uc.`user_id` = uu.`user_id`)
WHERE uc.`user_id` IS NOT NULL $whereSql
ORDER BY ". $this->mDb->convertSortmode( $pListHash['sort_mode'] );
$result = $this->mDb->query( $query, $bindVars, $pListHash['max_records'], $pListHash['offset'] );
while( $res = $result->fetchRow() ) {
$res['users_information'] = $this->getPreference( 'users_information', 'public', $res['content_id'] );
SELECT COUNT( uc.`user_id` )
INNER JOIN `". BIT_DB_PREFIX. "users_users` uu ON (uc.`user_id` = uu.`user_id`)
WHERE uc.`user_id` IS NOT NULL $whereSql";
$pListHash['cant'] = $this->mDb->GetOne( $countSql, $bindVars );
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
SELECT uu.*, lcp.`pref_value` AS `style`
INNER JOIN `". BIT_DB_PREFIX. "liberty_content_prefs` lcp ON( uu.`content_id` = lcp.`content_id` )
WHERE uu.`login` = ? AND lcp.`pref_name` = ?";
$ret = $this->mDb->getRow( $sql, array( $pLogin, 'domain_style' ) );
* @param array $pContentId
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
$ret['content_id'] = $pContentId;
$ret['style'] = $this->mDb->getOne( "SELECT `pref_value` FROM `". BIT_DB_PREFIX. "liberty_content_prefs` WHERE `content_id`=? AND `pref_name`=?", array( $pContentId, 'domain_style' ));
* canCustomizeTheme check if a user can customise their theme
* @return TRUE on success, FALSE on failure
return( $this->hasPermission( 'p_tidbits_custom_home_theme' ) || $gBitSystem->getConfig( 'users_themes' ) == 'y' || $gBitSystem->getConfig( 'users_themes' ) == 'h' || $gBitSystem->getConfig( 'users_themes' ) == 'u' );
* canCustomizeLayout check if a user can customise their layout
* @return TRUE on success, FALSE on failure
return( $this->hasPermission( 'p_tidbits_custom_home_layout' ) || $gBitSystem->getConfig( 'users_layouts' ) == 'y' || $gBitSystem->getConfig( 'users_layouts' ) == 'h' || $gBitSystem->getConfig( 'users_layouts' ) == 'u' );
// {{{ ==================== image and file functions ====================
* @param array $pInfoHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function getThumbnailUrl( $pSize = 'small', $pInfoHash = NULL, $pSecondaryId = NULL, $pDefault= TRUE ) {
// do some stuff if we are passed a hash-o-crap, not implemented currently
* storeImages will store any user images - please note that uploaded files have to be in predefined keys in $_FILES
* $_FILES['user_portrait_file']
* $_FILES['user_auto_avatar']
* $_FILES['user_logo_file']
* @param array $pParamHash array of options
* @param boolean $pParamHash['user_auto_avatar'] automatically create avatar from portrait
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( isset ( $_FILES['user_portrait_file'] ) && is_uploaded_file( $_FILES['user_portrait_file']['tmp_name'] ) && $_FILES['user_portrait_file']['size'] > 0 ) {
$portraitHash = $pParamHash;
$portraitHash['user_id'] = $this->mUserId;
$portraitHash['upload'] = $_FILES['user_portrait_file'];
$portraitHash['upload']['source_file'] = $_FILES['user_portrait_file']['tmp_name'];
$this->storePortrait( $portraitHash, !empty( $portraitHash['user_auto_avatar'] ));
if( isset ( $_FILES['user_avatar_file'] ) && is_uploaded_file( $_FILES['user_avatar_file']['tmp_name'] ) && $_FILES['user_avatar_file']['size'] > 0 ) {
$avatarHash = $pParamHash;
$avatarHash['user_id'] = $this->mUserId;
$avatarHash['upload'] = $_FILES['user_avatar_file'];
$avatarHash['upload']['source_file'] = $_FILES['user_avatar_file']['tmp_name'];
if( isset ( $_FILES['user_logo_file'] ) && is_uploaded_file( $_FILES['user_logo_file']['tmp_name'] ) && $_FILES['user_logo_file']['size'] > 0 ) {
$logoHash['user_id'] = $this->mUserId;
$logoHash['upload'] = $_FILES['user_logo_file'];
$logoHash['upload']['source_file'] = $_FILES['user_logo_file']['tmp_name'];
* @param array $pStorageHash
* @param array $pGenerateAvatar
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function storePortrait( &$pStorageHash, $pGenerateAvatar = FALSE ) {
// make a copy before the uploaded file disappears
$avatarHash = $pStorageHash;
$avatarHash['upload']['tmp_name'] = $pStorageHash['upload']['tmp_name']. '.av';
copy( $pStorageHash['upload']['tmp_name'], $pStorageHash['upload']['tmp_name']. '.av' );
if( $this->storeUserImage( $pStorageHash, 'portrait' ) && $pGenerateAvatar ) {
@unlink( $pStorageHash['upload']['tmp_name']. '.av' );
* @param array $pStorageHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
* @param array $pStorageHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
* @param array $pStorageHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
// don't do the content thing
$pStorageHash['skip_content_store'] = TRUE;
// setup the hash for central storage functions
$pStorageHash['no_perm_check'] = TRUE;
$pStorageHash['_files_override'][$pType] = $pStorageHash['upload'];
$pStorageHash['_files_override'][$pType]['max_width'] = constant( strtoupper( $pType ). "_MAX_DIM" );
$pStorageHash['_files_override'][$pType]['max_height'] = constant( strtoupper( $pType ). "_MAX_DIM" );
$pStorageHash['_files_override'][$pType]['attachment_id'] = !empty( $this->mInfo["{ $pType}_attachment_id "] ) ? $this->mInfo["{ $pType}_attachment_id "] : NULL;
$pStorageHash['_files_override'][$pType]['user_id'] = $this->mUserId;
$file = $pStorageHash['upload_store']['files'][$pType];
if( empty( $this->mInfo["{ $pType}_attachment_id "] ) || $this->mInfo["{ $pType}_attachment_id "] != $file['attachment_id'] ) {
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `{$pType}_attachment_id` = ? WHERE `user_id`=?";
$result = $this->mDb->query( $query, array( $file['attachment_id'], $this->mUserId ) );
$this->mInfo["{ $pType}_attachment_id "] = $file['attachment_id'];
$pStorageHash["{ $pType}_file_name "] = $file['upload']['dest_branch'];
$this->mErrors["{ $pType}_file "] = 'File '. $pStorageHash['upload_store']['files'][$pType]['name']. ' could not be stored.';
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
$this->mDb->StartTrans();
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `". $pType. "_attachment_id` = NULL WHERE `user_id`=?";
$result = $this->mDb->query( $query, array( $this->mUserId ) );
unset ( $this->mInfo[$pType. '_file_name'] );
unset ( $this->mInfo[$pType. '_attachment_id'] );
unset ( $this->mInfo[$pType. '_url'] );
$this->mDb->CompleteTrans();
* @return TRUE on success, FALSE on failure
* @return TRUE on success, FALSE on failure
* @return TRUE on success, FALSE on failure
// {{{ ==================== Watches ====================
// TODO: clean up all watch functions. these are old and messy. - xing - Thursday Oct 16, 2008 11:07:55 CEST
* @return TRUE on success, FALSE on failure
function storeWatch( $pEvent, $pObject, $pType, $pTitle, $pUrl ) {
$query = "DELETE FROM `". BIT_DB_PREFIX. "users_watches` WHERE `user_id`=? AND `event`=? AND `object`=?";
$this->mDb->query($query,array( $this->mUserId, $pEvent, $pObject ) );
$query = "INSERT INTO `". BIT_DB_PREFIX. "users_watches`(`user_id` ,`event` ,`object` , `email`, `hash`, `watch_type`, `title`, `url`) VALUES(?,?,?,?,?,?,?,?)";
$this->mDb->query( $query, array( $this->mUserId, $pEvent, $pObject, $this->mInfo['email'], $hash, $pType, $pTitle, $pUrl ) );
* @return TRUE on success, FALSE on failure
$mid = " and `event`=? ";
$query = "select * from `". BIT_DB_PREFIX. "users_watches` where `user_id`=? $mid";
$result = $this->mDb->query($query,$bindvars);
while ($res = $result->fetchRow()) {
* @return TRUE on success, FALSE on failure
$query = "SELECT * FROM `". BIT_DB_PREFIX. "users_watches` WHERE `user_id`=? AND `event`=? AND `object`=?";
$result = $this->mDb->query($query,array( $this->mUserId, $pEvent, $pObject ) );
if ( $result->numRows() ) {
$ret = $result->fetchRow();
* @return TRUE on success, FALSE on failure
$query = "select * from `". BIT_DB_PREFIX. "users_watches` tw INNER JOIN `". BIT_DB_PREFIX. "users_users` uu ON ( tw.`user_id`=uu.`user_id` ) where `event`=? and `object`=?";
$result = $this->mDb->query( $query,array( $pEvent,$pObject ));
if( !$result->numRows() ) {
while ($res = $result->fetchRow()) {
* remove_user_watch_by_hash
* @return TRUE on success, FALSE on failure
$query = "DELETE FROM `". BIT_DB_PREFIX. "users_watches` WHERE `hash`=?";
$this->mDb->query( $query,array( $pHash ));
* @return TRUE on success, FALSE on failure
$query = "DELETE FROM `". BIT_DB_PREFIX. "users_watches` WHERE `user_id`=? AND `event`=? AND `object`=?";
$this->mDb->query( $query, array( $this->mUserId, $pEvent, $pObject ));
* @return TRUE on success, FALSE on failure
$query = "select distinct `event` from `". BIT_DB_PREFIX. "users_watches`";
$result = $this->mDb->query($query,array());
while ($res = $result->fetchRow()) {
* @param array $pListHash
* @return list of attachments
$pListHash['user_id'] = $this->mUserId;
return $mime->getAttachmentList( $pListHash );
// {{{ ==================== Favorites ====================
* @param array $pContentId
* @return TRUE on success, FALSE on failure
$this->mDb->query( "INSERT INTO `". BIT_DB_PREFIX. "users_favorites_map` ( `user_id`, `favorite_content_id` ) VALUES (?,?)", array( $this->mUserId, $pContentId ) );
$this->mDb->query( "DELETE FROM `". BIT_DB_PREFIX. "users_favorites_map` WHERE `user_id`=? AND `favorite_content_id`=?", array( $this->mUserId, $pContentId ) );
$rslt = $this->mDb->getOne( "SELECT `favorite_content_id` FROM `". BIT_DB_PREFIX. "users_favorites_map` WHERE `user_id`=? AND `favorite_content_id`=?", array( $this->mUserId, $pContentId ) );
* @see LibertyContent::getContentList
* @return Array of content data
$listHash['user_favs'] = TRUE;
$listHash['order_table'] = 'ufm.';
$listHash['sort_mode'] = 'map_position_desc';
* @return user id of currently loaded user
* @param array $pUserName
* @return URL to users homepage
$ret = override_user_url( $pParamHash );
$rewrite_tag = $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ? 'view/': '';
if ($gBitSystem->isFeatureActive( 'pretty_urls' )
|| $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ) {
$ret = USERS_PKG_URL . $rewrite_tag;
$ret = USERS_PKG_URL . 'index.php?home=';
* @param array $pUserName
* @param array $pDisplayHash
* @return get a link to the the users homepage
public function getDisplayLink( $pLinkText= NULL, $pMixed= NULL, $pAnchor= NULL ) {
* @return get the users display name
public function getTitle( $pHash = NULL, $pDefault= TRUE ) {
if( empty( $pHash ) && $this && $this->isValid() ) {
* Get user information for a particular user
* @param pUseLink return the information in the form of a url that links to the users information page
* @param pHash todo - need explanation on how to use this...
* @return display name or link to user information page
global $gBitSystem, $gBitUser;
if( !empty( $pHash['real_name'] ) && $gBitSystem->getConfig( 'users_display_name', 'real_name' ) == 'real_name' ) {
$displayName = $pHash['real_name'];
} elseif( !empty( $pHash['user'] )) {
$displayName = $pHash['user'];
} elseif( !empty( $pHash['login'] )) {
$displayName = $pHash['login'];
} elseif( !empty( $pHash['email'] )) {
$displayName = substr( $pHash['email'], 0, strpos( $pHash['email'], '@' ));
$displayName = $pHash['user_id'];
if( !empty( $pHash['user'] )) {
$iHomepage = $pHash['user'];
} elseif( !empty( $pHash['login'] )) {
// user of 'login' is deprecated and eventually should go away!
$iHomepage = $pHash['login'];
} elseif( BitBase::verifyId( $pHash['user_id'] )) {
$iHomepage = $pHash['user_id'];
} elseif( !empty( $pHash['email'] )) {
$iHomepage = $pHash['email'];
// this won't work right now, we need to alter userslib::interpret_home() to interpret a real name
$iHomepage = $pHash['real_name'];
if( empty( $pHash['users_information'] ) ) {
$pHash['users_information'] = $gBitSystem->mDb->getOne( "SELECT pref_value FROM liberty_content_prefs lcp INNER JOIN users_users uu ON (lcp.content_id=uu.content_id) WHERE uu.login=? AND pref_name='users_information'", array( $pHash['login'] ), 1, NULL, 86400 );
if( $pUseLink && $gBitUser->hasPermission( 'p_users_view_user_homepage' ) && (empty( $pHash['users_information'] ) || $pHash['users_information'] == 'public') ) {
$ret = '<a class="username" title="'. ( !empty( $pHash['link_title'] ) ? $pHash['link_title'] : tra( 'Profile for' ). ' '. htmlspecialchars( $displayName ))
. htmlspecialchars( isset ( $pHash['link_label'] ) ? $pHash['link_label'] : $displayName )
$ret = tra( "Anonymous" );
* Get user information for a particular user
* @param pUseLink return the information in the form of a url that links to the users information page
* @param pHash todo - need explanation on how to use this...
* @return display name or link to user information page
if( empty( $pHash ) && !empty( $this ) && !empty( $this->mInfo )) {
return self::getDisplayNameFromHash( $pUseLink, $pHash );
* getRenderFile Returns include file that will
* @return the fully specified path to file to be included
* getSelectionList get a list of users that can be used in dropdown lists in forms to choose from
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
SELECT uu.`user_id`, uu.`login`, uu.`real_name`
$result = $this->mDb->query( $query );
while( $res = $result->fetchRow()) {
$ret[$res['user_id']] = $res['login']. (( !empty( $res['real_name'] ) && $res['real_name'] != $res['login'] ) ? ' - '. $res['real_name'] : '' );
* getList get a list of users
* @param array $pParamHash
global $gBitSystem, $gBitUser;
if( empty( $pParamHash['sort_mode'] )) {
$pParamHash['sort_mode'] = 'registration_date_desc';
$selectSql = $joinSql = $whereSql = '';
$this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars, NULL, $pParamHash );
// limit search to users with a specific language
if( !empty( $pParamHash['lang_code'] ) ) {
$joinSql .= " INNER JOIN `". BIT_DB_PREFIX. "liberty_content_prefs` lcp ON ( lcp.`content_id`=uu.`content_id` AND lcp.`pref_name`='bitlanguage' )";
$whereSql .= " AND lcp.`pref_value`=? ";
$bindVars[] = $pParamHash['lang_code'];
if( !$gBitUser->hasPermission( 'p_users_admin' ) ) {
$joinSql .= " LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_content_prefs` lcp2 ON ( lcp2.`content_id`=uu.`content_id` AND lcp2.`pref_name`='users_information' )";
$whereSql .= " AND (lcp2.`pref_value` IS NULL OR lcp2.`pref_value`='public')";
// limit search to users with a specific IP
if( !empty( $pParamHash['ip'] ) ) {
$joinSql .= " LEFT OUTER JOIN `". BIT_DB_PREFIX. "users_cnxn` uc ON ( uu.`user_id`=uc.`user_id`) ";
$ips = explode( ',', $pParamHash['ip'] );
$whereSql .= " uc.`ip` LIKE ? ";
$whereSql .= " uc.`ip`=? ";
// limit to registrations over a time period like 'YYYY-MM-DD' or 'Y \Week W' or anything convertible by SQLDate
if( !empty( $pParamHash['period'] ) ) {
$sqlPeriod = $this->mDb->SQLDate( $this->mDb->getPeriodFormat( $pParamHash['period'] ), $this->mDb->SQLIntToTimestamp( 'registration_date' ));
$whereSql .= ' AND '. $sqlPeriod. '=?';
$bindVars[] = $pParamHash['timeframe'];
// lets search for a user
if ( $pParamHash['find'] ) {
$whereSql .= " AND ( UPPER( uu.`login` ) LIKE ? OR UPPER( uu.`real_name` ) LIKE ? OR UPPER( uu.`email` ) LIKE ? ) ";
$bindVars[] = '%'. strtoupper( $pParamHash['find'] ). '%';
$bindVars[] = '%'. strtoupper( $pParamHash['find'] ). '%';
$bindVars[] = '%'. strtoupper( $pParamHash['find'] ). '%';
if( $gBitSystem->isPackageActive( 'stats' ) ) {
$joinSql .= " LEFT OUTER JOIN `". BIT_DB_PREFIX. "stats_referer_users_map` srum ON (srum.`user_id`=uu.`user_id`)
LEFT OUTER JOIN `". BIT_DB_PREFIX. "stats_referer_urls` sru ON (srum.`referer_url_id`=sru.`referer_url_id`)";
$selectSql .= ", sru.`referer_url`";
if( !empty( $pParamHash['referer'] ) ) {
if( $pParamHash['referer'] == 'none' ) {
$whereSql .= " AND `referer_url` IS NULL";
$whereSql .= " AND `referer_url` LIKE ?";
$bindVars[] = '%'. strtolower( $pParamHash['find'] ). '%';
// Return an array of users indicating name, email, last changed pages, versions, last_login
SELECT uu.*, lc.`content_status_id`, lf_ava.`file_name` AS `avatar_file_name`, lf_ava.`mime_type` AS `avatar_mime_type`, la_ava.`attachment_id` AS `avatar_attachment_id` $selectSql
INNER JOIN `". BIT_DB_PREFIX. "liberty_content` lc ON (uu.`content_id`=lc.`content_id`)
LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_content_hits` lch ON ( lc.`content_id` = lch.`content_id` )
LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_attachments` la_ava ON ( uu.`avatar_attachment_id`=la_ava.`attachment_id` )
LEFT OUTER JOIN `". BIT_DB_PREFIX. "liberty_files` lf_ava ON ( lf_ava.`file_id`=la_ava.`foreign_id` )
WHERE lc.`content_type_guid` = ? $whereSql ORDER BY ". $this->mDb->convertSortmode( $pParamHash['sort_mode'] );
$result = $this->mDb->query( $query, $bindVars, $pParamHash['max_records'], $pParamHash['offset'] );
while( $res = $result->fetchRow() ) {
// Used for pulling out dead/empty/spam accounts
if( isset ( $pParamHash['max_content_count'] ) && is_numeric( $pParamHash['max_content_count'] ) ) {
$contentCount = $this->mDb->getOne( "SELECT COUNT(*) FROM `". BIT_DB_PREFIX. "liberty_content` lc INNER JOIN `". BIT_DB_PREFIX. "users_users` uu ON ( lc.`user_id`=uu.`user_id` ) WHERE uu.`user_id`=? AND `content_type_guid` != 'bituser'", array( $res['user_id'] ) );
if( $contentCount > $pParamHash['max_content_count'] ) {
// Used for pulling out non-idle accounts or pigs
if( isset ( $pParamHash['min_content_count'] ) && is_numeric( $pParamHash['min_content_count'] ) ) {
$contentCount = $this->mDb->getOne( "SELECT COUNT(*) FROM `". BIT_DB_PREFIX. "liberty_content` lc INNER JOIN `". BIT_DB_PREFIX. "users_users` uu ON ( lc.`user_id`=uu.`user_id` ) WHERE uu.`user_id`=? AND `content_type_guid` != 'bituser'", array( $res['user_id'] ) );
if( $contentCount < $pParamHash['min_content_count'] ) {
if( !empty( $res['referer_url'] )) {
if ( $gBitSystem->isPackageActive('stats') ) {
$res['short_referer_url'] = stats_referer_display_short($res['referer_url']);
if( !empty( $res['avatar_file_name'] )) {
$res['avatar_url'] = $this->getSourceUrl( array( 'attachment_id'=> $res['avatar_attachment_id'], 'mime_type'=> $res['avatar_mime_type'], 'file_name'=> $res['avatar_file_name'] ) );
'source_file' => $this->getSourceFile( array( 'sub_dir'=> $res['avatar_attachment_id'], 'user_id' => $res['user_id'], 'file_name'=> $res['avatar_file_name'], 'mime_type'=> $res['avatar_mime_type'], 'package'=> liberty_mime_get_storage_sub_dir_name( array( 'mime_type'=> $res['avatar_mime_type'], 'name'=> $res['avatar_file_name'] ) ) ) ),
'file_name' => $res['avatar_url'],
// TODO: Make this a preference
$res["roles"] = $this->getRoles( $res['user_id'] );
$ret[$res['user_id']] = $res;
INNER JOIN `". BIT_DB_PREFIX. "liberty_content` lc ON (uu.`content_id`=lc.`content_id`) $joinSql
WHERE lc.`content_type_guid` = ? $whereSql";
$pParamHash["cant"] = $this->mDb->getOne( $query, $bindVars );
* @param array $pForceRefresh
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function getRoles( $pUserId= NULL, $pForceRefresh = FALSE ) {
$pUserId = !empty( $pUserId ) ? $pUserId : $this->mUserId;
if( !isset ( $this->cUserRoles[$pUserId] ) || $pForceRefresh ) {
SELECT ur.`role_id`, ur.`role_name`, ur.`user_id` as role_owner_user_id
$ret = $this->mDb->getAssoc( $query, array(( int ) $pUserId ));
foreach( $res as $key=> $val) {
$ret[$key] = array( 'role_name' => $val );
$this->cUserRoles[$pUserId] = $ret;
return $this->cUserRoles[$pUserId];
* @return TRUE if user is loaded
* isAdmin "PURE VIRTUAL BASE FUNCTION";
* @return TRUE if user is registered, FALSE otherwise
* @return TRUE if user is registered, otherwise a login dialog is displayed
$gBitSystem->fatalPermission( "", $pMsg );
* @param array $pUserMixed
* @return TRUE on success, FALSE on failure
if( $cur = current( $pUserMixed ) ) {
$conditionSql = " `". key( $pUserMixed ). "` ";
$conditionSql = " UPPER(`". key( $pUserMixed ). "`)";
$query = "SELECT `user_id` FROM `". BIT_DB_PREFIX. "users_users` WHERE $conditionSql = ?";
$ret = $this->mDb->getOne( $query, array( strtoupper( $cur ) ) );
* Create an export hash from the data
'real_name' => $this->getField( 'real_name' ),
'registration_date' => date( DateTime::W3C, $this->getField('registration_date') ),
'last_login' => date( DateTime::W3C, $this->getField('last_login') ),
if( $gBitSystem->isPackageActive( 'stats' ) ) {
$ret['referer'] = $this->mDb->getOne( "SELECT sru.`referer_url` FROM `". BIT_DB_PREFIX. "stats_referer_urls` sru INNER JOIN `". BIT_DB_PREFIX. "stats_referer_users_map` srum ON (srum.`referer_url_id`=sru.`referer_url_id`) WHERE `user_id`=?", $this->mUserId );
if( empty( $pReturn['user_id'] )) {
if( !empty( $gQueryUserId )) {
$pReturn['user_id'] = $gQueryUserId;
} elseif( isset ( $pInput['user_id'] ) ) {
$pReturn['user_id'] = $pInput['user_id'];
if( @BitBase::verifyId( $pInput['role_id'] ) ) {
$pReturn['role_id'] = $pInput['role_id'];
$userClass = $gBitSystem->getConfig( 'user_class', 'BitPermUser' );
if( $ret = new $userClass( $pUserId ) ) {
if( BitBase::verifyId( $pUserId ) ) {
return $gBitDb->getOne( "SELECT COUNT(`content_id`) FROM `". BIT_DB_PREFIX. "liberty_content` lc WHERE lc.`content_type_guid`!='bituser' AND lc.`user_id`=?", array( $pUserId ) );
// {{{ ==================== Services ====================
if( !empty( $pParamHash['user_favs'] ) ){
// $ret['select_sql'] = "";
$ret['join_sql'] = " INNER JOIN `". BIT_DB_PREFIX. "users_favorites_map` ufm ON ( ufm.`favorite_content_id`=lc.`content_id` )";
$ret['where_sql'] = " AND ufm.`user_id` = ?";
$ret['bind_vars'][] = $pObject->mUserId;
if( !empty( $pParamHash['role_id'] ) and BitBase::verifyId( $pParamHash['role_id'] ) ){
// $ret['select_sql'] = "";
$ret['join_sql'] = " INNER JOIN `". BIT_DB_PREFIX. "users_roles_map` urm ON (ugm.`user_id`=uu.`user_id`)";
$ret['where_sql'] = ' AND urm.`role_id` = ? ';
$ret['bind_vars'][] = $pParamHash['role_id'];
/* vim: :set fdm=marker : */
|