Compare commits

...

17 Commits

Author SHA1 Message Date
slawkens
e106ef7f6c First attempt 2025-09-28 16:58:37 +02:00
slawkens
c898fe25ef New function: getColumnInfo($table, $column) 2025-09-28 16:21:31 +02:00
slawkens
73c07d470d Add variable types, don't use $config 2025-09-28 16:10:58 +02:00
slawkens
56bd7ec5ed Prevent injection in $db->hasColumn 2025-09-28 16:09:14 +02:00
slawkens
4c6277c124 Start v1.8.3-dev 2025-09-28 14:16:28 +02:00
slawkens
228780f0ad Just leaving it here, for future use (twig hook display)
Maybe configurable in the future
2025-09-28 14:14:26 +02:00
slawkens
4e9999cc0d Do not use constant on twig hooks
So it can be displayed which hook is used
2025-09-28 14:13:51 +02:00
slawkens
8bc328d6fb Now v1.8.2 real 2025-09-26 10:14:48 +02:00
slawkens
ac41b82579 Update index.php 2025-09-26 10:14:38 +02:00
slawkens
df7b6e29fb Replace firstChild with firstElementChild (Thanks to @un000000) 2025-09-26 08:56:15 +02:00
slawkens
e0cc19ad86 Release v1.8.2 2025-09-26 07:54:40 +02:00
slawkens
85e7005fd3 Fix Menu div wrong tag/closing (#329) 2025-09-24 15:39:47 +02:00
slawkens
3c0cb53e17 Add missing csrf() - fix create account buton 2025-09-23 21:45:49 +02:00
slawkens
d0112d1a67 Fix exception when email cannot be send on create account 2025-09-23 21:45:32 +02:00
slawkens
ed9beaf2b6 Fix account lost routes in tibiacom template 2025-09-14 21:02:01 +02:00
slawkens
5aa9bbf1c8 Ignore child tables of myaac-table class 2025-09-14 20:50:00 +02:00
slawkens
a6032093b2 Better look for myaac-table 2025-09-14 19:35:12 +02:00
11 changed files with 125 additions and 44 deletions

View File

@@ -1,5 +1,21 @@
# Changelog
## [1.8.2 - 26.09.2025]
### Added
* Routes: Possibility to override routes with plugins pages, like characters.php - No need to define routes in plugin.json anymore (https://github.com/slawkens/myaac/commit/3f24f961b1cdeff5c60387e837ae454448bc5e1b)
### Changed
* Style: Better look for myaac-table (https://github.com/slawkens/myaac/commit/a6032093b21e5bb3f0e75d2704da87d6dea6469d, https://github.com/slawkens/myaac/commit/5aa9bbf1c8e580d973ec82ac012489f8e7bc437e)
### Fixed
* Install: Fix when config.local.php cannot be saved (https://github.com/slawkens/myaac/commit/4eab805d26d8c5562b29ed699769919d77dabced)
* Create Account: Fix an exception when email cannot be sent (https://github.com/slawkens/myaac/commit/d0112d1a67e8b854b65ad131f0375b79305df8d3)
* Login Page: Add missing csrf() - fix create account button (https://github.com/slawkens/myaac/commit/3c0cb53e17dd0b85394cfa0fdc9cf9ad8d4551df)
* tibiacom template: Fix account lost menu (https://github.com/slawkens/myaac/commit/ed9beaf2b6ca069e304e569c52e5b9188b58f05c)
* tibiacom template: Fix Menu div wrong tag/closing (#329) (https://github.com/slawkens/myaac/commit/85e7005fd3f0be51466151a3c122b96085fdfe68)
* tibiacom template: Replace firstChild with firstElementChild (Thanks to @un000000) (https://github.com/slawkens/myaac/commit/df7b6e29fb8875da97f431468c81ee99116271d9)
## [1.8.1 - 05.09.2025]
### Added

View File

@@ -669,11 +669,17 @@ else if (isset($_REQUEST['search'])) {
<div class="col-12 col-sm-12 col-lg-6">
<label for="lastip" class="control-label">Last IP:</label>
<input type="text" class="form-control" id="lastip" name="lastip" autocomplete="off" maxlength="10" value="<?php
if (strlen($player->getLastIP()) > 11) {
echo inet_ntop($player->getLastIP());
$lastIPColumnInfo = $db->getColumnInfo('players', 'lastip');
if ($lastIPColumnInfo && is_array($lastIPColumnInfo)) {
if (str_contains($lastIPColumnInfo['type'], 'varbinary')) {
echo inet_ntop($player->getLastIP());
}
else {
echo longToIp($player->getLastIP());
}
}
else {
echo longToIp($player->getLastIP());
echo 'Error';
}
?>" readonly/>
</div>

View File

@@ -26,7 +26,7 @@
if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.');
const MYAAC = true;
const MYAAC_VERSION = '1.8.2-dev';
const MYAAC_VERSION = '1.8.3-dev';
const DATABASE_VERSION = 45;
const TABLE_PREFIX = 'myaac_';
define('START_TIME', microtime(true));

View File

@@ -26,10 +26,11 @@ use MyAAC\Cache\Cache;
*/
class OTS_DB_MySQL extends OTS_Base_DB
{
private $has_table_cache = array();
private $has_column_cache = array();
private array $has_table_cache = [];
private array $has_column_cache = [];
private array $get_column_info_cache = [];
private $clearCacheAfter = false;
private bool $clearCacheAfter = false;
/**
* Creates database connection.
*
@@ -209,7 +210,8 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $sql;
}
public function hasTable($name) {
public function hasTable($name): bool
{
if(isset($this->has_table_cache[$name])) {
return $this->has_table_cache[$name];
}
@@ -217,12 +219,13 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $this->hasTableInternal($name);
}
private function hasTableInternal($name) {
global $config;
return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote($config['database_name']) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0);
private function hasTableInternal($name): bool
{
return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote(config('database_name')) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0);
}
public function hasColumn($table, $column) {
public function hasColumn($table, $column): bool
{
if(isset($this->has_column_cache[$table . '.' . $column])) {
return $this->has_column_cache[$table . '.' . $column];
}
@@ -230,8 +233,8 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $this->hasColumnInternal($table, $column);
}
private function hasColumnInternal($table, $column) {
return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE '" . $column . "'")->fetchAll()) > 0);
private function hasColumnInternal($table, $column): bool {
return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column))->fetchAll()) > 0);
}
public function hasTableAndColumns(string $table, array $columns = []): bool
@@ -247,6 +250,51 @@ class OTS_DB_MySQL extends OTS_Base_DB
return true;
}
public function getColumnInfo(string $table, string $column): bool|array
{
if(isset($this->get_column_info_cache[$table . '.' . $column])) {
return $this->get_column_info_cache[$table . '.' . $column];
}
return $this->getColumnInfoInternal($table, $column);
}
private function getColumnInfoInternal(string $table, string $column): bool|array
{
if (!$this->hasTable($table) || !$this->hasColumn($table, $column)) {
return false;
}
$formatResult = function ($result) {
return [
'field' => $result['Field'],
'type' => $result['Type'],
'null' => strtolower($result['Null']),
'default' => $result['Default'],
'extra' => $result['Extra'],
];
};
$query = $this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column));
$rowCount = $query->rowCount();
if ($rowCount > 1) {
$tmp = [];
$results = $query->fetchAll(PDO::FETCH_ASSOC);
foreach ($results as $result) {
$tmp[] = $formatResult($result);
}
return ($this->get_column_info_cache[$table . '.' . $column] = $tmp);
}
else if ($rowCount == 1) {
$result = $query->fetch(PDO::FETCH_ASSOC);
return ($this->get_column_info_cache[$table . '.' . $column] = $formatResult($result));
}
return [];
}
public function revalidateCache() {
foreach($this->has_table_cache as $key => $value) {
$this->hasTableInternal($key);

View File

@@ -268,8 +268,10 @@ if($save)
}
else
{
error('An error occorred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log');
error('An error occurred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log');
$new_account->delete();
return;
}
}
else

View File

@@ -9,7 +9,7 @@
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr>
<td><img src="{{ template_path }}/images/general/blank.gif" width="10" height="1" border="0"></td>
<td>
{{ hook(constant('HOOK_CHARACTERS_BEFORE_INFORMATIONS')) }}
{{ hook('HOOK_CHARACTERS_BEFORE_INFORMATIONS') }}
{% if canEdit %}
<a href="{{ constant('ADMIN_URL') }}?p=players&id={{ player.getId() }}" title="Edit in Admin Panel" target="_blank">
<img src="images/edit.png"/>Edit
@@ -153,11 +153,11 @@
<td>{% if account.isPremium() %}Premium Account{% else %}Free Account{% endif %}</td>
</tr>
</table>
{{ hook(constant('HOOK_CHARACTERS_AFTER_INFORMATIONS')) }}
{{ hook('HOOK_CHARACTERS_AFTER_INFORMATIONS') }}
<br/>
<table border="0" width="100%">
<tr>
{{ hook(constant('HOOK_CHARACTERS_BEFORE_SKILLS')) }}
{{ hook('HOOK_CHARACTERS_BEFORE_SKILLS') }}
{% if config.characters.skills %}
<!-- SKILLS -->
@@ -179,7 +179,7 @@
<!-- SKILLS_END -->
{% endif %}
{{ hook(constant('HOOK_CHARACTERS_AFTER_SKILLS')) }}
{{ hook('HOOK_CHARACTERS_AFTER_SKILLS') }}
{% if quests_enabled %}
<!-- QUESTS -->
@@ -201,7 +201,7 @@
<!-- QUESTS_END -->
{% endif %}
{{ hook(constant('HOOK_CHARACTERS_AFTER_QUESTS')) }}
{{ hook('HOOK_CHARACTERS_AFTER_QUESTS') }}
{% if config.characters.equipment %}
<!-- EQUIPMENT -->
@@ -239,11 +239,11 @@
<!-- EQUIPMENT_END -->
{% endif %}
{{ hook(constant('HOOK_CHARACTERS_AFTER_EQUIPMENT')) }}
{{ hook('HOOK_CHARACTERS_AFTER_EQUIPMENT') }}
</tr>
</table>
{{ hook(constant('HOOK_CHARACTERS_BEFORE_DEATHS')) }}
{{ hook('HOOK_CHARACTERS_BEFORE_DEATHS') }}
{% if deaths|length > 0 %}
<!-- DEATHS -->
@@ -283,7 +283,7 @@
<!-- FRAGS_END -->
{% endif %}
{{ hook(constant('HOOK_CHARACTERS_BEFORE_SIGNATURE')) }}
{{ hook('HOOK_CHARACTERS_BEFORE_SIGNATURE') }}
{% if setting('core.signature_enabled') %}
<!-- SIGNATURE -->
@@ -327,7 +327,7 @@
</table>
<!-- SIGNATURE_END -->
{% endif %}
{{ hook(constant('HOOK_CHARACTERS_AFTER_SIGNATURE')) }}
{{ hook('HOOK_CHARACTERS_AFTER_SIGNATURE') }}
{% if not player.isHidden() %}
{% set rows = 0 %}
<!-- ACCOUNT_INFORMATION -->
@@ -377,7 +377,7 @@
</tr>
</table>
<!-- ACCOUNT_INFORMATION_END -->
{{ hook(constant('HOOK_CHARACTERS_AFTER_ACCOUNT')) }}
{{ hook('HOOK_CHARACTERS_AFTER_ACCOUNT') }}
<!-- CHARACTERS_LIST -->
<br/><br/>
<table border="0" cellspacing="1" cellpadding="4" width="100%">
@@ -421,7 +421,7 @@
</table>
<!-- CHARACTERS_LIST_END -->
{% endif %}
{{ hook(constant('HOOK_CHARACTERS_AFTER_CHARACTERS')) }}
{{ hook('HOOK_CHARACTERS_AFTER_CHARACTERS') }}
{% if canEdit %}
<a href="{{ constant('ADMIN_URL') }}?p=players&id={{ player.getId() }}" title="Edit in Admin Panel" target="_blank">
<img src="images/edit.png"/>Edit

View File

@@ -1,6 +1,9 @@
<style>
.myaac-table tbody tr:nth-child(even) {background: {{ config.lightborder }}}
.myaac-table tbody tr:nth-child(odd) {background: {{ config.darkborder }}}
.myaac-table thead td {background: {{ config.vdarkborder }}; color: #ffffff !important;}
.myaac-table tfoot td {background: {{ config.vdarkborder }}; color: #ffffff !important;}
.myaac-table {border-spacing: 1px;}
.myaac-table > tbody > tr:nth-child(even) {background: {{ config.lightborder }}}
.myaac-table > tbody > tr:nth-child(odd) {background: {{ config.darkborder }}}
.myaac-table > tbody > tr > td {padding: 4px; }
.myaac-table > thead > tr > td {padding: 4px; background: {{ config.vdarkborder }}; color: #ffffff !important;}
.myaac-table > thead > tr > th {padding: 4px; background: {{ config.vdarkborder }}; color: #ffffff !important;}
.myaac-table > tfoot > tr > td {padding: 4px; background: {{ config.vdarkborder }}; color: #ffffff !important;}
</style>

View File

@@ -101,6 +101,8 @@ $twig->addFunction($function);
$function = new TwigFunction('hook', function ($context, $hook, array $params = []) {
global $hooks;
//note($hook);
if(is_string($hook)) {
if (defined($hook)) {
$hook = constant($hook);

View File

@@ -130,6 +130,7 @@
<div style="float: right; margin-top: 20px;" >
{% apply spaceless %}
<form class="MediumButtonForm" action="{{ getLink('account/create') }}" method="post" >
{{ csrf() }}
<div class="MediumButtonBackground" style="background-image:url({{ template_path }}/images/global/buttons/mediumbutton.gif)" onMouseOver="MouseOverBigButton(this);" onMouseOut="MouseOutBigButton(this);">
<div class="MediumButtonOver" style="background-image:url({{ template_path }}/images/global/buttons/mediumbutton-over.gif)" onMouseOver="MouseOverBigButton(this);" onMouseOut="MouseOutBigButton(this);"></div>
<input class="MediumButtonText" type="image" name="Create Account" alt="Create Account" src="{{ template_path }}/images/global/buttons/mediumbutton_createaccount.png" />

View File

@@ -37,7 +37,9 @@ if(isset($config['boxes']))
$tmp = str_replace('/', '_', PAGE);
$exp = explode('/', PAGE);
if(PAGE !== 'account/create' && PAGE !== 'account/lost' && isset($exp[1])) {
if ($exp[0] === 'account') {
if ($exp[0] === 'account' && $exp[1] === 'lost') {
$tmp = 'account_lost';
} elseif ($exp[0] === 'account') {
$tmp = 'account_manage';
} else if ($exp[0] === 'news' && $exp[1] === 'archive') {
$tmp = 'news_archive';
@@ -90,24 +92,24 @@ if(isset($config['boxes']))
// mouse-over and click events of the loginbox
function MouseOverLoginBoxText(source)
{
source.lastChild.style.visibility = "visible";
source.firstChild.style.visibility = "hidden";
source.lastElementChild.style.visibility = "visible";
source.firstElementChild.style.visibility = "hidden";
}
function MouseOutLoginBoxText(source)
{
source.firstChild.style.visibility = "visible";
source.lastChild.style.visibility = "hidden";
source.firstElementChild.style.visibility = "visible";
source.lastElementChild.style.visibility = "hidden";
}
function LoginButtonAction()
{
if(loginStatus == "false") {
if(loginStatus === "false") {
window.location = "<?php echo getLink('account/manage'); ?>";
} else {
window.location = "<?php echo getLink('account/manage'); ?>";
}
}
function LoginstatusTextAction(source) {
if(loginStatus == "false") {
if(loginStatus === "false") {
window.location = "<?php echo getLink('account/create'); ?>";
} else {
window.location = "<?php echo getLink('account/logout'); ?>";
@@ -226,11 +228,11 @@ if(isset($config['boxes']))
// mouse-over effects of menubuttons and submenuitems
function MouseOverMenuItem(source)
{
source.firstChild.style.visibility = "visible";
source.firstElementChild.style.visibility = "visible";
}
function MouseOutMenuItem(source)
{
source.firstChild.style.visibility = "hidden";
source.firstElementChild.style.visibility = "hidden";
}
function MouseOverSubmenuItem(source)
{
@@ -336,7 +338,7 @@ if(isset($config['boxes']))
<div id="LoginBottom" class="Loginstatus" style="background-image:url(<?php echo $template_path; ?>/images/general/box-bottom.gif)" ></div>
</div>
<div-- id='Menu'>
<div id='Menu'>
<div id='MenuTop' style='background-image:url(<?php echo $template_path; ?>/images/general/box-top.gif);'></div>
<?php
@@ -401,6 +403,7 @@ foreach($config['menu_categories'] as $id => $cat) {
<?php
}
?>
</div>
<script type="text/javascript">
InitializePage();
</script>

View File

@@ -1,11 +1,11 @@
function MouseOverBigButton(source) {
if (source?.firstChild?.style) {
source.firstChild.style.visibility = "visible";
if (source?.firstElementChild?.style) {
source.firstElementChild.style.visibility = "visible";
}
}
function MouseOutBigButton(source) {
if (source?.firstChild?.style) {
source.firstChild.style.visibility = "hidden";
if (source?.firstElementChild?.style) {
source.firstElementChild.style.visibility = "hidden";
}
}
function BigButtonAction(path) {