r20160219

This commit is contained in:
Pachira 2016-02-19 00:28:44 +01:00
parent bbfd22d14d
commit 7c83d5c78d
29 changed files with 1103 additions and 1340 deletions

View file

@ -24,23 +24,25 @@ define('SAKURA_CRON', true);
require_once 'sakura.php';
// Clean expired sessions
Database::delete('sessions', [
'session_expire' => [time(), '<'],
'session_remember' => ['1', '!='],
$cleanSessions = DB::prepare('DELETE FROM `{prefix}sessions` WHERE `session_expire` < :time AND `session_remember` != 1');
$cleanSessions->execute([
'time' => time(),
]);
// Delete notifications that are older than a month but not unread
Database::delete('notifications', [
'alert_timestamp' => [(time() - 109500), '<'],
'alert_read' => ['1', '='],
$cleanAlerts = DB::prepare('DELETE FROM `{prefix}notifications` WHERE `alert_timestamp` < :time AND `alert_read` = 1');
$cleanAlerts->execute([
'time' => (time() - 109500),
]);
// Get expired premium accounts
$expiredPremium = Database::fetch('premium', true, [
'premium_expire' => [time(), '<'],
$expiredPremium = DB::prepare('SELECT * FROM `{prefix}premium` WHERE `premium_expire` < :time');
$expiredPremium->execute([
'time' => time(),
]);
$expiredPremium = $expiredPremium->fetchAll();
// Process expired premium accounts, make this not stupid in the future
foreach ($expiredPremium as $expired) {
Users::updatePremiumMeta($expired['user_id']);
Users::updatePremiumMeta($expired->user_id);
}

View file

@ -29,10 +29,11 @@ class ActionCode
$code = uniqid();
// Insert it
Database::insert('actioncodes', [
'code_action' => $action,
'user_id' => $user,
'action_code' => $code,
DB::prepare('INSERT INTO `{prefix}actioncodes` (`code_action`, `user_id`, `action_code`) VALUES (:action, :id, :code)')
->execute([
'action' => $action,
'id' => $user,
'code' => $code,
]);
// Return the code
@ -52,11 +53,13 @@ class ActionCode
public static function validate($action, $code, $user = 0, $invalidate = true)
{
// Fetch the code from the db
$get = Database::count('actioncodes', [
'code_action' => [$action, '='],
'action_code' => [$code, '='],
'user_id' => [$user, '='],
$get = DB::prepare('SELECT * FROM `{prefix}actioncodes` WHERE `code_action` = :code AND `action_code` = :action AND `user_id` = :id');
$get->execute([
'code' => $action,
'action' => $code,
'id' => $user,
]);
$get = $get->rowCount();
// Invalidate the code if requested
if ($invalidate) {
@ -64,7 +67,7 @@ class ActionCode
}
// Return the result
return $get[0] > 0;
return $get > 0;
}
/**
@ -74,8 +77,9 @@ class ActionCode
*/
public static function invalidate($code)
{
Database::delete('actioncodes', [
'code_action' => [$code, '='],
DB::prepare('DELETE FROM `{prefix}actioncodes` WHERE `code_action` = :code')
->execute([
'code' => $code,
]);
}
}

View file

@ -48,12 +48,14 @@ class BBcode
public static function parseEmoticons($text)
{
// Get emoticons from the database
$emotes = Database::fetch('emoticons');
$emotes = DB::prepare('SELECT * FROM `{prefix}emoticons`');
$emotes->execute();
$emotes = $emotes->fetchAll();
// Parse all emoticons
foreach ($emotes as $emote) {
$image = "<img src='{$emote['emote_path']}' alt='{$emote['emote_string']}' class='emoticon' />";
$icon = preg_quote($emote['emote_string'], '#');
$image = "<img src='{$emote->emote_path}' alt='{$emote->emote_string}' class='emoticon' />";
$icon = preg_quote($emote->emote_string, '#');
$text = preg_replace("#$icon#", $image, $text);
}

View file

@ -26,7 +26,11 @@ class Bans
{
// Attempt to get a ban from this user
$bans = Database::fetch('bans', true, ['user_id' => [$uid, '=']]);
$bans = DB::prepare('SELECT * FROM `{prefix}bans` WHERE `user_id` = :id');
$bans->execute([
'id' => $uid,
]);
$bans = $bans->fetchAll();
// Reverse the array so new bans are listed first
$bans = array_reverse($bans);
@ -34,21 +38,22 @@ class Bans
// Go over each ban
foreach ($bans as $ban) {
// Check if it hasn't expired
if ($ban['ban_end'] != 0 && $ban['ban_end'] < time()) {
if ($ban->ban_end != 0 && $ban->ban_end < time()) {
// If it has delete the entry and continue
Database::delete('bans', ['id' => [$ban['user_id'], '=']]);
DB::prepare('DELETE FROM `{prefix}bans` WHERE `ban_id` = :id')
->execute([
'id' => $ban->user_id,
]);
continue;
}
// Return the ban if all checks were passed
return [
'user' => $ban['user_id'],
'issuer' => $ban['ban_moderator'],
'issued' => $ban['ban_begin'],
'expires' => $ban['ban_end'],
'reason' => $ban['ban_reason'],
'user' => $ban->user_id,
'issuer' => $ban->ban_moderator,
'issued' => $ban->ban_begin,
'expires' => $ban->ban_end,
'reason' => $ban->ban_reason,
];
}

View file

@ -9,6 +9,7 @@ namespace Sakura;
/**
* Handles and serves comments on pages.
* Needs a reimplementation.
*
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
@ -46,15 +47,11 @@ class Comments
$this->category = $category;
// Get the comments and assign them to $comments
$comments = Database::fetch(
'comments',
true,
[
'comment_category' => [$this->category, '='],
'comment_reply_to' => ['0', '='],
],
['comment_id', true]
);
$comments = DB::prepare('SELECT * FROM `{prefix}comments` WHERE `comment_category` = :category AND `comment_reply_to` = 0 ORDER BY `comment_id` DESC');
$comments->execute([
'category' => $this->category,
]);
$comments = $comments->fetchAll(\PDO::FETCH_ASSOC);
// Feed them into the sorter
$this->comments = $this->sortComments($comments);
@ -99,10 +96,12 @@ class Comments
$this->count += 1;
// Attempt to get replies from the database
$replies = Database::fetch('comments', true, [
'comment_category' => [$this->category, '='],
'comment_reply_to' => [$comment['comment_id'], '='],
$replies = DB::prepare('SELECT * FROM `{prefix}comments` WHERE `comment_category` = :category AND `comment_reply_to` = :thread');
$replies->execute([
'category' => $this->category,
'thread' => $comment['comment_id'],
]);
$replies = $replies->fetchAll(\PDO::FETCH_ASSOC);
// Check if this was a reply to something
if ($replies) {
@ -124,9 +123,11 @@ class Comments
public function getComment($cid)
{
// Get from database
return Database::fetch('comments', false, [
'comment_id' => [$cid, '='],
$comment = DB::prepare('SELECT * FROM `{prefix}comments` WHERE `comment_id` = :id');
$comment->execute([
'id' => $cid,
]);
return $comment->fetch(\PDO::FETCH_ASSOC);
}
/**
@ -139,9 +140,11 @@ class Comments
public function getVotes($cid)
{
// Get from database
return Database::fetch('comment_votes', true, [
'vote_comment' => [$cid, '='],
$comment = DB::prepare('SELECT * FROM `{prefix}comment_votes` WHERE `vote_comment` = :id');
$comment->execute([
'id' => $cid,
]);
return $comment->fetchAll(\PDO::FETCH_ASSOC);
}
/**
@ -166,12 +169,13 @@ class Comments
}
// Insert into database
Database::insert('comments', [
'comment_category' => $this->category,
'comment_timestamp' => time(),
'comment_poster' => $uid,
'comment_reply_to' => (int) $reply,
'comment_text' => $content,
DB::prepare('INSERT INTO `{prefix}comments` (`comment_category`, `comment_timestamp`, `comment_poster`, `comment_reply_to`, `comment_text`) VALUES (:cat, :time, :user, :thread, :text)')
->execute([
'cat' => $this->category,
'time' => time(),
'user' => $uid,
'thread' => (int) $reply,
'text' => $content,
]);
// Return success
@ -190,38 +194,39 @@ class Comments
public function makeVote($uid, $cid, $mode)
{
// Attempt to get previous vote
$vote = Database::fetch('comment_votes', false, [
'vote_user' => [$uid, '='],
'vote_comment' => [$cid, '='],
$vote = DB::prepare('SELECT * FROM `{prefix}comment_votes` WHERE `vote_user` = :user AND `vote_comment` = :comment');
$vote->execute([
'user' => $uid,
'comment' => $cid,
]);
$vote = $vote->fetch(\PDO::FETCH_ASSOC);
// Check if anything was returned
if ($vote) {
// Check if the vote that's being casted is the same
if ($vote['vote_state'] == $mode) {
// Delete the vote
Database::delete('comment_votes', [
'vote_user' => [$uid, '='],
'vote_comment' => [$cid, '='],
DB::prepare('DELETE FROM `{prefix}comment_votes` WHERE `vote_user` = :user AND `vote_comment` = :comment')
->execute([
'user' => $uid,
'comment' => $cid,
]);
} else {
// Otherwise update the vote
Database::update('comment_votes', [
[
'vote_state' => $mode,
],
[
'vote_user' => [$uid, '='],
'vote_comment' => [$cid, '='],
],
DB::prepare('UPDATE `{prefix}comment_votes` SET `vote_state` = :state WHERE `vote_user` = :user AND `vote_comment` = :comment')
->execute([
'state' => $mode,
'user' => $uid,
'comment' => $cid,
]);
}
} else {
// Create a vote
Database::insert('comment_votes', [
'vote_user' => $uid,
'vote_comment' => $cid,
'vote_state' => $mode,
DB::prepare('INSERT INTO `{prefix}comment_votes` (`vote_user`, `vote_comment`, `vote_state`) VALUES (:user, :comment, :state)')
->execute([
'user' => $uid,
'comment' => $cid,
'state' => $mode,
]);
}
@ -232,14 +237,13 @@ class Comments
* Remove a comment
*
* @param int $cid ID of the comment to remove.
*
* @return mixed No idea what this returns but it doesn't really matter anyway, the comment is dead.
*/
public function removeComment($cid)
{
// Remove from database
return Database::delete('comments', [
'comment_id' => [$cid, '='],
DB::prepare('DELETE FROM `{prefix}comments` WHERE `comment_id` = :id')
->execute([
'id' => $cid,
]);
}
}

View file

@ -63,7 +63,7 @@ class Config
* @param string $key Configuration section.
* @param string $subkey Configuration key.
*
* @return string Configuration value.
* @return array|string Configuration value.
*/
public static function local($key, $subkey = null)
{
@ -101,9 +101,13 @@ class Config
// Then return the value
return self::$database[$key];
} else {
$value = Database::fetch('config', false, ['config_name' => [$key, '=']]);
$value = DB::prepare('SELECT * FROM `{prefix}config` WHERE `config_name` = :name');
$value->execute([
'name' => $key,
]);
$value = $value->fetch();
if ($value) {
self::$database[$key] = $value['config_value'];
self::$database[$key] = $value->config_value;
return self::$database[$key];
}
}
@ -115,4 +119,34 @@ class Config
);
return null;
}
public static function set($key, $value)
{
// Unset the cached copy
if (array_key_exists($key, self::$database)) {
unset(self::$database[$key]);
}
// Check if the value already exists
$exists = DB::prepare('SELECT * FROM `{prefix}config` WHERE `config_name` = :name');
$exists->execute([
'name' => $key,
]);
// If it exists run an update
if ($exists->rowCount()) {
$set = DB::prepare('UPDATE `{prefix}config` SET `config_value` = :value WHERE `config_name` = :name');
} else {
$set = DB::prepare('INSERT INTO `{prefix}config` (`config_name`, `config_value`) VALUES (:name, :value)');
}
// Run the setter
$set->execute([
'name' => $key,
'value' => $value,
]);
// Return the value
return $value;
}
}

View file

@ -9,6 +9,7 @@ namespace Sakura\Controllers;
use Sakura\Config;
use Sakura\Database;
use Sakura\DB;
use Sakura\Forum;
use Sakura\Perms\Forum as ForumPerms;
use Sakura\Template;
@ -31,18 +32,25 @@ class Forums extends Controller
*/
public function index()
{
$userCount = DB::prepare("SELECT * FROM `{prefix}users` WHERE `password_algo` != 'disabled' AND `rank_main` != 1");
$userCount->execute();
$threadCount = DB::prepare('SELECT * FROM `{prefix}topics`');
$threadCount->execute();
$postCount = DB::prepare('SELECT * FROM `{prefix}posts`');
$postCount->execute();
// Merge index specific stuff with the global render data
Template::vars([
'forum' => (new Forum\Forum()),
'stats' => [
'userCount' => Database::count('users', ['password_algo' => ['nologin', '!='], 'rank_main' => ['1', '!=']])[0],
'userCount' => $userCount->rowCount(),
'newestUser' => User::construct(Users::getNewestUserId()),
'lastRegData' => date_diff(
date_create(date('Y-m-d', User::construct(Users::getNewestUserId())->registered)),
date_create(date('Y-m-d'))
)->format('%a'),
'topicCount' => Database::count('topics')[0],
'postCount' => Database::count('posts')[0],
'topicCount' => $threadCount->rowCount(),
'postCount' => $postCount->rowCount(),
'onlineUsers' => Users::checkAllOnline(),
],
]);

View file

@ -9,6 +9,7 @@ namespace Sakura\Controllers;
use Sakura\Config;
use Sakura\Database;
use Sakura\DB;
use Sakura\News;
use Sakura\Template;
use Sakura\User;
@ -30,19 +31,26 @@ class Meta extends Controller
*/
public function index()
{
$userCount = DB::prepare("SELECT * FROM `{prefix}users` WHERE `password_algo` != 'disabled' AND `rank_main` != 1");
$userCount->execute();
$threadCount = DB::prepare('SELECT * FROM `{prefix}topics`');
$threadCount->execute();
$postCount = DB::prepare('SELECT * FROM `{prefix}posts`');
$postCount->execute();
// Merge index specific stuff with the global render data
Template::vars([
'news' => new News(Config::get('site_news_category')),
'newsCount' => Config::get('front_page_news_posts'),
'stats' => [
'userCount' => Database::count('users', ['password_algo' => ['nologin', '!='], 'rank_main' => ['1', '!=']])[0],
'userCount' => $userCount->rowCount(),
'newestUser' => User::construct(Users::getNewestUserId()),
'lastRegDate' => date_diff(
date_create(date('Y-m-d', User::construct(Users::getNewestUserId())->registered)),
date_create(date('Y-m-d'))
)->format('%a'),
'topicCount' => Database::count('topics')[0],
'postCount' => Database::count('posts')[0],
'topicCount' => $threadCount->rowCount(),
'postCount' => $postCount->rowCount(),
'onlineUsers' => Users::checkAllOnline(),
],
]);
@ -87,11 +95,16 @@ class Meta extends Controller
*/
public function faq()
{
// Get faq entries
$faq = DB::prepare('SELECT * FROM `{prefix}faq` ORDER BY `faq_id`');
$faq->execute();
$faq = $faq->fetchAll();
// Set parse variables
Template::vars([
'page' => [
'title' => 'Frequently Asked Questions',
'questions' => Database::fetch('faq', true, null, ['faq_id']),
'questions' => $faq,
],
]);
@ -109,25 +122,33 @@ class Meta extends Controller
public function infoPage($id = null)
{
// Set default variables
$renderData['page'] = [
'content' => '<h1>Unable to load the requested info page.</h1><p>Check the URL and try again.</p>',
];
Template::vars([
'page' => [
'content' => '<h1>Unable to load the requested info page.</h1><p>Check the URL and try again.</p>',
],
]);
// Set page id
$id = strtolower($id);
// Get info page data from the database
if ($ipData = Database::fetch('infopages', false, ['page_shorthand' => [$id, '=']])) {
// Assign new proper variable
$renderData['page'] = [
'id' => $id,
'title' => $ipData['page_title'],
'content' => $ipData['page_content'],
];
}
// Get the page from the database
$ipData = DB::prepare('SELECT * FROM `{prefix}infopages` WHERE `page_shorthand` = :id');
$ipData->execute([
'id' => $id,
]);
$ipData = $ipData->fetch();
// Set parse variables
Template::vars($renderData);
// Get info page data from the database
if ($ipData) {
// Assign new proper variable
Template::vars([
'page' => [
'id' => $id,
'title' => $ipData->page_title,
'content' => $ipData->page_content,
],
]);
}
// Return the compiled page
return Template::render('main/infopage');

View file

@ -103,6 +103,7 @@ class Premium extends Controller
// Attempt to complete the transaction
if ($finalise) {
// Make the user premium
Users::addUserPremium($currentUser->id, (2628000 * $_SESSION['premiumMonths']));
Users::updatePremiumMeta($currentUser->id);
Utils::updatePremiumTracker(
$currentUser->id,

View file

@ -9,6 +9,7 @@ namespace Sakura\Controllers;
use Sakura\Config;
use Sakura\Database;
use Sakura\DB;
use Sakura\Rank;
use Sakura\Template;
use Sakura\User as UserContext;
@ -39,13 +40,19 @@ class User extends Controller
// If the user id is zero check if there was a namechange
if ($profile->id == 0) {
// Fetch from username_history
$check = Database::fetch('username_history', false, ['username_old_clean' => [Utils::cleanString(isset($_GET['u']) ? $_GET['u'] : 0, true, true), '=']]);
$check = DB::prepare('SELECT `user_id` FROM `{prefix}username_history` WHERE `username_old_clean` = :uname ORDER BY `change_id` DESC');
$check->execute([
'uname' => Utils::cleanString($id, true, true),
]);
$check = $check->fetch();
// Redirect if so
if ($check) {
Template::vars([
'message' => 'The user this profile belongs to changed their username, you are being redirected.',
'redirect' => (new \Sakura\Urls)->format('USER_PROFILE', [$check['user_id']]),
'page' => [
'message' => 'The user this profile belongs to changed their username, you are being redirected.',
'redirect' => (new \Sakura\Urls)->format('USER_PROFILE', [$check->user_id]),
],
]);
// Print page contents

112
libraries/DB.php Normal file
View file

@ -0,0 +1,112 @@
<?php
/**
* Holds the database wrapper (v2).
*
* @package Sakura
*/
namespace Sakura;
use PDO;
use PDOException;
use PDOStatement;
/**
* A wrapper to make the database communication experience smoother.
*
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
class DB
{
/**
* The container for the PDO object.
*
* @var PDO
*/
public static $db = null;
/**
* The table prefix
*
* @var string
*/
public static $prefix = '';
/**
* Open the SQL connection and creates a PDO object.
*
* @param string $server A PDO driver.
* @param array $dsnParts An array consisting out of DSN string parts.
* @param string $username The username used to authenticate with the SQL server.
* @param string $password The password for the same purpose.
* @param array $options Additional PDO options.
*/
public static function open($server, $dsnParts, $username = null, $password = null, $prefix = '', $options = [])
{
// Check if the selected driver is available
if (!in_array($server, PDO::getAvailableDrivers())) {
trigger_error('A driver for the selected SQL server wasn\'t found!', E_USER_ERROR);
return;
}
// Set the table prefix
self::$prefix = $prefix;
// Create start of the DSN
$dsn = "{$server}:";
// Append the parts
foreach ($dsnParts as $name => $value) {
$dsn .= "{$name}={$value};";
}
try {
// Connect to SQL server using PDO
self::$db = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
// Catch connection errors
trigger_error($e->getMessage(), E_USER_ERROR);
}
self::$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
self::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
}
/**
* Closes the PDO object.
*/
public static function close()
{
self::$db = null;
}
/**
* Get the id of the item that was last inserted into the database.
*
* @param string $name Sequence of which the last id should be returned.
*
* @return string The last inserted id.
*/
public static function lastID($name = null)
{
return self::$db->lastInsertID($name);
}
/**
* Prepares a statement for execution and returns a statement object.
*
* @param string $stmt The statement to prepare.
* @param array $opts Statement specific driver options.
*
* @return PDOStatement
*/
public static function prepare($stmt, $opts = [])
{
// Replace the table prefix
$stmt = str_replace('{prefix}', self::$prefix, $stmt);
return self::$db->prepare($stmt, $opts);
}
}

View file

@ -1,478 +0,0 @@
<?php
/**
* Holds the MySQL/PDO wrapper.
*
* @package Sakura
*/
namespace Sakura\DBWrapper;
use PDO;
use PDOException;
use PDOStatement;
use \Sakura\Config;
/**
* Sakura MySQL Wrapper.
*
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
class mysql
{
/**
* Contains the PDO object.
*
* @var PDO
*/
protected $sql;
/**
* Constructor.
*/
public function __construct()
{
if (!extension_loaded('PDO')) {
// Return error and die
trigger_error('PDO extension not loaded.', E_USER_ERROR);
}
// Initialise connection
$this->initConnect(
(
Config::local('database', 'unixsocket') ?
$this->prepareSock(
Config::local('database', 'host'),
Config::local('database', 'database')
) :
$this->prepareHost(
Config::local('database', 'host'),
Config::local('database', 'database'),
(
Config::local('database', 'port') !== null ?
Config::local('database', 'port') :
3306
)
)
),
Config::local('database', 'username'),
Config::local('database', 'password')
);
}
/**
* Generates a DSN for a regular hostname:port endpoint.
*
* @param string $dbHost Database hostname.
* @param string $dbName Database name.
* @param int $dbPort Database host port.
*
* @return string The PDO DSN.
*/
private function prepareHost($dbHost, $dbName, $dbPort = 3306)
{
$dsn = 'mysql:host=' . $dbHost . ';port=' . $dbPort . ';dbname=' . $dbName;
return $dsn;
}
/**
* Generates a DSN for a unix socket endpoint.
*
* @param string $dbHost Path to the Unix Socket.
* @param string $dbName Database name.
*
* @return string The PDO DSN.
*/
private function prepareSock($dbHost, $dbName)
{
$dsn = 'mysql:unix_socket=' . $dbHost . ';dbname=' . $dbName;
return $dsn;
}
/**
* Initialise a the database connection.
*
* @param string $dsn The PDO DSN.
* @param string $dbUname The database username.
* @param string $dbPword The database password.
*
* @return bool Returns true if the connection was successful.
*/
private function initConnect($dsn, $dbUname, $dbPword)
{
try {
// Connect to SQL server using PDO
$this->sql = new PDO($dsn, $dbUname, $dbPword, [
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING,
]);
} catch (PDOException $e) {
// Catch connection errors
trigger_error('SQL Driver: ' . $e->getMessage(), E_USER_ERROR);
}
return true;
}
/**
* Select table row(s).
*
* @param string $table The table to select data from.
* @param array $data The WHERE selectors.
* @param array $order The order in which the data is returned.
* @param array $limit The limit of what should be returned.
* @param array $group The way MySQL will group the data.
* @param bool $distinct Only return distinct values.
* @param string $column Only select from this column.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return PDOStatement The PDOStatement object for this action.
*/
public function select($table, $data = null, $order = null, $limit = null, $group = null, $distinct = false, $column = '*', $prefix = null)
{
// Begin preparation of the statement
$prepare = 'SELECT ' . ($distinct ? 'DISTINCT ' : '') . ($column == '*' ? '' : '`') . $column . ($column == '*' ? '' : '`') . ' FROM `' . ($prefix ? $prefix : Config::local('database', 'prefix')) . $table . '`';
// If $data is set and is an array continue
if (is_array($data)) {
$prepare .= ' WHERE';
foreach ($data as $key => $value) {
// Check if there's multiple statements
if (!is_array($value[0])) {
$temp = $value;
unset($value);
$value[0] = $temp;
}
// Go over each data thing
foreach ($value as $sub => $val) {
$prepare .= ' `' . $key . '` ' . $val[1] . ' :' . $key . '_' . $sub . ($key == key(array_slice($data, -1, 1, true)) && $sub == key(array_slice($value, -1, 1, true)) ? '' : ' ' . (isset($val[2]) && $val[2] ? 'OR' : 'AND'));
unset($sub);
unset($val);
}
// Unset variables to be safe
unset($key);
unset($value);
}
}
// If $group is set and is an array continue
if (is_array($group)) {
$prepare .= ' GROUP BY';
foreach ($group as $key => $value) {
$prepare .= ' `' . $value . '`' . ($key == key(array_slice($group, -1, 1, true)) ? '' : ',');
// Unset variables to be safe
unset($key);
unset($value);
}
}
// If $order is set and is an array continue
if (is_array($order)) {
$prepare .= ' ORDER BY `' . $order[0] . '`' . (!empty($order[1]) && $order[1] ? ' DESC' : '');
}
// If $limit is set and is an array continue
if (is_array($limit)) {
$prepare .= ' LIMIT';
foreach ($limit as $key => $value) {
$prepare .= ' ' . $value . ($key == key(array_slice($limit, -1, 1, true)) ? '' : ',');
// Unset variables to be safe
unset($key);
unset($value);
}
}
// Add the finishing semicolon
$prepare .= ';';
// Actually prepare the preration
$query = $this->sql->prepare($prepare);
// Bind those parameters if $data is an array that is
if (is_array($data)) {
foreach ($data as $key => $value) {
// Check if there's multiple statements
if (!is_array($value[0])) {
$temp = $value;
unset($value);
$value[0] = $temp;
}
// Go over each data thing
foreach ($value as $sub => $val) {
$query->bindParam(':' . $key . '_' . $sub, $val[0]);
unset($sub);
unset($val);
}
// Unset variables to be safe
unset($key);
unset($value);
}
}
// Execute the prepared statements with parameters bound
$query->execute();
// Return the query
return $query;
}
/**
* Summary of fetch
*
* @param string $table The table to select data from.
* @param bool $fetchAll Whether all result will be returned or just the first one.
* @param array $data The WHERE selectors.
* @param array $order The order in which the data is returned.
* @param array $limit The limit of what should be returned.
* @param array $group The way MySQL will group the data.
* @param bool $distinct Only return distinct values.
* @param string $column Only select from this column.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return array The data the database returned.
*/
public function fetch($table, $fetchAll = true, $data = null, $order = null, $limit = null, $group = null, $distinct = false, $column = '*', $prefix = null)
{
// Run a select statement
$query = $this->select($table, $data, $order, $limit, $group, $distinct, $column, $prefix);
// Return the output
return $fetchAll ? $query->fetchAll(PDO::FETCH_ASSOC) : $query->fetch(PDO::FETCH_ASSOC);
}
/**
* Insert data into the database.
*
* @param string $table The table that the data will be inserted into.
* @param array $data The data that should be stored.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return bool Successfulness.
*/
public function insert($table, $data, $prefix = null)
{
// Begin preparation of the statement
$prepare = 'INSERT INTO `' . ($prefix ? $prefix : Config::local('database', 'prefix')) . $table . '` ';
// Run the foreach statement twice for (`stuff`) VALUES (:stuff)
for ($i = 0; $i < 2; $i++) {
$prepare .= '(';
// Do more shit, don't feel like describing this so yeah
foreach ($data as $key => $value) {
if (strlen($value)) {
$prepare .= ($i ? ':' : '`') . $key . ($i ? '' : '`') . ($key == key(array_slice($data, -1, 1, true)) ? '' : ', ');
}
}
$prepare .= ')' . ($i ? ';' : ' VALUES ');
}
// Actually prepare the preration
$query = $this->sql->prepare($prepare);
// Bind those parameters
foreach ($data as $key => $value) {
if (strlen($value)) {
$query->bindParam(':' . $key, $value);
}
// Unset variables to be safe
unset($key);
unset($value);
}
// Execute the prepared statements with parameters bound
$result = $query->execute();
// Return whatever can be returned
return $result;
}
/**
* Update existing database rows.
*
* @param string $table The table that the updated data will be inserted into.
* @param array $data The data that should be stored.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return bool Successfulness.
*/
public function update($table, $data, $prefix = null)
{
// Begin preparation of the statement
$prepare = 'UPDATE `' . ($prefix ? $prefix : Config::local('database', 'prefix')) . $table . '`';
// Run a foreach on $data and complete the statement
foreach ($data as $key => $values) {
// Append WHERE or SET depending on where we are
$prepare .= ' ' . ($key ? 'WHERE' : 'SET');
// Do this complicated shit, I barely know what's going on anymore but it works
foreach ($values as $column => $column_data) {
$prepare .= ' `' . $column . '` ' . ($key ? $column_data[1] : '=') . ' :' . ($key ? 'w' : 's') . '_' . $column . ($column == key(array_slice($values, -1, 1, true)) ? ($key ? ';' : '') : ($key ? ' ' . (isset($value[2]) && $value[2] ? 'OR' : 'AND') : ','));
}
}
// Actually prepare the preration
$query = $this->sql->prepare($prepare);
// Seperate the foreaches for the SET and WHERE clauses because it's fucking it up for some odd reason
// Bind Set Clauses
foreach ($data[0] as $key => $value) {
// Do the binding
$query->bindParam(':s_' . $key, $value);
// Unset variables to be safe
unset($key);
unset($value);
}
// Bind Where Clauses
foreach ($data[1] as $key => $values) {
// Assign the array entry to a variable because fuck strict standards
$value = $values[0];
// Binding two electrifying memes
$query->bindParam(':w_' . $key, $value);
// Unset variables to be safe
unset($key);
unset($value);
unset($values);
}
// Execute the prepared statements with parameters bound
$result = $query->execute();
// Return whatever can be returned
return $result;
}
/**
* Deleted data from the database.
*
* @param string $table The table that the data will be removed from.
* @param array $data The pointers to what should be deleted.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return bool Successfulness.
*/
public function delete($table, $data, $prefix = null)
{
// Begin preparation of the statement
$prepare = 'DELETE FROM `' . ($prefix ? $prefix : Config::local('database', 'prefix')) . $table . '`';
// If $data is set and is an array continue
if (is_array($data)) {
$prepare .= ' WHERE';
foreach ($data as $key => $value) {
$prepare .= ' `' . $key . '` ' . $value[1] . ' :' . $key . ($key == key(array_slice($data, -1, 1, true)) ? '' : ' ' . (isset($value[2]) && $value[2] ? 'OR' : 'AND'));
// Unset variables to be safe
unset($key);
unset($value);
}
}
// Actually prepare the preration
$query = $this->sql->prepare($prepare);
// Bind those parameters
foreach ($data as $key => $value) {
$query->bindParam(':' . $key, $value[0]);
// Unset variables to be safe
unset($key);
unset($value);
}
// Execute the prepared statements with parameters bound
$result = $query->execute();
// Return whatever can be returned
return $result;
}
/**
* Return the amount of rows from a table.
*
* @param string $table Table to count in.
* @param array $data Data that should be matched.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return array Array containing the SQL result.
*/
public function count($table, $data = null, $prefix = null)
{
// Begin preparation of the statement
$prepare = 'SELECT COUNT(*) FROM `' . ($prefix ? $prefix : Config::local('database', 'prefix')) . $table . '`';
// If $data is set and is an array continue
if (is_array($data)) {
$prepare .= ' WHERE';
foreach ($data as $key => $value) {
$prepare .= ' `' . $key . '` ' . $value[1] . ' :' . $key . ($key == key(array_slice($data, -1, 1, true)) ? '' : ' ' . (isset($value[2]) && $value[2] ? 'OR' : 'AND'));
// Unset variables to be safe
unset($key);
unset($value);
}
}
// Add the finishing semicolon
$prepare .= ';';
// Actually prepare the preration
$query = $this->sql->prepare($prepare);
// Bind those parameters if $data is an array that is
if (is_array($data)) {
foreach ($data as $key => $value) {
$query->bindParam(':' . $key, $value[0]);
// Unset variables to be safe
unset($key);
unset($value);
}
}
// Execute the prepared statements with parameters bound
$query->execute();
// Return the output
return $query->fetch(PDO::FETCH_BOTH);
}
/**
* Get the id of the item that was last inserted into the database.
*
* @param string $name Sequence of which the last id should be returned.
*
* @return string The last inserted id.
*/
public function lastInsertID($name = null)
{
return $this->sql->lastInsertID($name);
}
}

View file

@ -1,151 +0,0 @@
<?php
/**
* Holds the database wrapper interfacer.
*
* @package Sakura
*/
namespace Sakura;
/**
* A wrapper to make the database communication experience smoother.
*
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
class Database
{
/**
* The container for the wrapper.
*
* @var mixed
*/
public static $database;
/**
* Initialise the database wrapper.
*
* @param string $wrapper The wrapper to wrap.
*/
public static function init($wrapper)
{
// Make the wrapper class name lowercase
$wrapper = __NAMESPACE__ . '\DBWrapper\\' . strtolower($wrapper);
// Check if the class exists
if (!class_exists($wrapper)) {
trigger_error('Failed to load database wrapper', E_USER_ERROR);
}
// Initialise SQL wrapper
self::$database = new $wrapper;
}
/**
* Select table row(s).
*
* @param string $table The table to select data from.
* @param array $data The WHERE selectors.
* @param array $order The order in which the data is returned.
* @param array $limit The limit of what should be returned.
* @param array $group The way MySQL will group the data.
* @param bool $distinct Only return distinct values.
* @param string $column Only select from this column.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return \PDOStatement The PDOStatement object for this action.
*/
public static function select($table, $data = null, $order = null, $limit = null, $group = null, $distinct = false, $column = '*', $prefix = null)
{
return self::$database->select($table, $data, $order, $limit, $group, $distinct, $column, $prefix);
}
/**
* Summary of fetch
*
* @param string $table The table to select data from.
* @param bool $fetchAll Whether all result will be returned or just the first one.
* @param array $data The WHERE selectors.
* @param array $order The order in which the data is returned.
* @param array $limit The limit of what should be returned.
* @param array $group The way MySQL will group the data.
* @param bool $distinct Only return distinct values.
* @param string $column Only select from this column.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return array The data the database returned.
*/
public static function fetch($table, $fetchAll = true, $data = null, $order = null, $limit = null, $group = null, $distinct = false, $column = '*', $prefix = null)
{
return self::$database->fetch($table, $fetchAll, $data, $order, $limit, $group, $distinct, $column, $prefix);
}
/**
* Insert data into the database.
*
* @param string $table The table that the data will be inserted into.
* @param array $data The data that should be stored.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return bool Successfulness.
*/
public static function insert($table, $data, $prefix = null)
{
return self::$database->insert($table, $data, $prefix);
}
/**
* Update existing database rows.
*
* @param string $table The table that the updated data will be inserted into.
* @param array $data The data that should be stored.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return bool Successfulness.
*/
public static function update($table, $data, $prefix = null)
{
return self::$database->update($table, $data, $prefix);
}
/**
* Deleted data from the database.
*
* @param string $table The table that the data will be removed from.
* @param array $data The pointers to what should be deleted.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return bool Successfulness.
*/
public static function delete($table, $data, $prefix = null)
{
return self::$database->delete($table, $data, $prefix);
}
/**
* Return the amount of rows from a table.
*
* @param string $table Table to count in.
* @param array $data Data that should be matched.
* @param string $prefix Use a different table prefix than the one from the configuration.
*
* @return array Array containing the SQL result.
*/
public static function count($table, $data = null, $prefix = null)
{
return self::$database->count($table, $data, $prefix);
}
/**
* Get the id of the item that was last inserted into the database.
*
* @param string $name Sequence of which the last id should be returned.
*
* @return string The last inserted id.
*/
public static function lastInsertID($name = null)
{
return self::$database->lastInsertID($name);
}
}

View file

@ -81,17 +81,18 @@ class File
$mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($data);
// Insert it into the database
Database::insert('uploads', [
'user_id' => $user->id,
'file_data' => $data,
'file_name' => $name,
'file_mime' => $mime,
'file_time' => time(),
'file_expire' => $expire,
DB::prepare('INSERT INTO `{prefix}uploads` (`user_id`, `file_data`, `file_name`, `file_mime`, `file_time`, `file_expire`) VALUES (:id, :data, :name, :mime, :time, :expire)')
->execute([
'id' => $user->id,
'data' => $data,
'name' => $name,
'mime' => $mime,
'time' => time(),
'expire' => $expire,
]);
// Get the last insert id
$id = Database::lastInsertID();
$id = (int) DB::lastID();
// Return a new File object
return new File($id);
@ -105,17 +106,21 @@ class File
public function __construct($fileId)
{
// Attempt to get the database row
$fileRow = Database::fetch('uploads', false, ['file_id' => [$fileId, '=']]);
$fr = DB::prepare('SELECT * FROM `{prefix}uploads` WHERE `file_id` = :id');
$fr->execute([
'id' => $fileId,
]);
$fileRow = $fr->fetch();
// If anything was returned populate the variables
if ($fileRow) {
$this->id = $fileRow['file_id'];
$this->user = User::construct($fileRow['user_id']);
$this->data = $fileRow['file_data'];
$this->name = $fileRow['file_name'];
$this->mime = $fileRow['file_mime'];
$this->time = $fileRow['file_time'];
$this->expire = $fileRow['file_expire'];
$this->id = $fileRow->file_id;
$this->user = User::construct($fileRow->user_id);
$this->data = $fileRow->file_data;
$this->name = $fileRow->file_name;
$this->mime = $fileRow->file_mime;
$this->time = $fileRow->file_time;
$this->expire = $fileRow->file_expire;
}
}
@ -124,8 +129,9 @@ class File
*/
public function delete()
{
Database::delete('uploads', [
'file_id' => [$this->id, '='],
DB::prepare('DELETE FROM `{prefix}uploads` WHERE `file_id` = :id')
->execute([
'id' => $this->id,
]);
}
}

View file

@ -8,6 +8,7 @@
namespace Sakura\Forum;
use Sakura\Database;
use Sakura\DB;
use Sakura\Users;
use Sakura\User;
use Sakura\Perms;
@ -118,21 +119,25 @@ class Forum
public function __construct($forumId = 0)
{
// Get the row from the database
$forumRow = Database::fetch('forums', false, ['forum_id' => [$forumId, '=']]);
$forumRow = DB::prepare('SELECT * FROM `{prefix}forums` WHERE `forum_id` = :id');
$forumRow->execute([
'id' => $forumId,
]);
$forumRow = $forumRow->fetch();
// Create permissions object
$this->_permissions = new Perms(Perms::FORUM);
// Populate the variables
if ($forumRow) {
$this->id = $forumRow['forum_id'];
$this->order = $forumRow['forum_order'];
$this->name = $forumRow['forum_name'];
$this->description = $forumRow['forum_desc'];
$this->link = $forumRow['forum_link'];
$this->category = $forumRow['forum_category'];
$this->type = $forumRow['forum_type'];
$this->icon = $forumRow['forum_icon'];
$this->id = $forumRow->forum_id;
$this->order = $forumRow->forum_order;
$this->name = $forumRow->forum_name;
$this->description = $forumRow->forum_desc;
$this->link = $forumRow->forum_link;
$this->category = $forumRow->forum_category;
$this->type = $forumRow->forum_type;
$this->icon = $forumRow->forum_icon;
} elseif ($forumId != 0) {
$this->id = -1;
}
@ -173,14 +178,18 @@ class Forum
// Check if _forums is populated
if (!count($this->_forums)) {
// Get all rows with the category id set to the forum id
$forumRows = Database::fetch('forums', true, ['forum_category' => [$this->id, '=']], ['forum_order']);
$forumRows = DB::prepare('SELECT `forum_id` FROM `{prefix}forums` WHERE `forum_category` = :cat ORDER BY forum_order');
$forumRows->execute([
'cat' => $this->id,
]);
$forumRows = $forumRows->fetchAll();
// Create a storage array
$forums = [];
// Create new objects for each forum
foreach ($forumRows as $forum) {
$forums[$forum['forum_id']] = new Forum($forum['forum_id']);
$forums[$forum->forum_id] = new Forum($forum->forum_id);
}
$this->_forums = $forums;
@ -202,19 +211,18 @@ class Forum
// Check if _threads is populated
if (!count($this->_threads)) {
// Get all rows with the forum id for this forum
$announcements = Database::fetch('topics', true, ['forum_id' => [$this->id, '='], 'topic_type' => ['2', '=']], ['topic_last_reply', true]);
$sticky = Database::fetch('topics', true, ['forum_id' => [$this->id, '='], 'topic_type' => ['1', '=']], ['topic_last_reply', true]);
$regular = Database::fetch('topics', true, ['forum_id' => [$this->id, '='], 'topic_type' => ['0', '=']], ['topic_last_reply', true]);
// Combine them into one array
$threadRows = array_merge($announcements, $sticky, $regular);
$threadRows = DB::prepare('SELECT * FROM `{prefix}topics` WHERE `forum_id` = :forum ORDER BY `topic_type` DESC, `topic_last_reply` DESC');
$threadRows->execute([
'forum' => $this->id,
]);
$threadRows = $threadRows->fetchAll();
// Create a storage array
$threads = [];
// Create new objects for each thread
foreach ($threadRows as $thread) {
$threads[$thread['topic_id']] = new Thread($thread['topic_id']);
$threads[$thread->topic_id] = new Thread($thread->topic_id);
}
$this->_threads = $threads;
@ -236,10 +244,14 @@ class Forum
// Check if _firstPost is set
if ($this->_firstPost === null) {
// Get the row
$firstPost = Database::fetch('posts', false, ['forum_id' => [$this->id, '=']], ['post_id'], [1]);
$firstPost = DB::prepare('SELECT `post_id` FROM `{prefix}posts` WHERE `forum_id` = :id ORDER BY `post_id` LIMIT 1');
$firstPost->execute([
'id' => $this->id,
]);
$firstPost = $firstPost->fetch();
// Create the post object
$post = new Post(empty($firstPost) ? 0 : $firstPost['post_id']);
$post = new Post(empty($firstPost) ? 0 : $firstPost->post_id);
// Assign it to a "cache" variable
$this->_firstPost = $post;
@ -261,10 +273,14 @@ class Forum
// Check if _lastPost is set
if ($this->_lastPost === null) {
// Get the row
$lastPost = Database::fetch('posts', false, ['forum_id' => [$this->id, '=']], ['post_id', true], [1]);
$lastPost = DB::prepare('SELECT `post_id` FROM `{prefix}posts` WHERE `forum_id` = :id ORDER BY `post_id` DESC LIMIT 1');
$lastPost->execute([
'id' => $this->id,
]);
$lastPost = $lastPost->fetch();
// Create the post object
$post = new Post(empty($lastPost) ? 0 : $lastPost['post_id']);
$post = new Post(empty($lastPost) ? 0 : $lastPost->post_id);
// Assign it to a "cache" variable
$this->_lastPost = $post;
@ -283,7 +299,11 @@ class Forum
*/
public function threadCount()
{
return Database::count('topics', ['forum_id' => [$this->id, '=']])[0];
$count = DB::prepare('SELECT * FROM `{prefix}topics` WHERE `forum_id` = :id');
$count->execute([
'id' => $this->id,
]);
return $count->rowCount();
}
/**
@ -293,7 +313,11 @@ class Forum
*/
public function postCount()
{
return Database::count('posts', ['forum_id' => [$this->id, '=']])[0];
$count = DB::prepare('SELECT * FROM `{prefix}posts` WHERE `forum_id` = :id');
$count->execute([
'id' => $this->id,
]);
return $count->rowCount();
}
/**

View file

@ -9,6 +9,7 @@ namespace Sakura\Forum;
use Sakura\Utils;
use Sakura\Database;
use Sakura\DB;
use Sakura\User;
use Sakura\BBcode;
use Sakura\Config;
@ -114,21 +115,25 @@ class Post
public function __construct($postId)
{
// Attempt to get the database row
$postRow = Database::fetch('posts', false, ['post_id' => [$postId, '=']]);
$postRow = DB::prepare('SELECT * FROM `{prefix}posts` WHERE `post_id` = :id');
$postRow->execute([
'id' => $postId,
]);
$postRow = $postRow->fetch();
// Assign data if a row was returned
if ($postRow) {
$this->id = $postRow['post_id'];
$this->thread = $postRow['topic_id'];
$this->forum = $postRow['forum_id'];
$this->poster = User::construct($postRow['poster_id']);
$this->ip = $postRow['poster_ip'];
$this->time = $postRow['post_time'];
$this->subject = $postRow['post_subject'];
$this->text = $postRow['post_text'];
$this->editTime = $postRow['post_edit_time'];
$this->editReason = $postRow['post_edit_reason'];
$this->editUser = User::construct($postRow['post_edit_user']);
$this->id = $postRow->post_id;
$this->thread = $postRow->topic_id;
$this->forum = $postRow->forum_id;
$this->poster = User::construct($postRow->poster_id);
$this->ip = $postRow->poster_ip;
$this->time = $postRow->post_time;
$this->subject = $postRow->post_subject;
$this->text = $postRow->post_text;
$this->editTime = $postRow->post_edit_time;
$this->editReason = $postRow->post_edit_reason;
$this->editUser = User::construct($postRow->post_edit_user);
}
// Parse the markup
@ -144,7 +149,7 @@ class Post
* @param int $thread The ID of the thread this post is a reply to.
* @param mixed $forum The forum this post is a reply in.
*
* @return null|Post Either null, indicating a failure, or the Post object.
* @return null|self Either null, indicating a failure, or the Post object.
*/
public static function create($subject, $text, User $poster, $thread = 0, $forum = 0)
{
@ -169,18 +174,19 @@ class Post
}
// Insert the post
Database::insert('posts', [
'topic_id' => $thread->id,
'forum_id' => $thread->forum,
'poster_id' => $poster->id,
'poster_ip' => Net::IP(),
'post_time' => time(),
'post_subject' => $subject,
'post_text' => $text,
DB::prepare('INSERT INTO `{prefix}posts` (`topic_id`, `forum_id`, `poster_id`, `poster_ip`, `post_time`, `post_subject`, `post_text`) VALUES (:thread, :forum, :user, :ip, :time, :subject, :text)')
->execute([
'thread' => $thread->id,
'forum' => $thread->forum,
'user' => $poster->id,
'ip' => Net::IP(),
'time' => time(),
'subject' => $subject,
'text' => $text,
]);
// Get post id
$id = Database::lastInsertID();
$id = (int) DB::lastID();
// Update the last post date
$thread->lastUpdate();
@ -208,22 +214,19 @@ class Post
$thread = new Thread($this->thread);
// Update the post
Database::update('posts', [
[
'topic_id' => $thread->id,
'forum_id' => $thread->forum,
'poster_id' => $this->poster->id,
'poster_ip' => Net::pton(Net::IP()),
'post_time' => $this->time,
'post_subject' => $this->subject,
'post_text' => $this->text,
'post_edit_time' => $this->editTime,
'post_edit_reason' => $this->editReason,
'post_edit_user' => $this->editUser->id,
],
[
'post_id' => [$this->id, '='],
]
DB::prepare('UPDATE `{prefix}posts` SET `topic_id` = :thread, `forum_id` = :forum, `poster_id` = :user, `poster_ip` = :ip, `post_time` = :time, `post_subject` = :subject, `post_text` = :text, `post_edit_time` = :edit_time, `post_edit_reason` = :edit_reason, `post_edit_user` = :edit_user WHERE `post_id` = :post')
->execute([
'post' => $this->id,
'thread' => $thread->id,
'forum' => $thread->forum,
'user' => $this->poster->id,
'ip' => Net::pton(Net::IP()),
'time' => $this->time,
'subject' => $this->subject,
'text' => $this->text,
'edit_time' => $this->editTime,
'edit_reason' => $this->editReason,
'edit_user' => $this->editUser->id,
]);
// Return a new post object

View file

@ -8,6 +8,7 @@
namespace Sakura\Forum;
use Sakura\Database;
use Sakura\DB;
use Sakura\Utils;
/**
@ -129,21 +130,25 @@ class Thread
public function __construct($threadId)
{
// Attempt to get the database row
$threadRow = Database::fetch('topics', false, ['topic_id' => [$threadId, '=']]);
$threadRow = DB::prepare('SELECT * FROM `{prefix}topics` WHERE `topic_id` = :id');
$threadRow->execute([
'id' => $threadId,
]);
$threadRow = $threadRow->fetch();
// Assign data if a row was returned
if ($threadRow) {
$this->id = $threadRow['topic_id'];
$this->forum = $threadRow['forum_id'];
$this->hidden = (bool) $threadRow['topic_hidden'];
$this->title = $threadRow['topic_title'];
$this->time = $threadRow['topic_time'];
$this->timeLimit = $threadRow['topic_time_limit'];
$this->views = $threadRow['topic_views'];
$this->status = $threadRow['topic_status'];
$this->statusChange = $threadRow['topic_status_change'];
$this->type = $threadRow['topic_type'];
$this->oldForum = $threadRow['topic_old_forum'];
$this->id = $threadRow->topic_id;
$this->forum = $threadRow->forum_id;
$this->hidden = (bool) $threadRow->topic_hidden;
$this->title = $threadRow->topic_title;
$this->time = $threadRow->topic_time;
$this->timeLimit = $threadRow->topic_time_limit;
$this->views = $threadRow->topic_views;
$this->status = $threadRow->topic_status;
$this->statusChange = $threadRow->topic_status_change;
$this->type = $threadRow->topic_type;
$this->oldForum = $threadRow->topic_old_forum;
}
}
@ -155,21 +160,22 @@ class Thread
* @param mixed $status Status of the thread.
* @param mixed $type Type of thread.
*
* @return Thread The new thread instance.
* @return self The new thread instance.
*/
public static function create($forum, $title, $status = 0, $type = 0)
{
// Create the database entry
Database::insert('topics', [
'forum_id' => $forum,
'topic_title' => $title,
'topic_time' => time(),
'topic_status' => $status,
'topic_type' => $type,
DB::prepare('INSERT INTO `{prefix}topics` (`forum_id`, `topic_title`, `topic_time`, `topic_status`, `topic_type`) VALUES (:forum, :title, :time, :status, :type)')
->execute([
'forum' => $forum,
'title' => $title,
'time' => time(),
'status' => $status,
'type' => $type,
]);
// Return the thread object
return new Thread(Database::lastInsertID());
return new Thread(DB::lastID());
}
/**
@ -178,13 +184,15 @@ class Thread
public function delete()
{
// Delete all posts
Database::delete('posts', [
'topic_id' => [$this->id, '='],
DB::prepare('DELETE FROM `{prefix}posts` WHERE `topic_id` = :id')
->execute([
'id' => $this->id,
]);
// Delete thread meta
Database::delete('topics', [
'topic_id' => [$this->id, '='],
DB::prepare('DELETE FROM `{prefix}topics` WHERE `topic_id` = :id')
->execute([
'id' => $this->id,
]);
}
@ -197,48 +205,39 @@ class Thread
public function move($forum, $setOld = true)
{
// Update all posts
Database::update('posts', [
[
'forum_id' => $forum,
],
[
'topic_id' => [$this->id, '='],
]
DB::prepare('UPDATE `{prefix}posts` SET `forum_id` = :forum WHERE `topic_id` = :thread')
->execute([
'forum' => $forum,
'thread' => $this->id,
]);
// Update thread meta
Database::update('topics', [
[
'forum_id' => $forum,
'topic_old_forum' => ($setOld ? $this->forum : 0),
],
[
'topic_id' => [$this->id, '='],
]
DB::prepare('UPDATE `{prefix}topics` SET `forum_id` = :forum, `topic_old_forum` = :old WHERE `topic_id` = :thread')
->execute([
'forum' => $forum,
'old' => ($setOld ? $this->forum : 0),
'thread' => $this->id,
]);
}
/**
* Update the thread data.
*
* @return Thread The updated thread.
* @return self The updated thread.
*/
public function update()
{
// Update row
Database::update('topics', [
[
'topic_hidden' => $this->hidden,
'topic_title' => $this->title,
'topic_time_limit' => $this->timeLimit,
'topic_status' => $this->status,
'topic_status_change' => $this->statusChange,
'topic_type' => $this->type,
'topic_old_forum' => $this->oldForum,
],
[
'topic_id' => [$this->id, '='],
]
DB::prepare('UPDATE `{prefix}topics` SET `topic_hidden` = :hidden, `topic_title` = :title, `topic_time_limit` = :limit, `topic_status` = :status, `topic_status_change` = :change, `topic_type` = :type, `topic_old_forum` = :old WHERE `topic_id` = :id')
->execute([
'hidden' => $this->hidden,
'title' => $this->title,
'limit' => $this->timeLimit,
'status' => $this->status,
'change' => $this->statusChange,
'type' => $this->type,
'old' => $this->oldForum,
'id' => $this->id,
]);
// Return new object
@ -255,14 +254,18 @@ class Thread
// Check if _posts is something
if (!count($this->_posts)) {
// Get all rows with the thread id
$postRows = Database::fetch('posts', true, ['topic_id' => [$this->id, '=']]);
$postRows = DB::prepare('SELECT `post_id` FROM `{prefix}posts` WHERE `topic_id` = :thread');
$postRows->execute([
'thread' => $this->id,
]);
$postRows = $postRows->fetchAll();
// Create a storage array
$posts = [];
// Create new post objects for each post
foreach ($postRows as $post) {
$posts[$post['post_id']] = new Post($post['post_id']);
$posts[$post->post_id] = new Post($post->post_id);
}
$this->_posts = $posts;
@ -287,10 +290,14 @@ class Thread
}
// Get the row from the database
$post = Database::fetch('posts', false, ['topic_id' => [$this->id, '=']], ['post_id'], [1]);
$post = DB::prepare('SELECT `post_id` FROM `{prefix}posts` WHERE `topic_id` = :thread ORDER BY `post_id` LIMIT 1');
$post->execute([
'thread' => $this->id,
]);
$post = $post->fetch();
// Create the post class
$post = new Post($post ? $post['post_id'] : 0);
$post = new Post($post ? $post->post_id : 0);
// Assign it to the cache var
$this->_firstPost = $post;
@ -312,10 +319,14 @@ class Thread
}
// Get the row from the database
$post = Database::fetch('posts', false, ['topic_id' => [$this->id, '=']], ['post_id', true], [1]);
$post = DB::prepare('SELECT `post_id` FROM `{prefix}posts` WHERE `topic_id` = :thread ORDER BY `post_id` DESC LIMIT 1');
$post->execute([
'thread' => $this->id,
]);
$post = $post->fetch();
// Create the post class
$post = new Post($post ? $post['post_id'] : 0);
$post = new Post($post ? $post->post_id : 0);
// Assign it to the cache var
$this->_lastPost = $post;
@ -331,7 +342,11 @@ class Thread
*/
public function replyCount()
{
return Database::count('posts', ['topic_id' => [$this->id, '=']])[0];
$count = DB::prepare('SELECT * FROM `{prefix}posts` WHERE `topic_id` = :thread');
$count->execute([
'thread' => $this->id,
]);
return $count->rowCount();
}
/**
@ -344,10 +359,15 @@ class Thread
public function unread($user)
{
// Attempt to get track row from the database
$track = Database::fetch('topics_track', false, ['user_id' => [$user, '='], 'topic_id' => [$this->id, '='], 'mark_time' => [$this->lastPost()->time, '>']]);
$track = DB::prepare('SELECT * FROM `{prefix}topics_track` WHERE `user_id` = :user AND `topic_id` = :thread AND `mark_time` > :last');
$track->execute([
'user' => $user,
'thread' => $this->id,
'last' => $this->lastPost()->time,
]);
// If nothing was returned it's obvious that the status is unread
if (!$track) {
if (!$track->rowCount()) {
return true;
}
@ -363,26 +383,29 @@ class Thread
public function trackUpdate($user)
{
// Check if we already have a track record
$track = Database::fetch('topics_track', false, ['user_id' => [$user, '='], 'topic_id' => [$this->id, '='], 'forum_id' => [$this->forum, '=']]);
$track = DB::prepare('SELECT * FROM `{prefix}topics_track` WHERE `user_id` = :user AND `topic_id` = :thread AND `forum_id` = :forum');
$track->execute([
'user' => $user,
'thread' => $this->id,
'forum' => $this->forum,
]);
// If so update it
if ($track) {
Database::update('topics_track', [
[
'mark_time' => time(),
],
[
'user_id' => [$user, '='],
'topic_id' => [$this->id, '='],
],
if ($track->rowCount()) {
DB::prepare('UPDATE `{prefix}topics_track` SET `mark_time` = :time WHERE `user_id` = :user AND `topic_id` = :thread')
->execute([
'user' => $user,
'thread' => $this->id,
'time' => time(),
]);
} else {
// If not create a new record
Database::insert('topics_track', [
'user_id' => $user,
'topic_id' => $this->id,
'forum_id' => $this->forum,
'mark_time' => time(),
DB::prepare('INSERT INTO `{prefix}topics_track` (`user_id`, `topic_id`, `forum_id`, `mark_time`) VALUES (:user, :thread, :forum, :time)')
->execute([
'user' => $user,
'thread' => $this->id,
'forum' => $this->forum,
'time' => time(),
]);
}
}
@ -392,13 +415,10 @@ class Thread
*/
public function viewsUpdate()
{
Database::update('topics', [
[
'topic_views' => $this->views + 1,
],
[
'topic_id' => [$this->id, '='],
],
DB::prepare('UPDATE `{prefix}topics` SET `topic_views` = :views WHERE `topic_id` = :thread')
->execute([
'views' => $this->views + 1,
'thread' => $this->id,
]);
}
@ -407,13 +427,10 @@ class Thread
*/
public function lastUpdate()
{
Database::update('topics', [
[
'topic_last_reply' => time(),
],
[
'topic_id' => [$this->id, '='],
],
DB::prepare('UPDATE `{prefix}topics` SET `topic_last_reply` = :last WHERE `topic_id` = :thread')
->execute([
'last' => time(),
'thread' => $this->id,
]);
}
}

View file

@ -31,7 +31,11 @@ class News
{
// Get the news posts and assign them to $posts
$posts = Database::fetch('news', true, ['news_category' => [$category, '=']], ['news_id', true]);
$posts = DB::prepare('SELECT * FROM `{prefix}news` WHERE `news_category` = :cat ORDER BY `news_id` DESC');
$posts->execute([
'cat' => $category,
]);
$posts = $posts->fetchAll(\PDO::FETCH_ASSOC);
// Attach poster data
foreach ($posts as $post) {

View file

@ -93,11 +93,30 @@ class Perms
*/
public function rank($rid, $conditions = [], $perm = 0)
{
// Merge rank id and additional conditions
$conditions = array_merge(['rank_id' => [$rid, '='], 'user_id' => [0, '=']], $conditions);
// Build statement
$stmt = "SELECT * FROM `{prefix}{$this->table}` WHERE `rank_id` = :rank AND `user_id` = 0";
// Append additional conditionals (DBWrapper v1 format, except OR is ignored)
foreach ($conditions as $column => $value) {
$stmt .= " AND `{$column}` {$value[1]} :_retarded_{$column}";
}
// Prepare the statement
$get = DB::prepare($stmt);
// Bind rank
$get->bindParam('rank', $rid);
// Bind additionals
foreach ($conditions as $column => $value) {
$get->bindParam("_retarded_{$column}", $value[0]);
}
// Execute!
$get->execute();
// Fetch from the db
$get = Database::fetch($this->table, false, $conditions);
$get = $get->fetch(\PDO::FETCH_ASSOC);
// Check if anything was returned
if ($get && array_key_exists($this->column, $get) && $get['rank_id']) {
@ -127,12 +146,31 @@ class Perms
foreach (array_keys($user->ranks) as $rank) {
$perm = $perm | $this->rank($rank, $conditions, $perm);
}
// Build statement
$stmt = "SELECT * FROM `{prefix}{$this->table}` WHERE `rank_id` = 0 AND `user_id` = :user";
// Merge user id and additional conditions
$conditions = array_merge(['user_id' => [$uid, '='], 'rank_id' => [0, '=']], $conditions);
// Append additional conditionals (DBWrapper v1 format, except OR is ignored)
foreach ($conditions as $column => $value) {
$stmt .= " AND `{$column}` {$value[1]} :_retarded_{$column}";
}
// Prepare the statement
$get = DB::prepare($stmt);
// Bind rank
$get->bindParam('user', $uid);
// Bind additionals
foreach ($conditions as $column => $value) {
$get->bindParam("_retarded_{$column}", $value[0]);
}
// Execute!
$get->execute();
// Fetch from the db
$get = Database::fetch($this->table, false, $conditions);
$get = $get->fetch(\PDO::FETCH_ASSOC);
// Check if anything was returned
if ($get && array_key_exists($this->column, $get) && $get['user_id']) {

View file

@ -117,24 +117,22 @@ class Rank
{
// Get the rank database row
$rankRow = Database::fetch(
'ranks',
false,
[
'rank_id' => [$rid, '=', true],
]
);
$rankRow = DB::prepare('SELECT * FROM `{prefix}ranks` WHERE `rank_id` = :id');
$rankRow->execute([
'id' => $rid,
]);
$rankRow = $rankRow->fetch();
// Check if the rank actually exists
if ($rankRow) {
$this->id = $rankRow['rank_id'];
$this->name = $rankRow['rank_name'];
$this->hierarchy = $rankRow['rank_hierarchy'];
$this->multiple = $rankRow['rank_multiple'];
$this->hidden = (bool) $rankRow['rank_hidden'];
$this->colour = $rankRow['rank_colour'];
$this->description = $rankRow['rank_description'];
$this->title = $rankRow['rank_title'];
$this->id = $rankRow->rank_id;
$this->name = $rankRow->rank_name;
$this->hierarchy = $rankRow->rank_hierarchy;
$this->multiple = $rankRow->rank_multiple;
$this->hidden = (bool) $rankRow->rank_hidden;
$this->colour = $rankRow->rank_colour;
$this->description = $rankRow->rank_description;
$this->title = $rankRow->rank_title;
}
// Init the permissions
@ -191,7 +189,11 @@ class Rank
public function users($justIds = false)
{
// Fetch all users part of this rank
$userIds = array_column(Database::fetch('user_ranks', true, ['rank_id' => [$this->id, '=']]), 'user_id');
$fetch = DB::prepare('SELECT `user_id` FROM `{prefix}user_ranks` WHERE `rank_id` = :id');
$fetch->execute([
'id' => $this->id,
]);
$userIds = array_column($fetch->fetchAll(\PDO::FETCH_ASSOC), 'user_id');
// Just return that if we were asked for just the ids
if ($justIds) {

View file

@ -53,9 +53,10 @@ class Session
public function destroy()
{
// Invalidate the session key
Database::delete('sessions', [
'session_key' => [$this->sessionId, '='],
'user_id' => [$this->userId, '='],
DB::prepare('DELETE FROM `{prefix}sessions` WHERE `session_key` = :key AND `user_id` = :user')
->execute([
'key' => $this->sessionId,
'user' => $this->userId,
]);
// Unset userId and sessionId
@ -74,7 +75,10 @@ class Session
public function destroyAll()
{
// Delete all database entries with this user in it
Database::delete('sessions', ['user_id' => [$this->userId, '=']]);
DB::prepare('DELETE FROM `{prefix}sessions` WHERE `user_id` = :user')
->execute([
'user' => $this->userId,
]);
// Destroy this session to finish it off
$this->destroy();
@ -93,14 +97,15 @@ class Session
$session = hash('sha256', $this->userId . base64_encode('sakura' . mt_rand(0, 99999999)) . time());
// Insert the session into the database
Database::insert('sessions', [
'user_id' => $this->userId,
'user_ip' => Net::pton(Net::IP()),
'user_agent' => Utils::cleanString(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'No user agent header.'),
'session_key' => $session,
'session_start' => time(),
'session_expire' => time() + 604800,
'session_remember' => $permanent ? '1' : '0',
DB::prepare('INSERT INTO `{prefix}sessions` (`user_id`, `user_ip`, `user_agent`, `session_key`, `session_start`, `session_expire`, `session_remember`) VALUES (:id, :ip, :agent, :key, :start, :end, :remember)')
->execute([
'id' => $this->userId,
'ip' => Net::pton(Net::IP()),
'agent' => Utils::cleanString(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'No user agent header.'),
'key' => $session,
'start' => time(),
'end' => time() + 604800,
'remember' => $permanent ? '1' : '0',
]);
// Return the session key
@ -115,10 +120,12 @@ class Session
public function validate()
{
// Get session from database
$session = Database::fetch('sessions', false, [
'user_id' => [$this->userId, '='],
'session_key' => [$this->sessionId, '='],
$session = DB::prepare('SELECT * FROM `{prefix}sessions` WHERE `user_id` = :user AND `session_key` = :key');
$session->execute([
'user' => $this->userId,
'key' => $this->sessionId,
]);
$session = $session->fetch();
// Check if we actually got something in return
if (!$session) {
@ -126,13 +133,13 @@ class Session
}
// Check if the session expired
if ($session['session_expire'] < time()) {
if ($session->session_expire < time()) {
// ...and return false
return 0;
}
// IP Check
$ipCheck = false;// Config::get('session_check');
$ipCheck = false; // Forced disabled due to incompatibility with the Net class. -- Config::get('session_check');
// Origin checking
if ($ipCheck) {
@ -178,18 +185,15 @@ class Session
}
// If the remember flag is set extend the session time
if ($session['session_remember']) {
Database::update('sessions', [
[
'session_expire' => time() + 604800,
],
[
'session_id' => [$session['session_id'], '='],
],
if ($session->session_remember) {
DB::prepare('UPDATE `{prefix}sessions` SET `session_expire` = :expire WHERE `session_id` = :id')
->execute([
'expire' => time() + 604800,
'id' => $session->session_id,
]);
}
// Return 2 if the remember flag is set and return 1 if not
return $session['session_remember'] ? 2 : 1;
return $session->session_remember ? 2 : 1;
}
}

View file

@ -258,24 +258,25 @@ class User
$password = Hashing::createHash($password);
// Insert the user into the database
Database::insert('users', [
'username' => $username,
'username_clean' => $usernameClean,
'password_hash' => $password[3],
'password_salt' => $password[2],
'password_algo' => $password[0],
'password_iter' => $password[1],
DB::prepare('INSERT INTO `{prefix}users` (`username`, `username_clean`, `password_hash`, `password_salt`, `password_algo`, `password_iter`, `email`, `rank_main`, `register_ip`, `last_ip`, `user_registered`, `user_last_online`, `user_country`) VALUES (:uname, :uname_clean, :pw_hash, :pw_salt, :pw_algo, :pw_iter, :email, :rank, :r_ip, :l_ip, :registered, :l_online, :country)')
->execute([
'uname' => $username,
'uname_clean' => $usernameClean,
'pw_hash' => $password[3],
'pw_salt' => $password[2],
'pw_algo' => $password[0],
'pw_iter' => $password[1],
'email' => $emailClean,
'rank_main' => 0,
'register_ip' => Net::pton(Net::IP()),
'last_ip' => Net::pton(Net::IP()),
'user_registered' => time(),
'user_last_online' => 0,
'user_country' => Utils::getCountryCode(),
'rank' => 0,
'r_ip' => Net::pton(Net::IP()),
'l_ip' => Net::pton(Net::IP()),
'registered' => time(),
'l_online' => 0,
'country' => Utils::getCountryCode(),
]);
// Get the last id
$userId = Database::lastInsertID();
$userId = DB::lastID();
// Create a user object
$user = self::construct($userId);
@ -298,49 +299,51 @@ class User
private function __construct($uid)
{
// Get the user database row
$userRow = Database::fetch(
'users',
false,
[
'user_id' => [$uid, '=', true],
'username_clean' => [Utils::cleanString($uid, true), '=', true],
]
);
$userRow = DB::prepare('SELECT * FROM `{prefix}users` WHERE `user_id` = :id OR `username_clean` = :clean');
$userRow->execute([
'id' => $uid,
'clean' => Utils::cleanString($uid, true, true),
]);
$userRow = $userRow->fetch();
// Populate the variables
if ($userRow) {
$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'];
$this->registerIp = $userRow['register_ip'];
$this->lastIp = $userRow['last_ip'];
$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'];
$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;
$this->registerIp = $userRow->register_ip;
$this->lastIp = $userRow->last_ip;
$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;
}
// Get all ranks
$ranks = Database::fetch('user_ranks', true, ['user_id' => [$this->id, '=']]);
$ranks = DB::prepare('SELECT * FROM `{prefix}user_ranks` WHERE `user_id` = :id');
$ranks->execute([
'id' => $this->id,
]);
$ranks = $ranks->fetchAll();
// Get the rows for all the ranks
foreach ($ranks as $rank) {
// Store the database row in the array
$this->ranks[$rank['rank_id']] = Rank::construct($rank['rank_id']);
$this->ranks[$rank->rank_id] = Rank::construct($rank->rank_id);
}
// Check if ranks were set
@ -423,10 +426,13 @@ class User
public function isOnline()
{
// Get all sessions
$sessions = Database::fetch('sessions', true, ['user_id' => [$this->id, '=']]);
$sessions = DB::prepare('SELECT `user_id` FROM `{prefix}sessions` WHERE `user_id` = :id');
$sessions->execute([
'id' => $this->id,
]);
// If there's no entries just straight up return false
if (!$sessions) {
if (!$sessions->rowCount()) {
return false;
}
@ -441,19 +447,19 @@ class User
*/
public function forumStats()
{
$posts = DB::prepare('SELECT * FROM `{prefix}posts` WHERE `poster_id` = :id');
$posts->execute([
'id' => $this->id,
]);
$threads = DB::prepare('SELECT DISTINCT * FROM `{prefix}posts` WHERE `poster_id` = :id GROUP BY `topic_id` ORDER BY `post_time`');
$threads->execute([
'id' => $this->id,
]);
return [
'posts' => Database::count(
'posts',
['poster_id' => [$this->id, '=']]
)[0],
'topics' => count(Database::fetch(
'posts',
true,
['poster_id' => [$this->id, '=']],
['post_time'],
null,
['topic_id']
)),
'posts' => $posts->rowCount(),
'topics' => $threads->rowCount(),
];
}
@ -476,9 +482,10 @@ class User
// Save to the database
foreach ($ranks as $rank) {
Database::insert('user_ranks', [
'rank_id' => $rank,
'user_id' => $this->id,
DB::prepare('INSERT INTO `{prefix}ranks` (`rank_id`, `user_id`) VALUES (:rank, :user)')
->execute([
'rank' => $rank,
'user' => $this->id,
]);
}
}
@ -495,7 +502,11 @@ class User
// Iterate over the ranks
foreach ($remove as $rank) {
Database::delete('user_ranks', ['user_id' => [$this->id, '='], 'rank_id' => [$rank, '=']]);
DB::prepare('DELETE FROM `{prefix}user_ranks` WHERE `user_id` = :user AND `rank_id` = :rank')
->execute([
'user' => $this->id,
'rank' => $rank,
]);
}
}
@ -509,13 +520,10 @@ class User
public function setMainRank($rank)
{
// If it does exist update their row
Database::update('users', [
[
'rank_main' => $rank,
],
[
'user_id' => [$this->id, '='],
],
DB::prepare('UPDATE `{prefix}users` SET `rank_main` = :rank WHERE `user_id` = :id')
->execute([
'rank' => $rank,
'id' => $this->id,
]);
// Return true if everything was successful
@ -571,10 +579,11 @@ class User
}
// Add friend
Database::insert('friends', [
'user_id' => $this->id,
'friend_id' => $uid,
'friend_timestamp' => time(),
DB::prepare('INSERT INTO `{prefix}friends` (`user_id`, `friend_id`, `friend_timestamp`) VALUES (:user, :friend, :time)')
->execute([
'user' => $this->id,
'friend' => $uid,
'time' => time(),
]);
// Return true because yay
@ -599,17 +608,20 @@ class User
return [0, 'USER_NOT_EXIST'];
}
// Prepare the statement
$rem = DB::prepare('DELETE FROM `{prefix}friends` WHERE `user_id` = :user AND `friend_id` = :friend');
// Remove friend
Database::delete('friends', [
'user_id' => [$this->id, '='],
'friend_id' => [$uid, '='],
$rem->execute([
'user' => $this->id,
'friend' => $uid,
]);
// Attempt to remove the request
if ($deleteRequest) {
Database::delete('friends', [
'friend_id' => [$this->id, '='],
'user_id' => [$uid, '='],
$rem->execute([
'user' => $uid,
'friend' => $this->id,
]);
}
@ -627,16 +639,19 @@ class User
public function isFriends($with)
{
// Accepted from this user
$user = Database::count('friends', [
'user_id' => [$this->id, '='],
'friend_id' => [$with, '='],
])[0];
$get = DB::prepare('SELECT * FROM `{prefix}friends` WHERE `user_id` = :user AND `friend_id` = :friend');
$get->execute([
'user' => $this->id,
'friend' => $with,
]);
$user = $get->rowCount();
// And the other user
$friend = Database::count('friends', [
'user_id' => [$with, '='],
'friend_id' => [$this->id, '='],
])[0];
$get->execute([
'user' => $with,
'friend' => $this->id,
]);
$friend = $get->rowCount();
if ($user && $friend) {
return 2; // Mutual friends
@ -663,34 +678,72 @@ class User
// Select the correct level
switch ($level) {
// Mutual
case 2:
// Get all the current user's friends
$self = array_column(Database::fetch('friends', true, ['user_id' => [$this->id, '=']]), 'friend_id');
$self = DB::prepare('SELECT `friend_id` FROM `{prefix}friends` WHERE `user_id` = :user');
$self->execute([
'user' => $this->id,
]);
$self = array_column($self->fetchAll(\PDO::FETCH_ASSOC), 'friend_id');
// Get all the people that added this user as a friend
$others = array_column(Database::fetch('friends', true, ['friend_id' => [$this->id, '=']]), 'user_id');
$others = DB::prepare('SELECT `user_id` FROM `{prefix}friends` WHERE `friend_id` = :user');
$others->execute([
'user' => $this->id,
]);
$others = array_column($others->fetchAll(\PDO::FETCH_ASSOC), 'user_id');
// Create a difference map
$users = array_intersect($self, $others);
break;
// Non-mutual (from user perspective)
case 1:
$users = array_column(Database::fetch('friends', true, ['user_id' => [$this->id, '=']]), 'friend_id');
$users = DB::prepare('SELECT `friend_id` FROM `{prefix}friends` WHERE `user_id` = :user');
$users->execute([
'user' => $this->id,
]);
$users = array_column($users->fetchAll(\PDO::FETCH_ASSOC), 'friend_id');
break;
// All friend cases
case 0:
default:
// Get all the current user's friends
$self = array_column(Database::fetch('friends', true, ['user_id' => [$this->id, '=']]), 'friend_id');
$self = DB::prepare('SELECT `friend_id` FROM `{prefix}friends` WHERE `user_id` = :user');
$self->execute([
'user' => $this->id,
]);
$self = array_column($self->fetchAll(\PDO::FETCH_ASSOC), 'friend_id');
// Get all the people that added this user as a friend
$others = array_column(Database::fetch('friends', true, ['friend_id' => [$this->id, '=']]), 'user_id');
$others = DB::prepare('SELECT `user_id` FROM `{prefix}friends` WHERE `friend_id` = :user');
$others->execute([
'user' => $this->id,
]);
$others = array_column($others->fetchAll(\PDO::FETCH_ASSOC), 'user_id');
// Create a difference map
$users = array_merge($others, $self);
break;
// Open requests
case -1:
// Get all the current user's friends
$self = array_column(Database::fetch('friends', true, ['user_id' => [$this->id, '=']]), 'friend_id');
$self = DB::prepare('SELECT `friend_id` FROM `{prefix}friends` WHERE `user_id` = :user');
$self->execute([
'user' => $this->id,
]);
$self = array_column($self->fetchAll(\PDO::FETCH_ASSOC), 'friend_id');
// Get all the people that added this user as a friend
$others = array_column(Database::fetch('friends', true, ['friend_id' => [$this->id, '=']]), 'user_id');
$others = DB::prepare('SELECT `user_id` FROM `{prefix}friends` WHERE `friend_id` = :user');
$others->execute([
'user' => $this->id,
]);
$others = array_column($others->fetchAll(\PDO::FETCH_ASSOC), 'user_id');
// Create a difference map
$users = array_diff($others, $self);
break;
@ -770,8 +823,17 @@ class User
// Create array and get values
$profile = [];
$profileFields = Database::fetch('profilefields');
$profileValuesRaw = Database::fetch('user_profilefields', true, ['user_id' => [$this->id, '=']]);
$profileFields = DB::prepare('SELECT * FROM `{prefix}profilefields`');
$profileFields->execute();
$profileFields = $profileFields->fetchAll(\PDO::FETCH_ASSOC);
$profileValuesRaw = DB::prepare('SELECT * FROM `{prefix}user_profilefields` WHERE `user_id` = :user');
$profileValuesRaw->execute([
'user' => $this->id,
]);
$profileValuesRaw = $profileValuesRaw->fetchAll(\PDO::FETCH_ASSOC);
$profileValueKeys = array_map(function ($a) {
return $a['field_name'];
}, $profileValuesRaw);
@ -849,8 +911,17 @@ class User
// Create array and get values
$options = [];
$optionFields = Database::fetch('optionfields');
$optionValuesRaw = Database::fetch('user_optionfields', true, ['user_id' => [$this->id, '=']]);
$optionFields = DB::prepare('SELECT * FROM `{prefix}optionfields`');
$optionFields->execute();
$optionFields = $optionFields->fetchAll(\PDO::FETCH_ASSOC);
$optionValuesRaw = DB::prepare('SELECT * FROM `{prefix}user_optionfields` WHERE `user_id` = :user');
$optionValuesRaw->execute([
'user' => $this->id,
]);
$optionValuesRaw = $optionValuesRaw->fetchAll(\PDO::FETCH_ASSOC);
$optionValueKeys = array_map(function ($a) {
return $a['field_name'];
}, $optionValuesRaw);
@ -901,9 +972,11 @@ class User
}
// Attempt to retrieve the premium record from the database
$getRecord = Database::fetch('premium', false, [
'user_id' => [$this->id, '='],
$getRecord = DB::prepare('SELECT * FROM `{prefix}premium` WHERE `user_id` = :user');
$getRecord->execute([
'user' => $this->id,
]);
$getRecord = $getRecord->fetch();
// If nothing was returned just return false
if (empty($getRecord)) {
@ -911,12 +984,12 @@ class User
}
// Check if the Tenshi hasn't expired
if ($getRecord['premium_expire'] < time()) {
return [0, $getRecord['premium_start'], $getRecord['premium_expire']];
if ($getRecord->premium_expire < time()) {
return [0, $getRecord->premium_start, $getRecord->premium_expire];
}
// Else return the start and expiration date
return [1, $getRecord['premium_start'], $getRecord['premium_expire']];
return [1, $getRecord->premium_start, $getRecord->premium_expire];
}
/**
@ -927,9 +1000,11 @@ class User
public function getWarnings()
{
// Do the database query
$getWarnings = Database::fetch('warnings', true, [
'user_id' => [$this->id, '='],
$getWarnings = DB::prepare('SELECT * FROM `{prefix}warnings` WHERE `user_id` = :user');
$getWarnings->execute([
'user' => $this->id,
]);
$getWarnings = $getWarnings->fetchAll(\PDO::FETCH_ASSOC);
// Storage array
$warnings = [];
@ -938,7 +1013,10 @@ class User
foreach ($getWarnings as $warning) {
// Check if it hasn't expired
if ($warning['warning_expires'] < time()) {
Database::delete('warnings', ['warning_id' => [$warning['warning_id'], '=']]);
DB::prepare('DELETE FROM `{prefix}warnings` WHERE `warning_id` = :warn')
->execute([
'warn' => $warning['warning_id'],
]);
continue;
}
@ -1001,12 +1079,13 @@ class User
public function getUsernameHistory()
{
// Do the database query
$changes = Database::fetch('username_history', true, [
'user_id' => [$this->id, '='],
], ['change_id', true]);
$changes = DB::prepare('SELECT * FROM `{prefix}username_history` WHERE `user_id` = :user ORDER BY `change_id` DESC');
$changes->execute([
'user' => $this->id,
]);
// Return all the warnings
return $changes;
// Return all the changes
return $changes->fetchAll(\PDO::FETCH_ASSOC);
}
/**
@ -1032,45 +1111,47 @@ class User
}
// Check if this username hasn't been used in the last amount of days set in the config
$getOld = Database::fetch('username_history', false, [
'username_old_clean' => [$username_clean, '='],
'change_time' => [(Config::get('old_username_reserve') * 24 * 60 * 60), '>'],
], ['change_id', true]);
$getOld = DB::prepare('SELECT * FROM `{prefix}username_history` WHERE `username_old_clean` = :clean AND `change_time` > :time ORDER BY `change_id` DESC');
$getOld->execute([
'clean' => $username_clean,
'time' => (Config::get('old_username_reserve') * 24 * 60 * 60),
]);
$getOld = $getOld->fetch();
// Check if anything was returned
if ($getOld && $getOld['user_id'] != $this->id) {
if ($getOld && $getOld->user_id != $this->id) {
return [0, 'TOO_RECENT', $getOld['change_time']];
}
// Check if the username is already in use
$getInUse = Database::fetch('users', false, [
'username_clean' => [$username_clean, '='],
$getInUse = DB::prepare('SELECT * FROM `{prefix}users` WHERE `username_clean` = :clean');
$getInUse->execute([
'clean' => $username_clean,
]);
$getInUse = $getInUse->fetch();
// Check if anything was returned
if ($getInUse) {
return [0, 'IN_USE', $getInUse['user_id']];
return [0, 'IN_USE', $getInUse->user_id];
}
// Insert into username_history table
Database::insert('username_history', [
'change_time' => time(),
'user_id' => $this->id,
'username_new' => $username,
'username_new_clean' => $username_clean,
'username_old' => $this->username,
'username_old_clean' => $this->usernameClean,
DB::prepare('INSERT INTO `{prefix}username_history` (`change_time`, `user_id`, `username_new`, `username_new_clean`, `username_old`, `username_old_clean`) VALUES (:time, :user, :new, :new_clean, :old, :old_clean)')
->execute([
'time' => time(),
'user' => $this->id,
'new' => $username,
'new_clean' => $username_clean,
'old' => $this->username,
'old_clean' => $this->usernameClean,
]);
// Update userrow
Database::update('users', [
[
'username' => $username,
'username_clean' => $username_clean,
],
[
'user_id' => [$this->id, '='],
],
DB::prepare('UPDATE `{prefix}users` SET `username` = :username, `username_clean` = :clean WHERE `user_id` = :id')
->execute([
'username' => $username,
'clean' => $username_clean,
'id' => $this->id,
]);
// Return success
@ -1092,23 +1173,22 @@ class User
}
// Check if the username is already in use
$getInUse = Database::fetch('users', false, [
'email' => [$email, '='],
$getInUse = DB::prepare('SELECT * FROM `{prefix}users` WHERE `email` = :email');
$getInUse->execute([
'email' => $email,
]);
$getInUse = $getInUse->fetch();
// Check if anything was returned
if ($getInUse) {
return [0, 'IN_USE', $getInUse['user_id']];
return [0, 'IN_USE', $getInUse->user_id];
}
// Update userrow
Database::update('users', [
[
'email' => $email,
],
[
'user_id' => [$this->id, '='],
],
DB::prepare('UPDATE `{prefix}users` SET `email` = :email WHERE `user_id` = :id')
->execute([
'email' => $email,
'id' => $this->id,
]);
// Return success
@ -1159,17 +1239,14 @@ class User
$password = Hashing::createHash($new);
// Update userrow
Database::update('users', [
[
'password_hash' => $password[3],
'password_salt' => $password[2],
'password_algo' => $password[0],
'password_iter' => $password[1],
'password_chan' => time(),
],
[
'user_id' => [$this->id, '='],
],
DB::prepare('UPDATE `{prefix}users` SET `password_hash` = :hash, `password_salt` = :salt, `password_algo` = :algo, `password_iter` = :iter, `password_chan` = :chan WHERE `user_id` = :id')
->execute([
'hash' => $password[3],
'salt' => $password[2],
'algo' => $password[0],
'iter' => $password[1],
'chan' => time(),
'id' => $this->id,
]);
// Return success

View file

@ -85,13 +85,10 @@ class Users
}
// Update last online
Database::update('users', [
[
'user_last_online' => time(),
],
[
'user_id' => [$uid, '='],
],
DB::prepare('UPDATE `{prefix}users` SET `user_last_online` = :lo WHERE `user_id` = :id')
->execute([
'lo' => time(),
'id' => $uid,
]);
// Update the premium meta
@ -119,11 +116,12 @@ class Users
}
// Check if we haven't hit the rate limit
$rates = Database::fetch('login_attempts', true, [
'attempt_ip' => [Net::pton(Net::IP()), '='],
'attempt_timestamp' => [time() - 1800, '>'],
'attempt_success' => [0, '='],
$rates = DB::prepare('SELECT * FROM `{prefix}login_attempts` WHERE `attempt_ip` = :ip AND `attempt_timestamp` > :time AND `attempt_success` = 0');
$rates->execute([
'ip' => Net::pton(Net::IP()),
'time' => time() - 1800,
]);
$rates = $rates->fetchAll(\PDO::FETCH_ASSOC);
if (count($rates) > 4) {
return [0, 'RATE_LIMIT'];
@ -287,7 +285,11 @@ class Users
}
// Check if the e-mail has already been used
if (Database::count('users', ['email' => [$email, '=']])[0] > 0) {
$emailCheck = DB::prepare('SELECT `user_id` FROM `{prefix}users` WHERE `email` = :email');
$emailCheck->execute([
'email' => $email,
]);
if ($emailCheck->rowCount() > 0) {
return [0, 'EMAIL_EXISTS'];
}
@ -338,10 +340,12 @@ class Users
$emailClean = Utils::cleanString($email, true);
// Do database request
$user = Database::fetch('users', false, [
'username_clean' => [$usernameClean, '='],
'email' => [$emailClean, '='],
$user = DB::prepare('SELECT * FROM `{prefix}users` WHERE `username_clean` = :clean AND `email` = :email');
$user->execute([
'clean' => $usernameClean,
'email' => $emailClean,
]);
$user = $user->fetch(\PDO::FETCH_ASSOC);
// Check if user exists
if (count($user) < 2) {
@ -417,20 +421,16 @@ class Users
// Hash the password
$password = Hashing::createHash($newpass);
$time = time();
// Update the user
Database::update('users', [
[
'password_hash' => $password[3],
'password_salt' => $password[2],
'password_algo' => $password[0],
'password_iter' => $password[1],
'password_chan' => $time,
],
[
'user_id' => [$uid, '='],
],
DB::prepare('UPDATE `{prefix}users` SET `password_hash` = :hash, `password_salt` = :salt, `password_algo` = :algo, `password_iter` = :iter, `password_chan` = :chan WHERE `user_id` = :id')
->execute([
'hash' => $password[3],
'salt' => $password[2],
'algo' => $password[0],
'iter' => $password[1],
'chan' => time(),
'id' => $uid,
]);
// Return success
@ -457,10 +457,12 @@ class Users
$emailClean = Utils::cleanString($email, true);
// Do database request
$user = Database::fetch('users', false, [
'username_clean' => [$usernameClean, '='],
'email' => [$emailClean, '='],
$user = DB::prepare('SELECT * FROM `{prefix}users` WHERE `username_clean` = :clean AND `email` = :email');
$user->execute([
'clean' => $usernameClean,
'email' => $emailClean,
]);
$user = $user->fetch(\PDO::FETCH_ASSOC);
// Check if user exists
if (count($user) < 2) {
@ -580,21 +582,23 @@ class Users
/**
* Check if a user exists.
*
* @param mixed $user The Username or ID.
* @param bool $id Use id instead.
* @param mixed $id The Username or ID.
* @param mixed $unused Unused variable.
*
* @return mixed Returns the ID if it exists, false otherwise.
*/
public static function userExists($user, $id = true)
public static function userExists($id, $unused = null)
{
// Clean string
$user = Utils::cleanString($user, true);
// Do database request
$user = Database::fetch('users', true, [($id ? 'user_id' : 'username_clean') => [$user, '=']]);
$user = DB::prepare('SELECT * FROM `{prefix}users` WHERE `user_id` = :id OR `username_clean` = :clean');
$user->execute([
'id' => $id,
'clean' => Utils::cleanString($id, true, true),
]);
$user = $user->fetch();
// Return count (which would return 0, aka false, if nothing was found)
return count($user) ? $user[0]['user_id'] : false;
return $user ? $user->user_id : false;
}
/**
@ -605,7 +609,9 @@ class Users
public static function getProfileFields()
{
// Get profile fields
$profileFields = Database::fetch('profilefields');
$profileFields = DB::prepare('SELECT * FROM `{prefix}profilefields`');
$profileFields->execute();
$profileFields = $profileFields->fetchAll(\PDO::FETCH_ASSOC);
// If there's nothing just return null
if (!count($profileFields)) {
@ -634,7 +640,9 @@ class Users
public static function getOptionFields()
{
// Get option fields
$optionFields = Database::fetch('optionfields');
$optionFields = DB::prepare('SELECT * FROM `{prefix}optionfields`');
$optionFields->execute();
$optionFields = $optionFields->fetchAll(\PDO::FETCH_ASSOC);
// If there's nothing just return null
if (!count($optionFields)) {
@ -672,10 +680,14 @@ class Users
$return = [];
// Get all online users in the past 5 minutes
$getAll = Database::fetch('users', true, ['user_last_online' => [$time, '>']]);
$getAll = DB::prepare('SELECT * FROM `{prefix}users` WHERE `user_last_online` > :lo');
$getAll->execute([
'lo' => $time,
]);
$getAll = $getAll->fetchAll();
foreach ($getAll as $user) {
$return[] = User::construct($user['user_id']);
$return[] = User::construct($user->user_id);
}
// Return all the online users
@ -693,9 +705,11 @@ class Users
public static function addUserPremium($id, $seconds)
{
// Check if there's already a record of premium for this user in the database
$getUser = Database::fetch('premium', false, [
'user_id' => [$id, '='],
$getUser = DB::prepare('SELECT * FROM `{prefix}premium` WHERE `user_id` = :user');
$getUser->execute([
'user' => $id,
]);
$getUser = $getUser->fetch(\PDO::FETCH_ASSOC);
// Calculate the (new) start and expiration timestamp
$start = isset($getUser['premium_start']) ? $getUser['premium_start'] : time();
@ -703,19 +717,17 @@ class Users
// If the user already exists do an update call, otherwise an insert call
if (empty($getUser)) {
Database::insert('premium', [
'user_id' => $id,
'premium_start' => $start,
'premium_expire' => $expire,
DB::prepare('INSERT INTO `{prefix}premium` (`user_id`, `premium_start`, `premium_expire`) VALUES (:user, :start, :expire)')
->execute([
'user' => $id,
'start' => $start,
'expire' => $expire,
]);
} else {
Database::update('premium', [
[
'premium_expire' => $expire,
],
[
'user_id' => [$id, '='],
],
DB::prepare('UPDATE `{prefix}premium` SET `premium_expire` = :expire WHERE `user_id` = :id')
->execute([
'expire' => $expire,
'user_id' => $id,
]);
}
@ -751,8 +763,9 @@ class Users
}
} elseif (!$check[0]) {
// Remove the expired entry
Database::delete('premium', [
'user_id' => [$user->id, '='],
DB::prepare('DELETE FROM `{prefix}premium` WHERE `user_id` = :user')
->execute([
'user' => $user->id,
]);
// Else remove the rank from them
@ -769,56 +782,18 @@ class Users
*/
public static function getUsersByIP($ip)
{
// Get users by registration IP
$registeredFrom = Database::fetch('users', true, ['register_ip' => [$ip, '=']]);
// Get users by last IP
$lastFrom = Database::fetch('users', true, ['last_ip' => [$ip, '='], 'register_ip' => [$ip, '!=']]);
// Merge the arrays
$users = array_merge($registeredFrom, $lastFrom);
// Get the users
$users = DB::prepare('SELECT * FROM `{prefix}users` WHERE `register_ip` = :rip OR `last_ip` = :lip');
$users->execute([
'rip' => $ip,
'lip' => $ip,
]);
$users = $users->fetchAll(\PDO::FETCH_ASSOC);
// Return the array with users
return $users;
}
/**
* Get all users.
*
* @param mixed $includeInactive include deactivated users.
* @param mixed $includeRestricted include restricted users.
*
* @return array The users.
*/
public static function getAllUsers($includeInactive = true, $includeRestricted = false)
{
// Execute query
$getUsers = Database::fetch('users', true);
// Define variable
$users = [];
// Reorder shit
foreach ($getUsers as $user) {
$user = User::construct($user['user_id']);
// Skip if inactive and not include deactivated users
if (!$includeInactive && $user->permission(Site::DEACTIVATED)) {
continue;
}
// Skip if inactive and not include restricted users
if (!$includeRestricted && $user->permission(Site::RESTRICTED)) {
continue;
}
$users[$user->id] = $user;
}
// and return an array with the users
return $users;
}
/**
* Get all ranks.
*
@ -827,14 +802,16 @@ class Users
public static function getAllRanks()
{
// Execute query
$getRanks = Database::fetch('ranks', true);
$getRanks = DB::prepare('SELECT * FROM `{prefix}ranks`');
$getRanks->execute();
$getRanks = $getRanks->fetchAll();
// Define variable
$ranks = [];
// Reorder shit
foreach ($getRanks as $rank) {
$ranks[$rank['rank_id']] = Rank::construct($rank['rank_id']);
$ranks[$rank->rank_id] = Rank::construct($rank->rank_id);
}
// and return an array with the ranks
@ -854,19 +831,18 @@ class Users
public static function getNotifications($uid = null, $timediff = 0, $excludeRead = true, $markRead = false)
{
// Prepare conditions
$conditions = [];
$conditions['user_id'] = [($uid ? $uid : self::checkLogin()[0]), '='];
if ($timediff) {
$conditions['alert_timestamp'] = [time() - $timediff, '>'];
}
if ($excludeRead) {
$conditions['alert_read'] = [0, '='];
}
$uid = $uid ? $uid : self::checkLogin()[0];
$time = $timediff ? time() - $timediff : '%';
$read = $excludeRead ? '0' : '%';
// Get notifications for the database
$notifications = Database::fetch('notifications', true, $conditions);
$notifications = DB::prepare('SELECT * FROM `{prefix}notifications` WHERE `user_id` = :user AND `alert_timestamp` > :time AND `alert_read` = :read');
$notifications->execute([
'user' => $uid,
'time' => $time,
'read' => $read,
]);
$notifications = $notifications->fetchAll(\PDO::FETCH_ASSOC);
// Mark the notifications as read
if ($markRead) {
@ -895,13 +871,10 @@ class Users
public static function markNotificationRead($id, $mode = true)
{
// Execute an update statement
Database::update('notifications', [
[
'alert_read' => ($mode ? 1 : 0),
],
[
'alert_id' => [$id, '='],
],
DB::prepare('UPDATE `{prefix}notifications` SET `alert_read` = :read WHERE `alert_id` = :id')
->execute([
'read' => ($mode ? 1 : 0),
'id' => $id,
]);
}
@ -918,20 +891,18 @@ class Users
*/
public static function createNotification($user, $title, $text, $timeout = 60000, $img = 'FONT:fa-info-circle', $link = '', $sound = 0)
{
// Get current timestamp
$time = time();
// Insert it into the database
Database::insert('notifications', [
'user_id' => $user,
'alert_timestamp' => $time,
'alert_read' => 0,
'alert_sound' => ($sound ? 1 : 0),
'alert_title' => $title,
'alert_text' => $text,
'alert_link' => $link,
'alert_img' => $img,
'alert_timeout' => $timeout,
DB::prepare('INSERT INTO `{prefix}notifications` (`user_id`, `alert_timestamp`, `alert_read`, `alert_sound`, `alert_title`, `alert_text`, `alert_link`, `alert_img`, `alert_timeout`) VALUES (:user, :time, :read, :sound, :title, :text, :link, :img, :timeout)')
->execute([
'user' => $user,
'time' => time(),
'read' => 0,
'sound' => ($sound ? 1 : 0),
'title' => $title,
'text' => $text,
'link' => $link,
'img' => $img,
'timeout' => $timeout,
]);
}
@ -942,6 +913,12 @@ class Users
*/
public static function getNewestUserId()
{
return Database::fetch('users', false, ['rank_main' => [Config::get('restricted_rank_id'), '!=']], ['user_id', true], ['1'])['user_id'];
$get = DB::prepare('SELECT `user_id` FROM `{prefix}users` WHERE `rank_main` != :restricted ORDER BY `user_id` DESC LIMIT 1');
$get->execute([
'restricted' => Config::get('restricted_rank_id'),
]);
$get = $get->fetch();
return $get ? $get->user_id : 0;
}
}

View file

@ -66,31 +66,32 @@ class Utils
$backtrace = base64_encode(json_encode(debug_backtrace()));
// Check if this error has already been logged in the past
if ($past = Database::fetch(
'error_log',
false,
[
'error_backtrace' => [$backtrace, '=', true],
'error_string' => [$errstr, '='],
'error_line' => [$errline, '='],
]
)) {
$past = DB::prepare('SELECT * FROM `{prefix}error_log` WHERE `error_backtrace` = :bc OR (`error_string` = :str AND `error_line` = :li)');
$past->execute([
'bc' => $backtrace,
'str' => $errstr,
'li' => $errline,
]);
$past = $past->fetch();
if ($past) {
// If so assign the errid
$errid = $past['error_id'];
$errid = $past->error_id;
} else {
// Create an error ID
$errid = substr(md5(microtime()), rand(0, 22), 10);
// Log the error
Database::insert('error_log', [
'error_id' => $errid,
'error_timestamp' => date("r"),
'error_revision' => SAKURA_VERSION,
'error_type' => $errno,
'error_line' => $errline,
'error_string' => $errstr,
'error_file' => $errfile,
'error_backtrace' => $backtrace,
DB::prepare('INSERT INTO `{prefix}error_log` (`error_id`, `error_timestamp`, `error_revision`, `error_type`, `error_line`, `error_string`, `error_file`, `error_backtrace`) VALUES (:id, :time, :rev, :type, :line, :string, :file, :bc)')
->execute([
'id' => $errid,
'time' => date("r"),
'rev' => SAKURA_VERSION,
'type' => $errno,
'line' => $errline,
'string' => $errstr,
'file' => $errfile,
'bc' => $backtrace,
]);
}
}
@ -430,7 +431,9 @@ class Utils
$data = [];
// Get database stuff
$table = Database::fetch('premium_log', true, null, ['transaction_id', true]);
$table = DB::prepare('SELECT * FROM `{prefix}premium_log` ORDER BY `transaction_id` DESC');
$table->execute();
$table = $table->fetchAll(\PDO::FETCH_ASSOC);
// Add raw table data to data array
$data['table'] = $table;
@ -465,11 +468,12 @@ class Utils
*/
public static function updatePremiumTracker($id, $amount, $comment)
{
Database::insert('premium_log', [
'user_id' => $id,
'transaction_amount' => $amount,
'transaction_date' => time(),
'transaction_comment' => $comment,
DB::prepare('INSERT INTO `{prefix}premium_log` (`user_id`, `transaction_amount`, `transaction_date`, `transaction_comment`) VALUES (:user, :amount, :date, :comment)')
->execute([
'user' => $id,
'amount' => $amount,
'date' => time(),
'comment' => $comment,
]);
}

View file

@ -184,11 +184,12 @@ if (isset($_REQUEST['mode'])) {
// Check if we're not RATE_LIMIT
if ($login[1] != 'RATE_LIMIT') {
// Add to database
Database::insert('login_attempts', [
'attempt_success' => $login[0],
'attempt_timestamp' => time(),
'attempt_ip' => Net::pton(Net::IP()),
'user_id' => isset($login[2]) ? $login[2] : 0,
DB::prepare('INSERT INTO `{prefix}login_attempts` (`attempt_success`, `attempt_timestamp`, `attempt_ip`, `user_id`) VALUES (:succ, :time, :ip, :user)')
->execute([
'succ' => $login[0],
'time' => time(),
'ip' => Net::pton(Net::IP()),
'user' => isset($login[2]) ? $login[2] : 0,
]);
}

View file

@ -67,9 +67,12 @@ if (!isset($thread) && !$forum->permission(ForumPerms::CREATE_THREADS, $currentU
$mode = isset($_GET['f']) ? 'f' : (isset($_GET['t']) ? 't' : (isset($_GET['p']) ? 'p' : null));
$emotes = DB::prepare('SELECT * FROM `{prefix}emoticons`');
$emotes->execute();
// Include emotes and bbcodes
$posting = [
'emoticons' => Database::fetch('emoticons'),
'emoticons' => $emotes->fetchAll(),
];
// Check if we're in reply mode
@ -198,8 +201,9 @@ if ($mode != 'f') {
// Post deletion code
if (isset($_POST['yes'])) {
// Delete the post
Database::delete('posts', [
'post_id' => [$_POST['post_id'], '='],
DB::prepare('DELETE FROM `{prefix}posts` WHERE `post_id` = :post')
->execute([
'post' => $_POST['post_id'],
]);
// Reload the topic
@ -207,8 +211,9 @@ if ($mode != 'f') {
// If there's no more posts left in the topic delete it as well
if (!$thread->replyCount()) {
Database::delete('topics', [
'topic_id' => [$thread->id, '='],
DB::prepare('DELETE FROM `{prefix}topics` WHERE `topic_id` = :thread')
->execute([
'thread' => $thread->id,
]);
}

View file

@ -451,14 +451,14 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
// Assign the correct column and title to a variable
switch ($mode) {
case 'background':
$column = 'user_background';
$stmt = 'UPDATE `{prefix}users` SET `user_background` = :img WHERE `user_id` = :user';
$msgTitle = 'Background';
$current = $currentUser->background;
$permission = $currentUser->permission(Site::CHANGE_BACKGROUND);
break;
case 'header':
$column = 'user_header';
$stmt = 'UPDATE `{prefix}users` SET `user_header` = :img WHERE `user_id` = :user';
$msgTitle = 'Header';
$current = $currentUser->header;
$permission = $currentUser->permission(Site::CHANGE_HEADER);
@ -466,7 +466,7 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
case 'avatar':
default:
$column = 'user_avatar';
$stmt = 'UPDATE `{prefix}users` SET `user_avatar` = :img WHERE `user_id` = :user';
$msgTitle = 'Avatar';
$current = $currentUser->avatar;
$permission = $currentUser->permission(Site::CHANGE_AVATAR);
@ -617,13 +617,10 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
}
// Update table
Database::update('users', [
[
$column => $fileId,
],
[
'user_id' => [$currentUser->id, '='],
],
DB::prepare($stmt)
->execute([
'img' => $fileId,
'user' => $currentUser->id,
]);
// Set render data
@ -643,11 +640,16 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
foreach ($fields as $field) {
// Add to the store array
if (isset($_POST['profile_' . $field['field_identity']]) && !empty($_POST['profile_' . $field['field_identity']])) {
Database::delete('user_profilefields', ['user_id' => [$currentUser->id, '='], 'field_name' => [$field['field_identity'], '=']]);
Database::insert('user_profilefields', [
'user_id' => $currentUser->id,
'field_name' => $field['field_identity'],
'field_value' => $_POST['profile_' . $field['field_identity']],
DB::prepare('DELETE FROM `{prefix}user_profilefields` WHERE `user_id` = :user AND `field_name` = :id')
->execute([
'user' => $currentUser->id,
'id' => $field['field_identity'],
]);
DB::prepare('INSERT INTO `{prefix}user_profilefields` (`user_id`, `field_name`, `field_value`) VALUES (:user, :name, :value)')
->execute([
'user' => $currentUser->id,
'name' => $field['field_identity'],
'value' => $_POST['profile_' . $field['field_identity']],
]);
}
@ -657,11 +659,16 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
foreach ($field['field_additional'] as $addKey => $addVal) {
// Add to the array
$store = (isset($_POST['profile_additional_' . $addKey]) || !empty($_POST['profile_additional_' . $addKey])) ? $_POST['profile_additional_' . $addKey] : false;
Database::delete('user_profilefields', ['user_id' => [$currentUser->id, '='], 'field_name' => [$addKey, '=']]);
Database::insert('user_profilefields', [
'user_id' => $currentUser->id,
'field_name' => $addKey,
'field_value' => $store,
DB::prepare('DELETE FROM `{prefix}user_profilefields` WHERE `user_id` = :user AND `field_name` = :id')
->execute([
'user' => $currentUser->id,
'id' => $addKey,
]);
DB::prepare('INSERT INTO `{prefix}user_profilefields` (`user_id`, `field_name`, `field_value`) VALUES (:user, :name, :value)')
->execute([
'user' => $currentUser->id,
'name' => $addKey,
'value' => $store,
]);
}
}
@ -724,13 +731,10 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
[$_POST['birthday_year'], $_POST['birthday_month'], $_POST['birthday_day']]
);
Database::update('users', [
[
'user_birthday' => $birthdate,
],
[
'user_id' => [$currentUser->id, '='],
],
DB::prepare('UPDATE `{prefix}users` SET `user_birthday` = :bd WHERE `user_id` = :id')
->execute([
'bd' => $birthdate,
'id' => $currentUser->id,
]);
}
break;
@ -742,7 +746,11 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
// Go over each field
foreach ($fields as $field) {
Database::delete('user_optionfields', ['user_id' => [$currentUser->id, '='], 'field_name' => [$field['option_id'], '=']]);
DB::prepare('DELETE FROM `{prefix}user_optionfields` WHERE `user_id` = :user AND `field_name` = :id')
->execute([
'user' => $currentUser->id,
'id' => $field['option_id'],
]);
// Make sure the user has sufficient permissions to complete this action
if (!$currentUser->permission(constant('Sakura\Perms\Site::' . $field['option_permission']))) {
@ -751,10 +759,11 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
if (isset($_POST['option_' . $field['option_id']])
&& !empty($_POST['option_' . $field['option_id']])) {
Database::insert('user_optionfields', [
'user_id' => $currentUser->id,
'field_name' => $field['option_id'],
'field_value' => $_POST['option_' . $field['option_id']],
DB::prepare('INSERT INTO `{prefix}user_optionfields` (`user_id`, `field_name`, `field_value`) VALUES (:user, :name, :value)')
->execute([
'user' => $currentUser->id,
'name' => $field['option_id'],
'value' => $_POST['option_' . $field['option_id']],
]);
}
}
@ -792,17 +801,11 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
}
// Update database
Database::update(
'users',
[
[
'user_title' => (isset($_POST['usertitle']) ? $_POST['usertitle'] : null),
],
[
'user_id' => [$currentUser->id, '='],
],
]
);
DB::prepare('UPDATE `{prefix}users` SET `user_title` = :title WHERE `user_id` = :id')
->execute([
'title' => (isset($_POST['usertitle']) ? $_POST['usertitle'] : null),
'id' => $currentUser->id,
]);
// Set render data
$renderData['page'] = [
@ -935,7 +938,11 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
}
// Update database
Database::update('users', [['user_page' => $_POST['userpage']], ['user_id' => [$currentUser->id, '=']]]);
DB::prepare('UPDATE `{prefix}users` SET `user_page` = :up WHERE `user_id` = :id')
->execute([
'up' => $_POST['userpage'],
'id' => $currentUser->id,
]);
// Set render data
$renderData['page'] = [
@ -957,7 +964,11 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
}
// Update database
Database::update('users', [['user_signature' => $_POST['signature']], ['user_id' => [$currentUser->id, '=']]]);
DB::prepare('UPDATE `{prefix}users` SET `user_signature` = :us WHERE `user_id` = :id')
->execute([
'us' => $_POST['signature'],
'id' => $currentUser->id,
]);
// Set render data
$renderData['page'] = [
@ -1038,8 +1049,9 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
// Check if sessionid is set to all
if ($_POST['sessionid'] === 'all') {
// Delete all sessions assigned to the current user
Database::delete('sessions', [
'user_id' => [$currentUser->id, '='],
DB::prepare('DELETE FROM `{prefix}sessions` WHERE `user_id` = :user')
->execute([
'user' => $currentUser->id,
]);
// Set render data
@ -1052,7 +1064,12 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
}
// Check if the session is owned by the current user
if (!Database::fetch('sessions', false, ['user_id' => [$currentUser->id, '='], 'session_id' => [$_POST['sessionid'], '=']])) {
$us = DB::prepare('SELECT * FROM `{prefix}sessions` WHERE `user_id` = :user AND `session_id` = :key');
$us->execute([
'user' => $currentUser->id,
'key' => $_POST['sessionid'],
]);
if (!$us->rowCount()) {
$renderData['page'] = [
'redirect' => $redirect,
'message' => 'The session you tried to kill doesn\'t exist.',
@ -1062,8 +1079,10 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
}
// Delete the session
Database::delete('sessions', [
'session_id' => [$_POST['sessionid'], '='],
DB::prepare('DELETE FROM `{prefix}sessions` WHERE `user_id` = :user AND `session_id` = :session')
->execute([
'user' => $currentUser->id,
'session' => $_POST['sessionid'],
]);
// Set render data
@ -1500,7 +1519,12 @@ if (Users::checkLogin()) {
// Sessions
case 'advanced.sessions':
$renderData['sessions'] = Database::fetch('sessions', true, ['user_id' => [$currentUser->id, '=']]);
$sessions = DB::prepare('SELECT * FROM `{prefix}sessions` WHERE `user_id` = :user');
$sessions->execute([
'user' => $currentUser->id,
]);
$renderData['sessions'] = $sessions->fetchAll();
break;
}

View file

@ -8,7 +8,7 @@
namespace Sakura;
// Define Sakura version
define('SAKURA_VERSION', '20160215');
define('SAKURA_VERSION', '20160219');
define('SAKURA_VLABEL', 'Amethyst');
define('SAKURA_COLOUR', '#9966CC');
@ -62,7 +62,13 @@ Config::init(ROOT . 'config/config.ini');
error_reporting(Config::local('dev', 'show_errors') ? -1 : 0);
// Make the database connection
Database::init(Config::local('database', 'driver'));
DB::open(
Config::local('database', 'driver'),
Config::local('dsn'),
Config::local('database', 'username'),
Config::local('database', 'password'),
Config::local('database', 'prefix')
);
// Check if we're using console
if (php_sapi_name() === 'cli' && !defined('SAKURA_CRON')) {
@ -83,7 +89,7 @@ if (Config::get('no_cron_service')) {
}
// Update last execution time
Database::update('config', [['config_value' => time()], ['config_name' => ['no_cron_last', '=']]]);
Config::set('no_cron_last', time());
}
}
@ -117,7 +123,7 @@ if (!defined('SAKURA_NO_TPL')) {
Template::set($templateName);
// Set base page rendering data
$renderData = [
Template::vars([
'sakura' => [
'versionInfo' => [
'version' => SAKURA_VERSION,
@ -176,10 +182,10 @@ if (!defined('SAKURA_NO_TPL')) {
'get' => $_GET,
'post' => $_POST,
];
]);
// Add the default render data
Template::vars($renderData);
$renderData = [];
// Site closing
if (Config::get('site_closed')) {

View file

@ -12,5 +12,5 @@
</div>
<div class="clear"></div>
<div class="news-post-time">
Posted on <time>{{ post.news_timestamp|date(sakura.dateFormat) }}</time>{% if not (viewPost and postExists) %} <a class="default" href="{{ urls.format('SITE_NEWS_CAT_POST', [post.news_category, post.news_id]) }}#comments">{{ post.news_comments.count }} comment{% if post.news_comments.count != 1 %}s{% endif %}</a>{% endif %}
Posted <time>{{ post.news_timestamp|date(sakura.dateFormat) }}</time>{% if not (viewPost and postExists) %} <a class="default" href="{{ urls.format('SITE_NEWS_CAT_POST', [post.news_category, post.news_id]) }}#comments">{{ post.news_comments.count }} comment{% if post.news_comments.count != 1 %}s{% endif %}</a>{% endif %}
</div>