$userid))->fetchAssoc(); if (!$vbuser) { return FALSE; } $vb_options = drupalvb_get_options(); $cookie_prefix = drupalvb_get_cookieprefix(); $cookie_path = $vb_options['cookiepath']; $now = time(); $expire = $now + (@ini_get('session.cookie_lifetime') ? ini_get('session.cookie_lifetime') : 60 * 60 * 24 * 365); $vb_cookie_domain = (!empty($vb_options['cookiedomain']) ? $vb_options['cookiedomain'] : $GLOBALS['cookie_domain']); // Per RFC 2109, cookie domains must contain at least one dot other than the // first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain. // @see conf_init() if (!(count(explode('.', $vb_cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $vb_cookie_domain)))) { $vb_cookie_domain = ''; } // Clear out old session (if available). if (!empty($_COOKIE[$cookie_prefix .'sessionhash'])) { drupalvb_db_query("DELETE FROM {session} WHERE sessionhash = :hash", array(":hash" => $_COOKIE[$cookie_prefix .'sessionhash'])); } // Setup user session. $ip = implode('.', array_slice(explode('.', drupalvb_get_ip()), 0, 4 - $vb_options['ipcheck'])); $idhash = md5($_SERVER['HTTP_USER_AGENT'] . $ip); $sessionhash = md5($now . request_uri() . $idhash . $_SERVER['REMOTE_ADDR'] . user_password(6)); $browserstring = substr(trim($_SERVER['HTTP_USER_AGENT']), 0, 100); drupalvb_db_query("REPLACE INTO {session} (sessionhash, userid, host, idhash, lastactivity, location, useragent, loggedin) VALUES (:hash, :userid, :host, :idhash, :lastactivity, :location, :useragent, :loggedin)", array(":hash" => $sessionhash, ":userid" => $vbuser['userid'], ":host" => substr($_SERVER['REMOTE_ADDR'], 0, 15), ":idhash" => $idhash, ":lastactivity" => $now, ":location" => '/forum/', ":useragent" => $browserstring, ":loggedin" => 2)); // Setup cookies. setcookie($cookie_prefix .'sessionhash', $sessionhash, $expire, $cookie_path, $vb_cookie_domain); setcookie($cookie_prefix .'lastvisit', $now, $expire, $cookie_path, $vb_cookie_domain); setcookie($cookie_prefix .'lastactivity', $now, $expire, $cookie_path, $vb_cookie_domain); setcookie($cookie_prefix .'userid', $vbuser['userid'], $expire, $cookie_path, $vb_cookie_domain); setcookie($cookie_prefix .'password', md5($vbuser['password'] . variable_get('drupalvb_license', '')), $expire, $cookie_path, $vb_cookie_domain); return TRUE; } /** * Clear all vB cookies for the current user. * * @see drupalvb_logout(), drupalvb_user_logout() */ function drupalvb_clear_cookies($userid = NULL) { $vb_options = drupalvb_get_options(); $cookie_prefix = drupalvb_get_cookieprefix(); $cookie_path = $vb_options['cookiepath']; $expire = time() - 86400; $vb_cookie_domain = (!empty($vb_options['cookiedomain']) ? $vb_options['cookiedomain'] : $GLOBALS['cookie_domain']); // Per RFC 2109, cookie domains must contain at least one dot other than the // first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain. // @see conf_init() if (!(count(explode('.', $vb_cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $vb_cookie_domain)))) { $vb_cookie_domain = ''; } // @todo Without a vB user id, we cannot delete the session, so vBulletin // will automatically authenticate again. We badly need a solution here, // since this is the cause for broken session handling. Proposal: Use // drupalvb_get_ip() to count the # of sessions; if there exactly one, // kill it. // @ttkaminski's suggestion - validate the sessionhash and userid from the // cookies against the vBulletin session table. If it matches, then kill // the session. if (!empty($userid)) { drupalvb_db_query("DELETE FROM {session} WHERE userid = :userid", array(':userid' => $userid)); drupalvb_db_query("UPDATE {user} SET lastvisit = :time WHERE userid = :userid", array(":time" => time(), ":userid" => $userid)); } setcookie($cookie_prefix .'sessionhash', '', $expire, $cookie_path, $vb_cookie_domain); setcookie($cookie_prefix .'lastvisit', '', $expire, $cookie_path, $vb_cookie_domain); setcookie($cookie_prefix .'lastactivity', '', $expire, $cookie_path, $vb_cookie_domain); setcookie($cookie_prefix .'userid', '', $expire, $cookie_path, $vb_cookie_domain); setcookie($cookie_prefix .'password', '', $expire, $cookie_path, $vb_cookie_domain); } /** * Determines the IP address of current user. * * @todo Duplicate of ip_address() in D6+ ? */ function drupalvb_get_ip() { $ip = $_SERVER['REMOTE_ADDR']; if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) { // Make sure we don't pick up an internal IP defined by RFC1918. foreach ($matches[0] as $match) { if (!preg_match("#^(10|172\.16|192\.168)\.#", $match)) { $ip = $match; break; } } } elseif (isset($_SERVER['HTTP_FROM'])) { $ip = $_SERVER['HTTP_FROM']; } return $ip; } /** * Create a user in vBulletin. * * @param object $account * A Drupal user account. * @param array $edit * Form values provided by hook_user(). */ function drupalvb_create_user($account, $edit) { // Ensure we are not duplicating a user. $userid = drupalvb_db_select("user","u") ->fields("u", array("userid") ) ->condition("username", drupalvb_htmlspecialchars($edit['name']) ) ->execute() ->fetchColumn(0); if(!$userid) { $salt = ''; for ($i = 0; $i < 3; $i++) { $salt .= chr(rand(32, 126)); } // Note: Password is already hashed during user export. if (isset($edit['md5pass'])) { $passhash = md5($edit['md5pass'] . $salt); } else { $passhash = md5(md5($edit['pass']) . $salt); } $time = $account->created; $passdate = date('Y-m-d', $time); $joindate = $time; // Attempt to grab the user title from the database. $result = drupalvb_db_query("SELECT title FROM {usertitle} WHERE minposts = 0"); if ($resarray = $result->fetchAssoc()) { $usertitle = $resarray['title']; } else { $usertitle = 'Junior Member'; } // Divide timezone by 3600, since vBulletin stores hours. $timezone = variable_get('date_default_timezone', 0); $timezone = ($timezone != 0 ? $timezone / 3600 : 0); // Default new user options: I got these by setting up a new user how I // wanted and looking in the database to see what options were set for him. $options = variable_get('drupalvb_default_options', '3415'); // Default usergroup id. $usergroupid = variable_get('drupalvb_default_usergroup', '2'); $lid = drupalvb_get_languageid(); if (!isset($lid)) { $lid = 1; } // Insert user to vBulletin $userid = drupalvb_db_insert("user") ->fields( array( "username" => drupalvb_htmlspecialchars($edit['name']), "usergroupid" => $usergroupid, "password" => $passhash, "passworddate" => $passdate, "usertitle" => $usertitle, "email" => $account->mail, "salt" => $salt, "languageid" => 1, "timezoneoffset" => $timezone, "joindate" => $joindate, "lastvisit" => time(), "lastactivity" => time(), "options" => $options ))->execute(); $rr = drupalvb_db_query("SELECT * FROM {userfield} WHERE userid=1"); $fields = $rr->fetchAssoc(); foreach($fields as $f => $v) $fields[$f] = ''; $fields['userid'] = $userid; drupalvb_db_insert("userfield")->fields($fields)->execute(); $rr = drupalvb_db_query("SELECT * FROM {usertextfield} WHERE userid=1"); $fields = $rr->fetchAssoc(); foreach($fields as $f => $v) $fields[$f] = ''; $fields['userid'] = $userid; drupalvb_db_insert("usertextfield")->fields($fields)->execute(); } // Insert new user into mapping table. drupalvb_set_mapping($account->uid, $userid); // Return userid of newly created account. return $userid; } /** * Update a user in vBulletin. */ function drupalvb_update_user($account, $edit) { $fields = $values = array(); foreach ($edit as $field => $value) { if (empty($value)) { continue; } switch ($field) { case 'name': $fields[] = "username = :name"; $values[':name'] = drupalvb_htmlspecialchars($value); break; case 'current_pass': $fields[] = "password = :password"; $values[':password'] = md5(md5($value) . $edit['salt']); $fields[] = "salt = :salt"; $values[':salt'] = $edit['salt']; $fields[] = "passworddate = :date"; $values[':date'] = date('Y-m-d', time()); break; case 'mail': $fields[] = "email = :email"; $values[':email'] = $value; break; case 'language': $fields[] = "languageid = :lid"; $values[':lid'] = 1; break; } } $fields[] = 'lastactivity = :activity'; $values[':activity'] = time(); // Ensure this user exists in the mapping table. // When integrating an existing installation, the mapping may not yet exist. if (isset($edit['userid'])) { $userid = $edit['userid']; } else { $userid = drupalvb_db_query("SELECT userid FROM {user} WHERE username = :name", array(':name' => drupalvb_htmlspecialchars($account->name)))->fetchField(); } drupalvb_set_mapping($account->uid, $userid); $values[':userid'] = $userid; drupalvb_db_query("UPDATE {user} SET " . implode(', ', $fields) . " WHERE userid=:userid", $values); } /** * Ensure that a mapping between two existing user accounts exists. * * @param $uid * A Drupal user id. * @param $userid * A vBulletin user id. */ function drupalvb_set_mapping($uid, $userid) { db_query("INSERT IGNORE INTO {drupalvb_users} (uid, userid) VALUES (:uid, :userid)", array(':uid' => $uid, ':userid' => $userid)); } /** * Export all drupal users to vBulletin. */ function drupalvb_export_drupal_users() { module_load_include('inc', 'drupalvb'); $result = db_query("SELECT * FROM {users} WHERE uid>0 ORDER BY uid"); foreach ($result as $user) { // Let create/update functions know that passwords are hashed already. $user->md5pass = $user->pass; if (!drupalvb_create_user($user, (array)$user)) { // Username already exists, update email and password only. // Case insensitive username is required to detect collisions. $vbuser = drupalvb_db_query("SELECT salt,userid FROM {user} WHERE LOWER(username) = LOWER(:name)", array(':name' => drupalvb_htmlspecialchars($user->name)))->fetchAssoc(); drupalvb_update_user($user, array_merge((array)$user, $vbuser)); } } } /** * Get vBulletin configuration options. */ function drupalvb_get_options() { static $options = array(); if (empty($options)) { $result = drupalvb_db_query("SELECT varname, value FROM {setting}"); foreach ($result as $var) { $options[$var->varname] = $var->value; } } return $options; } /** * Get vBulletin configuration. * * @return array * An associative array containing the vBulletin configuration, plus * additional key: * - version: The vBulletin version number string, as contained in the first * PHP comment lines of config.php. */ function drupalvb_get_config() { static $config; if (!isset($config)) { $config = array(); $config['version'] = NULL; // @todo Find & include vB's config automatically? // $files = file_scan_directory('.', '^config.php$', $nomask = array('.', '..', 'CVS', '.svn')); $config_file = './' . conf_path() . '/config.php'; if (!file_exists($config_file)) { $config_file = drupal_get_path('module', 'drupalvb') . '/config.php'; } if (file_exists($config_file)) { require_once $config_file; // Additionally parse the vBulletin version out of the php file header, as // some integration functionality needs to account for API changes in // later vBulletin versions. $file = fopen($config_file, 'r'); $max_lines = 10; while ($max_lines && $line = fgets($file, 30)) { if (preg_match('@vBulletin\s+([0-9a-zA-Z\.-]+)@', $line, $version)) { $config['version'] = $version[1]; } $max_lines--; } fclose($file); } } return $config; } /** * Get vB user roles. */ function drupalvb_get_roles() { $result = drupalvb_db_query("SELECT usergroupid, title FROM {usergroup}"); $roles = array(); foreach ($result as $data) { $roles[$data->usergroupid] = $data->title; } if (!$roles) { $roles[] = t('No user roles could be found.'); } return $roles; } /** * Get vB language id by given ISO language code. */ function drupalvb_get_languageid($language = NULL) { //static $vblanguages if (!isset($vblanguages)) { $vblanguages = array(); $result = drupalvb_db_query("SELECT languageid, title, languagecode FROM {language}"); foreach ($result as $lang) { $vblanguages[$lang->languagecode] = $lang->languageid; } } $options = drupalvb_get_options(); return 1; //return (!empty($language) && isset($vblanguages[$language]) ? $vblanguages[$language] : $vblanguages[$options['languageid']]); } /** * Get counts of guests and members currently online. */ function drupalvb_get_users_online() { $vb_options = drupalvb_get_options(); $datecut = time() - $vb_options['cookietimeout']; $numbervisible = 0; $numberregistered = 0; $numberguest = 0; $result = drupalvb_db_query("SELECT user.username, user.usergroupid, session.userid, session.lastactivity FROM {session} AS session LEFT JOIN {user} AS user ON (user.userid = session.userid) WHERE session.lastactivity > :datecut", array(':datecut' => $datecut)); $userinfos = array(); while ($loggedin = $result->fetchAssoc()) { $userid = $loggedin['userid']; if (!$userid) { $numberguest++; } elseif (empty($userinfos[$userid]) || ($userinfos[$userid]['lastactivity'] < $loggedin['lastactivity'])) { $userinfos[$userid] = $loggedin; } } foreach ($userinfos as $userid => $loggedin) { $numberregistered++; } return array('guests' => $numberguest, 'members' => $numberregistered); } /** * Get counts of new or recent posts for the current user. */ function drupalvb_get_recent_posts($scope = 'last') { global $user; // Queries the vB user database to find a matching set of user data. $result = drupalvb_db_query("SELECT userid, username, lastvisit FROM {user} WHERE username = :name", array(':name' => drupalvb_htmlspecialchars($user->name))); // Make sure a user is logged in to get their last visit and appropriate post // count. if ($vb_user = $result->fetchAssoc()) { if ($scope == 'last') { $datecut = $vb_user['lastvisit']; } elseif ($scope == 'daily') { $datecut = time() - 86400; } $posts = drupalvb_db_query("SELECT COUNT(postid) FROM {post} WHERE dateline > :datecut", array(':datecut' => $datecut))->fetchField(); } else { $posts = 0; } return $posts; } function drupalvb_htmlspecialchars($text) { $text = preg_replace('/&(?!#[0-9]+|shy;)/si', '&', $text); return str_replace(array('<', '>', '"'), array('<', '>', '"'), $text); } /** * Get vB cookie prefix. */ function drupalvb_get_cookieprefix() { $vb_config = drupalvb_get_config(); $cookie_prefix = (isset($vb_config['Misc']['cookieprefix']) ? $vb_config['Misc']['cookieprefix'] : 'bb'); // Version 4 began using an underscore following the prefix. if (version_compare($vb_config['version'], 4, '>=')) { $cookie_prefix .= '_'; } return $cookie_prefix; }