diff --git a/CHANGELOG.md b/CHANGELOG.md index 66117c5d..99fda8da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,57 @@ # Changelog +## [1.0-RC.2 - 25.10.2024] + +Still waiting for your reports about bugs found in this release. We are very close to stable release. + +### Added +* feat: rate limit settings for blocking accounts login attempts (@gpedro, #266) +* search by email in accounts editor (https://github.com/slawkens/myaac/commit/c2ec46824621468f2a1cb4046805c485ed13fea5) +* New hooks in account manage + create (https://github.com/slawkens/myaac/commit/93641fc68ac9a5f1479329e2bd41380c19534d5d) + +### Changed +* chore: drop raw queries + accounts - search by email + accounts - required min size for search by account number (@gpedro, #266) +* Use https for outfit & item images (https://github.com/slawkens/myaac/commit/71c00aa5e01fbdfd88802912e200dd1025976231) +* Do not require players & guilds tables on install (https://github.com/slawkens/myaac/commit/779aa152fa940261c9b161533946f44e288597a2) +* Do not create player if there is no players table in db (https://github.com/slawkens/myaac/commit/201f95caa8b70e88fa651eac8c3c3aa7cd765bd0) + +### Fixed +* Highscore frags fixed for TFS 0.3 (@Scrollog, #263) +* Missing groups variable #262. thanks, @Scrollog for reporting (https://github.com/slawkens/myaac/commit/8d8bdb6dac6df21672ac77288fff2f2f8d6eb665) +* Verified email for login.php (@gpedro, #265) +* Warning if core.account_country is disabled (https://github.com/slawkens/myaac/commit/ab73d60c61e14a1cacdb6cfbf7f89f4bf3be0833) + + +## [1.0-RC.1 - 23.07.2024] + +Changes since 1.0-beta: + +### Added +* Feat: Hooks priority (https://github.com/slawkens/myaac/commit/dc17b701da053e04bfa64e21be9247a4f07505e1) +* Make autoload of pages, commands and themes configurable (https://github.com/slawkens/myaac/commit/c1d4b4f80cd6bb85507ee9471e47013955a26a91) +* Fraggers in characters page for TFS 1.x and canary (https://github.com/slawkens/myaac/commit/42f99c3edc8de39cccc5632cb42e88b24579c5a6) +* New hooks: HOOK_INSTALL_FINISH, HOOK_ACCOUNT_CREATE_CHARACTER_* (https://github.com/slawkens/myaac/commit/08ac8ebade106521a5c7396faa5ce7006e629f7c, https://github.com/slawkens/myaac/commit/45dda5e834ff2059faea6ef9be2efa76f1723cbd) + +### Changed +* Allow account_create_character_create even if account_mail_verify is activated (https://github.com/slawkens/myaac/commit/203e411b626fe62401a4b74a48420769e512aa39) +* Create guild_rank entries, in case MySQL trigger not loaded (https://github.com/slawkens/myaac/commit/d9c1b2507c81f306970642b35e4bf5f7cc04a6f2, https://github.com/slawkens/myaac/commit/47a19e85dd84e9f3b39a1b29cfc2c04b004832b9) +* Set Admin Account verified by default (https://github.com/slawkens/myaac/commit/cd49dfc79942f3301ce9c0b8d899b9f39bda9a41) +* Refactor account routes into sub folders (https://github.com/slawkens/myaac/commit/bdc0c43d3fd3a51030c3e916bdb9f008468f5ecd) +* Order towns by id (https://github.com/slawkens/myaac/commit/9ea2a5067fc4b75de395f381577b18914132ad84) +* Do not create news about myaac, if any news already exist (on installation (https://github.com/slawkens/myaac/commit/504242fb846b73b56b87bc1e39d070687ad7f5b4) + +### Fixed +* Not working google recaptcha plugin (https://github.com/slawkens/myaac/commit/a1bcb217ecf4e21fd58da4ba491da1852029898a) +* Not working account create if account_country is disabled (https://github.com/slawkens/myaac/commit/933b681a9fcdbb6283e0469b3806d2ded492d232) +* Account verify - do not allow login without verified email (Thanks @anyeor, https://github.com/slawkens/myaac/commit/fcb13f3c0fb8ceafda0bd614a229a26a269432bd) +* Detect tools/ext exists on install to prevent broken installs (https://github.com/slawkens/myaac/commit/10a739773c4f2911876bc802a0ee0537c3e00a92) +* Cache reloading each time page refreshes (https://github.com/slawkens/myaac/commit/ec96985872057340112f65073efc0c4bf86dddb0) +* Highscores frags for TFS 1.x and canary (https://github.com/slawkens/myaac/commit/a04d186c22912915f0a7873dfe677ef3b5a23c79) +* Monsters page: monster not found exception (https://github.com/slawkens/myaac/commit/ef79b99b8acc179f14b8475547347d9daca27512) +* Fixed bug if \ are not present in monster.xml (https://github.com/slawkens/myaac/commit/57b47ab7983f625c7c0ef4f5303a4d07ef172786) +* fastRoute duplicate errors (https://github.com/slawkens/myaac/commit/4c0739d3e93812dff0c33849ea3f38e4e49113ac) +* useGuildNick displaying (https://github.com/slawkens/myaac/commit/0db0ec1aa47e044c26bc403ff5078a2115d086f8) + ## [1.0-beta - 18.05.2024] Minimum PHP version for this release is 8.1. diff --git a/aac b/aac index d87042f8..d4ce7b7d 100644 --- a/aac +++ b/aac @@ -9,14 +9,13 @@ if(!IS_CLI) { } require_once SYSTEM . 'functions.php'; -require_once SYSTEM . 'init.php'; define('SELF_NAME', basename(__FILE__)); use MyAAC\Plugins; use Symfony\Component\Console\Application; -$application = new Application(); +$application = new Application('MyAAC', MYAAC_VERSION); $commandsGlob = glob(SYSTEM . 'src/Commands/*.php'); foreach ($commandsGlob as $item) { @@ -34,7 +33,4 @@ foreach ($pluginCommands as $item) { $application->add(require $item); } -$application->setName('MyAAC'); -$application->setVersion(MYAAC_VERSION); - $application->run(); diff --git a/admin/pages/accounts.php b/admin/pages/accounts.php index d42a2ee6..c2154299 100644 --- a/admin/pages/accounts.php +++ b/admin/pages/accounts.php @@ -8,6 +8,7 @@ * @link https://my-aac.org */ +use MyAAC\Models\Account as AccountModel; use MyAAC\Models\Player; defined('MYAAC') or die('Direct access not allowed!'); @@ -22,10 +23,7 @@ $use_datatable = true; if (setting('core.account_country')) require SYSTEM . 'countries.conf.php'; -$nameOrNumberColumn = 'name'; -if (USE_ACCOUNT_NUMBER) { - $nameOrNumberColumn = 'number'; -} +$nameOrNumberColumn = getAccountIdentityColumn(); $hasSecretColumn = $db->hasColumn('accounts', 'secret'); $hasCoinsColumn = $db->hasColumn('accounts', 'coins'); @@ -51,36 +49,51 @@ $acc_type = setting('core.account_types'); limit(11)->get(['email', 'id']); + if (count($accountModel) == 0) { + echo_error('No entries found.'); + } else if (count($accountModel) == 1) { + $id = $accountModel->first()->getKey(); + } else if (count($accountModel) > 10) { + echo_error('Specified e-mail resulted with too many accounts.'); + } +} else if (isset($_REQUEST['search'])) { $search_account = $_REQUEST['search']; - if (strlen($search_account) < 3 && !Validator::number($search_account)) { - echo_error('Player name is too short.'); + $min_size = 3; + if (in_array($nameOrNumberColumn, ['id', 'number'])) { + $min_size = 1; + } + + if (strlen($search_account) < $min_size && !Validator::number($search_account)) { + echo_error('Account ' . $nameOrNumberColumn . ' is too short.'); } else { - $query = $db->query('SELECT `id` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` = ' . $db->quote($search_account)); - if ($query->rowCount() == 1) { - $query = $query->fetch(); - $id = (int)$query['id']; + $query = AccountModel::where($nameOrNumberColumn, '=', $search_account)->limit(11)->get(['id', $nameOrNumberColumn]); + if (count($query) == 0) { + echo_error('No entries found.'); + } else if (count($query) == 1) { + $id = $query->first()->getKey(); + } else if (count($query) > 10) { + echo_error('Specified name resulted with too many accounts.'); } else { - $query = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` LIKE ' . $db->quote('%' . $search_account . '%')); - if ($query->rowCount() > 0 && $query->rowCount() <= 10) { - $str_construct = 'Do you mean?'; - echo_error($str_construct); - } else if ($query->rowCount() > 10) - echo_error('Specified name resulted with too many accounts.'); - else - echo_error('No entries found.'); + $str_construct = 'Do you mean?'; + echo_error($str_construct); } } } ?>
0) { $account = new OTS_Account(); $account->load($id); @@ -143,7 +156,9 @@ else if (isset($_REQUEST['search'])) { $rl_loca = $_POST['rl_loca']; //country - $rl_country = $_POST['rl_country']; + if(setting('core.account_country')) { + $rl_country = $_POST['rl_country']; + } $web_flags = $_POST['web_flags']; verify_number($web_flags, 'Web Flags', 1); @@ -190,7 +205,11 @@ else if (isset($_REQUEST['search'])) { } $account->setRLName($rl_name); $account->setLocation($rl_loca); - $account->setCountry($rl_country); + + if(setting('core.account_country')) { + $account->setCountry($rl_country); + } + $account->setCustomField('created', $created); $account->setWebFlags($web_flags); $account->setCustomField('web_lastlogin', $web_lastlogin); @@ -214,7 +233,7 @@ else if (isset($_REQUEST['search'])) { } } } else if ($id == 0) { - $accounts_db = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '`' . ($hasTypeColumn ? ',type' : ($hasGroupColumn ? ',group_id' : '')) . ' FROM `accounts` ORDER BY `id` ASC'); + $accounts_db = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '`' . ($hasTypeColumn ? ',type' : ($hasGroupColumn ? ',group_id' : '')) . ', email FROM `accounts` ORDER BY `id` ASC'); ?>
@@ -226,8 +245,9 @@ else if (isset($_REQUEST['search'])) { ID - + + E-Mail Position Edit @@ -238,6 +258,7 @@ else if (isset($_REQUEST['search'])) { +
+
+
+ + +
+ + +
+
+
diff --git a/admin/pages/mailer.php b/admin/pages/mailer.php index d9cf8888..1f8d3188 100644 --- a/admin/pages/mailer.php +++ b/admin/pages/mailer.php @@ -7,6 +7,9 @@ * @copyright 2019 MyAAC * @link https://my-aac.org */ + +use MyAAC\Models\Account; + defined('MYAAC') or die('Direct access not allowed!'); $title = 'Mailer'; @@ -61,15 +64,15 @@ if (!empty($mail_content) && !empty($mail_subject) && empty($mail_to)) { $add = ' AND `email_verified` = 1'; } - $query = $db->query('SELECT `email` FROM `accounts` WHERE `email` != ""' . $add); + $query = Account::where('email', '!=', '')->get(['email']); foreach ($query as $email) { - if (_mail($email['email'], $mail_subject, $mail_content)) { + if (_mail($email->email, $mail_subject, $mail_content)) { $success++; } else { $failed++; echo '
'; - error('An error occorred while sending email to ' . $email['email'] . '. For Admin: More info can be found in system/logs/mailer-error.log'); + error('An error occorred while sending email to ' . $email->email . '. For Admin: More info can be found in system/logs/mailer-error.log'); } } diff --git a/admin/pages/mass_account.php b/admin/pages/mass_account.php index dc921ac5..46c9bc9d 100644 --- a/admin/pages/mass_account.php +++ b/admin/pages/mass_account.php @@ -24,20 +24,13 @@ $freePremium = $config['lua']['freePremium']; function admin_give_points($points) { - global $db, $hasPointsColumn; + global $hasPointsColumn; if (!$hasPointsColumn) { displayMessage('Points not supported.'); return; } - - $statement = $db->prepare('UPDATE `accounts` SET `premium_points` = `premium_points` + :points'); - if (!$statement) { - displayMessage('Failed to prepare query statement.'); - return; - } - if (!Account::query()->increment('premium_points', $points)) { displayMessage('Failed to add points.'); return; @@ -47,7 +40,7 @@ function admin_give_points($points) function admin_give_coins($coins) { - global $db, $hasCoinsColumn; + global $hasCoinsColumn; if (!$hasCoinsColumn) { displayMessage('Coins not supported.'); @@ -62,24 +55,6 @@ function admin_give_coins($coins) displayMessage($coins . ' coins added to all accounts.', true); } -function query_add_premium($column, $value_query, $condition_query = '1=1', $params = []) -{ - global $db; - - $statement = $db->prepare("UPDATE `accounts` SET `{$column}` = $value_query WHERE $condition_query"); - if (!$statement) { - displayMessage('Failed to prepare query statement.'); - return false; - } - - if (!$statement->execute($params)) { - displayMessage('Failed to add premium days.'); - return false; - } - - return true; -} - function admin_give_premdays($days) { global $db, $freePremium; @@ -94,9 +69,9 @@ function admin_give_premdays($days) // othire if ($db->hasColumn('accounts', 'premend')) { // append premend - if (query_add_premium('premend', '`premend` + :value', '`premend` > :now', ['value' => $value, 'now' => $now])) { + if (Account::where('premend', '>', $now)->increment('premend', $value)) { // set premend - if (query_add_premium('premend', ':value', '`premend` <= :now', ['value' => $now + $value, 'now' => $now])) { + if (Account::where('premend', '<=', $now)->update(['premend' => $now + $value])) { displayMessage($days . ' premium days added to all accounts.', true); return; } else { @@ -114,11 +89,11 @@ function admin_give_premdays($days) // tfs 0.x if ($db->hasColumn('accounts', 'premdays')) { // append premdays - if (query_add_premium('premdays', '`premdays` + :value', '1=1', ['value' => $days])) { + if (Account::query()->update(['premdays' => $days])) { // append lastday - if (query_add_premium('lastday', '`lastday` + :value', '`lastday` > :now', ['value' => $value, 'now' => $now])) { + if (Account::where('lastday', '>', $now)->increment('lastday', $value)) { // set lastday - if (query_add_premium('lastday', ':value', '`lastday` <= :now', ['value' => $now + $value, 'now' => $now])) { + if (Account::where('lastday', '<=', $now)->update(['lastday' => $now + $value])) { displayMessage($days . ' premium days added to all accounts.', true); return; } else { @@ -142,9 +117,9 @@ function admin_give_premdays($days) // tfs 1.x if ($db->hasColumn('accounts', 'premium_ends_at')) { // append premium_ends_at - if (query_add_premium('premium_ends_at', '`premium_ends_at` + :value', '`premium_ends_at` > :now', ['value' => $value, 'now' => $now])) { + if (Account::where('premium_ends_at', '>', $now)->increment('premium_ends_at', $value)) { // set premium_ends_at - if (query_add_premium('premium_ends_at', ':value', '`premium_ends_at` <= :now', ['value' => $now + $value, 'now' => $now])) { + if (Account::where('premium_ends_at', '<=', $now)->update(['premium_ends_at' => $now + $value])) { displayMessage($days . ' premium days added to all accounts.', true); return; } else { diff --git a/admin/pages/modules/created.php b/admin/pages/modules/created.php index cc72d660..f59e4e86 100644 --- a/admin/pages/modules/created.php +++ b/admin/pages/modules/created.php @@ -7,7 +7,7 @@ defined('MYAAC') or die('Direct access not allowed!'); $accounts = 0; if ($db->hasColumn('accounts', 'created')) { - $accounts = Account::orderByDesc('created')->limit(10)->get(['created', (USE_ACCOUNT_NAME ? 'name' : 'id')])->toArray(); + $accounts = Account::orderByDesc('created')->limit(10)->get(['id', 'created'])->toArray(); } $twig->display('created.html.twig', array( diff --git a/admin/pages/modules/templates/created.html.twig b/admin/pages/modules/templates/created.html.twig index 862e6f18..b42b6b02 100644 --- a/admin/pages/modules/templates/created.html.twig +++ b/admin/pages/modules/templates/created.html.twig @@ -19,7 +19,7 @@ {% set i = i + 1 %} {{ i }} - {{ result.name }} + {{ result.id }} {{ result.created|date("M d Y, H:i:s") }} {% endfor %} diff --git a/admin/pages/news.php b/admin/pages/news.php index d74d6405..61571597 100644 --- a/admin/pages/news.php +++ b/admin/pages/news.php @@ -26,7 +26,7 @@ if (!hasFlag(FLAG_CONTENT_PAGES) && !superAdmin()) { header('X-XSS-Protection:0'); -// some constants, used mainly by database (cannot by modified without schema changes) +// some constants, used mainly by database (cannot be modified without schema changes) const NEWS_TITLE_LIMIT = 100; const NEWS_BODY_LIMIT = 65535; // maximum news body length const ARTICLE_TEXT_LIMIT = 300; @@ -136,9 +136,18 @@ if($action == 'edit' || $action == 'new') { $query = $db->query('SELECT * FROM ' . $db->tableName(TABLE_PREFIX . 'news')); $newses = array(); + +$cachePlayers = []; foreach ($query as $_news) { - $_player = new OTS_Player(); - $_player->load($_news['player_id']); + $playerId = $_news['player_id']; + if (isset($cachePlayers[$playerId])) { + $_player = $cachePlayers[$playerId]; + } + else { + $_player = new OTS_Player(); + $_player->load($playerId); + $cachePlayers[$playerId] = $_player; + } $newses[$_news['type']][] = array( 'id' => $_news['id'], @@ -147,7 +156,7 @@ foreach ($query as $_news) { 'title' => $_news['title'], 'date' => $_news['date'], 'player_name' => $_player->isLoaded() ? $_player->getName() : '', - 'player_link' => $_player->isLoaded() ? getPlayerLink($_player->getName(), false) : '', + 'player_link' => $_player->isLoaded() ? getPlayerLink($_player, false) : '', ); } diff --git a/admin/pages/players.php b/admin/pages/players.php index e8084afd..c44bc012 100644 --- a/admin/pages/players.php +++ b/admin/pages/players.php @@ -51,22 +51,20 @@ else if (isset($_REQUEST['search'])) { if (strlen($search_player) < 3 && !Validator::number($search_player)) { echo_error('Player name is too short.'); } else { - $query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($search_player)); - if ($query->rowCount() == 1) { - $query = $query->fetch(); - $id = (int)$query['id']; + $query = Player::where('name', 'like', '%' . $search_player . '%')->orderBy('name')->limit(11)->get(['id', 'name']); + if (count($query) == 0) { + echo_error('No entries found.'); + } else if (count($query) == 1) { + $id = $query->first()->getKey(); + } else if (count($query) > 10) { + echo_error('Specified name resulted with too many players.'); } else { - $query = $db->query('SELECT `id`, `name` FROM `players` WHERE `name` LIKE ' . $db->quote('%' . $search_player . '%')); - if ($query->rowCount() > 0 && $query->rowCount() <= 10) { - $str_construct = 'Do you mean?'; - echo_error($str_construct); - } else if ($query->rowCount() > 10) - echo_error('Specified name resulted with too many players.'); - else - echo_error('No entries found.'); + $str_construct = 'Do you mean?
    '; + foreach ($query as $row) { + $str_construct .= '
  • ' . $row->name . '
  • '; + } + $str_construct .= '
'; + echo_error($str_construct); } } } @@ -307,7 +305,7 @@ else if (isset($_REQUEST['search'])) { } } } else if ($id == 0) { - $players_db = $db->query('SELECT `id`, `name`, `level` FROM `players` ORDER BY `id` asc'); + $players_db = Player::orderBy('id')->get(['id','name', 'level']); ?>
@@ -327,11 +325,11 @@ else if (isset($_REQUEST['search'])) { - - - + id; ?> + name; ?> + level; ?> - + diff --git a/admin/pages/plugins.php b/admin/pages/plugins.php index f130a15c..8e87f75e 100644 --- a/admin/pages/plugins.php +++ b/admin/pages/plugins.php @@ -21,7 +21,13 @@ if (!getBoolean(setting('core.admin_plugins_manage_enable'))) { warning('Plugin installation and management is disabled in Settings.
If you wish to enable, go to Settings and enable Enable Plugins Manage.'); } else { - $twig->display('admin.plugins.form.html.twig'); + $pluginUploadEnabled = true; + if(!\class_exists('\ZipArchive')) { + error('Please install PHP zip extension. Plugins upload disabled until then.'); + $pluginUploadEnabled = false; + } + + $twig->display('admin.plugins.form.html.twig', ['pluginUploadEnabled' => $pluginUploadEnabled]); if (isset($_POST['uninstall'])) { $uninstall = $_POST['uninstall']; diff --git a/common.php b/common.php index 2057e972..c63f4494 100644 --- a/common.php +++ b/common.php @@ -26,8 +26,8 @@ if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.'); const MYAAC = true; -const MYAAC_VERSION = '1.0-beta.2'; -const DATABASE_VERSION = 40; +const MYAAC_VERSION = '1.0-RC.2'; +const DATABASE_VERSION = 41; const TABLE_PREFIX = 'myaac_'; define('START_TIME', microtime(true)); define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX')); diff --git a/composer.json b/composer.json index 47d68dbe..f36588c7 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "require": { - "php": "^8.0", + "php": "^8.1", "ext-pdo": "*", "ext-pdo_mysql": "*", "ext-json": "*", @@ -18,7 +18,7 @@ "symfony/string": "^6.4", "symfony/var-dumper": "^6.4", "filp/whoops": "^2.15", - "maximebf/debugbar": "dev-master" + "maximebf/debugbar": "1.*" }, "require-dev": { "phpstan/phpstan": "^1.10" diff --git a/composer.lock b/composer.lock index ea12d783..f9296128 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "230e3acec441b5af61be78d2d3b0b364", + "content-hash": "27c63d07ab6337cd8bb5b59f2b2e08d8", "packages": [ { "name": "brick/math", @@ -137,24 +137,24 @@ }, { "name": "composer/semver", - "version": "3.4.0", + "version": "3.4.3", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -198,7 +198,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" + "source": "https://github.com/composer/semver/tree/3.4.3" }, "funding": [ { @@ -214,7 +214,7 @@ "type": "tidelift" } ], - "time": "2023-08-31T09:50:34+00:00" + "time": "2024-09-19T14:15:21+00:00" }, { "name": "doctrine/inflector", @@ -309,16 +309,16 @@ }, { "name": "dragonmantank/cron-expression", - "version": "v3.3.3", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a" + "reference": "8c784d071debd117328803d86b2097615b457500" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", - "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", + "reference": "8c784d071debd117328803d86b2097615b457500", "shasum": "" }, "require": { @@ -331,10 +331,14 @@ "require-dev": { "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.0", - "phpstan/phpstan-webmozart-assert": "^1.0", "phpunit/phpunit": "^7.0|^8.0|^9.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, "autoload": { "psr-4": { "Cron\\": "src/Cron/" @@ -358,7 +362,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" }, "funding": [ { @@ -366,7 +370,7 @@ "type": "github" } ], - "time": "2023-08-10T19:36:49+00:00" + "time": "2024-10-09T13:47:03+00:00" }, { "name": "erusev/parsedown", @@ -420,26 +424,26 @@ }, { "name": "filp/whoops", - "version": "2.15.4", + "version": "2.16.0", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546" + "reference": "befcdc0e5dce67252aa6322d82424be928214fa2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/a139776fa3f5985a50b509f2a02ff0f709d2a546", - "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546", + "url": "https://api.github.com/repos/filp/whoops/zipball/befcdc0e5dce67252aa6322d82424be928214fa2", + "reference": "befcdc0e5dce67252aa6322d82424be928214fa2", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0 || ^8.0", + "php": "^7.1 || ^8.0", "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { - "mockery/mockery": "^0.9 || ^1.0", - "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", - "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" }, "suggest": { "symfony/var-dumper": "Pretty print complex values better with var-dumper available", @@ -479,7 +483,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.15.4" + "source": "https://github.com/filp/whoops/tree/2.16.0" }, "funding": [ { @@ -487,20 +491,20 @@ "type": "github" } ], - "time": "2023-11-03T12:00:00+00:00" + "time": "2024-09-25T12:00:00+00:00" }, { "name": "illuminate/collections", - "version": "v10.48.10", + "version": "v10.48.25", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", - "reference": "f9589f1063a449111dcaa1d68285b507d9483a95" + "reference": "48de3d6bc6aa779112ddcb608a3a96fc975d89d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/f9589f1063a449111dcaa1d68285b507d9483a95", - "reference": "f9589f1063a449111dcaa1d68285b507d9483a95", + "url": "https://api.github.com/repos/illuminate/collections/zipball/48de3d6bc6aa779112ddcb608a3a96fc975d89d8", + "reference": "48de3d6bc6aa779112ddcb608a3a96fc975d89d8", "shasum": "" }, "require": { @@ -542,20 +546,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-03-20T20:09:13+00:00" + "time": "2024-11-21T14:02:44+00:00" }, { "name": "illuminate/conditionable", - "version": "v10.48.10", + "version": "v10.48.25", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", - "reference": "d0958e4741fc9d6f516a552060fd1b829a85e009" + "reference": "3ee34ac306fafc2a6f19cd7cd68c9af389e432a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/conditionable/zipball/d0958e4741fc9d6f516a552060fd1b829a85e009", - "reference": "d0958e4741fc9d6f516a552060fd1b829a85e009", + "url": "https://api.github.com/repos/illuminate/conditionable/zipball/3ee34ac306fafc2a6f19cd7cd68c9af389e432a5", + "reference": "3ee34ac306fafc2a6f19cd7cd68c9af389e432a5", "shasum": "" }, "require": { @@ -588,20 +592,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-02-03T08:06:17+00:00" + "time": "2024-11-21T14:02:44+00:00" }, { "name": "illuminate/container", - "version": "v10.48.10", + "version": "v10.48.25", "source": { "type": "git", "url": "https://github.com/illuminate/container.git", - "reference": "ddc26273085fad3c471b2602ad820e0097ff7939" + "reference": "ed6253f7dd3a67d468b2cc7a69a657e1f14c7ba3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/container/zipball/ddc26273085fad3c471b2602ad820e0097ff7939", - "reference": "ddc26273085fad3c471b2602ad820e0097ff7939", + "url": "https://api.github.com/repos/illuminate/container/zipball/ed6253f7dd3a67d468b2cc7a69a657e1f14c7ba3", + "reference": "ed6253f7dd3a67d468b2cc7a69a657e1f14c7ba3", "shasum": "" }, "require": { @@ -639,20 +643,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-06-18T09:12:03+00:00" + "time": "2024-11-21T14:02:44+00:00" }, { "name": "illuminate/contracts", - "version": "v10.48.10", + "version": "v10.48.25", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac" + "reference": "f90663a69f926105a70b78060a31f3c64e2d1c74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac", - "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/f90663a69f926105a70b78060a31f3c64e2d1c74", + "reference": "f90663a69f926105a70b78060a31f3c64e2d1c74", "shasum": "" }, "require": { @@ -687,20 +691,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-01-15T18:52:32+00:00" + "time": "2024-11-21T14:02:44+00:00" }, { "name": "illuminate/database", - "version": "v10.48.10", + "version": "v10.48.25", "source": { "type": "git", "url": "https://github.com/illuminate/database.git", - "reference": "eb8edf206d3a6eea8894bc6e21f53469e27dd5c9" + "reference": "088cb4ffae1ef180b2b83d9d930763ae03eea41a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/database/zipball/eb8edf206d3a6eea8894bc6e21f53469e27dd5c9", - "reference": "eb8edf206d3a6eea8894bc6e21f53469e27dd5c9", + "url": "https://api.github.com/repos/illuminate/database/zipball/088cb4ffae1ef180b2b83d9d930763ae03eea41a", + "reference": "088cb4ffae1ef180b2b83d9d930763ae03eea41a", "shasum": "" }, "require": { @@ -760,11 +764,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-04-29T13:23:17+00:00" + "time": "2024-11-21T14:02:44+00:00" }, { "name": "illuminate/macroable", - "version": "v10.48.10", + "version": "v10.48.25", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -810,16 +814,16 @@ }, { "name": "illuminate/support", - "version": "v10.48.10", + "version": "v10.48.25", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "ee3a1aaed36d916654ce0ae09dfbd38644a4f582" + "reference": "64b258f80175c658aef9e22dd3f2ba18c99b243c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/ee3a1aaed36d916654ce0ae09dfbd38644a4f582", - "reference": "ee3a1aaed36d916654ce0ae09dfbd38644a4f582", + "url": "https://api.github.com/repos/illuminate/support/zipball/64b258f80175c658aef9e22dd3f2ba18c99b243c", + "reference": "64b258f80175c658aef9e22dd3f2ba18c99b243c", "shasum": "" }, "require": { @@ -877,20 +881,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-04-07T17:47:33+00:00" + "time": "2024-11-21T14:02:44+00:00" }, { "name": "matomo/device-detector", - "version": "6.3.1", + "version": "6.4.1", "source": { "type": "git", "url": "https://github.com/matomo-org/device-detector.git", - "reference": "8096093346917ee2477d802ab3b00c4c091c5cee" + "reference": "0d364e0dd6c177da3c24cd4049178026324fd7ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/8096093346917ee2477d802ab3b00c4c091c5cee", - "reference": "8096093346917ee2477d802ab3b00c4c091c5cee", + "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/0d364e0dd6c177da3c24cd4049178026324fd7ac", + "reference": "0d364e0dd6c177da3c24cd4049178026324fd7ac", "shasum": "" }, "require": { @@ -946,20 +950,20 @@ "source": "https://github.com/matomo-org/matomo", "wiki": "https://dev.matomo.org/" }, - "time": "2024-04-12T12:16:21+00:00" + "time": "2024-09-24T13:50:04+00:00" }, { "name": "maximebf/debugbar", - "version": "dev-master", + "version": "v1.23.3", "source": { "type": "git", "url": "https://github.com/maximebf/php-debugbar.git", - "reference": "40d2d7e986082287b47bb6f675541ba43db09398" + "reference": "687400043d77943ef95e8417cb44e1673ee57844" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/40d2d7e986082287b47bb6f675541ba43db09398", - "reference": "40d2d7e986082287b47bb6f675541ba43db09398", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/687400043d77943ef95e8417cb44e1673ee57844", + "reference": "687400043d77943ef95e8417cb44e1673ee57844", "shasum": "" }, "require": { @@ -978,11 +982,10 @@ "monolog/monolog": "Log using Monolog", "predis/predis": "Redis storage" }, - "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.22-dev" + "dev-master": "1.23-dev" } }, "autoload": { @@ -1013,9 +1016,9 @@ ], "support": { "issues": "https://github.com/maximebf/php-debugbar/issues", - "source": "https://github.com/maximebf/php-debugbar/tree/master" + "source": "https://github.com/maximebf/php-debugbar/tree/v1.23.3" }, - "time": "2024-04-15T10:55:03+00:00" + "time": "2024-10-29T12:24:25+00:00" }, { "name": "mustangostang/spyc", @@ -1073,16 +1076,16 @@ }, { "name": "nesbot/carbon", - "version": "2.72.3", + "version": "2.72.5", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83" + "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/0c6fd108360c562f6e4fd1dedb8233b423e91c83", - "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/afd46589c216118ecd48ff2b95d77596af1e57ed", + "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed", "shasum": "" }, "require": { @@ -1116,8 +1119,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-3.x": "3.x-dev", - "dev-master": "2.x-dev" + "dev-master": "3.x-dev", + "dev-2.x": "2.x-dev" }, "laravel": { "providers": [ @@ -1176,7 +1179,7 @@ "type": "tidelift" } ], - "time": "2024-01-25T10:35:09+00:00" + "time": "2024-06-03T19:18:41+00:00" }, { "name": "nikic/fast-route", @@ -1289,16 +1292,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.1", + "version": "v6.9.3", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18" + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e", + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e", "shasum": "" }, "require": { @@ -1358,7 +1361,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.1" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3" }, "funding": [ { @@ -1366,7 +1369,7 @@ "type": "github" } ], - "time": "2023-11-25T22:23:28+00:00" + "time": "2024-11-24T18:04:13+00:00" }, { "name": "psr/clock", @@ -1471,16 +1474,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -1515,9 +1518,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "psr/simple-cache", @@ -1572,16 +1575,16 @@ }, { "name": "symfony/console", - "version": "v6.4.7", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f" + "reference": "f1fc6f47283e27336e7cebb9e8946c8de7bff9bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", - "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", + "url": "https://api.github.com/repos/symfony/console/zipball/f1fc6f47283e27336e7cebb9e8946c8de7bff9bd", + "reference": "f1fc6f47283e27336e7cebb9e8946c8de7bff9bd", "shasum": "" }, "require": { @@ -1646,7 +1649,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.7" + "source": "https://github.com/symfony/console/tree/v6.4.15" }, "funding": [ { @@ -1662,20 +1665,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-11-06T14:19:14+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -1713,7 +1716,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -1729,24 +1732,24 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -1792,7 +1795,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -1808,24 +1811,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -1870,7 +1873,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -1886,24 +1889,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -1951,7 +1954,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -1967,24 +1970,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -2031,7 +2034,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -2047,40 +2050,32 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25" + "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25", - "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", + "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, - "type": "library", + "type": "metapackage", "extra": { "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -2104,7 +2099,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.31.0" }, "funding": [ { @@ -2120,24 +2115,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -2184,7 +2179,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -2200,20 +2195,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", "shasum": "" }, "require": { @@ -2267,7 +2262,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" }, "funding": [ { @@ -2283,20 +2278,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/string", - "version": "v6.4.7", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "ffeb9591c61f65a68d47f77d12b83fa530227a69" + "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ffeb9591c61f65a68d47f77d12b83fa530227a69", - "reference": "ffeb9591c61f65a68d47f77d12b83fa530227a69", + "url": "https://api.github.com/repos/symfony/string/zipball/73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", "shasum": "" }, "require": { @@ -2353,7 +2348,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.7" + "source": "https://github.com/symfony/string/tree/v6.4.15" }, "funding": [ { @@ -2369,20 +2364,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-11-13T13:31:12+00:00" }, { "name": "symfony/translation", - "version": "v6.4.7", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "7495687c58bfd88b7883823747b0656d90679123" + "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/7495687c58bfd88b7883823747b0656d90679123", - "reference": "7495687c58bfd88b7883823747b0656d90679123", + "url": "https://api.github.com/repos/symfony/translation/zipball/bee9bfabfa8b4045a66bf82520e492cddbaffa66", + "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66", "shasum": "" }, "require": { @@ -2448,7 +2443,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.7" + "source": "https://github.com/symfony/translation/tree/v6.4.13" }, "funding": [ { @@ -2464,20 +2459,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-09-27T18:14:25+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", - "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", "shasum": "" }, "require": { @@ -2526,7 +2521,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" }, "funding": [ { @@ -2542,20 +2537,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.7", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "7a9cd977cd1c5fed3694bee52990866432af07d7" + "reference": "38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7a9cd977cd1c5fed3694bee52990866432af07d7", - "reference": "7a9cd977cd1c5fed3694bee52990866432af07d7", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80", + "reference": "38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80", "shasum": "" }, "require": { @@ -2611,7 +2606,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.7" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.15" }, "funding": [ { @@ -2627,20 +2622,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-11-08T15:28:48+00:00" }, { "name": "twig/twig", - "version": "v2.16.0", + "version": "v2.16.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "0c9cc7ef2e0ec6d20c5af1200522a89ba101f623" + "reference": "19185947ec75d433a3ac650af32fc05649b95ee1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/0c9cc7ef2e0ec6d20c5af1200522a89ba101f623", - "reference": "0c9cc7ef2e0ec6d20c5af1200522a89ba101f623", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/19185947ec75d433a3ac650af32fc05649b95ee1", + "reference": "19185947ec75d433a3ac650af32fc05649b95ee1", "shasum": "" }, "require": { @@ -2695,7 +2690,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v2.16.0" + "source": "https://github.com/twigphp/Twig/tree/v2.16.1" }, "funding": [ { @@ -2707,20 +2702,20 @@ "type": "tidelift" } ], - "time": "2023-12-22T07:22:15+00:00" + "time": "2024-09-09T17:53:56+00:00" }, { "name": "voku/portable-ascii", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", - "reference": "b56450eed252f6801410d810c8e1727224ae0743" + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743", - "reference": "b56450eed252f6801410d810c8e1727224ae0743", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", "shasum": "" }, "require": { @@ -2745,7 +2740,7 @@ "authors": [ { "name": "Lars Moelleken", - "homepage": "http://www.moelleken.org/" + "homepage": "https://www.moelleken.org/" } ], "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", @@ -2757,7 +2752,7 @@ ], "support": { "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.0.1" + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" }, "funding": [ { @@ -2781,7 +2776,7 @@ "type": "tidelift" } ], - "time": "2022-03-08T17:03:00+00:00" + "time": "2024-11-21T01:49:47+00:00" }, { "name": "webmozart/assert", @@ -2845,16 +2840,16 @@ "packages-dev": [ { "name": "phpstan/phpstan", - "version": "1.11.1", + "version": "1.12.12", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e524358f930e41a2b4cca1320e3b04fc26b39e0b" + "reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e524358f930e41a2b4cca1320e3b04fc26b39e0b", - "reference": "e524358f930e41a2b4cca1320e3b04fc26b39e0b", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0", + "reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0", "shasum": "" }, "require": { @@ -2899,18 +2894,16 @@ "type": "github" } ], - "time": "2024-05-15T08:00:59+00:00" + "time": "2024-11-28T22:13:23+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "maximebf/debugbar": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^8.0", + "php": "^8.1", "ext-pdo": "*", "ext-pdo_mysql": "*", "ext-json": "*", diff --git a/install/includes/schema.sql b/install/includes/schema.sql index 46347707..1c8f4ccc 100644 --- a/install/includes/schema.sql +++ b/install/includes/schema.sql @@ -1,4 +1,4 @@ -SET @myaac_database_version = 40; +SET @myaac_database_version = 41; CREATE TABLE `myaac_account_actions` ( @@ -8,7 +8,7 @@ CREATE TABLE `myaac_account_actions` `date` INT(11) NOT NULL DEFAULT 0, `action` VARCHAR(255) NOT NULL DEFAULT '', KEY (`account_id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_admin_menu` ( @@ -19,22 +19,7 @@ CREATE TABLE `myaac_admin_menu` `flags` INT(11) NOT NULL DEFAULT 0, `enabled` INT(1) NOT NULL DEFAULT 1, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; - -CREATE TABLE `myaac_bugtracker` -( - `account` VARCHAR(255) NOT NULL, - `type` INT(11) NOT NULL DEFAULT 0, - `status` INT(11) NOT NULL DEFAULT 0, - `text` text NOT NULL, - `id` INT(11) NOT NULL DEFAULT 0, - `subject` VARCHAR(255) NOT NULL DEFAULT '', - `reply` INT(11) NOT NULL DEFAULT 0, - `who` INT(11) NOT NULL DEFAULT 0, - `uid` INT(11) NOT NULL AUTO_INCREMENT, - `tag` INT(11) NOT NULL DEFAULT 0, - PRIMARY KEY (`uid`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_changelog` ( @@ -46,7 +31,7 @@ CREATE TABLE `myaac_changelog` `player_id` INT(11) NOT NULL DEFAULT 0, `hide` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; INSERT INTO `myaac_changelog` (`id`, `type`, `where`, `date`, `body`, `hide`) VALUES (1, 3, 2, UNIX_TIMESTAMP(), 'MyAAC installed. (:', 0); @@ -57,7 +42,7 @@ CREATE TABLE `myaac_config` `value` VARCHAR(1000) NOT NULL, PRIMARY KEY (`id`), UNIQUE (`name`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; INSERT INTO `myaac_config` (`name`, `value`) VALUES ('database_version', @myaac_database_version); @@ -69,7 +54,7 @@ CREATE TABLE `myaac_faq` `ordering` INT(11) NOT NULL DEFAULT 0, `hide` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_forum_boards` ( @@ -82,7 +67,7 @@ CREATE TABLE `myaac_forum_boards` `closed` TINYINT(1) NOT NULL DEFAULT 0, `hide` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`, `closed`) VALUES (NULL, 'News', 'News commenting', 0, 1); INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Trade', 'Trade offers.', 1); INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Quests', 'Quest making.', 2); @@ -111,7 +96,7 @@ CREATE TABLE `myaac_forum` `closed` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `section` (`section`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_menu` ( @@ -125,7 +110,7 @@ CREATE TABLE `myaac_menu` `ordering` INT(11) NOT NULL DEFAULT 0, `enabled` INT(1) NOT NULL DEFAULT 1, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_monsters` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -158,7 +143,7 @@ CREATE TABLE `myaac_monsters` ( `loot` text NOT NULL, `summons` TEXT NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_news` ( @@ -176,7 +161,7 @@ CREATE TABLE `myaac_news` `article_image` VARCHAR(100) NOT NULL DEFAULT '', `hide` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_news_categories` ( @@ -186,7 +171,7 @@ CREATE TABLE `myaac_news_categories` `icon_id` INT(2) NOT NULL DEFAULT 0, `hide` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 0); INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 1); @@ -202,7 +187,7 @@ CREATE TABLE `myaac_notepad` `content` TEXT NOT NULL, /*`public` TINYINT(1) NOT NULL DEFAULT 0*/ PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_pages` ( @@ -218,7 +203,7 @@ CREATE TABLE `myaac_pages` `hide` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE (`name`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_gallery` ( @@ -230,7 +215,7 @@ CREATE TABLE `myaac_gallery` `ordering` INT(11) NOT NULL DEFAULT 0, `hide` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; INSERT INTO `myaac_gallery` (`id`, `ordering`, `comment`, `image`, `thumb`, `author`) VALUES (NULL, 1, 'Demon', 'images/gallery/demon.jpg', 'images/gallery/demon_thumb.gif', 'MyAAC'); @@ -242,7 +227,7 @@ CREATE TABLE `myaac_settings` `value` TEXT NOT NULL, PRIMARY KEY (`id`), KEY `key` (`key`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_spells` ( @@ -265,7 +250,7 @@ CREATE TABLE `myaac_spells` `hide` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE (`name`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_visitors` ( @@ -274,7 +259,7 @@ CREATE TABLE `myaac_visitors` `page` VARCHAR(2048) NOT NULL, `user_agent` VARCHAR(255) NOT NULL DEFAULT '', UNIQUE (`ip`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; CREATE TABLE `myaac_weapons` ( @@ -283,4 +268,4 @@ CREATE TABLE `myaac_weapons` `maglevel` INT(11) NOT NULL DEFAULT 0, `vocations` VARCHAR(100) NOT NULL DEFAULT '', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; diff --git a/install/index.php b/install/index.php index 91c8a7ef..1b9a0218 100644 --- a/install/index.php +++ b/install/index.php @@ -114,7 +114,7 @@ else if($step == 'finish') { $email = $_SESSION['var_email']; $password = $_SESSION['var_password']; $password_confirm = $_SESSION['var_password_confirm']; - $player_name = $_SESSION['var_player_name']; + $player_name = $_SESSION['var_player_name'] ?? null; // email check if(empty($email)) { @@ -125,18 +125,7 @@ else if($step == 'finish') { } // account check - if(isset($_SESSION['var_account'])) { - if(empty($_SESSION['var_account'])) { - $errors[] = $locale['step_admin_account_error_empty']; - } - else if(!Validator::accountName($_SESSION['var_account'])) { - $errors[] = $locale['step_admin_account_error_format']; - } - else if(strtoupper($_SESSION['var_account']) == strtoupper($password)) { - $errors[] = $locale['step_admin_account_error_same']; - } - } - else if(isset($_SESSION['var_account_id'])) { + if(isset($_SESSION['var_account_id'])) { if(empty($_SESSION['var_account_id'])) { $errors[] = $locale['step_admin_account_id_error_empty']; } @@ -147,6 +136,17 @@ else if($step == 'finish') { $errors[] = $locale['step_admin_account_id_error_same']; } } + else if(isset($_SESSION['var_account'])) { + if(empty($_SESSION['var_account'])) { + $errors[] = $locale['step_admin_account_error_empty']; + } + else if(!Validator::accountName($_SESSION['var_account'])) { + $errors[] = $locale['step_admin_account_error_format']; + } + else if(strtoupper($_SESSION['var_account']) == strtoupper($password)) { + $errors[] = $locale['step_admin_account_error_same']; + } + } // password check if(empty($password)) { @@ -159,12 +159,13 @@ else if($step == 'finish') { $errors[] = $locale['step_admin_password_confirm_error_not_same']; } - // player name check - if(empty($player_name)) { - $errors[] = $locale['step_admin_player_name_error_empty']; - } - else if(!Validator::characterName($player_name)) { - $errors[] = $locale['step_admin_player_name_error_format']; + if (isset($player_name)) { + // player name check + if (empty($player_name)) { + $errors[] = $locale['step_admin_player_name_error_empty']; + } else if (!Validator::characterName($player_name)) { + $errors[] = $locale['step_admin_player_name_error_format']; + } } if(!empty($errors)) { @@ -182,14 +183,14 @@ clearstatcache(); if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) { if(!file_exists(BASE . 'install/ip.txt')) { $content = warning('AAC installation is disabled. To enable it make file ip.txt in install/ directory and put there your IP.
- Your IP is:
' . $_SERVER['REMOTE_ADDR'] . '', true); + Your IP is:
' . get_browser_real_ip() . '', true); } else { $file_content = trim(file_get_contents(BASE . 'install/ip.txt')); $allow = false; $listIP = preg_split('/\s+/', $file_content); foreach($listIP as $ip) { - if($_SERVER['REMOTE_ADDR'] == $ip) { + if(get_browser_real_ip() == $ip) { $allow = true; } } @@ -198,7 +199,7 @@ if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) { { $content = warning('In file install/ip.txt must be your IP!
In file is:
' . nl2br($file_content) . '
- Your IP is:
' . $_SERVER['REMOTE_ADDR'] . '', true); + Your IP is:
' . get_browser_real_ip() . '', true); } else { ob_start(); diff --git a/install/steps/5-database.php b/install/steps/5-database.php index 881953d6..fee43246 100644 --- a/install/steps/5-database.php +++ b/install/steps/5-database.php @@ -40,6 +40,7 @@ if(!$error) { $configToSave['gzip_output'] = false; $configToSave['cache_engine'] = 'auto'; $configToSave['cache_prefix'] = 'myaac_' . generateRandomString(8, true, false, true); + $configToSave['database_auto_migrate'] = true; if (isset($config['install_ignore_ip_check'])) { $configToSave['install_ignore_ip_check'] = $config['install_ignore_ip_check']; } @@ -67,18 +68,6 @@ if(!$error) { $error = true; } - if (!$db->hasTable('players')) { - $tmp = str_replace('$TABLE$', 'players', $locale['step_database_error_table']); - error($tmp); - $error = true; - } - - if (!$db->hasTable('guilds')) { - $tmp = str_replace('$TABLE$', 'guilds', $locale['step_database_error_table']); - error($tmp); - $error = true; - } - if (!$error) { $twig->display('install.installer.html.twig', array( 'url' => 'tools/5-database.php', diff --git a/install/steps/6-admin.php b/install/steps/6-admin.php index e410fc93..ab30b477 100644 --- a/install/steps/6-admin.php +++ b/install/steps/6-admin.php @@ -18,6 +18,7 @@ if(!$error) { 'locale' => $locale, 'session' => $_SESSION, 'account' => $account, + 'hasTablePlayers' => $db->hasTable('players'), 'errors' => isset($errors) ? $errors : null, 'buttons' => next_buttons(true, $error ? false : true) )); diff --git a/install/steps/7-finish.php b/install/steps/7-finish.php index 84c2cce4..0ae302ea 100644 --- a/install/steps/7-finish.php +++ b/install/steps/7-finish.php @@ -42,23 +42,25 @@ if(isset($account)) else $account_db->load($account_id); -$player_name = $_SESSION['var_player_name']; -$player_db = new OTS_Player(); -$player_db->find($player_name); +if ($db->hasTable('players')) { + $player_name = $_SESSION['var_player_name']; + $player_db = new OTS_Player(); + $player_db->find($player_name); -if(!$player_db->isLoaded()) -{ - $player = new OTS_Player(); - $player->setName($player_name); + if(!$player_db->isLoaded()) + { + $player = new OTS_Player(); + $player->setName($player_name); - $player_used = &$player; + $player_used = &$player; + } + else { + $player_used = &$player_db; + } + + $groups = new OTS_Groups_List(); + $player_used->setGroupId($groups->getHighestId()); } -else { - $player_used = &$player_db; -} - -$groups = new OTS_Groups_List(); -$player_used->setGroupId($groups->getHighestId()); $email = $_SESSION['var_email']; if($account_db->isLoaded()) { @@ -100,10 +102,16 @@ if($db->hasColumn('accounts', 'group_id')) if($db->hasColumn('accounts', 'type')) $account_used->setCustomField('type', 6); -if(!$player_db->isLoaded()) - $player->setAccountId($account_used->getId()); -else - $player_db->setAccountId($account_used->getId()); +if ($db->hasTable('players')) { + if(!$player_db->isLoaded()) { + $player->setAccountId($account_used->getId()); + $player->save(); + } + else { + $player_db->setAccountId($account_used->getId()); + $player_db->save(); + } +} success($locale['step_database_created_account']); @@ -111,18 +119,14 @@ setSession('account', $account_used->getId()); setSession('password', encrypt($password)); setSession('remember_me', true); -if($player_db->isLoaded()) { - $player_db->save(); -} -else { - $player->save(); -} - if(!News::all()->count()) { $player_id = 0; - $tmpNewsPlayer = \MyAAC\Models\Player::where('name', $player_name)->first(); - if($tmpNewsPlayer) { - $player_id = $tmpNewsPlayer->id; + + if ($db->hasTable('players')) { + $tmpNewsPlayer = \MyAAC\Models\Player::where('name', $player_name)->first(); + if($tmpNewsPlayer) { + $player_id = $tmpNewsPlayer->id; + } } News::create([ diff --git a/install/tools/7-finish.php b/install/tools/7-finish.php index 37914a5f..6620f7d9 100644 --- a/install/tools/7-finish.php +++ b/install/tools/7-finish.php @@ -25,30 +25,33 @@ if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['save require SYSTEM . 'init.php'; -$deleted = 'deleted'; -if($db->hasColumn('players', 'deletion')) - $deleted = 'deletion'; +if ($db->hasTable('players')) { + $deleted = 'deleted'; + if ($db->hasColumn('players', 'deletion')) + $deleted = 'deletion'; -$time = time(); -function insert_sample_if_not_exist($p) { - global $db, $success, $deleted, $time; + $time = time(); + function insert_sample_if_not_exist($p) + { + global $db, $success, $deleted, $time; - $query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($p['name'])); - if($query->rowCount() == 0) { - if(!query("INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `lastlogout`, `balance`, `$deleted`, `created`, `hide`, `comment`) VALUES (null, " . $db->quote($p['name']) . ", 1, " . getSession('account') . ", " . $p['level'] . ", " . $p['vocation_id'] . ", " . $p['health'] . ", " . $p['healthmax'] . ", " . $p['experience'] . ", 118, 114, 38, 57, " . $p['looktype'] . ", 0, " . $p['mana'] . ", " . $p['manamax'] . ", 0, " . $p['soul'] . ", 1, 1000, 1000, 7, '', " . $p['cap'] . ", 1, " . $time . ", 2130706433, 1, " . $time . ", 0, 0, " . $time . ", 1, '');")) - $success = false; + $query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($p['name'])); + if ($query->rowCount() == 0) { + if (!query("INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `lastlogout`, `balance`, `$deleted`, `created`, `hide`, `comment`) VALUES (null, " . $db->quote($p['name']) . ", 1, " . getSession('account') . ", " . $p['level'] . ", " . $p['vocation_id'] . ", " . $p['health'] . ", " . $p['healthmax'] . ", " . $p['experience'] . ", 118, 114, 38, 57, " . $p['looktype'] . ", 0, " . $p['mana'] . ", " . $p['manamax'] . ", 0, " . $p['soul'] . ", 1, 1000, 1000, 7, '', " . $p['cap'] . ", 1, " . $time . ", 2130706433, 1, " . $time . ", 0, 0, " . $time . ", 1, '');")) + $success = false; + } } -} -$success = true; -insert_sample_if_not_exist(array('name' => 'Rook Sample', 'level' => 1, 'vocation_id' => 0, 'health' => 150, 'healthmax' => 150, 'experience' => 0, 'looktype' => 130, 'mana' => 0, 'manamax' => 0, 'soul' => 100, 'cap' => 400)); -insert_sample_if_not_exist(array('name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470)); -insert_sample_if_not_exist(array('name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470)); -insert_sample_if_not_exist(array('name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470)); -insert_sample_if_not_exist(array('name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470)); + $success = true; + insert_sample_if_not_exist(array('name' => 'Rook Sample', 'level' => 1, 'vocation_id' => 0, 'health' => 150, 'healthmax' => 150, 'experience' => 0, 'looktype' => 130, 'mana' => 0, 'manamax' => 0, 'soul' => 100, 'cap' => 400)); + insert_sample_if_not_exist(array('name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470)); + insert_sample_if_not_exist(array('name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470)); + insert_sample_if_not_exist(array('name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470)); + insert_sample_if_not_exist(array('name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470)); -if($success) { - success($locale['step_database_imported_players']); + if ($success) { + success($locale['step_database_imported_players']); + } } Plugins::installMenus('kathrine', require TEMPLATES . 'kathrine/menus.php'); @@ -59,16 +62,21 @@ DataLoader::load(); // update config.highscores_ids_hidden require_once SYSTEM . 'migrations/20.php'; +$up(); // add z_polls tables require_once SYSTEM . 'migrations/22.php'; +$up(); // add myaac_pages pages require_once SYSTEM . 'migrations/27.php'; +$up(); require_once SYSTEM . 'migrations/30.php'; +$up(); // new monster columns require_once SYSTEM . 'migrations/31.php'; +$up(); if(ModelsFAQ::count() == 0) { ModelsFAQ::create([ diff --git a/login.php b/login.php index 8be4d1f3..75aeed4d 100644 --- a/login.php +++ b/login.php @@ -4,6 +4,7 @@ use MyAAC\Models\BoostedCreature; use MyAAC\Models\PlayerOnline; use MyAAC\Models\Account; use MyAAC\Models\Player; +use MyAAC\RateLimit; require_once 'common.php'; require_once SYSTEM . 'functions.php'; @@ -130,12 +131,29 @@ switch ($action) { } $account = $account->first(); + + $ip = get_browser_real_ip(); + $limiter = new RateLimit('failed_logins', setting('core.account_login_attempts_limit'), setting('core.account_login_ban_time')); + $limiter->enabled = setting('core.account_login_ipban_protection'); + $limiter->load(); + + $ban_msg = 'A wrong account, password or secret has been entered ' . setting('core.account_login_attempts_limit') . ' times in a row. You are unable to log into your account for the next ' . setting('core.account_login_ban_time') . ' minutes. Please wait.'; if (!$account) { + $limiter->increment($ip); + if ($limiter->exceeded($ip)) { + sendError($ban_msg); + } + sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.'); } $current_password = encrypt((USE_ACCOUNT_SALT ? $account->salt : '') . $request->password); if (!$account || $account->password != $current_password) { + $limiter->increment($ip); + if ($limiter->exceeded($ip)) { + sendError($ban_msg); + } + sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.'); } @@ -145,16 +163,30 @@ switch ($action) { if ($accountSecret != null && $accountSecret != '') { $accountHasSecret = true; if ($inputToken === false) { + $limiter->increment($ip); + if ($limiter->exceeded($ip)) { + sendError($ban_msg); + } sendError('Submit a valid two-factor authentication token.', 6); } else { require_once LIBS . 'rfc6238.php'; if (TokenAuth6238::verify($accountSecret, $inputToken) !== true) { + $limiter->increment($ip); + if ($limiter->exceeded($ip)) { + sendError($ban_msg); + } + sendError('Two-factor authentication failed, token is wrong.', 6); } } } } + $limiter->reset($ip); + if (setting('core.account_mail_verify') && $account->email_verified !== 1) { + sendError('You need to verify your account, enter in our site and resend verify e-mail!'); + } + // common columns $columns = 'id, name, level, sex, vocation, looktype, lookhead, lookbody, looklegs, lookfeet, lookaddons'; diff --git a/phpstan.neon b/phpstan.neon index fda6a07c..020fa3a6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -28,7 +28,7 @@ parameters: - '#Variable \$guild might not be defined#' - '#Variable \$[a-zA-Z0-9\\_]+ might not be defined#' # Eloquent models - - '#Call to an undefined static method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+()#' + - '#Call to an undefined static method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+\(\)#' - '#Call to an undefined method object::toArray\(\)#' # system/pages/highscores.php - '#Call to an undefined method Illuminate\\Database\\Query\\Builder::withOnlineStatus\(\)#' diff --git a/system/clients.conf.php b/system/clients.conf.php index a7d2bf0c..fce41bb1 100644 --- a/system/clients.conf.php +++ b/system/clients.conf.php @@ -105,4 +105,8 @@ $config['clients'] = [ 1316, 1320, 1321, + 1322, + 1330, + 1332, + 1340, ]; diff --git a/system/compat/classes.php b/system/compat/classes.php index 2009140b..65d436bd 100644 --- a/system/compat/classes.php +++ b/system/compat/classes.php @@ -36,3 +36,5 @@ class Guild extends OTS_Guild { } class GuildRank extends OTS_GuildRank {} class House extends OTS_House {} + +class Cache extends \MyAAC\Cache\Cache {} diff --git a/system/database.php b/system/database.php index 34b4574a..b9dc6cc6 100644 --- a/system/database.php +++ b/system/database.php @@ -106,6 +106,7 @@ try { 'persistent' => @$config['database_persistent'] )); + global $db; $db = POT::getInstance()->getDBHandle(); $capsule = new Capsule; $capsule->addConnection([ diff --git a/system/functions.php b/system/functions.php index 70c0b93e..e7f7db9d 100644 --- a/system/functions.php +++ b/system/functions.php @@ -89,13 +89,18 @@ function getForumBoardLink($board_id, $page = NULL): string { function getPlayerLink($name, $generate = true, bool $colored = false): string { - $player = new OTS_Player(); - - if(is_numeric($name)) { - $player->load((int)$name); + if (is_object($name) and $name instanceof OTS_Player) { + $player = $name; } else { - $player->find($name); + $player = new OTS_Player(); + + if(is_numeric($name)) { + $player->load((int)$name); + } + else { + $player->find($name); + } } if (!$player->isLoaded()) { @@ -1041,7 +1046,7 @@ function load_config_lua($filename) return $result; } -function str_replace_first($search, $replace, $subject) { +function str_replace_first($search,$replace, $subject) { $pos = strpos($subject, $search); if ($pos !== false) { return substr_replace($subject, $replace, $pos, strlen($search)); @@ -1679,6 +1684,18 @@ function isRequestMethod(string $method): bool { return strtolower($_SERVER['REQUEST_METHOD']) == strtolower($method); } +function getAccountIdentityColumn(): string +{ + if (USE_ACCOUNT_NAME) { + return 'name'; + } + elseif (USE_ACCOUNT_NUMBER) { + return 'number'; + } + + return 'id'; +} + // validator functions require_once SYSTEM . 'compat/base.php'; diff --git a/system/init.php b/system/init.php index 9bc14514..9217e8f0 100644 --- a/system/init.php +++ b/system/init.php @@ -12,11 +12,12 @@ use DebugBar\StandardDebugBar; use MyAAC\Cache\Cache; use MyAAC\CsrfToken; use MyAAC\Hooks; +use MyAAC\Models\Town; use MyAAC\Settings; -use MyAAC\Towns; defined('MYAAC') or die('Direct access not allowed!'); +global $config; if(!isset($config['installed']) || !$config['installed']) { throw new RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.'); } @@ -38,13 +39,15 @@ if($config['server_path'][strlen($config['server_path']) - 1] !== '/') $config['server_path'] .= '/'; // enable gzip compression if supported by the browser -if(isset($config['gzip_output']) && $config['gzip_output'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false && function_exists('ob_gzhandler')) +if(isset($config['gzip_output']) && $config['gzip_output'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && str_contains($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('ob_gzhandler')) ob_start('ob_gzhandler'); // cache +global $cache; $cache = Cache::getInstance(); // event system +global $hooks; $hooks = new Hooks(); $hooks->load(); @@ -140,7 +143,10 @@ if(!defined('MYAAC_INSTALL') && !$db->hasTable('myaac_account_actions')) { } // execute migrations -require SYSTEM . 'migrate.php'; +$configDatabaseAutoMigrate = config('database_auto_migrate'); +if (!isset($configDatabaseAutoMigrate) || $configDatabaseAutoMigrate) { + require SYSTEM . 'migrate.php'; +} // settings $settings = Settings::getInstance(); @@ -155,6 +161,9 @@ if (!isset($token) || !$token) { // deprecated config values require_once SYSTEM . 'compat/config.php'; +// deprecated classes +require_once SYSTEM . 'compat/classes.php'; + date_default_timezone_set(setting('core.date_timezone')); setting( @@ -173,4 +182,17 @@ define('USE_ACCOUNT_NAME', $db->hasColumn('accounts', 'name')); define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number')); define('USE_ACCOUNT_SALT', $db->hasColumn('accounts', 'salt')); -Towns::load(); +$towns = Cache::remember('towns', 10 * 60, function () use ($db) { + if ($db->hasTable('towns') && Town::count() > 0) { + return Town::orderBy('id', 'ASC')->pluck('name', 'id')->toArray(); + } + + return []; +}); + +if (count($towns) <= 0) { + $towns = setting('core.towns'); +} + +config(['towns', $towns]); +unset($towns); diff --git a/system/libs/pot/OTS_Base_DB.php b/system/libs/pot/OTS_Base_DB.php index 21d6f756..1d7ae287 100644 --- a/system/libs/pot/OTS_Base_DB.php +++ b/system/libs/pot/OTS_Base_DB.php @@ -184,8 +184,14 @@ abstract class OTS_Base_DB extends PDO implements IOTS_DB $query = 'UPDATE '.$this->tableName($table).' SET '; $count = count($fields); - for ($i = 0; $i < $count; $i++) - $query.= $this->fieldName($fields[$i]).' = '.$this->quote($values[$i]).', '; + for ($i = 0; $i < $count; $i++) { + $value = 'NULL'; + if ($values[$i] !== null) { + $value = $this->quote($values[$i]); + } + + $query.= $this->fieldName($fields[$i]).' = '.$value.', '; + } $query = substr($query, 0, -2); $query.=' WHERE ('; @@ -229,6 +235,30 @@ abstract class OTS_Base_DB extends PDO implements IOTS_DB $this->exec($query); return true; } + + public function addColumn($table, $column, $definition): void { + $this->exec('ALTER TABLE ' . $this->tableName($table) . ' ADD ' . $this->fieldName($column) . ' ' . $definition . ';'); + } + + public function modifyColumn($table, $column, $definition): void { + $this->exec('ALTER TABLE ' . $this->tableName($table) . ' MODIFY ' . $this->fieldName($column) . ' ' . $definition . ';'); + } + + public function changeColumn($table, $from, $to, $definition): void { + $this->exec('ALTER TABLE ' . $this->tableName($table) . ' CHANGE ' . $this->fieldName($from) . ' ' . $this->fieldName($to) . ' ' . $definition . ';'); + } + + public function dropColumn($table, $column): void { + $this->exec('ALTER TABLE ' . $this->tableName($table) . ' DROP COLUMN ' . $this->fieldName($column) . ';'); + } + + public function renameTable($from, $to): void { + $this->exec('RENAME TABLE ' . $this->tableName($from) . ' TO ' . $this->tableName($to) . ';'); + } + + public function dropTable($table, $ifExists = true): void { + $this->exec('DROP TABLE ' . ($ifExists ? 'IF EXISTS' : '') . ' ' . $this->tableName($table) . ';'); + } /** * LIMIT/OFFSET clause for queries. * diff --git a/system/libs/pot/OTS_DB_MySQL.php b/system/libs/pot/OTS_DB_MySQL.php index 5ca7d28b..89e8dd0d 100644 --- a/system/libs/pot/OTS_DB_MySQL.php +++ b/system/libs/pot/OTS_DB_MySQL.php @@ -53,49 +53,49 @@ class OTS_DB_MySQL extends OTS_Base_DB * @param array $params Connection parameters. * @throws PDOException On PDO operation error. */ - public function __construct($params) - { - $user = null; - $password = null; - $dns = array(); + public function __construct($params) + { + $user = null; + $password = null; + $dns = array(); - // host:port support - if( strpos(':', $params['host']) !== false) - { - $host = explode(':', $params['host'], 2); + // host:port support + if( strpos(':', $params['host']) !== false) + { + $host = explode(':', $params['host'], 2); - $params['host'] = $host[0]; - $params['port'] = $host[1]; - } + $params['host'] = $host[0]; + $params['port'] = $host[1]; + } - if( isset($params['database']) ) - { - $dns[] = 'dbname=' . $params['database']; - } + if( isset($params['database']) ) + { + $dns[] = 'dbname=' . $params['database']; + } - if( isset($params['user']) ) - { - $user = $params['user']; - } + if( isset($params['user']) ) + { + $user = $params['user']; + } - if( isset($params['password']) ) - { - $password = $params['password']; - } + if( isset($params['password']) ) + { + $password = $params['password']; + } - if( isset($params['prefix']) ) - { - $this->prefix = $params['prefix']; - } + if( isset($params['prefix']) ) + { + $this->prefix = $params['prefix']; + } - if( isset($params['log']) && $params['log'] ) - { - $this->logged = true; - } + if( isset($params['log']) && $params['log'] ) + { + $this->logged = true; + } - if( !isset($params['persistent']) ) { - $params['persistent'] = false; - } + if( !isset($params['persistent']) ) { + $params['persistent'] = false; + } global $config; $cache = Cache::getInstance(); @@ -144,10 +144,10 @@ class OTS_DB_MySQL extends OTS_Base_DB } parent::__construct('mysql:' . implode(';', $dns), $user, $password, $driverAttributes); - } + } public function __destruct() - { + { global $config; $cache = Cache::getInstance(); @@ -165,7 +165,8 @@ class OTS_DB_MySQL extends OTS_Base_DB } if($this->logged) { - log_append('database.log', $_SERVER['REQUEST_URI'] . PHP_EOL . $this->getLog()); + $currentScript = $_SERVER['REQUEST_URI'] ?? $_SERVER['SCRIPT_FILENAME']; + log_append('database.log', $currentScript . PHP_EOL . $this->getLog()); } } @@ -175,10 +176,10 @@ class OTS_DB_MySQL extends OTS_Base_DB * @param string $name Field name. * @return string Quoted name. */ - public function fieldName($name) - { - return '`' . $name . '`'; - } + public function fieldName($name) + { + return '`' . $name . '`'; + } /** * LIMIT/OFFSET clause for queries. @@ -187,26 +188,26 @@ class OTS_DB_MySQL extends OTS_Base_DB * @param int|bool $offset Number of rows to be skipped before applying query effects (false if no offset). * @return string LIMIT/OFFSET SQL clause for query. */ - public function limit($limit = false, $offset = false) - { - // by default this is empty part - $sql = ''; + public function limit($limit = false, $offset = false) + { + // by default this is empty part + $sql = ''; - if($limit !== false) - { - $sql = ' LIMIT '; + if($limit !== false) + { + $sql = ' LIMIT '; - // OFFSET has no effect if there is no LIMIT - if($offset !== false) - { - $sql .= $offset . ', '; - } + // OFFSET has no effect if there is no LIMIT + if($offset !== false) + { + $sql .= $offset . ', '; + } - $sql .= $limit; - } + $sql .= $limit; + } - return $sql; - } + return $sql; + } public function hasTable($name) { if(isset($this->has_table_cache[$name])) { diff --git a/system/libs/pot/OTS_House.php b/system/libs/pot/OTS_House.php index 12a8f1cb..9ef0c149 100644 --- a/system/libs/pot/OTS_House.php +++ b/system/libs/pot/OTS_House.php @@ -60,12 +60,7 @@ class OTS_House extends OTS_Row_DAO private $tiles = array(); public function load($id) { - $this->data = $this->db->query('SELECT * FROM `houses` WHERE `id` = ' . $id )->fetch(); - foreach($this->data as $key => $value) { - if(is_numeric($key)) { - unset($this->data[$key]); - } - } + $this->data = $this->db->query('SELECT * FROM `houses` WHERE `id` = ' . $id )->fetch(PDO::FETCH_ASSOC); } public function find($name) diff --git a/system/locale/en/install.php b/system/locale/en/install.php index e25537c9..0cbd29ad 100644 --- a/system/locale/en/install.php +++ b/system/locale/en/install.php @@ -94,7 +94,7 @@ $locale['step_database_loaded_npcs'] = 'NPCs has been loaded...'; $locale['step_database_error_npcs'] = 'There were some problems loading your NPCs'; $locale['step_database_loaded_spells'] = 'Spells has been loaded...'; $locale['step_database_loaded_towns'] = 'Towns has been loaded...'; -$locale['step_database_error_towns'] = 'There were some problems loading your towns. You will need to configure them manually in config.'; +$locale['step_database_error_towns'] = 'There were some problems loading your towns. You will need to configure them manually in Settings.'; $locale['step_database_created_account'] = 'Created admin account...'; $locale['step_database_created_news'] = 'Newses has been created...'; diff --git a/system/locale/pl/install.php b/system/locale/pl/install.php index 22204adf..5b6725cf 100644 --- a/system/locale/pl/install.php +++ b/system/locale/pl/install.php @@ -93,7 +93,7 @@ $locale['step_database_loaded_npcs'] = 'Załadowano NPCs...'; $locale['step_database_error_npcs'] = 'Wystąpił problem podczas ładowania NPCs'; $locale['step_database_loaded_spells'] = 'Załadowano czary (spells)...'; $locale['step_database_loaded_towns'] = 'Załadowano miasta (towns)...'; -$locale['step_database_error_towns'] = 'Wystąpił problem podczas ładowania miast. Trzeba będzie je skonfigurować manualnie.'; +$locale['step_database_error_towns'] = 'Wystąpił problem podczas ładowania miast. Trzeba będzie je skonfigurować manualnie w ustawieniach.'; $locale['step_database_created_account'] = 'Utworzono konto admina...'; $locale['step_database_created_news'] = 'Utworzono newsy...'; diff --git a/system/migrate.php b/system/migrate.php index 4eb7bf7a..2199fd73 100644 --- a/system/migrate.php +++ b/system/migrate.php @@ -17,6 +17,12 @@ if(fetchDatabaseConfig('database_version', $tmp)) { // we got version $db->revalidateCache(); for($i = $tmp + 1; $i <= DATABASE_VERSION; $i++) { require SYSTEM . 'migrations/' . $i . '.php'; + + if (isset($up)) { + $up(); + unset($up); + } + updateDatabaseConfig('database_version', $i); } } @@ -26,6 +32,12 @@ else { // register first version $db->revalidateCache(); for($i = 1; $i <= DATABASE_VERSION; $i++) { require SYSTEM . 'migrations/' . $i . '.php'; + + if (isset($up)) { + $up(); + unset($up); + } + updateDatabaseConfig('database_version', $i); } } diff --git a/system/migrations/1-hooks.sql b/system/migrations/1-hooks.sql new file mode 100644 index 00000000..218988ce --- /dev/null +++ b/system/migrations/1-hooks.sql @@ -0,0 +1,8 @@ +CREATE TABLE `myaac_hooks` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(30) NOT NULL DEFAULT '', + `type` INT(2) NOT NULL DEFAULT 0, + `file` VARCHAR(100) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/1.php b/system/migrations/1.php index 6e4f3252..a3c38f66 100644 --- a/system/migrations/1.php +++ b/system/migrations/1.php @@ -1,16 +1,16 @@ query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` MODIFY `ip` INT(11) NOT NULL DEFAULT 0;"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` MODIFY `date` INT(11) NOT NULL DEFAULT 0;"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` MODIFY `action` VARCHAR(255) NOT NULL DEFAULT '';"); - $db->query(" - CREATE TABLE `myaac_hooks` -( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `name` VARCHAR(30) NOT NULL DEFAULT '', - `type` INT(2) NOT NULL DEFAULT 0, - `file` VARCHAR(100) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; -"); +/** + * @var OTS_DB_MySQL $db + */ -?> +$up = function () use ($db) { + $db->modifyColumn(TABLE_PREFIX . 'account_actions', 'ip', "INT(11) NOT NULL DEFAULT 0"); + $db->modifyColumn(TABLE_PREFIX . 'account_actions', 'date', "INT(11) NOT NULL DEFAULT 0"); + $db->modifyColumn(TABLE_PREFIX . 'account_actions', 'action', "VARCHAR(255) NOT NULL DEFAULT ''"); + + $db->query(file_get_contents(__DIR__ . '/1-hooks.sql')); +}; + +$down = function () use ($db) { + $db->dropTable(TABLE_PREFIX . 'hooks'); +}; diff --git a/system/migrations/10-admin_menu.sql b/system/migrations/10-admin_menu.sql new file mode 100644 index 00000000..72083c35 --- /dev/null +++ b/system/migrations/10-admin_menu.sql @@ -0,0 +1,10 @@ +CREATE TABLE `myaac_admin_menu` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL DEFAULT '', + `page` VARCHAR(255) NOT NULL DEFAULT '', + `ordering` INT(11) NOT NULL DEFAULT 0, + `flags` INT(11) NOT NULL DEFAULT 0, + `enabled` INT(1) NOT NULL DEFAULT 1, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/10.php b/system/migrations/10.php index da660ab9..8783dbf0 100644 --- a/system/migrations/10.php +++ b/system/migrations/10.php @@ -1,17 +1,24 @@ hasColumn(TABLE_PREFIX . 'hooks', 'ordering')) - $db->query("ALTER TABLE `" . TABLE_PREFIX . "hooks` ADD `ordering` INT(11) NOT NULL DEFAULT 0 AFTER `file`;"); +/** + * @var OTS_DB_MySQL $db + */ - if(!$db->hasTable(TABLE_PREFIX . 'admin_menu')) - $db->query(" -CREATE TABLE `myaac_admin_menu` -( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `name` VARCHAR(255) NOT NULL DEFAULT '', - `page` VARCHAR(255) NOT NULL DEFAULT '', - `ordering` INT(11) NOT NULL DEFAULT 0, - `flags` INT(11) NOT NULL DEFAULT 0, - `enabled` INT(1) NOT NULL DEFAULT 1, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; -"); \ No newline at end of file +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'hooks', 'ordering')) { + $db->addColumn(TABLE_PREFIX . 'hooks', 'ordering', "INT(11) NOT NULL DEFAULT 0 AFTER `file`"); + } + + if (!$db->hasTable(TABLE_PREFIX . 'admin_menu')) { + $db->query(file_get_contents(__DIR__ . '/10-admin_menu.sql')); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'hooks', 'ordering')) { + $db->dropColumn(TABLE_PREFIX . 'hooks', 'ordering'); + } + + if ($db->hasTable(TABLE_PREFIX . 'admin_menu')) { + $db->dropTable(TABLE_PREFIX . 'admin_menu'); + } +}; diff --git a/system/migrations/11.php b/system/migrations/11.php index 845f9e67..bc26da0e 100644 --- a/system/migrations/11.php +++ b/system/migrations/11.php @@ -1,19 +1,44 @@ query("RENAME TABLE - " . TABLE_PREFIX . "screenshots TO " . TABLE_PREFIX . "gallery, - " . TABLE_PREFIX . "movies TO " . TABLE_PREFIX . "videos;"); + $db->renameTable(TABLE_PREFIX . 'screenshots', TABLE_PREFIX . 'gallery'); + $db->renameTable(TABLE_PREFIX . 'movies', TABLE_PREFIX . 'videos'); // rename images dir - if(file_exists(BASE . 'images/screenshots') && !file_exists(BASE . GALLERY_DIR)) { + if (file_exists(BASE . 'images/screenshots') && !file_exists(BASE . GALLERY_DIR)) { rename(BASE . 'images/screenshots', BASE . GALLERY_DIR); } // convert old database screenshots images to gallery $query = $db->query('SELECT `id`, `image`, `thumb` FROM `' . TABLE_PREFIX . 'gallery`;'); - foreach($query->fetchAll() as $item) { + foreach ($query->fetchAll() as $item) { $db->update(TABLE_PREFIX . 'gallery', array( 'image' => str_replace('/screenshots/', '/gallery/', $item['image']), 'thumb' => str_replace('/screenshots/', '/gallery/', $item['thumb']), ), array('id' => $item['id'])); } +}; + +$down = function () use ($db) { + // rename database tables + $db->renameTable(TABLE_PREFIX . 'gallery', TABLE_PREFIX . 'screenshots'); + $db->renameTable(TABLE_PREFIX . 'videos', TABLE_PREFIX . 'movies'); + + // rename images dir + if (file_exists(BASE . GALLERY_DIR) && !file_exists(BASE . 'images/screenshots')) { + rename(BASE . GALLERY_DIR, BASE . 'images/screenshots'); + } + + // convert new database gallery images to screenshots + $query = $db->query('SELECT `id`, `image`, `thumb` FROM `' . TABLE_PREFIX . 'screenshots`;'); + foreach ($query->fetchAll() as $item) { + $db->update(TABLE_PREFIX . 'screenshots', [ + 'image' => str_replace('/gallery/', '/screenshots/', $item['image']), + 'thumb' => str_replace('/gallery/', '/screenshots/', $item['thumb']), + ], ['id' => $item['id']]); + } +}; diff --git a/system/migrations/12-items.sql b/system/migrations/12-items.sql new file mode 100644 index 00000000..458333e0 --- /dev/null +++ b/system/migrations/12-items.sql @@ -0,0 +1,9 @@ +CREATE TABLE `myaac_items` +( + `id` INT(11) NOT NULL, + `article` VARCHAR(5) NOT NULL DEFAULT '', + `name` VARCHAR(50) NOT NULL DEFAULT '', + `plural` VARCHAR(50) NOT NULL DEFAULT '', + `attributes` VARCHAR(500) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/12-weapons.sql b/system/migrations/12-weapons.sql new file mode 100644 index 00000000..9085732e --- /dev/null +++ b/system/migrations/12-weapons.sql @@ -0,0 +1,8 @@ +CREATE TABLE `myaac_weapons` +( + `id` INT(11) NOT NULL, + `level` INT(11) NOT NULL DEFAULT 0, + `maglevel` INT(11) NOT NULL DEFAULT 0, + `vocations` VARCHAR(100) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/12.php b/system/migrations/12.php index 9730ed8b..00d6d6f0 100644 --- a/system/migrations/12.php +++ b/system/migrations/12.php @@ -1,51 +1,65 @@ hasColumn(TABLE_PREFIX . 'spells', 'item_id')) - $db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` ADD `item_id` INT(11) NOT NULL DEFAULT 0 AFTER `conjure_count`;"); +use MyAAC\Models\Spell; -// change unique index from spell to name -$db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` DROP INDEX `spell`;"); -$db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` ADD UNIQUE INDEX (`name`);"); - -// change comment of spells.type -$db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` MODIFY `type` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - instant, 2 - conjure, 3 - rune';"); - -// new items table -if(!$db->hasTable(TABLE_PREFIX . 'items')) -$db->query(" -CREATE TABLE `" . TABLE_PREFIX . "items` -( - `id` INT(11) NOT NULL, - `article` VARCHAR(5) NOT NULL DEFAULT '', - `name` VARCHAR(50) NOT NULL DEFAULT '', - `plural` VARCHAR(50) NOT NULL DEFAULT '', - `attributes` VARCHAR(500) NOT NULL DEFAULT '', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; -"); - -// new weapons table -if(!$db->hasTable(TABLE_PREFIX . 'weapons')) -$db->query(" -CREATE TABLE `" . TABLE_PREFIX . "weapons` -( - `id` INT(11) NOT NULL, - `level` INT(11) NOT NULL DEFAULT 0, - `maglevel` INT(11) NOT NULL DEFAULT 0, - `vocations` VARCHAR(100) NOT NULL DEFAULT '', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; -"); - -// modify vocations to support json data -$db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` MODIFY `vocations` VARCHAR(100) NOT NULL DEFAULT '';"); -$query = $db->query('SELECT `id`, `vocations` FROM `' . TABLE_PREFIX . 'spells`'); -foreach($query->fetchAll() as $spell) { - $tmp = explode(',', $spell['vocations']); - foreach($tmp as &$v) { - $v = (int)$v; +$up = function () use ($db) { + // add new item_id field for runes + if (!$db->hasColumn(TABLE_PREFIX . 'spells', 'item_id')) { + $db->addColumn(TABLE_PREFIX . 'spells', 'item_id', 'INT(11) NOT NULL DEFAULT 0 AFTER `conjure_count`'); } - $db->update(TABLE_PREFIX . 'spells', array('vocations' => json_encode($tmp)), array('id' => $spell['id'])); -} -?> \ No newline at end of file + + // change unique index from spell to name + $db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` DROP INDEX `spell`;"); + $db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` ADD UNIQUE INDEX (`name`);"); + + // change comment of spells.type + $db->modifyColumn(TABLE_PREFIX . 'spells', 'type', "TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - instant, 2 - conjure, 3 - rune'"); + + // new items table + if (!$db->hasTable(TABLE_PREFIX . 'items')) { + $db->query(file_get_contents(__DIR__ . '/12-items.sql')); + } + + // new weapons table + if (!$db->hasTable(TABLE_PREFIX . 'weapons')) { + $db->query(file_get_contents(__DIR__ . '/12-weapons.sql')); + } + + // modify vocations to support json data + $db->modifyColumn(TABLE_PREFIX . 'spells', 'vocations', "VARCHAR(100) NOT NULL DEFAULT ''"); + + $spells = Spell::select('id', 'vocations')->get(); + foreach ($spells as $spell) { + $tmp = explode(',', $spell->vocations); + foreach ($tmp as &$v) { + $v = (int)$v; + } + + Spell::where('id', $spell->id)->update(['vocations' => json_encode($tmp)]); + } +}; + +$down = function () use ($db) { + // remove item_id field for runes + if ($db->hasColumn(TABLE_PREFIX . 'spells', 'item_id')) { + $db->dropColumn(TABLE_PREFIX . 'spells', 'item_id'); + } + + // change unique index from spell to name + $db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` DROP INDEX `name`;"); + $db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` ADD INDEX (`spell`);"); + + $db->dropTable(TABLE_PREFIX . 'items'); + $db->dropTable(TABLE_PREFIX . 'weapons'); + + $spells = Spell::select('id', 'vocations')->get(); + // modify vocations to use vocation separated by comma + foreach ($spells as $spell) { + $vocations = empty($spell->vocations) ? [] : json_decode($spell->vocations); + + Spell::where('id', $spell->id)->update(['vocations' => implode(',', $vocations)]); + } +}; diff --git a/system/migrations/13.php b/system/migrations/13.php index 4eee77f3..86da43ad 100644 --- a/system/migrations/13.php +++ b/system/migrations/13.php @@ -1,3 +1,16 @@ hasColumn(TABLE_PREFIX . 'spells', 'spell')) - $db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` DROP COLUMN `spell`;"); \ No newline at end of file +/** + * @var OTS_DB_MySQL $db + */ + +$up = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'spells', 'spell')) { + $db->dropColumn(TABLE_PREFIX . 'spells', 'spell'); + } +}; + +$down = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'spells', 'spell')) { + $db->addColumn(TABLE_PREFIX . 'spells', 'spell', "VARCHAR(255) NOT NULL DEFAULT ''"); + } +}; diff --git a/system/migrations/14.php b/system/migrations/14.php index acd13afb..4c295c67 100644 --- a/system/migrations/14.php +++ b/system/migrations/14.php @@ -1,18 +1,39 @@ hasColumn(TABLE_PREFIX . 'monsters', 'file_path')) { - $db->query("ALTER TABLE `" . TABLE_PREFIX . "monsters` CHANGE `file_path` `loot` VARCHAR(5000);"); -} +$up = function () use ($db) { + // change monsters.file_path field to loot + if ($db->hasColumn(TABLE_PREFIX . 'monsters', 'file_path')) { + $db->changeColumn(TABLE_PREFIX . 'monsters', 'file_path', 'loot', 'VARCHAR(5000)'); + } -// update loot to empty string -$db->query("UPDATE `" . TABLE_PREFIX . "monsters` SET `loot` = '';"); + // update loot to empty string + $db->query("UPDATE `" . TABLE_PREFIX . "monsters` SET `loot` = '';"); -// drop monsters.gfx_name field -$db->query("ALTER TABLE `" . TABLE_PREFIX . "monsters` DROP COLUMN `gfx_name`;"); + // drop monsters.gfx_name field + $db->dropColumn(TABLE_PREFIX . 'monsters', 'gfx_name'); -// rename hide_creature to hidden -if($db->hasColumn(TABLE_PREFIX . 'monsters', 'hide_creature')) { - $db->query("ALTER TABLE `" . TABLE_PREFIX . "monsters` CHANGE `hide_creature` `hidden` TINYINT(1) NOT NULL DEFAULT 0;"); -} -?> \ No newline at end of file + // rename hide_creature to hidden + if ($db->hasColumn(TABLE_PREFIX . 'monsters', 'hide_creature')) { + $db->changeColumn(TABLE_PREFIX . 'monsters', 'hide_creature', 'hidden', "TINYINT(1) NOT NULL DEFAULT 0"); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'monsters', 'loot')) { + $db->changeColumn(TABLE_PREFIX . 'monsters', 'loot', 'file_path', 'VARCHAR(5000)'); + } + + // update file_path to empty string + $db->query("UPDATE `" . TABLE_PREFIX . "monsters` SET `file_path` = '';"); + + // add monsters.gfx_name field + $db->addColumn(TABLE_PREFIX . 'monsters', 'gfx_name', 'varchar(255) NOT NULL AFTER `race`'); + + // rename hidden to hide_creature + if ($db->hasColumn(TABLE_PREFIX . 'monsters', 'hidden')) { + $db->changeColumn(TABLE_PREFIX . 'monsters', 'hidden', 'hide_creature', 'TINYINT(1) NOT NULL DEFAULT 0'); + } +}; diff --git a/system/migrations/15.php b/system/migrations/15.php index 971587ec..eff04c42 100644 --- a/system/migrations/15.php +++ b/system/migrations/15.php @@ -1,10 +1,26 @@ hasColumn(TABLE_PREFIX . 'forum_boards', 'guild')) { - $db->query("ALTER TABLE `" . TABLE_PREFIX . "forum_boards` ADD `guild` TINYINT(1) NOT NULL DEFAULT 0 AFTER `closed`;"); -} -if(!$db->hasColumn(TABLE_PREFIX . 'forum_boards', 'access')) { - $db->query("ALTER TABLE `" . TABLE_PREFIX . "forum_boards` ADD `access` TINYINT(1) NOT NULL DEFAULT 0 AFTER `guild`;"); -} +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'forum_boards', 'guild')) { + $db->addColumn(TABLE_PREFIX . 'forum_boards', 'guild', 'TINYINT(1) NOT NULL DEFAULT 0 AFTER `closed`'); + } + + if (!$db->hasColumn(TABLE_PREFIX . 'forum_boards', 'access')) { + $db->addColumn(TABLE_PREFIX . 'forum_boards', 'access', 'TINYINT(1) NOT NULL DEFAULT 0 AFTER `guild`'); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'forum_boards', 'guild')) { + $db->dropColumn(TABLE_PREFIX . 'forum_boards', 'guild'); + } + + if ($db->hasColumn(TABLE_PREFIX . 'forum_boards', 'access')) { + $db->dropColumn(TABLE_PREFIX . 'forum_boards', 'access'); + } +}; diff --git a/system/migrations/16.php b/system/migrations/16.php index ad0112a2..0be467d4 100644 --- a/system/migrations/16.php +++ b/system/migrations/16.php @@ -1,5 +1,14 @@ query("ALTER TABLE `" . TABLE_PREFIX . "spells` MODIFY `vocations` VARCHAR(300) NOT NULL DEFAULT '';"); -?> \ No newline at end of file + +$up = function () use ($db) { + $db->modifyColumn(TABLE_PREFIX . 'spells', 'vocations', "VARCHAR(300) NOT NULL DEFAULT ''"); +}; + +$down = function () { + // nothing to do here +}; diff --git a/system/migrations/17-menu.sql b/system/migrations/17-menu.sql new file mode 100644 index 00000000..738e722b --- /dev/null +++ b/system/migrations/17-menu.sql @@ -0,0 +1,11 @@ +CREATE TABLE `myaac_menu` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `template` VARCHAR(255) NOT NULL, + `name` VARCHAR(255) NOT NULL, + `link` VARCHAR(255) NOT NULL, + `category` INT(11) NOT NULL DEFAULT 1, + `ordering` INT(11) NOT NULL DEFAULT 0, + `enabled` INT(1) NOT NULL DEFAULT 1, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/17.php b/system/migrations/17.php index 73e3828c..497e3e3c 100644 --- a/system/migrations/17.php +++ b/system/migrations/17.php @@ -1,23 +1,20 @@ hasTable('myaac_menu')) { - $db->query(" -CREATE TABLE `myaac_menu` -( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `template` VARCHAR(255) NOT NULL, - `name` VARCHAR(255) NOT NULL, - `link` VARCHAR(255) NOT NULL, - `category` INT(11) NOT NULL DEFAULT 1, - `ordering` INT(11) NOT NULL DEFAULT 0, - `enabled` INT(1) NOT NULL DEFAULT 1, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; -"); -} +$up = function () use ($db) { + if (!$db->hasTable(TABLE_PREFIX . 'menu')) { + $db->exec(file_get_contents(__DIR__ . '/17-menu.sql')); + } -Plugins::installMenus('kathrine', require TEMPLATES . 'kathrine/menus.php'); -Plugins::installMenus('tibiacom', require TEMPLATES . 'tibiacom/menus.php'); + Plugins::installMenus('kathrine', require TEMPLATES . 'kathrine/menus.php'); + Plugins::installMenus('tibiacom', require TEMPLATES . 'tibiacom/menus.php'); +}; + +$down = function () use ($db) { + $db->dropTable(TABLE_PREFIX . 'menu'); +}; diff --git a/system/migrations/18.php b/system/migrations/18.php index 7ec9675a..7c251e7c 100644 --- a/system/migrations/18.php +++ b/system/migrations/18.php @@ -1,6 +1,24 @@ query("ALTER TABLE `" . TABLE_PREFIX . "news` ADD `article_text` VARCHAR(300) NOT NULL DEFAULT '' AFTER `comments`;"); -$db->query("ALTER TABLE `" . TABLE_PREFIX . "news` ADD `article_image` VARCHAR(100) NOT NULL DEFAULT '' AFTER `article_text`;"); +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'news', 'article_text')) { + $db->addColumn(TABLE_PREFIX . 'news', 'article_text', "VARCHAR(300) NOT NULL DEFAULT '' AFTER `comments`"); + } -?> \ No newline at end of file + if (!$db->hasColumn(TABLE_PREFIX . 'news', 'article_image')) { + $db->addColumn(TABLE_PREFIX . 'news', 'article_image', "VARCHAR(100) NOT NULL DEFAULT '' AFTER `article_text`"); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'news', 'article_text')) { + $db->dropColumn(TABLE_PREFIX . 'news', 'article_text'); + } + + if ($db->hasColumn(TABLE_PREFIX . 'news', 'article_image')) { + $db->dropColumn(TABLE_PREFIX . 'news', 'article_image'); + } +}; diff --git a/system/migrations/2.php b/system/migrations/2.php index 90d9a610..d65c0586 100644 --- a/system/migrations/2.php +++ b/system/migrations/2.php @@ -1,5 +1,11 @@ query("ALTER TABLE `" . TABLE_PREFIX . "faq` MODIFY `answer` VARCHAR(1020) NOT NULL DEFAULT '';"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "movies` MODIFY `title` VARCHAR(100) NOT NULL DEFAULT '';"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "news` MODIFY `title` VARCHAR(100) NOT NULL DEFAULT '';"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "news` MODIFY `body` TEXT NOT NULL DEFAULT '';"); +/** + * @var OTS_DB_MySQL $db + */ + +$up = function () use ($db) { + $db->modifyColumn(TABLE_PREFIX . 'faq', 'answer', "VARCHAR(1020) NOT NULL DEFAULT ''"); + $db->modifyColumn(TABLE_PREFIX . 'movies', 'title', "VARCHAR(100) NOT NULL DEFAULT ''"); + $db->modifyColumn(TABLE_PREFIX . 'news', 'title', "VARCHAR(100) NOT NULL DEFAULT ''"); + $db->modifyColumn(TABLE_PREFIX . 'news', 'body', "TEXT NOT NULL"); +}; diff --git a/system/migrations/20.php b/system/migrations/20.php index e7b5ee0a..ccc20a51 100644 --- a/system/migrations/20.php +++ b/system/migrations/20.php @@ -2,16 +2,33 @@ use MyAAC\Settings; -$query = $db->query("SELECT `id` FROM `players` WHERE (`name` = " . $db->quote("Rook Sample") . " OR `name` = " . $db->quote("Sorcerer Sample") . " OR `name` = " . $db->quote("Druid Sample") . " OR `name` = " . $db->quote("Paladin Sample") . " OR `name` = " . $db->quote("Knight Sample") . " OR `name` = " . $db->quote("Account Manager") . ") ORDER BY `id`;"); +function updateHighscoresIdsHidden(): void +{ + global $db; -$highscores_ignored_ids = array(); -if($query->rowCount() > 0) { - foreach($query->fetchAll() as $result) - $highscores_ignored_ids[] = $result['id']; -} -else { - $highscores_ignored_ids[] = 0; + if (!$db->hasTable('players')) { + return; + } + + $query = $db->query("SELECT `id` FROM `players` WHERE (`name` = " . $db->quote("Rook Sample") . " OR `name` = " . $db->quote("Sorcerer Sample") . " OR `name` = " . $db->quote("Druid Sample") . " OR `name` = " . $db->quote("Paladin Sample") . " OR `name` = " . $db->quote("Knight Sample") . " OR `name` = " . $db->quote("Account Manager") . ") ORDER BY `id`;"); + + $highscores_ignored_ids = array(); + if ($query->rowCount() > 0) { + foreach ($query->fetchAll() as $result) + $highscores_ignored_ids[] = $result['id']; + } else { + $highscores_ignored_ids[] = 0; + } + + $settings = Settings::getInstance(); + $settings->updateInDatabase('core', 'highscores_ids_hidden', implode(', ', $highscores_ignored_ids)); } -$settings = Settings::getInstance(); -$settings->updateInDatabase('core', 'highscores_ids_hidden', implode(', ', $highscores_ignored_ids)); +$up = function () { + updateHighscoresIdsHidden(); +}; + +$down = function () { + $settings = Settings::getInstance(); + $settings->updateInDatabase('core', 'highscores_ids_hidden', '0'); +}; diff --git a/system/migrations/21.php b/system/migrations/21.php index 51bb518a..6282407c 100644 --- a/system/migrations/21.php +++ b/system/migrations/21.php @@ -1,14 +1,23 @@ exec("ALTER TABLE `" . TABLE_PREFIX . "forum` ADD `post_html` TINYINT(1) NOT NULL DEFAULT 0 AFTER `post_smile`;"); +$up = function () use ($db) { + $db->addColumn(TABLE_PREFIX . 'forum', 'post_html', 'TINYINT(1) NOT NULL DEFAULT 0 AFTER `post_smile`'); -$query = $db->query("SELECT `id` FROM `" . TABLE_PREFIX . "forum_boards` WHERE `name` LIKE " . $db->quote('News') . " LIMIT 1;"); -if($query->rowCount() == 0) { - return; // don't make anything -} + $query = $db->query("SELECT `id` FROM `" . TABLE_PREFIX . "forum_boards` WHERE `name` LIKE " . $db->quote('News') . " LIMIT 1;"); + if ($query->rowCount() == 0) { + return; // don't make anything + } -$query = $query->fetch(); -$id = $query['id']; + $query = $query->fetch(); + $id = $query['id']; -// update all forum threads with is_html = 1 -$db->exec("UPDATE `" . TABLE_PREFIX . "forum` SET `post_html` = 1 WHERE `section` = " . $id . " AND `id` = `first_post`;"); \ No newline at end of file + // update all forum threads with is_html = 1 + $db->exec("UPDATE `" . TABLE_PREFIX . "forum` SET `post_html` = 1 WHERE `section` = " . $id . " AND `id` = `first_post`;"); +}; + +$down = function () use ($db) { + $db->dropColumn(TABLE_PREFIX . 'forum', 'post_html'); +}; diff --git a/system/migrations/22-z_polls.sql b/system/migrations/22-z_polls.sql new file mode 100644 index 00000000..7d5d39df --- /dev/null +++ b/system/migrations/22-z_polls.sql @@ -0,0 +1,10 @@ +CREATE TABLE `z_polls` ( + `id` int(11) NOT NULL auto_increment, + `question` varchar(255) NOT NULL, + `description` varchar(255) NOT NULL, + `end` int(11) NOT NULL DEFAULT 0, + `start` int(11) NOT NULL DEFAULT 0, + `answers` int(11) NOT NULL DEFAULT 0, + `votes_all` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/22-z_polls_answers.sql b/system/migrations/22-z_polls_answers.sql new file mode 100644 index 00000000..f28940cf --- /dev/null +++ b/system/migrations/22-z_polls_answers.sql @@ -0,0 +1,6 @@ +CREATE TABLE `z_polls_answers` ( + `poll_id` int(11) NOT NULL, + `answer_id` int(11) NOT NULL, + `answer` varchar(255) NOT NULL, + `votes` int(11) NOT NULL DEFAULT 0 +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/22.php b/system/migrations/22.php index eca1ddac..c9621032 100644 --- a/system/migrations/22.php +++ b/system/migrations/22.php @@ -1,31 +1,35 @@ hasTable('z_polls')) - $db->query(' -CREATE TABLE `z_polls` ( - `id` int(11) NOT NULL auto_increment, - `question` varchar(255) NOT NULL, - `description` varchar(255) NOT NULL, - `end` int(11) NOT NULL DEFAULT 0, - `start` int(11) NOT NULL DEFAULT 0, - `answers` int(11) NOT NULL DEFAULT 0, - `votes_all` int(11) NOT NULL DEFAULT 0, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; -'); +$up = function () use ($db) { + if (!$db->hasTable('z_polls')) { + $db->exec(file_get_contents(__DIR__ . '/22-z_polls.sql')); + } -if(!$db->hasTable('z_polls_answers')) -$db->query(' - CREATE TABLE `z_polls_answers` ( - `poll_id` int(11) NOT NULL, - `answer_id` int(11) NOT NULL, - `answer` varchar(255) NOT NULL, - `votes` int(11) NOT NULL DEFAULT 0 -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; -'); + if (!$db->hasTable('z_polls_answers')) { + $db->exec(file_get_contents(__DIR__ . '/22-z_polls_answers.sql')); + } -if(!$db->hasColumn('accounts', 'vote')) - $db->query('ALTER TABLE `accounts` ADD `vote` INT( 11 ) DEFAULT 0 NOT NULL ;'); -else { - $db->query('ALTER TABLE `accounts` MODIFY `vote` INT( 11 ) DEFAULT 0 NOT NULL ;'); -} \ No newline at end of file + if (!$db->hasColumn('accounts', 'vote')) { + $db->addColumn('accounts', 'vote', 'int(11) NOT NULL DEFAULT 0'); + } + else { + $db->modifyColumn('accounts', 'vote', 'int(11) NOT NULL DEFAULT 0'); + } +}; + +$down = function () use ($db) { + if ($db->hasTable('z_polls')) { + $db->dropTable('z_polls;'); + } + + if ($db->hasTable('z_polls_answers')) { + $db->dropTable('z_polls_answers'); + } + + if ($db->hasColumn('accounts', 'vote')) { + $db->dropColumn('accounts', 'vote'); + } +}; diff --git a/system/migrations/23.php b/system/migrations/23.php index ba4bbe0c..6174a086 100644 --- a/system/migrations/23.php +++ b/system/migrations/23.php @@ -1,7 +1,24 @@ hasColumn(TABLE_PREFIX . 'menu', 'blank')) - $db->query("ALTER TABLE `" . TABLE_PREFIX . "menu` ADD `blank` TINYINT(1) NOT NULL DEFAULT 0 AFTER `link`;"); +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'menu', 'blank')) { + $db->addColumn(TABLE_PREFIX . 'menu', 'blank', 'TINYINT(1) NOT NULL DEFAULT 0 AFTER `link`'); + } -if(!$db->hasColumn(TABLE_PREFIX . 'menu', 'color')) - $db->query("ALTER TABLE `" . TABLE_PREFIX . "menu` ADD `color` CHAR(6) NOT NULL DEFAULT '' AFTER `blank`;"); \ No newline at end of file + if (!$db->hasColumn(TABLE_PREFIX . 'menu', 'color')) { + $db->addColumn(TABLE_PREFIX . 'menu', 'color', "CHAR(6) NOT NULL DEFAULT '' AFTER `blank`"); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'menu', 'blank')) { + $db->dropColumn(TABLE_PREFIX . 'menu', 'blank'); + } + + if ($db->hasColumn(TABLE_PREFIX . 'menu', 'color')) { + $db->dropColumn(TABLE_PREFIX . 'menu', 'color'); + } +}; diff --git a/system/migrations/24-items.sql b/system/migrations/24-items.sql new file mode 100644 index 00000000..458333e0 --- /dev/null +++ b/system/migrations/24-items.sql @@ -0,0 +1,9 @@ +CREATE TABLE `myaac_items` +( + `id` INT(11) NOT NULL, + `article` VARCHAR(5) NOT NULL DEFAULT '', + `name` VARCHAR(50) NOT NULL DEFAULT '', + `plural` VARCHAR(50) NOT NULL DEFAULT '', + `attributes` VARCHAR(500) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/24.php b/system/migrations/24.php index b7e93819..3fa44ae1 100644 --- a/system/migrations/24.php +++ b/system/migrations/24.php @@ -1,3 +1,12 @@ exec('DROP TABLE IF EXISTS `' . TABLE_PREFIX . 'items`;'); \ No newline at end of file +$up = function () use ($db) { + $db->dropTable(TABLE_PREFIX . 'items'); +}; + +$down = function () use ($db) { + $db->exec(file_get_contents(__DIR__ . '/24-items.sql')); +}; diff --git a/system/migrations/25.php b/system/migrations/25.php index 9e87c504..6a4b3ad2 100644 --- a/system/migrations/25.php +++ b/system/migrations/25.php @@ -1,3 +1,12 @@ exec('ALTER TABLE `' . TABLE_PREFIX . 'monsters` MODIFY `loot` text NOT NULL;'); \ No newline at end of file +$up = function () use ($db) { + $db->modifyColumn(TABLE_PREFIX . 'monsters', 'loot', 'text NOT NULL'); +}; + +$down = function () { + // nothing to do +}; diff --git a/system/migrations/26.php b/system/migrations/26.php index 9804b774..ad565754 100644 --- a/system/migrations/26.php +++ b/system/migrations/26.php @@ -1,17 +1,32 @@ hasColumn(TABLE_PREFIX . 'spells', 'spell')) { - $db->exec('ALTER TABLE `' . TABLE_PREFIX . "spells` MODIFY `spell` VARCHAR(255) NOT NULL DEFAULT '';"); -} +$up = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'spells', 'spell')) { + $db->modifyColumn(TABLE_PREFIX . 'spells', 'spell', "VARCHAR(255) NOT NULL DEFAULT ''"); + } -if($db->hasColumn(TABLE_PREFIX . 'spells', 'words')) { - $db->exec('ALTER TABLE `' . TABLE_PREFIX . "spells` MODIFY `words` VARCHAR(255) NOT NULL DEFAULT '';"); -} + if ($db->hasColumn(TABLE_PREFIX . 'spells', 'words')) { + $db->modifyColumn(TABLE_PREFIX . 'spells', 'words', "VARCHAR(255) NOT NULL DEFAULT ''"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'spells', 'conjure_id')) { - $db->exec('ALTER TABLE `' . TABLE_PREFIX . 'spells` ADD `conjure_id` INT(11) NOT NULL DEFAULT 0 AFTER `soul`;'); -} + if (!$db->hasColumn(TABLE_PREFIX . 'spells', 'conjure_id')) { + $db->addColumn(TABLE_PREFIX . 'spells', 'conjure_id', 'INT(11) NOT NULL DEFAULT 0 AFTER `soul`'); + } -if(!$db->hasColumn(TABLE_PREFIX . 'spells', 'reagent')) { - $db->exec('ALTER TABLE `' . TABLE_PREFIX . 'spells` ADD `reagent` INT(11) NOT NULL DEFAULT 0 AFTER `conjure_count`;'); -} + if (!$db->hasColumn(TABLE_PREFIX . 'spells', 'reagent')) { + $db->addColumn(TABLE_PREFIX . 'spells', 'reagent', 'INT(11) NOT NULL DEFAULT 0 AFTER `conjure_count`'); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'spells', 'conjure_id')) { + $db->dropColumn(TABLE_PREFIX . 'spells', 'conjure_id'); + } + + if ($db->hasColumn(TABLE_PREFIX . 'spells', 'reagent')) { + $db->dropColumn(TABLE_PREFIX . 'spells', 'reagent'); + } +}; diff --git a/system/migrations/27-commands.html b/system/migrations/27-commands.html new file mode 100644 index 00000000..accb1c62 --- /dev/null +++ b/system/migrations/27-commands.html @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + +
WordsDescription
!exampleThis is just an example
!buyhouseBuy house you are looking at
!aolBuy AoL
diff --git a/system/migrations/27-downloads.html b/system/migrations/27-downloads.html new file mode 100644 index 00000000..ebf401fc --- /dev/null +++ b/system/migrations/27-downloads.html @@ -0,0 +1,6 @@ +

 

+

 

+
We're using official Tibia Client {{ config.client / 100 }}
+

Download Tibia Client {{ config.client / 100 }} for Windows HERE.

+

IP Changer:

+ HERE
diff --git a/system/migrations/27.php b/system/migrations/27.php index 42040092..95c0cd2a 100644 --- a/system/migrations/27.php +++ b/system/migrations/27.php @@ -1,47 +1,48 @@  

-

 

-
We're using official Tibia Client {{ config.client / 100 }}
-

Download Tibia Client {{ config.client / 100 }} for Windows HERE.

-

IP Changer:

-HERE
-HTML; +use MyAAC\Models\Pages; -$query = $db->query("SELECT `id` FROM `" . TABLE_PREFIX . "pages` WHERE `name` LIKE " . $db->quote('downloads') . " LIMIT 1;"); -if($query->rowCount() === 0) { - $db->exec("INSERT INTO `myaac_pages` (`id`, `name`, `title`, `body`, `date`, `player_id`, `php`, `access`, `hide`) VALUES - (null, 'downloads', 'Downloads', {$db->quote($downloadsPage)}, 0, 1, 0, 0, 0);"); -} +$up = function () use ($db) { + $downloadsModel = Pages::where('name', 'downloads')->first(); + if (!$downloadsModel) { + $db->insert(TABLE_PREFIX . 'pages', [ + 'name' => 'downloads', + 'title' => 'Downloads', + 'body' => file_get_contents(__DIR__ . '/27-downloads.html'), + 'date' => time(), + 'player_id' => 1, + 'php' => 0, + 'access' => 0, + ($db->hasColumn(TABLE_PREFIX . 'pages', 'hide') ? 'hide' : 'hidden') => 0, + ]); + } -$commandsPage = << - - -Words -Description - - - - -!example -This is just an example - - -!buyhouse -Buy house you are looking at - - -!aol -Buy AoL - - - -HTML; + $commandsModel = Pages::where('name', 'commands')->first(); + if (!$commandsModel) { + $db->insert(TABLE_PREFIX . 'pages', [ + 'name' => 'commands', + 'title' => 'Commands', + 'body' => file_get_contents(__DIR__ . '/27-commands.html'), + 'date' => time(), + 'player_id' => 1, + 'php' => 0, + 'access' => 0, + ($db->hasColumn(TABLE_PREFIX . 'pages', 'hide') ? 'hide' : 'hidden') => 0, + ]); + } +}; -$query = $db->query("SELECT `id` FROM `" . TABLE_PREFIX . "pages` WHERE `name` LIKE " . $db->quote('commands') . " LIMIT 1;"); -if($query->rowCount() === 0) { - $db->exec("INSERT INTO `myaac_pages` (`id`, `name`, `title`, `body`, `date`, `player_id`, `php`, `access`, `hide`) VALUES -(null, 'commands', 'Commands', {$db->quote($commandsPage)}, 0, 1, 0, 0, 0);"); -} +$down = function () { + $downloadsModel = Pages::where('name', 'downloads')->first(); + if ($downloadsModel) { + $downloadsModel->delete(); + } + + $commandsModel = Pages::where('name', 'commands')->first(); + if ($commandsModel) { + $commandsModel->delete(); + } +}; diff --git a/system/migrations/28-hooks.sql b/system/migrations/28-hooks.sql new file mode 100644 index 00000000..ff1a228d --- /dev/null +++ b/system/migrations/28-hooks.sql @@ -0,0 +1,10 @@ +CREATE TABLE `myaac_hooks` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(30) NOT NULL DEFAULT '', + `type` INT(2) NOT NULL DEFAULT 0, + `file` VARCHAR(100) NOT NULL, + `ordering` INT(11) NOT NULL DEFAULT 0, + `enabled` INT(1) NOT NULL DEFAULT 1, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/28.php b/system/migrations/28.php index d06487c8..9df8dedc 100644 --- a/system/migrations/28.php +++ b/system/migrations/28.php @@ -1,10 +1,25 @@ exec('DROP TABLE IF EXISTS `' . TABLE_PREFIX . 'hooks`;'); +$up = function () use ($db) { + $db->dropTable(TABLE_PREFIX . 'hooks'); + + $cache = Cache::getInstance(); + if($cache->enabled()) { + $cache->delete('hooks'); + } +}; + +$down = function () use ($db) { + $db->exec(file_get_contents(__DIR__ . '/28-hooks.sql')); + + $cache = Cache::getInstance(); + if($cache->enabled()) { + $cache->delete('hooks'); + } +}; -$cache = Cache::getInstance(); -if($cache->enabled()) { - $cache->delete('hooks'); -} diff --git a/system/migrations/29.php b/system/migrations/29.php index 79e3d81d..e9c1ec7f 100644 --- a/system/migrations/29.php +++ b/system/migrations/29.php @@ -1,5 +1,16 @@ hasColumn(TABLE_PREFIX . 'pages', 'enable_tinymce')) { - $db->exec('ALTER TABLE `' . TABLE_PREFIX . 'pages` ADD `enable_tinymce` TINYINT(1) NOT NULL DEFAULT 1 COMMENT \'1 - enabled, 0 - disabled\' AFTER `php`;'); -} +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'pages', 'enable_tinymce')) { + $db->addColumn(TABLE_PREFIX . 'pages', 'enable_tinymce', "TINYINT(1) NOT NULL DEFAULT 1 COMMENT '1 - enabled, 0 - disabled' AFTER `php`"); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'pages', 'enable_tinymce')) { + $db->dropColumn(TABLE_PREFIX . 'pages', 'enable_tinymce'); + } +}; diff --git a/system/migrations/3.php b/system/migrations/3.php index 76c0acc8..f79dcbe7 100644 --- a/system/migrations/3.php +++ b/system/migrations/3.php @@ -1,3 +1,15 @@ query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` ADD `ipv6` BINARY(16) NOT NULL DEFAULT 0;"); -?> \ No newline at end of file +/** + * @var OTS_DB_MySQL $db + */ + +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'account_actions', 'ipv6')) { + $db->addColumn(TABLE_PREFIX . 'account_actions', 'ipv6', "BINARY(16) NOT NULL DEFAULT 0"); + } +}; + +$down = function () { + // we don't want data loss + //$db->dropColumn(TABLE_PREFIX . 'account_actions', 'ipv6'); +}; diff --git a/system/migrations/30-rules.txt b/system/migrations/30-rules.txt new file mode 100644 index 00000000..2b226230 --- /dev/null +++ b/system/migrations/30-rules.txt @@ -0,0 +1,25 @@ +1. Names +a) Names which contain insulting (e.g. "Bastard"), racist (e.g. "Nigger"), extremely right-wing (e.g. "Hitler"), sexist (e.g. "Bitch") or offensive (e.g. "Copkiller") language. +b) Names containing parts of sentences (e.g. "Mike returns"), nonsensical combinations of letters (e.g. "Fgfshdsfg") or invalid formattings (e.g. "Thegreatknight"). +c) Names that obviously do not describe a person (e.g. "Christmastree", "Matrix"), names of real life celebrities (e.g. "Britney Spears"), names that refer to real countries (e.g. "Swedish Druid"), names which were created to fake other players' identities (e.g. "Arieswer" instead of "Arieswar") or official positions (e.g. "System Admin"). + +2. Cheating +a) Exploiting obvious errors of the game ("bugs"), for instance to duplicate items. If you find an error you must report it to CipSoft immediately. +b) Intentional abuse of weaknesses in the gameplay, for example arranging objects or players in a way that other players cannot move them. +c) Using tools to automatically perform or repeat certain actions without any interaction by the player ("macros"). +d) Manipulating the client program or using additional software to play the game. +e) Trying to steal other players\' account data ("hacking"). +f) Playing on more than one account at the same time ("multi-clienting"). +g) Offering account data to other players or accepting other players' account data ("account-trading/sharing"). + +3. Gamemasters +a) Threatening a gamemaster because of his or her actions or position as a gamemaster. +b) Pretending to be a gamemaster or to have influence on the decisions of a gamemaster. +c) Intentionally giving wrong or misleading information to a gamemaster concerning his or her investigations or making false reports about rule violations. + +4. Player Killing +a) Excessive killing of characters who are not marked with a "skull" on worlds which are not PvP-enforced. Please note that killing marked characters is not a reason for a banishment. + +A violation of the Tibia Rules may lead to temporary banishment of characters and accounts. In severe cases removal or modification of character skills, attributes and belongings, as well as the permanent removal of accounts without any compensation may be considered. The sanction is based on the seriousness of the rule violation and the previous record of the player. It is determined by the gamemaster imposing the banishment. + +These rules may be changed at any time. All changes will be announced on the official website. diff --git a/system/migrations/30.php b/system/migrations/30.php index 3d919597..2e38e468 100644 --- a/system/migrations/30.php +++ b/system/migrations/30.php @@ -1,31 +1,27 @@ query("SELECT `id` FROM `" . TABLE_PREFIX . "pages` WHERE `name` LIKE " . $db->quote('rules_on_the_page') . " LIMIT 1;"); -if($query->rowCount() === 0) { - $db->exec("INSERT INTO `myaac_pages` (`id`, `name`, `title`, `body`, `date`, `player_id`, `php`, `enable_tinymce`, `access`, `hide`) VALUES - (null, 'rules_on_the_page', 'Rules', '1. Names -a) Names which contain insulting (e.g. \"Bastard\"), racist (e.g. \"Nigger\"), extremely right-wing (e.g. \"Hitler\"), sexist (e.g. \"Bitch\") or offensive (e.g. \"Copkiller\") language. -b) Names containing parts of sentences (e.g. \"Mike returns\"), nonsensical combinations of letters (e.g. \"Fgfshdsfg\") or invalid formattings (e.g. \"Thegreatknight\"). -c) Names that obviously do not describe a person (e.g. \"Christmastree\", \"Matrix\"), names of real life celebrities (e.g. \"Britney Spears\"), names that refer to real countries (e.g. \"Swedish Druid\"), names which were created to fake other players\' identities (e.g. \"Arieswer\" instead of \"Arieswar\") or official positions (e.g. \"System Admin\"). +use MyAAC\Models\Pages; -2. Cheating -a) Exploiting obvious errors of the game (\"bugs\"), for instance to duplicate items. If you find an error you must report it to CipSoft immediately. -b) Intentional abuse of weaknesses in the gameplay, for example arranging objects or players in a way that other players cannot move them. -c) Using tools to automatically perform or repeat certain actions without any interaction by the player (\"macros\"). -d) Manipulating the client program or using additional software to play the game. -e) Trying to steal other players\' account data (\"hacking\"). -f) Playing on more than one account at the same time (\"multi-clienting\"). -g) Offering account data to other players or accepting other players\' account data (\"account-trading/sharing\"). +$up = function () { + $rulesOnPage = Pages::where('name', 'rules_on_the_page')->first(); + if (!$rulesOnPage) { + Pages::create([ + 'name' => 'rules_on_the_page', + 'title' => 'Rules', + 'body' => file_get_contents(__DIR__ . '/30-rules.txt'), + 'date' => time(), + 'player_id' => 1, + 'php' => 0, + 'enable_tinymce' => 0, + 'access' => 0, + 'hidden' => 0, + ]); + } +}; -3. Gamemasters -a) Threatening a gamemaster because of his or her actions or position as a gamemaster. -b) Pretending to be a gamemaster or to have influence on the decisions of a gamemaster. -c) Intentionally giving wrong or misleading information to a gamemaster concerning his or her investigations or making false reports about rule violations. - -4. Player Killing -a) Excessive killing of characters who are not marked with a \"skull\" on worlds which are not PvP-enforced. Please note that killing marked characters is not a reason for a banishment. - -A violation of the Tibia Rules may lead to temporary banishment of characters and accounts. In severe cases removal or modification of character skills, attributes and belongings, as well as the permanent removal of accounts without any compensation may be considered. The sanction is based on the seriousness of the rule violation and the previous record of the player. It is determined by the gamemaster imposing the banishment. - -These rules may be changed at any time. All changes will be announced on the official website.', 0, 1, 0, 0, 0, 0);"); -} +$down = function () { + $rulesOnPage = Pages::where('name', 'rules_on_the_page')->first(); + if ($rulesOnPage) { + Pages::where('name', 'rules_on_the_page')->delete(); + } +}; diff --git a/system/migrations/31.php b/system/migrations/31.php index 8dadb817..edbf7020 100644 --- a/system/migrations/31.php +++ b/system/migrations/31.php @@ -1,57 +1,121 @@ hasColumn(TABLE_PREFIX . 'monsters', 'elements')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `elements` TEXT NOT NULL AFTER `immunities`;"); -} +$up = function () use ($db) { + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'elements')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'elements', "TEXT NOT NULL AFTER `immunities`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'pushable')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `pushable` TINYINT(1) NOT NULL DEFAULT '0' AFTER `convinceable`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'pushable')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'pushable', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `convinceable`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canpushitems')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `canpushitems` TINYINT(1) NOT NULL DEFAULT '0' AFTER `pushable`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canpushitems')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'canpushitems', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `pushable`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canpushcreatures')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `canpushcreatures` TINYINT(1) NOT NULL DEFAULT '0' AFTER `canpushitems`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canpushcreatures')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'canpushcreatures', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `canpushitems`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canwalkonenergy')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `canwalkonenergy` TINYINT(1) NOT NULL DEFAULT '0' AFTER `canpushitems`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canwalkonenergy')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'canwalkonenergy', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `canpushitems`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canwalkonpoison')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `canwalkonpoison` TINYINT(1) NOT NULL DEFAULT '0' AFTER `canwalkonenergy`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canwalkonpoison')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'canwalkonpoison', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `canwalkonenergy`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canwalkonfire')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `canwalkonfire` TINYINT(1) NOT NULL DEFAULT '0' AFTER `canwalkonpoison`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'canwalkonfire')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'canwalkonfire', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `canwalkonpoison`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'runonhealth')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `runonhealth` TINYINT(1) NOT NULL DEFAULT '0' AFTER `canwalkonfire`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'runonhealth')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'runonhealth', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `canwalkonfire`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'hostile')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `hostile` TINYINT(1) NOT NULL DEFAULT '0' AFTER `runonhealth`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'hostile')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'hostile', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `runonhealth`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'attackable')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `attackable` TINYINT(1) NOT NULL DEFAULT '0' AFTER `hostile`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'attackable')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'attackable', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `hostile`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'rewardboss')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `rewardboss` TINYINT(1) NOT NULL DEFAULT '0' AFTER `attackable`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'rewardboss')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'rewardboss', "TINYINT(1) NOT NULL DEFAULT '0' AFTER `attackable`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'defense')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `defense` INT(11) NOT NULL DEFAULT '0' AFTER `rewardboss`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'defense')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'defense', "INT(11) NOT NULL DEFAULT '0' AFTER `rewardboss`"); + } -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'armor')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `armor` INT(11) NOT NULL DEFAULT '0' AFTER `defense`;"); -} + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'armor')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'armor', "INT(11) NOT NULL DEFAULT '0' AFTER `defense`"); + } + + if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'summons')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'summons', "TEXT NOT NULL AFTER `loot`"); + } +}; + +$down = function () use ($db) { + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'elements')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'elements'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'pushable')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'pushable'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'canpushitems')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'canpushitems'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'canpushcreatures')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'canpushcreatures'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'canwalkonenergy')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'canwalkonenergy'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'canwalkonpoison')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'canwalkonpoison'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'canwalkonfire')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'canwalkonfire'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'runonhealth')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'runonhealth'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'hostile')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'hostile'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'attackable')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'attackable'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'rewardboss')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'rewardboss'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'defense')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'defense'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'armor')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'armor'); + } + + if($db->hasColumn(TABLE_PREFIX . 'monsters', 'summons')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'summons'); + } +}; -if(!$db->hasColumn(TABLE_PREFIX . 'monsters', 'summons')) { - $db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `summons` TEXT NOT NULL AFTER `loot`;"); -} diff --git a/system/migrations/32.php b/system/migrations/32.php index ca1e4859..63f7b757 100644 --- a/system/migrations/32.php +++ b/system/migrations/32.php @@ -1,4 +1,14 @@ exec('ALTER TABLE `' . TABLE_PREFIX . "visitors` MODIFY `page` VARCHAR(2048) NOT NULL;"); +$up = function () use ($db) { + $db->modifyColumn(TABLE_PREFIX . 'visitors', 'page', 'VARCHAR(2048) NOT NULL'); +}; + +$down = function () { + // nothing to be done, as we have just extended the size of a column +}; diff --git a/system/migrations/33.php b/system/migrations/33.php index 12fe4c2c..97c39fcc 100644 --- a/system/migrations/33.php +++ b/system/migrations/33.php @@ -1,6 +1,16 @@ exec('ALTER TABLE `' . TABLE_PREFIX . "visitors` MODIFY `ip` VARCHAR(45) NOT NULL;"); +$up = function () use ($db) { + $db->modifyColumn(TABLE_PREFIX . 'visitors', 'ip', 'VARCHAR(15) NOT NULL'); +}; + +$down = function () { + // nothing to be done, as we have just extended the size of a column +}; diff --git a/system/migrations/34.php b/system/migrations/34.php index 6f4e6b4a..0e51c7c3 100644 --- a/system/migrations/34.php +++ b/system/migrations/34.php @@ -1,4 +1,18 @@ exec('ALTER TABLE `' . TABLE_PREFIX . "visitors` ADD `user_agent` VARCHAR(255) NOT NULL DEFAULT '';"); +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'visitors', 'user_agent')) { + $db->addColumn(TABLE_PREFIX . 'visitors', 'user_agent', "VARCHAR(255) NOT NULL DEFAULT ''"); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'visitors', 'user_agent')) { + $db->dropColumn(TABLE_PREFIX . 'visitors', 'user_agent'); + } +}; diff --git a/system/migrations/35.php b/system/migrations/35.php index 8016807d..1baf68a7 100644 --- a/system/migrations/35.php +++ b/system/migrations/35.php @@ -1,3 +1,17 @@ exec('ALTER TABLE `' . TABLE_PREFIX . "monsters` ADD `look` VARCHAR(255) NOT NULL DEFAULT '' AFTER `health`;"); \ No newline at end of file +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'monsters', 'look')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'look', "VARCHAR(255) NOT NULL DEFAULT '' AFTER `health`"); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'monsters', 'look')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'look'); + } +}; diff --git a/system/migrations/36-settings.sql b/system/migrations/36-settings.sql new file mode 100644 index 00000000..eded157b --- /dev/null +++ b/system/migrations/36-settings.sql @@ -0,0 +1,9 @@ +CREATE TABLE `myaac_settings` +( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL DEFAULT '', + `key` VARCHAR(255) NOT NULL DEFAULT '', + `value` TEXT NOT NULL, + PRIMARY KEY (`id`), + KEY `key` (`key`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; diff --git a/system/migrations/36.php b/system/migrations/36.php index d88e9d28..1f27c51f 100644 --- a/system/migrations/36.php +++ b/system/migrations/36.php @@ -1,14 +1,18 @@ hasTable(TABLE_PREFIX . 'settings')) { - $db->exec("CREATE TABLE `" . TABLE_PREFIX . "settings` - ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` VARCHAR(255) NOT NULL DEFAULT '', - `key` VARCHAR(255) NOT NULL DEFAULT '', - `value` TEXT NOT NULL, - PRIMARY KEY (`id`), - KEY `key` (`key`) - ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;"); -} +$up = function () use ($db) { + // add settings table + if (!$db->hasTable(TABLE_PREFIX . 'settings')) { + $db->exec(file_get_contents(__DIR__ . '/36-settings.sql')); + } +}; + +$down = function () { + // will break the aac + //if ($db->hasTable(TABLE_PREFIX . 'settings')) { + // $db->dropTable(TABLE_PREFIX . 'settings'); + //} +}; diff --git a/system/migrations/37.php b/system/migrations/37.php index dd12f35a..110d15c2 100644 --- a/system/migrations/37.php +++ b/system/migrations/37.php @@ -5,4 +5,10 @@ use MyAAC\Models\Pages; -Pages::query()->where('access', 1)->update(['access' => 0]); +$up = function () { + Pages::query()->where('access', 1)->update(['access' => 0]); +}; + +$down = function () { + Pages::query()->where('access', 0)->update(['access' => 1]); +}; diff --git a/system/migrations/38.php b/system/migrations/38.php index b2d066a7..c8f6326c 100644 --- a/system/migrations/38.php +++ b/system/migrations/38.php @@ -1,5 +1,16 @@ hasColumn('players', 'hide')) { - $db->exec("ALTER TABLE `players` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); -} +$definition = 'TINYINT(1) NOT NULL DEFAULT 0'; -$db->exec("ALTER TABLE `" . TABLE_PREFIX . "changelog` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); -$db->exec("ALTER TABLE `" . TABLE_PREFIX . "faq` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); -$db->exec("ALTER TABLE `" . TABLE_PREFIX . "forum_boards` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); -$db->exec("ALTER TABLE `" . TABLE_PREFIX . "monsters` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); -$db->exec("ALTER TABLE `" . TABLE_PREFIX . "news` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); -$db->exec("ALTER TABLE `" . TABLE_PREFIX . "news_categories` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); -$db->exec("ALTER TABLE `" . TABLE_PREFIX . "pages` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); -$db->exec("ALTER TABLE `" . TABLE_PREFIX . "gallery` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); -$db->exec("ALTER TABLE `" . TABLE_PREFIX . "spells` CHANGE `hidden` `hide` TINYINT(1) NOT NULL DEFAULT 0;"); +$up = function () use ($db, $definition) { + if (!$db->hasColumn('players', 'hide')) { + $db->changeColumn('players', 'hidden', 'hide', $definition); + } + + $db->changeColumn(TABLE_PREFIX . 'changelog', 'hidden', 'hide', $definition); + $db->changeColumn(TABLE_PREFIX . 'faq', 'hidden', 'hide', $definition); + $db->changeColumn(TABLE_PREFIX . 'forum_boards', 'hidden', 'hide', $definition); + $db->changeColumn(TABLE_PREFIX . 'monsters', 'hidden', 'hide', $definition); + $db->changeColumn(TABLE_PREFIX . 'news', 'hidden', 'hide', $definition); + $db->changeColumn(TABLE_PREFIX . 'news_categories', 'hidden', 'hide', $definition); + $db->changeColumn(TABLE_PREFIX . 'pages', 'hidden', 'hide', $definition); + $db->changeColumn(TABLE_PREFIX . 'gallery', 'hidden', 'hide', $definition); + $db->changeColumn(TABLE_PREFIX . 'spells', 'hidden', 'hide', $definition); +}; + +$down = function () use ($db, $definition) { + if (!$db->hasColumn('players', 'hidden')) { + $db->changeColumn('players', 'hide', 'hidden', $definition); + } + + $db->changeColumn(TABLE_PREFIX . 'changelog', 'hide', 'hidden', $definition); + $db->changeColumn(TABLE_PREFIX . 'faq', 'hide', 'hidden', $definition); + $db->changeColumn(TABLE_PREFIX . 'forum_boards', 'hide', 'hidden', $definition); + $db->changeColumn(TABLE_PREFIX . 'monsters', 'hide', 'hidden', $definition); + $db->changeColumn(TABLE_PREFIX . 'news', 'hide', 'hidden', $definition); + $db->changeColumn(TABLE_PREFIX . 'news_categories', 'hide', 'hidden', $definition); + $db->changeColumn(TABLE_PREFIX . 'pages', 'hide', 'hidden', $definition); + $db->changeColumn(TABLE_PREFIX . 'gallery', 'hide', 'hidden', $definition); + $db->changeColumn(TABLE_PREFIX . 'spells', 'hide', 'hidden', $definition); +}; diff --git a/system/migrations/4.php b/system/migrations/4.php index db17feb1..93746eef 100644 --- a/system/migrations/4.php +++ b/system/migrations/4.php @@ -1,3 +1,16 @@ hasColumn(TABLE_PREFIX . 'monsters', 'id')) - $db->query("ALTER TABLE `" . TABLE_PREFIX . "monsters` ADD `id` int(11) NOT NULL AUTO_INCREMENT primary key FIRST;"); \ No newline at end of file +/** + * @var OTS_DB_MySQL $db + */ + +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'monsters', 'id')) { + $db->addColumn(TABLE_PREFIX . 'monsters', 'id', "int(11) NOT NULL AUTO_INCREMENT primary key FIRST"); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'monsters', 'id')) { + $db->dropColumn(TABLE_PREFIX . 'monsters', 'id'); + } +}; diff --git a/system/migrations/40.php b/system/migrations/40.php index 7a7eb310..ef492a11 100644 --- a/system/migrations/40.php +++ b/system/migrations/40.php @@ -5,8 +5,19 @@ use MyAAC\Models\Menu; -Menu::where('link', 'lastkills')->update(['link' => 'last-kills']); -Menu::where('link', 'serverInfo')->update(['link' => 'server-info']); -Menu::where('link', 'experienceStages')->update(['link' => 'exp-stages']); -Menu::where('link', 'experienceTable')->update(['link' => 'exp-table']); -Menu::where('link', 'creatures')->update(['link' => 'monsters']); +$up = function() { + Menu::where('link', 'lastkills')->update(['link' => 'last-kills']); + Menu::where('link', 'serverInfo')->update(['link' => 'server-info']); + Menu::where('link', 'experienceStages')->update(['link' => 'exp-stages']); + Menu::where('link', 'experienceTable')->update(['link' => 'exp-table']); + Menu::where('link', 'creatures')->update(['link' => 'monsters']); +}; + +$down = function() { + Menu::where('link', 'last-kills')->update(['link' => 'lastkills']); + Menu::where('link', 'server-info')->update(['link' => 'serverInfo']); + Menu::where('link', 'exp-stages')->update(['link' => 'experienceStages']); + Menu::where('link', 'exp-table')->update(['link' => 'experienceTable']); + Menu::where('link', 'monsters')->update(['link' => 'creatures']); +}; + diff --git a/system/migrations/41.php b/system/migrations/41.php new file mode 100644 index 00000000..091f0cba --- /dev/null +++ b/system/migrations/41.php @@ -0,0 +1,35 @@ +hasTable(TABLE_PREFIX . $table)) { + $db->exec('ALTER TABLE ' . TABLE_PREFIX . $table . ' CONVERT TO CHARACTER SET utf8mb4'); + } + } +}; + +$down = function () use ($db, $tables) +{ + foreach ($tables as $table) { + if ($db->hasTable(TABLE_PREFIX . $table)) { + $db->exec('ALTER TABLE ' . TABLE_PREFIX . $table . ' CONVERT TO CHARACTER SET utf8'); + } + } +}; diff --git a/system/migrations/5.php b/system/migrations/5.php index bef48d61..d269a348 100644 --- a/system/migrations/5.php +++ b/system/migrations/5.php @@ -1,4 +1,16 @@ hasColumn(TABLE_PREFIX . 'spells', 'cities')) - $db->query("ALTER TABLE `" . TABLE_PREFIX . "spells` DROP COLUMN cities;"); -?> \ No newline at end of file +/** + * @var OTS_DB_MySQL $db + */ + +$up = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'spells', 'cities')) { + $db->dropColumn(TABLE_PREFIX . 'spells', 'cities'); + } +}; + +$up = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'spells', 'cities')) { + $db->addColumn(TABLE_PREFIX . 'spells', 'cities', 'VARCHAR(32) NOT NULL'); + } +}; diff --git a/system/migrations/6.php b/system/migrations/6.php index e287d55a..b99671d3 100644 --- a/system/migrations/6.php +++ b/system/migrations/6.php @@ -1,3 +1,16 @@ hasColumn(TABLE_PREFIX . 'hooks', 'enabled')) - $db->query("ALTER TABLE `" . TABLE_PREFIX . "hooks` ADD `enabled` INT(1) NOT NULL DEFAULT 1;"); \ No newline at end of file +/** + * @var OTS_DB_MySQL $db + */ + +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'hooks', 'enabled')) { + $db->addColumn(TABLE_PREFIX . 'hooks', 'enabled', 'INT(1) NOT NULL DEFAULT 1'); + } +}; + +$down = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'hooks', 'enabled')) { + $db->dropColumn(TABLE_PREFIX . 'hooks', 'enabled'); + } +}; diff --git a/system/migrations/7.php b/system/migrations/7.php index a34f5a22..a96ed7c9 100644 --- a/system/migrations/7.php +++ b/system/migrations/7.php @@ -1,4 +1,16 @@ hasColumn(TABLE_PREFIX . 'screenshots', 'name')) - $db->query("ALTER TABLE `" . TABLE_PREFIX . "screenshots` DROP `name`;"); -?> \ No newline at end of file +/** + * @var OTS_DB_MySQL $db + */ + +$up = function () use ($db) { + if ($db->hasColumn(TABLE_PREFIX . 'screenshots', 'name')) { + $db->dropColumn(TABLE_PREFIX . 'screenshots', 'name'); + } +}; + +$up = function () use ($db) { + if (!$db->hasColumn(TABLE_PREFIX . 'screenshots', 'name')) { + $db->addColumn(TABLE_PREFIX . 'screenshots', 'name', 'VARCHAR(30) NOT NULL'); + } +}; diff --git a/system/migrations/8.php b/system/migrations/8.php index 4785e23b..54e9db9d 100644 --- a/system/migrations/8.php +++ b/system/migrations/8.php @@ -1,17 +1,31 @@ hasTable(TABLE_PREFIX . 'forum_sections')) - $db->query('RENAME TABLE `' . TABLE_PREFIX . 'forum_sections` TO `' . TABLE_PREFIX . 'forum_boards`;'); - +/** + * @var OTS_DB_MySQL $db + */ + +$up = function () use ($db) { + if ($db->hasTable(TABLE_PREFIX . 'forum_sections')) { + $db->renameTable(TABLE_PREFIX . 'forum_sections', TABLE_PREFIX . 'forum_boards'); + } + $query = $db->query('SELECT `id` FROM `' . TABLE_PREFIX . 'forum_boards` WHERE `ordering` > 0;'); - if($query->rowCount() == 0) { - $boards = array( + if ($query->rowCount() == 0) { + $boards = [ 'News', 'Trade', 'Quests', 'Pictures', 'Bug Report' - ); - - foreach($boards as $id => $board) + ]; + + foreach ($boards as $id => $board) { $db->query('UPDATE `' . TABLE_PREFIX . 'forum_boards` SET `ordering` = ' . $id . ' WHERE `name` = ' . $db->quote($board)); - } \ No newline at end of file + } + } +}; + +$down = function () use ($db) { + if ($db->hasTable(TABLE_PREFIX . 'forum_boards')) { + $db->renameTable(TABLE_PREFIX . 'forum_boards', TABLE_PREFIX . 'forum_sections'); + } +}; diff --git a/system/migrations/9.php b/system/migrations/9.php index d4869c10..c0db4971 100644 --- a/system/migrations/9.php +++ b/system/migrations/9.php @@ -1,9 +1,18 @@ query("ALTER TABLE `" . TABLE_PREFIX . "bugtracker` MODIFY `type` INT(11) NOT NULL DEFAULT 0;"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "bugtracker` MODIFY `status` INT(11) NOT NULL DEFAULT 0;"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "bugtracker` MODIFY `id` INT(11) NOT NULL DEFAULT 0;"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "bugtracker` MODIFY `subject` VARCHAR(255) NOT NULL DEFAULT '';"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "bugtracker` MODIFY `reply` INT(11) NOT NULL DEFAULT 0;"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "bugtracker` MODIFY `who` INT(11) NOT NULL DEFAULT 0;"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "bugtracker` MODIFY `tag` INT(11) NOT NULL DEFAULT 0;"); -?> \ No newline at end of file +/** + * @var OTS_DB_MySQL $db + */ + +$up = function () use ($db) { + $db->modifyColumn(TABLE_PREFIX . 'bugtracker', 'type', "INT(11) NOT NULL DEFAULT 0"); + $db->modifyColumn(TABLE_PREFIX . 'bugtracker', 'status', "INT(11) NOT NULL DEFAULT 0"); + $db->modifyColumn(TABLE_PREFIX . 'bugtracker', 'id', "INT(11) NOT NULL DEFAULT 0"); + $db->modifyColumn(TABLE_PREFIX . 'bugtracker', 'subject', "VARCHAR(255) NOT NULL DEFAULT ''"); + $db->modifyColumn(TABLE_PREFIX . 'bugtracker', 'reply', "INT(11) NOT NULL DEFAULT 0"); + $db->modifyColumn(TABLE_PREFIX . 'bugtracker', 'who', "INT(11) NOT NULL DEFAULT 0"); + $db->modifyColumn(TABLE_PREFIX . 'bugtracker', 'tag', "INT(11) NOT NULL DEFAULT 0"); +}; + +$down = function () { + // nothing to do here +}; diff --git a/system/pages/account/characters/change-name.php b/system/pages/account/characters/change-name.php index 4a23131d..975369d1 100644 --- a/system/pages/account/characters/change-name.php +++ b/system/pages/account/characters/change-name.php @@ -40,8 +40,13 @@ else if(empty($errors)) { - if(!admin() && !Validator::newCharacterName($name)) + if(!Validator::characterName($name)) { $errors[] = Validator::getLastError(); + } + + if(!admin() && !Validator::newCharacterName($name)) { + $errors[] = Validator::getLastError(); + } } if(empty($errors)) { diff --git a/system/pages/account/create.php b/system/pages/account/create.php index 0074f9e3..af427d37 100644 --- a/system/pages/account/create.php +++ b/system/pages/account/create.php @@ -148,6 +148,10 @@ if($save) } } + /** + * two hooks for compatibility + */ + $hooks->trigger(HOOK_ACCOUNT_CREATE_AFTER_SUBMIT, $params); if (!$hooks->trigger(HOOK_ACCOUNT_CREATE_POST, $params)) { return; } @@ -187,6 +191,8 @@ if($save) $new_account->setEMail($email); $new_account->save(); + $hooks->trigger(HOOK_ACCOUNT_CREATE_AFTER_SAVED, ['account' => $new_account]); + if(USE_ACCOUNT_SALT) $new_account->setCustomField('salt', $salt); @@ -325,7 +331,7 @@ if(setting('core.account_country_recognize')) { $country_recognized = $country_session; } else { - $info = json_decode(@file_get_contents('http://ipinfo.io/' . $_SERVER['REMOTE_ADDR'] . '/geo'), true); + $info = json_decode(@file_get_contents('http://ipinfo.io/' . get_browser_real_ip() . '/geo'), true); if(isset($info['country'])) { $country_recognized = strtolower($info['country']); setSession('country', $country_recognized); diff --git a/system/pages/account/login.php b/system/pages/account/login.php index 0fce795d..3e8ebba3 100644 --- a/system/pages/account/login.php +++ b/system/pages/account/login.php @@ -8,6 +8,9 @@ * @copyright 2023 MyAAC * @link https://my-aac.org */ + +use MyAAC\RateLimit; + defined('MYAAC') or die('Direct access not allowed!'); // new login with data from form @@ -18,30 +21,13 @@ if($logged || !isset($_POST['account_login']) || !isset($_POST['password_login'] $login_account = $_POST['account_login']; $login_password = $_POST['password_login']; $remember_me = isset($_POST['remember_me']); +$ip = get_browser_real_ip(); if(!empty($login_account) && !empty($login_password)) { - if($cache->enabled()) - { - $tmp = ''; - if($cache->fetch('failed_logins', $tmp)) - { - $tmp = unserialize($tmp); - $to_remove = array(); - foreach($tmp as $ip => $t) - { - if(time() - $t['last'] >= 5 * 60) - $to_remove[] = $ip; - } - foreach($to_remove as $ip) - unset($tmp[$ip]); - } - else - $tmp = array(); - - $ip = $_SERVER['REMOTE_ADDR']; - $t = $tmp[$ip] ?? null; - } + $limiter = new RateLimit('failed_logins', setting('core.account_login_attempts_limit'), setting('core.account_login_ban_time')); + $limiter->enabled = setting('core.account_login_ipban_protection'); + $limiter->load(); $account_logged = new OTS_Account(); if (config('account_login_by_email')) { @@ -56,14 +42,12 @@ if(!empty($login_account) && !empty($login_password)) } } - if($account_logged->isLoaded() && encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $login_password) == $account_logged->getPassword() - && (!isset($t) || $t['attempts'] < 5) + if($account_logged->isLoaded() && encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $login_password) == $account_logged->getPassword() && (!$limiter->enabled || !$limiter->exceeded($ip)) ) { if (setting('core.account_mail_verify') && (int)$account_logged->getCustomField('email_verified') !== 1) { $errors[] = 'Your account is not verified. Please verify your email address. If the message is not coming check the SPAM folder in your E-Mail client.'; - } - else { + } else { session_regenerate_id(); setSession('account', $account_logged->getId()); setSession('password', encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $login_password)); @@ -87,38 +71,21 @@ if(!empty($login_account) && !empty($login_password)) $hooks->trigger(HOOK_LOGIN, array('account' => $account_logged, 'password' => $login_password, 'remember_me' => $remember_me)); } + + $limiter->reset($ip); } else { $hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me)); $errorMessage = getAccountLoginByLabel() . ' or password is not correct.'; - - // temporary solution for blocking failed login attempts - if($cache->enabled()) - { - if(isset($t)) - { - $t['attempts']++; - $t['last'] = time(); - - if($t['attempts'] >= 5) - $errors[] = 'A wrong password has been entered 5 times in a row. You are unable to log into your account for the next 5 minutes. Please wait.'; - else - $errors[] = $errorMessage; - } - else - { - $t = array('attempts' => 1, 'last' => time()); - $errors[] = $errorMessage; - } - - $tmp[$ip] = $t; - $cache->set('failed_logins', serialize($tmp), 60 * 60); // save for 1 hour - } - else { - $errors[] = $errorMessage; + $limiter->increment($ip); + if ($limiter->exceeded($ip)) { + $errorMessage = 'A wrong password has been entered ' . $limiter->max_attempts . ' times in a row. You are unable to log into your account for the next ' . $limiter->ttl . ' minutes. Please wait.'; } + + $errors[] = $errorMessage; + } } else { diff --git a/system/pages/forum/new_thread.php b/system/pages/forum/new_thread.php index 7a66ac27..d10e7a11 100644 --- a/system/pages/forum/new_thread.php +++ b/system/pages/forum/new_thread.php @@ -95,7 +95,7 @@ if(Forum::canPost($account_logged)) { if (count($errors) == 0) { $saved = true; - $db->query("INSERT INTO `" . FORUM_TABLE_PREFIX . "forum` (`first_post` ,`last_post` ,`section` ,`replies` ,`views` ,`author_aid` ,`author_guid` ,`post_text` ,`post_topic` ,`post_smile`, `post_html` ,`post_date` ,`last_edit_aid` ,`edit_date`, `post_ip`) VALUES ('0', '" . time() . "', '" . (int)$section_id . "', '0', '0', '" . $account_logged->getId() . "', '" . $char_id . "', " . $db->quote($text) . ", " . $db->quote($post_topic) . ", '" . $smile . "', '" . $html . "', '" . time() . "', '0', '0', '" . $_SERVER['REMOTE_ADDR'] . "')"); + $db->query("INSERT INTO `" . FORUM_TABLE_PREFIX . "forum` (`first_post` ,`last_post` ,`section` ,`replies` ,`views` ,`author_aid` ,`author_guid` ,`post_text` ,`post_topic` ,`post_smile`, `post_html` ,`post_date` ,`last_edit_aid` ,`edit_date`, `post_ip`) VALUES ('0', '" . time() . "', '" . (int)$section_id . "', '0', '0', '" . $account_logged->getId() . "', '" . $char_id . "', " . $db->quote($text) . ", " . $db->quote($post_topic) . ", '" . $smile . "', '" . $html . "', '" . time() . "', '0', '0', '" . get_browser_real_ip() . "')"); $thread_id = $db->lastInsertId(); diff --git a/system/pages/forum/show_board.php b/system/pages/forum/show_board.php index 5d61690a..0b192dfc 100644 --- a/system/pages/forum/show_board.php +++ b/system/pages/forum/show_board.php @@ -44,7 +44,7 @@ for($i = 0; $i < $threads_count['threads_count'] / setting('core.forum_threads_p echo 'Boards >> '.$sections[$section_id]['name'].''; -if(!$sections[$section_id]['closed'] || Forum::isModerator()) { +if($logged && (!$sections[$section_id]['closed'] || Forum::isModerator())) { echo '

'; } @@ -94,7 +94,7 @@ if(isset($last_threads[0])) { } echo ''; - if(!$sections[$section_id]['closed'] || Forum::isModerator()) { + if($logged && (!$sections[$section_id]['closed'] || Forum::isModerator())) { echo '
'; } } diff --git a/system/pages/highscores.php b/system/pages/highscores.php index 0e5662e1..d7eb7384 100644 --- a/system/pages/highscores.php +++ b/system/pages/highscores.php @@ -31,20 +31,22 @@ if(!is_numeric($page) || $page < 1 || $page > PHP_INT_MAX) { $query = Player::query(); -$settingHighscoresVocationBox = setting('core.highscores_vocation_box'); $configVocations = config('vocations'); $configVocationsAmount = config('vocations_amount'); -if($settingHighscoresVocationBox && $vocation !== 'all') -{ +$vocationId = null; +if($vocation !== 'all') { foreach($configVocations as $id => $name) { if(strtolower($name) == $vocation) { - $add_vocs = array($id); + $vocationId = $id; + $add_vocs = [$id]; - $i = $id + $configVocationsAmount; - while(isset($configVocations[$i])) { - $add_vocs[] = $i; - $i += $configVocationsAmount; + if ($id !== 0) { + $i = $id + $configVocationsAmount; + while (isset($configVocations[$i])) { + $add_vocs[] = $i; + $i += $configVocationsAmount; + } } $query->whereIn('players.vocation', $add_vocs); @@ -175,12 +177,12 @@ if (empty($highscores)) { $query ->join('player_skills', 'player_skills.player_id', '=', 'players.id') ->where('skillid', $skill) - ->addSelect('player_skills.skillid as value'); + ->addSelect('player_skills.value as value'); } } else if ($skill == SKILL_FRAGS) // frags { if ($db->hasTable('player_killers')) { - $query->addSelect(['value' => PlayerKillers::where('player_killers.player_id', 'players.id')->selectRaw('COUNT(*)')]); + $query->addSelect(['value' => PlayerKillers::whereColumn('player_killers.player_id', 'players.id')->selectRaw('COUNT(*)')]); } else { $query->addSelect(['value' => PlayerDeath::unjustified()->whereColumn('player_deaths.killed_by', 'players.name')->selectRaw('COUNT(*)')]); } @@ -287,6 +289,7 @@ $twig->display('highscores.html.twig', [ 'skillName' => ($skill == SKILL_FRAGS ? 'Frags' : ($skill == SKILL_BALANCE ? 'Balance' : getSkillName($skill))), 'levelName' => ($skill != SKILL_FRAGS && $skill != SKILL_BALANCE ? 'Level' : ($skill == SKILL_BALANCE ? 'Balance' : 'Frags')), 'vocation' => $vocation !== 'all' ? $vocation : null, + 'vocationId' => $vocationId, 'types' => $types, 'linkPreviousPage' => $linkPreviousPage, 'linkNextPage' => $linkNextPage, diff --git a/system/pages/monsters.php b/system/pages/monsters.php index 988d15b5..1678291e 100644 --- a/system/pages/monsters.php +++ b/system/pages/monsters.php @@ -62,7 +62,9 @@ if ($monsterModel && isset($monsterModel->name)) { $elements = json_decode($monster['elements'], true); $immunities = json_decode($monster['immunities'], true); $loot = json_decode($monster['loot'], true); - usort($loot, 'sort_by_chance'); + if (!empty($loot)) { + usort($loot, 'sort_by_chance'); + } foreach ($loot as &$item) { $item['name'] = getItemNameById($item['id']); diff --git a/system/pages/online.php b/system/pages/online.php index 77f01a2a..4f0baa7d 100644 --- a/system/pages/online.php +++ b/system/pages/online.php @@ -50,8 +50,8 @@ if (setting('core.online_outfit')) { } } +$vocs = []; if (setting('core.online_vocations')) { - $vocs = array(); foreach($config['vocations'] as $id => $name) { $vocs[$id] = 0; } @@ -100,7 +100,7 @@ foreach($playersOnline as $player) { } $record = ''; -if($players > 0) { +if(count($players_data) > 0) { if( setting('core.online_record')) { $result = null; $timestamp = false; @@ -114,7 +114,7 @@ if($players > 0) { } } - if($record) { + if($result) { $record = 'The maximum on this game world was ' . $result['record'] . ' players' . ($timestamp ? ' on ' . date("M d Y, H:i:s", $result['timestamp']) . '.' : '.'); } } @@ -122,7 +122,8 @@ if($players > 0) { $twig->display('online.html.twig', array( 'players' => $players_data, - 'record' => $record + 'record' => $record, + 'vocs' => $vocs, )); //search bar diff --git a/system/router.php b/system/router.php index 0a5ed7f8..5b103a90 100644 --- a/system/router.php +++ b/system/router.php @@ -279,7 +279,7 @@ else { $uri = str_replace_first('/', '', $uri); } - $page = $uri; + $page = str_replace('index.php/', '', $uri); if (empty($page)) { $page = 'news'; } diff --git a/system/settings.php b/system/settings.php index a7f1b53c..89028cf7 100644 --- a/system/settings.php +++ b/system/settings.php @@ -15,8 +15,7 @@ use MyAAC\Settings; return [ 'name' => 'MyAAC', - 'settings' => - [ + 'settings' => [ [ 'type' => 'category', 'title' => 'General' @@ -233,15 +232,14 @@ return [ 'name' => 'Client Version', 'type' => 'options', 'options' => '$clients', - 'desc' => 'what client version are you using on this OT?
used for the Downloads page and some templates aswell', + 'desc' => 'what client version are you using on this OT?
used for the Downloads page and some templates as well', 'default' => 710 ], 'towns' => [ 'name' => 'Towns', 'type' => 'textarea', - 'desc' => "if you use TFS 1.3 with support for 'towns' table in database, then you can ignore this - it will be configured automatically (from MySQL database - Table - towns)
" . - "otherwise it will try to load from your .OTBM map file
" . - "if you don't see towns on website, then you need to fill this out", + 'desc' => "If you use TFS 1.3+ with support for 'towns' table in database, then you can ignore this - it will be automatically configured from there.
" . + "If you don't see towns on website, then you need to fill this out", 'default' => "0=No Town\n1=Sample Town", 'callbacks' => [ 'get' => function ($value) { @@ -394,6 +392,13 @@ return [ 'default' => false, 'is_config' => true, ], + 'database_auto_migrate' => [ + 'name' => 'Database Auto Migrate', + 'desc' => 'Migrate database to latest version in myaac, automatically.', + 'type' => 'boolean', + 'default' => true, + 'is_config' => true, + ], [ 'type' => 'category', 'title' => 'Mailing', @@ -1374,7 +1379,7 @@ Sent by MyAAC,
'name' => 'Item Images URL', 'type' => 'text', 'desc' => 'Set to images/items if you host your own items in images folder', - 'default' => 'http://item-images.ots.me/1092/', + 'default' => 'https://item-images.ots.me/1092/', ], 'item_images_extension' => [ 'name' => 'Item Images File Extension', @@ -1390,7 +1395,7 @@ Sent by MyAAC,
'name' => 'Outfit Images URL', 'type' => 'text', 'desc' => 'Set to animoutfit.php for animated outfit', - 'default' => 'http://outfit-images.ots.me/outfit.php', + 'default' => 'https://outfit-images.ots.me/outfit.php', ], 'outfit_images_wrong_looktypes' => [ 'name' => 'Outfit Images Wrong Looktypes', @@ -1590,6 +1595,34 @@ Sent by MyAAC,
'account_change_character_sex', '=', 'true', ], ], + [ + 'type' => 'category', + 'title' => 'Security', + ], + [ + 'type' => 'section', + 'title' => 'IP Ban Protection', + ], + 'account_login_ipban_protection' => [ + 'name' => 'IP Ban Protection', + 'type' => 'boolean', + 'desc' => 'Activate IP ban protection after exceeding incorrect login attempts', + 'default' => true, + ], + + 'account_login_attempts_limit' => [ + 'name' => 'Login Attempts Limit', + 'type' => 'number', + 'desc' => 'Number of incorrect login attempts before banning the IP', + 'default' => 5, // Ajuste conforme necessário + ], + + 'account_login_ban_time' => [ + 'name' => 'Ban Time (Minutes)', + 'type' => 'number', + 'desc' => 'Time in minutes the IP will be banned after exceeding login attempts', + 'default' => 30, // Ajuste conforme necessário + ], ], 'callbacks' => [ 'beforeSave' => function(&$settings, &$values) { @@ -1658,6 +1691,6 @@ Sent by MyAAC,
return $success; }, - ], + ] ]; diff --git a/system/src/Cache.php b/system/src/Cache.php new file mode 100644 index 00000000..42ca597f --- /dev/null +++ b/system/src/Cache.php @@ -0,0 +1,5 @@ +trigger(HOOK_CRONJOB, ['scheduler' => $scheduler]); // Let the scheduler execute jobs which are due. diff --git a/system/src/Commands/CronjobInstallCommand.php b/system/src/Commands/CronjobInstallCommand.php index adcf8b20..d6b9ee60 100644 --- a/system/src/Commands/CronjobInstallCommand.php +++ b/system/src/Commands/CronjobInstallCommand.php @@ -17,6 +17,8 @@ class CronjobInstallCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { + require SYSTEM . 'init.php'; + $io = new SymfonyStyle($input, $output); if (MYAAC_OS !== 'LINUX') { diff --git a/system/src/Commands/MailSendCommand.php b/system/src/Commands/MailSendCommand.php index d0db7b69..ff1450e6 100644 --- a/system/src/Commands/MailSendCommand.php +++ b/system/src/Commands/MailSendCommand.php @@ -21,8 +21,15 @@ class MailSendCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { + require SYSTEM . 'init.php'; + $io = new SymfonyStyle($input, $output); + if (!setting('core.mail_enabled')) { + $io->error('Mailing is not enabled on this server'); + return Command::FAILURE; + } + $email_account_name = $input->getArgument('recipient'); $subject = $input->getOption('subject'); if (!$subject) { diff --git a/system/src/Commands/MigrateCommand.php b/system/src/Commands/MigrateCommand.php new file mode 100644 index 00000000..a8a21016 --- /dev/null +++ b/system/src/Commands/MigrateCommand.php @@ -0,0 +1,28 @@ +setName('migrate') + ->setDescription('This command updates the AAC to latest migration'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + require SYSTEM . 'init.php'; + + $io = new SymfonyStyle($input, $output); + require SYSTEM . 'migrate.php'; + + $io->success('Migrated to latest version (' . DATABASE_VERSION . ')'); + return Command::SUCCESS; + } +} diff --git a/system/src/Commands/MigrateRunCommand.php b/system/src/Commands/MigrateRunCommand.php index ee0265b3..edfa108d 100644 --- a/system/src/Commands/MigrateRunCommand.php +++ b/system/src/Commands/MigrateRunCommand.php @@ -21,6 +21,8 @@ class MigrateRunCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { + require SYSTEM . 'init.php'; + $io = new SymfonyStyle($input, $output); $ids = $input->getArgument('id'); diff --git a/system/src/Commands/MigrateToCommand.php b/system/src/Commands/MigrateToCommand.php new file mode 100644 index 00000000..b82012ed --- /dev/null +++ b/system/src/Commands/MigrateToCommand.php @@ -0,0 +1,108 @@ +setName('migrate:to') + ->setDescription('This command migrates to specific version of database') + ->addArgument('version', + InputArgument::REQUIRED, + 'Version number' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $versionDest = $input->getArgument('version'); + + if (!$versionDest || $versionDest > DATABASE_VERSION || $versionDest < 1) { + $io->error('Please enter a valid version number'); + return Command::FAILURE; + } + + $this->initEnv(); + + $currentVersion = Config::where('name', 'database_version')->first()->value; + if ($currentVersion > $versionDest) { + // downgrade + for ($i = $currentVersion; $i > $versionDest; $i--) { + echo $i . ' '; + $this->executeMigration($i, false); + } + } + else if ($currentVersion < $versionDest) { + // upgrade + for ($i = $currentVersion + 1; $i <= $versionDest; $i++) { + echo $i . ' '; + $this->executeMigration($i, true); + } + } + else { + $io->success('Nothing to be done'); + return Command::SUCCESS; + } + + $upgrade = ($currentVersion < $versionDest ? 'Upgrade' : 'Downgrade'); + $io->success("Migration ({$upgrade}) to version {$versionDest} has been completed"); + + return Command::SUCCESS; + } + + private function executeMigration($id, $_up): void + { + global $db; + + $db->revalidateCache(); + + require SYSTEM . 'migrations/' . $id . '.php'; + if ($_up) { + if (isset($up)) { + $up(); + } + } + else { + if (isset($down)) { + $down(); + } + } + + updateDatabaseConfig('database_version', ($_up ? $id : $id - 1)); + } + + private function initEnv() + { + global $config; + if (!isset($config['installed']) || !$config['installed']) { + throw new \RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.'); + } + + if(empty($config['server_path'])) { + throw new \RuntimeException('Server Path has been not set. Go to config.php and set it.'); + } + + // take care of trailing slash at the end + if($config['server_path'][strlen($config['server_path']) - 1] !== '/') + $config['server_path'] .= '/'; + + $config['lua'] = load_config_lua($config['server_path'] . 'config.lua'); + + // POT + require_once SYSTEM . 'libs/pot/OTS.php'; + $ots = POT::getInstance(); + $eloquentConnection = null; + + require_once SYSTEM . 'database.php'; + } +} diff --git a/system/src/Commands/PluginInstallCommand.php b/system/src/Commands/PluginInstallCommand.php index f40961e7..a37c0859 100644 --- a/system/src/Commands/PluginInstallCommand.php +++ b/system/src/Commands/PluginInstallCommand.php @@ -14,14 +14,16 @@ class PluginInstallCommand extends Command { $this->setName('plugin:install') ->setDescription('This command installs plugin') - ->addArgument('plugin', InputArgument::REQUIRED, 'Path to zip file (plugin) that you want to install'); + ->addArgument('pathToPluginZip', InputArgument::REQUIRED, 'Path to zip file (plugin) that you want to install'); } protected function execute(InputInterface $input, OutputInterface $output): int { + require SYSTEM . 'init.php'; + $io = new SymfonyStyle($input, $output); - $pathToFile = $input->getArgument('plugin'); + $pathToFile = $input->getArgument('pathToPluginZip'); $ext = strtolower(pathinfo($pathToFile, PATHINFO_EXTENSION)); if($ext !== 'zip') {// check if it is zipped/compressed file diff --git a/system/src/Commands/PluginInstallInstallCommand.php b/system/src/Commands/PluginInstallInstallCommand.php index 5f1a1cd6..fe1b4f14 100644 --- a/system/src/Commands/PluginInstallInstallCommand.php +++ b/system/src/Commands/PluginInstallInstallCommand.php @@ -19,6 +19,8 @@ class PluginInstallInstallCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { + require SYSTEM . 'init.php'; + $io = new SymfonyStyle($input, $output); $pluginName = $input->getArgument('plugin'); diff --git a/system/src/Commands/SettingsResetCommand.php b/system/src/Commands/SettingsResetCommand.php index a495edf4..78748b00 100644 --- a/system/src/Commands/SettingsResetCommand.php +++ b/system/src/Commands/SettingsResetCommand.php @@ -14,23 +14,43 @@ class SettingsResetCommand extends Command protected function configure(): void { $this->setName('settings:reset') - ->setDescription('Removes all settings in database'); + ->setDescription('Removes settings in database') + ->addArgument('name', + InputArgument::OPTIONAL, + 'Name of the plugin' + ); } protected function execute(InputInterface $input, OutputInterface $output): int { + require SYSTEM . 'init.php'; + $io = new SymfonyStyle($input, $output); - if (!$io->confirm('Are you sure you want to reset all settings in database?', false)) { + $name = $input->getArgument('name'); + + $all = !$name ? 'all' : $name; + if (!$io->confirm("Are you sure you want to reset {$all} settings in database?", false)) { return Command::FAILURE; } - SettingsModel::truncate(); + if (!$name) { + SettingsModel::truncate(); + } + else { + $settingsModel = SettingsModel::where('name', $name)->first(); + if (!$settingsModel) { + $io->warning('No settings for this plugin saved in database'); + return Command::SUCCESS; + } + + SettingsModel::where('name', $name)->delete(); + } $settings = Settings::getInstance(); $settings->clearCache(); - $io->success('Setting cleared successfully'); + $io->success('Settings cleared successfully'); return Command::SUCCESS; } } diff --git a/system/src/Commands/SettingsSetCommand.php b/system/src/Commands/SettingsSetCommand.php index 1159689a..4ad33227 100644 --- a/system/src/Commands/SettingsSetCommand.php +++ b/system/src/Commands/SettingsSetCommand.php @@ -27,6 +27,8 @@ class SettingsSetCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { + require SYSTEM . 'init.php'; + $io = new SymfonyStyle($input, $output); $key = $input->getArgument('key'); diff --git a/system/src/CreateCharacter.php b/system/src/CreateCharacter.php index ea0d2c6c..3d3ae8ff 100644 --- a/system/src/CreateCharacter.php +++ b/system/src/CreateCharacter.php @@ -23,32 +23,8 @@ class CreateCharacter */ public function checkName($name, &$errors) { - $minLength = setting('core.create_character_name_min_length'); - $maxLength = setting('core.create_character_name_max_length'); - - if(empty($name)) { - $errors['name'] = 'Please enter a name for your character!'; - return false; - } - - if(strlen($name) > $maxLength) { - $errors['name'] = 'Name is too long. Max. length ' . $maxLength . ' letters.'; - return false; - } - - if(strlen($name) < $minLength) { - $errors['name'] = 'Name is too short. Min. length ' . $minLength . ' letters.'; - return false; - } - - $name_length = strlen($name); - if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- '") != $name_length) { - $errors['name'] = 'This name contains invalid letters, words or format. Please use only a-Z, - , \' and space.'; - return false; - } - - if(!preg_match("/[A-z ']/", $name)) { - $errors['name'] = 'Your name contains illegal characters.'; + if (!\Validator::characterName($name)) { + $errors['name'] = \Validator::getLastError(); return false; } @@ -267,7 +243,7 @@ class CreateCharacter [ 'account' => $account, 'player' => $player, - 'samplePlayer' => $playerSample, + 'playerSample' => $playerSample, 'name' => $name, 'sex' => $sex, 'vocation' => $vocation, diff --git a/system/src/DataLoader.php b/system/src/DataLoader.php index df2ba6e9..6dca0c24 100644 --- a/system/src/DataLoader.php +++ b/system/src/DataLoader.php @@ -25,6 +25,9 @@ namespace MyAAC; +use MyAAC\Cache\Cache; +use MyAAC\Models\Town; + class DataLoader { private static $locale; @@ -78,7 +81,11 @@ class DataLoader self::$startTime = microtime(true); - if (Towns::save()) { + $cache = Cache::getInstance(); + $cache->delete('towns'); // will be reloaded after next page load + + global $db; + if ($db->hasTable('towns') && Town::count() > 0) { success(self::$locale['step_database_loaded_towns'] . self::getLoadedTime()); } else { diff --git a/system/src/Forum.php b/system/src/Forum.php index ec9baee5..64b22222 100644 --- a/system/src/Forum.php +++ b/system/src/Forum.php @@ -72,7 +72,7 @@ class Forum 'post_smile' => 0, 'post_html' => 1, 'post_date' => time(), 'last_edit_aid' => 0, 'edit_date' => 0, - 'post_ip' => $_SERVER['REMOTE_ADDR'] + 'post_ip' => get_browser_real_ip() ))) { $thread_id = $db->lastInsertId(); $db->query("UPDATE `" . FORUM_TABLE_PREFIX . "forum` SET `first_post`=".(int) $thread_id." WHERE `id` = ".(int) $thread_id); @@ -94,7 +94,7 @@ class Forum 'post_smile' => $smile, 'post_html' => $html, 'post_date' => time(), - 'post_ip' => $_SERVER['REMOTE_ADDR'] + 'post_ip' => get_browser_real_ip() )); } public static function add_board($name, $description, $access, $guild, &$errors) diff --git a/system/src/Models/Forum.php b/system/src/Models/Forum.php new file mode 100644 index 00000000..20fe4dcd --- /dev/null +++ b/system/src/Models/Forum.php @@ -0,0 +1,30 @@ + 'integer', + 'last_post' => 'integer', + 'section' => 'integer', + 'replies' => 'integer', + 'views' => 'integer', + 'author_aid' => 'integer', + 'author_guid' => 'integer', + 'post_smile' => 'boolean', + 'post_html' => 'boolean', + 'post_date' => 'integer', + 'last_edit_aid' => 'integer', + 'edit_date' => 'integer', + 'sticked' => 'boolean', + 'closed' => 'boolean' + ]; +} diff --git a/system/src/Models/PlayerKillers.php b/system/src/Models/PlayerKillers.php index 55abbfd8..d0bd9fdc 100644 --- a/system/src/Models/PlayerKillers.php +++ b/system/src/Models/PlayerKillers.php @@ -5,7 +5,7 @@ use Illuminate\Database\Eloquent\Model; class PlayerKillers extends Model { - protected $table = 'players_killers'; + protected $table = 'player_killers'; public $timestamps = false; diff --git a/system/src/News.php b/system/src/News.php index 02923837..5ef7a086 100644 --- a/system/src/News.php +++ b/system/src/News.php @@ -37,17 +37,29 @@ class News if(!self::verify($title, $body, $article_text, $article_image, $errors)) return false; - ModelsNews::create([ - 'title' => $title, - 'body' => $body, - 'type' => $type, - 'date' => time(), - 'category' => $category, - 'player_id' => isset($player_id) ? $player_id : 0, + $currentTime = time(); + + $params = [ + 'title' => $title, 'body' => $body, + 'type' => $type, 'category' => $category, + 'date' => $currentTime, + 'player_id' => $player_id ?? 0, 'comments' => $comments, 'article_text' => ($type == 3 ? $article_text : ''), 'article_image' => ($type == 3 ? $article_image : '') - ]); + ]; + + global $hooks; + if (!$hooks->trigger(HOOK_ADMIN_NEWS_ADD_PRE, $params)) { + return false; + } + + $newsModel = ModelsNews::create($params); + + $hooks->trigger(HOOK_ADMIN_NEWS_ADD, + $params + ['id' => $newsModel->id], + ); + self::clearCache(); return true; } @@ -58,30 +70,55 @@ class News static public function update($id, $title, $body, $type, $category, $player_id, $comments, $article_text, $article_image, &$errors) { - if(!self::verify($title, $body, $article_text, $article_image, $errors)) + if(!self::verify($title, $body, $article_text, $article_image, $errors)) { return false; + } - ModelsNews::where('id', $id)->update([ - 'title' => $title, - 'body' => $body, - 'type' => $type, - 'category' => $category, - 'last_modified_by' => isset($player_id) ? $player_id : 0, - 'last_modified_date' => time(), + $currentTime = time(); + + $params = [ + 'id' => $id, + 'title' => $title, 'body' => $body, + 'type' => $type, 'category' => $category, + 'last_modified_by' => $player_id ?? 0, 'last_modified_date' => $currentTime, 'comments' => $comments, - 'article_text' => $article_text, - 'article_image' => $article_image - ]); + 'article_text' => ($type == 3 ? $article_text : ''), + 'article_image' => ($type == 3 ? $article_image : ''), + ]; + + global $hooks; + if (!$hooks->trigger(HOOK_ADMIN_NEWS_UPDATE_PRE, $params)) { + return false; + } + + unset($params['id']); + + ModelsNews::where('id', $id)->update($params); + + $hooks->trigger(HOOK_ADMIN_NEWS_UPDATE, + $params + ['id' => $id] + ); + self::clearCache(); return true; } static public function delete($id, &$errors) { + global $hooks; + if(isset($id)) { $row = ModelsNews::find($id); if($row) { - if (!$row->delete()) { + $params = ['id' => $id]; + + if (!$hooks->trigger(HOOK_ADMIN_NEWS_DELETE_PRE, $params)) { + return false; + } + + if ($row->delete()) { + $hooks->trigger(HOOK_ADMIN_NEWS_DELETE, $params); + } else { $errors[] = 'Fail during delete News.'; } } @@ -103,22 +140,35 @@ class News static public function toggleHide($id, &$errors, &$status) { - if(isset($id)) - { + global $hooks; + + if(isset($id)) { $row = ModelsNews::find($id); - if($row) - { - $row->hide = $row->hide == 1 ? 0 : 1; - if (!$row->save()) { + if($row) { + $row->hide = ($row->hide == 1 ? 0 : 1); + + $params = ['hide' => $row->hide]; + + if (!$hooks->trigger(HOOK_ADMIN_NEWS_TOGGLE_HIDE_PRE, $params)) { + return false; + } + + if ($row->save()) { + $hooks->trigger(HOOK_ADMIN_NEWS_TOGGLE_HIDE, $params); + } + else { $errors[] = 'Fail during toggle hide News.'; } + $status = $row->hide; } - else + else { $errors[] = 'News with id ' . $id . ' does not exists.'; + } } - else + else { $errors[] = 'News id not set.'; + } if(count($errors)) { return false; diff --git a/system/src/Plugins.php b/system/src/Plugins.php index fbaa5e40..243ced24 100644 --- a/system/src/Plugins.php +++ b/system/src/Plugins.php @@ -766,22 +766,23 @@ class Plugins { * Helper function for plugins * * @param string $templateName - * @param array $categories + * @param array $menus */ - public static function installMenus($templateName, $categories, $clearOld = true) + public static function installMenus($templateName, $menus, $clearOld = false) { global $db; - if (!$db->hasTable(TABLE_PREFIX . 'menu')) { - return; - } if ($clearOld) { Menu::where('template', $templateName)->delete(); } - foreach ($categories as $category => $menus) { + if (Menu::where('template', $templateName)->count()) { + return; + } + + foreach ($menus as $category => $_menus) { $i = 0; - foreach ($menus as $name => $link) { + foreach ($_menus as $name => $link) { $color = ''; $blank = 0; @@ -805,10 +806,14 @@ class Plugins { 'link' => $link, 'category' => $category, 'ordering' => $i++, - 'blank' => $blank, - 'color' => $color, ]; + // support for color and blank attributes + if($db->hasColumn(TABLE_PREFIX . 'menu', 'blank') && $db->hasColumn(TABLE_PREFIX . 'menu', 'color')) { + $insert_array['blank'] = $blank; + $insert_array['color'] = $color; + } + Menu::create($insert_array); } } diff --git a/system/src/RateLimit.php b/system/src/RateLimit.php new file mode 100644 index 00000000..df4349e5 --- /dev/null +++ b/system/src/RateLimit.php @@ -0,0 +1,118 @@ +key = $key; + $this->max_attempts = $max_attempts; + $this->ttl = $ttl; + } + + public function attempts(string $ip): int + { + if (!$this->enabled) { + return 0; + } + + if (isset($this->data[$ip]['attempts'])) { + return $this->data[$ip]['attempts']; + } + + return 0; + } + + public function exceeded(string $ip): bool { + if (!$this->enabled) { + return false; + } + + return $this->attempts($ip) >= $this->max_attempts; + } + + public function increment(string $ip): bool + { + global $cache; + if ($this->enabled && $cache->enabled()) { + if (isset($this->data[$ip]['attempts']) && isset($this->data[$ip]['last'])) { + $this->data[$ip]['attempts']++; + $this->data[$ip]['last'] = time(); + } else { + $this->data[$ip] = [ + 'attempts' => 1, + 'last' => time(), + ]; + } + + $this->save(); + } + + return false; + } + + public function reset(string $ip): void + { + if (!$this->enabled) { + return; + } + + if (isset($this->data[$ip])) { + unset($this->data[$ip]); + } + + $this->save(); + } + + public function save(): void + { + global $cache; + if (!$this->enabled || !$cache->enabled()) { + return; + } + + $data = $this->data; + $cache->set($this->key, serialize($data), $this->ttl * 60); + } + + public function load(): void + { + global $cache; + if (!$this->enabled) { + return; + } + + $data = []; + if ($cache->enabled()) { + $tmp = ''; + if ($cache->fetch($this->key, $tmp)) { + $data = unserialize($tmp); + $to_remove = []; + foreach ($data as $ip => $t) { + if (time() - $t['last'] >= ($this->ttl * 60)) { + $to_remove[] = $ip; + } + } + + if (count($to_remove)) { + foreach ($to_remove as $ip) { + unset($data[$ip]); + } + + $this->save(); + } + } + } + + $this->data = $data; + } +} diff --git a/system/src/Towns.php b/system/src/Towns.php deleted file mode 100644 index 6b02d41b..00000000 --- a/system/src/Towns.php +++ /dev/null @@ -1,129 +0,0 @@ - - * @copyright 2020 MyAAC - * @link https://my-aac.org - */ - -namespace MyAAC; - -use MyAAC\Models\Town; - -class Towns -{ - /** - * @var string - */ - private static $filename = CACHE . 'persistent/' . 'towns.php'; - - /** - * Determine towns - * - * @return array - */ - public static function determine() - { - global $db; - - if($db->hasTable('towns')) { - return self::getFromDatabase(); - } - - return self::getFromOTBM(); - } - - /** - * Load cached towns file - */ - public static function load() - { - $towns = config('towns'); - if (file_exists(self::$filename)) { - $towns = require self::$filename; - } - - config(['towns', $towns]); - } - - /** - * Save into cache file - * - * @return bool - */ - public static function save() - { - $towns = self::determine(); - if (count($towns) > 0) { - file_put_contents(self::$filename, 'load(); - - $towns = $townsReader->get(); - } - - return $towns; - } - - /** - * Load from database - * - * @return array - */ - public static function getFromDatabase() - { - return Town::orderBy('id', 'ASC')->pluck('name', 'id')->toArray(); - } -} diff --git a/system/src/TownsReader.php b/system/src/TownsReader.php deleted file mode 100644 index b1323c31..00000000 --- a/system/src/TownsReader.php +++ /dev/null @@ -1,84 +0,0 @@ -file = fopen($file, 'rb'); - } - - public function load() - { - // checks if file is opened correctly - if ($this->file) { - // skips version - fseek($this->file, 4); - - // reads nodes chain - while (!feof($this->file)) { - // reads byte - switch (ord(fgetc($this->file))) { - // maybe a town node - case self::NODE_START: - // reads node type - if (ord(fgetc($this->file)) == self::OTBM_TOWN) { - $id = unpack('L', fread($this->file, 4)); - $length = unpack('S', fread($this->file, 2)); - - // reads town name - $this->towns[$id[1]] = fread($this->file, $length[1]); - } - break; - - // escape next character - it might be NODE_START character which is in fact not - case self::ESCAPE_CHAR: - fgetc($this->file); - break; - } - } - } - } - - public function get() { - return $this->towns; - } -} diff --git a/system/src/Validator.php b/system/src/Validator.php index 04c9b340..ad9e3e50 100644 --- a/system/src/Validator.php +++ b/system/src/Validator.php @@ -178,8 +178,7 @@ class Validator */ public static function characterName($name) { - if(!isset($name[0])) - { + if(empty($name)) { self::$lastError = 'Please enter character name.'; return false; } @@ -250,7 +249,7 @@ class Validator } } - if(substr($name_lower, -1) == "'" || substr($name_lower, -1) == "-") { + if(str_ends_with($name_lower, "'") || str_ends_with($name_lower, "-")) { self::$lastError = 'Your name contains illegal characters.'; return false; } @@ -285,7 +284,7 @@ class Validator $words_blocked = array_merge(['--', "''","' ", " '", '- ', ' -', "-'", "'-"], setting('core.create_character_name_blocked_words')); foreach($words_blocked as $word) { - if(!(strpos($name_lower, $word) === false)) { + if(str_contains($name_lower, $word)) { self::$lastError = 'Your name contains illegal words.'; return false; } @@ -335,7 +334,7 @@ class Validator NPCs::load(); if(NPCs::$npcs) { foreach (NPCs::$npcs as $npc) { - if(strpos($name_lower, $npc) !== false) { + if(str_contains($name_lower, $npc)) { self::$lastError = 'Your name cannot contains NPC name.'; return false; } diff --git a/system/src/Visitors.php b/system/src/Visitors.php index 32220c6a..9968a214 100644 --- a/system/src/Visitors.php +++ b/system/src/Visitors.php @@ -37,7 +37,7 @@ class Visitors $this->sessionTime = $sessionTime; $this->cleanVisitors(); - $ip = $_SERVER['REMOTE_ADDR']; + $ip = get_browser_real_ip(); $userAgentShortened = substr($_SERVER['HTTP_USER_AGENT'] ?? 'unknown', 0, 255); if($this->visitorExists($ip)) diff --git a/system/src/global.php b/system/src/global.php index d4bd0cc4..d5c54fd8 100644 --- a/system/src/global.php +++ b/system/src/global.php @@ -45,6 +45,12 @@ define('HOOK_ACCOUNT_CREATE_AFTER_TOWNS', ++$i); define('HOOK_ACCOUNT_CREATE_BEFORE_SUBMIT_BUTTON', ++$i); define('HOOK_ACCOUNT_CREATE_AFTER_FORM', ++$i); define('HOOK_ACCOUNT_CREATE_POST', ++$i); +define('HOOK_ACCOUNT_CREATE_AFTER_SUBMIT', ++$i); +define('HOOK_ACCOUNT_CREATE_AFTER_SAVED', ++$i); +define('HOOK_ACCOUNT_MANAGE_BEFORE_GENERAL_INFORMATION', ++$i); +define('HOOK_ACCOUNT_MANAGE_BEFORE_PUBLIC_INFORMATION', ++$i); +define('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS', ++$i); +define('HOOK_ACCOUNT_MANAGE_BEFORE_CHARACTERS', ++$i); define('HOOK_ACCOUNT_LOGIN_BEFORE_PAGE', ++$i); define('HOOK_ACCOUNT_LOGIN_BEFORE_ACCOUNT', ++$i); define('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT', ++$i); @@ -65,6 +71,14 @@ define('HOOK_ADMIN_BODY_START', ++$i); define('HOOK_ADMIN_BODY_END', ++$i); define('HOOK_ADMIN_BEFORE_PAGE', ++$i); define('HOOK_ADMIN_MENU', ++$i); +define('HOOK_ADMIN_NEWS_ADD_PRE', ++$i); +define('HOOK_ADMIN_NEWS_ADD', ++$i); +define('HOOK_ADMIN_NEWS_UPDATE_PRE', ++$i); +define('HOOK_ADMIN_NEWS_UPDATE', ++$i); +define('HOOK_ADMIN_NEWS_DELETE_PRE', ++$i); +define('HOOK_ADMIN_NEWS_DELETE', ++$i); +define('HOOK_ADMIN_NEWS_TOGGLE_HIDE_PRE', ++$i); +define('HOOK_ADMIN_NEWS_TOGGLE_HIDE', ++$i); define('HOOK_ADMIN_LOGIN_AFTER_ACCOUNT', ++$i); define('HOOK_ADMIN_LOGIN_AFTER_PASSWORD', ++$i); define('HOOK_ADMIN_LOGIN_AFTER_SIGN_IN', ++$i); diff --git a/system/status.php b/system/status.php index ee8b4317..835f204d 100644 --- a/system/status.php +++ b/system/status.php @@ -142,10 +142,14 @@ function updateStatus() { } } - $status['uptime'] = $serverStatus->getUptime(); - $h = floor($status['uptime'] / 3600); - $m = floor(($status['uptime'] - $h * 3600) / 60); - $status['uptimeReadable'] = $h . 'h ' . $m . 'm'; + $uptime = $status['uptime'] = $serverStatus->getUptime(); + $m = date('m', $uptime); + $m = $m > 1 ? "$m months, " : ($m == 1 ? 'month, ' : ''); + $d = date('d', $uptime); + $d = $d > 1 ? "$d days, " : ($d == 1 ? 'day, ' : ''); + $h = date('H', $uptime); + $min = date('i', $uptime); + $status['uptimeReadable'] = "{$m}{$d}{$h}h {$min}m"; $status['monsters'] = $serverStatus->getMonstersCount(); $status['motd'] = $serverStatus->getMOTD(); diff --git a/system/templates/account.change-password.html.twig b/system/templates/account.change-password.html.twig index 56e52c08..318d393f 100644 --- a/system/templates/account.change-password.html.twig +++ b/system/templates/account.change-password.html.twig @@ -4,6 +4,14 @@ Please enter your current password and a new password. For your security, please {% set background = config('darkborder') %} {% set content %} + + + + - - - -
+ Current Password: + + +
New Password: @@ -20,14 +28,6 @@ Please enter your current password and a new password. For your security, please
- Current Password: - - -
{% endset %} {% include 'tables.headline.html.twig' %} diff --git a/system/templates/account.management.html.twig b/system/templates/account.management.html.twig index db8c766f..2db1e57c 100644 --- a/system/templates/account.management.html.twig +++ b/system/templates/account.management.html.twig @@ -88,6 +88,7 @@


{% endif %} + {{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_GENERAL_INFORMATION') }}

General Information

@@ -127,6 +128,7 @@ {% endautoescape %}

+ {{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_PUBLIC_INFORMATION') }}

Public Information

@@ -145,8 +147,9 @@ {% include('buttons.base.html.twig') %}
+ {{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS') }} -

Action Log

+

Account Logs

@@ -164,6 +167,7 @@ {% endautoescape %}
ActionDateIP

+ {{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_CHARACTERS') }}

Character list: {{ players|length }} characters.

diff --git a/system/templates/admin.plugins.form.html.twig b/system/templates/admin.plugins.form.html.twig index 3a049184..aec82a8a 100644 --- a/system/templates/admin.plugins.form.html.twig +++ b/system/templates/admin.plugins.form.html.twig @@ -14,7 +14,7 @@ diff --git a/system/templates/highscores.html.twig b/system/templates/highscores.html.twig index 8a2c78a6..938220e5 100644 --- a/system/templates/highscores.html.twig +++ b/system/templates/highscores.html.twig @@ -7,21 +7,21 @@ @@ -119,7 +119,7 @@ diff --git a/system/templates/install.admin.html.twig b/system/templates/install.admin.html.twig index a3a306a8..f6ef2e7b 100644 --- a/system/templates/install.admin.html.twig +++ b/system/templates/install.admin.html.twig @@ -9,7 +9,13 @@ - {% for value in ['email', 'account', 'password', 'password_confirm', 'player_name'] %} + {% set values = ['email', account, 'password', 'password_confirm'] %} + + {% if hasTablePlayers %} + {% set values = values|merge(['player_name']) %} + {% endif %} + + {% for value in values %}
diff --git a/system/templates/online.html.twig b/system/templates/online.html.twig index b2090327..0210d80f 100644 --- a/system/templates/online.html.twig +++ b/system/templates/online.html.twig @@ -23,6 +23,9 @@ Currently {{ players|length }} players are online.
{% endif %} {% endif %} + {% if setting('core.online_record') %} + {{ record }} + {% endif %}
Filters - - {% set i = 0 %} {% for link, name in types %} - + {% endfor %} - {% set i = 0 %} - {% for i in 1..config.vocations_amount %} - + {% for i in 0..config.vocations_amount %} + {% endfor %}
[ALL]
- {% for i in 1..config.vocations_amount %} + {% for i in 0..config.vocations_amount %} {{ config.vocations[i]}}
{% endfor %}
diff --git a/system/twig.php b/system/twig.php index 9176c371..1268f292 100644 --- a/system/twig.php +++ b/system/twig.php @@ -16,6 +16,8 @@ use Twig\Loader\FilesystemLoader as Twig_FilesystemLoader; use Twig\TwigFilter; use Twig\TwigFunction; +global $twig, $twig_loader; + $dev_mode = (config('env') === 'dev'); $twig_loader = new Twig_FilesystemLoader(SYSTEM . 'templates'); $twig = new Twig_Environment($twig_loader, array( diff --git a/templates/tibiacom/account.management.html.twig b/templates/tibiacom/account.management.html.twig index 773ce6c9..5125f3ed 100644 --- a/templates/tibiacom/account.management.html.twig +++ b/templates/tibiacom/account.management.html.twig @@ -111,6 +111,7 @@


{% endif %} +{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_GENERAL_INFORMATION') }}
@@ -221,6 +222,7 @@ {% endset %} {% include 'tables.headline.html.twig' %}
+{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_PUBLIC_INFORMATION') }}
@@ -280,6 +282,7 @@ {% endset %} {% include 'tables.headline.html.twig' %}
+{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS') }}
@@ -288,7 +291,7 @@
-{% set title = 'Account logs' %} +{% set title = 'Account Logs' %} {% set tableClass = 'Table3' %} {% set content %} @@ -333,6 +336,7 @@ {% endset %} {% include 'tables.headline.html.twig' %}
+{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_CHARACTERS') }}
diff --git a/templates/tibiacom/buttons.base.html.twig b/templates/tibiacom/buttons.base.html.twig index fe8447dc..a4ab47d5 100644 --- a/templates/tibiacom/buttons.base.html.twig +++ b/templates/tibiacom/buttons.base.html.twig @@ -1,8 +1,19 @@ {% apply spaceless %} -
-
-
- + + {% set tmp_image = 'sbutton' %} + + {% if button_color is defined %} + {% if button_color == 'green' %} + {% set tmp_image = 'sbutton_green' %} + {% elseif button_color == 'red' %} + {% set tmp_image = 'sbutton_red' %} + {% endif %} + {% endif %} + +
+
+
+ +
-
{% endapply %} diff --git a/templates/tibiacom/buttons.create_character.html.twig b/templates/tibiacom/buttons.create_character.html.twig index 20f3e053..5e2c0dd0 100644 --- a/templates/tibiacom/buttons.create_character.html.twig +++ b/templates/tibiacom/buttons.create_character.html.twig @@ -1,3 +1,2 @@ {% set button_name = 'Create Character' %} -{% set button_image = '_sbutton_createcharacter' %} -{% include('buttons.base.html.twig') %} \ No newline at end of file +{% include('buttons.base.html.twig') %} diff --git a/templates/tibiacom/index.php b/templates/tibiacom/index.php index 65f78018..2152b043 100644 --- a/templates/tibiacom/index.php +++ b/templates/tibiacom/index.php @@ -34,17 +34,7 @@ if(isset($config['boxes'])) } } else { - $tmp = str_replace('/', '', URI); - $exp = explode('/', URI); - if(URI !== 'account/create' && URI !== 'account/lost' && isset($exp[1])) { - if ($exp[0] === 'account') { - $tmp = 'accountmanage'; - } else if ($exp[0] === 'news' && $exp[1] === 'archive') { - $tmp = 'newsarchive'; - } - else - $tmp = $exp[0]; - } + $tmp = str_replace('/', '_', PAGE); } } else { @@ -353,12 +343,15 @@ foreach($config['menu_categories'] as $id => $cat) { $default_menu_color = "ffffff"; foreach($menus[$id] as $category => $menu) { + if (empty($menu['link'])) { + $menu['link'] = 'news'; + } $link_color = '#' . (strlen($menu['color']) == 0 ? $default_menu_color : $menu['color']); ?> '> -
- - - + - - + + +
+
+ {{ include('buttons.back.html.twig') }} -
{% endif %} diff --git a/tools/validate.php b/tools/validate.php index 0eb76e0c..b3546aad 100644 --- a/tools/validate.php +++ b/tools/validate.php @@ -23,32 +23,36 @@ if(isset($_GET['account'])) { $account = $_GET['account']; if(USE_ACCOUNT_NAME) { - if(!Validator::accountName($account)) + if(!Validator::accountName($account)) { error_(Validator::getLastError()); + } } - else if(!Validator::accountId($account)) + else if(!Validator::accountId($account)) { error_(Validator::getLastError()); + } $_account = new OTS_Account(); - if(USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER) + if(USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER) { $_account->find($account); - else + } else { $_account->load($account); + } $accountNameOrNumber = (USE_ACCOUNT_NAME ? ' name' : 'number'); - if($_account->isLoaded()) + if($_account->isLoaded()) { error_("Account with this $accountNameOrNumber already exist."); + } success_("Good account $accountNameOrNumber ($account)."); } else if(isset($_GET['email'])) { $email = $_GET['email']; - if(!Validator::email($email)) + if(!Validator::email($email)) { error_(Validator::getLastError()); + } - if(setting('core.account_mail_unique')) - { + if(setting('core.account_mail_unique')) { if(Account::where('email', '=', $email)->exists()) error_('Account with this e-mail already exist.'); } @@ -62,11 +66,13 @@ else if(isset($_GET['name'])) $name = strtolower(stripslashes($name)); } - if(!Validator::characterName($name)) + if(!Validator::characterName($name)) { error_(Validator::getLastError()); + } - if(!admin() && !Validator::newCharacterName($name)) + if(!admin() && !Validator::newCharacterName($name)) { error_(Validator::getLastError()); + } $createCharacter = new CreateCharacter(); if (!$createCharacter->checkName($name, $errors)) { @@ -83,16 +89,19 @@ else if(isset($_GET['password']) && isset($_GET['password_confirm'])) { error_('Please enter the password for your new account.'); } - if(!Validator::password($password)) + if(!Validator::password($password)) { error_(Validator::getLastError()); + } - if($password != $password_confirm) + if($password != $password_confirm) { error_('Passwords are not the same.'); + } success_(1); } -else +else { error_('Error: no input specified.'); +} /** * Output message & exit.