user_stats.module in User Stats 6
Same filename and directory in other branches
User Stats provides commonly requested user statistics for themers. These are:
- days registered;
- join date;
- days since last login;
- days since last post;
- post count;
- login count;
- user online/offline;
- IP address;
Note for hackers: function parameters should go in the order $op/$type, $uid, $data (where applicable).
File
user_stats.moduleView source
<?php
/**
* @file
* User Stats provides commonly requested user statistics for themers.
* These are:
* - days registered;
* - join date;
* - days since last login;
* - days since last post;
* - post count;
* - login count;
* - user online/offline;
* - IP address;
*
* Note for hackers: function parameters should go in the order
* $op/$type, $uid, $data (where applicable).
*/
/**
* Implementation of hook_perm().
*/
function user_stats_perm() {
return array(
'administer user stats',
'View statistics',
'View IP addresses',
);
}
/**
* Implementation of hook_menu().
*/
function user_stats_menu() {
$items = array();
// Admin settings
$items['admin/settings/user_stats'] = array(
'title' => 'User Stats settings',
'description' => 'Configuration of user stats module options.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'user_stats_admin_settings',
),
'access arguments' => array(
'administer user stats',
),
'file' => 'user_stats.admin.inc',
'type' => MENU_NORMAL_ITEM,
);
$items['admin/settings/user_stats/reset_post_count'] = array(
'title' => 'reset user post stats',
'page callback' => 'user_stats_reset_post_count',
'access arguments' => array(
'administer user stats',
),
'file' => 'user_stats.admin.inc',
'type' => MENU_CALLBACK,
);
$items['admin/settings/user_stats/reset_login_count'] = array(
'title' => 'reset user login stats',
'page callback' => 'user_stats_reset_login_count',
'access arguments' => array(
'administer user stats',
),
'file' => 'user_stats.admin.inc',
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Returns user stats.
*
* @param $type
* The statistic to return. Possible values are:
* - "ip_address"
* - "join_date"
* - "login_count"
* - "login_days"
* - "post_count"
* - "post_days"
* - "reg_days"
* - "online"
* - "profile"
* @param $uid
* The user id who's stats should be retrieved.
*
* @return
* The statistic requested. Every statistic except join_date, online and IP address is a numeric.
* Join date is a string, whilst online is a boolean and IP Address a string.
* Note: if $type = "post_days" and the user hasn't posted any content (of the
* counted types) then 'n/a' is returned.
*/
function user_stats_get_stats($type, $uid) {
// Sometimes $uid can be NULL (comment previews for example).
if (!is_numeric($uid)) {
return;
}
// IP address is really a bit of feature creep.
// At some point in the future, this could be split off into its own module.
if ($type == 'ip_address') {
if (!user_access('View IP addresses')) {
return FALSE;
}
// Check cache.
if (user_stats_cache_get($type, $uid) === FALSE) {
$query = db_query("SELECT ip_address\n FROM {user_stats_ips} WHERE uid = %d\n ORDER BY first_seen_timestamp LIMIT 1", $uid);
user_stats_cache_set($type, $uid, db_result($query));
}
return user_stats_cache_get($type, $uid);
}
// Everything else is under the 'View statistics' permission.
if (!user_access('View statistics')) {
return FALSE;
}
// Check cache first.
if (user_stats_cache_get($type, $uid) !== FALSE) {
return user_stats_cache_get($type, $uid);
}
switch ($type) {
case 'join_date':
$query = db_query("SELECT created FROM {users} WHERE uid = %d", $uid);
$data = db_result($query);
break;
case 'login_count':
if (!variable_get('user_stats_count_logins', TRUE)) {
$data = 'n/a';
}
else {
if (user_stats_isset($type, $uid)) {
$query = db_query("SELECT value FROM {user_stats_values}\n WHERE name = 'login_count' AND uid = %d", $uid);
$data = db_result($query);
}
else {
return 0;
}
}
break;
case 'login_days':
$user_access = db_result(db_query("SELECT access FROM {users} WHERE uid = %d", $uid));
$data = floor((time() - $user_access) / 86400);
break;
case 'post_count':
if (!variable_get('user_stats_count_posts', TRUE) && !variable_get('user_stats_count_comments', TRUE)) {
$data = 'n/a';
}
else {
if (!user_stats_isset('post_count', $uid)) {
user_stats_post_count_update('reset', $uid);
}
}
$query = db_query("SELECT value FROM {user_stats_values}\n WHERE name = 'post_count' AND uid = %d", $uid);
$data = db_result($query);
break;
case 'post_days':
$last_post = _user_stats_last_post($uid);
if ($last_post !== FALSE) {
$data = floor((time() - $last_post) / 86400);
}
else {
$data = 'n/a';
}
break;
case 'reg_days':
$query = db_query("SELECT value FROM {user_stats_values}\n WHERE name = 'last_known_age' AND uid = %d", $uid);
$data = db_result($query);
if (!$data) {
$data = 0;
}
break;
case 'reg_days_onthefly':
$user_created = db_result(db_query("SELECT created FROM {users} WHERE uid = %d", $uid));
$data = floor((time() - $user_created) / 86400);
break;
case 'online':
$user_access = db_result(db_query("SELECT timestamp FROM {sessions} WHERE uid = %d", $uid));
$data = time() - $user_access < variable_get('user_block_seconds_online', 900) ? TRUE : FALSE;
break;
default:
// Check for custom statistics
$custom_stats = array();
$module_list = module_implements('default_user_stats');
foreach ($module_list as $module) {
$custom_stats = array_merge($custom_stats, module_invoke($module, 'default_user_stats'));
}
if (array_key_exists($type, $custom_stats)) {
module_load_include('module', 'qna');
$data = call_user_func($custom_stats[$type], $uid);
break;
}
else {
// Raise an error if the statistic doesn't exist.
$err_message = 'Statistic "' . check_plain($type) . '" does not exist.';
trigger_error($err_message, E_USER_WARNING);
return;
}
}
user_stats_cache_set($type, $uid, $data);
return user_stats_cache_get($type, $uid);
}
/**
* Return data from the non-persistent User Stats cache. Single values
* are returned according to type of statistic and unique user id.
*
* @param $type
* The type of statistic to retrieve, this corresponds to the statistic
* types used by user_stats_get_stats().
* @param $uid
* Unique ID of the user who's statistic is being retrieved.
*
* @return
* A single value, representing the statistic $type where the unique user id
* is $uid. Or FALSE if there is no value in the cache for this combination
* of $type and $uid.
*
* @see user_stats_get_stats().
* @see user_stats_cache_set().
*/
function user_stats_cache_get($type, $uid) {
$user_stats_cache = user_stats_cache_set();
if (isset($user_stats_cache[$uid][$type])) {
return $user_stats_cache[$uid][$type];
}
else {
return FALSE;
}
}
/**
* Store a value in the non-persistent User Stats cache.
*
* If the function is called with no arguments, the entire cache is returned
* without being cleared.
*
* The User Stats cache is a static array, which is why we call it
* non-persistent. The array structure is:
* $user_stats_cache[$uid][$type] = $value.
*
* @param $type
* The type of statistic being stored, this corresponds to the statistic
* types used by user_stats_get_stats(), and one extra used to reset the
* cache: 'reset'.
* @param $uid
* Unique ID of the user who's statistic is being stored. If the type
* is set to 'reset', this user id will have the cache values associated with
* it reset. Alternatively, if $type is set to 'reset' and this is -1, the
* entire cache will be reset.
*
* @return
* Array of the entire cache, or NULL if the cache has been reset.
*
* @see user_stats_get_stats().
* @see user_stats_cache_get().
*/
function user_stats_cache_set($type = NULL, $uid = 0, $data = NULL) {
static $user_stats_cache = array();
// Flush entire cache.
if ($uid == -1 && $type == 'reset') {
unset($user_stats_cache);
return;
}
else {
if ($uid > -1 && $type == 'reset') {
unset($user_stats_cache[$uid]);
return;
}
}
// Set cache data. Check against NULL since a zero (in $data at least)
// is valid.
if ($type !== NULL && $data !== NULL) {
$user_stats_cache[$uid][$type] = $data;
}
return $user_stats_cache;
}
/**
* Drupal hook implementations.
*/
/**
* Implementation of hook_nodeapi().
*
* Increments post count on insert or publish.
* Decrements post count on delete or unpublish.
* Checks and updates users without post counts on view.
*
* @param &$node
* The node the action is being performed on.
* @param $op
* The operation being performed. We are interested in insert, delete, update and view.
*/
function user_stats_nodeapi(&$node, $op) {
// We stop before any work is done if the $op isn't one of the ones we need
if (!in_array($op, array(
'insert',
'delete',
'update',
))) {
return;
}
$post_count_content_types = variable_get('user_stats_included_content_types', array());
if ((empty($post_count_content_types) || in_array($node->type, $post_count_content_types)) && variable_get('user_stats_count_posts', TRUE)) {
switch ($op) {
case 'insert':
if ($node->status) {
user_stats_post_count_update('increment', $node->uid);
}
break;
case 'delete':
// Node must be published as unpublished nodes would have already been
// removed from user's post count.
if ($node->status) {
user_stats_post_count_update('decrement', $node->uid);
}
break;
case 'update':
// Can't think of any other way of doing this than resetting the user.
user_stats_post_count_update('reset', $node->uid);
break;
}
}
// Do IP Address update.
switch ($op) {
case 'insert':
case 'update':
global $user;
// User IP addresses are only interesting if they are posting the content.
if ($node->uid == $user->uid) {
user_stats_ip_address_update($user->uid, ip_address());
}
}
}
/**
* Implementation of hook_comment().
*
* Increments post count on insert or publish.
* Decrements post count on delete or unpublish.
* Updates users with no post count on view.
*
* @param $a1
* Either the form values being submitted, the module form to be displayed,
* or the comment object.
* @param $op
* What kind of action is being performed.
*/
function user_stats_comment(&$a1, $op) {
// We stop before any work is done if the $op isn't one of the ones we need.
if (!in_array($op, array(
'insert',
'delete',
'update',
))) {
return;
}
// check to see if comments should be counted at all.
if (variable_get('user_stats_count_comments', TRUE)) {
$comment = (object) $a1;
// Bug [#479394] - Anonymous User Comment causes 'UID is not a number'
// errors. User Stats always expects UIDs to be numeric.
if ($comment->uid == NULL) {
$comment->uid = 0;
}
$post_count_content_types = variable_get('user_stats_included_content_types', array());
$node = node_load(array(
'nid' => $comment->nid,
));
if (empty($post_count_content_types) || in_array($node->type, $post_count_content_types)) {
switch ($op) {
case 'insert':
if ($comment->status == COMMENT_PUBLISHED) {
user_stats_post_count_update('increment', $comment->uid);
}
break;
case 'delete':
if ($comment->status == COMMENT_PUBLISHED) {
user_stats_post_count_update('decrement', $comment->uid);
}
break;
case 'update':
user_stats_post_count_update('reset', $comment->uid);
break;
}
}
}
// Do IP address update.
global $user;
if ($op == 'insert' && $comment->uid == $user->uid) {
// User IP addresses are only interesting if they are posting the content.
user_stats_ip_address_update($user->uid, ip_address());
}
}
/**
* Implementation of hook_cron().
*
* We slowly work through all users without a post count
* updating them.
*/
function user_stats_cron() {
if (variable_get('user_stats_rebuild_stats', TRUE) && (variable_get('user_stats_count_posts', TRUE) || variable_get('user_stats_count_comments', TRUE))) {
$sql = "SELECT uid FROM {users} WHERE uid NOT IN\n (SELECT uid FROM {user_stats_values} WHERE name = 'post_count')";
// Update 25 users per cron run.
$result = db_query_range($sql, 0, variable_get('user_stats_user_per_cron', '25'));
$users_updated = FALSE;
while ($update_user = db_fetch_object($result)) {
user_stats_post_count_update('reset', $update_user->uid);
$users_updated = TRUE;
}
// If all users have been updated we'll avoid running this expensive
// query again by setting the following flag!
if (!$users_updated) {
variable_set('user_stats_rebuild_stats', FALSE);
}
}
// Fire rules day_older event.
// This may seem grossly inefficient, but testing showed that, even firing
// the event for ~100 users, takes less than a second to run when there are
// no rules using this event. With a rule (that adds a role if the user has
// been a member for over 1,000 days) cron took an extra ~40 seconds to run.
// Basically, this has no potential to harm a site's performance, unless a
// rule is configured.
// Having said this: if there's a better way, please raise a bug report!
if (module_exists('rules')) {
// We're selecting the user, their calculated age, and their "last known age"
// as calculated the last time this function was run.
$sql = "SELECT u.uid, FLOOR((%d-created)/(60*60*24)) AS age, lka.value AS\n last_known_age FROM {users} u ";
$sql .= "LEFT JOIN {user_stats_values} lka ON lka.uid = u.uid AND\n lka.name = 'last_known_age'";
// ((last cron - created) - (time() - created)) > one day
$sql .= "WHERE (FLOOR((%d-created)/(60*60*24))-FLOOR((%d-created)/(60*60*24)))>0\n AND u.uid>0";
$result = db_query($sql, time(), time(), variable_get('cron_last', time()));
$reset_user_count = 0;
while ($update_user = db_fetch_object($result)) {
// If the user's calculated age is the same as their "last known age", that means
// This user has been already updated today, and processed at some point by this
// script. Maybe cron failed or something, and that's why they're being loaded
// again? Regardless, the event was already triggered for them - we're not going
// to trigger it again.
if ($update_user->age != $update_user->last_known_age) {
// We need to ensure the user_stats "last_known_age" value for this user is
// accurate because that is what the Rules event trigger will actually provide
// as an argument as the official "user's age".
if (isset($update_user->last_known_age)) {
// Update existing last known age
db_query("UPDATE {user_stats_values} SET value = %d\n WHERE name = 'last_known_age' AND uid = %d", $update_user->age, $update_user->uid);
}
else {
// If there isn't a value insert it.
db_query("INSERT INTO {user_stats_values} (name, uid, value)\n VALUES ('last_known_age', %d, %d)", $update_user->uid, $update_user->age);
}
rules_invoke_event('user_stats_day_older', $update_user->uid);
}
}
}
if (variable_get('user_stats_track_ips', TRUE)) {
// Delete items from the IP log that are past expiry.
db_query("DELETE FROM {user_stats_ips} WHERE first_seen_timestamp < %d", time() - variable_get('user_stats_flush_ips_timer', 31536000));
}
}
/**
* Implementation of hook_user().
*/
function user_stats_user($op, &$edit, &$account) {
// Update login count.
if ($op == 'login' && variable_get('user_stats_count_logins', TRUE)) {
user_stats_login_count_update('increment', $account->uid);
}
// Update IP Address.
if ($op == 'login' || $op == 'logout') {
user_stats_ip_address_update($account->uid, ip_address());
}
}
/**
* Helper function to get the last post created by the user.
*
* @param $account
* User object.
*
* @return
* Unix timestamp: date of the last post (node or comment).
*/
function _user_stats_last_post($uid) {
$sql = "SELECT MAX(created) FROM {node} WHERE status=%d AND uid=%d";
$all_content_types = node_get_types();
$post_count_content_types = variable_get('user_stats_included_content_types', array());
$where = "";
// If some, but not all, content types have been selected in the admin
// interface add a WHERE clause to select only them.
if (!empty($post_count_content_types) && array_keys($all_content_types) != array_keys($post_count_content_types)) {
$content_types = "'" . implode("','", $post_count_content_types) . "'";
$where = ' AND type IN (' . $content_types . ')';
}
$sql .= $where;
$max_node = db_result(db_query($sql, 1, $uid));
$sql = "SELECT MAX(timestamp) FROM {comments} c ";
$where = " WHERE c.status=%d AND c.uid=%d ";
$join = "";
if (!empty($post_count_content_types) && array_keys($all_content_types) != array_keys($post_count_content_types)) {
$join = " INNER JOIN {node} n ON c.nid=n.nid ";
$where .= 'AND n.type IN (' . $content_types . ')';
}
$sql .= $join . $where;
$max_comments = db_result(db_query($sql, COMMENT_PUBLISHED, $uid));
if (is_null($max_node) && is_null($max_comments)) {
return FALSE;
}
else {
if ($max_node > $max_comments) {
return $max_node;
}
else {
if ($max_node <= $max_comments) {
return $max_comments;
}
}
}
}
/**
* Implementation of hook_views_api().
*
* Other Views hooks in user_stats.views.inc.
*/
function user_stats_views_api() {
return array(
'api' => '2.0',
'path' => drupal_get_path('module', 'user_stats') . '/views',
);
}
/**
* Actions/Rules hooks and implementing functions.
*
* (we don't do Triggers as the API doesn't seem complete -- having to use
* _trigger_get_hook_aids() for example). Patches welcome for this, as long
* as they do not use private member functions!
*
* Most Rules hooks are in user_stats.rules.inc.
*/
/**
* Implementation of hook_action_info().
*/
function user_stats_action_info() {
return array(
'user_stats_post_count_reset_action' => array(
'description' => t('Reset user post count'),
'type' => 'user',
'configurable' => FALSE,
'hooks' => array(
'nodeapi' => array(
'delete',
'insert',
'update',
'view',
),
'comment' => array(
'view',
'insert',
'update',
'delete',
),
'user' => array(
'login',
'logout',
),
),
),
'user_stats_login_count_reset_action' => array(
'description' => t('Reset user login count'),
'type' => 'user',
'configurable' => FALSE,
'hooks' => array(
'nodeapi' => array(
'delete',
'insert',
'update',
'view',
),
'comment' => array(
'view',
'insert',
'update',
'delete',
),
'user' => array(
'login',
'logout',
),
),
),
);
}
/**
* Implementation of a Drupal action.
* Resets a user's post count.
*/
function user_stats_post_count_reset_action(&$object, $context = array()) {
if (isset($object->uid)) {
$uid = $object->uid;
}
elseif (isset($context['uid'])) {
$uid = $context['uid'];
}
else {
global $user;
$uid = $user->uid;
}
user_stats_post_count_update('reset', $uid);
}
/**
* Implementation of a Drupal action.
* Resets a user's login count.
*/
function user_stats_login_count_reset_action(&$object, $context = array()) {
if (isset($object->uid)) {
$uid = $object->uid;
}
elseif (isset($context['uid'])) {
$uid = $context['uid'];
}
else {
global $user;
$uid = $user->uid;
}
user_stats_login_count_update('reset', $uid);
}
/**
* Implementation of hook_user_stats().
*
* Invoke the Rules module.
*/
function user_stats_user_stats($type, $op, $uid, $value) {
if (module_exists('rules')) {
rules_invoke_event('user_stats_' . $type . '_' . $op, $uid, $value);
}
}
/**
* Token hook implementations
*/
/**
* Implementation of hook_token_values().
*/
function user_stats_token_values($type, $object = NULL) {
switch ($type) {
case 'user':
case 'all':
if (isset($object)) {
// Think this is sometimes an array (please raise this as an issue if wrong).
$object = (object) $object;
$uid = $object->uid;
}
else {
global $user;
$uid = $user->uid;
}
// Check_plain added as per Greggles suggestion: http://drupal.org/node/166305#comment-665874
$values['reg-days'] = check_plain(user_stats_get_stats('reg_days', $uid));
$values['login-days'] = check_plain(user_stats_get_stats('login_days', $uid));
$values['post-days'] = check_plain(user_stats_get_stats('post_days', $uid));
$values['post-count'] = check_plain(user_stats_get_stats('post_count', $uid));
$values['ip-address'] = check_plain(user_stats_get_stats('ip_address', $uid));
$values['login-count'] = check_plain(user_stats_get_stats('login_count', $uid));
return $values;
}
}
/**
* Implementation of hook_token_list().
*/
function user_stats_token_list($type = 'all') {
if ($type == 'user' || $type == 'all') {
$tokens['user']['reg-days'] = t('Number of days since the user registered');
$tokens['user']['login-days'] = t('Number of days since the user logged in');
$tokens['user']['post-days'] = t('Number of days since the user posted');
$tokens['user']['post-count'] = t("User's post count");
$tokens['user']['ip-address'] = t("User's IP address");
$tokens['user']['login-count'] = t("User's login count");
return $tokens;
}
}
/**
* Checks whether a statistic is set for a given user.
*
* @param $uid
* User ID of the user who's statistics should be checked.
* @param $statistic
* What statistic to check.
*/
function user_stats_isset($statistic, $uid) {
$result = db_result(db_query("SELECT COUNT(*) FROM {user_stats_values}\n WHERE uid = %d AND name = '%s'", $uid, $statistic));
if ($result > 0) {
return TRUE;
}
return FALSE;
}
/**
* Manage the login count of a given user.
*
* @param $uid
* Unique id of the user who's record should be updated.
* @param $op
* Whether the user login count should be incremented, decremented, or reset.
* Possible values are:
* - 'increment'
* - 'decrement'
* - 'reset'
*/
function user_stats_login_count_update($op, $uid) {
if (!is_numeric($uid)) {
return;
}
switch ($op) {
case 'increment':
if (user_stats_isset('login_count', $uid)) {
// Update existing value.
db_query("UPDATE {user_stats_values} SET value = value + 1\n WHERE name = 'login_count' AND uid = %d", $uid);
}
else {
// If there isn't a value insert it.
db_query("INSERT INTO {user_stats_values} (name, uid, value)\n VALUES ('login_count', %d, 1)", $uid);
}
break;
case 'decrement':
if (user_stats_isset('login_count', $uid)) {
// Update existing value.
db_query("UPDATE {user_stats_values} SET value = value - 1\n WHERE name = 'login_count' AND uid = %d", $uid);
}
else {
// If there isn't a value insert it.
db_query("INSERT INTO {user_stats_values} (name, uid, value)\n VALUES ('login_count', %d, 0)", $uid);
}
break;
case 'reset':
db_query("DELETE FROM {user_stats_values}\n WHERE name = 'login_count' AND uid = %d", $uid);
break;
}
// Flush token cache.
if (module_exists('token')) {
token_get_values('user', NULL, TRUE);
}
// Flush internal cache.
user_stats_cache_set('reset', $uid);
// Allow modules to react to a statistic change.
module_invoke_all('user_stats', 'login_count', $op, $uid, user_stats_get_stats('login_count', $uid));
}
/**
* Manage the post count of a given user.
*
* @param $uid
* Unique id of the user who's record should be updated.
* @param $op
* Whether the user post count should be incremented, decremented, or reset.
* The default is to increment. Possible values are:
* 'increment'
* 'decrement'
* 'reset'
*/
function user_stats_post_count_update($op, $uid) {
if (!is_numeric($uid)) {
return;
}
switch ($op) {
case 'increment':
if (user_stats_isset('post_count', $uid)) {
db_query("UPDATE {user_stats_values} SET value = value + 1\n WHERE name = 'post_count' AND uid = %d", $uid);
// Flush internal cache.
user_stats_cache_set('reset', $uid);
}
else {
user_stats_post_count_update('reset', $uid);
}
break;
case 'decrement':
if (user_stats_isset('post_count', $uid)) {
db_query("UPDATE {user_stats_values} SET value = value - 1\n WHERE name = 'post_count' AND uid = %d", $uid);
// Flush internal cache.
user_stats_cache_set('reset', $uid);
}
else {
user_stats_post_count_update('reset', $uid);
}
break;
case 'reset':
$total_count = 0;
if (variable_get('user_stats_count_posts', TRUE)) {
$sql = "SELECT COUNT(*) FROM {node} WHERE uid = %d AND status = 1";
$post_count_content_types = variable_get('user_stats_included_content_types', array());
if (!empty($post_count_content_types)) {
$content_types = "'" . implode("','", $post_count_content_types) . "'";
$where = ' AND type IN (' . $content_types . ')';
$sql .= $where;
}
$node_count = db_result(db_query($sql, $uid));
$total_count += $node_count;
}
if (variable_get('user_stats_count_comments', TRUE)) {
$sql = "SELECT COUNT(*) FROM {comments} c\n INNER JOIN {node} n ON c.nid = n.nid\n WHERE c.uid = %d AND c.status = 0 AND n.status = 1";
if (!empty($post_count_content_types)) {
$where = ' AND n.type IN (' . $content_types . ')';
$sql .= $where;
}
$comments_count = db_result(db_query($sql, $uid));
$total_count += $comments_count;
}
db_query("DELETE FROM {user_stats_values}\n WHERE name = 'post_count' AND uid = %d", $uid);
db_query("INSERT INTO {user_stats_values} (name, uid, value)\n VALUES ('post_count', %d, %d)", $uid, $total_count);
// Prime the cache, this will be used by module_invoke_all() below.
user_stats_cache_set('post_count', $uid, $total_count);
break;
}
// Flush token cache
if (module_exists('token')) {
token_get_values('user', NULL, TRUE);
}
// Allow modules to react to a statistic change.
module_invoke_all('user_stats', 'post_count', $op, $uid, user_stats_get_stats('post_count', $uid));
}
/**
* Update the IP address of a given user.
*
* The IP address is not updated if it is the same as the last recorded IP,
* however, if the user has IP address A, then switches to IP address B
* and back to A again, A will be recorded twice. This is to keep an accurate
* log of IP addresses used by users.
*
* @param $uid
* User ID of user who's IP is being updated.
* @param $ip_address
* IP address to assign to user.
*/
function user_stats_ip_address_update($uid, $ip_address) {
if (!is_numeric($uid)) {
return;
}
// Don't bother recording IPs of anonymous users, and don't record any
// addresses if the config form tells us not to.
if ($uid == 0 || !variable_get('user_stats_track_ips', TRUE)) {
return;
}
$query = db_query_range("SELECT ip_address\n FROM {user_stats_ips} WHERE uid = %d\n ORDER BY first_seen_timestamp DESC", $uid, 0, 1);
if ($ip_address != db_result($query)) {
// Reset internal cache.
user_stats_cache_set('reset', $uid);
db_query("INSERT INTO {user_stats_ips} (uid, ip_address, first_seen_timestamp)\n VALUES (%d, '%s', %d)", $uid, $ip_address, time());
// Allow modules to react to an IP address change.
module_invoke_all('user_stats', 'ip_address', 'insert', $uid, $ip_address);
}
}
/**
* Resets statistics. Full stop.
*
* @param $statistic
* The name of the statistic to be reset.
* Corresponds with {user_stats_values}.name.
*/
function user_stats_reset_counts($statistic) {
db_query("DELETE FROM {user_stats_values} WHERE name = '%s'", $statistic);
}
Functions
Name | Description |
---|---|
user_stats_action_info | Implementation of hook_action_info(). |
user_stats_cache_get | Return data from the non-persistent User Stats cache. Single values are returned according to type of statistic and unique user id. |
user_stats_cache_set | Store a value in the non-persistent User Stats cache. |
user_stats_comment | Implementation of hook_comment(). |
user_stats_cron | Implementation of hook_cron(). |
user_stats_get_stats | Returns user stats. |
user_stats_ip_address_update | Update the IP address of a given user. |
user_stats_isset | Checks whether a statistic is set for a given user. |
user_stats_login_count_reset_action | Implementation of a Drupal action. Resets a user's login count. |
user_stats_login_count_update | Manage the login count of a given user. |
user_stats_menu | Implementation of hook_menu(). |
user_stats_nodeapi | Implementation of hook_nodeapi(). |
user_stats_perm | Implementation of hook_perm(). |
user_stats_post_count_reset_action | Implementation of a Drupal action. Resets a user's post count. |
user_stats_post_count_update | Manage the post count of a given user. |
user_stats_reset_counts | Resets statistics. Full stop. |
user_stats_token_list | Implementation of hook_token_list(). |
user_stats_token_values | Implementation of hook_token_values(). |
user_stats_user | Implementation of hook_user(). |
user_stats_user_stats | Implementation of hook_user_stats(). |
user_stats_views_api | Implementation of hook_views_api(). |
_user_stats_last_post | Helper function to get the last post created by the user. |