This repository has been archived on 2024-06-26. You can view files and clone it, but cannot push or open issues or pull requests.
sakura/libraries/User.php

1296 lines
35 KiB
PHP
Raw Normal View History

2015-08-18 23:29:45 +00:00
<?php
2016-02-03 22:22:56 +00:00
/**
* Holds the user object class.
2016-03-08 23:07:58 +00:00
*
2016-02-03 22:22:56 +00:00
* @package Sakura
*/
2015-08-18 23:29:45 +00:00
namespace Sakura;
2015-12-29 21:52:19 +00:00
use Sakura\Perms;
use Sakura\Perms\Site;
2016-03-27 21:18:57 +00:00
use stdClass;
2015-12-29 21:52:19 +00:00
/**
2016-02-02 21:04:15 +00:00
* Everything you'd ever need from a specific user.
2016-03-08 23:07:58 +00:00
*
* @package Sakura
2016-02-02 21:04:15 +00:00
* @author Julian van de Groep <me@flash.moe>
*/
class User
{
2016-02-02 21:04:15 +00:00
/**
* The User's ID.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var int
*/
2016-01-17 01:58:31 +00:00
public $id = 0;
2016-02-02 21:04:15 +00:00
/**
* The user's username.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $username = 'User';
2016-02-02 21:04:15 +00:00
/**
* A cleaned version of the username.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $usernameClean = 'user';
2016-02-02 21:04:15 +00:00
/**
* The user's password hash.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $passwordHash = '';
2016-02-02 21:04:15 +00:00
/**
* The user's password salt.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $passwordSalt = '';
2016-02-02 21:04:15 +00:00
/**
* The user's password algorithm.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $passwordAlgo = 'disabled';
2016-02-02 21:04:15 +00:00
/**
* The password iterations.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var int
*/
2016-01-17 01:58:31 +00:00
public $passwordIter = 0;
2016-02-02 21:04:15 +00:00
/**
* UNIX timestamp of last time the password was changed.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var int
*/
2016-01-17 01:58:31 +00:00
public $passwordChan = 0;
2016-02-02 21:04:15 +00:00
/**
* The user's e-mail address.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $email = 'user@sakura';
2016-02-02 21:04:15 +00:00
/**
* The rank object of the user's main rank.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var Rank
*/
2016-01-17 01:58:31 +00:00
public $mainRank = null;
2016-02-02 21:04:15 +00:00
/**
* The ID of the main rank.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var int
*/
2016-01-17 01:58:31 +00:00
public $mainRankId = 1;
2016-02-02 21:04:15 +00:00
/**
* The index of rank objects.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var array
*/
2016-01-17 01:58:31 +00:00
public $ranks = [];
2016-02-02 21:04:15 +00:00
/**
* The user's username colour.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $colour = '';
2016-02-02 21:04:15 +00:00
/**
* The IP the user registered from.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $registerIp = '0.0.0.0';
2016-02-02 21:04:15 +00:00
/**
* The IP the user was last active from.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $lastIp = '0.0.0.0';
2016-02-02 21:04:15 +00:00
/**
* A user's title.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $title = '';
2016-02-02 21:04:15 +00:00
/**
* The UNIX timestamp of when the user registered.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var int
*/
2016-01-17 01:58:31 +00:00
public $registered = 0;
2016-02-02 21:04:15 +00:00
/**
* The UNIX timestamp of when the user was last online.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var int
*/
2016-01-17 01:58:31 +00:00
public $lastOnline = 0;
2016-02-02 21:04:15 +00:00
/**
* The 2 character country code of a user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $country = 'XX';
2016-02-02 21:04:15 +00:00
/**
* The File id of the user's avatar.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var int
*/
2016-01-17 01:58:31 +00:00
public $avatar = 0;
2016-02-02 21:04:15 +00:00
/**
* The File id of the user's background.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var int
*/
2016-01-17 01:58:31 +00:00
public $background = 0;
2016-02-02 21:04:15 +00:00
/**
2016-02-28 17:45:25 +00:00
* The File id of the user's header.
2016-02-02 21:04:15 +00:00
* @var mixed
*/
2016-01-17 01:58:31 +00:00
public $header = 0;
2016-02-02 21:04:15 +00:00
/**
* The raw userpage of the user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $page = '';
2016-02-02 21:04:15 +00:00
/**
* The raw signature of the user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
public $signature = '';
2016-02-02 21:04:15 +00:00
/**
* The user's birthday.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var string
*/
2016-01-17 01:58:31 +00:00
private $birthday = '0000-00-00';
2016-02-02 21:04:15 +00:00
/**
* The user's permission container.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var Perms
*/
2015-12-29 21:52:19 +00:00
private $permissions;
2016-02-02 21:04:15 +00:00
/**
* The user's option fields.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var array
*/
2016-01-17 01:58:31 +00:00
private $optionFields = null;
2016-02-02 21:04:15 +00:00
/**
* The user's profile fields.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var array
*/
2016-01-17 01:58:31 +00:00
private $profileFields = null;
2016-02-02 21:04:15 +00:00
/**
* The User instance cache array.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @var array
*/
2015-12-29 01:27:49 +00:00
protected static $_userCache = [];
2016-02-02 21:04:15 +00:00
/**
* Cached constructor.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param int|string $uid The user ID or clean username.
* @param bool $forceRefresh Force a recreation.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return User Returns a user object.
*/
public static function construct($uid, $forceRefresh = false)
{
2015-12-29 01:27:49 +00:00
// Check if a user object isn't present in cache
if ($forceRefresh || !array_key_exists($uid, self::$_userCache)) {
// If not create a new object and cache it
self::$_userCache[$uid] = new User($uid);
}
// Return the cached object
return self::$_userCache[$uid];
}
2015-08-18 23:29:45 +00:00
2016-02-02 21:04:15 +00:00
/**
* Create a new user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param string $username The username of the user.
* @param string $password The password of the user.
* @param string $email The e-mail, used primarily for activation.
* @param array $ranks The ranks assigned to the user on creation.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return User The newly created user's object.
*/
2016-01-04 20:14:09 +00:00
public static function create($username, $password, $email, $ranks = [2])
{
// Set a few variables
2016-01-17 01:58:31 +00:00
$usernameClean = Utils::cleanString($username, true);
$emailClean = Utils::cleanString($email, true);
2016-01-04 20:14:09 +00:00
$password = Hashing::createHash($password);
2016-01-17 02:08:08 +00:00
2016-02-28 17:45:25 +00:00
// Insert the user into the database and get the id
$userId = DB::table('users')
->insertGetId([
'username' => $username,
'username_clean' => $usernameClean,
'password_hash' => $password[3],
'password_salt' => $password[2],
'password_algo' => $password[0],
'password_iter' => $password[1],
'email' => $emailClean,
'rank_main' => 0,
2016-03-27 21:18:57 +00:00
'register_ip' => Net::pton(Net::ip()),
'last_ip' => Net::pton(Net::ip()),
2016-02-28 17:45:25 +00:00
'user_registered' => time(),
'user_last_online' => 0,
'user_country' => Utils::getCountryCode(),
]);
2016-01-04 20:14:09 +00:00
// Create a user object
$user = self::construct($userId);
// Assign the default rank
$user->addRanks($ranks);
// Set the default rank
$user->setMainRank($ranks[0]);
// Return the user object
return $user;
}
2016-02-02 21:04:15 +00:00
/**
* The actual constructor
2016-03-08 23:07:58 +00:00
*
2016-02-28 17:45:25 +00:00
* @param int|string $userId The user ID or clean username.
2016-02-02 21:04:15 +00:00
*/
2016-02-28 17:45:25 +00:00
private function __construct($userId)
{
2015-08-18 23:29:45 +00:00
// Get the user database row
2016-02-28 17:45:25 +00:00
$userRow = DB::table('users')
->where('user_id', $userId)
->orWhere('username_clean', Utils::cleanString($userId, true, true))
->get();
2015-08-21 22:07:45 +00:00
2016-01-17 01:58:31 +00:00
// Populate the variables
if ($userRow) {
2016-02-28 17:45:25 +00:00
$userRow = $userRow[0];
2016-02-18 23:28:44 +00:00
$this->id = $userRow->user_id;
$this->username = $userRow->username;
$this->usernameClean = $userRow->username_clean;
$this->passwordHash = $userRow->password_hash;
$this->passwordSalt = $userRow->password_salt;
$this->passwordAlgo = $userRow->password_algo;
$this->passwordIter = $userRow->password_iter;
$this->passwordChan = $userRow->password_chan;
$this->email = $userRow->email;
$this->mainRankId = $userRow->rank_main;
$this->colour = $userRow->user_colour;
2016-02-28 17:45:25 +00:00
$this->registerIp = Net::ntop($userRow->register_ip);
$this->lastIp = Net::ntop($userRow->last_ip);
2016-02-18 23:28:44 +00:00
$this->title = $userRow->user_title;
$this->registered = $userRow->user_registered;
$this->lastOnline = $userRow->user_last_online;
$this->birthday = $userRow->user_birthday;
$this->country = $userRow->user_country;
$this->avatar = $userRow->user_avatar;
$this->background = $userRow->user_background;
$this->header = $userRow->user_header;
$this->page = $userRow->user_page;
$this->signature = $userRow->user_signature;
2015-08-19 02:37:45 +00:00
}
2016-01-03 21:19:37 +00:00
// Get all ranks
2016-02-28 17:45:25 +00:00
$ranks = DB::table('user_ranks')
->where('user_id', $this->id)
->get(['rank_id']);
2015-08-18 23:29:45 +00:00
// Get the rows for all the ranks
2016-01-03 21:19:37 +00:00
foreach ($ranks as $rank) {
2015-08-19 02:37:45 +00:00
// Store the database row in the array
2016-02-18 23:28:44 +00:00
$this->ranks[$rank->rank_id] = Rank::construct($rank->rank_id);
2015-08-19 02:37:45 +00:00
}
// Check if ranks were set
if (empty($this->ranks)) {
2015-08-19 02:37:45 +00:00
// If not assign the fallback rank
2016-01-04 20:14:09 +00:00
$this->ranks[1] = Rank::construct(1);
2015-08-19 02:37:45 +00:00
}
2016-01-17 01:58:31 +00:00
// Check if the rank is actually assigned to this user
if (!array_key_exists($this->mainRankId, $this->ranks)) {
$this->mainRankId = array_keys($this->ranks)[0];
$this->setMainRank($this->mainRankId);
}
2016-01-17 01:58:31 +00:00
// Assign the main rank to its own var
$this->mainRank = $this->ranks[$this->mainRankId];
2016-01-17 01:58:31 +00:00
// Set user colour
$this->colour = $this->colour ? $this->colour : $this->mainRank->colour;
2016-01-17 01:58:31 +00:00
// Set user title
$this->title = $this->title ? $this->title : $this->mainRank->title;
2015-08-21 22:07:45 +00:00
2016-01-17 01:58:31 +00:00
// Init the permissions
$this->permissions = new Perms(Perms::SITE);
2015-08-19 02:37:45 +00:00
}
2016-02-02 21:04:15 +00:00
/**
* Get the user's birthday.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param bool $age Just get the age.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return int|string Return the birthday.
*/
2016-01-17 01:58:31 +00:00
public function birthday($age = false)
{
2016-01-17 01:58:31 +00:00
// If age is requested calculate it
if ($age) {
// Create dates
$birthday = date_create($this->birthday);
$now = date_create(date('Y-m-d'));
2016-01-17 01:58:31 +00:00
// Get the difference
$diff = date_diff($birthday, $now);
2015-08-19 02:37:45 +00:00
2016-01-17 01:58:31 +00:00
// Return the difference in years
2016-01-22 12:46:52 +00:00
return (int) $diff->format('%Y');
2016-01-17 01:58:31 +00:00
}
2016-01-17 01:58:31 +00:00
// Otherwise just return the birthday value
return $this->birthday;
2015-08-19 02:37:45 +00:00
}
2016-02-02 21:04:15 +00:00
/**
* Get the user's country.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param bool $long Get the full country name.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return string The country.
*/
2016-01-17 01:58:31 +00:00
public function country($long = false)
{
2016-01-17 01:58:31 +00:00
return $long ? Utils::getCountryName($this->country) : $this->country;
}
2016-02-02 21:04:15 +00:00
/**
* Check if a user is online.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return bool Are they online?
*/
public function isOnline()
{
2016-02-28 17:45:25 +00:00
// Count sessions
$sessions = DB::table('sessions')
->where('user_id', $this->id)
->count();
// If there's no entries just straight up return false
2016-02-28 17:45:25 +00:00
if (!$sessions) {
return false;
}
// Otherwise use the standard method
2016-01-17 01:58:31 +00:00
return $this->lastOnline > (time() - Config::get('max_online_time'));
}
2016-02-02 21:04:15 +00:00
/**
* Get a few forum statistics.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array Post and thread counts.
*/
public function forumStats()
{
2016-02-28 17:45:25 +00:00
$posts = DB::table('posts')
->where('poster_id', $this->id)
->count();
2016-02-18 23:28:44 +00:00
2016-02-28 17:45:25 +00:00
$threads = DB::table('posts')
->where('poster_id', $this->id)
->distinct()
->groupBy('topic_id')
->orderBy('post_time')
->count();
2016-02-18 23:28:44 +00:00
return [
2016-02-28 17:45:25 +00:00
'posts' => $posts,
'topics' => $threads,
];
2015-08-19 12:13:38 +00:00
}
2016-02-02 21:04:15 +00:00
/**
* Add ranks to a user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param array $ranks Array containing the rank IDs.
*/
2015-11-11 21:56:03 +00:00
public function addRanks($ranks)
{
// Update the ranks array
2016-01-17 01:58:31 +00:00
$ranks = array_diff(
array_unique(
array_merge(
array_keys($this->ranks),
2016-03-17 19:09:00 +00:00
$ranks
)
),
array_keys($this->ranks)
);
// Save to the database
2016-01-03 21:19:37 +00:00
foreach ($ranks as $rank) {
2016-02-28 17:45:25 +00:00
DB::table('user_ranks')
->insert([
'rank_id' => $rank,
'user_id' => $this->id,
]);
2016-01-03 21:19:37 +00:00
}
}
2016-02-02 21:04:15 +00:00
/**
* Remove a set of ranks from a user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param array $ranks Array containing the IDs of ranks to remove.
*/
public function removeRanks($ranks)
{
// Current ranks
2016-01-17 01:58:31 +00:00
$remove = array_intersect(array_keys($this->ranks), $ranks);
// Iterate over the ranks
2016-01-03 21:19:37 +00:00
foreach ($remove as $rank) {
2016-03-17 19:09:00 +00:00
DB::table('user_ranks')
2016-02-28 17:45:25 +00:00
->where('user_id', $this->id)
->where('rank_id', $rank)
->delete();
}
}
2016-02-02 21:04:15 +00:00
/**
* Change the main rank of a user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param int $rank The ID of the new main rank.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return bool Always true.
*/
2015-11-08 22:31:52 +00:00
public function setMainRank($rank)
{
// If it does exist update their row
2016-02-28 17:45:25 +00:00
DB::table('users')
->where('user_id', $this->id)
->update([
'rank_main' => $rank,
]);
// Return true if everything was successful
2015-11-08 22:31:52 +00:00
return true;
}
2016-02-02 21:04:15 +00:00
/**
* Check if a user has a certain set of rank.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param array $ranks Ranks IDs to check.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return bool Successful?
*/
2015-11-08 22:31:52 +00:00
public function hasRanks($ranks)
{
// Check if the main rank is the specified rank
2016-01-17 01:58:31 +00:00
if (in_array($this->mainRankId, $ranks)) {
return true;
}
// If not go over all ranks and check if the user has them
foreach ($ranks as $rank) {
// We check if $rank is in $this->ranks and if yes return true
2016-01-17 01:58:31 +00:00
if (in_array($rank, array_keys($this->ranks))) {
return true;
}
}
// If all fails return false
return false;
2015-11-08 22:31:52 +00:00
}
2016-02-02 21:04:15 +00:00
/**
* Add a new friend.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param int $uid The ID of the friend.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array Status indicator.
*/
2015-10-12 18:25:37 +00:00
public function addFriend($uid)
{
// Create the foreign object
2015-12-29 01:27:49 +00:00
$user = User::construct($uid);
2015-10-12 18:25:37 +00:00
// Validate that the user exists
2015-12-29 21:52:19 +00:00
if ($user->permission(Site::DEACTIVATED)) {
2015-10-12 18:25:37 +00:00
return [0, 'USER_NOT_EXIST'];
}
// Check if the user already has this user a friend
if ($this->isFriends($uid)) {
2015-10-12 18:25:37 +00:00
return [0, 'ALREADY_FRIENDS'];
}
// Add friend
2016-02-28 17:45:25 +00:00
DB::table('friends')
->insert([
'user_id' => $this->id,
'friend_id' => $uid,
'friend_timestamp' => time(),
]);
2015-10-12 18:25:37 +00:00
// Return true because yay
2016-01-17 01:58:31 +00:00
return [1, $user->isFriends($this->id) ? 'FRIENDS' : 'NOT_MUTUAL'];
2015-10-12 18:25:37 +00:00
}
2016-02-02 21:04:15 +00:00
/**
* Remove a friend.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param int $uid The friend Id
* @param bool $deleteRequest Delete the open request as well (remove you from their friends list).
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array Status indicator.
*/
2015-10-12 18:25:37 +00:00
public function removeFriend($uid, $deleteRequest = false)
{
// Create the foreign object
2015-12-29 01:27:49 +00:00
$user = User::construct($uid);
2015-10-12 18:25:37 +00:00
// Validate that the user exists
2015-12-29 21:52:19 +00:00
if ($user->permission(Site::DEACTIVATED)) {
2015-10-12 18:25:37 +00:00
return [0, 'USER_NOT_EXIST'];
}
// Remove friend
DB::table('friends')
->where('user_id', $this->id)
->where('friend_id', $uid)
->delete();
2015-10-12 18:25:37 +00:00
// Attempt to remove the request
if ($deleteRequest) {
DB::table('friends')
->where('user_id', $uid)
->where('friend_id', $this->id)
->delete();
2015-10-12 18:25:37 +00:00
}
// Return true because yay
return [1, 'REMOVED'];
}
2016-02-02 21:04:15 +00:00
/**
* Check if this user is friends with another user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param int $with ID of the other user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return int 0 = no, 1 = pending request, 2 = mutual
*/
public function isFriends($with)
{
// Accepted from this user
$user = DB::table('friends')
->where('user_id', $this->id)
->where('friend_id', $with)
->count();
// And the other user
2016-03-19 15:29:47 +00:00
$friend = DB::table('friends')
->where('user_id', $with)
->where('friend_id', $this->id)
->count();
if ($user && $friend) {
return 2; // Mutual friends
} elseif ($user) {
return 1; // Pending request
}
// Else return 0
return 0;
}
2015-10-12 18:25:37 +00:00
2016-02-02 21:04:15 +00:00
/**
* Get all the friends from this user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param int $level Friend level; (figure out what the levels are at some point)
* @param bool $noObj Just return IDs.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array The array with either the objects or the ids.
*/
2015-11-11 00:30:22 +00:00
public function friends($level = 0, $noObj = false)
{
// User ID container
$users = [];
// Select the correct level
switch ($level) {
2016-02-18 23:28:44 +00:00
// Mutual
case 2:
// Get all the current user's friends
$self = DB::table('friends')
->where('user_id', $this->id)
->get(['friend_id']);
$self = array_column($self, 'friend_id');
2016-02-18 23:28:44 +00:00
// Get all the people that added this user as a friend
$others = DB::table('friends')
->where('friend_id', $this->id)
->get(['user_id']);
$others = array_column($others, 'user_id');
2016-02-18 23:28:44 +00:00
// Create a difference map
$users = array_intersect($self, $others);
break;
2016-02-18 23:28:44 +00:00
// Non-mutual (from user perspective)
case 1:
$users = DB::table('friends')
->where('user_id', $this->id)
->get(['friend_id']);
$users = array_column($users, 'friend_id');
break;
2016-02-18 23:28:44 +00:00
// All friend cases
case 0:
default:
// Get all the current user's friends
$self = DB::table('friends')
->where('user_id', $this->id)
->get(['friend_id']);
$self = array_column($self, 'friend_id');
2016-02-18 23:28:44 +00:00
// Get all the people that added this user as a friend
$others = DB::table('friends')
->where('friend_id', $this->id)
->get(['user_id']);
$others = array_column($others, 'user_id');
2016-02-18 23:28:44 +00:00
// Create a difference map
$users = array_merge($others, $self);
break;
2016-02-18 23:28:44 +00:00
// Open requests
case -1:
// Get all the current user's friends
$self = DB::table('friends')
->where('user_id', $this->id)
->get(['friend_id']);
$self = array_column($self, 'friend_id');
2016-02-18 23:28:44 +00:00
// Get all the people that added this user as a friend
$others = DB::table('friends')
->where('friend_id', $this->id)
->get(['user_id']);
$others = array_column($others, 'user_id');
2016-02-18 23:28:44 +00:00
// Create a difference map
$users = array_diff($others, $self);
break;
2015-10-12 18:25:37 +00:00
}
2015-11-11 00:30:22 +00:00
// Check if we only requested the IDs
if ($noObj) {
// If so just return $users
return $users;
}
// Create the storage array
$objects = [];
2015-11-11 00:30:22 +00:00
// Create the user objects
foreach ($users as $user) {
// Create new object
2015-12-29 01:27:49 +00:00
$objects[$user] = User::construct($user);
2015-10-12 18:25:37 +00:00
}
// Return the objects
return $objects;
2015-08-19 12:13:38 +00:00
}
2016-02-02 21:04:15 +00:00
/**
* Check if the user has a certaing permission flag.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param int $flag The permission flag.
* @param string $mode The permission mode.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return bool Success?
*/
2015-12-29 21:52:19 +00:00
public function permission($flag, $mode = null)
{
2015-12-29 21:52:19 +00:00
// Set mode
$this->permissions->mode($mode ? $mode : Perms::SITE);
// Set default permission value
$perm = 0;
// Bitwise OR it with the permissions for this forum
2016-01-17 01:58:31 +00:00
$perm = $this->permissions->user($this->id);
2015-12-29 21:52:19 +00:00
return $this->permissions->check($flag, $perm);
2015-08-21 22:07:45 +00:00
}
2016-02-02 21:04:15 +00:00
/**
2016-03-28 14:47:43 +00:00
* Get the comments from the user's profile.
*
2016-02-02 21:04:15 +00:00
* @return Comments
*/
public function profileComments()
{
2016-03-28 14:47:43 +00:00
$commentIds = DB::table('comments')
->where('comment_category', "profile-{$this->id}")
->orderBy('comment_id', 'desc')
->where('comment_reply_to', 0)
->get(['comment_id']);
$commentIds = array_column($commentIds, 'comment_id');
$comments = [];
foreach ($commentIds as $comment) {
$comments[$comment] = new Comment($comment);
}
return $comments;
}
2016-02-02 21:04:15 +00:00
/**
* Get the user's profile fields.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array The profile fields.
*/
public function profileFields()
{
2016-01-17 01:58:31 +00:00
// Check if we have cached data
if ($this->profileFields) {
return $this->profileFields;
2015-08-19 02:37:45 +00:00
}
2016-01-17 01:58:31 +00:00
// Create array and get values
2015-08-19 02:37:45 +00:00
$profile = [];
2016-02-18 23:28:44 +00:00
$profileFields = DB::table('profilefields')
->get();
2016-02-18 23:28:44 +00:00
$profileValuesRaw = DB::table('user_profilefields')
->where('user_id', $this->id)
->get();
2016-02-18 23:28:44 +00:00
$profileValues = array_column($profileValuesRaw, 'field_value', 'field_name');
2016-01-17 01:58:31 +00:00
// Check if anything was returned
if (!$profileFields || !$profileValues) {
return $profile;
}
2015-08-19 02:37:45 +00:00
// Check if profile fields aren't fake
foreach ($profileFields as $field) {
2015-08-19 02:37:45 +00:00
// Completely strip all special characters from the field name
$fieldName = Utils::cleanString($field->field_name, true, true);
2015-08-19 02:37:45 +00:00
// Check if the user has the current field set otherwise continue
2016-01-17 01:58:31 +00:00
if (!array_key_exists($fieldName, $profileValues)) {
2015-08-19 02:37:45 +00:00
continue;
}
// Assign field to output with value
$profile[$fieldName] = [];
$profile[$fieldName]['name'] = $field->field_name;
2016-01-17 01:58:31 +00:00
$profile[$fieldName]['value'] = $profileValues[$fieldName];
$profile[$fieldName]['islink'] = $field->field_link;
2015-08-19 02:37:45 +00:00
// If the field is set to be a link add a value for that as well
if ($field->field_link) {
2015-09-14 21:41:43 +00:00
$profile[$fieldName]['link'] = str_replace(
'{{ VAL }}',
2016-01-17 01:58:31 +00:00
$profileValues[$fieldName],
$field->field_linkformat
2015-09-14 21:41:43 +00:00
);
2015-08-19 02:37:45 +00:00
}
// Check if we have additional options as well
if ($field->field_additional != null) {
2015-08-19 02:37:45 +00:00
// Decode the json of the additional stuff
$additional = json_decode($field->field_additional, true);
2015-08-19 02:37:45 +00:00
// Go over all additional forms
foreach ($additional as $subName => $subField) {
2015-08-19 02:37:45 +00:00
// Check if the user has the current field set otherwise continue
2016-01-17 01:58:31 +00:00
if (!array_key_exists($subName, $profileValues)) {
2015-08-19 02:37:45 +00:00
continue;
}
// Assign field to output with value
2016-01-17 01:58:31 +00:00
$profile[$fieldName][$subName] = $profileValues[$subName];
2015-08-19 02:37:45 +00:00
}
}
}
2016-01-17 01:58:31 +00:00
// Assign cache
$this->profileFields = $profile;
2015-08-19 02:37:45 +00:00
// Return appropiate profile data
return $profile;
2015-08-18 23:29:45 +00:00
}
2016-02-02 21:04:15 +00:00
/**
* Get a user's option fields.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array The array containing the fields.
*/
public function optionFields()
{
2016-01-17 01:58:31 +00:00
// Check if we have cached data
if ($this->optionFields) {
return $this->optionFields;
2015-08-21 22:07:45 +00:00
}
2016-01-17 01:58:31 +00:00
// Create array and get values
2015-08-21 22:07:45 +00:00
$options = [];
2016-02-18 23:28:44 +00:00
$optionFields = DB::table('optionfields')
->get();
2016-02-18 23:28:44 +00:00
$optionValuesRaw = DB::table('user_optionfields')
->where('user_id', $this->id)
->get();
2016-02-18 23:28:44 +00:00
$optionValues = array_column($optionValuesRaw, 'field_value', 'field_name');
2016-01-17 02:08:08 +00:00
2016-01-17 01:58:31 +00:00
// Check if anything was returned
if (!$optionFields || !$optionValues) {
return $options;
}
2015-08-21 22:07:45 +00:00
2016-01-17 01:58:31 +00:00
// Check if option fields aren't fake
foreach ($optionFields as $field) {
2015-08-21 22:07:45 +00:00
// Check if the user has the current field set otherwise continue
if (!array_key_exists($field->option_id, $optionValues)) {
2015-08-21 22:07:45 +00:00
continue;
}
// Make sure the user has the proper permissions to use this option
if (!$this->permission(constant('Sakura\Perms\Site::' . $field->option_permission))) {
2015-08-21 22:07:45 +00:00
continue;
}
// Assign field to output with value
$options[$field->option_id] = $optionValues[$field->option_id];
2015-08-21 22:07:45 +00:00
}
2016-01-17 02:08:08 +00:00
2016-01-17 01:58:31 +00:00
// Assign cache
$this->optionFields = $options;
2016-01-17 02:08:08 +00:00
2016-01-17 01:58:31 +00:00
// Return appropiate option data
2015-08-21 22:07:45 +00:00
return $options;
}
2016-03-27 21:18:57 +00:00
/**
* Add premium in seconds.
*
* @param int $seconds The amount of seconds.
*
* @return int The new expiry date.
*/
public function addPremium($seconds)
{
// Check if there's already a record of premium for this user in the database
$getUser = DB::table('premium')
->where('user_id', $this->id)
->get();
// Calculate the (new) start and expiration timestamp
$start = $getUser ? $getUser[0]->premium_start : time();
$expire = $getUser ? $getUser[0]->premium_expire + $seconds : time() + $seconds;
// If the user already exists do an update call, otherwise an insert call
if ($getUser) {
DB::table('premium')
->where('user_id', $this->id)
->update([
'premium_expire' => $expire,
]);
} else {
DB::table('premium')
->insert([
'user_id' => $this->id,
'premium_start' => $start,
'premium_expire' => $expire,
]);
}
// Return the expiration timestamp
return $expire;
}
2016-02-02 21:04:15 +00:00
/**
* Does this user have premium?
2016-03-08 23:07:58 +00:00
*
2016-03-27 21:18:57 +00:00
* @return int Returns the premium expiration date.
2016-02-02 21:04:15 +00:00
*/
public function isPremium()
{
2016-03-27 21:18:57 +00:00
// Get rank IDs from the db
$premiumRank = (int) Config::get('premium_rank_id');
$defaultRank = (int) Config::get('default_rank_id');
// Fetch expiration date
$expire = $this->premiumInfo()->expire;
2015-08-19 12:13:38 +00:00
// Check if the user has static premium
2016-03-27 21:18:57 +00:00
if (!$expire
&& $this->permission(Site::STATIC_PREMIUM)) {
$expire = time() + 1;
2015-08-19 12:13:38 +00:00
}
2016-03-27 21:18:57 +00:00
// Check if the user has premium and isn't in the premium rank
if ($expire
&& !$this->hasRanks([$premiumRank])) {
// Add the premium rank
$this->addRanks([$premiumRank]);
// Set it as default
if ($this->mainRankId == $defaultRank) {
$this->setMainRank($premiumRank);
}
} elseif (!$expire
&& $this->hasRanks([$premiumRank])) {
$this->removeRanks([$premiumRank]);
if ($this->mainRankId == $premiumRank) {
$this->setMainRank($defaultRank);
}
}
return $expire;
}
public function premiumInfo()
{
2015-08-19 12:13:38 +00:00
// Attempt to retrieve the premium record from the database
2016-03-27 21:18:57 +00:00
$check = DB::table('premium')
->where('user_id', $this->id)
2016-03-27 21:18:57 +00:00
->where('premium_expire', '>', time())
->get();
2015-08-19 12:13:38 +00:00
2016-03-27 21:18:57 +00:00
$return = new stdClass;
2016-03-27 21:18:57 +00:00
$return->start = $check ? $check[0]->premium_start : 0;
$return->expire = $check ? $check[0]->premium_expire : 0;
2015-08-19 12:13:38 +00:00
2016-03-27 21:18:57 +00:00
return $return;
2015-08-19 12:13:38 +00:00
}
2016-02-02 21:04:15 +00:00
/**
* Get the open warnings on this user.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array The warnings.
*/
public function getWarnings()
{
2015-08-19 12:13:38 +00:00
// Do the database query
$getWarnings = DB::table('warnings')
->where('user_id', $this->id)
->get();
2015-08-19 12:13:38 +00:00
// Storage array
$warnings = [];
// Add special stuff
foreach ($getWarnings as $warning) {
// Check if it hasn't expired
if ($warning->warning_expires < time()) {
DB::table('warnings')
->where('warning_id', $warning['warning_id'])
->delete();
continue;
}
// Text action
switch ($warning->warning_action) {
default:
case '0':
$warning->warning_action_text = 'Warning';
break;
case '1':
$warning->warning_action_text = 'Silence';
break;
case '2':
$warning->warning_action_text = 'Restriction';
break;
case '3':
$warning->warning_action_text = 'Ban';
break;
case '4':
$warning->warning_action_text = 'Abyss';
break;
}
// Text expiration
$warning->warning_length = round(($warning->warning_expires - $warning->warning_issued) / 60);
// Add to array
$warnings[$warning->warning_id] = $warning;
}
2015-08-19 12:13:38 +00:00
// Return all the warnings
return $warnings;
}
2016-02-02 21:04:15 +00:00
/**
* Parse the user's userpage.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return string The parsed page.
*/
public function userPage()
{
2016-01-20 23:06:21 +00:00
return BBcode::toHTML(htmlentities($this->page));
}
2016-02-02 21:04:15 +00:00
/**
* Parse a user's signature
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return string The parsed signature.
*/
public function signature()
{
2016-01-20 23:06:21 +00:00
return BBcode::toHTML(htmlentities($this->signature));
}
2016-02-02 21:04:15 +00:00
/**
* Get a user's username history.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array The history.
*/
public function getUsernameHistory()
{
return DB::table('username_history')
->where('user_id', $this->id)
->orderBy('change_id', 'desc')
->get();
}
2016-02-02 21:04:15 +00:00
/**
* Alter the user's username
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param string $username The new username.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array Status indicator.
*/
public function setUsername($username)
{
// Create a cleaned version
2016-01-17 01:58:31 +00:00
$username_clean = Utils::cleanString($username, true);
// Check if the username is too short
2015-12-04 14:19:10 +00:00
if (strlen($username_clean) < Config::get('username_min_length')) {
return [0, 'TOO_SHORT'];
}
// Check if the username is too long
2015-12-04 14:19:10 +00:00
if (strlen($username_clean) > Config::get('username_max_length')) {
return [0, 'TOO_LONG'];
}
// Check if this username hasn't been used in the last amount of days set in the config
$getOld = DB::table('username_history')
->where('username_old_clean', $username_clean)
->where('change_time', '>', (Config::get('old_username_reserve') * 24 * 60 * 60))
->orderBy('change_id', 'desc')
->get();
// Check if anything was returned
if ($getOld && $getOld[0]->user_id != $this->id) {
return [0, 'TOO_RECENT', $getOld[0]['change_time']];
}
// Check if the username is already in use
$getInUse = DB::table('users')
->where('username_clean', $username_clean)
->get();
// Check if anything was returned
if ($getInUse) {
return [0, 'IN_USE', $getInUse[0]->user_id];
}
// Insert into username_history table
DB::table('username_history')
->insert([
'change_time' => time(),
'user_id' => $this->id,
2016-03-26 18:03:35 +00:00
'username_new' => $username,
'username_new_clean' => $username_clean,
'username_old' => $this->username,
'username_old_clean' => $this->usernameClean,
]);
// Update userrow
DB::table('users')
->where('user_id', $this->id)
->update([
'username' => $username,
'username_clean' => $username_clean,
]);
// Return success
return [1, 'SUCCESS', $username];
}
2016-02-02 21:04:15 +00:00
/**
* Alter a user's e-mail address
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param string $email The new e-mail address.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array Status indicator.
*/
public function setEMailAddress($email)
{
// Validate e-mail address
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return [0, 'INVALID'];
}
// Check if the username is already in use
$getInUse = DB::table('users')
->where('email', $email)
->get();
// Check if anything was returned
if ($getInUse) {
return [0, 'IN_USE', $getInUse[0]->user_id];
}
// Update userrow
DB::table('users')
->where('user_id', $this->id)
->update([
'email' => $email,
]);
// Return success
return [1, 'SUCCESS', $email];
}
2016-02-02 21:04:15 +00:00
/**
* Change the user's password
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @param string $old The old password.
* @param string $new The new password
* @param string $confirm The new one again.
2016-03-08 23:07:58 +00:00
*
2016-02-02 21:04:15 +00:00
* @return array Status indicator.
*/
public function setPassword($old, $new, $confirm)
{
// Validate password
2016-01-17 01:58:31 +00:00
switch ($this->passwordAlgo) {
// Disabled account
case 'disabled':
return [0, 'NO_LOGIN'];
// Default hashing method
default:
if (!Hashing::validatePassword($old, [
2016-01-17 01:58:31 +00:00
$this->passwordAlgo,
$this->passwordIter,
$this->passwordSalt,
$this->passwordHash,
])) {
2016-01-17 01:58:31 +00:00
return [0, 'INCORRECT_PASSWORD', $this->passwordChan];
}
}
// Check password entropy
2016-01-17 01:58:31 +00:00
if (Utils::pwdEntropy($new) < Config::get('min_entropy')) {
return [0, 'PASS_TOO_SHIT'];
}
// Passwords do not match
if ($new != $confirm) {
return [0, 'PASS_NOT_MATCH'];
}
// Create hash
$password = Hashing::createHash($new);
// Update userrow
DB::table('users')
->where('user_id', $this->id)
->update([
'password_hash' => $password[3],
'password_salt' => $password[2],
'password_algo' => $password[0],
'password_iter' => $password[1],
'password_chan' => time(),
]);
// Return success
return [1, 'SUCCESS'];
}
2016-03-26 16:36:58 +00:00
/**
* Get all the notifications for this user.
*
* @param int $timeDifference The timeframe of alerts that should be fetched.
* @param bool $excludeRead Whether alerts that are marked as read should be included.
*
* @return array An array with Notification objects.
*/
public function notifications($timeDifference = 0, $excludeRead = true)
{
$alertIds = DB::table('notifications')
->where('user_id', $this->id);
if ($timeDifference) {
$alertIds->where('alert_timestamp', '>', time() - $timeDifference);
}
if ($excludeRead) {
$alertIds->where('alert_read', 0);
}
$alertIds = array_column($alertIds->get(['alert_id']), 'alert_id');
$alerts = [];
foreach ($alertIds as $alertId) {
$alerts[$alertId] = new Notification($alertId);
}
return $alerts;
}
2015-08-18 23:29:45 +00:00
}