* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Cache\Cache;
use MyAAC\CsrfToken;
use MyAAC\Items;
use MyAAC\Models\Config;
use MyAAC\Models\Guild;
use MyAAC\Models\House;
use MyAAC\Models\Pages;
use MyAAC\Models\Player;
use MyAAC\News;
use MyAAC\Plugins;
use MyAAC\Settings;
use PHPMailer\PHPMailer\PHPMailer;
use Twig\Loader\ArrayLoader as Twig_ArrayLoader;
function message($message, $type, $return)
{
if(IS_CLI) {
if($return) {
return $message;
}
echo $message;
return true;
}
if($return) {
// for install and admin pages use bootstrap classes
return '
' . $message . '
';
}
echo '
' . $message . '
';
return true;
}
function success($message, $return = false) {
return message($message, 'success', $return);
}
function warning($message, $return = false) {
return message($message, 'warning', $return);
}
function note($message, $return = false) {
return message($message, 'note', $return);
}
function info($message, $return = false) {
return message($message, 'info', $return);
}
function error($message, $return = false) {
return message($message, ((defined('MYAAC_INSTALL') || defined('MYAAC_ADMIN')) ? 'danger' : 'error'), $return);
}
function longToIp($ip): string
{
$exp = explode(".", long2ip($ip));
return $exp[3].".".$exp[2].".".$exp[1].".".$exp[0];
}
function generateLink($url, $name, $blank = false): string {
return '' . $name . '';
}
function getFullLink($page, $name, $blank = false): string {
return generateLink(getLink($page), $name, $blank);
}
function getLink($page, $action = null): string {
return BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . $page . ($action ? '/' . $action : '');
}
function internalLayoutLink($page, $action = null): string {
return getLink($page, $action);
}
function getForumThreadLink($thread_id, $page = NULL): string {
return BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'forum/thread/' . (int)$thread_id . (isset($page) ? '/' . $page : '');
}
function getForumBoardLink($board_id, $page = NULL): string {
return BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'forum/board/' . (int)$board_id . (isset($page) ? '/' . $page : '');
}
function getPlayerLink($name, $generate = true, bool $colored = false): string
{
if (is_object($name) and $name instanceof OTS_Player) {
$player = $name;
}
else {
$player = new OTS_Player();
if(is_numeric($name)) {
$player->load((int)$name);
}
else {
$player->find($name);
}
}
if (!$player->isLoaded()) {
return '(error)';
}
$name = $player->getName();
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'characters/' . urlencode($name);
if ($colored) {
$name = '' . $name . '';
}
if(!$generate) return $url;
return generateLink($url, $name);
}
function getMonsterLink($name, $generate = true): string
{
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'monsters?name=' . urlencode($name);
if(!$generate) return $url;
return generateLink($url, $name);
}
function getHouseLink($name, $generate = true): string
{
if(is_numeric($name)) {
$house = House::find(intval($name), ['name']);
if ($house) {
$name = $house->name;
}
}
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'houses?name=' . urlencode($name);
if(!$generate) return $url;
return generateLink($url, $name);
}
function getGuildLink($name, $generate = true): string
{
if(is_numeric($name)) {
$guild = Guild::find(intval($name), ['name']);
$name = $guild->name ?? 'Unknown';
}
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'guilds/' . urlencode($name);
if(!$generate) return $url;
return generateLink($url, $name);
}
function getItemNameById($id) {
$item = Items::get($id);
return !empty($item['name']) ? $item['name'] : '';
}
function getItemImage($id, $count = 1)
{
$tooltip = '';
$name = getItemNameById($id);
if(!empty($name)) {
$tooltip = ' class="item_image" title="' . $name . '"';
}
$file_name = $id;
if($count > 1)
$file_name .= '-' . $count;
return '';
}
function getItemRarity($chance) {
if ($chance >= 21) {
return "common";
} elseif (between($chance, 8, 21)) {
return "uncommon";
} elseif (between($chance, 1.1, 8)) {
return "semi rare";
} elseif (between($chance, 0.4, 1.1)) {
return "rare";
} elseif (between($chance, 0.8, 0.4)) {
return "very rare";
} elseif ($chance <= 0.8) {
return "extremely rare";
}
return '';
}
function getFlagImage($country): string
{
if(!isset($country[0]))
return '';
global $config;
if(!isset($config['countries']))
require SYSTEM . 'countries.conf.php';
if(!isset($config['countries'][$country])) {
return '';
}
return '';
}
/**
* Performs a boolean check on the value.
*
* @param mixed $v Variable to check.
* @return bool Value boolean status.
*/
function getBoolean(mixed $v): bool
{
if(is_bool($v)) {
return $v;
}
if(is_numeric($v))
return (int)$v > 0;
if (is_null($v)) {
return false;
}
$v = strtolower($v);
return $v === 'yes' || $v === 'true';
}
/**
* Generates random string.
*
* @param int $length Length of the generated string.
* @param bool $lowCase Should lower case characters be used?
* @param bool $upCase Should upper case characters be used?
* @param bool $numeric Should numbers by used too?
* @param bool $special Should special characters by used?
* @return string Generated string.
*/
function generateRandomString($length, $lowCase = true, $upCase = false, $numeric = false, $special = false): string
{
$characters = '';
if($lowCase)
$characters .= 'abcdefghijklmnopqrstuxyvwz';
if($upCase)
$characters .= 'ABCDEFGHIJKLMNPQRSTUXYVWZ';
if($numeric)
$characters .= '123456789';
if($special)
$characters .= '+-*#&@!?';
$characters_length = strlen($characters) - 1;
if($characters_length <= 0) return '';
$ret = '';
for($i = 0; $i < $length; $i++)
$ret .= $characters[mt_rand(0, $characters_length)];
return $ret;
}
/**
* Get forum sections
*
* @return array Forum sections.
*/
function getForumBoards()
{
global $db, $canEdit;
$sections = $db->query('SELECT `id`, `name`, `description`, `closed`, `guild`, `access`' . ($canEdit ? ', `hide`, `ordering`' : '') . ' FROM `' . TABLE_PREFIX . 'forum_boards` ' . (!$canEdit ? ' WHERE `hide` != 1' : '') .
' ORDER BY `ordering`;');
if($sections)
return $sections->fetchAll();
return array();
}
// TODO:
// convert forum threads links from just forum/ID
// INTO: forum/thread-name-id, like in XenForo
//function convertForumThreadTitle($title) {
// return str_replace(' ', '-', strtolower($title));
//}
/**
* Retrieves data from myaac database config.
*
* @param string $name Key.
* @param string &$value Reference where requested data will be set to.
* @return bool False if value was not found in table, otherwise true.
*/
function fetchDatabaseConfig($name, &$value)
{
$config = Config::select('value')->where('name', '=', $name)->first();
if (!$config) {
return false;
}
$value = $config->value;
return true;
}
/**
* Retrieves data from database config.
*
* $param string $name Key.
* @return string Requested data.
*/
function getDatabaseConfig($name)
{
$value = null;
fetchDatabaseConfig($name, $value);
return $value;
}
/**
* Register a new key pair in myaac database config.
*
* @param string $name Key name.
* @param string $value Data to be associated with key.
*/
function registerDatabaseConfig($name, $value)
{
Config::create(compact('name', 'value'));
}
/**
* Updates a value in myaac database config.
*
* @param string $name Key name.
* @param string $value New data.
*/
function updateDatabaseConfig($name, $value)
{
Config::where('name', '=', $name)->update([
'value' => $value
]);
}
/**
* Encrypt text using method specified in config.lua (encryptionType or passwordType)
*/
function encrypt($str)
{
global $config;
if(isset($config['database_salt'])) // otserv
$str .= $config['database_salt'];
$encryptionType = $config['database_encryption'];
if(isset($encryptionType) && strtolower($encryptionType) !== 'plain')
{
if($encryptionType === 'vahash')
return base64_encode(hash('sha256', $str));
return hash($encryptionType, $str);
}
return $str;
}
//delete player with name
function delete_player($name)
{
// DB::beginTransaction();
global $capsule;
$player = Player::where(compact('name'))->first();
if (!$player) {
return false;
}
return false;
// global $db;
// $player = new OTS_Player();
// $player->find($name);
// if($player->isLoaded()) {
// try { $db->exec("DELETE FROM player_skills WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {}
// try { $db->exec("DELETE FROM guild_invites WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {}
// try { $db->exec("DELETE FROM player_items WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {}
// try { $db->exec("DELETE FROM player_depotitems WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {}
// try { $db->exec("DELETE FROM player_spells WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {}
// try { $db->exec("DELETE FROM player_storage WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {}
// try { $db->exec("DELETE FROM player_viplist WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {}
// try { $db->exec("DELETE FROM player_deaths WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {}
// try { $db->exec("DELETE FROM player_deaths WHERE killed_by = '".$player->getId()."';"); } catch(PDOException $error) {}
// $rank = $player->getRank();
// if($rank->isLoaded()) {
// $guild = $rank->getGuild();
// if($guild->getOwner()->getId() == $player->getId()) {
// $rank_list = $guild->getGuildRanksList();
// if(count($rank_list) > 0) {
// $rank_list->orderBy('level');
// foreach($rank_list as $rank_in_guild) {
// $players_with_rank = $rank_in_guild->getPlayersList();
// $players_with_rank->orderBy('name');
// $players_with_rank_number = count($players_with_rank);
// if($players_with_rank_number > 0) {
// foreach($players_with_rank as $player_in_guild) {
// $player_in_guild->setRank();
// $player_in_guild->save();
// }
// }
// $rank_in_guild->delete();
// }
// $guild->delete();
// }
// }
// }
// $player->delete();
// return true;
// }
// return false;
}
//delete guild with id
function delete_guild($id)
{
$guild = new OTS_Guild();
$guild->load($id);
if(!$guild->isLoaded())
return false;
$rank_list = $guild->getGuildRanksList();
if(count($rank_list) > 0) {
$rank_list->orderBy('level');
global $db;
/**
* @var OTS_GuildRank $rank_in_guild
*/
foreach($rank_list as $rank_in_guild) {
if($db->hasTable('guild_members'))
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_members`.`rank_id` as `rank_id` FROM `players`, `guild_members` WHERE `guild_members`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_members`.`player_id` ORDER BY `name`;');
else if($db->hasTable('guild_membership'))
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_membership`.`rank_id` as `rank_id` FROM `players`, `guild_membership` WHERE `guild_membership`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_membership`.`player_id` ORDER BY `name`;');
else
$players_with_rank = $db->query('SELECT `id`, `rank_id` FROM `players` WHERE `rank_id` = ' . $rank_in_guild->getId() . ' AND `deleted` = 0;');
$players_with_rank_number = $players_with_rank->rowCount();
if($players_with_rank_number > 0) {
foreach($players_with_rank as $result) {
$player = new OTS_Player();
$player->load($result['id']);
if(!$player->isLoaded())
continue;
$player->setRank();
$player->save();
}
}
$rank_in_guild->delete();
}
}
$guild->delete();
return true;
}
//################### DISPLAY FUNCTIONS #####################
//return shorter text (news ticker)
function short_text($text, $limit)
{
if(strlen($text) > $limit)
return substr($text, 0, strrpos(substr($text, 0, $limit), " ")).'...';
return $text;
}
function tickers()
{
global $tickers_content, $featured_article;
if(PAGE === 'news') {
if(isset($tickers_content))
return $tickers_content . $featured_article;
}
return '';
}
/**
* Template place holder
*
* Types: head_start, head_end, body_start, body_end, center_top
*
*/
function template_place_holder($type): string
{
global $twig, $template_place_holders, $debugBar;
$ret = '';
if (isset($debugBar)) {
$debugBarRenderer = $debugBar->getJavascriptRenderer();
}
if(array_key_exists($type, $template_place_holders) && is_array($template_place_holders[$type]))
$ret = implode($template_place_holders[$type]);
if($type === 'head_start') {
$ret .= template_header();
if (isset($debugBar)) {
$ret .= $debugBarRenderer->renderHead();
}
}
elseif ($type === 'body_start') {
$ret .= $twig->render('browsehappy.html.twig');
}
elseif($type === 'body_end') {
$ret .= template_ga_code();
if (isset($debugBar)) {
$ret .= $debugBarRenderer->render();
}
}
return $ret;
}
/**
* Returns content to be used by templates.
*/
function template_header($is_admin = false): string
{
global $title_full, $twig;
$charset = setting('core.charset') ?? 'utf-8';
return $twig->render('templates.header.html.twig',
[
'charset' => $charset,
'title' => $title_full,
'is_admin' => $is_admin
]
);
}
/**
* Returns footer content to be used by templates.
*/
function template_footer(): string
{
global $views_counter;
$ret = '';
if(admin()) {
$ret .= generateLink(ADMIN_URL, 'Admin Panel', true);
}
if(setting('core.visitors_counter')) {
global $visitors;
$amount = $visitors->getAmountVisitors();
$ret .= ' Currently there ' . ($amount > 1 ? 'are' : 'is') . ' ' . $amount . ' visitor' . ($amount > 1 ? 's' : '') . '.';
}
if(setting('core.views_counter')) {
$ret .= ' Page has been viewed ' . $views_counter . ' times.';
}
if(setting('core.footer_load_time')) {
$ret .= ' Load time: ' . round(microtime(true) - START_TIME, 4) . ' seconds.';
}
$settingFooter = setting('core.footer');
if(isset($settingFooter[0])) {
$ret .= ' ' . $settingFooter;
}
// please respect my work and help spreading the word, thanks!
return $ret . ' ' . base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4=');
}
function template_ga_code()
{
global $twig;
if(!isset(setting('core.google_analytics_id')[0]))
return '';
return $twig->render('google_analytics.html.twig');
}
function template_form()
{
global $template_name;
$templates = Cache::remember('templates', 5 * 60, function() {
return get_templates();
});
$options = '';
foreach($templates as $value)
$options .= '';
global $twig;
return $twig->render('forms.change_template.html.twig', ['options' => $options]);
}
function getStyle($i)
{
global $config;
return is_int($i / 2) ? $config['darkborder'] : $config['lightborder'];
}
$vowels = array('e', 'y', 'u', 'i', 'o', 'a');
function getCreatureName($killer, $showStatus = false, $extendedInfo = false)
{
global $vowels, $ots, $config;
$str = "";
$players_rows = '';
if(is_numeric($killer))
{
$player = new OTS_Player();
$player->load($killer);
if($player->isLoaded())
{
$str .= '';
if(!$showStatus)
return $str.''.$player->getName().'';
$str .= '' . $player->getName() . '';
if($extendedInfo) {
$str .= ' '.$player->getLevel().' '.$player->getVocationName().'';
}
return $str;
}
}
else
{
if($killer == "-1")
$players_rows .= "item or field";
else
{
if(in_array(strtolower($killer[0]), $vowels))
$players_rows .= "an ";
else
$players_rows .= "a ";
$players_rows .= $killer;
}
}
return $players_rows;
}
/**
* Find skill name using skill id.
*
* @param int $skillId Skill id.
* @param bool $suffix Should suffix also be added?
* @return string Skill name or 'unknown' if not found.
*/
function getSkillName($skillId, $suffix = true)
{
switch($skillId)
{
case POT::SKILL_FIST:
{
$tmp = 'fist';
if($suffix)
$tmp .= ' fighting';
return $tmp;
}
case POT::SKILL_CLUB:
{
$tmp = 'club';
if($suffix)
$tmp .= ' fighting';
return $tmp;
}
case POT::SKILL_SWORD:
{
$tmp = 'sword';
if($suffix)
$tmp .= ' fighting';
return $tmp;
}
case POT::SKILL_AXE:
{
$tmp = 'axe';
if($suffix)
$tmp .= ' fighting';
return $tmp;
}
case POT::SKILL_DIST:
{
$tmp = 'distance';
if($suffix)
$tmp .= ' fighting';
return $tmp;
}
case POT::SKILL_SHIELD:
return 'shielding';
case POT::SKILL_FISH:
return 'fishing';
case POT::SKILL__MAGLEVEL:
return 'magic level';
case POT::SKILL__LEVEL:
return 'level';
default:
break;
}
return 'unknown';
}
/**
* Performs flag check on the current logged in user.
* Table in database: accounts, field: website_flags
*/
function hasFlag(int $flag): bool {
global $logged, $logged_flags;
return ($logged && ($logged_flags & $flag) == $flag);
}
/**
* Check if current logged user have got admin flag set.
*/
function admin() {
return hasFlag(FLAG_ADMIN) || superAdmin();
}
/**
* Check if current logged user have got super admin flag set.
*/
function superAdmin() {
return hasFlag(FLAG_SUPER_ADMIN);
}
/**
* Format experience according to its amount (natural/negative number).
*
* @param int $exp Experience amount.
* @param bool $color Should result be colorized?
* @return string Resulted message attached in tag.
*/
function formatExperience($exp, $color = true)
{
$ret = '';
if($color)
{
$ret .= ' 0 ? 'green' : 'red') . '">';
}
else {
$ret .= '>';
}
}
$ret .= '' . ($exp > 0 ? '+' : '') . number_format($exp) . '';
if($color)
$ret .= '';
return $ret;
}
function get_locales()
{
$ret = array();
$path = LOCALE;
foreach(scandir($path, 0) as $file)
{
if($file[0] != '.' && $file != '..' && is_dir($path . $file))
$ret[] = $file;
}
return $ret;
}
function get_browser_languages()
{
$ret = array();
if(empty($_SERVER['HTTP_ACCEPT_LANGUAGE']))
return $ret;
$acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$languages = strtolower($acceptLang);
// $languages = 'pl,en-us;q=0.7,en;q=0.3 ';
// need to remove spaces from strings to avoid error
$languages = str_replace(' ', '', $languages);
foreach(explode(',', $languages) as $language_list)
$ret[] = substr($language_list, 0, 2);
return $ret;
}
/**
* Generates list of templates, according to templates/ dir.
*/
function get_templates()
{
$ret = array();
$path = TEMPLATES;
foreach(scandir($path, 0) as $file)
{
if($file[0] !== '.' && $file !== '..' && is_dir($path . $file))
$ret[] = $file;
}
foreach (Plugins::getThemes() as $name => $path) {
$ret[] = $name;
}
return $ret;
}
/**
* Generates list of installed plugins
* @return array $plugins
*/
function get_plugins($disabled = false): array
{
$ret = [];
$path = PLUGINS;
foreach(scandir($path, SCANDIR_SORT_ASCENDING) as $file) {
$file_ext = pathinfo($file, PATHINFO_EXTENSION);
$file_name = pathinfo($file, PATHINFO_FILENAME);
if ($file === '.' || $file === '..' || $file === 'example.json' || $file_ext !== 'json' || is_dir($path . $file)) {
continue;
}
if (!$disabled && strpos($file, 'disabled.') !== false) {
continue;
}
$ret[] = str_replace('.json', '', $file_name);
}
return $ret;
}
function getWorldName($id)
{
global $config;
if(isset($config['worlds'][$id]))
return $config['worlds'][$id];
return $config['lua']['serverName'];
}
/**
* Mailing users.
* Mailing has to be enabled in settings (in Admin Panel).
*
* @param string $to Recipient email address.
* @param string $subject Subject of the message.
* @param string $body Message body in html format.
* @param string $altBody Alternative message body, plain text.
* @return bool PHPMailer status returned (success/failure).
*/
function _mail($to, $subject, $body, $altBody = '', $add_html_tags = true)
{
global $mailer, $config;
if (!setting('core.mail_enabled')) {
log_append('mailer-error.log', '_mail() function has been used, but Mail Support is disabled.');
return false;
}
if(!$mailer)
{
$mailer = new PHPMailer();
//$mailer->setLanguage('en', LIBS . 'phpmailer/language/');
}
else {
$mailer->clearAllRecipients();
}
$signature_html = setting('core.mail_signature_html');
if($add_html_tags && isset($body[0]))
$tmp_body = '' . $body . '