2007-04-16 11:58:25 +00:00
|
|
|
<?php
|
2009-07-21 06:36:12 +00:00
|
|
|
/** @private */
|
2009-05-30 13:47:35 +00:00
|
|
|
function _new_user($row) {
|
|
|
|
return new User($row);
|
|
|
|
}
|
|
|
|
|
2012-02-07 13:44:54 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2007-12-06 11:01:18 +00:00
|
|
|
* An object representing a row in the "users" table.
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
|
|
|
* The currently logged in user will always be accessable via the global variable $user
|
2007-12-06 11:01:18 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
class User {
|
|
|
|
var $id;
|
|
|
|
var $name;
|
|
|
|
var $email;
|
|
|
|
var $join_date;
|
|
|
|
var $admin;
|
2008-08-23 12:05:24 +00:00
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Initialisation *
|
|
|
|
* *
|
|
|
|
* User objects shouldn't be created directly, they should be *
|
|
|
|
* fetched from the database like so: *
|
|
|
|
* *
|
2009-05-30 13:47:35 +00:00
|
|
|
* $user = User::by_name("bob"); *
|
2008-08-23 12:05:24 +00:00
|
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* One will very rarely construct a user directly, more common
|
|
|
|
* would be to use User::by_id, User::by_session, etc
|
|
|
|
*/
|
2009-05-11 14:04:33 +00:00
|
|
|
public function User($row) {
|
2007-04-16 11:58:25 +00:00
|
|
|
$this->id = int_escape($row['id']);
|
|
|
|
$this->name = $row['name'];
|
|
|
|
$this->email = $row['email'];
|
|
|
|
$this->join_date = $row['joindate'];
|
|
|
|
$this->admin = ($row['admin'] == 'Y');
|
2010-05-28 12:04:57 +00:00
|
|
|
$this->passhash = $row['pass'];
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2012-02-02 13:58:48 +00:00
|
|
|
public static function by_session(/*string*/ $name, /*string*/ $session) {
|
2009-05-11 14:04:33 +00:00
|
|
|
global $config, $database;
|
2012-01-11 20:57:00 +00:00
|
|
|
if($database->engine->name === "mysql") {
|
2011-01-01 15:28:30 +00:00
|
|
|
$query = "SELECT * FROM users WHERE name = :name AND md5(concat(pass, :ip)) = :sess";
|
2010-02-02 00:43:10 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-01-01 15:28:30 +00:00
|
|
|
$query = "SELECT * FROM users WHERE name = :name AND md5(pass || :ip) = :sess";
|
2010-02-02 00:43:10 +00:00
|
|
|
}
|
2011-01-01 15:28:30 +00:00
|
|
|
$row = $database->get_row($query, array("name"=>$name, "ip"=>get_session_ip($config), "sess"=>$session));
|
2009-05-11 14:04:33 +00:00
|
|
|
return is_null($row) ? null : new User($row);
|
2008-08-23 12:05:24 +00:00
|
|
|
}
|
|
|
|
|
2012-02-02 13:58:48 +00:00
|
|
|
public static function by_id(/*int*/ $id) {
|
2008-08-23 12:05:24 +00:00
|
|
|
assert(is_numeric($id));
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2012-01-11 20:57:00 +00:00
|
|
|
if($id === 1) {
|
|
|
|
$cached = $database->cache->get('user-id:'.$id);
|
2011-03-23 11:26:11 +00:00
|
|
|
if($cached) return new User($cached);
|
|
|
|
}
|
2011-01-01 15:58:09 +00:00
|
|
|
$row = $database->get_row("SELECT * FROM users WHERE id = :id", array("id"=>$id));
|
2012-01-11 20:57:00 +00:00
|
|
|
if($id === 1) $database->cache->set('user-id:'.$id, $row, 300);
|
2009-05-11 14:04:33 +00:00
|
|
|
return is_null($row) ? null : new User($row);
|
2008-08-23 12:05:24 +00:00
|
|
|
}
|
|
|
|
|
2012-02-02 13:58:48 +00:00
|
|
|
public static function by_name(/*string*/ $name) {
|
2008-08-23 12:05:24 +00:00
|
|
|
assert(is_string($name));
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2011-01-01 15:58:09 +00:00
|
|
|
$row = $database->get_row("SELECT * FROM users WHERE name = :name", array("name"=>$name));
|
2009-05-11 14:04:33 +00:00
|
|
|
return is_null($row) ? null : new User($row);
|
2008-08-23 12:05:24 +00:00
|
|
|
}
|
|
|
|
|
2012-02-02 13:58:48 +00:00
|
|
|
public static function by_name_and_hash(/*string*/ $name, /*string*/ $hash) {
|
2008-08-23 12:05:24 +00:00
|
|
|
assert(is_string($name));
|
|
|
|
assert(is_string($hash));
|
|
|
|
assert(strlen($hash) == 32);
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2011-01-01 15:58:09 +00:00
|
|
|
$row = $database->get_row("SELECT * FROM users WHERE name = :name AND pass = :hash", array("name"=>$name, "hash"=>$hash));
|
2009-05-11 14:04:33 +00:00
|
|
|
return is_null($row) ? null : new User($row);
|
2008-08-23 12:05:24 +00:00
|
|
|
}
|
|
|
|
|
2012-02-02 13:58:48 +00:00
|
|
|
public static function by_list(/*int*/ $offset, /*int*/ $limit=50) {
|
2009-05-30 13:47:35 +00:00
|
|
|
assert(is_numeric($offset));
|
|
|
|
assert(is_numeric($limit));
|
|
|
|
global $database;
|
2011-01-01 15:58:09 +00:00
|
|
|
$rows = $database->get_all("SELECT * FROM users WHERE id >= :start AND id < :end", array("start"=>$offset, "end"=>$offset+$limit));
|
2009-05-30 13:47:35 +00:00
|
|
|
return array_map("_new_user", $rows);
|
|
|
|
}
|
|
|
|
|
2008-08-23 12:05:24 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* useful user object functions start here
|
|
|
|
*/
|
2012-02-07 13:44:54 +00:00
|
|
|
public function can($ability) {
|
2012-02-07 15:15:18 +00:00
|
|
|
global $config;
|
|
|
|
|
|
|
|
// TODO: make this into an editable database table
|
|
|
|
$user_classes = array(
|
|
|
|
"anonymous" => array(
|
|
|
|
"change_setting" => False, # web-level settings, eg the config table
|
|
|
|
"override_config" => False, # sys-level config, eg config.php
|
|
|
|
"big_search" => False, # more than 3 tags (speed mode only)
|
|
|
|
"lock_image" => False,
|
|
|
|
"view_ip" => False, # view IP addresses associated with things
|
|
|
|
"change_password" => False,
|
|
|
|
"change_user_info" => False,
|
|
|
|
"delete_user" => False,
|
|
|
|
"delete_image" => False,
|
|
|
|
"delete_comment" => False,
|
|
|
|
"replace_image" => False,
|
|
|
|
"manage_extension_list" => False,
|
|
|
|
"manage_alias_list" => False,
|
2012-02-09 17:03:39 +00:00
|
|
|
"edit_image_tag" => $config->get_bool("tag_edit_anon"),
|
|
|
|
"edit_image_source" => $config->get_bool("source_edit_anon"),
|
|
|
|
"edit_image_owner" => False,
|
2012-02-07 15:15:18 +00:00
|
|
|
"mass_tag_edit" => False,
|
|
|
|
),
|
|
|
|
"user" => array(
|
|
|
|
"change_setting" => False,
|
|
|
|
"override_config" => False,
|
|
|
|
"big_search" => True,
|
|
|
|
"lock_image" => False,
|
|
|
|
"view_ip" => False,
|
|
|
|
"change_password" => False,
|
|
|
|
"change_user_info" => False,
|
|
|
|
"delete_user" => False,
|
|
|
|
"delete_image" => False,
|
|
|
|
"delete_comment" => False,
|
2012-02-09 17:03:39 +00:00
|
|
|
"change_image_owner" => False,
|
2012-02-07 15:15:18 +00:00
|
|
|
"replace_image" => False,
|
|
|
|
"manage_extension_list" => False,
|
|
|
|
"manage_alias_list" => False,
|
2012-02-09 17:03:39 +00:00
|
|
|
"edit_image_tag" => True,
|
|
|
|
"edit_image_source" => True,
|
|
|
|
"edit_image_owner" => False,
|
2012-02-07 15:15:18 +00:00
|
|
|
"mass_tag_edit" => False,
|
|
|
|
),
|
|
|
|
"admin" => array(
|
|
|
|
"change_setting" => True,
|
|
|
|
"override_config" => True,
|
|
|
|
"big_search" => True,
|
|
|
|
"lock_image" => True,
|
|
|
|
"view_ip" => True,
|
|
|
|
"change_password" => True,
|
|
|
|
"change_user_info" => True,
|
|
|
|
"delete_user" => True,
|
|
|
|
"delete_image" => True,
|
|
|
|
"delete_comment" => True,
|
|
|
|
"replace_image" => True,
|
|
|
|
"manage_extension_list" => True,
|
|
|
|
"manage_alias_list" => True,
|
2012-02-09 17:03:39 +00:00
|
|
|
"edit_image_tag" => True,
|
|
|
|
"edit_image_source" => True,
|
|
|
|
"edit_image_owner" => True,
|
2012-02-07 15:15:18 +00:00
|
|
|
"mass_tag_edit" => True,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
2012-02-07 18:27:53 +00:00
|
|
|
return $user_classes[$this->get_class()][$ability];
|
2012-02-07 15:15:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: this should be a column in the users table
|
|
|
|
public function get_class() {
|
|
|
|
if($this->is_admin()) return "admin";
|
|
|
|
else if($this->is_logged_in()) return "user";
|
|
|
|
else return"anonymous";
|
2012-02-07 13:44:54 +00:00
|
|
|
}
|
|
|
|
|
2008-08-23 12:05:24 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Test if this user is anonymous (not logged in)
|
|
|
|
*
|
2009-07-21 06:36:12 +00:00
|
|
|
* @retval bool
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function is_anonymous() {
|
2009-05-11 14:04:33 +00:00
|
|
|
global $config;
|
2012-01-12 19:46:58 +00:00
|
|
|
return ($this->id === $config->get_int('anon_id'));
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2010-01-12 15:01:34 +00:00
|
|
|
/**
|
|
|
|
* Test if this user is logged in
|
|
|
|
*
|
|
|
|
* @retval bool
|
|
|
|
*/
|
|
|
|
public function is_logged_in() {
|
|
|
|
global $config;
|
2012-01-12 19:46:58 +00:00
|
|
|
return ($this->id !== $config->get_int('anon_id'));
|
2010-01-12 15:01:34 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Test if this user is an administrator
|
|
|
|
*
|
2009-07-21 06:36:12 +00:00
|
|
|
* @retval bool
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function is_admin() {
|
|
|
|
return $this->admin;
|
|
|
|
}
|
|
|
|
|
2012-02-02 13:58:48 +00:00
|
|
|
public function set_admin(/*bool*/ $admin) {
|
2008-08-23 12:05:24 +00:00
|
|
|
assert(is_bool($admin));
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2007-04-16 11:58:25 +00:00
|
|
|
$yn = $admin ? 'Y' : 'N';
|
2011-01-01 15:58:09 +00:00
|
|
|
$database->Execute("UPDATE users SET admin=:yn WHERE id=:id", array("yn"=>$yn, "id"=>$this->id));
|
2012-01-12 19:46:58 +00:00
|
|
|
log_info("core-user", 'Made '.$this->name.' admin='.$yn);
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2012-02-02 13:58:48 +00:00
|
|
|
public function set_password(/*string*/ $password) {
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2007-11-04 03:51:41 +00:00
|
|
|
$hash = md5(strtolower($this->name) . $password);
|
2011-01-01 15:58:09 +00:00
|
|
|
$database->Execute("UPDATE users SET pass=:hash WHERE id=:id", array("hash"=>$hash, "id"=>$this->id));
|
2012-01-12 19:46:58 +00:00
|
|
|
log_info("core-user", 'Set password for '.$this->name);
|
2007-11-04 03:51:41 +00:00
|
|
|
}
|
2009-08-11 16:07:03 +00:00
|
|
|
|
2012-02-02 13:58:48 +00:00
|
|
|
public function set_email(/*string*/ $address) {
|
2009-08-11 16:07:03 +00:00
|
|
|
global $database;
|
2011-01-01 15:58:09 +00:00
|
|
|
$database->Execute("UPDATE users SET email=:email WHERE id=:id", array("email"=>$address, "id"=>$this->id));
|
2012-01-12 19:46:58 +00:00
|
|
|
log_info("core-user", 'Set email for '.$this->name);
|
2009-08-11 16:07:03 +00:00
|
|
|
}
|
2009-10-08 01:57:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a snippet of HTML which will render the user's avatar, be that
|
|
|
|
* a local file, a remote file, a gravatar, a something else, etc
|
2012-02-08 01:05:38 +00:00
|
|
|
* @retval String of HTML
|
2009-10-08 01:57:28 +00:00
|
|
|
*/
|
|
|
|
public function get_avatar_html() {
|
|
|
|
// FIXME: configurable
|
2009-10-08 11:40:52 +00:00
|
|
|
global $config;
|
2012-01-11 20:57:00 +00:00
|
|
|
if($config->get_string("avatar_host") === "gravatar") {
|
2009-10-08 11:40:52 +00:00
|
|
|
if(!empty($this->email)) {
|
|
|
|
$hash = md5(strtolower($this->email));
|
2010-04-21 16:56:01 +00:00
|
|
|
$s = $config->get_string("avatar_gravatar_size");
|
|
|
|
$d = $config->get_string("avatar_gravatar_default");
|
|
|
|
$r = $config->get_string("avatar_gravatar_rating");
|
|
|
|
return "<img class=\"avatar gravatar\" src=\"http://www.gravatar.com/avatar/$hash.jpg?s=$s&d=$d&r=$r\">";
|
2009-10-08 11:40:52 +00:00
|
|
|
}
|
2009-10-08 01:57:28 +00:00
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
2010-05-28 12:04:57 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get an auth token to be used in POST forms
|
|
|
|
*
|
|
|
|
* password = secret, avoid storing directly
|
|
|
|
* passhash = md5(password), so someone who gets to the database can't get passwords
|
|
|
|
* sesskey = md5(passhash . IP), so if it gets sniffed it can't be used from another IP,
|
|
|
|
* and it can't be used to get the passhash to generate new sesskeys
|
|
|
|
* authtok = md5(sesskey, salt), presented to the user in web forms, to make sure that
|
|
|
|
* the form was generated within the session. Salted and re-hashed so that
|
|
|
|
* reading a web page from the user's cache doesn't give access to the session key
|
2012-02-08 01:05:38 +00:00
|
|
|
*
|
|
|
|
* @retval String containing auth token (MD5sum)
|
2010-05-28 12:04:57 +00:00
|
|
|
*/
|
|
|
|
public function get_auth_token() {
|
|
|
|
global $config;
|
2012-02-02 03:53:18 +00:00
|
|
|
$salt = DATABASE_DSN;
|
2010-05-28 12:04:57 +00:00
|
|
|
$addr = get_session_ip($config);
|
2010-09-22 12:20:08 +00:00
|
|
|
return md5(md5($this->passhash . $addr) . "salty-csrf-" . $salt);
|
2010-05-28 12:04:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function get_auth_html() {
|
|
|
|
$at = $this->get_auth_token();
|
2012-01-11 20:57:00 +00:00
|
|
|
return '<input type="hidden" name="auth_token" value="'.$at.'">';
|
2010-05-28 12:04:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function check_auth_token() {
|
2012-01-26 17:36:22 +00:00
|
|
|
return (isset($_POST["auth_token"]) && $_POST["auth_token"] == $this->get_auth_token());
|
2010-05-28 12:04:57 +00:00
|
|
|
}
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
?>
|