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

View file

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

View file

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

View file

@ -26,7 +26,11 @@ class Bans
{ {
// Attempt to get a ban from this user // 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 // Reverse the array so new bans are listed first
$bans = array_reverse($bans); $bans = array_reverse($bans);
@ -34,21 +38,22 @@ class Bans
// Go over each ban // Go over each ban
foreach ($bans as $ban) { foreach ($bans as $ban) {
// Check if it hasn't expired // 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 // 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; continue;
} }
// Return the ban if all checks were passed // Return the ban if all checks were passed
return [ return [
'user' => $ban->user_id,
'user' => $ban['user_id'], 'issuer' => $ban->ban_moderator,
'issuer' => $ban['ban_moderator'], 'issued' => $ban->ban_begin,
'issued' => $ban['ban_begin'], 'expires' => $ban->ban_end,
'expires' => $ban['ban_end'], 'reason' => $ban->ban_reason,
'reason' => $ban['ban_reason'],
]; ];
} }

View file

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

View file

@ -63,7 +63,7 @@ class Config
* @param string $key Configuration section. * @param string $key Configuration section.
* @param string $subkey Configuration key. * @param string $subkey Configuration key.
* *
* @return string Configuration value. * @return array|string Configuration value.
*/ */
public static function local($key, $subkey = null) public static function local($key, $subkey = null)
{ {
@ -101,9 +101,13 @@ class Config
// Then return the value // Then return the value
return self::$database[$key]; return self::$database[$key];
} else { } 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) { if ($value) {
self::$database[$key] = $value['config_value']; self::$database[$key] = $value->config_value;
return self::$database[$key]; return self::$database[$key];
} }
} }
@ -115,4 +119,34 @@ class Config
); );
return null; 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\Config;
use Sakura\Database; use Sakura\Database;
use Sakura\DB;
use Sakura\Forum; use Sakura\Forum;
use Sakura\Perms\Forum as ForumPerms; use Sakura\Perms\Forum as ForumPerms;
use Sakura\Template; use Sakura\Template;
@ -31,18 +32,25 @@ class Forums extends Controller
*/ */
public function index() 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 // Merge index specific stuff with the global render data
Template::vars([ Template::vars([
'forum' => (new Forum\Forum()), 'forum' => (new Forum\Forum()),
'stats' => [ 'stats' => [
'userCount' => Database::count('users', ['password_algo' => ['nologin', '!='], 'rank_main' => ['1', '!=']])[0], 'userCount' => $userCount->rowCount(),
'newestUser' => User::construct(Users::getNewestUserId()), 'newestUser' => User::construct(Users::getNewestUserId()),
'lastRegData' => date_diff( 'lastRegData' => date_diff(
date_create(date('Y-m-d', User::construct(Users::getNewestUserId())->registered)), date_create(date('Y-m-d', User::construct(Users::getNewestUserId())->registered)),
date_create(date('Y-m-d')) date_create(date('Y-m-d'))
)->format('%a'), )->format('%a'),
'topicCount' => Database::count('topics')[0], 'topicCount' => $threadCount->rowCount(),
'postCount' => Database::count('posts')[0], 'postCount' => $postCount->rowCount(),
'onlineUsers' => Users::checkAllOnline(), 'onlineUsers' => Users::checkAllOnline(),
], ],
]); ]);

View file

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

View file

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

View file

@ -9,6 +9,7 @@ namespace Sakura\Controllers;
use Sakura\Config; use Sakura\Config;
use Sakura\Database; use Sakura\Database;
use Sakura\DB;
use Sakura\Rank; use Sakura\Rank;
use Sakura\Template; use Sakura\Template;
use Sakura\User as UserContext; 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 the user id is zero check if there was a namechange
if ($profile->id == 0) { if ($profile->id == 0) {
// Fetch from username_history // 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 // Redirect if so
if ($check) { if ($check) {
Template::vars([ Template::vars([
'page' => [
'message' => 'The user this profile belongs to changed their username, you are being redirected.', 'message' => 'The user this profile belongs to changed their username, you are being redirected.',
'redirect' => (new \Sakura\Urls)->format('USER_PROFILE', [$check['user_id']]), 'redirect' => (new \Sakura\Urls)->format('USER_PROFILE', [$check->user_id]),
],
]); ]);
// Print page contents // 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); $mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($data);
// Insert it into the database // Insert it into the database
Database::insert('uploads', [ 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)')
'user_id' => $user->id, ->execute([
'file_data' => $data, 'id' => $user->id,
'file_name' => $name, 'data' => $data,
'file_mime' => $mime, 'name' => $name,
'file_time' => time(), 'mime' => $mime,
'file_expire' => $expire, 'time' => time(),
'expire' => $expire,
]); ]);
// Get the last insert id // Get the last insert id
$id = Database::lastInsertID(); $id = (int) DB::lastID();
// Return a new File object // Return a new File object
return new File($id); return new File($id);
@ -105,17 +106,21 @@ class File
public function __construct($fileId) public function __construct($fileId)
{ {
// Attempt to get the database row // 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 anything was returned populate the variables
if ($fileRow) { if ($fileRow) {
$this->id = $fileRow['file_id']; $this->id = $fileRow->file_id;
$this->user = User::construct($fileRow['user_id']); $this->user = User::construct($fileRow->user_id);
$this->data = $fileRow['file_data']; $this->data = $fileRow->file_data;
$this->name = $fileRow['file_name']; $this->name = $fileRow->file_name;
$this->mime = $fileRow['file_mime']; $this->mime = $fileRow->file_mime;
$this->time = $fileRow['file_time']; $this->time = $fileRow->file_time;
$this->expire = $fileRow['file_expire']; $this->expire = $fileRow->file_expire;
} }
} }
@ -124,8 +129,9 @@ class File
*/ */
public function delete() public function delete()
{ {
Database::delete('uploads', [ DB::prepare('DELETE FROM `{prefix}uploads` WHERE `file_id` = :id')
'file_id' => [$this->id, '='], ->execute([
'id' => $this->id,
]); ]);
} }
} }

View file

@ -8,6 +8,7 @@
namespace Sakura\Forum; namespace Sakura\Forum;
use Sakura\Database; use Sakura\Database;
use Sakura\DB;
use Sakura\Users; use Sakura\Users;
use Sakura\User; use Sakura\User;
use Sakura\Perms; use Sakura\Perms;
@ -118,21 +119,25 @@ class Forum
public function __construct($forumId = 0) public function __construct($forumId = 0)
{ {
// Get the row from the database // 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 // Create permissions object
$this->_permissions = new Perms(Perms::FORUM); $this->_permissions = new Perms(Perms::FORUM);
// Populate the variables // Populate the variables
if ($forumRow) { if ($forumRow) {
$this->id = $forumRow['forum_id']; $this->id = $forumRow->forum_id;
$this->order = $forumRow['forum_order']; $this->order = $forumRow->forum_order;
$this->name = $forumRow['forum_name']; $this->name = $forumRow->forum_name;
$this->description = $forumRow['forum_desc']; $this->description = $forumRow->forum_desc;
$this->link = $forumRow['forum_link']; $this->link = $forumRow->forum_link;
$this->category = $forumRow['forum_category']; $this->category = $forumRow->forum_category;
$this->type = $forumRow['forum_type']; $this->type = $forumRow->forum_type;
$this->icon = $forumRow['forum_icon']; $this->icon = $forumRow->forum_icon;
} elseif ($forumId != 0) { } elseif ($forumId != 0) {
$this->id = -1; $this->id = -1;
} }
@ -173,14 +178,18 @@ class Forum
// Check if _forums is populated // Check if _forums is populated
if (!count($this->_forums)) { if (!count($this->_forums)) {
// Get all rows with the category id set to the forum id // 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 // Create a storage array
$forums = []; $forums = [];
// Create new objects for each forum // Create new objects for each forum
foreach ($forumRows as $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; $this->_forums = $forums;
@ -202,19 +211,18 @@ class Forum
// Check if _threads is populated // Check if _threads is populated
if (!count($this->_threads)) { if (!count($this->_threads)) {
// Get all rows with the forum id for this forum // 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]); $threadRows = DB::prepare('SELECT * FROM `{prefix}topics` WHERE `forum_id` = :forum ORDER BY `topic_type` DESC, `topic_last_reply` DESC');
$sticky = Database::fetch('topics', true, ['forum_id' => [$this->id, '='], 'topic_type' => ['1', '=']], ['topic_last_reply', true]); $threadRows->execute([
$regular = Database::fetch('topics', true, ['forum_id' => [$this->id, '='], 'topic_type' => ['0', '=']], ['topic_last_reply', true]); 'forum' => $this->id,
]);
// Combine them into one array $threadRows = $threadRows->fetchAll();
$threadRows = array_merge($announcements, $sticky, $regular);
// Create a storage array // Create a storage array
$threads = []; $threads = [];
// Create new objects for each thread // Create new objects for each thread
foreach ($threadRows as $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; $this->_threads = $threads;
@ -236,10 +244,14 @@ class Forum
// Check if _firstPost is set // Check if _firstPost is set
if ($this->_firstPost === null) { if ($this->_firstPost === null) {
// Get the row // 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 // 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 // Assign it to a "cache" variable
$this->_firstPost = $post; $this->_firstPost = $post;
@ -261,10 +273,14 @@ class Forum
// Check if _lastPost is set // Check if _lastPost is set
if ($this->_lastPost === null) { if ($this->_lastPost === null) {
// Get the row // 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 // 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 // Assign it to a "cache" variable
$this->_lastPost = $post; $this->_lastPost = $post;
@ -283,7 +299,11 @@ class Forum
*/ */
public function threadCount() 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() 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\Utils;
use Sakura\Database; use Sakura\Database;
use Sakura\DB;
use Sakura\User; use Sakura\User;
use Sakura\BBcode; use Sakura\BBcode;
use Sakura\Config; use Sakura\Config;
@ -114,21 +115,25 @@ class Post
public function __construct($postId) public function __construct($postId)
{ {
// Attempt to get the database row // 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 // Assign data if a row was returned
if ($postRow) { if ($postRow) {
$this->id = $postRow['post_id']; $this->id = $postRow->post_id;
$this->thread = $postRow['topic_id']; $this->thread = $postRow->topic_id;
$this->forum = $postRow['forum_id']; $this->forum = $postRow->forum_id;
$this->poster = User::construct($postRow['poster_id']); $this->poster = User::construct($postRow->poster_id);
$this->ip = $postRow['poster_ip']; $this->ip = $postRow->poster_ip;
$this->time = $postRow['post_time']; $this->time = $postRow->post_time;
$this->subject = $postRow['post_subject']; $this->subject = $postRow->post_subject;
$this->text = $postRow['post_text']; $this->text = $postRow->post_text;
$this->editTime = $postRow['post_edit_time']; $this->editTime = $postRow->post_edit_time;
$this->editReason = $postRow['post_edit_reason']; $this->editReason = $postRow->post_edit_reason;
$this->editUser = User::construct($postRow['post_edit_user']); $this->editUser = User::construct($postRow->post_edit_user);
} }
// Parse the markup // Parse the markup
@ -144,7 +149,7 @@ class Post
* @param int $thread The ID of the thread this post is a reply to. * @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. * @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) public static function create($subject, $text, User $poster, $thread = 0, $forum = 0)
{ {
@ -169,18 +174,19 @@ class Post
} }
// Insert the post // Insert the post
Database::insert('posts', [ 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)')
'topic_id' => $thread->id, ->execute([
'forum_id' => $thread->forum, 'thread' => $thread->id,
'poster_id' => $poster->id, 'forum' => $thread->forum,
'poster_ip' => Net::IP(), 'user' => $poster->id,
'post_time' => time(), 'ip' => Net::IP(),
'post_subject' => $subject, 'time' => time(),
'post_text' => $text, 'subject' => $subject,
'text' => $text,
]); ]);
// Get post id // Get post id
$id = Database::lastInsertID(); $id = (int) DB::lastID();
// Update the last post date // Update the last post date
$thread->lastUpdate(); $thread->lastUpdate();
@ -208,22 +214,19 @@ class Post
$thread = new Thread($this->thread); $thread = new Thread($this->thread);
// Update the post // Update the post
Database::update('posts', [ 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([
'topic_id' => $thread->id, 'post' => $this->id,
'forum_id' => $thread->forum, 'thread' => $thread->id,
'poster_id' => $this->poster->id, 'forum' => $thread->forum,
'poster_ip' => Net::pton(Net::IP()), 'user' => $this->poster->id,
'post_time' => $this->time, 'ip' => Net::pton(Net::IP()),
'post_subject' => $this->subject, 'time' => $this->time,
'post_text' => $this->text, 'subject' => $this->subject,
'post_edit_time' => $this->editTime, 'text' => $this->text,
'post_edit_reason' => $this->editReason, 'edit_time' => $this->editTime,
'post_edit_user' => $this->editUser->id, 'edit_reason' => $this->editReason,
], 'edit_user' => $this->editUser->id,
[
'post_id' => [$this->id, '='],
]
]); ]);
// Return a new post object // Return a new post object

View file

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

View file

@ -31,7 +31,11 @@ class News
{ {
// Get the news posts and assign them to $posts // 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 // Attach poster data
foreach ($posts as $post) { foreach ($posts as $post) {

View file

@ -93,11 +93,30 @@ class Perms
*/ */
public function rank($rid, $conditions = [], $perm = 0) public function rank($rid, $conditions = [], $perm = 0)
{ {
// Merge rank id and additional conditions // Build statement
$conditions = array_merge(['rank_id' => [$rid, '='], 'user_id' => [0, '=']], $conditions); $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 // Fetch from the db
$get = Database::fetch($this->table, false, $conditions); $get = $get->fetch(\PDO::FETCH_ASSOC);
// Check if anything was returned // Check if anything was returned
if ($get && array_key_exists($this->column, $get) && $get['rank_id']) { if ($get && array_key_exists($this->column, $get) && $get['rank_id']) {
@ -128,11 +147,30 @@ class Perms
$perm = $perm | $this->rank($rank, $conditions, $perm); $perm = $perm | $this->rank($rank, $conditions, $perm);
} }
// Merge user id and additional conditions // Build statement
$conditions = array_merge(['user_id' => [$uid, '='], 'rank_id' => [0, '=']], $conditions); $stmt = "SELECT * FROM `{prefix}{$this->table}` WHERE `rank_id` = 0 AND `user_id` = :user";
// 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 // Fetch from the db
$get = Database::fetch($this->table, false, $conditions); $get = $get->fetch(\PDO::FETCH_ASSOC);
// Check if anything was returned // Check if anything was returned
if ($get && array_key_exists($this->column, $get) && $get['user_id']) { if ($get && array_key_exists($this->column, $get) && $get['user_id']) {

View file

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

View file

@ -53,9 +53,10 @@ class Session
public function destroy() public function destroy()
{ {
// Invalidate the session key // Invalidate the session key
Database::delete('sessions', [ DB::prepare('DELETE FROM `{prefix}sessions` WHERE `session_key` = :key AND `user_id` = :user')
'session_key' => [$this->sessionId, '='], ->execute([
'user_id' => [$this->userId, '='], 'key' => $this->sessionId,
'user' => $this->userId,
]); ]);
// Unset userId and sessionId // Unset userId and sessionId
@ -74,7 +75,10 @@ class Session
public function destroyAll() public function destroyAll()
{ {
// Delete all database entries with this user in it // 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 // Destroy this session to finish it off
$this->destroy(); $this->destroy();
@ -93,14 +97,15 @@ class Session
$session = hash('sha256', $this->userId . base64_encode('sakura' . mt_rand(0, 99999999)) . time()); $session = hash('sha256', $this->userId . base64_encode('sakura' . mt_rand(0, 99999999)) . time());
// Insert the session into the database // Insert the session into the database
Database::insert('sessions', [ 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)')
'user_id' => $this->userId, ->execute([
'user_ip' => Net::pton(Net::IP()), 'id' => $this->userId,
'user_agent' => Utils::cleanString(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'No user agent header.'), 'ip' => Net::pton(Net::IP()),
'session_key' => $session, 'agent' => Utils::cleanString(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'No user agent header.'),
'session_start' => time(), 'key' => $session,
'session_expire' => time() + 604800, 'start' => time(),
'session_remember' => $permanent ? '1' : '0', 'end' => time() + 604800,
'remember' => $permanent ? '1' : '0',
]); ]);
// Return the session key // Return the session key
@ -115,10 +120,12 @@ class Session
public function validate() public function validate()
{ {
// Get session from database // Get session from database
$session = Database::fetch('sessions', false, [ $session = DB::prepare('SELECT * FROM `{prefix}sessions` WHERE `user_id` = :user AND `session_key` = :key');
'user_id' => [$this->userId, '='], $session->execute([
'session_key' => [$this->sessionId, '='], 'user' => $this->userId,
'key' => $this->sessionId,
]); ]);
$session = $session->fetch();
// Check if we actually got something in return // Check if we actually got something in return
if (!$session) { if (!$session) {
@ -126,13 +133,13 @@ class Session
} }
// Check if the session expired // Check if the session expired
if ($session['session_expire'] < time()) { if ($session->session_expire < time()) {
// ...and return false // ...and return false
return 0; return 0;
} }
// IP Check // 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 // Origin checking
if ($ipCheck) { if ($ipCheck) {
@ -178,18 +185,15 @@ class Session
} }
// If the remember flag is set extend the session time // If the remember flag is set extend the session time
if ($session['session_remember']) { if ($session->session_remember) {
Database::update('sessions', [ DB::prepare('UPDATE `{prefix}sessions` SET `session_expire` = :expire WHERE `session_id` = :id')
[ ->execute([
'session_expire' => time() + 604800, 'expire' => time() + 604800,
], 'id' => $session->session_id,
[
'session_id' => [$session['session_id'], '='],
],
]); ]);
} }
// Return 2 if the remember flag is set and return 1 if not // 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); $password = Hashing::createHash($password);
// Insert the user into the database // Insert the user into the database
Database::insert('users', [ 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)')
'username' => $username, ->execute([
'username_clean' => $usernameClean, 'uname' => $username,
'password_hash' => $password[3], 'uname_clean' => $usernameClean,
'password_salt' => $password[2], 'pw_hash' => $password[3],
'password_algo' => $password[0], 'pw_salt' => $password[2],
'password_iter' => $password[1], 'pw_algo' => $password[0],
'pw_iter' => $password[1],
'email' => $emailClean, 'email' => $emailClean,
'rank_main' => 0, 'rank' => 0,
'register_ip' => Net::pton(Net::IP()), 'r_ip' => Net::pton(Net::IP()),
'last_ip' => Net::pton(Net::IP()), 'l_ip' => Net::pton(Net::IP()),
'user_registered' => time(), 'registered' => time(),
'user_last_online' => 0, 'l_online' => 0,
'user_country' => Utils::getCountryCode(), 'country' => Utils::getCountryCode(),
]); ]);
// Get the last id // Get the last id
$userId = Database::lastInsertID(); $userId = DB::lastID();
// Create a user object // Create a user object
$user = self::construct($userId); $user = self::construct($userId);
@ -298,49 +299,51 @@ class User
private function __construct($uid) private function __construct($uid)
{ {
// Get the user database row // Get the user database row
$userRow = Database::fetch( $userRow = DB::prepare('SELECT * FROM `{prefix}users` WHERE `user_id` = :id OR `username_clean` = :clean');
'users', $userRow->execute([
false, 'id' => $uid,
[ 'clean' => Utils::cleanString($uid, true, true),
'user_id' => [$uid, '=', true], ]);
'username_clean' => [Utils::cleanString($uid, true), '=', true], $userRow = $userRow->fetch();
]
);
// Populate the variables // Populate the variables
if ($userRow) { if ($userRow) {
$this->id = $userRow['user_id']; $this->id = $userRow->user_id;
$this->username = $userRow['username']; $this->username = $userRow->username;
$this->usernameClean = $userRow['username_clean']; $this->usernameClean = $userRow->username_clean;
$this->passwordHash = $userRow['password_hash']; $this->passwordHash = $userRow->password_hash;
$this->passwordSalt = $userRow['password_salt']; $this->passwordSalt = $userRow->password_salt;
$this->passwordAlgo = $userRow['password_algo']; $this->passwordAlgo = $userRow->password_algo;
$this->passwordIter = $userRow['password_iter']; $this->passwordIter = $userRow->password_iter;
$this->passwordChan = $userRow['password_chan']; $this->passwordChan = $userRow->password_chan;
$this->email = $userRow['email']; $this->email = $userRow->email;
$this->mainRankId = $userRow['rank_main']; $this->mainRankId = $userRow->rank_main;
$this->colour = $userRow['user_colour']; $this->colour = $userRow->user_colour;
$this->registerIp = $userRow['register_ip']; $this->registerIp = $userRow->register_ip;
$this->lastIp = $userRow['last_ip']; $this->lastIp = $userRow->last_ip;
$this->title = $userRow['user_title']; $this->title = $userRow->user_title;
$this->registered = $userRow['user_registered']; $this->registered = $userRow->user_registered;
$this->lastOnline = $userRow['user_last_online']; $this->lastOnline = $userRow->user_last_online;
$this->birthday = $userRow['user_birthday']; $this->birthday = $userRow->user_birthday;
$this->country = $userRow['user_country']; $this->country = $userRow->user_country;
$this->avatar = $userRow['user_avatar']; $this->avatar = $userRow->user_avatar;
$this->background = $userRow['user_background']; $this->background = $userRow->user_background;
$this->header = $userRow['user_header']; $this->header = $userRow->user_header;
$this->page = $userRow['user_page']; $this->page = $userRow->user_page;
$this->signature = $userRow['user_signature']; $this->signature = $userRow->user_signature;
} }
// Get all ranks // 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 // Get the rows for all the ranks
foreach ($ranks as $rank) { foreach ($ranks as $rank) {
// Store the database row in the array // 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 // Check if ranks were set
@ -423,10 +426,13 @@ class User
public function isOnline() public function isOnline()
{ {
// Get all sessions // 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 there's no entries just straight up return false
if (!$sessions) { if (!$sessions->rowCount()) {
return false; return false;
} }
@ -441,19 +447,19 @@ class User
*/ */
public function forumStats() 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 [ return [
'posts' => Database::count( 'posts' => $posts->rowCount(),
'posts', 'topics' => $threads->rowCount(),
['poster_id' => [$this->id, '=']]
)[0],
'topics' => count(Database::fetch(
'posts',
true,
['poster_id' => [$this->id, '=']],
['post_time'],
null,
['topic_id']
)),
]; ];
} }
@ -476,9 +482,10 @@ class User
// Save to the database // Save to the database
foreach ($ranks as $rank) { foreach ($ranks as $rank) {
Database::insert('user_ranks', [ DB::prepare('INSERT INTO `{prefix}ranks` (`rank_id`, `user_id`) VALUES (:rank, :user)')
'rank_id' => $rank, ->execute([
'user_id' => $this->id, 'rank' => $rank,
'user' => $this->id,
]); ]);
} }
} }
@ -495,7 +502,11 @@ class User
// Iterate over the ranks // Iterate over the ranks
foreach ($remove as $rank) { 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) public function setMainRank($rank)
{ {
// If it does exist update their row // If it does exist update their row
Database::update('users', [ DB::prepare('UPDATE `{prefix}users` SET `rank_main` = :rank WHERE `user_id` = :id')
[ ->execute([
'rank_main' => $rank, 'rank' => $rank,
], 'id' => $this->id,
[
'user_id' => [$this->id, '='],
],
]); ]);
// Return true if everything was successful // Return true if everything was successful
@ -571,10 +579,11 @@ class User
} }
// Add friend // Add friend
Database::insert('friends', [ DB::prepare('INSERT INTO `{prefix}friends` (`user_id`, `friend_id`, `friend_timestamp`) VALUES (:user, :friend, :time)')
'user_id' => $this->id, ->execute([
'friend_id' => $uid, 'user' => $this->id,
'friend_timestamp' => time(), 'friend' => $uid,
'time' => time(),
]); ]);
// Return true because yay // Return true because yay
@ -599,17 +608,20 @@ class User
return [0, 'USER_NOT_EXIST']; 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 // Remove friend
Database::delete('friends', [ $rem->execute([
'user_id' => [$this->id, '='], 'user' => $this->id,
'friend_id' => [$uid, '='], 'friend' => $uid,
]); ]);
// Attempt to remove the request // Attempt to remove the request
if ($deleteRequest) { if ($deleteRequest) {
Database::delete('friends', [ $rem->execute([
'friend_id' => [$this->id, '='], 'user' => $uid,
'user_id' => [$uid, '='], 'friend' => $this->id,
]); ]);
} }
@ -627,16 +639,19 @@ class User
public function isFriends($with) public function isFriends($with)
{ {
// Accepted from this user // Accepted from this user
$user = Database::count('friends', [ $get = DB::prepare('SELECT * FROM `{prefix}friends` WHERE `user_id` = :user AND `friend_id` = :friend');
'user_id' => [$this->id, '='], $get->execute([
'friend_id' => [$with, '='], 'user' => $this->id,
])[0]; 'friend' => $with,
]);
$user = $get->rowCount();
// And the other user // And the other user
$friend = Database::count('friends', [ $get->execute([
'user_id' => [$with, '='], 'user' => $with,
'friend_id' => [$this->id, '='], 'friend' => $this->id,
])[0]; ]);
$friend = $get->rowCount();
if ($user && $friend) { if ($user && $friend) {
return 2; // Mutual friends return 2; // Mutual friends
@ -663,34 +678,72 @@ class User
// Select the correct level // Select the correct level
switch ($level) { switch ($level) {
// Mutual
case 2: case 2:
// Get all the current user's friends // 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 // 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 // Create a difference map
$users = array_intersect($self, $others); $users = array_intersect($self, $others);
break; break;
// Non-mutual (from user perspective)
case 1: 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; break;
// All friend cases
case 0: case 0:
default: default:
// Get all the current user's friends // 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 // 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 // Create a difference map
$users = array_merge($others, $self); $users = array_merge($others, $self);
break; break;
// Open requests
case -1: case -1:
// Get all the current user's friends // 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 // 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 // Create a difference map
$users = array_diff($others, $self); $users = array_diff($others, $self);
break; break;
@ -770,8 +823,17 @@ class User
// Create array and get values // Create array and get values
$profile = []; $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) { $profileValueKeys = array_map(function ($a) {
return $a['field_name']; return $a['field_name'];
}, $profileValuesRaw); }, $profileValuesRaw);
@ -849,8 +911,17 @@ class User
// Create array and get values // Create array and get values
$options = []; $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) { $optionValueKeys = array_map(function ($a) {
return $a['field_name']; return $a['field_name'];
}, $optionValuesRaw); }, $optionValuesRaw);
@ -901,9 +972,11 @@ class User
} }
// Attempt to retrieve the premium record from the database // Attempt to retrieve the premium record from the database
$getRecord = Database::fetch('premium', false, [ $getRecord = DB::prepare('SELECT * FROM `{prefix}premium` WHERE `user_id` = :user');
'user_id' => [$this->id, '='], $getRecord->execute([
'user' => $this->id,
]); ]);
$getRecord = $getRecord->fetch();
// If nothing was returned just return false // If nothing was returned just return false
if (empty($getRecord)) { if (empty($getRecord)) {
@ -911,12 +984,12 @@ class User
} }
// Check if the Tenshi hasn't expired // Check if the Tenshi hasn't expired
if ($getRecord['premium_expire'] < time()) { if ($getRecord->premium_expire < time()) {
return [0, $getRecord['premium_start'], $getRecord['premium_expire']]; return [0, $getRecord->premium_start, $getRecord->premium_expire];
} }
// Else return the start and expiration date // 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() public function getWarnings()
{ {
// Do the database query // Do the database query
$getWarnings = Database::fetch('warnings', true, [ $getWarnings = DB::prepare('SELECT * FROM `{prefix}warnings` WHERE `user_id` = :user');
'user_id' => [$this->id, '='], $getWarnings->execute([
'user' => $this->id,
]); ]);
$getWarnings = $getWarnings->fetchAll(\PDO::FETCH_ASSOC);
// Storage array // Storage array
$warnings = []; $warnings = [];
@ -938,7 +1013,10 @@ class User
foreach ($getWarnings as $warning) { foreach ($getWarnings as $warning) {
// Check if it hasn't expired // Check if it hasn't expired
if ($warning['warning_expires'] < time()) { 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; continue;
} }
@ -1001,12 +1079,13 @@ class User
public function getUsernameHistory() public function getUsernameHistory()
{ {
// Do the database query // Do the database query
$changes = Database::fetch('username_history', true, [ $changes = DB::prepare('SELECT * FROM `{prefix}username_history` WHERE `user_id` = :user ORDER BY `change_id` DESC');
'user_id' => [$this->id, '='], $changes->execute([
], ['change_id', true]); 'user' => $this->id,
]);
// Return all the warnings // Return all the changes
return $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 // Check if this username hasn't been used in the last amount of days set in the config
$getOld = Database::fetch('username_history', false, [ $getOld = DB::prepare('SELECT * FROM `{prefix}username_history` WHERE `username_old_clean` = :clean AND `change_time` > :time ORDER BY `change_id` DESC');
'username_old_clean' => [$username_clean, '='], $getOld->execute([
'change_time' => [(Config::get('old_username_reserve') * 24 * 60 * 60), '>'], 'clean' => $username_clean,
], ['change_id', true]); 'time' => (Config::get('old_username_reserve') * 24 * 60 * 60),
]);
$getOld = $getOld->fetch();
// Check if anything was returned // 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']]; return [0, 'TOO_RECENT', $getOld['change_time']];
} }
// Check if the username is already in use // Check if the username is already in use
$getInUse = Database::fetch('users', false, [ $getInUse = DB::prepare('SELECT * FROM `{prefix}users` WHERE `username_clean` = :clean');
'username_clean' => [$username_clean, '='], $getInUse->execute([
'clean' => $username_clean,
]); ]);
$getInUse = $getInUse->fetch();
// Check if anything was returned // Check if anything was returned
if ($getInUse) { if ($getInUse) {
return [0, 'IN_USE', $getInUse['user_id']]; return [0, 'IN_USE', $getInUse->user_id];
} }
// Insert into username_history table // Insert into username_history table
Database::insert('username_history', [ 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)')
'change_time' => time(), ->execute([
'user_id' => $this->id, 'time' => time(),
'username_new' => $username, 'user' => $this->id,
'username_new_clean' => $username_clean, 'new' => $username,
'username_old' => $this->username, 'new_clean' => $username_clean,
'username_old_clean' => $this->usernameClean, 'old' => $this->username,
'old_clean' => $this->usernameClean,
]); ]);
// Update userrow // Update userrow
Database::update('users', [ DB::prepare('UPDATE `{prefix}users` SET `username` = :username, `username_clean` = :clean WHERE `user_id` = :id')
[ ->execute([
'username' => $username, 'username' => $username,
'username_clean' => $username_clean, 'clean' => $username_clean,
], 'id' => $this->id,
[
'user_id' => [$this->id, '='],
],
]); ]);
// Return success // Return success
@ -1092,23 +1173,22 @@ class User
} }
// Check if the username is already in use // Check if the username is already in use
$getInUse = Database::fetch('users', false, [ $getInUse = DB::prepare('SELECT * FROM `{prefix}users` WHERE `email` = :email');
'email' => [$email, '='], $getInUse->execute([
'email' => $email,
]); ]);
$getInUse = $getInUse->fetch();
// Check if anything was returned // Check if anything was returned
if ($getInUse) { if ($getInUse) {
return [0, 'IN_USE', $getInUse['user_id']]; return [0, 'IN_USE', $getInUse->user_id];
} }
// Update userrow // Update userrow
Database::update('users', [ DB::prepare('UPDATE `{prefix}users` SET `email` = :email WHERE `user_id` = :id')
[ ->execute([
'email' => $email, 'email' => $email,
], 'id' => $this->id,
[
'user_id' => [$this->id, '='],
],
]); ]);
// Return success // Return success
@ -1159,17 +1239,14 @@ class User
$password = Hashing::createHash($new); $password = Hashing::createHash($new);
// Update userrow // Update userrow
Database::update('users', [ 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([
'password_hash' => $password[3], 'hash' => $password[3],
'password_salt' => $password[2], 'salt' => $password[2],
'password_algo' => $password[0], 'algo' => $password[0],
'password_iter' => $password[1], 'iter' => $password[1],
'password_chan' => time(), 'chan' => time(),
], 'id' => $this->id,
[
'user_id' => [$this->id, '='],
],
]); ]);
// Return success // Return success

View file

@ -85,13 +85,10 @@ class Users
} }
// Update last online // Update last online
Database::update('users', [ DB::prepare('UPDATE `{prefix}users` SET `user_last_online` = :lo WHERE `user_id` = :id')
[ ->execute([
'user_last_online' => time(), 'lo' => time(),
], 'id' => $uid,
[
'user_id' => [$uid, '='],
],
]); ]);
// Update the premium meta // Update the premium meta
@ -119,11 +116,12 @@ class Users
} }
// Check if we haven't hit the rate limit // Check if we haven't hit the rate limit
$rates = Database::fetch('login_attempts', true, [ $rates = DB::prepare('SELECT * FROM `{prefix}login_attempts` WHERE `attempt_ip` = :ip AND `attempt_timestamp` > :time AND `attempt_success` = 0');
'attempt_ip' => [Net::pton(Net::IP()), '='], $rates->execute([
'attempt_timestamp' => [time() - 1800, '>'], 'ip' => Net::pton(Net::IP()),
'attempt_success' => [0, '='], 'time' => time() - 1800,
]); ]);
$rates = $rates->fetchAll(\PDO::FETCH_ASSOC);
if (count($rates) > 4) { if (count($rates) > 4) {
return [0, 'RATE_LIMIT']; return [0, 'RATE_LIMIT'];
@ -287,7 +285,11 @@ class Users
} }
// Check if the e-mail has already been used // 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']; return [0, 'EMAIL_EXISTS'];
} }
@ -338,10 +340,12 @@ class Users
$emailClean = Utils::cleanString($email, true); $emailClean = Utils::cleanString($email, true);
// Do database request // Do database request
$user = Database::fetch('users', false, [ $user = DB::prepare('SELECT * FROM `{prefix}users` WHERE `username_clean` = :clean AND `email` = :email');
'username_clean' => [$usernameClean, '='], $user->execute([
'email' => [$emailClean, '='], 'clean' => $usernameClean,
'email' => $emailClean,
]); ]);
$user = $user->fetch(\PDO::FETCH_ASSOC);
// Check if user exists // Check if user exists
if (count($user) < 2) { if (count($user) < 2) {
@ -417,20 +421,16 @@ class Users
// Hash the password // Hash the password
$password = Hashing::createHash($newpass); $password = Hashing::createHash($newpass);
$time = time();
// Update the user // Update the user
Database::update('users', [ 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([
'password_hash' => $password[3], 'hash' => $password[3],
'password_salt' => $password[2], 'salt' => $password[2],
'password_algo' => $password[0], 'algo' => $password[0],
'password_iter' => $password[1], 'iter' => $password[1],
'password_chan' => $time, 'chan' => time(),
], 'id' => $uid,
[
'user_id' => [$uid, '='],
],
]); ]);
// Return success // Return success
@ -457,10 +457,12 @@ class Users
$emailClean = Utils::cleanString($email, true); $emailClean = Utils::cleanString($email, true);
// Do database request // Do database request
$user = Database::fetch('users', false, [ $user = DB::prepare('SELECT * FROM `{prefix}users` WHERE `username_clean` = :clean AND `email` = :email');
'username_clean' => [$usernameClean, '='], $user->execute([
'email' => [$emailClean, '='], 'clean' => $usernameClean,
'email' => $emailClean,
]); ]);
$user = $user->fetch(\PDO::FETCH_ASSOC);
// Check if user exists // Check if user exists
if (count($user) < 2) { if (count($user) < 2) {
@ -580,21 +582,23 @@ class Users
/** /**
* Check if a user exists. * Check if a user exists.
* *
* @param mixed $user The Username or ID. * @param mixed $id The Username or ID.
* @param bool $id Use id instead. * @param mixed $unused Unused variable.
* *
* @return mixed Returns the ID if it exists, false otherwise. * @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 // 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 (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() public static function getProfileFields()
{ {
// Get profile fields // 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 there's nothing just return null
if (!count($profileFields)) { if (!count($profileFields)) {
@ -634,7 +640,9 @@ class Users
public static function getOptionFields() public static function getOptionFields()
{ {
// Get option fields // 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 there's nothing just return null
if (!count($optionFields)) { if (!count($optionFields)) {
@ -672,10 +680,14 @@ class Users
$return = []; $return = [];
// Get all online users in the past 5 minutes // 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) { foreach ($getAll as $user) {
$return[] = User::construct($user['user_id']); $return[] = User::construct($user->user_id);
} }
// Return all the online users // Return all the online users
@ -693,9 +705,11 @@ class Users
public static function addUserPremium($id, $seconds) public static function addUserPremium($id, $seconds)
{ {
// Check if there's already a record of premium for this user in the database // Check if there's already a record of premium for this user in the database
$getUser = Database::fetch('premium', false, [ $getUser = DB::prepare('SELECT * FROM `{prefix}premium` WHERE `user_id` = :user');
'user_id' => [$id, '='], $getUser->execute([
'user' => $id,
]); ]);
$getUser = $getUser->fetch(\PDO::FETCH_ASSOC);
// Calculate the (new) start and expiration timestamp // Calculate the (new) start and expiration timestamp
$start = isset($getUser['premium_start']) ? $getUser['premium_start'] : time(); $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 the user already exists do an update call, otherwise an insert call
if (empty($getUser)) { if (empty($getUser)) {
Database::insert('premium', [ DB::prepare('INSERT INTO `{prefix}premium` (`user_id`, `premium_start`, `premium_expire`) VALUES (:user, :start, :expire)')
'user_id' => $id, ->execute([
'premium_start' => $start, 'user' => $id,
'premium_expire' => $expire, 'start' => $start,
'expire' => $expire,
]); ]);
} else { } else {
Database::update('premium', [ DB::prepare('UPDATE `{prefix}premium` SET `premium_expire` = :expire WHERE `user_id` = :id')
[ ->execute([
'premium_expire' => $expire, 'expire' => $expire,
], 'user_id' => $id,
[
'user_id' => [$id, '='],
],
]); ]);
} }
@ -751,8 +763,9 @@ class Users
} }
} elseif (!$check[0]) { } elseif (!$check[0]) {
// Remove the expired entry // Remove the expired entry
Database::delete('premium', [ DB::prepare('DELETE FROM `{prefix}premium` WHERE `user_id` = :user')
'user_id' => [$user->id, '='], ->execute([
'user' => $user->id,
]); ]);
// Else remove the rank from them // Else remove the rank from them
@ -769,56 +782,18 @@ class Users
*/ */
public static function getUsersByIP($ip) public static function getUsersByIP($ip)
{ {
// Get users by registration IP // Get the users
$registeredFrom = Database::fetch('users', true, ['register_ip' => [$ip, '=']]); $users = DB::prepare('SELECT * FROM `{prefix}users` WHERE `register_ip` = :rip OR `last_ip` = :lip');
$users->execute([
// Get users by last IP 'rip' => $ip,
$lastFrom = Database::fetch('users', true, ['last_ip' => [$ip, '='], 'register_ip' => [$ip, '!=']]); 'lip' => $ip,
]);
// Merge the arrays $users = $users->fetchAll(\PDO::FETCH_ASSOC);
$users = array_merge($registeredFrom, $lastFrom);
// Return the array with users // Return the array with users
return $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. * Get all ranks.
* *
@ -827,14 +802,16 @@ class Users
public static function getAllRanks() public static function getAllRanks()
{ {
// Execute query // Execute query
$getRanks = Database::fetch('ranks', true); $getRanks = DB::prepare('SELECT * FROM `{prefix}ranks`');
$getRanks->execute();
$getRanks = $getRanks->fetchAll();
// Define variable // Define variable
$ranks = []; $ranks = [];
// Reorder shit // Reorder shit
foreach ($getRanks as $rank) { 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 // 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) public static function getNotifications($uid = null, $timediff = 0, $excludeRead = true, $markRead = false)
{ {
// Prepare conditions // Prepare conditions
$conditions = []; $uid = $uid ? $uid : self::checkLogin()[0];
$conditions['user_id'] = [($uid ? $uid : self::checkLogin()[0]), '=']; $time = $timediff ? time() - $timediff : '%';
$read = $excludeRead ? '0' : '%';
if ($timediff) {
$conditions['alert_timestamp'] = [time() - $timediff, '>'];
}
if ($excludeRead) {
$conditions['alert_read'] = [0, '='];
}
// Get notifications for the database // 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 // Mark the notifications as read
if ($markRead) { if ($markRead) {
@ -895,13 +871,10 @@ class Users
public static function markNotificationRead($id, $mode = true) public static function markNotificationRead($id, $mode = true)
{ {
// Execute an update statement // Execute an update statement
Database::update('notifications', [ DB::prepare('UPDATE `{prefix}notifications` SET `alert_read` = :read WHERE `alert_id` = :id')
[ ->execute([
'alert_read' => ($mode ? 1 : 0), 'read' => ($mode ? 1 : 0),
], 'id' => $id,
[
'alert_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) 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 // Insert it into the database
Database::insert('notifications', [ 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)')
'user_id' => $user, ->execute([
'alert_timestamp' => $time, 'user' => $user,
'alert_read' => 0, 'time' => time(),
'alert_sound' => ($sound ? 1 : 0), 'read' => 0,
'alert_title' => $title, 'sound' => ($sound ? 1 : 0),
'alert_text' => $text, 'title' => $title,
'alert_link' => $link, 'text' => $text,
'alert_img' => $img, 'link' => $link,
'alert_timeout' => $timeout, 'img' => $img,
'timeout' => $timeout,
]); ]);
} }
@ -942,6 +913,12 @@ class Users
*/ */
public static function getNewestUserId() 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())); $backtrace = base64_encode(json_encode(debug_backtrace()));
// Check if this error has already been logged in the past // Check if this error has already been logged in the past
if ($past = Database::fetch( $past = DB::prepare('SELECT * FROM `{prefix}error_log` WHERE `error_backtrace` = :bc OR (`error_string` = :str AND `error_line` = :li)');
'error_log', $past->execute([
false, 'bc' => $backtrace,
[ 'str' => $errstr,
'error_backtrace' => [$backtrace, '=', true], 'li' => $errline,
'error_string' => [$errstr, '='], ]);
'error_line' => [$errline, '='], $past = $past->fetch();
]
)) { if ($past) {
// If so assign the errid // If so assign the errid
$errid = $past['error_id']; $errid = $past->error_id;
} else { } else {
// Create an error ID // Create an error ID
$errid = substr(md5(microtime()), rand(0, 22), 10); $errid = substr(md5(microtime()), rand(0, 22), 10);
// Log the error // Log the error
Database::insert('error_log', [ 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)')
'error_id' => $errid, ->execute([
'error_timestamp' => date("r"), 'id' => $errid,
'error_revision' => SAKURA_VERSION, 'time' => date("r"),
'error_type' => $errno, 'rev' => SAKURA_VERSION,
'error_line' => $errline, 'type' => $errno,
'error_string' => $errstr, 'line' => $errline,
'error_file' => $errfile, 'string' => $errstr,
'error_backtrace' => $backtrace, 'file' => $errfile,
'bc' => $backtrace,
]); ]);
} }
} }
@ -430,7 +431,9 @@ class Utils
$data = []; $data = [];
// Get database stuff // 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 // Add raw table data to data array
$data['table'] = $table; $data['table'] = $table;
@ -465,11 +468,12 @@ class Utils
*/ */
public static function updatePremiumTracker($id, $amount, $comment) public static function updatePremiumTracker($id, $amount, $comment)
{ {
Database::insert('premium_log', [ DB::prepare('INSERT INTO `{prefix}premium_log` (`user_id`, `transaction_amount`, `transaction_date`, `transaction_comment`) VALUES (:user, :amount, :date, :comment)')
'user_id' => $id, ->execute([
'transaction_amount' => $amount, 'user' => $id,
'transaction_date' => time(), 'amount' => $amount,
'transaction_comment' => $comment, 'date' => time(),
'comment' => $comment,
]); ]);
} }

View file

@ -184,11 +184,12 @@ if (isset($_REQUEST['mode'])) {
// Check if we're not RATE_LIMIT // Check if we're not RATE_LIMIT
if ($login[1] != 'RATE_LIMIT') { if ($login[1] != 'RATE_LIMIT') {
// Add to database // Add to database
Database::insert('login_attempts', [ DB::prepare('INSERT INTO `{prefix}login_attempts` (`attempt_success`, `attempt_timestamp`, `attempt_ip`, `user_id`) VALUES (:succ, :time, :ip, :user)')
'attempt_success' => $login[0], ->execute([
'attempt_timestamp' => time(), 'succ' => $login[0],
'attempt_ip' => Net::pton(Net::IP()), 'time' => time(),
'user_id' => isset($login[2]) ? $login[2] : 0, '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)); $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 // Include emotes and bbcodes
$posting = [ $posting = [
'emoticons' => Database::fetch('emoticons'), 'emoticons' => $emotes->fetchAll(),
]; ];
// Check if we're in reply mode // Check if we're in reply mode
@ -198,8 +201,9 @@ if ($mode != 'f') {
// Post deletion code // Post deletion code
if (isset($_POST['yes'])) { if (isset($_POST['yes'])) {
// Delete the post // Delete the post
Database::delete('posts', [ DB::prepare('DELETE FROM `{prefix}posts` WHERE `post_id` = :post')
'post_id' => [$_POST['post_id'], '='], ->execute([
'post' => $_POST['post_id'],
]); ]);
// Reload the topic // 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 there's no more posts left in the topic delete it as well
if (!$thread->replyCount()) { if (!$thread->replyCount()) {
Database::delete('topics', [ DB::prepare('DELETE FROM `{prefix}topics` WHERE `topic_id` = :thread')
'topic_id' => [$thread->id, '='], ->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 // Assign the correct column and title to a variable
switch ($mode) { switch ($mode) {
case 'background': case 'background':
$column = 'user_background'; $stmt = 'UPDATE `{prefix}users` SET `user_background` = :img WHERE `user_id` = :user';
$msgTitle = 'Background'; $msgTitle = 'Background';
$current = $currentUser->background; $current = $currentUser->background;
$permission = $currentUser->permission(Site::CHANGE_BACKGROUND); $permission = $currentUser->permission(Site::CHANGE_BACKGROUND);
break; break;
case 'header': case 'header':
$column = 'user_header'; $stmt = 'UPDATE `{prefix}users` SET `user_header` = :img WHERE `user_id` = :user';
$msgTitle = 'Header'; $msgTitle = 'Header';
$current = $currentUser->header; $current = $currentUser->header;
$permission = $currentUser->permission(Site::CHANGE_HEADER); $permission = $currentUser->permission(Site::CHANGE_HEADER);
@ -466,7 +466,7 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
case 'avatar': case 'avatar':
default: default:
$column = 'user_avatar'; $stmt = 'UPDATE `{prefix}users` SET `user_avatar` = :img WHERE `user_id` = :user';
$msgTitle = 'Avatar'; $msgTitle = 'Avatar';
$current = $currentUser->avatar; $current = $currentUser->avatar;
$permission = $currentUser->permission(Site::CHANGE_AVATAR); $permission = $currentUser->permission(Site::CHANGE_AVATAR);
@ -617,13 +617,10 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
} }
// Update table // Update table
Database::update('users', [ DB::prepare($stmt)
[ ->execute([
$column => $fileId, 'img' => $fileId,
], 'user' => $currentUser->id,
[
'user_id' => [$currentUser->id, '='],
],
]); ]);
// Set render data // Set render data
@ -643,11 +640,16 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
foreach ($fields as $field) { foreach ($fields as $field) {
// Add to the store array // Add to the store array
if (isset($_POST['profile_' . $field['field_identity']]) && !empty($_POST['profile_' . $field['field_identity']])) { 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'], '=']]); DB::prepare('DELETE FROM `{prefix}user_profilefields` WHERE `user_id` = :user AND `field_name` = :id')
Database::insert('user_profilefields', [ ->execute([
'user_id' => $currentUser->id, 'user' => $currentUser->id,
'field_name' => $field['field_identity'], 'id' => $field['field_identity'],
'field_value' => $_POST['profile_' . $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) { foreach ($field['field_additional'] as $addKey => $addVal) {
// Add to the array // Add to the array
$store = (isset($_POST['profile_additional_' . $addKey]) || !empty($_POST['profile_additional_' . $addKey])) ? $_POST['profile_additional_' . $addKey] : false; $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, '=']]); DB::prepare('DELETE FROM `{prefix}user_profilefields` WHERE `user_id` = :user AND `field_name` = :id')
Database::insert('user_profilefields', [ ->execute([
'user_id' => $currentUser->id, 'user' => $currentUser->id,
'field_name' => $addKey, 'id' => $addKey,
'field_value' => $store, ]);
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']] [$_POST['birthday_year'], $_POST['birthday_month'], $_POST['birthday_day']]
); );
Database::update('users', [ DB::prepare('UPDATE `{prefix}users` SET `user_birthday` = :bd WHERE `user_id` = :id')
[ ->execute([
'user_birthday' => $birthdate, 'bd' => $birthdate,
], 'id' => $currentUser->id,
[
'user_id' => [$currentUser->id, '='],
],
]); ]);
} }
break; break;
@ -742,7 +746,11 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
// Go over each field // Go over each field
foreach ($fields as $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 // Make sure the user has sufficient permissions to complete this action
if (!$currentUser->permission(constant('Sakura\Perms\Site::' . $field['option_permission']))) { 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']]) if (isset($_POST['option_' . $field['option_id']])
&& !empty($_POST['option_' . $field['option_id']])) { && !empty($_POST['option_' . $field['option_id']])) {
Database::insert('user_optionfields', [ DB::prepare('INSERT INTO `{prefix}user_optionfields` (`user_id`, `field_name`, `field_value`) VALUES (:user, :name, :value)')
'user_id' => $currentUser->id, ->execute([
'field_name' => $field['option_id'], 'user' => $currentUser->id,
'field_value' => $_POST['option_' . $field['option_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 // Update database
Database::update( DB::prepare('UPDATE `{prefix}users` SET `user_title` = :title WHERE `user_id` = :id')
'users', ->execute([
[ 'title' => (isset($_POST['usertitle']) ? $_POST['usertitle'] : null),
[ 'id' => $currentUser->id,
'user_title' => (isset($_POST['usertitle']) ? $_POST['usertitle'] : null), ]);
],
[
'user_id' => [$currentUser->id, '='],
],
]
);
// Set render data // Set render data
$renderData['page'] = [ $renderData['page'] = [
@ -935,7 +938,11 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
} }
// Update database // 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 // Set render data
$renderData['page'] = [ $renderData['page'] = [
@ -957,7 +964,11 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
} }
// Update database // 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 // Set render data
$renderData['page'] = [ $renderData['page'] = [
@ -1038,8 +1049,9 @@ if (isset($_REQUEST['request-notifications']) && $_REQUEST['request-notification
// Check if sessionid is set to all // Check if sessionid is set to all
if ($_POST['sessionid'] === 'all') { if ($_POST['sessionid'] === 'all') {
// Delete all sessions assigned to the current user // Delete all sessions assigned to the current user
Database::delete('sessions', [ DB::prepare('DELETE FROM `{prefix}sessions` WHERE `user_id` = :user')
'user_id' => [$currentUser->id, '='], ->execute([
'user' => $currentUser->id,
]); ]);
// Set render data // 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 // 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'] = [ $renderData['page'] = [
'redirect' => $redirect, 'redirect' => $redirect,
'message' => 'The session you tried to kill doesn\'t exist.', '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 // Delete the session
Database::delete('sessions', [ DB::prepare('DELETE FROM `{prefix}sessions` WHERE `user_id` = :user AND `session_id` = :session')
'session_id' => [$_POST['sessionid'], '='], ->execute([
'user' => $currentUser->id,
'session' => $_POST['sessionid'],
]); ]);
// Set render data // Set render data
@ -1500,7 +1519,12 @@ if (Users::checkLogin()) {
// Sessions // Sessions
case 'advanced.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; break;
} }

View file

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

View file

@ -12,5 +12,5 @@
</div> </div>
<div class="clear"></div> <div class="clear"></div>
<div class="news-post-time"> <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> </div>