/include/api/user.php
PHP | 3295 lines | 1158 code | 274 blank | 1863 comment | 281 complexity | b5ac9d94d404681b080f4d9f563fea24 MD5 | raw file
Possible License(s): LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- <?php
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // Copyright (C) 2010 Phorum Development Team //
- // http://www.phorum.org //
- // //
- // This program is free software. You can redistribute it and/or modify //
- // it under the terms of either the current Phorum License (viewable at //
- // phorum.org) or the Phorum License that was distributed with this file //
- // //
- // This program is distributed in the hope that it will be useful, //
- // but WITHOUT ANY WARRANTY, without even the implied warranty of //
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. //
- // //
- // You should have received a copy of the Phorum License //
- // along with this program. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- /**
- * This script implements the Phorum user API.
- *
- * The user API is used for managing users and user related data. The API
- * does also implement the Phorum session system, which is used for
- * remembering authenticated users. See the documentation for the function
- * {@link phorum_api_user_session_create()} for more information on
- * Phorum user sessions.
- *
- * The Phorum user API supports modules which can override Phorum's
- * authentication and session handling. And example module is provided
- * with the user API documentation.
- *
- * @package PhorumAPI
- * @subpackage UserAPI
- * @copyright 2010, Phorum Development Team
- * @license Phorum License, http://www.phorum.org/license.txt
- *
- * @example user_auth_module.php Authentication override module example
- *
- * @todo Document what fields are in a user record.
- *
- * @todo Create in line docs for all hook calls.
- *
- */
- if (!defined('PHORUM')) return;
- // {{{ Constant and variable definitions
- /**
- * If a user API is written as a replacement for the standard Phorum user API,
- * where the replacement API is incompatible with the standard API, then this
- * define should be set to FALSE. That will disable the user management
- * functions in the admin interface.
- */
- define("PHORUM_ORIGINAL_USER_CODE", TRUE);
- /**
- * Used for identifying long term sessions. The value is used as
- * the name for the session cookie for long term sessions.
- */
- define( 'PHORUM_SESSION_LONG_TERM' , 'phorum_session_v5' );
- /**
- * Used for identifying short term sessions. The value is used as
- * the name for the session cookie for short term sessions
- * (this is used by the tighter authentication scheme).
- */
- define( 'PHORUM_SESSION_SHORT_TERM', 'phorum_session_st' );
- /**
- * Used for identifying admin sessions. The value is used as
- * the name for the session cookie for admin sessions.
- */
- define( 'PHORUM_SESSION_ADMIN', 'phorum_admin_session' );
- /**
- * Function call parameter, which tells various functions that
- * a front end forum session has to be handled.
- */
- define('PHORUM_FORUM_SESSION', 1);
- /**
- * Function call parameter, which tells various functions that
- * an admin back end session has to be handled.
- */
- define('PHORUM_ADMIN_SESSION', 2);
- /**
- * Function call flag, which tells {@link phorum_api_user_set_active_user()}
- * that the short term forum session has to be activated.
- */
- define('PHORUM_FLAG_SESSION_ST', 1);
- /**
- * Function call flag, which tells {@link phorum_api_user_save()} that the
- * password field should be stored as is.
- * This can be used to feed Phorum MD5 encrypted passwords. Normally,
- * the password field would be MD5 encrypted by the function. This will
- * keep the phorum_api_user_save() function from double encrypting the password.
- */
- define('PHORUM_FLAG_RAW_PASSWORD', 1);
- /**
- * Function call flag, which tells {@link phorum_api_user_get_display_name()}
- * that the returned display names have to be HTML formatted, so they can be
- * used for showing the name in HTML pages.
- */
- define('PHORUM_FLAG_HTML', 1);
- /**
- * Function call flag, which tells {@link phorum_api_user_get_display_name()}
- * that the returned display names should be stripped down to plain text
- * format, so they can be used for showing the name in things like mail
- * messages and message quoting.
- */
- define('PHORUM_FLAG_PLAINTEXT', 2);
- /**
- * Function call parameter, which tells {@link phorum_api_user_session_create()}
- * that session ids have to be reset to new values as far as that is sensible
- * for a newly logged in user.
- */
- define('PHORUM_SESSID_RESET_LOGIN', 1);
- /**
- * Function call parameter, which tells {@link phorum_api_user_session_create()}
- * that all session ids have to be reset to new values. This is for example
- * appropriate after a user changed the password (so active sessions on
- * other computers or browsers will be ended).
- */
- define('PHORUM_SESSID_RESET_ALL', 2);
- /**
- * Function call parameter, which tells {@link phorum_api_user_get_list()}
- * that all users have to be returned.
- */
- define('PHORUM_GET_ALL', 0);
- /**
- * Function call parameter, which tells {@link phorum_api_user_get_list()}
- * that all active users have to be returned.
- */
- define('PHORUM_GET_ACTIVE', 1);
- /**
- * Function call parameter, which tells {@link phorum_api_user_get_list()}
- * that all inactive users have to be returned.
- */
- define('PHORUM_GET_INACTIVE', 2);
- /**
- * Function call parameter, which tells {@link phorum_api_user_check_access()}
- * and {@link phorum_api_user_check_group_access()} to return an array
- * of respectively forums or groups for which a user is granted access.
- */
- define('PHORUM_ACCESS_LIST', -1);
- /**
- * Function call parameter, which tells {@link phorum_api_user_check_access()}
- * and {@link phorum_api_user_check_group_access()} to check if the user
- * is granted access for respectively any forum or group.
- */
- define('PHORUM_ACCESS_ANY', -2);
- /**
- * User status, indicating that the user has not yet confirmed the registration
- * by email and that a user moderator will have to approve the registration
- * as well.
- */
- define("PHORUM_USER_PENDING_BOTH", -3);
- /**
- * User status, indicating that the user has not yet confirmed the registration
- * by email.
- */
- define("PHORUM_USER_PENDING_EMAIL", -2);
- /**
- * User status, indicating that the registration has not yet been approved
- * by a user moderator.
- */
- define("PHORUM_USER_PENDING_MOD", -1);
- /**
- * User status, indicating that the user has been deactivated.
- */
- define("PHORUM_USER_INACTIVE", 0);
- /**
- * User status, indicating that the registration has been completed and that
- * the user can access the forums.
- */
- define("PHORUM_USER_ACTIVE", 1);
- /**
- * Permission flag which allows users to read forum messages.
- */
- define('PHORUM_USER_ALLOW_READ', 1);
- /**
- * Permission flag which allows users to reply to forum messages.
- */
- define('PHORUM_USER_ALLOW_REPLY', 2);
- /**
- * Permission flag which allows users to edit their own forum messages.
- */
- define('PHORUM_USER_ALLOW_EDIT', 4);
- /**
- * Permission flag which allows users to start new forum topics.
- */
- define('PHORUM_USER_ALLOW_NEW_TOPIC', 8);
- /**
- * Permission flag which allows users to attach files to their forum messages.
- */
- define('PHORUM_USER_ALLOW_ATTACH', 32);
- /**
- * Permission flag which allows users to edit other users' messages.
- */
- define('PHORUM_USER_ALLOW_MODERATE_MESSAGES', 64);
- /**
- * Permission flag which allows users to moderate user signup
- * requests within the vroot.
- */
- define('PHORUM_USER_ALLOW_MODERATE_USERS', 128);
- /**
- * Group permission flag for users which are suspended by a group moderator.
- */
- define('PHORUM_USER_GROUP_SUSPENDED', -1);
- /**
- * Group permission flag for users which are not yet approved by
- * a group moderator.
- */
- define('PHORUM_USER_GROUP_UNAPPROVED', 0);
- /**
- * Group permission flag for users which are active approved group members.
- */
- define('PHORUM_USER_GROUP_APPROVED', 1);
- /**
- * Group permission flag for users which are group moderator.
- */
- define('PHORUM_USER_GROUP_MODERATOR', 2);
- /**
- * Subscription type, which tells Phorum explicitly that the user
- * does not have a subscription of any kind for the forum or thread.
- */
- define("PHORUM_SUBSCRIPTION_NONE", -1);
- /**
- * Subscription type, which tells Phorum to send out a mail message for
- * every new forum or thread that a user is subscribed to.
- */
- define("PHORUM_SUBSCRIPTION_MESSAGE", 0);
- /**
- * Subscription type, which tells Phorum to periodially send a mail message,
- * containing a list of new messages in forums or threads that a user is
- * subscribed to. There is currently no support for this type of subscription
- * in the Phorum core code.
- */
- define("PHORUM_SUBSCRIPTION_DIGEST", 1);
- /**
- * Subscription type, which tells Phorum to make the forums or threads that
- * a user is subscribed to accessible from the followed threads interface in
- * the control center. No mail is sent for new messages, but the user can
- * check for new messages using that interface.
- */
- define("PHORUM_SUBSCRIPTION_BOOKMARK", 2);
- /**
- * This array describes user data fields. It is mainly used internally
- * for configuring how to handle the fields and for doing checks on them.
- */
- $GLOBALS['PHORUM']['API']['user_fields'] = array
- (
- // Fields that are really in the Phorum users table.
- 'user_id' => 'int',
- 'username' => 'string',
- 'real_name' => 'string',
- 'display_name' => 'string',
- 'password' => 'string',
- 'password_temp' => 'string',
- 'sessid_lt' => 'string',
- 'sessid_st' => 'string',
- 'sessid_st_timeout' => 'string',
- 'email' => 'string',
- 'email_temp' => 'string',
- 'hide_email' => 'bool',
- 'active' => 'int',
- 'admin' => 'bool',
- 'signature' => 'string',
- 'posts' => 'int',
- 'date_added' => 'int',
- 'date_last_active' => 'int',
- 'last_active_forum' => 'int',
- 'threaded_list' => 'int',
- 'threaded_read' => 'int',
- 'hide_activity' => 'bool',
- 'show_signature' => 'bool',
- 'email_notify' => 'int',
- 'pm_email_notify' => 'bool',
- 'tz_offset' => 'float',
- 'is_dst' => 'bool',
- 'user_language' => 'string',
- 'user_template' => 'string',
- 'moderation_email' => 'bool',
- 'moderator_data' => 'array',
- 'settings_data' => 'array',
- // Fields that are used for passing on information about user related,
- // data, which is not stored in a standard user table field.
- 'forum_permissions' => 'array',
- // Fields that we do not use for saving data (yet?), but which might
- // be in the user data (e.g. if we store a user data array like it was
- // returned by phorum_api_user_get()).
- 'groups' => NULL,
- 'group_permissions' => NULL,
- 'permissions' => NULL,
- );
- // }}}
- // ----------------------------------------------------------------------
- // Handling user data.
- // ----------------------------------------------------------------------
- // {{{ Function: phorum_api_user_save()
- /**
- * Create or update Phorum users.
- *
- * This function can be used for both creating and updating Phorum users.
- * If the user_id in the user data is NULL, a new user will be created.
- * If a user_id is provided, then the existing user will be updated or a
- * new user with that user_id is created.
- *
- * Often when calling this function yourself, you will be doing that for
- * synchronizing a user from some external system with the Phorum database.
- * For those cases, the most basic use of this API function can be found
- * in the examples below.
- * <code>
- * $user = array(
- * "user_id" => 1234,
- * "username" => 'johndoe',
- * "password" => '#barbar#',
- * "email" => 'john.doe@example.com',
- * "admin" => 0,
- * "active" => PHORUM_USER_ACTIVE
- * );
- * phorum_api_user_save($user);
- * </code>
- *
- * If you do not have the plain text password available, but only an MD5
- * hash for the password, then you can use the following code instead.
- * <code>
- * $user = array(
- * "user_id" => 1234,
- * "username" => 'johndoe',
- * "password" => '5d61ed116ffdecf2d29cd1ed9bd9d4cb',
- * "email" => 'john.doe@example.com',
- * "admin" => 0,
- * "active" => PHORUM_USER_ACTIVE
- * );
- * phorum_api_user_save($user, PHORUM_FLAG_RAW_PASSWORD);
- * </code>
- *
- * @param array $user
- * An array containing user data. This array should at least contain
- * a field "user_id". This field can be NULL to create a new user
- * with an automatically assigned user_id. It can also be set to a
- * user_id to either update an existing user or to create a new user
- * with the provided user_id.
- * If a new user is created, then all user fields must be provided
- * in the user data.
- *
- * @param int $flags
- * If the flag {@link PHORUM_FLAG_RAW_PASSWORD} is set, then the
- * password fields ("password" and "password_temp") are considered to be
- * MD5 encrypted already. So this can be used to feed Phorum existing MD5
- * encrypted passwords.
- *
- * @return int
- * The user_id of the user. For new users, the newly assigned user_id
- * will be returned.
- */
- function phorum_api_user_save($user, $flags = 0)
- {
- global $PHORUM;
- include_once('./include/api/custom_profile_fields.php');
- // $user must be an array.
- if (!is_array($user)) {
- trigger_error(
- 'phorum_api_user_save(): $user argument is not an array',
- E_USER_ERROR
- );
- return NULL;
- }
- // We need at least the user_id field.
- if (!array_key_exists('user_id', $user)) {
- trigger_error(
- 'phorum_api_user_save(): missing field "user_id" in user data array',
- E_USER_ERROR
- );
- return NULL;
- }
- if ($user['user_id'] !== NULL && !is_numeric($user['user_id'])) {
- trigger_error(
- 'phorum_api_user_save(): field "user_id" not NULL or numerical',
- E_USER_ERROR
- );
- return NULL;
- }
- // Check if we are handling an existing or new user.
- $existing = NULL;
- if ($user['user_id'] !== NULL) {
- $existing = phorum_api_user_get($user['user_id'], TRUE, TRUE, TRUE);
- }
- // Create a user data array that is understood by the database layer.
- // We start out with the existing record, if we have one.
- $dbuser = $existing === NULL ? array() : $existing;
- // Merge in the fields from the $user argument.
- foreach ($user as $fld => $val) {
- $dbuser[$fld] = $val;
- }
- // Initialize storage for custom profile field data.
- $user_data = array();
- // Check and format the user data fields.
- foreach ($dbuser as $fld => $val)
- {
- // Determine the field type that we are handling.
- $fldtype = NULL;
- $custom = NULL;
- // Check if we are handling a custom profile field. We asume that any
- // field that is not in the user_fields array is a custom profile
- // field. If we find that it isn't such field, then we will ignore
- // the field (it's either a field that was manually added to the
- // user table or a custom profile field that was just deleted).
- if (!array_key_exists($fld, $PHORUM['API']['user_fields'])) {
- $custom = phorum_api_custom_profile_field_byname($fld);
- if ($custom === NULL) {
- $fldtype = 'ignore_field';
- } else {
- $fldtype = 'custom_profile_field';
- }
- } else {
- $fldtype = $PHORUM['API']['user_fields'][$fld];
- }
- switch ($fldtype)
- {
- // A field that has to be fully ignored.
- case NULL:
- break;
- case 'int':
- $dbuser[$fld] = $val === NULL ? NULL : (int) $val;
- break;
- case 'float':
- $dbuser[$fld] = $val === NULL ? NULL : (float) $val;
- break;
- case 'string':
- $dbuser[$fld] = $val === NULL ? NULL : trim($val);
- break;
- case 'bool':
- $dbuser[$fld] = $val ? 1 : 0;
- break;
- case 'array':
- // TODO: maybe check for real arrays here?
- $dbuser[$fld] = $val;
- break;
- case 'custom_profile_field':
- // Arrays and NULL values are left untouched.
- // Other values are truncated to their configured field length.
- if ($val !== NULL && !is_array($val)) {
- $val = substr($val, 0, $custom['length']);
- }
- $user_data[$custom['id']] = $val;
- unset($dbuser[$fld]);
- break;
- case 'ignore_field':
- unset($dbuser[$fld]);
- break;
- default:
- trigger_error(
- 'phorum_api_user_save(): Illegal field type used: ' .
- htmlspecialchars($fldtype),
- E_USER_ERROR
- );
- return NULL;
- break;
- }
- }
- // Add the custom profile field data to the user data.
- $dbuser['user_data'] = $user_data;
- // At this point, we should have a couple of mandatory fields available
- // in our data. Without these fields, the user record is not sane
- // enough to continue with.
- // We really need a username, so we can always generate a display name.
- if (!isset($dbuser['username']) || $dbuser['username'] == '') {
- trigger_error(
- 'phorum_api_user_save(): the username field for a user record ' .
- 'cannot be empty',
- E_USER_ERROR
- );
- return NULL;
- }
- // Phorum sends out mail messages on several occasions. So we need a
- // mail address for the user.
- if (!isset($dbuser['email']) || $dbuser['email'] == '') {
- trigger_error(
- 'phorum_api_user_save(): the email field for a user record ' .
- 'cannot be empty',
- E_USER_ERROR
- );
- return NULL;
- }
- // For new accounts only.
- if (!$existing)
- {
- if (empty($dbuser['date_added']))
- $dbuser['date_added'] = time();
- if (empty($dbuser['date_last_active']))
- $dbuser['date_last_active'] = time();
- }
- // Handle password encryption.
- foreach (array('password', 'password_temp') as $fld)
- {
- // Sometimes, this function is (accidentally) called with existing
- // passwords in the data. Prevent duplicate encryption.
- if ($existing && strlen($existing[$fld]) == 32 &&
- $existing[$fld] == $dbuser[$fld]) {
- continue;
- }
- // If the password field is empty, we should never store the MD5 sum
- // of an empty string as a safety precaution. Instead we store a
- // string which will never work as a password. This could happen in
- // case of bugs in the code or in case external user auth is used
- // (in which case Phorum can have empty passwords, since the Phorum
- // passwords are not used at all).
- if (!isset($dbuser[$fld]) || $dbuser[$fld] === NULL ||
- $dbuser[$fld] == '' || $dbuser[$fld] == '*NO PASSWORD SET*') {
- $dbuser[$fld] = '*NO PASSWORD SET*';
- continue;
- }
- // Only crypt the password using MD5, if the PHORUM_FLAG_RAW_PASSWORD
- // flag is not set.
- if (!($flags & PHORUM_FLAG_RAW_PASSWORD)) {
- $dbuser[$fld] = md5($dbuser[$fld]);
- }
- }
- // Determine the display name to use for the user. If the setting
- // $PHORUM["custom_display_name"] is enabled (a "secret" setting which
- // cannot be changed through the admin settings, but only through
- // modules that consciously set it), then Phorum expects that the display
- // name is a HTML formatted display_name field, which is provided by
- // 3rd party software. Otherwise, the username or real_name is used
- // (depending on the $PHORUM["display_name_source"] Phorum setting).
- if (empty($PHORUM['custom_display_name'])) {
- $display_name = $dbuser['username'];
- if ($PHORUM['display_name_source'] == 'real_name' &&
- isset($dbuser['real_name']) &&
- trim($dbuser['real_name']) != '') {
- $display_name = $dbuser['real_name'];
- }
- $dbuser['display_name'] = $display_name;
- }
- // If the 3rd party software provided no or an empty display_name,
- // then we save the day by using the username (just so users won't show up
- // empty on screen, this should not happen at all in the first place).
- // We HTML encode the username, because custom display names are supposed
- // to be provided in escaped HTML format.
- elseif (!isset($dbuser['display_name']) ||
- trim($dbuser['display_name']) == '') {
- $dbuser['display_name'] = htmlspecialchars($dbuser['username'], ENT_COMPAT, $PHORUM['DATA']['HCHARSET']);
- }
- /**
- * [hook]
- * user_save
- *
- * [description]
- * This hook can be used to handle the data that is going to be
- * stored in the database for a user. Modules can do some last
- * minute change on the data or keep some external system in sync
- * with the Phorum user data.<sbr/>
- * <sbr/>
- * In combination with the <hook>user_get</hook> hook, this hook
- * could also be used to store and retrieve some of the Phorum
- * user fields using some external system.
- *
- * [category]
- * User data handling
- *
- * [when]
- * Just before user data is stored in the database.
- *
- * [input]
- * An array containing user data that will be sent to the database.
- *
- * [output]
- * The same array as the one that was used for the hook call
- * argument, possibly with some updated fields in it.
- *
- * [example]
- * <hookcode>
- * function phorum_mod_foo_user_save($user)
- * {
- * // Add "[A]" in front of admin user real_name fields.
- * $A = $user["admin"] ? "[A]" : "";
- * $real_name = preg_replace('/^\[A\]/', $A, $user["real_name"]);
- * $user['real_name'] = $real_name;
- *
- * // Some fictional external system to keep in sync.
- * include("../coolsys.php");
- * coolsys_save($user);
- *
- * return $user;
- * }
- * </hookcode>
- */
- if (isset($PHORUM['hooks']['user_save'])) {
- $dbuser = phorum_hook('user_save', $dbuser);
- }
- /**
- * [hook]
- * user_register
- *
- * [description]
- * This hook is called when a user registration is completed by
- * setting the status for the user to PHORUM_USER_ACTIVE.
- * This hook will not be called right after filling in the
- * registration form (unless of course, the registration has been
- * setup to require no verification at all in which case the user
- * becomes active right away).
- *
- * [category]
- * User data handling
- *
- * [when]
- * Right after a new user registration becomes active.
- *
- * [input]
- * An array containing user data for the registered user.
- *
- * [output]
- * The same array as the one that was used for the hook call
- * argument, possibly with some updated fields in it.
- *
- * [example]
- * <hookcode>
- * function phorum_mod_foo_user_register($user)
- * {
- * // Log user registrations through syslog.
- * openlog("Phorum", LOG_PID | LOG_PERROR, LOG_LOCAL0);
- * syslog(LOG_NOTICE, "New user registration: $user[username]");
- *
- * return $user;
- * }
- * </hookcode>
- */
- if (isset($PHORUM['hooks']['user_register']))
- {
- // Only fire this hook if a user goes from some pending state
- // to the active state.
- if ($dbuser['active'] == PHORUM_USER_ACTIVE)
- {
- // For new users we have no existing status. For those we asume
- // a pending status, so below a switch to active status will mean
- // that the user registration is activated.
- $orig_status = $existing
- ? $existing['active']
- : PHORUM_USER_PENDING_MOD;
- if ($orig_status == PHORUM_USER_PENDING_BOTH ||
- $orig_status == PHORUM_USER_PENDING_EMAIL ||
- $orig_status == PHORUM_USER_PENDING_MOD) {
- $dbuser = phorum_hook('user_register', $dbuser);
- }
- }
- }
- // Add or update the user in the database.
- if ($existing) {
- phorum_db_user_save($dbuser);
- } else {
- $dbuser['user_id'] = phorum_db_user_add($dbuser);
- }
- // If the display name changed for the user, then we do need to run
- // updates throughout the Phorum database to make references to this
- // user to show up correctly.
- if ($existing && $existing['display_name'] != $dbuser['display_name']) {
- phorum_db_user_display_name_updates($dbuser);
- }
- // If user caching is enabled, we invalidate the cache for this user.
- if (!empty($PHORUM['cache_users'])) {
- phorum_cache_remove('user', $dbuser['user_id']);
- }
- // Are we handling the active Phorum user? Then refresh the user data.
- if (isset($PHORUM['user']) &&
- $PHORUM['user']['user_id'] == $dbuser['user_id']) {
- $PHORUM['user'] = phorum_api_user_get($user['user_id'], TRUE, TRUE);
- }
- return $dbuser['user_id'];
- }
- // }}}
- // {{{ Function: phorum_api_user_save_raw()
- /**
- * This function quickly updates the Phorum users table, using all fields in
- * the user data as real user table fields.
- *
- * This is the quickest way to update the user table. Care has to be taken
- * by the calling function though, to provide the information exactly as the
- * Phorum users table expects it. Only use this function if speed is really
- * an issue.
- *
- * @param array $user
- * An array containing user data. This array should at least contain
- * a field "user_id", pointing to the user_id of an existing user to
- * update. Besides "user_id", this array can contain other fields,
- * which should all be valid fields from the users table.
- */
- function phorum_api_user_save_raw($user)
- {
- if (empty($user['user_id'])) {
- trigger_error(
- 'phorum_api_user_save_raw(): the user_id field cannot be empty',
- E_USER_ERROR
- );
- return NULL;
- }
- // This hook is documented in phorum_api_user_save().
- if (isset($PHORUM['hooks']['user_save'])) {
- $user = phorum_hook('user_save', $user);
- }
- // Store the data in the database.
- phorum_db_user_save($user);
- // Invalidate the cache for the user, unless we are only updating
- // user activity tracking fields.
- if (!empty($GLOBALS['PHORUM']['cache_users']))
- {
- // Count the number of activity tracking fields in the data.
- $count = 1; // count user_id as an activity tracking field
- if (array_key_exists('date_last_active', $user)) $count ++;
- if (array_key_exists('last_active_forum', $user)) $count ++;
- // Invalidate the cache, if there are non-activity tracking fields.
- if ($count != count($user)) {
- phorum_cache_remove('user', $user['user_id']);
- }
- }
- }
- // }}}
- // {{{ Function: phorum_api_user_save_settings()
- /**
- * Create or update user settings for the active Phorum user.
- *
- * This function can be used to store arbitrairy settings for the active
- * Phorum user in the database. The main goal for this function is to store
- * user settings which are not available as a Phorum user table field in
- * the database. These are settings which do not really belong to the Phorum
- * core, but which are for example used for remembering some kind of state
- * in a user interface (templates). Since each user interface might require
- * different settings, a dynamic settings storage like this is required.
- *
- * If you are writing modules that need to store data for a user, then please
- * do not use this function. Instead, use custom profile fields. The data
- * that is stored using this function can be best looked at as if it were
- * session data.
- *
- * @param array $settings
- * An array of setting name => value pairs to store as user
- * settings in the database.
- */
- function phorum_api_user_save_settings($settings)
- {
- global $PHORUM;
- // Get the active user's user_id.
- if (empty($PHORUM['user']['user_id'])) return;
- $user_id = $PHORUM['user']['user_id'];
- // The settings data must always be an array.
- if (empty($PHORUM['user']['settings_data'])) {
- $PHORUM['user']['settings_data'] = array();
- }
- // Merge the setting with the existing settings.
- if (is_array($settings)) {
- foreach ($settings as $name => $value) {
- if ($value === NULL) {
- unset($PHORUM['user']['settings_data'][$name]);
- } else {
- $PHORUM['user']['settings_data'][$name] = $value;
- }
- }
- }
- // Save the settings in the database.
- phorum_db_user_save(array(
- 'user_id' => $user_id,
- 'settings_data' => $PHORUM['user']['settings_data']
- ));
- // If user caching is enabled, we remove the user from the cache.
- if (!empty($GLOBALS['PHORUM']['cache_users'])) {
- phorum_cache_remove('user', $user_id);
- }
- }
- // }}}
- // {{{ Function: phorum_api_user_get()
- /**
- * Retrieve data for Phorum users.
- *
- * @param mixed $user_id
- * Either a single user_id or an array of user_ids.
- *
- * @param boolean $detailed
- * If this parameter is TRUE (default is FALSE), then the user's
- * groups and permissions are included in the user data.
- *
- * @param boolean $use_write_server
- * This parameter is for internal use only. It is used to flag that
- * the database layer has to run the query against the master database
- * server (known as the "write server"; only applicable if the database
- * system is setup as a replicated master/slave environment). When you
- * are using this API call in your own code, then you most probably do
- * not need to use this parameter.
- *
- * @return mixed
- * If the $user_id parameter is a single user_id, then either an array
- * containing user data is returned or NULL if the user was not found.
- * If the $user_id parameter is an array of user_ids, then an array
- * of user data arrays is returned, indexed by the user_id.
- * Users for user_ids that are not found are not included in the
- * returned array.
- */
- function phorum_api_user_get($user_id, $detailed = FALSE, $use_write_server = FALSE, $raw_data = FALSE)
- {
- $PHORUM = $GLOBALS['PHORUM'];
- if (!is_array($user_id)) {
- $user_ids = array($user_id);
- } else {
- $user_ids = $user_id;
- }
- // Prepare the return data array. For each requested user_id,
- // a slot is prepared in this array. Also, turn the user id array
- // into an array which has the user_id as both the key and value.
- $users = array();
- $new_user_ids = array();
- foreach ($user_ids as $id) {
- $users[$id] = NULL;
- $new_user_ids[$id] = $id;
- }
- $user_ids = $new_user_ids;
- // First, try to retrieve user data from the user cache,
- // if user caching is enabled.
- if ($raw_data === FALSE && !empty($PHORUM['cache_users']))
- {
- $cached_users = phorum_cache_get('user', $user_ids);
- if (is_array($cached_users))
- {
- foreach ($cached_users as $id => $user) {
- $users[$id] = $user;
- unset($user_ids[$id]);
- }
- // We need to retrieve the data for some dynamic fields
- // from the database.
- $dynamic_data = phorum_db_user_get_fields(
- array_keys($cached_users),
- array('date_last_active','last_active_forum','posts')
- );
- // Store the results in the users array.
- foreach ($dynamic_data as $id => $data) {
- $users[$id] = array_merge($users[$id],$data);
- }
- }
- }
- // Retrieve user data for the users for which no data was
- // retrieved from the cache.
- if (count($user_ids))
- {
- $db_users = phorum_db_user_get($user_ids, $detailed, $use_write_server, $raw_data);
- foreach ($db_users as $id => $user)
- {
- // Merge the group and forum permissions into a final
- // permission value per forum. Forum permissions that are
- // assigned to a user directly override any group based
- // permission.
- if (!$user['admin']) {
- if (!empty($user['group_permissions'])) {
- foreach ($user['group_permissions'] as $fid => $perm) {
- if (!isset($user['permissions'][$fid])) {
- $user['permissions'][$fid] = $perm;
- } else {
- $user['permissions'][$fid] |= $perm;
- }
- }
- }
- if (!empty($user['forum_permissions'])) {
- foreach ($user['forum_permissions'] as $fid => $perm) {
- $user['permissions'][$fid] = $perm;
- }
- }
- }
- // If detailed information was requested, we store the data in
- // the cache. For non-detailed information, we do not cache the
- // data, because there is not much to gain there by caching.
- if ($detailed && !empty($PHORUM['cache_users']) && $raw_data === FALSE) {
- phorum_cache_put('user', $id, $user);
- }
- // Store the results in the users array.
- $users[$id] = $user;
- }
- }
- // Remove the users for which we did not find data from the array.
- foreach ($users as $id => $user) {
- if ($user === NULL) {
- unset($users[$id]);
- }
- }
- /**
- * [hook]
- * user_get
- *
- * [description]
- * This hook can be used to handle the data that was retrieved
- * from the database for a user. Modules can add and modify the
- * user data.<sbr/>
- * <sbr/>
- * In combination with the <hook>user_save</hook> hook, this hook
- * could also be used to store and retrieve some of the Phorum
- * user fields in some external system
- *
- * [category]
- * User data handling
- *
- * [when]
- * Just after user data has been retrieved from the database.
- *
- * [input]
- * This hook receives two arguments.<sbr/>
- * The first argument contains an array of users.
- * Each item in this array is an array containing data for
- * a single user, which can be updated.<sbr/>
- * The second argument contains a boolean that indicates whether
- * detailed information (i.e. including group info) is retrieved.
- *
- * [output]
- * The array that was used as the first argument for the hook call,
- * possibly with some updated users in it.
- *
- * [example]
- * <hookcode>
- * function phorum_mod_foo_user_get($user, $detailed)
- * {
- * // Let's asume that our usernames are based on the
- * // system users on a UNIX system. We could merge some
- * // info from the password file with the Phorum info here.
- *
- * // First try to lookup the password file entry.
- * // Return if this lookup fails.
- * $pw = posix_getpwnam($user['username']);
- * if (empty($pw)) return $user;
- *
- * // On a lot of systems, the "gecos" field contains
- * // the real name for the user.
- * $user['real_name'] = $pw["gecos"] != ''
- * ? $pw["gecos"]
- * : $user["real_name"];
- *
- * // If a custom profile field "shell" was created, then
- * // we could also put the user's shell in the data.
- * $user['shell'] = $pw['shell'];
- *
- * return $user;
- * }
- * </hookcode>
- */
- if (isset($PHORUM['hooks']['user_get'])) {
- $users = phorum_hook('user_get', $users, $detailed);
- }
- // Return the results.
- if (is_array($user_id)) {
- return $users;
- } else {
- return isset($users[$user_id]) ? $users[$user_id] : NULL;
- }
- }
- // }}}
- // {{{ Function: phorum_api_user_get_setting()
- /**
- * This function can be used to retrieve the value for a user setting
- * that was stored by the {@link phorum_api_user_save_settings()} function
- * for the active Phorum user.
- *
- * @param string $name
- * The name of the setting for which to retrieve the setting value.
- *
- * @return mixed
- * The value of the setting or NULL if it is not available.
- */
- function phorum_api_user_get_setting($name)
- {
- $PHORUM = $GLOBALS['PHORUM'];
- // No settings available at all?
- if (empty($PHORUM['user']['settings_data'])) return NULL;
- // The setting is available.
- if (array_key_exists($name, $PHORUM['user']['settings_data'])) {
- return $PHORUM['user']['settings_data'][$name];
- } else {
- return NULL;
- }
- }
- // }}}
- // {{{ Function: phorum_api_user_get_display_name()
- /**
- * Retrieve the display name to use for one or more users.
- *
- * The name to use depends on the "display_name_source" setting. This
- * one points to either the username or the real_name field of the
- * user. If the display_name is requested for an unknown user, then
- * a fallback name will be used.
- *
- * @param mixed $user_id
- * Either a single user_id, an array of user_ids or NULL to use the
- * user_id of the active Phorum user.
- *
- * @param mixed $fallback
- * The fallback display name to use in case the user is unknown or NULL
- * to use the "AnonymousUser" language string.
- *
- * @param mixed $flags
- * One of {@link PHORUM_FLAG_HTML} (the default) or
- * {@link PHORUM_FLAG_PLAINTEXT}. These determine what output format
- * is used for the display names.
- *
- * @return mixed
- * If the $user_id parameter was NULL or a single user_id, then this
- * function will return a single display name. If it was an array,
- * then this function will return an array of display names, indexed
- * by user_id.
- */
- function phorum_api_user_get_display_name($user_id = NULL, $fallback = NULL, $flags = PHORUM_FLAG_HTML)
- {
- $PHORUM = $GLOBALS['PHORUM'];
- if ($fallback === NULL) {
- $fallback = $PHORUM['DATA']['LANG']['AnonymousUser'];
- }
- // Use the user_id for the active user.
- if ($user_id === NULL) {
- $user_id = $PHORUM['user']['user_id'];
- }
- // From here on, we need an array of user_ids to lookup.
- $user_ids = is_array($user_id) ? $user_id : array((int)$user_id);
- // Lookup the users.
- $users = phorum_api_user_get($user_ids, FALSE);
- // Determine the display names.
- $display_names = array();
- foreach ($user_ids as $id)
- {
- $display_name = empty($users[$id])
- ? $fallback
- : $users[$id]['display_name'];
- // Generate HTML based display names.
- if ($flags == PHORUM_FLAG_HTML)
- {
- // If the setting $PHORUM["custom_display_name"] is enabled,
- // then Phorum expects that the display name is a HTML
- // formatted display_name field, which is provided by
- // 3rd party software. So those do not have to be HTML escaped.
- // Other names do have to be escaped.
- if (empty($users[$id]) || empty($PHORUM['custom_display_name']))
- {
- $display_name = htmlspecialchars($display_name, ENT_COMPAT, $PHORUM['DATA']['HCHARSET']);
- }
- }
- // Generate a plain text version of the display name. This is the
- // display name as it can be found in the database. Only for
- // custom_display_name cases, we need to strip HTML code.
- elseif ($flags == PHORUM_FLAG_PLAINTEXT)
- {
- // Strip tags from the name. These might be in the
- // name if the custom_display_name feature is enabled.
- // So for custom display names we strip the HTML from the
- // display name that we found above.
- if (!empty($PHORUM['custom_display_name']))
- {
- $display_name = trim(strip_tags($display_name));
- // If the name was 100% HTML code (so empty after stripping),
- // then fallback to the default display_name that Phorum
- // would use without the custom display name feature.
- if ($display_name == '') {
- if (empty($users[$id])) {
- $display_name = $fallback;
- } else {
- $display_name = $users[$id]['username'];
- if ($PHORUM['display_name_source'] == 'real_name' &&
- trim($users[$id]['real_name']) != '') {
- $display_name = $users[$id]['real_name'];
- }
- }
- }
- }
- }
- $display_names[$id] = $display_name;
- }
- if (is_array($user_id)) {
- return $display_names;
- } else {
- return $display_names[$user_id];
- }
- }
- // }}}
- // {{{ Function: phorum_api_user_search()
- /**
- * Search for users, based on simple search conditions, which act on
- * fields in the user table.
- *
- * The parameters $field, $value and $operator (which are used for defining
- * the search condition) can be arrays or single values. If arrays are used,
- * then all three parameter arrays must contain the same number of elements
- * and the keys in the arrays must be the same.
- *
- * @param mixed $field
- * The user table field (string) or fields (array) to search on.
- *
- * @param mixed $value
- * The value (string) or values (array) to search for.
- *
- * @param mixed $operator
- * The operator (string) or operators (array) to use. Valid operators are
- * "=", "!=", "<>", "<", ">", ">=" and "<=", "*". The
- * "*" operator is for executing a "LIKE '%value%'" matching query.
- *
- * @param boolean $return_array
- * If this parameter has a true value, then an array of all matching
- * user_ids will be returned. Else, a single user_id will be returned.
- *
- * @param string $type
- * The type of search to perform. This can be one of:
- * - AND match against all fields
- * - OR match against any of the fields
- *
- * @param mixed $sort
- * The field (string) or fields (array) to sort the results by. For
- * ascending sort, "fieldname" or "+fieldname" can be used. For
- * descending sort, "-fieldname" can be used. By default, the results
- * will be sorted by user_id.
- *
- * @param integer $offset
- * The result page offset starting with 0.
- *
- * @param integer $length
- * The result page length (nr. of results per page)
- * or 0 (zero, the default) to return all results.
- *
- * @param boolean $count_only
- * Tells the function to just return the count of results for this
- * search query.
- *
- * @return mixed
- * An array of matching user_ids or a single user_id (based on the
- * $return_array parameter) or a count of results (based on $count_only).
- * If no user_ids can be found at all, then 0 (zero) will be returned.
- */
- function phorum_api_user_search($field, $value, $operator = '=', $return_array = FALSE, $type = 'AND', $sort = NULL, $offset = 0, $length = 0,$count_only=false)
- {
- return phorum_db_user_search($field, $value, $operator, $return_array, $type, $sort, $offset, $length,$count_only);
- }
- // }}}
- // {{{ Function: phorum_api_user_search_custom_profile_field()
- /**
- * Search for users, based on a simple search condition,
- * which can be used to search on custom profile fields.
- *
- * The parameters $field_id, $value and $operator (which are used for defining
- * the search condition) can be arrays or single values. If arrays are used,
- * then all three parameter arrays must contain the same number of elements
- * and the keys in the arrays must be the same.
- *
- * @param mixed $field_id
- * The custom profile field id (integer) or ids (array) to search on.
- *
- * @param mixed $value
- * The value (string) or values (array) to search for.
- *
- * @param mixed $operator
- * The operator (string) or operators (array) to use. Valid operators are
- * "=", "!=", "<>", "<", ">", ">=" and "<=", "*". The
- * "*" operator is for executing a "LIKE '%value%'" matching query.
- *
- * @param boolean $return_array
- * If this parameter has a true value, then an array of all matching
- * user_ids will be returned. Else, a single user_id will be returned.
- *
- * @param string $type
- * The type of search to perform. This can be one of:
- * - AND match against all fields
- * - OR match against any of the fields
- *
- * @param integer $offset
- * The result page offset starting with 0.
- *
- * @param integer $length
- * The result page length (nr. of results per page)
- * or 0 (zero, the default) to return all results.
- *
- * @return mixed
- * An array of matching user_ids or a single user_id (based on the
- * $return_array parameter). If no user_ids can be found at all,
- * then 0 (zero) will be returned.
- */
- function phorum_api_user_search_custom_profile_field($field_id, $value, $operator = '=', $return_array = FALSE, $type = 'AND', $offset = 0, $length = 0)
- {
- return phorum_db_user_search_custom_profile_field($field_id, $value, $operator, $return_array, $type, $offset, $length);
- }
- // }}}
- // {{{ Function: phorum_api_user_list()
- /**
- * Retrieve a list of Phorum users.
- *
- * @param int $type
- * One of:
- * - {@link PHORUM_GET_ALL}: retrieve a list of all users (the default)
- * - {@link PHORUM_GET_ACTIVE}: retrieve a list of all active users
- * - {@link PHORUM_GET_INACTIVE}: retrieve a list of all inactive users
- *
- * @return array
- * An array of users, indexed by user_id. Each element in the array
- * is an array, containing the fields "user_id", "username" and
- * "display_name".
- *
- * @todo Do we really need phorum_api_user_list() or could we use the
- * phorum_api_user_search() functionality in combination with
- * phorum_api_user_get() instead?
- */
- function phorum_api_user_list($type = PHORUM_GET_ALL)
- {
- // Retrieve a list of users from the database.
- $list = phorum_db_user_get_list($type);
- /**
- * [hook]
- * user_list
- *
- * [description]
- *
- * This hook can be used for reformatting the list of users that
- * is returned by the phorum_api_user_list() function. Reformatting
- * could mean things like changing the sort order or modifying the
- * fields in the user arrays.
- *
- * [category]
- * User data handling
- *
- * [when]
- * Each time the phorum_api_user_list() function is called. The core
- * Phorum code calls the function for creating user drop down lists
- * (if those are enabled in the Phorum general settings) for the
- * group moderation interface in the control center and for sending
- * private messages.
- *
- * [input]
- * An array of user info arrays. Each user info array contains the
- * fields "user_id", "username" and "display_name". The hook function
- * is allowed to update the "username" and "display_name" fields.
- *
- * [output]
- * The same array as was used for the hook call argument,
- * possibly with some updated fields in it.
- *
- * [example]
- * <hookcode>
- * function phorum_mod_foo_user_list($users)
- * {
- * // Only run this hook code for authenticated users.
- * if (empty($PHORUM["user"]["user_id"])) return $users;
- *
- * // Retrieve a list of buddies for the active user.
- * // If there are no buddies, then no work is needed.
- * $buddies = phorum_db_pm_buddy_list();
- * if (empty($buddies)) return $users;
- *
- * // Flag buddies in the user list.
- * $langstr = $GLOBALS["PHORUM"]["DATA"]["LANG"]["Buddy"];
- * foreach ($buddies as $user_id => $info) {
- * $users[$user_id]["display_name"] .= " ($langstr)";
- * }
- *
- * return $users;
- * }
- * </hookcode>
- */
- if (isset($GLOBALS['PHORUM']['hooks']['user_list'])) {
- $list = phorum_hook('user_list', $list);
- }
- return $list;
- }
- // }}}
- // {{{ Function: phorum_api_user_increment_posts()
- /**
- * Increment the posts counter for a user.
- *
- * @param mixed $user_id
- * The user_id for which to increment the posts counter
- * or NULL (the default…
Large files files are truncated, but you can click here to view the full file