public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null)
{
$result = $this->_execute($template, $cache_id, $compile_id, $parent, 0);
return $result === null ? ob_get_clean() : $result;
}
/**
* displays a Smarty template
*
* @param string $template the resource handle of the template file or template object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
*
* @throws \Exception
* @throws \SmartyException
*/
public function display($template = null, $cache_id = null, $compile_id = null, $parent = null)
{
// display template
$this->_execute($template, $cache_id, $compile_id, $parent, 1);
}
/**
* test if cache is valid
*
* @api Smarty::isCached()
* @link https://www.smarty.net/docs/en/api.is.cached.tpl
*
* @param null|string|\Smarty_Internal_Template $template the resource handle of the template file or template
* object
* @param mixed $cache_id cache id to be used with this template
* @param mixed $compile_id compile id to be used with this template
* @param object $parent next higher level of Smarty variables
*
* @return bool cache status
* @throws \Exception
* @throws \SmartyException
*/
public function isCached($template = null, $cache_id = null, $compile_id = null, $parent = null)
{
public function displayTemplate(string $template, Smarty $smarty): void {
[$css, $js] = $this->assets()->compile();
// Put the assets at the start of the arrays, so they load first (SBAdmin requires JQuery first, etc.)
array_unshift($this->_css, ...$css);
array_unshift($this->_js, ...$js);
$smarty->assign([
'TEMPLATE_CSS' => $this->getCSS(),
'TEMPLATE_JS' => $this->getJS()
]);
if (defined('PHPDEBUGBAR') && PHPDEBUGBAR) {
$debugBar = DebugBarHelper::getInstance()->getDebugBar()->getJavascriptRenderer();
$smarty->assign([
'DEBUGBAR_JS' => $debugBar->renderHead(),
'DEBUGBAR_HTML' => $debugBar->render()
]);
}
$smarty->display($template);
}
/**
* Get all internal CSS styles.
*
* @return array Array of strings of CSS.
*/
public function getCSS(): array {
return $this->_css;
}
/**
* Get all internal JS code.
*
* @return array Array of strings of JS.
*/
public function getJS(): array {
return $this->_js;
}
* Get the display order of this widget.
*
* @return int Display order of widget.
*/
public function getOrder(): ?int {
return $this->_order;
}
/**
* Generate this widget's `$_content`.
*/
abstract public function initialise(): void;
/**
* Get the data (location, order, pages) for a widget.
*
* @param string $name The widget to get data for.
* @return object|null Widgets data.
*/
protected static function getData(string $name): ?object {
return DB::getInstance()->query('SELECT `location`, `order`, `pages` FROM nl2_widgets WHERE `name` = ?', [$name])->first();
}
/**
* Parse the widgets JSON pages string into an array.
*
* @param object|null $data The widget data to get pages from.
* @return array The parsed pages array.
*/
protected static function parsePages(?object $data): array {
if (isset($data->pages)) {
return json_decode($data->pages, true) ?? [];
}
return [];
}
}
* Get the display order of this widget.
*
* @return int Display order of widget.
*/
public function getOrder(): ?int {
return $this->_order;
}
/**
* Generate this widget's `$_content`.
*/
abstract public function initialise(): void;
/**
* Get the data (location, order, pages) for a widget.
*
* @param string $name The widget to get data for.
* @return object|null Widgets data.
*/
protected static function getData(string $name): ?object {
return DB::getInstance()->query('SELECT `location`, `order`, `pages` FROM nl2_widgets WHERE `name` = ?', [$name])->first();
}
/**
* Parse the widgets JSON pages string into an array.
*
* @param object|null $data The widget data to get pages from.
* @return array The parsed pages array.
*/
protected static function parsePages(?object $data): array {
if (isset($data->pages)) {
return json_decode($data->pages, true) ?? [];
}
return [];
}
}
* Get the display order of this widget.
*
* @return int Display order of widget.
*/
public function getOrder(): ?int {
return $this->_order;
}
/**
* Generate this widget's `$_content`.
*/
abstract public function initialise(): void;
/**
* Get the data (location, order, pages) for a widget.
*
* @param string $name The widget to get data for.
* @return object|null Widgets data.
*/
protected static function getData(string $name): ?object {
return DB::getInstance()->query('SELECT `location`, `order`, `pages` FROM nl2_widgets WHERE `name` = ?', [$name])->first();
}
/**
* Parse the widgets JSON pages string into an array.
*
* @param object|null $data The widget data to get pages from.
* @return array The parsed pages array.
*/
protected static function parsePages(?object $data): array {
if (isset($data->pages)) {
return json_decode($data->pages, true) ?? [];
}
return [];
}
}
* Get the display order of this widget.
*
* @return int Display order of widget.
*/
public function getOrder(): ?int {
return $this->_order;
}
/**
* Generate this widget's `$_content`.
*/
abstract public function initialise(): void;
/**
* Get the data (location, order, pages) for a widget.
*
* @param string $name The widget to get data for.
* @return object|null Widgets data.
*/
protected static function getData(string $name): ?object {
return DB::getInstance()->query('SELECT `location`, `order`, `pages` FROM nl2_widgets WHERE `name` = ?', [$name])->first();
}
/**
* Parse the widgets JSON pages string into an array.
*
* @param object|null $data The widget data to get pages from.
* @return array The parsed pages array.
*/
protected static function parsePages(?object $data): array {
if (isset($data->pages)) {
return json_decode($data->pages, true) ?? [];
}
return [];
}
}
* Get the display order of this widget.
*
* @return int Display order of widget.
*/
public function getOrder(): ?int {
return $this->_order;
}
/**
* Generate this widget's `$_content`.
*/
abstract public function initialise(): void;
/**
* Get the data (location, order, pages) for a widget.
*
* @param string $name The widget to get data for.
* @return object|null Widgets data.
*/
protected static function getData(string $name): ?object {
return DB::getInstance()->query('SELECT `location`, `order`, `pages` FROM nl2_widgets WHERE `name` = ?', [$name])->first();
}
/**
* Parse the widgets JSON pages string into an array.
*
* @param object|null $data The widget data to get pages from.
* @return array The parsed pages array.
*/
protected static function parsePages(?object $data): array {
if (isset($data->pages)) {
return json_decode($data->pages, true) ?? [];
}
return [];
}
}
* Get the display order of this widget.
*
* @return int Display order of widget.
*/
public function getOrder(): ?int {
return $this->_order;
}
/**
* Generate this widget's `$_content`.
*/
abstract public function initialise(): void;
/**
* Get the data (location, order, pages) for a widget.
*
* @param string $name The widget to get data for.
* @return object|null Widgets data.
*/
protected static function getData(string $name): ?object {
return DB::getInstance()->query('SELECT `location`, `order`, `pages` FROM nl2_widgets WHERE `name` = ?', [$name])->first();
}
/**
* Parse the widgets JSON pages string into an array.
*
* @param object|null $data The widget data to get pages from.
* @return array The parsed pages array.
*/
protected static function parsePages(?object $data): array {
if (isset($data->pages)) {
return json_decode($data->pages, true) ?? [];
}
return [];
}
}
* Get the display order of this widget.
*
* @return int Display order of widget.
*/
public function getOrder(): ?int {
return $this->_order;
}
/**
* Generate this widget's `$_content`.
*/
abstract public function initialise(): void;
/**
* Get the data (location, order, pages) for a widget.
*
* @param string $name The widget to get data for.
* @return object|null Widgets data.
*/
protected static function getData(string $name): ?object {
return DB::getInstance()->query('SELECT `location`, `order`, `pages` FROM nl2_widgets WHERE `name` = ?', [$name])->first();
}
/**
* Parse the widgets JSON pages string into an array.
*
* @param object|null $data The widget data to get pages from.
* @return array The parsed pages array.
*/
protected static function parsePages(?object $data): array {
if (isset($data->pages)) {
return json_decode($data->pages, true) ?? [];
}
return [];
}
}
* Get the display order of this widget.
*
* @return int Display order of widget.
*/
public function getOrder(): ?int {
return $this->_order;
}
/**
* Generate this widget's `$_content`.
*/
abstract public function initialise(): void;
/**
* Get the data (location, order, pages) for a widget.
*
* @param string $name The widget to get data for.
* @return object|null Widgets data.
*/
protected static function getData(string $name): ?object {
return DB::getInstance()->query('SELECT `location`, `order`, `pages` FROM nl2_widgets WHERE `name` = ?', [$name])->first();
}
/**
* Parse the widgets JSON pages string into an array.
*
* @param object|null $data The widget data to get pages from.
* @return array The parsed pages array.
*/
protected static function parsePages(?object $data): array {
if (isset($data->pages)) {
return json_decode($data->pages, true) ?? [];
}
return [];
}
}
* Create a new row in nl2_placeholders_settings if a row with the "server_id" of $server_id and "name" of $name does not exist (this lets the same placeholder name be used across multiple NamelessMC plugin servers).
*
* @param int $server_id ID of the server this placeholder resides on
*
* @param string $name Name of placeholder
*/
public function registerPlaceholder(int $server_id, string $name): void {
$this->_db->query('INSERT IGNORE INTO nl2_placeholders_settings (server_id, name) VALUES (?, ?)', [$server_id, $name]);
}
/**
* Load placeholders for a specific user.
*
* @param string $uuid Their valid Minecraft uuid to use for lookup.
*
* @return array Their placeholders.
*/
public function loadUserPlaceholders(string $uuid): array {
$binUuid = hex2bin(str_replace('-', '', $uuid));
$placeholder_query = $this->_db->query('SELECT * FROM nl2_users_placeholders up JOIN nl2_placeholders_settings ps ON up.name = ps.name AND up.server_id = ps.server_id WHERE up.uuid = ?', [$binUuid]);
if (!$placeholder_query->count()) {
return [];
}
$user_placeholders = [];
$placeholders = $placeholder_query->results();
foreach ($placeholders as $placeholder) {
$data = new stdClass();
$data->server_id = $placeholder->server_id;
$data->name = Output::getClean($placeholder->name);
$data->friendly_name = isset($placeholder->friendly_name) ? Output::getClean($placeholder->friendly_name) : Output::getClean($placeholder->name);
$data->value = Output::getClean($placeholder->value);
$data->last_updated = $placeholder->last_updated;
$data->show_on_profile = $placeholder->show_on_profile;
$data->show_on_forum = $placeholder->show_on_forum;
$user_placeholders[$data->name] = $data;
/**
* Get if the current user is authenticated as an administrator.
*
* @return bool Whether they're logged in as admin.
*/
public function isAdmLoggedIn(): bool {
return $this->_isAdmLoggedIn;
}
/**
* Get profile fields for this user
*
* @param bool $show_private Whether to only return public fields or not (default `true`).
* @param bool $only_forum Whether to only return fields which display on forum posts, only if $public is true (default `false`).
*
* @return array<int, UserProfileField> Array of profile fields.
*/
public function getProfileFields(bool $show_private = false, bool $only_forum = false): array {
$rows = DB::getInstance()->query('SELECT pf.*, upf.id as upf_id, upf.value, upf.updated FROM nl2_profile_fields pf LEFT JOIN nl2_users_profile_fields upf ON (pf.id = upf.field_id AND upf.user_id = ?)', [
$this->data()->id,
])->results();
$fields = [];
foreach ($rows as $row) {
$field = new UserProfileField($row);
// Check that the field is public, or they are viewing private fields
// also if they're checking forum fields, check that the field is a forum field
// TODO: ideally within the query
if (($field->public || $show_private) && (!$only_forum || $field->forum_posts)) {
$fields[$row->id] = $field;
}
}
return $fields;
}
/**
* Is a user blocked?
*
// Avoid bug in pagination class
Redirect::to($profile_user->getProfileURL());
}
$p = $_GET['p'];
} else {
$p = 1;
}
// View count
// Check if user is logged in and the viewer is not the owner of this profile.
if (($user->isLoggedIn() && $user->data()->id != $query->id)
// If no one is logged in check if they have accepted the cookies.
|| (!$user->isLoggedIn() && (defined('COOKIE_CHECK') && COOKIES_ALLOWED))
) {
if (!Cookie::exists('nl-profile-' . $query->id)) {
DB::getInstance()->increment('users', $query->id, 'profile_views');
Cookie::put('nl-profile-' . $query->id, 'true', 3600);
}
} else {
if (!Session::exists('nl-profile-' . $query->id)) {
DB::getInstance()->increment('users', $query->id, 'profile_views');
Session::put('nl-profile-' . $query->id, 'true');
}
}
// Set Can view
if ($profile_user->isPrivateProfile() && $user->canPrivateProfile()) {
$smarty->assign([
'PRIVATE_PROFILE' => $language->get('user', 'private_profile_page'),
'CAN_VIEW' => false
]);
} else {
$smarty->assign([
'CAN_VIEW' => true
]);
}
// Generate Smarty variables to pass to template
if ($user->isLoggedIn()) {
// Form token
$smarty->assign([
/**
* Find a user by unique identifier (username, ID, email, etc).
* Loads instance variables for this class.
*
* @param string|null $value Unique identifier.
* @param string $field What column to check for their unique identifier in.
*
* @return bool True/false on success or failure respectfully.
*/
public function find(string $value = null, string $field = 'id'): bool {
if ($value) {
if (isset(self::$_user_cache["$value.$field"])) {
$cache = self::$_user_cache["$value.$field"];
$this->_data = $cache['data'];
$this->_groups = $cache['groups'];
return true;
}
if ($field != 'hash') {
$data = $this->_db->get('users', [$field, $value]);
} else {
$data = $this->_db->query('SELECT nl2_users.* FROM nl2_users LEFT JOIN nl2_users_session ON nl2_users.id = user_id WHERE hash = ? AND nl2_users_session.active = 1', [$value]);
}
if ($data->count()) {
$this->_data = new UserData($data->first());
// Get user groups
$groups_query = $this->_db->query('SELECT nl2_groups.* FROM nl2_users_groups INNER JOIN nl2_groups ON group_id = nl2_groups.id WHERE user_id = ? AND deleted = 0 ORDER BY `order`;', [$this->data()->id]);
if ($groups_query->count()) {
$groups_query = $groups_query->results();
foreach ($groups_query as $item) {
$this->_groups[$item->id] = new Group($item);
}
self::$_user_cache["$value.$field"] = [
'data' => $this->_data,
'groups' => $this->_groups,
private static function setSettingsCache(?string $module, array $cache): void {
$cache_name = $module !== null ? $module : 'core';
self::$_cached_settings[$cache_name] = $cache;
}
/**
* Get a setting from the database table `nl2_settings`.
*
* @param string $setting Setting to check.
* @param ?string $fallback Fallback to return if $setting is not set in DB. Defaults to null.
* @param string $module Module name to keep settings separate from other modules. Set module
* to 'Core' for global settings.
* @return ?string Setting from DB or $fallback.
*/
public static function getSetting(string $setting, ?string $fallback = null, string $module = 'core'): ?string {
$cache = self::getSettingsCache($module);
if ($cache === null) {
// Load all settings for this module and store it as a dictionary
if ($module === 'core') {
$result = DB::getInstance()->query('SELECT `name`, `value` FROM `nl2_settings` WHERE `module` IS NULL')->results();
} else {
$result = DB::getInstance()->query('SELECT `name`, `value` FROM `nl2_settings` WHERE `module` = ?', [$module])->results();
}
$cache = [];
foreach ($result as $row) {
$cache[$row->name] = $row->value;
}
self::setSettingsCache($module, $cache);
}
return $cache[$setting] ?? $fallback;
}
/**
* Modify a setting in the database table `nl2_settings`.
*
* @param string $setting Setting name.
* @param string|null $new_value New setting value, or null to delete
* @param string $module Module name to keep settings separate from other modules. Set module
/**
* Checks the number of existing migration files compared to executed migrations in the database.
* Alternatively we could check the output of a Phinx command, but that takes ~8x as long to execute.
*
* @throws RuntimeException If these numbers don't match.
*/
public static function ensureUpToDate(): void {
$migration_files = array_map(
static function ($file_name) {
[$version, $migration_name] = explode('_', $file_name, 2);
$migration_name = str_replace(['.php', '_'], '', ucwords($migration_name, '_'));
return $version . '_' . $migration_name;
},
array_filter(scandir(__DIR__ . '/../../migrations'), static function ($file_name) {
return !in_array($file_name, ['.', '..', 'phinx.php']);
}),
);
$migration_database_entries = array_map(static function ($row) {
return $row->version . '_' . $row->migration_name;
}, DB::getInstance()->query('SELECT version, migration_name FROM nl2_phinxlog')->results());
$missing = array_diff($migration_files, $migration_database_entries);
$extra = array_diff($migration_database_entries, $migration_files);
// Likely a pull from the repo dev branch or migrations
// weren't run during an upgrade script.
if (($missing_count = count($missing)) > 0) {
echo "There are $missing_count migrations files which have not been executed:" . '<br>';
foreach ($missing as $missing_migration) {
echo " - $missing_migration" . '<br>';
}
}
// Something went wonky, either they've deleted migration files,
// or they've added stuff to the nl2_phinxlog table.
if (($extra_count = count($extra)) > 0) {
if ($missing_count > 0) {
echo '<br>';
}
echo "There are $extra_count executed migrations which do not have migration files associated:" . '<br>';
Important - only share this link with people you trust!