diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 2e60e570..8a1e73a3 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: [ '8.1', '8.2', '8.3' ] + php-versions: [ '8.1', '8.2', '8.3', '8.4' ] steps: - name: "Checkout" uses: "actions/checkout@v4" diff --git a/.gitignore b/.gitignore index b198856f..15c069b1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ Thumbs.db # /.htaccess -lua +/lua # composer composer.phar diff --git a/CHANGELOG-1.x.md b/CHANGELOG-1.x.md index c6feb09d..b8c57ce7 100644 --- a/CHANGELOG-1.x.md +++ b/CHANGELOG-1.x.md @@ -1,5 +1,195 @@ # Changelog +## [1.8.4 - 27.10.2025] + +### Changed +* Reimport myaac_ tables on every install, this fixes errors when one table is missing or is duplicated (https://github.com/slawkens/myaac/commit/2580edadf84779f09fd395c21f92019b2c762f83) +* Use custom env init on migrate, migrate:run and migrate:to (https://github.com/slawkens/myaac/commit/13ea68cc0c9349380c8e4051d702a6c2c8256f44, https://github.com/slawkens/myaac/commit/07fd034fe4cb0ffdb88667b1e400f414d0c6d06f) + +### Fixed +* Show if there is mysql error on import schema (https://github.com/slawkens/myaac/commit/44110a9496b4385e42c31b75de301037e711b6c3) +* Fix the premium checks, introduced in v1.8.3 (https://github.com/slawkens/myaac/commit/9d92a11fb7cb6d7a1619d79c12faaa0b1c01f980) + +## [1.8.3 - 21.10.2025] + +### Added +* Feature: resend email verify (https://github.com/slawkens/myaac/commit/fe821c58085483e70491dcf76376ad5b96de3fdd) +* New config: hooks_debug (To view where hooks are located in .twig files) (https://github.com/slawkens/myaac/commit/8c3cb0e06f9709c1de3398b48221241e7cbdd310) +* Functions: Add db->getColumnInfo(table, column) (https://github.com/slawkens/myaac/commit/c898fe25efff6793a01d11c26fc153cb23fcb858) +* Plugins: Add option to use ?subtopic=x for plugins pages (https://github.com/slawkens/myaac/commit/97f9d3d6f6c28aef6d824973058d7133f56e09c4) +* getTopPlayers() Function - Add lookmount & promotion (https://github.com/slawkens/myaac/commit/2da0024c68f1cedc38a16ebbc6f52ffa55e65f7a, https://github.com/slawkens/myaac/commit/901df48d134079d648a18f9d82b60182e818ac02) +* New hooks for account/change-password (https://github.com/slawkens/myaac/commit/470555f2687809a0c12491bbb27597e64b8929c1) + +### Changed +* Feature: show vip days in account management (https://github.com/slawkens/myaac/commit/c88b08eb1ec1f560cbfdaaa16b24e3a0f26da7b3, by @andreoam) +* Allow links in error_box.html.twig (https://github.com/slawkens/myaac/commit/9acad15451071639acf7a7d4e81619b0a9742b12) +* Canary - Comment code to update lastday in login.php (https://github.com/slawkens/myaac/commit/38902c30d114fdbce259467f5820f97037b393e9) +* Cache::remember $ttl = -1 = infinite (https://github.com/slawkens/myaac/commit/64acf70d3854182d88aaf0b67f77cea2a254f179) + +### Fixed +* Online - Allow for html code (example - img) in online_datacenter (https://github.com/slawkens/myaac/commit/3bb272ebbbd2eb7769d174b7082061d14a17bd44) +* Guilds - Fix guild create with freePremium enabled (https://github.com/slawkens/myaac/commit/c91bb5d4097647dca2196d3dea87bc90c89181d2) +* Canary - Fix premDays count (https://github.com/slawkens/myaac/commit/3e61692780d4add93b7b0e9f12f7a283bd8f4b7a) +* Template Change: Ignore set last visit for AJAX pages - Fixes template change redirect (https://github.com/slawkens/myaac/commit/89fae38caa7e4f645957fcf1a9330a36358ac04f) +* Admin Panel - Accounts: Fix lastip v6 (TFS master) (https://github.com/slawkens/myaac/commit/f54b1bdd2af4c16c64ddff0e87a6c96bc4cf9eeb) +* Functions - Prevent injection in $db->hasColumn (https://github.com/slawkens/myaac/commit/56bd7ec5ed904666074492f2e4f13e4fce226bee) +* Compat Config: Add missing config: email_lai_sec_interval (https://github.com/slawkens/myaac/commit/2eae44e0755e624a91be68b4d1ec26d01eb4d9a1) + +## [1.8.2 - 26.09.2025] + +### Added +* Routes: Possibility to override routes with plugins pages, like characters.php - No need to define routes in plugin.json anymore (https://github.com/slawkens/myaac/commit/3f24f961b1cdeff5c60387e837ae454448bc5e1b) + +### Changed +* Style: Better look for myaac-table (https://github.com/slawkens/myaac/commit/a6032093b21e5bb3f0e75d2704da87d6dea6469d, https://github.com/slawkens/myaac/commit/5aa9bbf1c8e580d973ec82ac012489f8e7bc437e) + +### Fixed +* Install: Fix when config.local.php cannot be saved (https://github.com/slawkens/myaac/commit/4eab805d26d8c5562b29ed699769919d77dabced) +* Create Account: Fix an exception when email cannot be sent (https://github.com/slawkens/myaac/commit/d0112d1a67e8b854b65ad131f0375b79305df8d3) +* Login Page: Add missing csrf() - fix create account button (https://github.com/slawkens/myaac/commit/3c0cb53e17dd0b85394cfa0fdc9cf9ad8d4551df) +* tibiacom template: Fix account lost menu (https://github.com/slawkens/myaac/commit/ed9beaf2b6ca069e304e569c52e5b9188b58f05c) +* tibiacom template: Fix Menu div wrong tag/closing (#329) (https://github.com/slawkens/myaac/commit/85e7005fd3f0be51466151a3c122b96085fdfe68) +* tibiacom template: Replace firstChild with firstElementChild (Thanks to @un000000) (https://github.com/slawkens/myaac/commit/df7b6e29fb8875da97f431468c81ee99116271d9) + +## [1.8.1 - 05.09.2025] + +### Added +* New Commands: plugin:enable/disable/uninstall {plugin-name} (https://github.com/slawkens/myaac/commit/7a08f91d3fc0897c1ff76089ef3c649a2c6d2003, https://github.com/slawkens/myaac/commit/fec773ba4b740f35c0a3ef92ca8444a4c7d02082) +* Gifts: Added Transferable Coins to the store dropdown menu in the admin area (by @andreoam, #321) (https://github.com/slawkens/myaac/commit/42671c5c199dd9e91c774d8c9d30da9e12f1b695) + +### Changed +* Commands: Allow settings to be changed/reset by plugin name (https://github.com/slawkens/myaac/commit/f8c4332e03e838d285ea0afb4b72b7c23e324d45, https://github.com/slawkens/myaac/commit/4b948e9510f7ba69d00f84d7fdaea8b3bf05b630) +* Templates: Menus should be saved for each template separately (https://github.com/slawkens/myaac/commit/482f4067b2a2e7513d9ba214274a361ffaf123d8) + +### Fixed +* Online: Fix skulls display (#320) (https://github.com/slawkens/myaac/commit/98073a110ae13f9592ec9d2c4d1d1aace87587a9) +* Online: Fix if there is no world_id in the server_record table (https://github.com/slawkens/myaac/commit/b6e1620f14c20eecfc9001a7d86dfb67942985c6) (Reported by @gesior in #318) +* tibiacom: some fixes to menus (https://github.com/slawkens/myaac/commit/20f99903ae80c74ad66c1cf5a5ea8d0b0fc2fd70, https://github.com/slawkens/myaac/commit/11dae90fa94fbbf47447017db5e5847c33d6aadf) +* Guilds: Fix for some servers that don't have guild_invites table (https://github.com/slawkens/myaac/commit/9725a3c2bdb7003f5cb48febb77604c31a9b805b) + +## [1.8 - 02.08.2025] + +### Added +* Templates - Kathrine: Possibility to add custom menu categories (https://github.com/slawkens/myaac/commit/ec11c1402417c25980582467546d1c1e9bb8267f) +* Admin Panel - Accounts Editor: Add Coins Transferable (https://github.com/slawkens/myaac/commit/45d6047031c9c3a0e7e512dc5d15c75629aec5a2, https://github.com/slawkens/myaac/commit/bb097b69ce106500a49686d6f4fe604348eaa310) +* Highscores: + * Revamped: (https://github.com/slawkens/myaac/commit/d8132d4d76e03d5aa0c042be426320655a601392) + * Show real rank, if 2 or more players have the same skill, show them with same rank + * New setting: highscores_online_status + * Additional fields passed to twig: updatedAt, totalResults, page, baseLink + * Add new Setting: Display Skills Box (https://github.com/slawkens/myaac/commit/36ca755243ef1c83f6ac87465b426d4d8d3b0bb9) +* Functions: Add getExperienceForLevel (level) (https://github.com/slawkens/myaac/commit/1566deb84a082176b8c683fda205d828bc38fbcc) +* Commands - cache:clear : Add warning about APCu clear in CLI (https://github.com/slawkens/myaac/commit/83f84172e02e8ea2ccb6dca29bc033e44c35aebc) +* Models - PlayerOnline: Add missing $fillable into model (https://github.com/slawkens/myaac/commit/43415cf35db1c1307f2684c1728693d65065ffff) +* Twig: add cache variable (https://github.com/slawkens/myaac/commit/0efe47ce71c4b364a9e96bc5a55b1655326ae6da) + +### Changed +* pages/online: add cache, resulting in 20x performance boost + * (for an example server with 2k players) (https://github.com/slawkens/myaac/commit/c8363086015cbb6e8786c398c7b9ac3959a26ec4) +* Admin Bar: Move admin bar code into body_start place_holder (https://github.com/slawkens/myaac/commit/f17269e44ce9dd38447bd2e2a8e1bdb065d4161f) +* Cache::remember: $ttl = 0 means no cache (https://github.com/slawkens/myaac/commit/3b47e9df2f4051807c5ff87892f7fa3d348f9c55) +* Templates: Load config.ini with $process_sections set to true (https://github.com/slawkens/myaac/commit/a89f9a84847630eb75b4890fdcc8b7a7bfa6b8ac) +* Twig: Allow for timestamp as integer in the timeago twig function + (https://github.com/slawkens/myaac/commit/34fead906ea13b9f09d7a3c41ed88109d34d386c) + +### Fixed +* Settings: Fixed two exceptions (https://github.com/slawkens/myaac/commit/6e5a4ff8c78ff5373aba091baa66cae029557643, https://github.com/slawkens/myaac/commit/20d69a641c0a933d14889a89da6d32f6a4bc6c7d) +* Models\Account + OTS_Account -> isPremium -> ignore config.freePremium (https://github.com/slawkens/myaac/commit/5271633bdbfbbfed0b1d59c403093ce6fc2b7d20) +* Admin Panel - Mailer: + * Fix send to email link redirecting from accounts page (https://github.com/slawkens/myaac/commit/080cc2781f034c844af658229e495e9a47fd2298) + * Option to send only to verified accounts - only if setting('core.account_mail_verify') enabled (https://github.com/slawkens/myaac/commit/cf7fd20452e863980045bb5d6012ec86c6e8e01f) + +### Internal +* Rewrite to use constants (account transferable coins) (https://github.com/slawkens/myaac/commit/bccf8e056df985bbe1bab5f7ab5492f714d6b62b) +* Refactor to use HAS_ACCOUNT_COINS (https://github.com/slawkens/myaac/commit/caf326a6584a234775ebc6c8000ea02b3fecd160) + +## [1.7.1 - 27.06.2025] + +### Changed +* Rename plugin:install:install to plugin:setup, also add alias to previous command (https://github.com/slawkens/myaac/commit/13d33822b59df349199e885a78a3d6beb0863d0b) + +### Fixed +* Fix commands: setup + cache:clear (https://github.com/slawkens/myaac/commit/0da524fefe93b3028392e9014550eea3324d3a22, https://github.com/slawkens/myaac/commit/fe8281594e989f00280ba1adc734a9198c6b5cc1) +* Fix polls link in tibiacom template (https://github.com/slawkens/myaac/commit/d90fa323d7c77d81768df60feeb1c374b1650a0c) + +## [1.7 - 22.06.2025] + +### Added +* Feature: plugins versions check (#310) +* New hooks: HOOK_ACCOUNT_MANAGE_AFTER_CHARACTERS, HOOK_GUILDS_AFTER_MANAGE_BUTTON (https://github.com/slawkens/myaac/commit/c074a48f245df55646b6705737f667b6a84149b2, https://github.com/slawkens/myaac/commit/e6100a1b72de8695bba1dae9ba4e28bfdce47b10) +* Add OTS_Toolbox::getVocationName(id, promotion) + OTS_Player->isNameLocked() (https://github.com/slawkens/myaac/commit/e222957893c4a1de0dc8dbba55bce1a43418d275, https://github.com/slawkens/myaac/commit/522f6c11d835afd36fd07a07074d96d7e219b488) +* Add missing csrf in more places, causing white page with error about Request (https://github.com/slawkens/myaac/commit/dca904e61d21d856bf809070e7652803a2df0f58, https://github.com/slawkens/myaac/commit/c720ccc451ff90ef40b2a1595468d061ffd7e1e4) + +### Changed +* Revamped online page (https://github.com/slawkens/myaac/commit/9a90e4aae280e607430511c6727d9a714b11f4c5, https://github.com/slawkens/myaac/commit/4767120043b09141870383e249f3729638d53dc2) +* Better $title inventing (https://github.com/slawkens/myaac/commit/0c95bcfd06b68b21512e477646ef7bd3a0d4912b) + +### Fixed +* Use apcu cache clear (https://github.com/slawkens/myaac/commit/b329da52aae9d0e21120a6444d3caf442420ce50, https://github.com/slawkens/myaac/commit/566c2a9151ab6392286f74e26853faa19a1b4f24) +* fix: boostedcreatures for 13.40 (by @GooseWithAKnife) (#307) + +## [1.6.1 - 11.06.2025] + +### Fixed +* Fixed "Request has been cancelled due to security reasons", cause of missing csrf() in twig files (https://github.com/slawkens/myaac/commit/10cd71a6630ffec91b43a26a6d685b66c5836a6a) +* Fix: Ignore duplicated route exception (https://github.com/slawkens/myaac/commit/9d8e9d27bd87167d8d4005942a6af62bfe4c0892) + +### Changed +* Move counter & visitors code before router (In case someone wants to include that info on page) (https://github.com/slawkens/myaac/commit/f78285030708ad3c74ab048711f73bbf3ee5281e) +* Set TinyMCE license key to gpl (Avoid warning message in browser console) (https://github.com/slawkens/myaac/commit/8d29fdb98b92dbc3d2853ef88a185c67036b4a77) + +### Removed +* Remove deprecated TinyMCE plugin - template (https://github.com/slawkens/myaac/commit/309c1fb715b882e67cb673b1544a03befbf64a22) + +## [1.6 - 03.06.2025] + +### Added +* Add new setting/configurable: site_url, prevents domain spoofing (https://github.com/slawkens/myaac/commit/d8a6090be382c35c19117cfef964b594ed02b8d4) +* Add new account coins setting (https://github.com/slawkens/myaac/commit/28886551e86fe562172c4c7f2afb89a2e7672c2e) +* autoload: settings/install/init.php (https://github.com/slawkens/myaac/commit/e5749437074c3b3556628a2aeb5bad2edf97bde0, https://github.com/slawkens/myaac/commit/7d213f479a7e40c6254069b5fc4e578dc32bf8d9, https://github.com/slawkens/myaac/commit/207d6bc69120aba1af2b51808f17e0059b571fed) +* Protect against csrf in more places (accounts & guilds & forums pages) (https://github.com/slawkens/myaac/commit/6eda38603c8ed7e99b92a78a4600b1245377f74d, https://github.com/slawkens/myaac/commit/e776bd52beb3064a9e694efd1b9021ec972ee2f6, https://github.com/slawkens/myaac/commit/84d502bf105f2a789481fba1acc820d236b4de66) +* Added two new hooks for pages loaded from database (custom pages): HOOK_BEFORE_PAGE_CUSTOM, HOOK_AFTER_PAGE_CUSTOM (https://github.com/slawkens/myaac/commit/c961a1ebf837f2ab1734a825ff2c57b4937610c9) +* Add global variables into $hooks->executeFilter (https://github.com/slawkens/myaac/commit/8fdea943768b20193eede99d60313ee84511a0be) +* Add getNPCsCount() to OTS_InfoRespond (https://github.com/slawkens/myaac/commit/7d435ff6433ef1fb2295ee79ed043ee10dc725e9) + +### Fixed +* Allow [] in character name (https://github.com/slawkens/myaac/commit/de6603a51347b9e656c58637ed9971fffdd7cedd) +* Do not allow access to tools/ folder after install (https://github.com/slawkens/myaac/commit/6e0f5913831f8dba69fd2d1505be3e2a303c6324) +* Fix CHANGELOG-1.x.md loading in admin panel (https://github.com/slawkens/myaac/commit/4a30fb495dbfbe1d434e8d52419eaf44fe517aee) +* Fix links not working in admin dashboard modules (https://github.com/slawkens/myaac/commit/be7b27c31aa3bbd6c0289c34d1e61139a3fe015c) +* Fix twig variables: logged + account_logged being not set directly after login (https://github.com/slawkens/myaac/commit/1e9b10d6489c488cadf7f6ed17b42f1ea6c767a8) + +### Changed +* OTS_ServerInfo -> move setTimeout out of class - Possibility to use the class without MyAAC (https://github.com/slawkens/myaac/commit/40d65a6613149fda51bdceb82c807e5301a3388b) + +## [1.5 - 14.05.2025] + +### Added +* Feature/twig hooks filters (#258) +* Add latest client versions (14.00 - 15.01) (https://github.com/slawkens/myaac/commit/5367df23812c6182863353c9a39fd7fb0b743f4b) +* db variable to twig (https://github.com/slawkens/myaac/commit/5ed1aec28e146b871a75597411d12e42a067f4e6) +* New filter: HOOK_FILTER_ROUTES (https://github.com/slawkens/myaac/commit/9b75011224f385db8b27e109bfeb28e75b9d779c) +* Allow optionally separate folder for views (thanks @Scrollog for idea) (https://github.com/slawkens/myaac/commit/03e275213901a89edb0ebb8974b776a992ab391f) +* Add float & double types to the Settings (https://github.com/slawkens/myaac/commit/67ab425bb9796d9d123296e3fda542fa8f7f05ee) +* Add optional param _page_only for single-page apps etc. (https://github.com/slawkens/myaac/commit/113473f2560aab6d364c301cc14a8b5ba8f309f4) + +### Changed +* Change OTS_Account->getPremDays to not return -1 in case of freePremium (https://github.com/slawkens/myaac/commit/3befde2a1e4d24a011311e785f15185db57e19b8) +* Add note about highscores being updated x minutes + allow ttl 0 to disable cache (https://github.com/slawkens/myaac/commit/a161cff00329da6f970f3a70967fe8346fe92bbc) +* Better monster images (no image not found anymore) + use cache (https://github.com/slawkens/myaac/commit/73a5829974ceca3f02d7925d5cfbd5fa50b1bbd2) +* Rename server-info -> ots-info, changelog -> change-log (Due to conflict with apache2 server-info mod) (https://github.com/slawkens/myaac/commit/3949d84e5d7631f332111b6d00278bddbd0ad10a) +* Move rules page to admin panel (https://github.com/slawkens/myaac/commit/3949d84e5d7631f332111b6d00278bddbd0ad10a) + +### Fixed +* php 8.4 warnings +* Visitors counter not working properly on dev mode (https://github.com/slawkens/myaac/commit/da151051186c913dd0dd091aabe893649c2b9ee7) +* Fix login.php boosted creature & boss (not sure exact version, but should be 14.12 or around) (https://github.com/slawkens/myaac/commit/c48b8006319f6c3b5f082befd16785420bb98110) +* Fix installMenus when theme/template was removed from disc (https://github.com/slawkens/myaac/commit/c24c580796bccd54bf9e95b864763f4642684d55) +* Fix if user removes the menu category (https://github.com/slawkens/myaac/commit/dbea69f31478391dacfbbc02c8353c39b4245daf) + +### Updated: +* Update cypress from version ^13.17.0 to ^14.3.3 (https://github.com/slawkens/myaac/commit/629fd18ea166860d5898a822f44f9277da6ce43d) + ## [1.4 - 22.04.2025] ### Added diff --git a/README.md b/README.md index e34e806a..54b27d07 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Pull requests should be made to the *develop* branch as that is the working bran Bug fixes to current release should be done to master branch. -Look: [Contributing](https://github.com/otsoft/myaac/wiki/Contributing) in our wiki. +Look: [Contributing](https://docs.my-aac.org/misc/contributing) in our wiki. ### Other Notes @@ -95,4 +95,4 @@ Many thanks to Jetbrains for kindly providing a license for me to work on this a ### License This program and all associated files are released under the GNU Public License. -See [LICENSE](https://github.com/slawkens/myaac/blob/master/LICENSE) for details. +See [LICENSE](https://github.com/slawkens/myaac/blob/main/LICENSE) for details. diff --git a/aac b/aac index d4ce7b7d..8f213136 100644 --- a/aac +++ b/aac @@ -25,7 +25,9 @@ foreach ($commandsGlob as $item) { } $commandPre = '\\MyAAC\Commands\\'; - $application->add(new ($commandPre . $name)); + if (!trait_exists($class = $commandPre . $name)) { + $application->add(new $class); + } } $pluginCommands = Plugins::getCommands(); diff --git a/admin/pages/accounts.php b/admin/pages/accounts.php index 67381b5e..8a20aa62 100644 --- a/admin/pages/accounts.php +++ b/admin/pages/accounts.php @@ -27,7 +27,6 @@ if (setting('core.account_country')) $nameOrNumberColumn = getAccountIdentityColumn(); $hasSecretColumn = $db->hasColumn('accounts', 'secret'); -$hasCoinsColumn = $db->hasColumn('accounts', 'coins'); $hasPointsColumn = $db->hasColumn('accounts', 'premium_points'); $hasTypeColumn = $db->hasColumn('accounts', 'type'); $hasGroupColumn = $db->hasColumn('accounts', 'group_id'); @@ -137,11 +136,18 @@ else if (isset($_REQUEST['search'])) { if (!Validator::email($email)) $errors['email'] = Validator::getLastError(); - //tibia coins - if ($hasCoinsColumn) { + // tibia coins + if (HAS_ACCOUNT_COINS) { $t_coins = $_POST['t_coins']; verify_number($t_coins, 'Tibia coins', 12); } + + // transferable tibia coins + if (HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS) { + $t_coins_transferable = $_POST['t_coins_transferable']; + verify_number($t_coins_transferable, 'Transferable Tibia coins', 12); + } + // prem days $p_days = (int)$_POST['p_days']; verify_number($p_days, 'Prem days', 11); @@ -186,12 +192,18 @@ else if (isset($_REQUEST['search'])) { if ($hasSecretColumn) { $account->setCustomField('secret', $secret); } + $account->setCustomField('key', $key); $account->setEMail($email); - if ($hasCoinsColumn) { + + if (HAS_ACCOUNT_COINS) { $account->setCustomField('coins', $t_coins); } + if (HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS) { + $account->setCustomField(ACCOUNT_COINS_TRANSFERABLE_COLUMN, $t_coins_transferable); + } + $lastDay = 0; if($p_days != 0 && $p_days != OTS_Account::GRATIS_PREMIUM_DAYS) { $lastDay = time(); @@ -224,9 +236,6 @@ else if (isset($_REQUEST['search'])) { $password = encrypt($password); $account->setPassword($password); - - if (USE_ACCOUNT_SALT) - $account->setCustomField('salt', $salt); } $account->save(); @@ -396,12 +405,18 @@ else if (isset($_REQUEST['search'])) { getEMail() . '">Send Mail)' : ''); ?> - +
+ +
+ + +
+
diff --git a/admin/pages/clmd.php b/admin/pages/clmd.php index f0ad49d3..fa06a130 100644 --- a/admin/pages/clmd.php +++ b/admin/pages/clmd.php @@ -11,12 +11,12 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'MyAAC Changelog'; -if (!file_exists(BASE . 'CHANGELOG.md')) { +if (!file_exists(BASE . 'CHANGELOG-1.x.md')) { echo 'File CHANGELOG.md doesn\'t exist.'; return; } -$changelog = file_get_contents(BASE . 'CHANGELOG.md'); +$changelog = file_get_contents(BASE . 'CHANGELOG-1.x.md'); $Parsedown = new Parsedown(); diff --git a/admin/pages/mailer.php b/admin/pages/mailer.php index 1f8d3188..5ac8f58c 100644 --- a/admin/pages/mailer.php +++ b/admin/pages/mailer.php @@ -25,9 +25,10 @@ if (!setting('core.mail_enabled')) { return; } -$mail_to = isset($_POST['mail_to']) ? stripslashes(trim($_POST['mail_to'])) : null; +$mail_to = isset($_REQUEST['mail_to']) ? stripslashes(trim($_REQUEST['mail_to'])) : null; $mail_subject = isset($_POST['mail_subject']) ? stripslashes($_POST['mail_subject']) : null; $mail_content = isset($_POST['mail_content']) ? stripslashes($_POST['mail_content']) : null; +$mail_verified_only = $_POST['mail_verified_only'] ?? false; if (isset($_POST['submit'])) { if (empty($mail_subject)) { @@ -58,14 +59,14 @@ if (!empty($mail_content) && !empty($mail_subject) && empty($mail_to)) { $success = 0; $failed = 0; - $add = ''; - if (setting('core.account_mail_verify')) { - note('Note: Sending only to users with verified E-Mail.'); - $add = ' AND `email_verified` = 1'; + $query = Account::where('email', '!=', ''); + + if ($mail_verified_only) { + info('Note: Sending only to users with verified E-Mail.'); + $query->where('email_verified', 1); } - $query = Account::where('email', '!=', '')->get(['email']); - foreach ($query as $email) { + foreach ($query->get(['email']) as $email) { if (_mail($email->email, $mail_subject, $mail_content)) { $success++; } @@ -84,5 +85,6 @@ if (!empty($mail_content) && !empty($mail_subject) && empty($mail_to)) { $twig->display('admin.mailer.html.twig', [ 'mail_to' => $mail_to, 'mail_subject' => $mail_subject, - 'mail_content' => $mail_content + 'mail_content' => $mail_content, + 'mail_verified_only' => $mail_verified_only, ]); diff --git a/admin/pages/mass_account.php b/admin/pages/mass_account.php index 46c9bc9d..4ee9f63b 100644 --- a/admin/pages/mass_account.php +++ b/admin/pages/mass_account.php @@ -6,6 +6,7 @@ * @package MyAAC * @author Slawkens * @author Lee + * @author gpedro * @copyright 2020 MyAAC * @link https://my-aac.org */ @@ -18,11 +19,10 @@ $title = 'Mass Account Actions'; csrfProtect(); -$hasCoinsColumn = $db->hasColumn('accounts', 'coins'); $hasPointsColumn = $db->hasColumn('accounts', 'premium_points'); -$freePremium = $config['lua']['freePremium']; +$freePremium = getBoolean(configLua('freePremium')); -function admin_give_points($points) +function admin_give_points($points): void { global $hasPointsColumn; @@ -38,11 +38,9 @@ function admin_give_points($points) displayMessage($points . ' points added to all accounts.', true); } -function admin_give_coins($coins) +function admin_give_coins($coins): void { - global $hasCoinsColumn; - - if (!$hasCoinsColumn) { + if (!HAS_ACCOUNT_COINS) { displayMessage('Coins not supported.'); return; } @@ -55,7 +53,7 @@ function admin_give_coins($coins) displayMessage($coins . ' coins added to all accounts.', true); } -function admin_give_premdays($days) +function admin_give_premdays($days): void { global $db, $freePremium; @@ -66,6 +64,7 @@ function admin_give_premdays($days) $value = $days * 86400; $now = time(); + // othire if ($db->hasColumn('accounts', 'premend')) { // append premend @@ -73,14 +72,11 @@ function admin_give_premdays($days) // set premend if (Account::where('premend', '<=', $now)->update(['premend' => $now + $value])) { displayMessage($days . ' premium days added to all accounts.', true); - return; } else { displayMessage('Failed to execute set query.'); - return; } } else { displayMessage('Failed to execute append query.'); - return; } return; @@ -95,20 +91,14 @@ function admin_give_premdays($days) // set lastday if (Account::where('lastday', '<=', $now)->update(['lastday' => $now + $value])) { displayMessage($days . ' premium days added to all accounts.', true); - return; } else { displayMessage('Failed to execute set query.'); - return; } - - return; } else { displayMessage('Failed to execute append query.'); - return; } } else { displayMessage('Failed to execute set days query.'); - return; } return; @@ -121,14 +111,11 @@ function admin_give_premdays($days) // set premium_ends_at if (Account::where('premium_ends_at', '<=', $now)->update(['premium_ends_at' => $now + $value])) { displayMessage($days . ' premium days added to all accounts.', true); - return; } else { displayMessage('Failed to execute set query.'); - return; } } else { displayMessage('Failed to execute append query.'); - return; } return; @@ -167,19 +154,20 @@ if (!empty(ACTION) && isRequestMethod('post')) { } else { $twig->display('admin.tools.account.html.twig', array( - 'hasCoinsColumn' => $hasCoinsColumn, + 'hasCoinsColumn' => HAS_ACCOUNT_COINS, 'hasPointsColumn' => $hasPointsColumn, 'freePremium' => $freePremium, )); } -function displayMessage($message, $success = false) { - global $twig, $hasCoinsColumn, $hasPointsColumn, $freePremium; +function displayMessage($message, $success = false): void +{ + global $twig, $hasPointsColumn, $freePremium; $success ? success($message): error($message); $twig->display('admin.tools.account.html.twig', array( - 'hasCoinsColumn' => $hasCoinsColumn, + 'hasCoinsColumn' => HAS_ACCOUNT_COINS, 'hasPointsColumn' => $hasPointsColumn, 'freePremium' => $freePremium, )); diff --git a/admin/pages/modules/balance.php b/admin/pages/modules/balance.php index d700ef16..82070469 100644 --- a/admin/pages/modules/balance.php +++ b/admin/pages/modules/balance.php @@ -7,7 +7,7 @@ defined('MYAAC') or die('Direct access not allowed!'); $balance = 0; if ($db->hasColumn('players', 'balance')) { - $balance = Player::orderByDesc('balance')->limit(10)->get(['balance', 'id','name', 'level'])->toArray(); + $balance = Player::orderByDesc('balance')->limit(10)->get(['id', 'name', 'balance'])->toArray(); } $twig->display('balance.html.twig', array( diff --git a/admin/pages/modules/coins.php b/admin/pages/modules/coins.php index 725c2e45..66ce0186 100644 --- a/admin/pages/modules/coins.php +++ b/admin/pages/modules/coins.php @@ -6,8 +6,13 @@ defined('MYAAC') or die('Direct access not allowed!'); $coins = 0; -if ($db->hasColumn('accounts', 'coins')) { - $coins = Account::orderByDesc('coins')->limit(10)->get(['coins', (USE_ACCOUNT_NAME ? 'name' : 'id')])->toArray(); +if (HAS_ACCOUNT_COINS) { + $whatToGet = ['id', 'coins']; + if (USE_ACCOUNT_NAME) { + $whatToGet[] = 'name'; + } + + $coins = Account::orderByDesc('coins')->limit(10)->get($whatToGet)->toArray(); } $twig->display('coins.html.twig', array( diff --git a/admin/pages/modules/lastlogin.php b/admin/pages/modules/lastlogin.php index 7fae3469..f20b11d2 100644 --- a/admin/pages/modules/lastlogin.php +++ b/admin/pages/modules/lastlogin.php @@ -7,7 +7,7 @@ defined('MYAAC') or die('Direct access not allowed!'); $players = 0; if ($db->hasColumn('players', 'lastlogin')) { - $players = Player::orderByDesc('lastlogin')->limit(10)->get(['name', 'level', 'lastlogin'])->toArray(); + $players = Player::orderByDesc('lastlogin')->limit(10)->get(['id', 'name', 'level', 'lastlogin'])->toArray(); } $twig->display('lastlogin.html.twig', array( diff --git a/admin/pages/modules/templates/balance.html.twig b/admin/pages/modules/templates/balance.html.twig index 70f0dc62..ee4a1771 100644 --- a/admin/pages/modules/templates/balance.html.twig +++ b/admin/pages/modules/templates/balance.html.twig @@ -19,7 +19,7 @@ {% set i = i + 1 %} {{ i }} - {{ result.name }} + {{ result.name }} {{ result.balance }} {% endfor %} diff --git a/admin/pages/modules/templates/coins.html.twig b/admin/pages/modules/templates/coins.html.twig index a822dfd5..ae586ee8 100644 --- a/admin/pages/modules/templates/coins.html.twig +++ b/admin/pages/modules/templates/coins.html.twig @@ -19,7 +19,7 @@ {% set i = i + 1 %} {{ i }} - {{ result.name }} + {{ result.name ?? result.id }} {{ result.coins }} {% endfor %} diff --git a/admin/pages/modules/templates/lastlogin.html.twig b/admin/pages/modules/templates/lastlogin.html.twig index 4127671d..dbf628e0 100644 --- a/admin/pages/modules/templates/lastlogin.html.twig +++ b/admin/pages/modules/templates/lastlogin.html.twig @@ -19,7 +19,7 @@ {% set i = i + 1 %} {{ i }} - {{ result.name }} + {{ result.name }} {{ result.lastlogin|date("M d Y, H:i:s") }} {% endfor %} diff --git a/admin/pages/modules/templates/points.html.twig b/admin/pages/modules/templates/points.html.twig index 019a9964..d30a3e36 100644 --- a/admin/pages/modules/templates/points.html.twig +++ b/admin/pages/modules/templates/points.html.twig @@ -19,7 +19,7 @@ {% set i = i + 1 %} {{ i }} - {{ result.name }} + {{ result.name }} {{ result.premium_points }} {% endfor %} diff --git a/admin/pages/players.php b/admin/pages/players.php index c44bc012..bd3ab713 100644 --- a/admin/pages/players.php +++ b/admin/pages/players.php @@ -669,11 +669,17 @@ else if (isset($_REQUEST['search'])) {
diff --git a/admin/pages/plugins.php b/admin/pages/plugins.php index db886635..82f8309c 100644 --- a/admin/pages/plugins.php +++ b/admin/pages/plugins.php @@ -51,6 +51,56 @@ else { } else { error('Error while disabling plugin ' . $disable . ': ' . Plugins::getError()); } + } + else if (isset($_GET['check-updates'])) { + $repoUri = $config['admin_plugins_api_uri'] ?? 'https://plugins.my-aac.org/api/'; + success("Fetching latest info from $repoUri.."); + + $adminPlugins = new \MyAAC\Admin\Plugins(); + + $adminPlugins->setApiBaseUri($repoUri); + + try { + $plugins = $adminPlugins->getLatestVersions(); + } + catch (Exception $e) { + error($e->getMessage()); + } + + if (isset($plugins) && count($plugins) > 0) { + $outdated = []; + + foreach (get_plugins(true) as $plugin) { + $string = file_get_contents(BASE . 'plugins/' . $plugin . '.json'); + $plugin_info = json_decode($string, true); + + if (!$plugin_info) { + continue; + } + + $disabled = (str_contains($plugin, 'disabled.')); + $pluginOriginal = ($disabled ? str_replace('disabled.', '', $plugin) : $plugin); + + $info = $plugins[$pluginOriginal] ?? false; + if ($info && version_compare($info['version'], $plugin_info['version'], '>')) { + $outdated[] = [ + 'name' => $pluginOriginal, + 'yourVersion' => $plugin_info['version'], + 'latestVersion' => $info['version'], + 'link' => $info['link'] ?? 'Unknown', + 'download_link' => $info['download_link'] ?? 'Unknown', + ]; + } + } + + if (count($outdated) > 0) { + info('Following updates have been found for your plugins:'); + $twig->display('admin.plugins.outdated.html.twig', ['plugins' => $outdated]); + } + else { + success('All plugins up to date!'); + } + } } else if (isset($_FILES['plugin']['name'])) { $file = $_FILES['plugin']; $filename = $file['name']; diff --git a/admin/pages/visitors.php b/admin/pages/visitors.php index 9e83d339..9fae4d24 100644 --- a/admin/pages/visitors.php +++ b/admin/pages/visitors.php @@ -19,8 +19,7 @@ $use_datatable = true; if (!setting('core.visitors_counter')): ?> Visitors counter is disabled.
- You can enable it by editing this configurable in config.local.php file:
-

$config['visitors_counter'] = true;

+ You can enable it in Settings -> General -> Visitors Counter.
isBot()) { $bot = $dd->getBot(); $message = '(Bot) %s, %s'; - $browser = sprintf($message, $bot['category'], $bot['url'], $bot['name']); + $browser = sprintf($message, $bot['category'] ?? 'Unknown', $bot['url'] ?? '', $bot['name'] ?? 'Unknown name'); } else { $osFamily = OperatingSystem::getOsFamily($dd->getOs('name')); diff --git a/admin/tools/phpinfo.php b/admin/tools/phpinfo.php index cd043279..bd09fb5d 100644 --- a/admin/tools/phpinfo.php +++ b/admin/tools/phpinfo.php @@ -1,5 +1,6 @@ =7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, { "name": "psr/log", "version": "3.0.2", @@ -1573,6 +2058,50 @@ }, "time": "2021-10-29T13:26:27+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "symfony/console", "version": "v6.4.17", @@ -2910,7 +3439,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -2921,6 +3450,6 @@ "ext-xml": "*", "ext-dom": "*" }, - "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform-dev": {}, + "plugin-api-version": "2.6.0" } diff --git a/cypress/e2e/3-check-public-pages.cy.js b/cypress/e2e/3-check-public-pages.cy.js index 9460739b..be7b7702 100644 --- a/cypress/e2e/3-check-public-pages.cy.js +++ b/cypress/e2e/3-check-public-pages.cy.js @@ -17,7 +17,7 @@ describe('Check Public Pages', () => { it('Go to changelog page', () => { cy.visit({ - url: Cypress.env('URL') + '/changelog', + url: Cypress.env('URL') + '/change-log', method: 'GET', }) }) @@ -132,7 +132,7 @@ describe('Check Public Pages', () => { it('Go to server info page', () => { cy.visit({ - url: Cypress.env('URL') + '/server-info', + url: Cypress.env('URL') + '/ots-info', method: 'GET', }) }) diff --git a/images/order_asc.gif b/images/order_asc.gif new file mode 100644 index 00000000..c9698a5a Binary files /dev/null and b/images/order_asc.gif differ diff --git a/images/order_desc.gif b/images/order_desc.gif new file mode 100644 index 00000000..4a764bd5 Binary files /dev/null and b/images/order_desc.gif differ diff --git a/index.php b/index.php index bc8a3663..ee8f7a87 100644 --- a/index.php +++ b/index.php @@ -93,6 +93,7 @@ if(setting('core.backward_support')) { if($logged && $account_logged) $group_id_of_acc_logged = $account_logged->getGroupId(); + $config['serverPath'] = $config['server_path']; $config['site'] = &$config; $config['server'] = &$config['lua']; $config['site']['shop_system'] = setting('core.gifts_system'); @@ -117,6 +118,14 @@ if(setting('core.backward_support')) { $config['status']['serverStatus_' . $key] = $value; } +if(setting('core.views_counter')) { + require_once SYSTEM . 'counter.php'; +} + +if(setting('core.visitors_counter')) { + $visitors = new Visitors(setting('core.visitors_counter_ttl')); +} + require_once SYSTEM . 'router.php'; // anonymous usage statistics @@ -153,22 +162,6 @@ if(setting('core.anonymous_usage_statistics')) { } } -if(setting('core.views_counter')) - require_once SYSTEM . 'counter.php'; - -if(setting('core.visitors_counter')) { - $visitors = new Visitors(setting('core.visitors_counter_ttl')); -} - -/** - * @var OTS_Account $account_logged - */ -if ($logged && admin()) { - $content .= $twig->render('admin-bar.html.twig', [ - 'username' => USE_ACCOUNT_NAME ? $account_logged->getName() : $account_logged->getId() - ]); -} - $title_full = (isset($title) ? $title . ' - ' : '') . $config['lua']['serverName']; require $template_path . '/' . $template_index; diff --git a/install/includes/import_base_data.php b/install/includes/import_base_data.php new file mode 100644 index 00000000..45c803ed --- /dev/null +++ b/install/includes/import_base_data.php @@ -0,0 +1,69 @@ + 3, + 'where' => 2, + 'date' => time(), + 'body' => 'MyAAC installed. (:', + 'hide' => 0, + ]); +} + +if (Config::where('name', 'database_version')->count() === 0) { + Config::create([ + 'name' => 'database_version', + 'value' => DATABASE_VERSION, + ]); +} + +if (ForumBoard::count() === 0) { + $forumBoards = [ + ['name' => 'News', 'description' => 'News commenting', 'closed' => 1], + ['name' => 'Trade', 'description' => 'Trade offers.', 'closed' => 0], + ['name' => 'Quests', 'description' => 'Quest making.', 'closed' => 0], + ['name' => 'Pictures', 'description' => 'Your pictures.', 'closed' => 0], + ['name' => 'Bug Report', 'description' => 'Report bugs there.', 'closed' => 0], + ]; + + $i = 0; + foreach ($forumBoards as $forumBoard) { + ForumBoard::create([ + 'name' => $forumBoard['name'], + 'description' => $forumBoard['description'], + 'ordering' => $i++, + 'closed' => $forumBoard['closed'], + ]); + } +} + +if (NewsCategory::count() === 0) { + $newsCategoriesIcons = [ + 0, 1, 2, 3, 4 + ]; + + foreach ($newsCategoriesIcons as $iconId) { + NewsCategory::create([ + 'icon_id' => $iconId, + ]); + } +} + +if (Gallery::count() === 0) { + Gallery::create([ + 'comment' => 'Demon', + 'image' => 'images/gallery/demon.jpg', + 'thumb' => 'images/gallery/demon_thumb.gif', + 'author' => 'MyAAC', + 'ordering' => 0, + ]); +} + +success($locale['step_database_success_import_data']); diff --git a/install/includes/schema.sql b/install/includes/schema.sql index 00a50f50..088dc27d 100644 --- a/install/includes/schema.sql +++ b/install/includes/schema.sql @@ -1,6 +1,4 @@ -SET @myaac_database_version = 43; - -CREATE TABLE `myaac_account_actions` +CREATE TABLE IF NOT EXISTS `myaac_account_actions` ( `id` int NOT NULL AUTO_INCREMENT, `account_id` int NOT NULL, @@ -10,7 +8,16 @@ CREATE TABLE `myaac_account_actions` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_admin_menu` +CREATE TABLE IF NOT EXISTS `myaac_account_emails_verify` +( + `id` int NOT NULL AUTO_INCREMENT, + `account_id` int NOT NULL, + `hash` varchar(32) NOT NULL, + `sent_at` int NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; + +CREATE TABLE IF NOT EXISTS `myaac_admin_menu` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL DEFAULT '', @@ -21,7 +28,7 @@ CREATE TABLE `myaac_admin_menu` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_changelog` +CREATE TABLE IF NOT EXISTS `myaac_changelog` ( `id` int NOT NULL AUTO_INCREMENT, `body` varchar(500) NOT NULL DEFAULT '', @@ -33,9 +40,7 @@ CREATE TABLE `myaac_changelog` PRIMARY KEY (`id`) ) 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); - -CREATE TABLE `myaac_config` +CREATE TABLE IF NOT EXISTS `myaac_config` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(30) NOT NULL, @@ -44,9 +49,7 @@ CREATE TABLE `myaac_config` UNIQUE (`name`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -INSERT INTO `myaac_config` (`name`, `value`) VALUES ('database_version', @myaac_database_version); - -CREATE TABLE `myaac_faq` +CREATE TABLE IF NOT EXISTS `myaac_faq` ( `id` int NOT NULL AUTO_INCREMENT, `question` varchar(255) NOT NULL DEFAULT '', @@ -56,7 +59,7 @@ CREATE TABLE `myaac_faq` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_forum_boards` +CREATE TABLE IF NOT EXISTS `myaac_forum_boards` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL, @@ -68,13 +71,8 @@ CREATE TABLE `myaac_forum_boards` `hide` tinyint NOT NULL DEFAULT 0, PRIMARY KEY (`id`) ) 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); -INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Pictures', 'Your pictures.', 3); -INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Bug Report', 'Report bugs there.', 4); -CREATE TABLE `myaac_forum` +CREATE TABLE IF NOT EXISTS `myaac_forum` ( `id` int NOT NULL AUTO_INCREMENT, `first_post` int NOT NULL DEFAULT 0, @@ -98,7 +96,7 @@ CREATE TABLE `myaac_forum` KEY `section` (`section`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_menu` +CREATE TABLE IF NOT EXISTS `myaac_menu` ( `id` int NOT NULL AUTO_INCREMENT, `template` varchar(255) NOT NULL, @@ -112,7 +110,7 @@ CREATE TABLE `myaac_menu` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_monsters` ( +CREATE TABLE IF NOT EXISTS `myaac_monsters` ( `id` int NOT NULL AUTO_INCREMENT, `hide` tinyint NOT NULL DEFAULT 0, `name` varchar(255) NOT NULL, @@ -145,7 +143,7 @@ CREATE TABLE `myaac_monsters` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_news` +CREATE TABLE IF NOT EXISTS `myaac_news` ( `id` int NOT NULL AUTO_INCREMENT, `title` varchar(100) NOT NULL, @@ -163,7 +161,7 @@ CREATE TABLE `myaac_news` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_news_categories` +CREATE TABLE IF NOT EXISTS `myaac_news_categories` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL DEFAULT "", @@ -173,13 +171,7 @@ CREATE TABLE `myaac_news_categories` PRIMARY KEY (`id`) ) 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); -INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 2); -INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 3); -INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 4); - -CREATE TABLE `myaac_notepad` +CREATE TABLE IF NOT EXISTS `myaac_notepad` ( `id` int NOT NULL AUTO_INCREMENT, `account_id` int NOT NULL, @@ -189,7 +181,7 @@ CREATE TABLE `myaac_notepad` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_pages` +CREATE TABLE IF NOT EXISTS `myaac_pages` ( `id` INT NOT NULL AUTO_INCREMENT, `name` varchar(30) NOT NULL, @@ -205,7 +197,7 @@ CREATE TABLE `myaac_pages` UNIQUE (`name`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_gallery` +CREATE TABLE IF NOT EXISTS `myaac_gallery` ( `id` int NOT NULL AUTO_INCREMENT, `comment` varchar(255) NOT NULL DEFAULT '', @@ -217,9 +209,7 @@ CREATE TABLE `myaac_gallery` PRIMARY KEY (`id`) ) 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'); - -CREATE TABLE `myaac_settings` +CREATE TABLE IF NOT EXISTS `myaac_settings` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL DEFAULT '', @@ -229,7 +219,7 @@ CREATE TABLE `myaac_settings` KEY `key` (`key`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_spells` +CREATE TABLE IF NOT EXISTS `myaac_spells` ( `id` int NOT NULL AUTO_INCREMENT, `spell` varchar(255) NOT NULL DEFAULT '', @@ -252,7 +242,7 @@ CREATE TABLE `myaac_spells` UNIQUE (`name`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_visitors` +CREATE TABLE IF NOT EXISTS `myaac_visitors` ( `ip` varchar(45) NOT NULL, `lastvisit` int NOT NULL DEFAULT 0, @@ -261,7 +251,7 @@ CREATE TABLE `myaac_visitors` UNIQUE (`ip`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_weapons` +CREATE TABLE IF NOT EXISTS `myaac_weapons` ( `id` int NOT NULL, `level` int NOT NULL DEFAULT 0, diff --git a/install/steps/4-config.php b/install/steps/4-config.php index 325b97f1..342edd06 100644 --- a/install/steps/4-config.php +++ b/install/steps/4-config.php @@ -10,6 +10,14 @@ foreach($config['clients'] as $client) { $clients[$client] = $client_version; } +if (empty($_SESSION['var_site_url'])) { + //require SYSTEM . 'base.php'; + $serverUrl = 'http' . (isHttps() ? 's' : '') . '://' . $baseHost; + $siteURL = $serverUrl . $baseDir; + + $_SESSION['var_site_url'] = $siteURL; +} + $twig->display('install.config.html.twig', array( 'clients' => $clients, 'timezones' => DateTimeZone::listIdentifiers(), diff --git a/install/steps/5-database.php b/install/steps/5-database.php index cb4f14a3..ecf7f150 100644 --- a/install/steps/5-database.php +++ b/install/steps/5-database.php @@ -42,45 +42,44 @@ if(!$error) { $configToSave['cache_prefix'] = 'myaac_' . generateRandomString(8, true, false, true); $configToSave['database_auto_migrate'] = true; - if(!$error) { - $content = ''; - $saved = Settings::saveConfig($configToSave, BASE . 'config.local.php', $content); - if ($saved) { - success($locale['step_database_config_saved']); - $_SESSION['saved'] = true; + $content = ''; + $saved = Settings::saveConfig($configToSave, BASE . 'config.local.php', $content); + if ($saved || file_exists(BASE . 'config.local.php')) { + success($locale['step_database_config_saved']); + $_SESSION['saved'] = true; - require BASE . 'config.local.php'; - require BASE . 'install/includes/config.php'; + require BASE . 'config.local.php'; + require BASE . 'install/includes/config.php'; - if (!$error) { - require BASE . 'install/includes/database.php'; + if (!$error) { + require BASE . 'install/includes/database.php'; - if (isset($database_error)) { // we failed connect to the database - error($database_error); + if (isset($database_error)) { // we failed connect to the database + error($database_error); + } + else { + if (!$db->hasTable('accounts')) { + $tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']); + error($tmp); + $error = true; } - else { - if (!$db->hasTable('accounts')) { - $tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']); - error($tmp); - $error = true; - } - if (!$error) { - $twig->display('install.installer.html.twig', array( - 'url' => 'tools/5-database.php', - 'message' => $locale['loading_spinner'] - )); - } + if (!$error) { + $twig->display('install.installer.html.twig', array( + 'url' => 'tools/5-database.php', + 'message' => $locale['loading_spinner'] + )); } } - } else { - $_SESSION['config_content'] = $content; - unset($_SESSION['saved']); - - $locale['step_database_error_file'] = str_replace('$FILE$', '' . BASE . 'config.php', $locale['step_database_error_file']); - error($locale['step_database_error_file'] . '
- '); } + } else { + $error = true; + $_SESSION['config_content'] = $content; + unset($_SESSION['saved']); + + $locale['step_database_error_file'] = str_replace('$FILE$', '' . BASE . 'config.local.php', $locale['step_database_error_file']); + error($locale['step_database_error_file'] . '
+ '); } } ?> diff --git a/install/steps/7-finish.php b/install/steps/7-finish.php index 0ae302ea..afe63603 100644 --- a/install/steps/7-finish.php +++ b/install/steps/7-finish.php @@ -195,13 +195,4 @@ if(!isset($_SESSION['installed'])) { $_SESSION['installed'] = true; } -foreach($_SESSION as $key => $value) { - if(strpos($key, 'var_') !== false) - unset($_SESSION[$key]); -} -unset($_SESSION['saved']); -if(file_exists(CACHE . 'install.txt')) { - unlink(CACHE . 'install.txt'); -} - $hooks->trigger(HOOK_INSTALL_FINISH_END); diff --git a/install/tools/5-database.php b/install/tools/5-database.php index 395492ee..6406ee48 100644 --- a/install/tools/5-database.php +++ b/install/tools/5-database.php @@ -7,6 +7,11 @@ require SYSTEM . 'functions.php'; require BASE . 'install/includes/functions.php'; require BASE . 'install/includes/locale.php'; +if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) { + warning($locale['already_installed']); + return; +} + $error = false; require BASE . 'install/includes/config.php'; @@ -25,26 +30,22 @@ if(!$error) { } } -if($db->hasTable(TABLE_PREFIX . 'account_actions')) { - $locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']); - warning($locale['step_database_error_table_exist']); -} -else { - // import schema - try { - $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']); - success($locale['step_database_importing']); +// import schema +try { + $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']); + success($locale['step_database_importing']); - $db->query(file_get_contents(BASE . 'install/includes/schema.sql')); + $db->exec(file_get_contents(BASE . 'install/includes/schema.sql')); - $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); - success($locale['step_database_success_schema']); - } - catch(PDOException $error_) { - error($locale['step_database_error_schema'] . ' ' . $error_); - return; - } + $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); + success($locale['step_database_success_schema']); } +catch(PDOException $error_) { + error($locale['step_database_error_schema'] . ' ' . $error_); + return; +} + +require BASE . 'install/includes/import_base_data.php'; if(!$db->hasColumn('accounts', 'email')) { if(query("ALTER TABLE `accounts` ADD `email` varchar(255) NOT NULL DEFAULT '';")) @@ -97,18 +98,13 @@ if(!$db->hasColumn('accounts', 'web_flags')) { success($locale['step_database_adding_field'] . ' accounts.web_flags...'); } -if(!$db->hasColumn('accounts', 'email_hash')) { - if(query("ALTER TABLE `accounts` ADD `email_hash` VARCHAR(32) NOT NULL DEFAULT '' AFTER `web_flags`;")) - success($locale['step_database_adding_field'] . ' accounts.email_hash...'); -} - if(!$db->hasColumn('accounts', 'email_verified')) { - if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `email_hash`;")) + if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `web_flags`;")) success($locale['step_database_adding_field'] . ' accounts.email_verified...'); } if(!$db->hasColumn('accounts', 'email_new')) { - if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_hash`;")) + if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_verified`;")) success($locale['step_database_adding_field'] . ' accounts.email_new...'); } diff --git a/install/tools/7-finish.php b/install/tools/7-finish.php index 6f6b2d30..9c64382b 100644 --- a/install/tools/7-finish.php +++ b/install/tools/7-finish.php @@ -17,11 +17,11 @@ ini_set('max_execution_time', 300); ob_implicit_flush(); header('X-Accel-Buffering: no'); -/* + if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) { warning($locale['already_installed']); return; -}*/ +} require SYSTEM . 'init.php'; @@ -79,6 +79,10 @@ $up(); require_once SYSTEM . 'migrations/31.php'; $up(); +// rules page +require_once SYSTEM . 'migrations/45.php'; +$up(); + if(ModelsFAQ::count() == 0) { ModelsFAQ::create([ 'question' => 'What is this?', @@ -90,6 +94,17 @@ $hooks->trigger(HOOK_INSTALL_FINISH); $db->setClearCacheAfter(true); +// cleanup +foreach($_SESSION as $key => $value) { + if(str_contains($key, 'var_')) { + unset($_SESSION[$key]); + } +} +unset($_SESSION['saved']); +if(file_exists(CACHE . 'install.txt')) { + unlink(CACHE . 'install.txt'); +} + $locale['step_finish_desc'] = str_replace('$ADMIN_PANEL$', generateLink(str_replace('tools/', '',ADMIN_URL), $locale['step_finish_admin_panel'], true), $locale['step_finish_desc']); $locale['step_finish_desc'] = str_replace('$HOMEPAGE$', generateLink(str_replace('tools/', '', BASE_URL), $locale['step_finish_homepage'], true), $locale['step_finish_desc']); $locale['step_finish_desc'] = str_replace('$LINK$', generateLink('https://my-aac.org', 'https://my-aac.org', true), $locale['step_finish_desc']); diff --git a/login.php b/login.php index d51ae57b..438754e2 100644 --- a/login.php +++ b/login.php @@ -86,12 +86,25 @@ switch ($action) { die(json_encode(['eventlist' => $eventlist, 'lastupdatetimestamp' => time()])); case 'boostedcreature': + $clientVersion = (int)setting('core.client'); + + // 13.40 and up + if ($clientVersion >= 1340) { + $creatureBoost = $db->query("SELECT * FROM " . $db->tableName('boosted_creature'))->fetchAll(); + $bossBoost = $db->query("SELECT * FROM " . $db->tableName('boosted_boss'))->fetchAll(); + die(json_encode([ + 'boostedcreature' => true, + 'creatureraceid' => intval($creatureBoost[0]['raceid']), + 'bossraceid' => intval($bossBoost[0]['raceid']) + ])); + } + + // lower clients $boostedCreature = BoostedCreature::first(); die(json_encode([ 'boostedcreature' => true, 'raceid' => $boostedCreature->raceid ])); - break; case 'login': @@ -207,6 +220,8 @@ switch ($action) { } } + /* + * not needed anymore? if (fieldExist('premdays', 'accounts') && fieldExist('lastday', 'accounts')) { $save = false; $timeNow = time(); @@ -243,6 +258,7 @@ switch ($action) { $account->save(); } } + */ $worlds = [$world]; $playdata = compact('worlds', 'characters'); diff --git a/package-lock.json b/package-lock.json index a8c17859..3ea74539 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,24 +14,13 @@ "tinymce": "^7.2.0" }, "devDependencies": { - "cypress": "^13.17.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.1.90" + "cypress": "^14.3.3" } }, "node_modules/@cypress/request": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.7.tgz", - "integrity": "sha512-LzxlLEMbBOPYB85uXrDqvD4MgcenjRBLIns3zyhx7vTPj/0u2eQhzXvPiGcaJrV38Q9dbkExWp6cOHPJ+EtFYg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.8.tgz", + "integrity": "sha512-h0NFgh1mJmm1nr4jCwkGHwKneVYKghUyWe6TMNrk0B9zsjAJxpg8C4/+BAcmLgCPa1vj1V8rNUaILl+zYRUWBQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -48,7 +37,7 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "6.13.1", + "qs": "6.14.0", "safe-buffer": "^5.1.2", "tough-cookie": "^5.0.0", "tunnel-agent": "^0.6.0", @@ -387,9 +376,9 @@ } }, "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -401,14 +390,14 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -504,9 +493,9 @@ } }, "node_modules/cli-table3": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", - "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", + "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", "dev": true, "license": "MIT", "dependencies": { @@ -516,7 +505,7 @@ "node": "10.* || >= 12.*" }, "optionalDependencies": { - "@colors/colors": "1.5.0" + "colors": "1.4.0" } }, "node_modules/cli-truncate": { @@ -563,6 +552,17 @@ "dev": true, "license": "MIT" }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -619,14 +619,14 @@ } }, "node_modules/cypress": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.17.0.tgz", - "integrity": "sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==", + "version": "14.3.3", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-14.3.3.tgz", + "integrity": "sha512-1Rz7zc9iqLww6BysaESqUhtIuaFHS7nL3wREovAKYsNhLTfX3TbcBWHWgEz70YimH2NkSOsm4oIcJJ9HYHOlew==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "@cypress/request": "^3.0.6", + "@cypress/request": "^3.0.8", "@cypress/xvfb": "^1.2.4", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", @@ -637,9 +637,9 @@ "cachedir": "^2.3.0", "chalk": "^4.1.0", "check-more-types": "^2.24.0", - "ci-info": "^4.0.0", + "ci-info": "^4.1.0", "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.1", + "cli-table3": "0.6.1", "commander": "^6.2.1", "common-tags": "^1.8.0", "dayjs": "^1.10.4", @@ -663,7 +663,7 @@ "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", - "semver": "^7.5.3", + "semver": "^7.7.1", "supports-color": "^8.1.1", "tmp": "~0.2.3", "tree-kill": "1.2.2", @@ -674,7 +674,7 @@ "cypress": "bin/cypress" }, "engines": { - "node": "^16.0.0 || ^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" } }, "node_modules/cypress/node_modules/fs-extra": { @@ -819,9 +819,9 @@ } }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "license": "MIT", "dependencies": { @@ -831,6 +831,22 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -960,14 +976,16 @@ } }, "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -999,18 +1017,18 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "get-proto": "^1.0.0", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", @@ -1131,6 +1149,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -1560,9 +1594,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", "engines": { @@ -1709,13 +1743,13 @@ } }, "node_modules/qs": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.1.tgz", - "integrity": "sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -1794,9 +1828,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -2031,29 +2065,29 @@ "license": "GPL-2.0-or-later" }, "node_modules/tldts": { - "version": "6.1.71", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.71.tgz", - "integrity": "sha512-LQIHmHnuzfZgZWAf2HzL83TIIrD8NhhI0DVxqo9/FdOd4ilec+NTNZOlDZf7EwrTNoutccbsHjvWHYXLAtvxjw==", + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^6.1.71" + "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.71", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.71.tgz", - "integrity": "sha512-LRbChn2YRpic1KxY+ldL1pGXN/oVvKfCVufwfVzEQdFYNo39uF7AJa/WXdo+gYO7PTvdfkCPCed6Hkvz/kR7jg==", + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", "dev": true, "license": "MIT" }, "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", + "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==", "dev": true, "license": "MIT", "engines": { @@ -2061,9 +2095,9 @@ } }, "node_modules/tough-cookie": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.0.tgz", - "integrity": "sha512-rvZUv+7MoBYTiDmFPBrhL7Ujx9Sk+q9wwm22x8c8T5IJaR+Wsyc7TNxbVxo84kZoRJZZMazowFLqpankBEQrGg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { diff --git a/package.json b/package.json index 7bf43b48..82c079dd 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "postinstall": "node ./npm-post-install.js" }, "devDependencies": { - "cypress": "^13.17.0" + "cypress": "^14.3.3" }, "dependencies": { "@tinymce/tinymce-jquery": "^2.1.0", diff --git a/phpstan.neon b/phpstan.neon index 020fa3a6..68e1aa6a 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -28,10 +28,9 @@ parameters: - '#Variable \$guild might not be defined#' - '#Variable \$[a-zA-Z0-9\\_]+ might not be defined#' # Eloquent models + - '#Call to an undefined 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\(\)#' - '#Access to an undefined property Illuminate\\Database\\Eloquent\\Model::\$online_status#' - '#Access to an undefined property Illuminate\\Database\\Eloquent\\Model::\$vocation_name#' - diff --git a/plugins/example.json b/plugins/example.json index 395db41d..fd5e183b 100644 --- a/plugins/example.json +++ b/plugins/example.json @@ -51,5 +51,8 @@ "themes": true, "admin-pages": true, "admin-pages-sub-folders": true, + "settings": true, + "install": true, + "init": false } } diff --git a/system/base.php b/system/base.php new file mode 100644 index 00000000..9cab2925 --- /dev/null +++ b/system/base.php @@ -0,0 +1,21 @@ + 'account_change_character_name_price', 'account_change_character_sex', 'account_change_character_sex_points' => 'account_change_character_name_price', + 'email_lai_sec_interval' => 'mail_lost_account_interval', ]; foreach ($deprecatedConfig as $key => $value) { diff --git a/system/database.php b/system/database.php index b9dc6cc6..8fa8f869 100644 --- a/system/database.php +++ b/system/database.php @@ -122,6 +122,10 @@ try { $eloquentConnection = $capsule->getConnection(); + if (isset($twig)) { + $twig->addGlobal('db', $db); + } + } catch (Exception $e) { if(isset($cache) && $cache->enabled()) { $cache->delete('config_lua'); diff --git a/system/functions.php b/system/functions.php index 6e58ca9d..582f9c30 100644 --- a/system/functions.php +++ b/system/functions.php @@ -512,6 +512,13 @@ function template_place_holder($type): string } elseif ($type === 'body_start') { $ret .= $twig->render('browsehappy.html.twig'); + + if (admin()) { + global $account_logged; + $ret .= $twig->render('admin-bar.html.twig', [ + 'username' => USE_ACCOUNT_NAME ? $account_logged->getName() : $account_logged->getId() + ]); + } } elseif($type === 'body_end') { $ret .= template_ga_code(); @@ -767,6 +774,10 @@ function formatExperience($exp, $color = true) return $ret; } +function getExperienceForLevel($level): float|int { + return ( 50 / 3 ) * pow( $level, 3 ) - ( 100 * pow( $level, 2 ) ) + ( ( 850 / 3 ) * $level ) - 200; +} + function get_locales() { $ret = array(); @@ -982,11 +993,12 @@ function load_config_lua($filename) foreach($lines as $ln => $line) { $line = trim($line); - if(@$line[0] === '{' || @$line[0] === '}') { + if(isset($line[0]) && ($line[0] === '{' || $line[0] === '}')) { // arrays are not supported yet // just ignore the error continue; } + $tmp_exp = explode('=', $line, 2); if(str_contains($line, 'dofile')) { $delimiter = '"'; @@ -1130,10 +1142,18 @@ function getTopPlayers($limit = 5, $skill = 'level') { 'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet' ]; + if ($db->hasColumn('players', 'promotion')) { + $columns[] = 'promotion'; + } + if ($db->hasColumn('players', 'lookaddons')) { $columns[] = 'lookaddons'; } + if ($db->hasColumn('players', 'lookmount')) { + $columns[] = 'lookmount'; + } + return Player::query() ->select($columns) ->withOnlineStatus() @@ -1216,7 +1236,8 @@ function setting($key) return $settings[$key[0]] = $key[1]; } - return $settings[$key]['value']; + $ret = $settings[$key]; + return isset($ret) ? $ret['value'] : null; } function clearCache() @@ -1265,14 +1286,15 @@ function clearCache() $db->setClearCacheAfter(true); } + if (function_exists('apcu_clear_cache')) { + apcu_clear_cache(); + } + deleteDirectory(CACHE . 'signatures', ['index.html'], true); deleteDirectory(CACHE . 'twig', ['index.html'], true); deleteDirectory(CACHE . 'plugins', ['index.html'], true); deleteDirectory(CACHE, ['signatures', 'twig', 'plugins', 'index.html', 'persistent'], true); - // routes cache - clearRouteCache(); - global $hooks; $hooks->trigger(HOOK_CACHE_CLEAR, ['cache' => Cache::getInstance()]); @@ -1618,13 +1640,14 @@ function camelCaseToUnderscore($input) return ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $input)), '_'); } -function removeIfFirstSlash(&$text) { +function removeIfFirstSlash(&$text): void +{ if(strpos($text, '/') === 0) { $text = str_replace_first('/', '', $text); } }; -function escapeHtml($html) { +function escapeHtml($html): string { return htmlspecialchars($html); } @@ -1638,7 +1661,7 @@ function getGuildNameById($id) return false; } -function getGuildLogoById($id) +function getGuildLogoById($id): string { $logo = 'default.gif'; @@ -1654,7 +1677,8 @@ function getGuildLogoById($id) return BASE_URL . GUILD_IMAGES_DIR . $logo; } -function displayErrorBoxWithBackButton($errors, $action = null) { +function displayErrorBoxWithBackButton($errors, $action = null): void +{ global $twig; $twig->display('error_box.html.twig', ['errors' => $errors]); $twig->display('account.back_button.html.twig', [ @@ -1682,6 +1706,12 @@ function getAccountIdentityColumn(): string return 'id'; } +function isCanary(): bool +{ + $vipSystemEnabled = configLua('vipSystemEnabled'); + return isset($vipSystemEnabled); +} + // validator functions require_once SYSTEM . 'compat/base.php'; diff --git a/system/init.php b/system/init.php index ba2990db..57c299ba 100644 --- a/system/init.php +++ b/system/init.php @@ -12,6 +12,7 @@ use DebugBar\StandardDebugBar; use MyAAC\Cache\Cache; use MyAAC\CsrfToken; use MyAAC\Hooks; +use MyAAC\Plugins; use MyAAC\Models\Town; use MyAAC\Settings; @@ -46,6 +47,11 @@ if(isset($config['gzip_output']) && $config['gzip_output'] && isset($_SERVER['HT global $cache; $cache = Cache::getInstance(); +// load plugins init.php +foreach (Plugins::getInits() as $init) { + require $init; +} + // event system global $hooks; $hooks = new Hooks(); @@ -138,6 +144,18 @@ $ots = POT::getInstance(); $eloquentConnection = null; require_once SYSTEM . 'database.php'; +define('USE_ACCOUNT_NAME', $db->hasColumn('accounts', 'name')); +define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number')); +define('USE_ACCOUNT_SALT', $db->hasColumn('accounts', 'salt')); + +define('HAS_ACCOUNT_COINS', $db->hasColumn('accounts', 'coins')); +define('HAS_ACCOUNT_COINS_TRANSFERABLE', $db->hasColumn('accounts', 'coins_transferable')); +define('HAS_ACCOUNT_TRANSFERABLE_COINS', $db->hasColumn('accounts', 'transferable_coins')); +const ACCOUNT_COINS_TRANSFERABLE_COLUMN = (HAS_ACCOUNT_COINS_TRANSFERABLE ? 'coins_transferable' : 'transferable_coins'); + +$twig->addGlobal('logged', false); +$twig->addGlobal('account_logged', new \OTS_Account()); + // verify myaac tables exists in database if(!defined('MYAAC_INSTALL') && !$db->hasTable('myaac_account_actions')) { throw new RuntimeException('Seems that the table myaac_account_actions of MyAAC doesn\'t exist in the database. This is a fatal error. You can try to reinstall MyAAC by visiting ' . (IS_CLI ? 'http://your-ip.com/' : BASE_URL) . 'install'); @@ -179,10 +197,6 @@ if($settingsItemImagesURL[strlen($settingsItemImagesURL) - 1] !== '/') { setting(['core.item_images_url', $settingsItemImagesURL . '/']); } -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 = Cache::remember('towns', 10 * 60, function () use ($db) { if ($db->hasTable('towns') && Town::count() > 0) { return Town::orderBy('id', 'ASC')->pluck('name', 'id')->toArray(); diff --git a/system/libs/pot/OTS.php b/system/libs/pot/OTS.php index 9c988210..fb93afea 100644 --- a/system/libs/pot/OTS.php +++ b/system/libs/pot/OTS.php @@ -32,19 +32,19 @@ class POT /** * North. */ - const DIRECTION_NORTH = 0; + const DIRECTION_NORTH = 0; /** * East. */ - const DIRECTION_EAST = 1; + const DIRECTION_EAST = 1; /** * South. */ - const DIRECTION_SOUTH = 2; + const DIRECTION_SOUTH = 2; /** * West. */ - const DIRECTION_WEST = 3; + const DIRECTION_WEST = 3; /** @@ -80,70 +80,70 @@ class POT * @version 0.0.3 * @since 0.0.3 */ - const SLOT_HEAD = 1; + const SLOT_HEAD = 1; /** * Necklace slot. * * @version 0.0.3 * @since 0.0.3 */ - const SLOT_NECKLACE = 2; + const SLOT_NECKLACE = 2; /** * Backpack slot. * * @version 0.0.3 * @since 0.0.3 */ - const SLOT_BACKPACK = 3; + const SLOT_BACKPACK = 3; /** * Armor slot. * * @version 0.0.3 * @since 0.0.3 */ - const SLOT_ARMOR = 4; + const SLOT_ARMOR = 4; /** * Right hand slot. * * @version 0.0.3 * @since 0.0.3 */ - const SLOT_RIGHT = 5; + const SLOT_RIGHT = 5; /** * Left hand slot. * * @version 0.0.3 * @since 0.0.3 */ - const SLOT_LEFT = 6; + const SLOT_LEFT = 6; /** * Legs slot. * * @version 0.0.3 * @since 0.0.3 */ - const SLOT_LEGS = 7; + const SLOT_LEGS = 7; /** * Boots slot. * * @version 0.0.3 * @since 0.0.3 */ - const SLOT_FEET = 8; + const SLOT_FEET = 8; /** * Ring slot. * * @version 0.0.3 * @since 0.0.3 */ - const SLOT_RING = 9; + const SLOT_RING = 9; /** * Ammunition slot. * * @version 0.0.3 * @since 0.0.3 */ - const SLOT_AMMO = 10; + const SLOT_AMMO = 10; /** * First depot item sid. @@ -151,7 +151,7 @@ class POT * @version 0.0.4 * @since 0.0.4 */ - const DEPOT_SID_FIRST = 100; + const DEPOT_SID_FIRST = 100; /** * IP ban. @@ -159,21 +159,21 @@ class POT * @version 0.0.5 * @since 0.0.5 */ - const BAN_IP = 1; + const BAN_IP = 1; /** * Player ban. * * @version 0.0.5 * @since 0.0.5 */ - const BAN_PLAYER = 2; + const BAN_PLAYER = 2; /** * Account ban. * * @version 0.0.5 * @since 0.0.5 */ - const BAN_ACCOUNT = 3; + const BAN_ACCOUNT = 3; /** * Ascencind sorting order. @@ -181,33 +181,33 @@ class POT * @version 0.0.5 * @since 0.0.5 */ - const ORDER_ASC = 1; + const ORDER_ASC = 1; /** * Descending sorting order. * * @version 0.0.5 * @since 0.0.5 */ - const ORDER_DESC = 2; + const ORDER_DESC = 2; /** * @version 0.0.7 * @since 0.0.7 * @deprecated 0.1.0 Use OTS_SpellsList::SPELL_RUNE. */ - const SPELL_RUNE = 0; + const SPELL_RUNE = 0; /** * @version 0.0.7 * @since 0.0.7 * @deprecated 0.1.0 Use OTS_SpellsList::SPELL_INSTANT. */ - const SPELL_INSTANT = 1; + const SPELL_INSTANT = 1; /** * @version 0.0.7 * @since 0.0.7 * @deprecated 0.1.0 Use OTS_SpellsList::SPELL_CONJURE. */ - const SPELL_CONJURE = 2; + const SPELL_CONJURE = 2; /** * Singleton. @@ -220,18 +220,18 @@ class POT * @example examples/quickstart.php quickstart.php * @tutorial POT/Basics.pkg#basics.instance */ - public static function getInstance() - { - static $instance; + public static function getInstance() + { + static $instance; - // creates new instance - if( !isset($instance) ) - { - $instance = new self(); - } + // creates new instance + if( !isset($instance) ) + { + $instance = new self(); + } - return $instance; - } + return $instance; + } /** * POT classes directory. @@ -242,7 +242,7 @@ class POT * * @var string */ - private $path = ''; + private $path = ''; /** * Set POT directory. @@ -255,16 +255,16 @@ class POT * @example examples/fakeroot.php fakeroot.php * @tutorial POT/Basics.pkg#basics.fakeroot */ - public function setPOTPath($path) - { - $this->path = str_replace('\\', '/', $path); + public function setPOTPath($path) + { + $this->path = str_replace('\\', '/', $path); - // appends ending slash to directory path - if( substr($this->path, -1) !== '/') - { - $this->path .= '/'; - } - } + // appends ending slash to directory path + if( substr($this->path, -1) !== '/') + { + $this->path .= '/'; + } + } /** * Class initialization tools. @@ -283,13 +283,13 @@ class POT * * @version 0.0.3 */ - private function __construct() - { - // default POT directory - $this->path = __DIR__ . '/'; - // registers POT autoload mechanism - spl_autoload_register( array($this, 'loadClass') ); - } + private function __construct() + { + // default POT directory + $this->path = __DIR__ . '/'; + // registers POT autoload mechanism + spl_autoload_register( array($this, 'loadClass') ); + } /** * Loads POT class file. @@ -309,13 +309,13 @@ class POT * @version 0.0.3 * @param string $class Class name. */ - public function loadClass($class) - { - if( preg_match('/^(I|E_)?OTS_/', $class) > 0) - { - include_once($this->path . $class . '.php'); - } - } + public function loadClass($class) + { + if( preg_match('/^(I|E_)?OTS_/', $class) > 0) + { + include_once($this->path . $class . '.php'); + } + } /** * Database connection. @@ -326,7 +326,7 @@ class POT * * @var OTS_DB_MySQL */ - private $db; + private $db; /** * Connects to database. @@ -363,14 +363,14 @@ class POT * @example examples/quickstart.php quickstart.php * @tutorial POT/Basics.pkg#basics.database */ - public function connect($params) - { - // checks if PDO extension is loaded - if( !extension_loaded('PDO') ) { - throw new RuntimeException('Please install PHP pdo extension. MyAAC will not work without it.'); - } + public function connect($params) + { + // checks if PDO extension is loaded + if( !extension_loaded('PDO') ) { + throw new RuntimeException('Please install PHP pdo extension. MyAAC will not work without it.'); + } - global $debugBar; + global $debugBar; if (isset($debugBar)) { $this->db = new DebugBar\DataCollector\PDO\TraceablePDO(new OTS_DB_MySQL($params)); $debugBar->addCollector(new DebugBar\DataCollector\PDO\PDOCollector($this->db)); @@ -379,8 +379,8 @@ class POT $this->db = new OTS_DB_MySQL($params); } - $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - } + $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } /** * @version 0.1.0 @@ -388,11 +388,11 @@ class POT * @return IOTS_DAO OTServ database object. * @deprecated 0.1.0 Create objects directly from now. */ - public function createObject($class) - { - $class = 'OTS_' . $class; - return new $class(); - } + public function createObject($class) + { + $class = 'OTS_' . $class; + return new $class(); + } /** * Queries server status. @@ -415,11 +415,13 @@ class POT * @tutorial POT/Server_status.pkg * @deprecated 0.1.4 Use OTS_ServerInfo->status(). */ - public static function serverStatus($server, $port) - { - $status = new OTS_ServerInfo($server, $port); - return $status->status(); - } + public static function serverStatus($server, $port, $timeout = 2.0) + { + $status = new OTS_ServerInfo($server, $port); + $status->setTimeout($timeout); + + return $status->status(); + } /** * Returns database connection handle. @@ -440,10 +442,10 @@ class POT * @since 0.0.4 * @return OTS_DB_MySQL Database connection handle. */ - public function getDBHandle() - { - return $this->db; - } + public function getDBHandle() + { + return $this->db; + } /** * Bans given IP number. @@ -464,37 +466,37 @@ class POT * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_IPBan class. */ - public function banIP($ip, $mask = '255.255.255.255', $time = 0) - { - // long2ip( ip2long('255.255.255.255') ) != '255.255.255.255' -.-' - // it's because that PHP integer types are signed - if($ip === '255.255.255.255') - { - $ip = 4294967295; - } - else - { - $ip = sprintf('%u', ip2long($ip) ); - } + public function banIP($ip, $mask = '255.255.255.255', $time = 0) + { + // long2ip( ip2long('255.255.255.255') ) != '255.255.255.255' -.-' + // it's because that PHP integer types are signed + if($ip === '255.255.255.255') + { + $ip = 4294967295; + } + else + { + $ip = sprintf('%u', ip2long($ip) ); + } - if($mask === '255.255.255.255') - { - $mask = 4294967295; - } - else - { - $mask = sprintf('%u', ip2long($mask) ); - } + if($mask === '255.255.255.255') + { + $mask = 4294967295; + } + else + { + $mask = sprintf('%u', ip2long($mask) ); + } - // creates ban entry - $ban = new OTS_IPBan(); - $ban->setValue($ip); - $ban->setParam($mask); - $ban->setExpires($time); - $ban->setAdded( time() ); - $ban->activate(); - $ban->save(); - } + // creates ban entry + $ban = new OTS_IPBan(); + $ban->setValue($ip); + $ban->setParam($mask); + $ban->setExpires($time); + $ban->setAdded( time() ); + $ban->activate(); + $ban->save(); + } /** * Deletes ban from given IP number. @@ -510,26 +512,26 @@ class POT * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_IPBan class. */ - public function unbanIP($ip, $mask = '255.255.255.255') - { - // long2ip( ip2long('255.255.255.255') ) != '255.255.255.255' -.-' - // it's because that PHP integer types are signed - if($ip === '255.255.255.255') - { - $ip = 4294967295; - } - else - { - $ip = sprintf('%u', ip2long($ip) ); - } + public function unbanIP($ip, $mask = '255.255.255.255') + { + // long2ip( ip2long('255.255.255.255') ) != '255.255.255.255' -.-' + // it's because that PHP integer types are signed + if($ip === '255.255.255.255') + { + $ip = 4294967295; + } + else + { + $ip = sprintf('%u', ip2long($ip) ); + } - // mask is not used anymore + // mask is not used anymore - // deletes ban entry - $ban = new OTS_IPBan(); - $ban->find($ip); - $ban->delete(); - } + // deletes ban entry + $ban = new OTS_IPBan(); + $ban->find($ip); + $ban->delete(); + } /** * Checks if given IP is banned. @@ -541,24 +543,24 @@ class POT * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_IPBan class. */ - public function isIPBanned($ip) - { - // long2ip( ip2long('255.255.255.255') ) != '255.255.255.255' -.-' - // it's because that PHP integer types are signed - if($ip === '255.255.255.255') - { - $ip = 4294967295; - } - else - { - $ip = sprintf('%u', ip2long($ip) ); - } + public function isIPBanned($ip) + { + // long2ip( ip2long('255.255.255.255') ) != '255.255.255.255' -.-' + // it's because that PHP integer types are signed + if($ip === '255.255.255.255') + { + $ip = 4294967295; + } + else + { + $ip = sprintf('%u', ip2long($ip) ); + } - // finds ban entry - $ban = new OTS_IPBan(); - $ban->find($ip); - return $ban->isLoaded() && $ban->isActive() && ( $ban->getExpires() == 0 || $ban->getExpires() > time() ); - } + // finds ban entry + $ban = new OTS_IPBan(); + $ban->find($ip); + return $ban->isLoaded() && $ban->isActive() && ( $ban->getExpires() == 0 || $ban->getExpires() > time() ); + } /** * Returns list of banned IPs as list of pairs (ip => IP, mask => MASK). @@ -569,22 +571,22 @@ class POT * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_IPBans_List class. */ - public function bannedIPs() - { - $list = array(); + public function bannedIPs() + { + $list = array(); - // generates bans array - foreach( new OTS_IPBans_List() as $ban) - { - // checks if ban is active - if( $ban->isActive() && ( $ban->getExpires() == 0 || $ban->getExpires() > time() ) ) - { - $list[] = array('ip' => $ban->getValue(), 'mask' => $ban->getParam() ); - } - } + // generates bans array + foreach( new OTS_IPBans_List() as $ban) + { + // checks if ban is active + if( $ban->isActive() && ( $ban->getExpires() == 0 || $ban->getExpires() > time() ) ) + { + $list[] = array('ip' => $ban->getValue(), 'mask' => $ban->getParam() ); + } + } - return $list; - } + return $list; + } /** * @version 0.1.0 @@ -592,10 +594,10 @@ class POT * @return OTS_SQLFilter Filter object. * @deprecated 0.1.0 Create objects directly from now. */ - public function createFilter() - { - return new OTS_SQLFilter(); - } + public function createFilter() + { + return new OTS_SQLFilter(); + } /** * List of vocations. @@ -604,7 +606,7 @@ class POT * @since 0.0.5 * @var OTS_VocationsList */ - private $vocations; + private $vocations; /** * Loads vocations list. @@ -622,11 +624,11 @@ class POT * @param string $file vocations.xml file location. * @throws DOMException On DOM operation error. */ - public function loadVocations($file) - { - // loads DOM document - $this->vocations = new OTS_VocationsList($file); - } + public function loadVocations($file) + { + // loads DOM document + $this->vocations = new OTS_VocationsList($file); + } /** * Checks if vocations are loaded. @@ -639,10 +641,10 @@ class POT * @since 0.1.0 * @return bool True if vocations are loaded. */ - public function areVocationsLoaded() - { - return isset($this->vocations); - } + public function areVocationsLoaded() + { + return isset($this->vocations); + } /** * Unloads vocations list. @@ -650,10 +652,10 @@ class POT * @version 0.1.0 * @since 0.1.0 */ - public function unloadVocations() - { - unset($this->vocations); - } + public function unloadVocations() + { + unset($this->vocations); + } /** * Returns vocations list object. @@ -667,15 +669,15 @@ class POT * @return OTS_VocationsList List of vocations. * @throws E_OTS_NotLoaded If vocations list is not loaded. */ - public function getVocationsList() - { - if( isset($this->vocations) ) - { - return $this->vocations; - } + public function getVocationsList() + { + if( isset($this->vocations) ) + { + return $this->vocations; + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -685,15 +687,15 @@ class POT * @throws E_OTS_NotLoaded If vocations list is not loaded. * @deprecated 0.1.3 Use POT::getVocationsList()->getVocationId(). */ - public function getVocationId($name) - { - if( isset($this->vocations) ) - { - return $this->vocations->getVocationId($name); - } + public function getVocationId($name) + { + if( isset($this->vocations) ) + { + return $this->vocations->getVocationId($name); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -703,15 +705,15 @@ class POT * @throws E_OTS_NotLoaded If vocations list is not loaded. * @deprecated 0.1.3 Use POT::getVocationsList()->getVocationName(). */ - public function getVocationName($id) - { - if( isset($this->vocations) ) - { - return $this->vocations->getVocationName($id); - } + public function getVocationName($id) + { + if( isset($this->vocations) ) + { + return $this->vocations->getVocationName($id); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * List of loaded monsters. @@ -720,7 +722,7 @@ class POT * @since 0.0.6 * @var OTS_MonstersList */ - private $monsters; + private $monsters; /** * Loads monsters mapping file. @@ -738,10 +740,10 @@ class POT * @param string $path Monsters directory. * @throws DOMException On DOM operation error. */ - public function loadMonsters($path) - { - $this->monsters = new OTS_MonstersList($path); - } + public function loadMonsters($path) + { + $this->monsters = new OTS_MonstersList($path); + } /** * Checks if monsters are loaded. @@ -754,10 +756,10 @@ class POT * @since 0.1.0 * @return bool True if monsters are loaded. */ - public function areMonstersLoaded() - { - return isset($this->monsters); - } + public function areMonstersLoaded() + { + return isset($this->monsters); + } /** * Unloads monsters list. @@ -765,10 +767,10 @@ class POT * @version 0.1.0 * @since 0.1.0 */ - public function unloadMonsters() - { - unset($this->monsters); - } + public function unloadMonsters() + { + unset($this->monsters); + } /** * Returns list of laoded monsters. @@ -782,15 +784,15 @@ class POT * @return OTS_MonstersList List of monsters. * @throws E_OTS_NotLoaded If monsters list is not loaded. */ - public function getMonstersList() - { - if( isset($this->monsters) ) - { - return $this->monsters; - } + public function getMonstersList() + { + if( isset($this->monsters) ) + { + return $this->monsters; + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -800,15 +802,15 @@ class POT * @throws E_OTS_NotLoaded If monsters list is not loaded. * @deprecated 0.1.3 Use POT::getMonstersList()->getMonster(). */ - public function getMonster($name) - { - if( isset($this->monsters) ) - { - return $this->monsters->getMonster($name); - } + public function getMonster($name) + { + if( isset($this->monsters) ) + { + return $this->monsters->getMonster($name); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * Spells list. @@ -817,7 +819,7 @@ class POT * @since 0.1.0 * @var OTS_SpellsList */ - private $spells; + private $spells; /** * Loads spells list. @@ -835,10 +837,10 @@ class POT * @param string $file Spells file name. * @throws DOMException On DOM operation error. */ - public function loadSpells($file) - { - $this->spells = new OTS_SpellsList($file); - } + public function loadSpells($file) + { + $this->spells = new OTS_SpellsList($file); + } /** * Checks if spells are loaded. @@ -851,10 +853,10 @@ class POT * @since 0.1.0 * @return bool True if spells are loaded. */ - public function areSpellsLoaded() - { - return isset($this->spells); - } + public function areSpellsLoaded() + { + return isset($this->spells); + } /** * Unloads spells list. @@ -862,10 +864,10 @@ class POT * @version 0.1.0 * @since 0.1.0 */ - public function unloadSpells() - { - unset($this->spells); - } + public function unloadSpells() + { + unset($this->spells); + } /** * Returns list of laoded spells. @@ -875,15 +877,15 @@ class POT * @return OTS_SpellsList List of spells. * @throws E_OTS_NotLoaded If spells list is not loaded. */ - public function getSpellsList() - { - if( isset($this->spells) ) - { - return $this->spells; - } + public function getSpellsList() + { + if( isset($this->spells) ) + { + return $this->spells; + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -892,15 +894,15 @@ class POT * @throws E_OTS_NotLoaded If spells list is not loaded. * @deprecated 0.1.3 Use POT::getSpellsList()->getRunesList(). */ - public function getRunesList() - { - if( isset($this->spells) ) - { - return $this->spells->getRunesList(); - } + public function getRunesList() + { + if( isset($this->spells) ) + { + return $this->spells->getRunesList(); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -910,15 +912,15 @@ class POT * @throws E_OTS_NotLoaded If spells list is not loaded. * @deprecated 0.1.3 Use POT::getSpellsList()->getRune(). */ - public function getRune($name) - { - if( isset($this->spells) ) - { - return $this->spells->getRune($name); - } + public function getRune($name) + { + if( isset($this->spells) ) + { + return $this->spells->getRune($name); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -927,15 +929,15 @@ class POT * @throws E_OTS_NotLoaded If spells list is not loaded. * @deprecated 0.1.3 Use POT::getSpellsList()->getInstantsList(). */ - public function getInstantsList() - { - if( isset($this->spells) ) - { - return $this->spells->getInstantsList(); - } + public function getInstantsList() + { + if( isset($this->spells) ) + { + return $this->spells->getInstantsList(); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -945,15 +947,15 @@ class POT * @throws E_OTS_NotLoaded If spells list is not loaded. * @deprecated 0.1.3 Use POT::getSpellsList()->getInstant(). */ - public function getInstant($name) - { - if( isset($this->spells) ) - { - return $this->spells->getInstant($name); - } + public function getInstant($name) + { + if( isset($this->spells) ) + { + return $this->spells->getInstant($name); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -962,15 +964,15 @@ class POT * @throws E_OTS_NotLoaded If spells list is not loaded. * @deprecated 0.1.3 Use POT::getSpellsList()->getConjuresList(). */ - public function getConjuresList() - { - if( isset($this->spells) ) - { - return $this->spells->getConjuresList(); - } + public function getConjuresList() + { + if( isset($this->spells) ) + { + return $this->spells->getConjuresList(); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -980,15 +982,15 @@ class POT * @throws E_OTS_NotLoaded If spells list is not loaded. * @deprecated 0.1.3 Use POT::getSpellsList()->getConjure(). */ - public function getConjure($name) - { - if( isset($this->spells) ) - { - return $this->spells->getConjure($name); - } + public function getConjure($name) + { + if( isset($this->spells) ) + { + return $this->spells->getConjure($name); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * List of loaded houses. @@ -997,7 +999,7 @@ class POT * @since 0.1.0 * @var OTS_HousesList */ - private $houses; + private $houses; /** * Loads houses list file. @@ -1011,10 +1013,10 @@ class POT * @param string $path Houses file. * @throws DOMException On DOM operation error. */ - public function loadHouses($path) - { - $this->houses = new OTS_HousesList($path); - } + public function loadHouses($path) + { + $this->houses = new OTS_HousesList($path); + } /** * Checks if houses are loaded. @@ -1027,10 +1029,10 @@ class POT * @since 0.1.0 * @return bool True if houses are loaded. */ - public function areHousesLoaded() - { - return isset($this->houses); - } + public function areHousesLoaded() + { + return isset($this->houses); + } /** * Unloads houses list. @@ -1038,10 +1040,10 @@ class POT * @version 0.1.0 * @since 0.1.0 */ - public function unloadHouses() - { - unset($this->houses); - } + public function unloadHouses() + { + unset($this->houses); + } /** * Returns list of laoded houses. @@ -1051,15 +1053,15 @@ class POT * @return OTS_HousesList List of houses. * @throws E_OTS_NotLoaded If houses list is not loaded. */ - public function getHousesList() - { - if( isset($this->houses) ) - { - return $this->houses; - } + public function getHousesList() + { + if( isset($this->houses) ) + { + return $this->houses; + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -1069,15 +1071,15 @@ class POT * @throws E_OTS_NotLoaded If houses list is not loaded. * @deprecated 0.1.3 Use POT::getHousesList()->getHouse(). */ - public function getHouse($id) - { - if( isset($this->houses) ) - { - return $this->houses->getHouse($id); - } + public function getHouse($id) + { + if( isset($this->houses) ) + { + return $this->houses->getHouse($id); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -1087,15 +1089,15 @@ class POT * @throws E_OTS_NotLoaded If houses list is not loaded. * @deprecated 0.1.3 Use POT::getHousesList()->getHouseId(). */ - public function getHouseId($name) - { - if( isset($this->houses) ) - { - return $this->houses->getHouseId($name); - } + public function getHouseId($name) + { + if( isset($this->houses) ) + { + return $this->houses->getHouseId($name); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * Cache handler for items loading. @@ -1104,7 +1106,7 @@ class POT * @since 0.1.0 * @var IOTS_FileCache */ - private $itemsCache; + private $itemsCache; /** * Presets cache handler for items loader. @@ -1115,10 +1117,10 @@ class POT * * @param IOTS_FileCache $cache Cache handler (skip this parameter to reset cache handler to null). */ - public function setItemsCache(IOTS_FileCache $cache = null) - { - $this->itemsCache = $cache; - } + public function setItemsCache(?IOTS_FileCache $cache = null) + { + $this->itemsCache = $cache; + } /** * List of loaded items. @@ -1127,7 +1129,7 @@ class POT * @since 0.1.0 * @var OTS_ItemsList */ - private $items; + private $items; /** * Loads items list. @@ -1141,18 +1143,18 @@ class POT * @param string $path Items information directory. * @throws E_OTS_FileLoaderError On binary file loading error. */ - public function loadItems($path) - { - $this->items = new OTS_ItemsList(); + public function loadItems($path) + { + $this->items = new OTS_ItemsList(); - // sets items cache if any - if( isset($this->itemsCache) ) - { - $this->items->setCacheDriver($this->itemsCache); - } + // sets items cache if any + if( isset($this->itemsCache) ) + { + $this->items->setCacheDriver($this->itemsCache); + } - $this->items->loadItems($path); - } + $this->items->loadItems($path); + } /** * Checks if items are loaded. @@ -1165,10 +1167,10 @@ class POT * @since 0.1.0 * @return bool True if items are loaded. */ - public function areItemsLoaded() - { - return isset($this->items); - } + public function areItemsLoaded() + { + return isset($this->items); + } /** * Unloads items list. @@ -1176,10 +1178,10 @@ class POT * @version 0.1.0 * @since 0.1.0 */ - public function unloadItems() - { - unset($this->items); - } + public function unloadItems() + { + unset($this->items); + } /** * Returns list of laoded items. @@ -1189,15 +1191,15 @@ class POT * @return OTS_ItemsList List of items. * @throws E_OTS_NotLoaded If items list is not loaded. */ - public function getItemsList() - { - if( isset($this->items) ) - { - return $this->items; - } + public function getItemsList() + { + if( isset($this->items) ) + { + return $this->items; + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -1207,15 +1209,15 @@ class POT * @throws E_OTS_NotLoaded If items list is not loaded. * @deprecated 0.1.3 Use POT::getItemsList()->getItemType(). */ - public function getItemType($id) - { - if( isset($this->items) ) - { - return $this->items->getItemType($id); - } + public function getItemType($id) + { + if( isset($this->items) ) + { + return $this->items->getItemType($id); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -1225,15 +1227,15 @@ class POT * @throws E_OTS_NotLoaded If items list is not loaded. * @deprecated 0.1.3 Use POT::getItemsList()->getItemTypeId(). */ - public function getItemTypeId($name) - { - if( isset($this->items) ) - { - return $this->items->getItemTypeId($name); - } + public function getItemTypeId($name) + { + if( isset($this->items) ) + { + return $this->items->getItemTypeId($name); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * Cache handler for OTBM loading. @@ -1242,7 +1244,7 @@ class POT * @since 0.1.0 * @var IOTS_FileCache */ - private $mapCache; + private $mapCache; /** * Presets cache handler for OTBM loader. @@ -1253,10 +1255,10 @@ class POT * * @param IOTS_FileCache $cache Cache handler (skip this parameter to reset cache handler to null). */ - public function setMapCache(IOTS_FileCache $cache = null) - { - $this->mapCache = $cache; - } + public function setMapCache(?IOTS_FileCache $cache = null) + { + $this->mapCache = $cache; + } /** * Loaded map. @@ -1265,7 +1267,7 @@ class POT * @since 0.1.0 * @var OTS_OTBMFile */ - private $map; + private $map; /** * Loads OTBM map. @@ -1282,19 +1284,19 @@ class POT * @since 0.1.0 * @param string $path Map file path. */ - public function loadMap($path) - { - $this->map = new OTS_OTBMFile(); + public function loadMap($path) + { + $this->map = new OTS_OTBMFile(); - // sets items cache if any - if( isset($this->mapCache) ) - { - $this->map->setCacheDriver($this->mapCache); - } + // sets items cache if any + if( isset($this->mapCache) ) + { + $this->map->setCacheDriver($this->mapCache); + } - $this->map->loadFile($path); - $this->houses = $this->map->getHousesList(); - } + $this->map->loadFile($path); + $this->houses = $this->map->getHousesList(); + } /** * Checks if OTBM is loaded. @@ -1307,10 +1309,10 @@ class POT * @since 0.1.0 * @return bool True if map is loaded. */ - public function isMapLoaded() - { - return isset($this->map); - } + public function isMapLoaded() + { + return isset($this->map); + } /** * Unloads OTBM map. @@ -1318,10 +1320,10 @@ class POT * @version 0.1.0 * @since 0.1.0 */ - public function unloadMap() - { - unset($this->map); - } + public function unloadMap() + { + unset($this->map); + } /** * Returns loaded map. @@ -1331,15 +1333,15 @@ class POT * @return OTS_OTBMFile Loaded OTBM file. * @throws E_OTS_NotLoaded If map is not loaded. */ - public function getMap() - { - if( isset($this->map) ) - { - return $this->map; - } + public function getMap() + { + if( isset($this->map) ) + { + return $this->map; + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -1348,15 +1350,15 @@ class POT * @throws E_OTS_NotLoaded If map is not loaded. * @deprecated 0.1.3 Use POT::getMap()->getMapWidth(). */ - public function getMapWidth() - { - if( isset($this->map) ) - { - return $this->map->getWidth(); - } + public function getMapWidth() + { + if( isset($this->map) ) + { + return $this->map->getWidth(); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -1365,15 +1367,15 @@ class POT * @throws E_OTS_NotLoaded If map is not loaded. * @deprecated 0.1.3 Use POT::getMap()->getMapHeight(). */ - public function getMapHeight() - { - if( isset($this->map) ) - { - return $this->map->getHeight(); - } + public function getMapHeight() + { + if( isset($this->map) ) + { + return $this->map->getHeight(); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -1382,15 +1384,15 @@ class POT * @throws E_OTS_NotLoaded If map is not loaded. * @deprecated 0.1.3 Use POT::getMap()->getMapDescription(). */ - public function getMapDescription() - { - if( isset($this->map) ) - { - return $this->map->getDescription(); - } + public function getMapDescription() + { + if( isset($this->map) ) + { + return $this->map->getDescription(); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -1400,15 +1402,15 @@ class POT * @throws E_OTS_NotLoaded If map is not loaded. * @deprecated 0.1.3 Use POT::getMap()->getTownId(). */ - public function getTownId($name) - { - if( isset($this->map) ) - { - return $this->map->getTownId($name); - } + public function getTownId($name) + { + if( isset($this->map) ) + { + return $this->map->getTownId($name); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * @version 0.1.3 @@ -1418,15 +1420,15 @@ class POT * @throws E_OTS_NotLoaded If map is not loaded. * @deprecated 0.1.3 Use POT::getMap()->getTownName(). */ - public function getTownName($id) - { - if( isset($this->map) ) - { - return $this->map->getTownName($id); - } + public function getTownName($id) + { + if( isset($this->map) ) + { + return $this->map->getTownName($id); + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * Display driver. @@ -1435,7 +1437,7 @@ class POT * @since 0.1.0 * @var IOTS_Display */ - private $display; + private $display; /** * Sets display driver for database-related resources. @@ -1444,10 +1446,10 @@ class POT * @since 0.1.0 * @param IOTS_Display $display Display driver. */ - public function setDisplayDriver(IOTS_Display $display) - { - $this->display = $display; - } + public function setDisplayDriver(IOTS_Display $display) + { + $this->display = $display; + } /** * Checks if any display driver is loaded. @@ -1460,10 +1462,10 @@ class POT * @since 0.1.0 * @return bool True if driver is loaded. */ - public function isDisplayDriverLoaded() - { - return isset($this->display); - } + public function isDisplayDriverLoaded() + { + return isset($this->display); + } /** * Unloads display driver. @@ -1471,10 +1473,10 @@ class POT * @version 0.1.0 * @since 0.1.0 */ - public function unloadDisplayDriver() - { - unset($this->display); - } + public function unloadDisplayDriver() + { + unset($this->display); + } /** * Returns current display driver. @@ -1488,15 +1490,15 @@ class POT * @return IOTS_Display Current display driver. * @throws E_OTS_NotLoaded If display driver is not loaded. */ - public function getDisplayDriver() - { - if( isset($this->display) ) - { - return $this->display; - } + public function getDisplayDriver() + { + if( isset($this->display) ) + { + return $this->display; + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } /** * Display driver for non-database resources. @@ -1505,7 +1507,7 @@ class POT * @since 0.1.3 * @var IOTS_DataDisplay */ - private $dataDisplay; + private $dataDisplay; /** * Sets display driver for non-database resources. @@ -1514,10 +1516,10 @@ class POT * @since 0.1.3 * @param IOTS_DataDisplay $dataDisplay Display driver. */ - public function setDataDisplayDriver(IOTS_DataDisplay $dataDisplay) - { - $this->dataDisplay = $dataDisplay; - } + public function setDataDisplayDriver(IOTS_DataDisplay $dataDisplay) + { + $this->dataDisplay = $dataDisplay; + } /** * Checks if any display driver for non-database resources is loaded. @@ -1530,10 +1532,10 @@ class POT * @since 0.1.3 * @return bool True if driver is loaded. */ - public function isDataDisplayDriverLoaded() - { - return isset($this->dataDisplay); - } + public function isDataDisplayDriverLoaded() + { + return isset($this->dataDisplay); + } /** * Unloads display driver. @@ -1541,10 +1543,10 @@ class POT * @version 0.1.3 * @since 0.1.3 */ - public function unloadDataDisplayDriver() - { - unset($this->dataDisplay); - } + public function unloadDataDisplayDriver() + { + unset($this->dataDisplay); + } /** * Returns current display driver. @@ -1558,15 +1560,15 @@ class POT * @return IOTS_DataDisplay Current display driver. * @throws E_OTS_NotLoaded If display driver is not loaded. */ - public function getDataDisplayDriver() - { - if( isset($this->dataDisplay) ) - { - return $this->dataDisplay; - } + public function getDataDisplayDriver() + { + if( isset($this->dataDisplay) ) + { + return $this->dataDisplay; + } - throw new E_OTS_NotLoaded(); - } + throw new E_OTS_NotLoaded(); + } } /* @@ -1581,7 +1583,7 @@ if( !defined('PDO_PARAM_STR') ) * @since 0.0.7 * @deprecated Will be dropped after dropping IOTS_DB::SQLquote() since only this deprecated method uses it. */ - define('PDO_PARAM_STR', PDO::PARAM_STR); + define('PDO_PARAM_STR', PDO::PARAM_STR); } if( !defined('PDO_ATTR_STATEMENT_CLASS') ) @@ -1592,7 +1594,7 @@ if( !defined('PDO_ATTR_STATEMENT_CLASS') ) * @since 0.0.7 * @deprecated Use PDO::ATTR_STATEMENT_CLASS, this is for PHP 5.0 compatibility. */ - define('PDO_ATTR_STATEMENT_CLASS', PDO::ATTR_STATEMENT_CLASS); + define('PDO_ATTR_STATEMENT_CLASS', PDO::ATTR_STATEMENT_CLASS); } if( !defined('PDO_ATTR_ERRMODE') ) @@ -1603,7 +1605,7 @@ if( !defined('PDO_ATTR_ERRMODE') ) * @since 0.1.3 * @deprecated Use PDO::ATTR_ERRMODE, this is for PHP 5.0 compatibility. */ - define('PDO_ATTR_ERRMODE', PDO::ATTR_ERRMODE); + define('PDO_ATTR_ERRMODE', PDO::ATTR_ERRMODE); } if( !defined('PDO_ERRMODE_EXCEPTION') ) @@ -1614,7 +1616,7 @@ if( !defined('PDO_ERRMODE_EXCEPTION') ) * @since 0.1.3 * @deprecated Use PDO::ERRMODE_EXCEPTION, this is for PHP 5.0 compatibility. */ - define('PDO_ERRMODE_EXCEPTION', PDO::ERRMODE_EXCEPTION); + define('PDO_ERRMODE_EXCEPTION', PDO::ERRMODE_EXCEPTION); } /**#@-*/ diff --git a/system/libs/pot/OTS_Account.php b/system/libs/pot/OTS_Account.php index 231230af..6ad211df 100644 --- a/system/libs/pot/OTS_Account.php +++ b/system/libs/pot/OTS_Account.php @@ -40,7 +40,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @var array * @version 0.1.5 */ - private $data = array('email' => '', 'rlname' => '','location' => '', 'country' => '','web_flags' => 0, 'lastday' => 0, 'premdays' => 0, 'created' => 0); + private $data = array('email' => '', 'rlname' => '','location' => '', 'country' => '','web_flags' => 0, 'lastday' => 0, 'premdays' => 0, 'created' => 0); public static $cache = array(); @@ -68,39 +68,39 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @example examples/create.php create.php * @tutorial POT/Accounts.pkg#create */ - public function createNamed($name = null) - { - // if name is not passed then it will be generated randomly - if( !isset($name) ) - { - // reads already existing names - foreach( $this->db->query('SELECT ' . $this->db->fieldName('name') . ' FROM ' . $this->db->tableName('accounts') )->fetchAll() as $account) - { - $exist[] = $account['name']; - } + public function createNamed($name = null) + { + // if name is not passed then it will be generated randomly + if( !isset($name) ) + { + // reads already existing names + foreach( $this->db->query('SELECT ' . $this->db->fieldName('name') . ' FROM ' . $this->db->tableName('accounts') )->fetchAll() as $account) + { + $exist[] = $account['name']; + } - // initial name - $name = uniqid(); + // initial name + $name = uniqid(); - // repeats until name is unique - while( in_array($name, $exist) ) - { - $name .= '_'; - } + // repeats until name is unique + while( in_array($name, $exist) ) + { + $name .= '_'; + } - // resets array for account numbers loop - $exist = array(); - } + // resets array for account numbers loop + $exist = array(); + } - // saves blank account info - $this->db->exec('INSERT INTO ' . $this->db->tableName('accounts') . ' (' . $this->db->fieldName('name') . ', ' . $this->db->fieldName('password') . ', ' . $this->db->fieldName('email') . ') VALUES (' . $this->db->quote($name) . ', \'\', \'\')'); + // saves blank account info + $this->db->exec('INSERT INTO ' . $this->db->tableName('accounts') . ' (' . $this->db->fieldName('name') . ', ' . $this->db->fieldName('password') . ', ' . $this->db->fieldName('email') . ') VALUES (' . $this->db->quote($name) . ', \'\', \'\')'); - // reads created account's ID - $this->data['id'] = $this->db->lastInsertId(); + // reads created account's ID + $this->data['id'] = $this->db->lastInsertId(); - // return name of newly created account - return $name; - } + // return name of newly created account + return $name; + } /** * @param $email @@ -168,8 +168,8 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws Exception ON lastInsertId error. * @deprecated 0.1.5 Use createNamed(). */ - public function create($name = NULL, $id = NULL) - { + public function create($name = NULL, $id = NULL) + { if(isset($name)) { $nameOrNumber = 'name'; $nameOrNumberValue = $name; @@ -185,8 +185,8 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable } } - // saves blank account info - $this->db->exec('INSERT INTO `accounts` (' . (isset($id) ? '`id`,' : '') . (isset($nameOrNumber) ? '`' . $nameOrNumber . '`,' : '') . '`password`, `email`, `created`) VALUES (' . (isset($id) ? $id . ',' : '') . (isset($nameOrNumber) ? $this->db->quote($nameOrNumberValue) . ',' : '') . ' \'\', \'\',' . time() . ')'); + // saves blank account info + $this->db->exec('INSERT INTO `accounts` (' . (isset($id) ? '`id`,' : '') . (isset($nameOrNumber) ? '`' . $nameOrNumber . '`,' : '') . '`password`, `email`, `created`) VALUES (' . (isset($id) ? $id . ',' : '') . (isset($nameOrNumber) ? $this->db->quote($nameOrNumberValue) . ',' : '') . ' \'\', \'\',' . time() . ')'); if(isset($name)) { $this->data['name'] = $name; @@ -208,8 +208,8 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable throw new Exception(__CLASS__ . ':' . __METHOD__ . ' unexpected error. Please report to MyAAC Developers.'); } - return $this->data['id']; - } + return $this->data['id']; + } /** * @version 0.0.6 @@ -220,10 +220,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return int Created account number. * @deprecated 0.0.6 There is no more group_id field in database, use create(). */ - public function createEx(OTS_Group $group, $min = 1, $max = 9999999) - { - return $this->create($min, $max); - } + public function createEx(OTS_Group $group, $min = 1, $max = 9999999) + { + return $this->create($min, $max); + } /** * Loads account with given number. @@ -232,8 +232,8 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @param int $id Account number. * @throws PDOException On PDO operation error. */ - public function load($id, $fresh = false) - { + public function load($id, $fresh = false) + { if(!$fresh && isset(self::$cache[$id])) { $this->data = self::$cache[$id]; return; @@ -246,10 +246,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable $nameOrNumber = '`number`,'; } - // SELECT query on database + // SELECT query on database $this->data = $this->db->query('SELECT `id`, ' . $nameOrNumber . '`password`, `email`, `rlname`, `location`, `country`, `web_flags`, ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays`, ' : '') . ($this->db->hasColumn('accounts', 'lastday') ? '`lastday`, ' : ($this->db->hasColumn('accounts', 'premend') ? '`premend`,' : ($this->db->hasColumn('accounts', 'premium_ends_at') ? '`premium_ends_at`,' : ''))) . '`created` FROM `accounts` WHERE `id` = ' . (int) $id)->fetch(); self::$cache[$id] = $this->data; - } + } /** * Loads account by it's name. @@ -263,22 +263,22 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @param string $name Account's name. * @throws PDOException On PDO operation error. */ - public function find($name) - { + public function find($name) + { $nameOrNumberColumn = 'name'; if (USE_ACCOUNT_NUMBER) { $nameOrNumberColumn = 'number'; } - // finds player's ID - $id = $this->db->query('SELECT `id` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` = ' . $this->db->quote($name) )->fetch(); + // finds player's ID + $id = $this->db->query('SELECT `id` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` = ' . $this->db->quote($name) )->fetch(); - // if anything was found - if( isset($id['id']) ) - { - $this->load($id['id']); - } - } + // if anything was found + if( isset($id['id']) ) + { + $this->load($id['id']); + } + } /** * Loads account by it's e-mail address. @@ -288,27 +288,27 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @param string $email Account's e-mail address. * @throws PDOException On PDO operation error. */ - public function findByEMail($email) - { - // finds player's ID - $id = $this->db->query('SELECT `id` FROM `accounts` WHERE `email` = ' . $this->db->quote($email) )->fetch(); + public function findByEMail($email) + { + // finds player's ID + $id = $this->db->query('SELECT `id` FROM `accounts` WHERE `email` = ' . $this->db->quote($email) )->fetch(); - // if anything was found - if( isset($id['id']) ) - { - $this->load($id['id']); - } - } + // if anything was found + if( isset($id['id']) ) + { + $this->load($id['id']); + } + } /** * Checks if object is loaded. * * @return bool Load state. */ - public function isLoaded() - { - return isset($this->data['id']); - } + public function isLoaded() + { + return isset($this->data['id']); + } /** * Updates account in database. @@ -325,16 +325,16 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account doesn't have ID assigned. * @throws PDOException On PDO operation error. */ - public function save() - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function save() + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } $field = 'lastday'; if($this->db->hasColumn('accounts', 'premend')) { // othire - $field = 'premend'; + $field = 'premend'; if(!isset($this->data['premend'])) { $this->data['premend'] = 0; } @@ -346,9 +346,9 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable } } - // UPDATE query on database - $this->db->exec('UPDATE `accounts` SET ' . ($this->db->hasColumn('accounts', 'name') ? '`name` = ' . $this->db->quote($this->data['name']) . ',' : '') . '`password` = ' . $this->db->quote($this->data['password']) . ', `email` = ' . $this->db->quote($this->data['email']) . ', `rlname` = ' . $this->db->quote($this->data['rlname']) . ', `location` = ' . $this->db->quote($this->data['location']) . ', `country` = ' . $this->db->quote($this->data['country']) . ', `web_flags` = ' . (int) $this->data['web_flags'] . ', ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays` = ' . (int) $this->data['premdays'] . ',' : '') . '`' . $field . '` = ' . (int) $this->data[$field] . ' WHERE `id` = ' . $this->data['id']); - } + // UPDATE query on database + $this->db->exec('UPDATE `accounts` SET ' . ($this->db->hasColumn('accounts', 'name') ? '`name` = ' . $this->db->quote($this->data['name']) . ',' : '') . '`password` = ' . $this->db->quote($this->data['password']) . ', `email` = ' . $this->db->quote($this->data['email']) . ', `rlname` = ' . $this->db->quote($this->data['rlname']) . ', `location` = ' . $this->db->quote($this->data['location']) . ', `country` = ' . $this->db->quote($this->data['country']) . ', `web_flags` = ' . (int) $this->data['web_flags'] . ', ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays` = ' . (int) $this->data['premdays'] . ',' : '') . '`' . $field . '` = ' . (int) $this->data[$field] . ' WHERE `id` = ' . $this->data['id']); + } /** * Account number. @@ -361,15 +361,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return int Account number. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getId() - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getId() + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['id']; - } + return $this->data['id']; + } public function getNumber() { @@ -380,45 +380,45 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable return $this->data['id']; } - public function getRLName() - { - if( !isset($this->data['rlname']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getRLName() + { + if( !isset($this->data['rlname']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['rlname']; - } + return $this->data['rlname']; + } - public function getLocation() - { - if( !isset($this->data['location']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getLocation() + { + if( !isset($this->data['location']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['location']; - } + return $this->data['location']; + } - public function getCountry() - { - if( !isset($this->data['country']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getCountry() + { + if( !isset($this->data['country']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['country']; - } + return $this->data['country']; + } - public function getWebFlags() - { - if( !isset($this->data['web_flags']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getWebFlags() + { + if( !isset($this->data['web_flags']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['web_flags']; - } + return $this->data['web_flags']; + } public function hasFlag($flag) { @@ -445,13 +445,11 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable throw new E_OTS_NotLoaded(); } - $configFreePremium = configLua('freePremium'); - if(isset($configFreePremium) && getBoolean($configFreePremium)) {return -1;} - - if(isset($this->data['premium_ends_at']) || isset($this->data['premend'])) { - $col = isset($this->data['premium_ends_at']) ? 'premium_ends_at' : 'premend'; - $ret = ceil(($this->data[$col] - time()) / (24 * 60 * 60)); - return max($ret, 0); + if(isset($this->data['premium_ends_at']) || isset($this->data['premend']) || + (isCanary() && isset($this->data['lastday']))) { + $col = (isset($this->data['premium_ends_at']) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend')); + $ret = ceil(($this->data[$col] - time()) / (24 * 60 * 60)); + return max($ret, 0); } if($this->data['premdays'] == 0) { @@ -467,40 +465,39 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable } public function getLastLogin() - { - if( !isset($this->data['lastday']) ) - { - throw new E_OTS_NotLoaded(); - } + { + if( !isset($this->data['lastday']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['lastday']; - } + return $this->data['lastday']; + } - public function isPremium() - { - global $config; - if(isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium'])) return true; + public function isPremium(): bool + { + if(isset($this->data['premium_ends_at']) || isset($this->data['premend']) || + (isCanary() && isset($this->data['lastday']))) { + $col = (isset($this->data['premium_ends_at']) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend')); + return $this->data[$col] > time(); + } - if(isset($this->data['premium_ends_at'])) { - return $this->data['premium_ends_at'] > time(); - } - - if(isset($this->data['premend'])) { - return $this->data['premend'] > time(); + if($this->data['premdays'] == self::GRATIS_PREMIUM_DAYS){ + return true; } return ($this->data['premdays'] - (date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->data['lastday']))) - date("z", $this->data['lastday'])) > 0); } - public function getCreated() - { - if( !isset($this->data['created']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getCreated() + { + if( !isset($this->data['created']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['created']; - } + return $this->data['created']; + } /** * Name. @@ -509,37 +506,37 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @since 0.7.5 * @throws E_OTS_NotLoaded If account is not loaded. */ - public function setPremDays($premdays) - { + public function setPremDays($premdays) + { $this->data['premdays'] = (int) $premdays; $this->data['premend'] = time() + ($premdays * 24 * 60 * 60); $this->data['premium_ends_at'] = time() + ($premdays * 24 * 60 * 60); - } + } - public function setRLName($name) - { - $this->data['rlname'] = (string) $name; - } + public function setRLName($name) + { + $this->data['rlname'] = (string) $name; + } - public function setLocation($location) - { - $this->data['location'] = (string) $location; - } + public function setLocation($location) + { + $this->data['location'] = (string) $location; + } - public function setCountry($country) - { - $this->data['country'] = (string) $country; - } + public function setCountry($country) + { + $this->data['country'] = (string) $country; + } public function setLastLogin($lastlogin) - { - $this->data['lastday'] = (int) $lastlogin; - } + { + $this->data['lastday'] = (int) $lastlogin; + } - public function setWebFlags($webflags) - { - $this->data['web_flags'] = (int) $webflags; - } + public function setWebFlags($webflags) + { + $this->data['web_flags'] = (int) $webflags; + } /** * Name. @@ -549,15 +546,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return string Name. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getName() - { - if( !isset($this->data['name']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getName() + { + if( !isset($this->data['name']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['name']; - } + return $this->data['name']; + } /** * Sets account's name. @@ -570,10 +567,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @since 0.1.5 * @param string $name Account name. */ - public function setName($name) - { - $this->data['name'] = (string) $name; - } + public function setName($name) + { + $this->data['name'] = (string) $name; + } /** * Account's password. @@ -590,15 +587,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return string Password. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getPassword() - { - if( !isset($this->data['password']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getPassword() + { + if( !isset($this->data['password']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['password']; - } + return $this->data['password']; + } /** * Sets account's password. @@ -613,10 +610,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * * @param string $password Password. */ - public function setPassword($password) - { - $this->data['password'] = (string) $password; - } + public function setPassword($password) + { + $this->data['password'] = (string) $password; + } /** * E-mail address. * @@ -628,15 +625,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return string E-mail. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getEMail() - { - if( !isset($this->data['email']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getEMail() + { + if( !isset($this->data['email']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['email']; - } + return $this->data['email']; + } /** * Sets account's email. @@ -647,10 +644,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * * @param string $email E-mail address. */ - public function setEMail($email) - { - $this->data['email'] = (string) $email; - } + public function setEMail($email) + { + $this->data['email'] = (string) $email; + } /** * Reads custom field. @@ -670,16 +667,16 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account is not loaded. * @throws PDOException On PDO operation error. */ - public function getCustomField($field) - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getCustomField($field) + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - $value = $this->db->query('SELECT ' . $this->db->fieldName($field) . ' FROM ' . $this->db->tableName('accounts') . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id'])->fetch(); - return $value[$field]; - } + $value = $this->db->query('SELECT ' . $this->db->fieldName($field) . ' FROM ' . $this->db->tableName('accounts') . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id'])->fetch(); + return $value[$field]; + } /** * Writes custom field. @@ -703,20 +700,20 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account is not loaded. * @throws PDOException On PDO operation error. */ - public function setCustomField($field, $value) - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function setCustomField($field, $value) + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - // quotes value for SQL query - if(!( is_int($value) || is_float($value) )) - { - $value = $this->db->quote($value); - } - $this->db->exec('UPDATE ' . $this->db->tableName('accounts') . ' SET ' . $this->db->fieldName($field) . ' = ' . $value . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); - } + // quotes value for SQL query + if(!( is_int($value) || is_float($value) )) + { + $value = $this->db->quote($value); + } + $this->db->exec('UPDATE ' . $this->db->tableName('accounts') . ' SET ' . $this->db->fieldName($field) . ' = ' . $value . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); + } /** * @version 0.1.0 @@ -724,25 +721,25 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account is not loaded. * @deprecated 0.0.5 Use getPlayersList(). */ - public function getPlayers() - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getPlayers() + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - $players = array(); + $players = array(); - foreach( $this->db->query('SELECT ' . $this->db->fieldName('id') . ' FROM ' . $this->db->tableName('players') . ' WHERE ' . $this->db->fieldName('account_id') . ' = ' . $this->data['id'])->fetchAll() as $player) - { - // creates new object - $object = new OTS_Player(); - $object->load($player['id']); - $players[] = $object; - } + foreach( $this->db->query('SELECT ' . $this->db->fieldName('id') . ' FROM ' . $this->db->tableName('players') . ' WHERE ' . $this->db->fieldName('account_id') . ' = ' . $this->data['id'])->fetchAll() as $player) + { + // creates new object + $object = new OTS_Player(); + $object->load($player['id']); + $players[] = $object; + } - return $players; - } + return $players; + } /** * List of characters on account. @@ -760,16 +757,16 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return OTS_Players_List List of players from current account. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getPlayersList($withDeleted = true) - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getPlayersList($withDeleted = true) + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - // creates filter - $filter = new OTS_SQLFilter(); - $filter->compareField('account_id', (int) $this->data['id']); + // creates filter + $filter = new OTS_SQLFilter(); + $filter->compareField('account_id', (int) $this->data['id']); if(!$withDeleted) { global $db; @@ -780,12 +777,12 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable } } - // creates list object - $list = new OTS_Players_List(); - $list->setFilter($filter); + // creates list object + $list = new OTS_Players_List(); + $list->setFilter($filter); - return $list; - } + return $list; + } /** * @version 0.1.5 @@ -794,22 +791,22 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_AccountBan class. */ - public function ban($time = 0) - { - // can't ban nothing - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function ban($time = 0) + { + // can't ban nothing + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } - // creates ban entry - $ban = new OTS_AccountBan(); - $ban->setValue($this->data['id']); - $ban->setExpires($time); - $ban->setAdded( time() ); - $ban->activate(); - $ban->save(); - } + // creates ban entry + $ban = new OTS_AccountBan(); + $ban->setValue($this->data['id']); + $ban->setExpires($time); + $ban->setAdded( time() ); + $ban->activate(); + $ban->save(); + } /** * @version 0.1.5 @@ -817,19 +814,19 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_AccountBan class. */ - public function unban() - { - // can't unban nothing - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function unban() + { + // can't unban nothing + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } - // deletes ban entry - $ban = new OTS_AccountBan(); - $ban->find($this->data['id']); - $ban->delete(); - } + // deletes ban entry + $ban = new OTS_AccountBan(); + $ban->find($this->data['id']); + $ban->delete(); + } /** * @version 0.1.5 @@ -838,37 +835,37 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_AccountBan class. */ - public function isBanned() - { - // nothing can't be banned - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function isBanned() + { + // nothing can't be banned + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } if( !isset($this->data['banned']) ) $this->loadBan(); - return ($this->data['banned'] === true); - } + return ($this->data['banned'] === true); + } - public function getBanTime() - { - // nothing can't be banned - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function getBanTime() + { + // nothing can't be banned + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } if( !isset($this->data['banned_time']) ) $this->loadBan(); - return $this->data['banned_time']; - } + return $this->data['banned_time']; + } - public function loadBan() - { - // nothing can't be banned - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function loadBan() + { + // nothing can't be banned + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } if($this->db->hasTable('account_bans')) { $ban = $this->db->query('SELECT `expires_at` FROM `account_bans` WHERE `account_id` = ' . $this->data['id'] . ' AND (`expires_at` > ' . time() .' OR `expires_at` = -1) ORDER BY `expires_at` DESC')->fetch(); @@ -891,7 +888,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable $this->data['banned'] = false; $this->data['banned_time'] = 0; } - } + } /** * Deletes account. @@ -905,19 +902,19 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account is not loaded. * @throws PDOException On PDO operation error. */ - public function delete() - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function delete() + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - // deletes row from database - $this->db->exec('DELETE FROM ' . $this->db->tableName('accounts') . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); + // deletes row from database + $this->db->exec('DELETE FROM ' . $this->db->tableName('accounts') . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); - // resets object handle - unset($this->data['id']); - } + // resets object handle + unset($this->data['id']); + } /** * Checks highest access level of account. @@ -925,10 +922,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return int Access level (highest access level of all characters). * @throws PDOException On PDO operation error. */ - public function getAccess() - { + public function getAccess() + { return $this->getGroupId(); - } + } public function getGroupId() { @@ -990,25 +987,25 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return int Access level (highest access level of all characters). * @throws PDOException On PDO operation error. */ - public function getGuildAccess(OTS_Guild $guild) - { - // by default - $access = 0; + public function getGuildAccess(OTS_Guild $guild) + { + // by default + $access = 0; - // finds ranks of all characters - foreach($this->getPlayersList(false) as $player) - { - $rank = $player->getRank(); + // finds ranks of all characters + foreach($this->getPlayersList(false) as $player) + { + $rank = $player->getRank(); - // checks if rank's access level is higher then previouls found highest - if( isset($rank) && $rank->isLoaded() && $rank->getGuild()->getId() == $guild->getId() && $rank->getLevel() > $access) - { - $access = $rank->getLevel(); - } - } + // checks if rank's access level is higher then previouls found highest + if( isset($rank) && $rank->isLoaded() && $rank->getGuild()->getId() == $guild->getId() && $rank->getLevel() > $access) + { + $access = $rank->getLevel(); + } + } - return $access; - } + return $access; + } public function logAction($action) { @@ -1037,10 +1034,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return Iterator List of players. */ #[\ReturnTypeWillChange] - public function getIterator() - { - return $this->getPlayersList(); - } + public function getIterator() + { + return $this->getPlayersList(); + } /** * Returns number of player within. @@ -1051,10 +1048,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws PDOException On PDO operation error. * @return int Count of players. */ - public function count(): int - { - return $this->getPlayersList()->count(); - } + public function count(): int + { + return $this->getPlayersList()->count(); + } /** * Magic PHP5 method. @@ -1067,44 +1064,44 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws OutOfBoundsException For non-supported properties. * @throws PDOException On PDO operation error. */ - public function __get($name) - { - switch($name) - { - case 'id': - return $this->getId(); + public function __get($name) + { + switch($name) + { + case 'id': + return $this->getId(); - case 'name': - return $this->getName(); + case 'name': + return $this->getName(); - case 'password': - return $this->getPassword(); + case 'password': + return $this->getPassword(); - case 'eMail': - return $this->getEMail(); + case 'eMail': + return $this->getEMail(); - case 'premiumEnd': - return $this->getPremiumEnd(); + case 'premiumEnd': + return $this->getPremiumEnd(); - case 'loaded': - return $this->isLoaded(); + case 'loaded': + return $this->isLoaded(); - case 'playersList': - return $this->getPlayersList(); + case 'playersList': + return $this->getPlayersList(); - case 'deleted': - return $this->isDeleted(); + case 'deleted': + return $this->isDeleted(); - case 'banned': - return $this->isBanned(); + case 'banned': + return $this->isBanned(); - case 'access': - return $this->getAccess(); + case 'access': + return $this->getAccess(); - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } /** * Magic PHP5 method. @@ -1117,52 +1114,52 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws OutOfBoundsException For non-supported properties. * @throws PDOException On PDO operation error. */ - public function __set($name, $value) - { - switch($name) - { - case 'name': - $this->setName($name); - break; + public function __set($name, $value) + { + switch($name) + { + case 'name': + $this->setName($name); + break; - case 'password': - $this->setPassword($value); - break; + case 'password': + $this->setPassword($value); + break; - case 'eMail': - $this->setEMail($value); - break; + case 'eMail': + $this->setEMail($value); + break; - case 'premiumEnd': - $this->setPremiumEnd($value); - break; + case 'premiumEnd': + $this->setPremiumEnd($value); + break; - case 'deleted': - if($value) - { - $this->setDeleted(); - } - else - { - $this->unsetDeleted(); - } - break; + case 'deleted': + if($value) + { + $this->setDeleted(); + } + else + { + $this->unsetDeleted(); + } + break; - case 'banned': - if($value) - { - $this->ban(); - } - else - { - $this->unban(); - } - break; + case 'banned': + if($value) + { + $this->ban(); + } + else + { + $this->unban(); + } + break; - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } /** * Returns string representation of object. @@ -1175,18 +1172,18 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @since 0.1.0 * @return string String representation of object. */ - public function __toString() - { - $ots = POT::getInstance(); + public function __toString() + { + $ots = POT::getInstance(); - // checks if display driver is loaded - if( $ots->isDisplayDriverLoaded() ) - { - return $ots->getDisplayDriver()->displayAccount($this); - } + // checks if display driver is loaded + if( $ots->isDisplayDriverLoaded() ) + { + return $ots->getDisplayDriver()->displayAccount($this); + } - return $this->getId(); - } + return $this->getId(); + } } /**#@-*/ diff --git a/system/libs/pot/OTS_DB_MySQL.php b/system/libs/pot/OTS_DB_MySQL.php index baa38c76..8b9626d9 100644 --- a/system/libs/pot/OTS_DB_MySQL.php +++ b/system/libs/pot/OTS_DB_MySQL.php @@ -26,10 +26,11 @@ use MyAAC\Cache\Cache; */ class OTS_DB_MySQL extends OTS_Base_DB { - private $has_table_cache = array(); - private $has_column_cache = array(); + private array $has_table_cache = []; + private array $has_column_cache = []; + private array $get_column_info_cache = []; - private $clearCacheAfter = false; + private bool $clearCacheAfter = false; /** * Creates database connection. * @@ -119,6 +120,11 @@ class OTS_DB_MySQL extends OTS_Base_DB if($cache->fetch('database_columns', $tmp) && $tmp) { $this->has_column_cache = unserialize($tmp); } + + $tmp = null; + if($cache->fetch('database_columns_info', $tmp) && $tmp) { + $this->get_column_info_cache = unserialize($tmp); + } } } @@ -155,11 +161,13 @@ class OTS_DB_MySQL extends OTS_Base_DB if ($this->clearCacheAfter) { $cache->delete('database_tables'); $cache->delete('database_columns'); + $cache->delete('database_columns_info'); $cache->delete('database_checksum'); } else { $cache->set('database_tables', serialize($this->has_table_cache), 3600); $cache->set('database_columns', serialize($this->has_column_cache), 3600); + $cache->set('database_columns_info', serialize($this->get_column_info_cache), 3600); $cache->set('database_checksum', serialize(sha1($config['database_host'] . '.' . $config['database_name'])), 3600); } } @@ -209,7 +217,8 @@ class OTS_DB_MySQL extends OTS_Base_DB return $sql; } - public function hasTable($name) { + public function hasTable($name): bool + { if(isset($this->has_table_cache[$name])) { return $this->has_table_cache[$name]; } @@ -217,12 +226,13 @@ class OTS_DB_MySQL extends OTS_Base_DB return $this->hasTableInternal($name); } - private function hasTableInternal($name) { - global $config; - return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote($config['database_name']) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0); + private function hasTableInternal($name): bool + { + return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote(config('database_name')) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0); } - public function hasColumn($table, $column) { + public function hasColumn($table, $column): bool + { if(isset($this->has_column_cache[$table . '.' . $column])) { return $this->has_column_cache[$table . '.' . $column]; } @@ -230,8 +240,8 @@ class OTS_DB_MySQL extends OTS_Base_DB return $this->hasColumnInternal($table, $column); } - private function hasColumnInternal($table, $column) { - return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE '" . $column . "'")->fetchAll()) > 0); + private function hasColumnInternal($table, $column): bool { + return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column))->fetchAll()) > 0); } public function hasTableAndColumns(string $table, array $columns = []): bool @@ -247,7 +257,53 @@ class OTS_DB_MySQL extends OTS_Base_DB return true; } - public function revalidateCache() { + public function getColumnInfo(string $table, string $column): bool|array + { + if(isset($this->get_column_info_cache[$table . '.' . $column])) { + return $this->get_column_info_cache[$table . '.' . $column]; + } + + return $this->getColumnInfoInternal($table, $column); + } + + private function getColumnInfoInternal(string $table, string $column): bool|array + { + if (!$this->hasTable($table) || !$this->hasColumn($table, $column)) { + return false; + } + + $formatResult = function ($result) { + return [ + 'field' => $result['Field'], + 'type' => $result['Type'], + 'null' => strtolower($result['Null']), + 'default' => $result['Default'], + 'extra' => $result['Extra'], + ]; + }; + + $query = $this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column)); + $rowCount = $query->rowCount(); + if ($rowCount > 1) { + $tmp = []; + + $results = $query->fetchAll(PDO::FETCH_ASSOC); + foreach ($results as $result) { + $tmp[] = $formatResult($result); + } + + return ($this->get_column_info_cache[$table . '.' . $column] = $tmp); + } + else if ($rowCount == 1) { + $result = $query->fetch(PDO::FETCH_ASSOC); + return ($this->get_column_info_cache[$table . '.' . $column] = $formatResult($result)); + } + + return []; + } + + public function revalidateCache(): void + { foreach($this->has_table_cache as $key => $value) { $this->hasTableInternal($key); } @@ -262,6 +318,21 @@ class OTS_DB_MySQL extends OTS_Base_DB $this->hasColumnInternal($explode[0], $explode[1]); } } + + foreach($this->get_column_info_cache as $key => $value) { + $explode = explode('.', $key); + if(!isset($this->has_table_cache[$explode[0]])) { // first check if table exist + $this->hasTableInternal($explode[0]); + } + + if($this->has_table_cache[$explode[0]]) { + $this->hasColumnInternal($explode[0], $explode[1]); + } + + if($this->has_table_cache[$explode[0]]) { + $this->getColumnInfoInternal($explode[0], $explode[1]); + } + } } public function setClearCacheAfter($clearCache) diff --git a/system/libs/pot/OTS_InfoRespond.php b/system/libs/pot/OTS_InfoRespond.php index 6e452371..3b345497 100644 --- a/system/libs/pot/OTS_InfoRespond.php +++ b/system/libs/pot/OTS_InfoRespond.php @@ -15,11 +15,11 @@ /** * Wrapper for 'info' respond's DOMDocument. - * + * *

* Note: as this class extends DOMDocument class and contains exacly respond XML tree you can work on it as on normal DOM tree. *

- * + * * @package POT * @version 0.1.0 * @property-read string $tspqVersion Root element version. @@ -48,252 +48,257 @@ class OTS_InfoRespond extends DOMDocument { /** * Returns version of root element. - * + * * @return string TSPQ version. * @throws DOMException On DOM operation error. */ - public function getTSPQVersion() - { - return $this->documentElement->getAttribute('version'); - } + public function getTSPQVersion() + { + return $this->documentElement->getAttribute('version'); + } /** * Returns server uptime. - * + * * @return int Uptime. * @throws DOMException On DOM operation error. */ - public function getUptime() - { - return (int) $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('uptime'); - } + public function getUptime() + { + return (int) $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('uptime'); + } /** * Returns server IP. - * + * * @return string IP. * @throws DOMException On DOM operation error. */ - public function getIP() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('ip'); - } + public function getIP() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('ip'); + } /** * Returns server name. - * + * * @return string Name. * @throws DOMException On DOM operation error. */ - public function getName() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('servername'); - } + public function getName() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('servername'); + } /** * Returns server port. - * + * * @return int Port. * @throws DOMException On DOM operation error. */ - public function getPort() - { - return (int) $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('port'); - } + public function getPort() + { + return (int) $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('port'); + } /** * Returns server location. - * + * * @return string Location. * @throws DOMException On DOM operation error. */ - public function getLocation() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('location'); - } + public function getLocation() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('location'); + } /** * Returns server website. - * + * * @return string Website URL. * @throws DOMException On DOM operation error. */ - public function getURL() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('url'); - } + public function getURL() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('url'); + } /** * Returns server attribute. - * + * * I have no idea what the hell is it representing :P. - * + * * @return string Attribute value. * @throws DOMException On DOM operation error. */ - public function getServer() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('server'); - } + public function getServer() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('server'); + } /** * Returns server version. - * + * * @return string Version. * @throws DOMException On DOM operation error. */ - public function getServerVersion() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('version'); - } + public function getServerVersion() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('version'); + } /** * Returns dedicated version of client. - * + * * @return string Version. * @throws DOMException On DOM operation error. */ - public function getClientVersion() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('client'); - } + public function getClientVersion() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('client'); + } /** * Returns owner name. - * + * * @return string Owner name. * @throws DOMException On DOM operation error. */ - public function getOwner() - { - return $this->documentElement->getElementsByTagName('owner')->item(0)->getAttribute('name'); - } + public function getOwner() + { + return $this->documentElement->getElementsByTagName('owner')->item(0)->getAttribute('name'); + } /** * Returns owner e-mail. - * + * * @return string Owner e-mail. * @throws DOMException On DOM operation error. */ - public function getEMail() - { - return $this->documentElement->getElementsByTagName('owner')->item(0)->getAttribute('email'); - } + public function getEMail() + { + return $this->documentElement->getElementsByTagName('owner')->item(0)->getAttribute('email'); + } /** * Returns current amount of players online. - * + * * @return int Count of players. * @throws DOMException On DOM operation error. */ - public function getOnlinePlayers() - { - return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('online'); - } + public function getOnlinePlayers() + { + return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('online'); + } /** * Returns maximum amount of players online. - * + * * @return int Maximum allowed count of players. * @throws DOMException On DOM operation error. */ - public function getMaxPlayers() - { - return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('max'); - } + public function getMaxPlayers() + { + return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('max'); + } /** * Returns record of online players. - * + * * @return int Players online record. * @throws DOMException On DOM operation error. */ - public function getPlayersPeak() - { - return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('peak'); - } + public function getPlayersPeak() + { + return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('peak'); + } /** * Returns number of all monsters on map. - * + * * @return int Count of monsters. * @throws DOMException On DOM operation error. */ - public function getMonstersCount() - { - return (int) $this->documentElement->getElementsByTagName('monsters')->item(0)->getAttribute('total'); - } + public function getMonstersCount(): int + { + return (int) $this->documentElement->getElementsByTagName('monsters')->item(0)->getAttribute('total'); + } + + public function getNPCsCount(): int + { + return (int) $this->documentElement->getElementsByTagName('npcs')->item(0)->getAttribute('total'); + } /** * Returns map name. - * + * * @return string Map name. * @throws DOMException On DOM operation error. */ - public function getMapName() - { - return $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('name'); - } + public function getMapName() + { + return $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('name'); + } /** * Returns map author. - * + * * @return string Mapper name. * @throws DOMException On DOM operation error. */ - public function getMapAuthor() - { - return $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('author'); - } + public function getMapAuthor() + { + return $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('author'); + } /** * Returns map width. - * + * * @return int Map width. * @throws DOMException On DOM operation error. */ - public function getMapWidth() - { - return (int) $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('width'); - } + public function getMapWidth() + { + return (int) $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('width'); + } /** * Returns map height. - * + * * @return int Map height. * @throws DOMException On DOM operation error. */ - public function getMapHeight() - { - return (int) $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('height'); - } + public function getMapHeight() + { + return (int) $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('height'); + } /** * Returns server's Message Of The Day - * + * * @version 0.1.0 * @return string Server MOTD. * @throws DOMException On DOM operation error. */ - public function getMOTD() - { - // look for text node child - foreach( $this->documentElement->getElementsByTagName('motd')->item(0)->childNodes as $child) - { - if($child->nodeType == XML_TEXT_NODE) - { - // found - return $child->nodeValue; - } - } + public function getMOTD() + { + // look for text node child + foreach( $this->documentElement->getElementsByTagName('motd')->item(0)->childNodes as $child) + { + if($child->nodeType == XML_TEXT_NODE) + { + // found + return $child->nodeValue; + } + } - // strange... - return ''; - } + // strange... + return ''; + } /** * Magic PHP5 method. - * + * * @version 0.1.0 * @since 0.1.0 * @param string $name Property name. @@ -301,89 +306,89 @@ class OTS_InfoRespond extends DOMDocument * @throws OutOfBoundsException For non-supported properties. * @throws DOMException On DOM operation error. */ - public function __get($name) - { - switch($name) - { - case 'tspqVersion': - return $this->getTSPQVersion(); + public function __get($name) + { + switch($name) + { + case 'tspqVersion': + return $this->getTSPQVersion(); - case 'uptime': - return $this->getUptime(); + case 'uptime': + return $this->getUptime(); - case 'ip': - return $this->getIP(); + case 'ip': + return $this->getIP(); - case 'name': - return $this->getName(); + case 'name': + return $this->getName(); - case 'port': - return $this->getPort(); + case 'port': + return $this->getPort(); - case 'location': - return $this->getLocation(); + case 'location': + return $this->getLocation(); - case 'url': - return $this->getURL(); + case 'url': + return $this->getURL(); - case 'server': - return $this->getServer(); + case 'server': + return $this->getServer(); - case 'serverVersion': - return $this->getServerVersion(); + case 'serverVersion': + return $this->getServerVersion(); - case 'clientVersion': - return $this->getClientVersion(); + case 'clientVersion': + return $this->getClientVersion(); - case 'owner': - return $this->getOwner(); + case 'owner': + return $this->getOwner(); - case 'eMail': - return $this->getEMail(); + case 'eMail': + return $this->getEMail(); - case 'onlinePlayers': - return $this->getOnlinePlayers(); + case 'onlinePlayers': + return $this->getOnlinePlayers(); - case 'maxPlayers': - return $this->getMaxPlayers(); + case 'maxPlayers': + return $this->getMaxPlayers(); - case 'playersPeak': - return $this->getPlayersPeak(); + case 'playersPeak': + return $this->getPlayersPeak(); - case 'monstersCount': - return $this->getMonstersCount(); + case 'monstersCount': + return $this->getMonstersCount(); - case 'mapName': - return $this->getMapName(); + case 'mapName': + return $this->getMapName(); - case 'mapAuthor': - return $this->getMapAuthor(); + case 'mapAuthor': + return $this->getMapAuthor(); - case 'mapWidth': - return $this->getMapWidth(); + case 'mapWidth': + return $this->getMapWidth(); - case 'mapHeight': - return $this->getMapHeight(); + case 'mapHeight': + return $this->getMapHeight(); - case 'motd': - return $this->getMOTD(); + case 'motd': + return $this->getMOTD(); - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } /** * Returns string representation of XML. - * + * * @version 0.1.0 * @since 0.1.0 * @return string String representation of object. */ - public function __toString() - { - return $this->saveXML(); - } + public function __toString() + { + return $this->saveXML(); + } } /**#@-*/ diff --git a/system/libs/pot/OTS_Player.php b/system/libs/pot/OTS_Player.php index 7b688d1c..099f5db1 100644 --- a/system/libs/pot/OTS_Player.php +++ b/system/libs/pot/OTS_Player.php @@ -2919,6 +2919,32 @@ class OTS_Player extends OTS_Row_DAO $this->data['banned'] = $ban['active']; $this->data['banned_time'] = $ban['expires']; } + + public function isNameLocked(): bool + { + // nothing can't be banned + if( !$this->isLoaded() ) { + throw new E_OTS_NotLoaded(); + } + + if($this->db->hasTable('player_namelocks')) { + $ban = $this->db->query('SELECT 1 FROM `player_namelocks` WHERE `player_id` = ' . $this->data['id'])->fetch(PDO::FETCH_ASSOC); + return (isset($ban['1'])); + } + else if($this->db->hasTable('bans')) { + if($this->db->hasColumn('bans', 'active')) { + $ban = $this->db->query('SELECT `active`, `expires` FROM `bans` WHERE `type` = 2 AND `active` = 1 AND `value` = ' . $this->data['id'] . ' AND (`expires` > ' . time() .' OR `expires` = -1) ORDER BY `expires` DESC')->fetch(); + return isset($ban['active']); + } + else { // tfs 0.2 + $ban = $this->db->query('SELECT `time` FROM `bans` WHERE `type` = 2 AND `account` = ' . $this->data['account_id'] . ' AND (`time` > ' . time() .' OR `time` = -1) ORDER BY `time` DESC')->fetch(); + + return isset($ban['time']) && ($ban['time'] == -1 || $ban['time'] > 0); + } + } + + return false; + } /** * Deletes player. * @@ -2953,21 +2979,14 @@ class OTS_Player extends OTS_Row_DAO * @return string Player proffesion name. * @throws E_OTS_NotLoaded If player is not loaded or global vocations list is not loaded. */ - public function getVocationName() + public function getVocationName(): string { if( !isset($this->data['vocation']) ) { throw new E_OTS_NotLoaded(); } - global $config; - $voc = $this->getVocation(); - if(!isset($config['vocations'][$voc])) { - return 'Unknown'; - } - - return $config['vocations'][$voc]; - //return POT::getInstance()->getVocationsList()->getVocationName($this->data['vocation']); + return OTS_Toolbox::getVocationName($this->data['vocation'], $this->data['promotion'] ?? 0); } /** diff --git a/system/libs/pot/OTS_ServerInfo.php b/system/libs/pot/OTS_ServerInfo.php index eebe0d2e..76ebcaf7 100644 --- a/system/libs/pot/OTS_ServerInfo.php +++ b/system/libs/pot/OTS_ServerInfo.php @@ -26,14 +26,19 @@ class OTS_ServerInfo * * @var string */ - private $server; + private string $server; /** * Connection port. * * @var int */ - private $port; + private int $port; + + /** + * Status timeout + */ + private float $timeout = 2.0; /** * Creates handler for new server. @@ -41,11 +46,11 @@ class OTS_ServerInfo * @param string $server Server IP/domain. * @param int $port OTServ port. */ - public function __construct($server, $port) - { - $this->server = $server; - $this->port = $port; - } + public function __construct($server, $port) + { + $this->server = $server; + $this->port = $port; + } /** * Sends packet to server. @@ -54,46 +59,46 @@ class OTS_ServerInfo * @return OTS_Buffer|null Respond buffer (null if server is offline). * @throws E_OTS_OutOfBuffer When there is read attemp after end of packet stream. */ - private function send(OTS_Buffer $packet) - { - // connects to server - $socket = @fsockopen($this->server, $this->port, $error, $message, setting('core.status_timeout')); + private function send(OTS_Buffer $packet) + { + // connects to server + $socket = @fsockopen($this->server, $this->port, $error, $message, $this->timeout); - // if connected then checking statistics - if($socket) - { - // sets 5 second timeout for reading and writing - stream_set_timeout($socket, 5); + // if connected then checking statistics + if($socket) + { + // sets 5 second timeout for reading and writing + stream_set_timeout($socket, 5); - // creates real packet - $packet = $packet->getBuffer(); - $packet = pack('v', strlen($packet) ) . $packet; + // creates real packet + $packet = $packet->getBuffer(); + $packet = pack('v', strlen($packet) ) . $packet; - // sends packet with request - // 06 - length of packet, 255, 255 is the comamnd identifier, 'info' is a request - fwrite($socket, $packet); + // sends packet with request + // 06 - length of packet, 255, 255 is the comamnd identifier, 'info' is a request + fwrite($socket, $packet); - // reads respond - //$data = stream_get_contents($socket); + // reads respond + //$data = stream_get_contents($socket); $data = ''; while (!feof($socket)) $data .= fgets($socket, 1024); - // closing connection to current server - fclose($socket); + // closing connection to current server + fclose($socket); - // sometimes server returns empty info - if( empty($data) ) - { - // returns offline state - return false; - } + // sometimes server returns empty info + if( empty($data) ) + { + // returns offline state + return false; + } - return new OTS_Buffer($data); - } + return new OTS_Buffer($data); + } - return false; - } + return false; + } /** * Queries server status. @@ -108,30 +113,30 @@ class OTS_ServerInfo * @example examples/info.php info.php * @tutorial POT/Server_status.pkg */ - public function status() - { - // request packet - $request = new OTS_Buffer(); - $request->putChar(255); - $request->putChar(255); - $request->putString('info', false); + public function status() + { + // request packet + $request = new OTS_Buffer(); + $request->putChar(255); + $request->putChar(255); + $request->putString('info', false); - $status = $this->send($request); + $status = $this->send($request); - // checks if server is online - if($status) - { - // loads respond XML - $info = new OTS_InfoRespond(); - if(!$info->loadXML( $status->getBuffer())) + // checks if server is online + if($status) + { + // loads respond XML + $info = new OTS_InfoRespond(); + if(!$info->loadXML( $status->getBuffer())) return false; - return $info; - } + return $info; + } - // offline - return false; - } + // offline + return false; + } /** * Queries server information. @@ -146,26 +151,26 @@ class OTS_ServerInfo * @example examples/server.php info.php * @tutorial POT/Server_status.pkg */ - public function info($flags) - { - // request packet - $request = new OTS_Buffer(); - $request->putChar(255); - $request->putChar(1); - $request->putShort($flags); + public function info($flags) + { + // request packet + $request = new OTS_Buffer(); + $request->putChar(255); + $request->putChar(1); + $request->putShort($flags); - $status = $this->send($request); + $status = $this->send($request); - // checks if server is online - if($status) - { - // loads respond - return new OTS_ServerStatus($status); - } + // checks if server is online + if($status) + { + // loads respond + return new OTS_ServerStatus($status); + } - // offline - return false; - } + // offline + return false; + } /** * Checks player online status. @@ -180,27 +185,27 @@ class OTS_ServerInfo * @example examples/server.php info.php * @tutorial POT/Server_status.pkg */ - public function playerStatus($name) - { - // request packet - $request = new OTS_Buffer(); - $request->putChar(255); - $request->putChar(1); - $request->putShort(OTS_ServerStatus::REQUEST_PLAYER_STATUS_INFO); - $request->putString($name); + public function playerStatus($name) + { + // request packet + $request = new OTS_Buffer(); + $request->putChar(255); + $request->putChar(1); + $request->putShort(OTS_ServerStatus::REQUEST_PLAYER_STATUS_INFO); + $request->putString($name); - $status = $this->send($request); + $status = $this->send($request); - // checks if server is online - if($status) - { - $status->getChar(); - return (bool) $status->getChar(); - } + // checks if server is online + if($status) + { + $status->getChar(); + return (bool) $status->getChar(); + } - // offline - return false; - } + // offline + return false; + } /** * Magic PHP5 method. @@ -210,20 +215,24 @@ class OTS_ServerInfo * @throws OutOfBoundsException For non-supported properties. * @throws E_OTS_OutOfBuffer When there is read attemp after end of packet stream. */ - public function __get($name) - { - switch($name) - { - case 'status': - return $this->status(); + public function __get($name) + { + switch($name) + { + case 'status': + return $this->status(); - case 'info': - return $this->info(OTS_ServerStatus::REQUEST_BASIC_SERVER_INFO | OTS_ServerStatus::REQUEST_OWNER_SERVER_INFO | OTS_ServerStatus::REQUEST_MISC_SERVER_INFO | OTS_ServerStatus::REQUEST_PLAYERS_INFO | OTS_ServerStatus::REQUEST_MAP_INFO | OTS_ServerStatus::REQUEST_PLAYER_STATUS_INFO); + case 'info': + return $this->info(OTS_ServerStatus::REQUEST_BASIC_SERVER_INFO | OTS_ServerStatus::REQUEST_OWNER_SERVER_INFO | OTS_ServerStatus::REQUEST_MISC_SERVER_INFO | OTS_ServerStatus::REQUEST_PLAYERS_INFO | OTS_ServerStatus::REQUEST_MAP_INFO | OTS_ServerStatus::REQUEST_PLAYER_STATUS_INFO); - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } + + public function setTimeout($timeout) { + $this->timeout = $timeout; + } } /**#@-*/ diff --git a/system/libs/pot/OTS_ServerStatus.php b/system/libs/pot/OTS_ServerStatus.php index e13a0f5b..4ba0035c 100644 --- a/system/libs/pot/OTS_ServerStatus.php +++ b/system/libs/pot/OTS_ServerStatus.php @@ -40,175 +40,175 @@ class OTS_ServerStatus /** * Basic server info. */ - const REQUEST_BASIC_SERVER_INFO = 1; + const REQUEST_BASIC_SERVER_INFO = 1; /** * Server owner info. */ - const REQUEST_OWNER_SERVER_INFO = 2; + const REQUEST_OWNER_SERVER_INFO = 2; /** * Server extra info. */ - const REQUEST_MISC_SERVER_INFO = 4; + const REQUEST_MISC_SERVER_INFO = 4; /** * Players stats info. */ - const REQUEST_PLAYERS_INFO = 8; + const REQUEST_PLAYERS_INFO = 8; /** * Map info. */ - const REQUEST_MAP_INFO = 16; + const REQUEST_MAP_INFO = 16; /** * Extended players info. */ - const REQUEST_EXT_PLAYERS_INFO = 32; + const REQUEST_EXT_PLAYERS_INFO = 32; /** * Player status info. */ - const REQUEST_PLAYER_STATUS_INFO = 64; + const REQUEST_PLAYER_STATUS_INFO = 64; /** * Server software info. */ - const REQUEST_SERVER_SOFTWARE_INFO = 128; + const REQUEST_SERVER_SOFTWARE_INFO = 128; /** * Basic server respond. */ - const RESPOND_BASIC_SERVER_INFO = 0x10; + const RESPOND_BASIC_SERVER_INFO = 0x10; /** * Server owner respond. */ - const RESPOND_OWNER_SERVER_INFO = 0x11; + const RESPOND_OWNER_SERVER_INFO = 0x11; /** * Server extra respond. */ - const RESPOND_MISC_SERVER_INFO = 0x12; + const RESPOND_MISC_SERVER_INFO = 0x12; /** * Players stats respond. */ - const RESPOND_PLAYERS_INFO = 0x20; + const RESPOND_PLAYERS_INFO = 0x20; /** * Map respond. */ - const RESPOND_MAP_INFO = 0x30; + const RESPOND_MAP_INFO = 0x30; /** * Extended players info. */ - const RESPOND_EXT_PLAYERS_INFO = 0x21; + const RESPOND_EXT_PLAYERS_INFO = 0x21; /** * Player status info. */ - const RESPOND_PLAYER_STATUS_INFO = 0x22; + const RESPOND_PLAYER_STATUS_INFO = 0x22; /** * Server software info. */ - const RESPOND_SERVER_SOFTWARE_INFO = 0x23; + const RESPOND_SERVER_SOFTWARE_INFO = 0x23; /** * Server name. * * @var string */ - private $name; + private $name; /** * Server IP. * * @var string */ - private $ip; + private $ip; /** * Server port. * * @var string */ - private $port; + private $port; /** * Owner name. * * @var string */ - private $owner; + private $owner; /** * Owner's e-mail. * * @var string */ - private $eMail; + private $eMail; /** * Message of the day. * * @var string */ - private $motd; + private $motd; /** * Server location. * * @var string */ - private $location; + private $location; /** * Website URL. * * @var string */ - private $url; + private $url; /** * Uptime. * * @var int */ - private $uptime; + private $uptime; /** * Status version. * * @var string */ - private $version; + private $version; /** * Players online. * * @var int */ - private $online; + private $online; /** * Maximum players. * * @var int */ - private $max; + private $max; /** * Players peak. * * @var int */ - private $peak; + private $peak; /** * Map name. * * @var string */ - private $map; + private $map; /** * Map author. * * @var string */ - private $author; + private $author; /** * Map width. * * @var int */ - private $width; + private $width; /** * Map height. * * @var int */ - private $height; + private $height; /** * Players online list. * * @var array */ - private $players = array(); + private $players = array(); /** * Server software. @@ -224,277 +224,277 @@ class OTS_ServerStatus * * @param OTS_Buffer $info Information packet. */ - public function __construct(OTS_Buffer $info) - { - // skips packet length - $info->getShort(); + public function __construct(OTS_Buffer $info) + { + // skips packet length + $info->getShort(); - while( $info->isValid() ) - { - switch( $info->getChar() ) - { - case self::RESPOND_BASIC_SERVER_INFO: - $this->name = $info->getString(); - $this->ip = $info->getString(); - $this->port = (int) $info->getString(); - break; + while( $info->isValid() ) + { + switch( $info->getChar() ) + { + case self::RESPOND_BASIC_SERVER_INFO: + $this->name = $info->getString(); + $this->ip = $info->getString(); + $this->port = (int) $info->getString(); + break; - case self::RESPOND_OWNER_SERVER_INFO: - $this->owner = $info->getString(); - $this->eMail = $info->getString(); - break; + case self::RESPOND_OWNER_SERVER_INFO: + $this->owner = $info->getString(); + $this->eMail = $info->getString(); + break; - case self::RESPOND_MISC_SERVER_INFO: - $this->motd = $info->getString(); - $this->location = $info->getString(); - $this->url = $info->getString(); + case self::RESPOND_MISC_SERVER_INFO: + $this->motd = $info->getString(); + $this->location = $info->getString(); + $this->url = $info->getString(); - $uptime = $info->getLong() << 32; + $uptime = $info->getLong() << 32; - $this->uptime += $info->getLong() + $uptime; - $this->version = $info->getString(); - break; + $this->uptime += $info->getLong() + $uptime; + $this->version = $info->getString(); + break; - case self::RESPOND_PLAYERS_INFO: - $this->online = $info->getLong(); - $this->max = $info->getLong(); - $this->peak = $info->getLong(); - break; + case self::RESPOND_PLAYERS_INFO: + $this->online = $info->getLong(); + $this->max = $info->getLong(); + $this->peak = $info->getLong(); + break; - case self::RESPOND_MAP_INFO: - $this->map = $info->getString(); - $this->author = $info->getString(); - $this->width = $info->getShort(); - $this->height = $info->getShort(); - break; + case self::RESPOND_MAP_INFO: + $this->map = $info->getString(); + $this->author = $info->getString(); + $this->width = $info->getShort(); + $this->height = $info->getShort(); + break; - case self::RESPOND_EXT_PLAYERS_INFO: - $count = $info->getLong(); + case self::RESPOND_EXT_PLAYERS_INFO: + $count = $info->getLong(); - for($i = 0; $i < $count; $i++) - { - $name = $info->getString(); - $this->players[$name] = $info->getLong(); - } - break; + for($i = 0; $i < $count; $i++) + { + $name = $info->getString(); + $this->players[$name] = $info->getLong(); + } + break; case self::RESPOND_SERVER_SOFTWARE_INFO: $this->softwareName = $info->getString(); $this->softwareVersion = $info->getString(); $this->softwareProtocol = $info->getString(); break; - } - } - } + } + } + } /** * Returns server uptime. * * @return int Uptime. */ - public function getUptime() - { - return $this->uptime; - } + public function getUptime() + { + return $this->uptime; + } /** * Returns server IP. * * @return string IP. */ - public function getIP() - { - return $this->ip; - } + public function getIP() + { + return $this->ip; + } /** * Returns server name. * * @return string Name. */ - public function getName() - { - return $this->name; - } + public function getName() + { + return $this->name; + } /** * Returns server port. * * @return int Port. */ - public function getPort() - { - return $this->port; - } + public function getPort() + { + return $this->port; + } /** * Returns server location. * * @return string Location. */ - public function getLocation() - { - return $this->location; - } + public function getLocation() + { + return $this->location; + } /** * Returns server website. * * @return string Website URL. */ - public function getURL() - { - return $this->url; - } + public function getURL() + { + return $this->url; + } /** * Returns server version. * * @return string Version. */ - public function getServerVersion() - { - return $this->version; - } + public function getServerVersion() + { + return $this->version; + } /** * Returns owner name. * * @return string Owner name. */ - public function getOwner() - { - return $this->owner; - } + public function getOwner() + { + return $this->owner; + } /** * Returns owner e-mail. * * @return string Owner e-mail. */ - public function getEMail() - { - return $this->eMail; - } + public function getEMail() + { + return $this->eMail; + } /** * Returns current amount of players online. * * @return int Count of players. */ - public function getOnlinePlayers() - { - return $this->online; - } + public function getOnlinePlayers() + { + return $this->online; + } /** * Returns maximum amount of players online. * * @return int Maximum allowed count of players. */ - public function getMaxPlayers() - { - return $this->max; - } + public function getMaxPlayers() + { + return $this->max; + } /** * Returns record of online players. * * @return int Players online record. */ - public function getPlayersPeak() - { - return $this->peak; - } + public function getPlayersPeak() + { + return $this->peak; + } /** * Returns map name. * * @return string Map name. */ - public function getMapName() - { - return $this->map; - } + public function getMapName() + { + return $this->map; + } /** * Returns map author. * * @return string Mapper name. */ - public function getMapAuthor() - { - return $this->author; - } + public function getMapAuthor() + { + return $this->author; + } /** * Returns map width. * * @return int Map width. */ - public function getMapWidth() - { - return $this->width; - } + public function getMapWidth() + { + return $this->width; + } /** * Returns map height. * * @return int Map height. */ - public function getMapHeight() - { - return $this->height; - } + public function getMapHeight() + { + return $this->height; + } /** * Returns server's Message Of The Day * * @return string Server MOTD. */ - public function getMOTD() - { - return $this->motd; - } + public function getMOTD() + { + return $this->motd; + } /** * Returns list of players currently online. * * @return array List of players in format 'name' => level. */ - public function getPlayers() - { - } + public function getPlayers() + { + } /** * Returns software name. * * @return string Software name. */ - public function getSoftwareName() - { - return $this->softwareName; - } + public function getSoftwareName() + { + return $this->softwareName; + } /** * Returns software version. * * @return string Software version. */ - public function getSoftwareVersion() - { - return $this->softwareVersion; - } + public function getSoftwareVersion() + { + return $this->softwareVersion; + } /** * Returns software protocol. * * @return string Software protocol. */ - public function getSoftwareProtocol() - { - return $this->softwareProtocol; - } + public function getSoftwareProtocol() + { + return $this->softwareProtocol; + } /** * Magic PHP5 method. @@ -503,68 +503,68 @@ class OTS_ServerStatus * @return mixed Property value. * @throws OutOfBoundsException For non-supported properties. */ - public function __get($name) - { - switch($name) - { - case 'uptime': - return $this->getUptime(); + public function __get($name) + { + switch($name) + { + case 'uptime': + return $this->getUptime(); - case 'ip': - return $this->getIP(); + case 'ip': + return $this->getIP(); - case 'name': - return $this->getName(); + case 'name': + return $this->getName(); - case 'port': - return $this->getPort(); + case 'port': + return $this->getPort(); - case 'location': - return $this->getLocation(); + case 'location': + return $this->getLocation(); - case 'url': - return $this->getURL(); + case 'url': + return $this->getURL(); - case 'serverVersion': - return $this->getServerVersion(); + case 'serverVersion': + return $this->getServerVersion(); - case 'owner': - return $this->getOwner(); + case 'owner': + return $this->getOwner(); - case 'eMail': - return $this->getEMail(); + case 'eMail': + return $this->getEMail(); - case 'onlinePlayers': - return $this->getOnlinePlayers(); + case 'onlinePlayers': + return $this->getOnlinePlayers(); - case 'maxPlayers': - return $this->getMaxPlayers(); + case 'maxPlayers': + return $this->getMaxPlayers(); - case 'playersPeak': - return $this->getPlayersPeak(); + case 'playersPeak': + return $this->getPlayersPeak(); - case 'mapName': - return $this->getMapName(); + case 'mapName': + return $this->getMapName(); - case 'mapAuthor': - return $this->getMapAuthor(); + case 'mapAuthor': + return $this->getMapAuthor(); - case 'mapWidth': - return $this->getMapWidth(); + case 'mapWidth': + return $this->getMapWidth(); - case 'mapHeight': - return $this->getMapHeight(); + case 'mapHeight': + return $this->getMapHeight(); - case 'motd': - return $this->getMOTD(); + case 'motd': + return $this->getMOTD(); - case 'players': - return $this->getPlayers(); + case 'players': + return $this->getPlayers(); - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } } /**#@-*/ diff --git a/system/libs/pot/OTS_Toolbox.php b/system/libs/pot/OTS_Toolbox.php index 980e5cb5..575dba6f 100644 --- a/system/libs/pot/OTS_Toolbox.php +++ b/system/libs/pot/OTS_Toolbox.php @@ -15,7 +15,7 @@ /** * Toolbox for common operations. - * + * * @package POT * @version 0.1.5 */ @@ -23,41 +23,41 @@ class OTS_Toolbox { /** * Calculates experience points needed for given level. - * + * * @param int $level Level for which experience should be calculated. * @param int $experience Current experience points. * @return int Experience points for level. */ public static function experienceForLevel($level, $experience = 0) - { - //return 50 * ($level - 1) * ($level * $level - 5 * $level + 12) / 3 - $experience; + { + //return 50 * ($level - 1) * ($level * $level - 5 * $level + 12) / 3 - $experience; $level = $level - 1; return ((50 * $level * $level * $level) - (150 * $level * $level) + (400 * $level)) / 3; - } + } /** * Finds out which level user have basing on his/her experience. - * + * *

* PHP doesn't support complex numbers natively so solving third-level polynomials would be quite hard. Rather then doing this, this method iterates calculating experience for next levels until it finds one which requires enought experience we have. Because of that, for high experience values this function can take relatively long time to be executed. *

- * + * * @param int $experience Current experience points. * @return int Experience level. */ - public static function levelForExperience($experience) - { - // default level - $level = 1; + public static function levelForExperience($experience) + { + // default level + $level = 1; - // until we will find level which requires more experience then we have we will step to next - while( self::experienceForLevel($level + 1) <= $experience) - { - $level++; - } + // until we will find level which requires more experience then we have we will step to next + while( self::experienceForLevel($level + 1) <= $experience) + { + $level++; + } - return $level; - } + return $level; + } /** * @version 0.1.5 @@ -65,25 +65,25 @@ class OTS_Toolbox * @return OTS_Players_List Filtered list. * @deprecated 0.1.5 Use OTS_PlayerBans_List. */ - public static function bannedPlayers() - { - // creates filter - $filter = new OTS_SQLFilter(); - $filter->addFilter( new OTS_SQLField('type', 'bans'), POT::BAN_PLAYER); - $filter->addFilter( new OTS_SQLField('active', 'bans'), 1); - $filter->addFilter( new OTS_SQLField('value', 'bans'), new OTS_SQLField('id', 'players') ); + public static function bannedPlayers() + { + // creates filter + $filter = new OTS_SQLFilter(); + $filter->addFilter( new OTS_SQLField('type', 'bans'), POT::BAN_PLAYER); + $filter->addFilter( new OTS_SQLField('active', 'bans'), 1); + $filter->addFilter( new OTS_SQLField('value', 'bans'), new OTS_SQLField('id', 'players') ); - // selects only active bans - $actives = new OTS_SQLFilter(); - $actives->addFilter( new OTS_SQLField('expires', 'bans'), 0); - $actives->addFilter( new OTS_SQLField('time', 'bans'), time(), OTS_SQLFilter::OPERATOR_GREATER, OTS_SQLFilter::CRITERIUM_OR); - $filter->addFilter($actives); + // selects only active bans + $actives = new OTS_SQLFilter(); + $actives->addFilter( new OTS_SQLField('expires', 'bans'), 0); + $actives->addFilter( new OTS_SQLField('time', 'bans'), time(), OTS_SQLFilter::OPERATOR_GREATER, OTS_SQLFilter::CRITERIUM_OR); + $filter->addFilter($actives); - // creates list and aplies filter - $list = new OTS_Players_List(); - $list->setFilter($filter); - return $list; - } + // creates list and aplies filter + $list = new OTS_Players_List(); + $list->setFilter($filter); + return $list; + } /** * @version 0.1.5 @@ -91,25 +91,34 @@ class OTS_Toolbox * @return OTS_Accounts_List Filtered list. * @deprecated 0.1.5 Use OTS_AccountBans_List. */ - public static function bannedAccounts() - { - // creates filter - $filter = new OTS_SQLFilter(); - $filter->addFilter( new OTS_SQLField('type', 'bans'), POT::BAN_ACCOUNT); - $filter->addFilter( new OTS_SQLField('active', 'bans'), 1); - $filter->addFilter( new OTS_SQLField('value', 'bans'), new OTS_SQLField('id', 'accounts') ); + public static function bannedAccounts() + { + // creates filter + $filter = new OTS_SQLFilter(); + $filter->addFilter( new OTS_SQLField('type', 'bans'), POT::BAN_ACCOUNT); + $filter->addFilter( new OTS_SQLField('active', 'bans'), 1); + $filter->addFilter( new OTS_SQLField('value', 'bans'), new OTS_SQLField('id', 'accounts') ); - // selects only active bans - $actives = new OTS_SQLFilter(); - $actives->addFilter( new OTS_SQLField('expires', 'bans'), 0); - $actives->addFilter( new OTS_SQLField('time', 'bans'), time(), OTS_SQLFilter::OPERATOR_GREATER, OTS_SQLFilter::CRITERIUM_OR); - $filter->addFilter($actives); + // selects only active bans + $actives = new OTS_SQLFilter(); + $actives->addFilter( new OTS_SQLField('expires', 'bans'), 0); + $actives->addFilter( new OTS_SQLField('time', 'bans'), time(), OTS_SQLFilter::OPERATOR_GREATER, OTS_SQLFilter::CRITERIUM_OR); + $filter->addFilter($actives); - // creates list and aplies filter - $list = new OTS_Accounts_List(); - $list->setFilter($filter); - return $list; - } + // creates list and aplies filter + $list = new OTS_Accounts_List(); + $list->setFilter($filter); + return $list; + } + + public static function getVocationName($id, $promotion = 0): string + { + if($promotion > 0) { + $id = ($id + ($promotion * config('vocations_amount'))); + } + + return config('vocations')[$id] ?? 'Unknown'; + } } /**#@-*/ diff --git a/system/locale/de/install.php b/system/locale/de/install.php index ad354609..351f6009 100644 --- a/system/locale/de/install.php +++ b/system/locale/de/install.php @@ -48,6 +48,8 @@ $locale['step_config'] = 'Konfiguration'; $locale['step_config_title'] = 'Grundkonfiguration'; $locale['step_config_server_path'] = 'Serverpfad'; $locale['step_config_server_path_desc'] = 'Pfad zu Ihrem TFS-Hauptverzeichnis, in dem sich die config.lua befinden.'; +$locale['step_config_site_url'] = 'Website URL'; +$locale['step_config_site_url_desc'] = 'Ihre Website-Adresse.'; $locale['step_config_mail_admin'] = 'Admin E-Mail'; $locale['step_config_mail_admin_desc'] = 'Adresse, an die E-Mails aus dem Kontaktformular gesendet werden, z. B. admin@gmail.com'; $locale['step_config_mail_admin_error'] = 'Admin E-Mail ist nicht korrekt.'; @@ -76,6 +78,7 @@ $locale['step_database_error_mysql_connect_3'] = 'MySQL ist nicht richtig konfig $locale['step_database_error_mysql_connect_4'] = 'MySQL-Server läuft nicht.'; $locale['step_database_error_schema'] = 'Fehler beim Importieren des Schemas:'; $locale['step_database_success_schema'] = '$PREFIX$ Tabellen wurden erfolgreich installiert.'; +$locale['step_database_success_import_data'] = 'Import von Daten für Tabellen was erfolgreich.'; $locale['step_database_error_file'] = '$FILE$ konnte nicht geöffnet werden. Bitte kopieren Sie diesen Inhalt und fügen Sie ihn dort ein:'; $locale['step_database_adding_field'] = 'Folgendes Feld wurde hinzugefügt: '; $locale['step_database_modifying_field'] = 'Folgendes Feld wurde geändert: '; diff --git a/system/locale/en/install.php b/system/locale/en/install.php index 0cbd29ad..c623035c 100644 --- a/system/locale/en/install.php +++ b/system/locale/en/install.php @@ -52,6 +52,8 @@ $locale['step_config'] = 'Configuration'; $locale['step_config_title'] = 'Basic configuration'; $locale['step_config_server_path'] = 'Server path'; $locale['step_config_server_path_desc'] = 'Path to your TFS main directory, where you have config.lua located.'; +$locale['step_config_site_url'] = 'Website URL'; +$locale['step_config_site_url_desc'] = 'Your website address.'; $locale['step_config_mail_admin'] = 'Admin Email'; $locale['step_config_mail_admin_desc'] = 'Address where emails from contact form will be delivered, for example admin@gmail.com'; $locale['step_config_mail_admin_error'] = 'Admin Email is not correct.'; @@ -81,6 +83,7 @@ $locale['step_database_error_mysql_connect_3'] = 'MySQL is not configured proper $locale['step_database_error_mysql_connect_4'] = 'MySQL server is not running.'; $locale['step_database_error_schema'] = 'Error while importing schema:'; $locale['step_database_success_schema'] = 'Successfully installed $PREFIX$ tables.'; +$locale['step_database_success_import_data'] = 'Successfully imported base data for tables.'; $locale['step_database_error_file'] = '$FILE$ couldn\'t be opened. Please copy this content and paste there:'; $locale['step_database_adding_field'] = 'Adding field'; $locale['step_database_modifying_field'] = 'Modifying field'; diff --git a/system/locale/pl/install.php b/system/locale/pl/install.php index 5b6725cf..a8ea0cf6 100644 --- a/system/locale/pl/install.php +++ b/system/locale/pl/install.php @@ -52,6 +52,8 @@ $locale['step_config'] = 'Konfiguracja'; $locale['step_config_title'] = 'Podstawowa konfiguracja'; $locale['step_config_server_path'] = 'Ścieżka do serwera'; $locale['step_config_server_path_desc'] = 'Ścieżka do Twojego folderu z TFS, gdzie znajduje się plik config.lua.'; +$locale['step_config_server_url'] = 'Adres strony'; +$locale['step_config_server_url_desc'] = 'Adres tej strony www.'; $locale['step_config_mail_admin'] = 'E-Mail admina'; $locale['step_config_mail_admin_desc'] = 'Na ten adres będą dostarczane E-Maile z formularza kontaktowego, przykładowo admin@gmail.com'; $locale['step_config_mail_admin_error'] = 'E-Mail admina jest niepoprawny.'; @@ -79,7 +81,8 @@ $locale['step_database_error_mysql_connect_2'] = 'Możliwe przyczyny:'; $locale['step_database_error_mysql_connect_3'] = 'MySQL nie jest poprawnie skonfigurowane w config.lua.'; $locale['step_database_error_mysql_connect_4'] = 'Serwer MySQL nie jest uruchomiony.'; $locale['step_database_error_schema'] = 'Błąd podczas importowania struktury bazy danych:'; -$locale['step_database_success_schema'] = 'Pomyślnie zainstalowano tabele $PREFIX$.'; +$locale['step_database_success_schema'] = 'Pomyślnie zaimportowano tabele $PREFIX$.'; +$locale['step_database_success_import_data'] = 'Pomyślnie załadowano bazowe dane dla tabel.'; $locale['step_database_error_file'] = '$FILE$ nie mógł zostać otwarty. Proszę skopiować zawartość pola tekstowego i wkleić do tego pliku:'; $locale['step_database_adding_field'] = 'Dodawanie pola'; $locale['step_database_modifying_field'] = 'Modyfikacja pola'; diff --git a/system/login.php b/system/login.php index 42a96111..335177e7 100644 --- a/system/login.php +++ b/system/login.php @@ -34,8 +34,10 @@ if($logged) { $twig->addGlobal('account_logged', $account_logged); } -setSession('last_visit', time()); -if(defined('PAGE')) { - setSession('last_page', PAGE); +if (!defined('IGNORE_SET_LAST_VISIT') || !IGNORE_SET_LAST_VISIT) { + setSession('last_visit', time()); + if(defined('PAGE')) { + setSession('last_page', PAGE); + } + setSession('last_uri', $_SERVER['REQUEST_URI']); } -setSession('last_uri', $_SERVER['REQUEST_URI']); diff --git a/system/migrate.php b/system/migrate.php index 2199fd73..2bbb3786 100644 --- a/system/migrate.php +++ b/system/migrate.php @@ -9,6 +9,8 @@ */ defined('MYAAC') or die('Direct access not allowed!'); +global $db; + // database migrations $tmp = ''; if(fetchDatabaseConfig('database_version', $tmp)) { // we got version diff --git a/system/migrations/44.php b/system/migrations/44.php index ea98d6f2..6db23412 100644 --- a/system/migrations/44.php +++ b/system/migrations/44.php @@ -1,27 +1,20 @@ query("ALTER TABLE `myaac_account_actions` DROP KEY `account_id`;"); - $db->query("ALTER TABLE `myaac_account_actions` ADD COLUMN `id` INT(11) NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`id`);"); +// 2025-05-14 +// update pages links +// server-info conflicts with apache2 mod +// Changelog conflicts with changelog files - $db->modifyColumn(TABLE_PREFIX . 'account_actions', 'ip', "VARCHAR(45) NOT NULL DEFAULT ''"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = INET_NTOA(`ip`) WHERE `ip` != '0';"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = INET6_NTOA(`ipv6`) WHERE `ip` = '0';"); - $db->dropColumn(TABLE_PREFIX . 'account_actions', 'ipv6'); +use MyAAC\Models\Menu; +use MyAAC\Models\Pages; + +$up = function() { + Menu::where('link', 'server-info')->update(['link' => 'ots-info']); + Menu::where('link', 'changelog')->update(['link' => 'change-log']); }; -$down = function () use ($db) { - $db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` DROP `id`;"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` ADD KEY (`account_id`);"); - - $db->addColumn(TABLE_PREFIX . 'account_actions', 'ipv6', "BINARY(16) NOT NULL DEFAULT 0x00000000000000000000000000000000 AFTER ip"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ipv6` = INET6_ATON(ip) WHERE NOT IS_IPV4(`ip`);"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = INET_ATON(`ip`) WHERE IS_IPV4(`ip`);"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = 0 WHERE `ipv6` != 0x00000000000000000000000000000000;"); - $db->modifyColumn(TABLE_PREFIX . 'account_actions', 'ip', "INT(11) UNSIGNED NOT NULL DEFAULT 0;"); +$down = function() { + Menu::where('link', 'ots-info')->update(['link' => 'server-info']); + Menu::where('link', 'change-log')->update(['link' => 'changelog']); }; + diff --git a/system/migrations/45.php b/system/migrations/45.php new file mode 100644 index 00000000..c2d8aaec --- /dev/null +++ b/system/migrations/45.php @@ -0,0 +1,32 @@ +update(['hide' => 1]); + + $rules = Pages::where('name', 'rules')->first(); + if (!$rules) { + Pages::create([ + 'name' => 'rules', + 'title' => 'Server Rules', + 'body' => '{{ config.lua.serverName }} Rules
' . nl2br(file_get_contents(__DIR__ . '/30-rules.txt')), + 'date' => time(), + 'player_id' => 1, + 'php' => 0, + 'enable_tinymce' => 1, + 'access' => 0, + 'hide' => 0, + ]); + } +}; + +$down = function() { + Pages::where('name', 'rules_on_the_page')->update(['hide' => 0]); +}; + diff --git a/system/migrations/46-account_emails_verify.sql b/system/migrations/46-account_emails_verify.sql new file mode 100644 index 00000000..13d42b16 --- /dev/null +++ b/system/migrations/46-account_emails_verify.sql @@ -0,0 +1,8 @@ +CREATE TABLE `myaac_account_emails_verify` +( + `id` int NOT NULL AUTO_INCREMENT, + `account_id` int NOT NULL, + `hash` varchar(32) NOT NULL, + `sent_at` int NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; diff --git a/system/migrations/46.php b/system/migrations/46.php new file mode 100644 index 00000000..452527e5 --- /dev/null +++ b/system/migrations/46.php @@ -0,0 +1,24 @@ +hasColumn('accounts', 'email_hash')) { + $db->dropColumn('accounts', 'email_hash'); + } + + if (!$db->hasTable(TABLE_PREFIX . 'account_emails_verify')) { + $db->query(file_get_contents(__DIR__ . '/46-account_emails_verify.sql')); + } +}; + +$down = function () use ($db) { + if (!$db->hasColumn('accounts', 'email_hash')) { + $db->addColumn('accounts', 'email_hash', "varchar(32) NOT NULL DEFAULT ''"); + } + + if ($db->hasTable(TABLE_PREFIX . 'account_emails_verify')) { + $db->dropTable(TABLE_PREFIX . 'account_emails_verify'); + } +}; diff --git a/system/pages/404.php b/system/pages/404.php index 90a8921a..60fb66aa 100644 --- a/system/pages/404.php +++ b/system/pages/404.php @@ -8,7 +8,7 @@ * @link https://my-aac.org */ defined('MYAAC') or die('Direct access not allowed!'); -$title = '404 Not Found'; +$title = 'Not Found'; header('HTTP/1.0 404 Not Found'); ?> diff --git a/system/pages/405.php b/system/pages/405.php index 3d585f59..d1eee43a 100644 --- a/system/pages/405.php +++ b/system/pages/405.php @@ -8,7 +8,7 @@ * @link https://my-aac.org */ defined('MYAAC') or die('Direct access not allowed!'); -$title = '405 Method Not Allowed'; +$title = 'Method Not Allowed'; header('HTTP/1.0 405 Method Not Allowed'); ?> diff --git a/system/pages/account/change-email.php b/system/pages/account/change-email.php index c97b5541..6dc8d388 100644 --- a/system/pages/account/change-email.php +++ b/system/pages/account/change-email.php @@ -17,6 +17,8 @@ if(!$logged) { return; } +csrfProtect(); + $email_new_time = $account_logged->getCustomField("email_new_time"); if($email_new_time > 10) { @@ -164,7 +166,7 @@ if(isset($_POST['emailchangecancel']) && $_POST['emailchangecancel'] == 1) { $account_logged->setCustomField("email_new", ""); $account_logged->setCustomField("email_new_time", 0); - $custom_buttons = '
' . $twig->render('buttons.back.html.twig') . '
'; + $custom_buttons = '
' . csrf(true) . '
' . $twig->render('buttons.back.html.twig') . '
'; $twig->display('success.html.twig', array( 'title' => 'Email Address Change Cancelled', diff --git a/system/pages/account/change-info.php b/system/pages/account/change-info.php index 709dce27..4aa64be5 100644 --- a/system/pages/account/change-info.php +++ b/system/pages/account/change-info.php @@ -20,6 +20,8 @@ if(!$logged) { return; } +csrfProtect(); + if(setting('core.account_country')) require SYSTEM . 'countries.conf.php'; diff --git a/system/pages/account/change-password.php b/system/pages/account/change-password.php index bf172455..157515b7 100644 --- a/system/pages/account/change-password.php +++ b/system/pages/account/change-password.php @@ -17,18 +17,19 @@ if(!$logged) { return; } -$new_password = $_POST['newpassword'] ?? NULL; -$new_password_confirm = $_POST['newpassword_confirm'] ?? NULL; -$old_password = $_POST['oldpassword'] ?? NULL; +csrfProtect(); + +$new_password = $_POST['new_password'] ?? null; +$new_password_confirm = $_POST['new_password_confirm'] ?? null; +$old_password = $_POST['old_password'] ?? null; if(empty($new_password) && empty($new_password_confirm) && empty($old_password)) { $twig->display('account.change-password.html.twig'); } -else -{ +else { if(empty($new_password) || empty($new_password_confirm) || empty($old_password)){ $errors[] = 'Please fill in form.'; } - $password_strlen = strlen($new_password); + if($new_password != $new_password_confirm) { $errors[] = 'The new passwords do not match!'; } @@ -39,10 +40,13 @@ else } /** @var OTS_Account $account_logged */ - $old_password = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password); - if($old_password != $account_logged->getPassword()) { + $old_password_hashed = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password); + if($old_password_hashed != $account_logged->getPassword()) { $errors[] = 'Current password is incorrect!'; } + else if ($old_password == $new_password) { + $errors[] = 'The old password is same as the new password!'; + } $hooks->trigger(HOOK_ACCOUNT_CHANGE_PASSWORD_POST); } diff --git a/system/pages/account/characters/change-comment.php b/system/pages/account/characters/change-comment.php index 7fa10c69..919e6aa6 100644 --- a/system/pages/account/characters/change-comment.php +++ b/system/pages/account/characters/change-comment.php @@ -20,6 +20,8 @@ if(!$logged) { return; } +csrfProtect(); + $player = null; $player_name = isset($_REQUEST['name']) ? stripslashes(urldecode($_REQUEST['name'])) : null; $new_comment = isset($_POST['comment']) ? htmlspecialchars(stripslashes(substr($_POST['comment'],0,2000))) : NULL; diff --git a/system/pages/account/characters/change-name.php b/system/pages/account/characters/change-name.php index 975369d1..3e9254fb 100644 --- a/system/pages/account/characters/change-name.php +++ b/system/pages/account/characters/change-name.php @@ -17,6 +17,8 @@ if(!$logged) { return; } +csrfProtect(); + $player_id = isset($_POST['player_id']) ? (int)$_POST['player_id'] : NULL; $name = isset($_POST['name']) ? stripslashes(ucwords(strtolower($_POST['name']))) : NULL; if((!setting('core.account_change_character_name'))) diff --git a/system/pages/account/characters/change-sex.php b/system/pages/account/characters/change-sex.php index efefe7c9..101feb22 100644 --- a/system/pages/account/characters/change-sex.php +++ b/system/pages/account/characters/change-sex.php @@ -17,6 +17,8 @@ if(!$logged) { return; } +csrfProtect(); + $sex_changed = false; $player_id = isset($_POST['player_id']) ? (int)$_POST['player_id'] : NULL; $new_sex = isset($_POST['new_sex']) ? (int)$_POST['new_sex'] : NULL; diff --git a/system/pages/account/characters/create.php b/system/pages/account/characters/create.php index 5ad21dab..6469319d 100644 --- a/system/pages/account/characters/create.php +++ b/system/pages/account/characters/create.php @@ -20,6 +20,8 @@ if(!$logged) { return; } +csrfProtect(); + $character_name = isset($_POST['name']) ? stripslashes($_POST['name']) : null; $character_sex = isset($_POST['sex']) ? (int)$_POST['sex'] : null; $character_vocation = isset($_POST['vocation']) ? (int)$_POST['vocation'] : null; diff --git a/system/pages/account/characters/delete.php b/system/pages/account/characters/delete.php index af32070b..c737ad5c 100644 --- a/system/pages/account/characters/delete.php +++ b/system/pages/account/characters/delete.php @@ -17,6 +17,8 @@ if(!$logged) { return; } +csrfProtect(); + $player_name = isset($_POST['delete_name']) ? stripslashes($_POST['delete_name']) : null; $password_verify = isset($_POST['delete_password']) ? $_POST['delete_password'] : null; $password_verify = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $password_verify); diff --git a/system/pages/account/confirm-email.php b/system/pages/account/confirm-email.php index 615dd942..87183a3c 100644 --- a/system/pages/account/confirm-email.php +++ b/system/pages/account/confirm-email.php @@ -9,6 +9,7 @@ */ use MyAAC\Models\Account; +use MyAAC\Models\AccountEmailVerify; defined('MYAAC') or die('Direct access not allowed!'); @@ -20,16 +21,20 @@ if(empty($hash)) { return; } -if(!Account::where('email_hash', $hash)->exists()) { - note("Your email couldn't be verified. Please contact staff to do it manually."); +// by default link is valid for 30 days +$accountEmailVerify = AccountEmailVerify::where('hash', $hash)->where('sent_at', '>', time() - 30 * 24 * 60 * 60)->first(); +if(!$accountEmailVerify) { + note("Wrong link or link has expired."); } else { - $accountModel = Account::where('email_hash', $hash)->where('email_verified', 0)->first(); + $accountModel = Account::where('id', $accountEmailVerify->account_id)->where('email_verified', 0)->first(); if ($accountModel) { $accountModel->email_verified = 1; $accountModel->save(); + AccountEmailVerify::where('account_id', $accountModel->id)->delete(); + success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this. You can now log in.'); $account = new OTS_Account(); @@ -39,6 +44,6 @@ else } } else { - error('Link has expired.'); + error('Your account is already verified.'); } } diff --git a/system/pages/account/create.php b/system/pages/account/create.php index 1c8f1e9f..9ffdf6f7 100644 --- a/system/pages/account/create.php +++ b/system/pages/account/create.php @@ -10,6 +10,7 @@ */ use MyAAC\CreateCharacter; +use MyAAC\Models\AccountEmailVerify; defined('MYAAC') or die('Direct access not allowed!'); $title = 'Create Account'; @@ -23,6 +24,8 @@ if($logged) return; } +csrfProtect(); + if(setting('core.account_create_character_create')) { $createCharacter = new CreateCharacter(); } @@ -219,8 +222,19 @@ if($save) } } - if(setting('core.account_premium_points') && setting('core.account_premium_points') > 0) { - $new_account->setCustomField('premium_points', setting('core.account_premium_points')); + $accountDefaultPremiumPoints = setting('core.account_premium_points'); + if($accountDefaultPremiumPoints > 0) { + $new_account->setCustomField('premium_points', $accountDefaultPremiumPoints); + } + + $accountDefaultCoins = setting('core.account_coins'); + if(HAS_ACCOUNT_COINS && $accountDefaultCoins > 0) { + $new_account->setCustomField('coins', $accountDefaultCoins); + } + + $accountDefaultCoinsTransferable = setting('core.account_coins_transferable'); + if((HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS) && $accountDefaultCoinsTransferable > 0) { + $new_account->setCustomField(ACCOUNT_COINS_TRANSFERABLE_COLUMN, $accountDefaultCoinsTransferable); } $tmp_account = $email; @@ -231,7 +245,12 @@ if($save) if(setting('core.mail_enabled') && setting('core.account_mail_verify')) { $hash = md5(generateRandomString(16, true, true) . $email); - $new_account->setCustomField('email_hash', $hash); + + AccountEmailVerify::create([ + 'account_id' => $new_account->getId(), + 'hash' => $hash, + 'sent_at' => time(), + ]); $verify_url = getLink('account/confirm-email/' . $hash); $body_html = $twig->render('mail.account.verify.html.twig', array( @@ -255,8 +274,10 @@ if($save) } else { - error('An error occorred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log'); + error('An error occurred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log'); $new_account->delete(); + + return; } } else diff --git a/system/pages/account/login.php b/system/pages/account/login.php index 3e8ebba3..e18dacf4 100644 --- a/system/pages/account/login.php +++ b/system/pages/account/login.php @@ -18,6 +18,8 @@ if($logged || !isset($_POST['account_login']) || !isset($_POST['password_login'] return; } +csrfProtect(); + $login_account = $_POST['account_login']; $login_password = $_POST['password_login']; $remember_me = isset($_POST['remember_me']); @@ -46,7 +48,9 @@ if(!empty($login_account) && !empty($login_password)) ) { 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.'; + $link = getLink('account/resend-email-verify'); + $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.
' . + 'You can resend the Email here: ' . $link . ''; } else { session_regenerate_id(); setSession('account', $account_logged->getId()); @@ -95,3 +99,8 @@ else { } $hooks->trigger(HOOK_ACCOUNT_LOGIN_POST); + +if($logged) { + $twig->addGlobal('logged', true); + $twig->addGlobal('account_logged', $account_logged); +} diff --git a/system/pages/account/manage.php b/system/pages/account/manage.php index 3b3dc288..f323c127 100644 --- a/system/pages/account/manage.php +++ b/system/pages/account/manage.php @@ -34,17 +34,28 @@ if(isset($_REQUEST['redirect'])) return; } +csrfProtect(); + $groups = new OTS_Groups_List(); -$freePremium = isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium']) || $account_logged->getPremDays() == OTS_Account::GRATIS_PREMIUM_DAYS; -$dayOrDays = $account_logged->getPremDays() == 1 ? 'day' : 'days'; /** * @var OTS_Account $account_logged */ -if(!$account_logged->isPremium()) +$premDays = $account_logged->getPremDays(); + +$freePremium = isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium']) || $premDays == OTS_Account::GRATIS_PREMIUM_DAYS; +$dayOrDays = ($premDays == 1 ? 'day' : 'days'); + +$vipSystemEnabled = isset($config['lua']['vipSystemEnabled']) && getBoolean($config['lua']['vipSystemEnabled']); +$premiumLabel = $vipSystemEnabled ? 'VIP' : 'Premium Account'; + +if ($freePremium && !$vipSystemEnabled) { + $account_status = 'Gratis Premium Account'; +} else if(!$account_logged->isPremium()) { $account_status = 'Free Account'; -else - $account_status = '' . ($freePremium ? 'Gratis Premium Account' : 'Premium Account, ' . $account_logged->getPremDays() . ' '.$dayOrDays.' left') . ''; +} else { + $account_status = '' . $premiumLabel . ', ' . $premDays . ' '.$dayOrDays.' left'; +} $recovery_key = $account_logged->getCustomField('key'); if(empty($recovery_key)) diff --git a/system/pages/account/redirect.php b/system/pages/account/redirect.php deleted file mode 100644 index 78bc54d9..00000000 --- a/system/pages/account/redirect.php +++ /dev/null @@ -1,23 +0,0 @@ - - * @author Slawkens - * @copyright 2019 MyAAC - * @link https://my-aac.org - */ -defined('MYAAC') or die('Direct access not allowed!'); - -$redirect = urldecode($_REQUEST['redirect']); - -// should never happen, unless hacker modify the URL -if (!str_contains($redirect, BASE_URL)) { - error('Fatal error: Cannot redirect outside the website.'); - return; -} - -$twig->display('account.redirect.html.twig', array( - 'redirect' => $redirect -)); diff --git a/system/pages/account/register-new.php b/system/pages/account/register-new.php index 04e8bf33..bca3b798 100644 --- a/system/pages/account/register-new.php +++ b/system/pages/account/register-new.php @@ -17,6 +17,8 @@ if(!$logged) { return; } +csrfProtect(); + if(isset($_POST['reg_password'])) $reg_password = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $_POST['reg_password']); diff --git a/system/pages/account/register.php b/system/pages/account/register.php index f33f0b17..8aa3089e 100644 --- a/system/pages/account/register.php +++ b/system/pages/account/register.php @@ -17,6 +17,8 @@ if(!$logged) { return; } +csrfProtect(); + $_POST['reg_password'] = $_POST['reg_password'] ?? ''; $reg_password = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $_POST['reg_password']); $old_key = $account_logged->getCustomField("key"); diff --git a/system/pages/account/resend-email-verify.php b/system/pages/account/resend-email-verify.php new file mode 100644 index 00000000..ffccb548 --- /dev/null +++ b/system/pages/account/resend-email-verify.php @@ -0,0 +1,94 @@ +display('error_box.html.twig', ['errors' => $errors]); + $twig->display('account.back_button.html.twig', [ + 'action' => getLink('account/resend-email-verify'), + ]); +}; + +if (!setting('core.mail_enabled') || !setting('core.account_mail_verify')) { + $errorWithBackButton('Resending email is not possible on this server.'); + return; +} + +$showForm = true; + +if (isset($_POST['submit']) && $_POST['submit'] == '1') { + $email = $_REQUEST['email']; + + if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) { + $errorWithBackButton('Please enter valid Email.'); + return; + } + + $account = new OTS_Account(); + $account->findByEMail($email); + if ($account->isLoaded()) { + if ($account->getCustomField('email_verified') == '1') { + $errorWithBackButton('This account is already verified! You can log in on the website.'); + return; + } + + $accountEmailVerify = AccountEmailVerify::where('account_id', $account->getId())->orderBy('sent_at', 'DESC')->first(); + if ($accountEmailVerify && time() - $accountEmailVerify->sent_at < 60) { + $errorWithBackButton('Only one Email per minute is allowed. Please try again later.'); + return; + } + + $tmp_account = $email; + if (!config('account_login_by_email')) { + $tmp_account = (USE_ACCOUNT_NAME ? $account->getName() : $account->getId()); + } + + $hash = md5(generateRandomString(16, true, true) . $email); + + AccountEmailVerify::create([ + 'account_id' => $account->getId(), + 'hash' => $hash, + 'sent_at' => time(), + ]); + + $verify_url = getLink('account/confirm-email/' . $hash); + $body_html = $twig->render('mail.account.resend-email-verify.html.twig', array( + 'account' => $tmp_account, + 'verify_url' => generateLink($verify_url, $verify_url, true) + )); + + if (_mail($account->getEMail(), configLua('serverName') . ' - Verify Account', $body_html)) { + $message = "If account with this email exists - you will become an email with verification link."; + $showForm = false; + } else { + $message = "

An error occurred while sending email ({$email} )! Try again later. For Admin: More info can be found in system/logs/mailer-error.log

"; + } + } + else { + $message = "
If account with this email exists - you will become an email with verification link."; + $showForm = false; + } + + $twig->display('success.html.twig', array( + 'title' => 'Verify Email Sent', + 'description' => $message, + )); +} + +//show errors if not empty +if (!empty($errors)) { + $twig->display('error_box.html.twig', ['errors' => $errors]); + $twig->display('account.back_button.html.twig', [ + 'action' => getLink('account/resend-email-verify'), + ]); +} + +if ($showForm) { + $twig->display('account.resend-email-verify.html.twig'); +} diff --git a/system/pages/change-log.php b/system/pages/change-log.php new file mode 100644 index 00000000..27504e4a --- /dev/null +++ b/system/pages/change-log.php @@ -0,0 +1,46 @@ + + * @copyright 2019 MyAAC + * @link https://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'Changelog'; + +use MyAAC\Models\Changelog; + +$_page = isset($_GET['page']) ? (int)$_GET['page'] : 0; +$limit = 30; +$offset = $_page * $limit; +$next_page = false; + +$canEdit = hasFlag(FLAG_CONTENT_NEWS) || superAdmin(); + +$changelogs = Changelog::isPublic()->orderByDesc('date')->limit($limit + 1)->offset($offset)->get()->toArray(); + +$i = 0; +foreach($changelogs as $key => &$log) +{ + if($i < $limit) { + $log['type'] = getChangelogType($log['type']); + $log['where'] = getChangelogWhere($log['where']); + } + else { + unset($changelogs[$key]); + } + + if ($i >= $limit) + $next_page = true; + + $i++; +} + +$twig->display('changelog.html.twig', array( + 'changelogs' => $changelogs, + 'page' => $_page, + 'next_page' => $next_page, + 'canEdit' => $canEdit, +)); diff --git a/system/pages/changelog.php b/system/pages/changelog.php index 27504e4a..d57ec47b 100644 --- a/system/pages/changelog.php +++ b/system/pages/changelog.php @@ -1,46 +1,3 @@ - * @copyright 2019 MyAAC - * @link https://my-aac.org - */ -defined('MYAAC') or die('Direct access not allowed!'); -$title = 'Changelog'; -use MyAAC\Models\Changelog; - -$_page = isset($_GET['page']) ? (int)$_GET['page'] : 0; -$limit = 30; -$offset = $_page * $limit; -$next_page = false; - -$canEdit = hasFlag(FLAG_CONTENT_NEWS) || superAdmin(); - -$changelogs = Changelog::isPublic()->orderByDesc('date')->limit($limit + 1)->offset($offset)->get()->toArray(); - -$i = 0; -foreach($changelogs as $key => &$log) -{ - if($i < $limit) { - $log['type'] = getChangelogType($log['type']); - $log['where'] = getChangelogWhere($log['where']); - } - else { - unset($changelogs[$key]); - } - - if ($i >= $limit) - $next_page = true; - - $i++; -} - -$twig->display('changelog.html.twig', array( - 'changelogs' => $changelogs, - 'page' => $_page, - 'next_page' => $next_page, - 'canEdit' => $canEdit, -)); +require 'change-log.php'; diff --git a/system/pages/forum/admin.php b/system/pages/forum/admin.php index 6e35bba5..73be2dc2 100644 --- a/system/pages/forum/admin.php +++ b/system/pages/forum/admin.php @@ -17,6 +17,8 @@ if(!$canEdit) { return; } +csrfProtect(); + $groupsList = new OTS_Groups_List(); $groups = [ ['id' => 0, 'name' => 'Guest'], @@ -30,23 +32,24 @@ foreach ($groupsList as $group) { } if(!empty($action)) { - if($action == 'delete_board' || $action == 'edit_board' || $action == 'hide_board' || $action == 'moveup_board' || $action == 'movedown_board') + if($action == 'delete_board' || $action == 'edit_board' || $action == 'hide_board' || $action == 'moveup_board' || $action == 'movedown_board') { $id = $_REQUEST['id']; - - if(isset($_REQUEST['access'])) { - $access = $_REQUEST['access']; } - if(isset($_REQUEST['guild'])) { - $guild = $_REQUEST['guild']; + if(isset($_POST['access'])) { + $access = $_POST['access']; } - if(isset($_REQUEST['name'])) { - $name = $_REQUEST['name']; + if(isset($_POST['guild'])) { + $guild = $_POST['guild']; } - if(isset($_REQUEST['description'])) { - $description = stripslashes($_REQUEST['description']); + if(isset($_POST['name'])) { + $name = $_POST['name']; + } + + if(isset($_POST['description'])) { + $description = stripslashes($_POST['description']); } $errors = []; @@ -55,12 +58,13 @@ if(!empty($action)) { if(Forum::add_board($name, $description, $access, $guild, $errors)) { $action = $name = $description = ''; header('Location: ' . getLink('forum')); + exit; } } else if($action == 'delete_board') { Forum::delete_board($id, $errors); header('Location: ' . getLink('forum')); - $action = ''; + exit; } else if($action == 'edit_board') { @@ -74,28 +78,27 @@ if(!empty($action)) { else { Forum::update_board($id, $name, $access, $guild, $description); header('Location: ' . getLink('forum')); - $action = $name = $description = ''; - $access = $guild = 0; + exit; } } else if($action == 'hide_board') { Forum::toggleHide_board($id, $errors); header('Location: ' . getLink('forum')); - $action = ''; + exit; } else if($action == 'moveup_board') { Forum::move_board($id, -1, $errors); header('Location: ' . getLink('forum')); - $action = ''; + exit; } else if($action == 'movedown_board') { Forum::move_board($id, 1, $errors); header('Location: ' . getLink('forum')); - $action = ''; + exit; } if(!empty($errors)) { - $twig->display('error_box.html.twig', array('errors' => $errors)); + $twig->display('error_box.html.twig', ['errors' => $errors]); $action = ''; } } diff --git a/system/pages/forum/edit_post.php b/system/pages/forum/edit_post.php index 53fcdb71..b9f2890d 100644 --- a/system/pages/forum/edit_post.php +++ b/system/pages/forum/edit_post.php @@ -23,8 +23,9 @@ if(!$logged) { return; } -if(Forum::canPost($account_logged)) -{ +csrfProtect(); + +if(Forum::canPost($account_logged)) { $post_id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : false; if(!$post_id) { $errors[] = 'Please enter post id.'; @@ -41,12 +42,12 @@ if(Forum::canPost($account_logged)) $char_id = $post_topic = $text = $smile = $html = null; $players_from_account = $db->query("SELECT `players`.`name`, `players`.`id` FROM `players` WHERE `players`.`account_id` = ".(int) $account_logged->getId())->fetchAll(); $saved = false; - if(isset($_REQUEST['save'])) { - $text = stripslashes(trim($_REQUEST['text'])); - $char_id = (int) $_REQUEST['char_id']; - $post_topic = stripslashes(trim($_REQUEST['topic'])); - $smile = isset($_REQUEST['smile']) ? (int)$_REQUEST['smile'] : 0; - $html = isset($_REQUEST['html']) ? (int)$_REQUEST['html'] : 0; + if(isset($_POST['save'])) { + $text = stripslashes(trim($_POST['text'])); + $char_id = (int) $_POST['char_id']; + $post_topic = stripslashes(trim($_POST['topic'])); + $smile = isset($_POST['smile']) ? (int)$_POST['smile'] : 0; + $html = isset($_POST['html']) ? (int)$_POST['html'] : 0; if (!superAdmin()) { $html = 0; diff --git a/system/pages/forum/move_thread.php b/system/pages/forum/move_thread.php index d9731e5b..aa101b08 100644 --- a/system/pages/forum/move_thread.php +++ b/system/pages/forum/move_thread.php @@ -23,15 +23,17 @@ if(!$logged) { return; } +csrfProtect(); + if(!Forum::isModerator()) { echo 'You are not logged in or you are not moderator.'; return; } -$save = isset($_REQUEST['save']) && (int)$_REQUEST['save'] == 1; +$save = isset($_POST['save']) && (int)$_POST['save'] == 1; if($save) { - $post_id = (int)$_REQUEST['id']; - $board = (int)$_REQUEST['section']; + $post_id = (int)$_POST['id']; + $board = (int)$_POST['section']; if(!Forum::hasAccess($board)) { $errors[] = "You don't have access to this board."; displayErrorBoxWithBackButton($errors, getLink('forum')); diff --git a/system/pages/forum/new_post.php b/system/pages/forum/new_post.php index b0db84fd..71bc3417 100644 --- a/system/pages/forum/new_post.php +++ b/system/pages/forum/new_post.php @@ -28,6 +28,8 @@ if(!$logged) { return; } +csrfProtect(); + if(Forum::canPost($account_logged)) { $players_from_account = $db->query("SELECT `players`.`name`, `players`.`id` FROM `players` WHERE `players`.`account_id` = ".(int) $account_logged->getId())->fetchAll(); $thread_id = isset($_REQUEST['thread_id']) ? (int) $_REQUEST['thread_id'] : 0; @@ -43,11 +45,11 @@ if(Forum::canPost($account_logged)) { echo 'Boards >> '.$sections[$thread['section']]['name'].' >> '.htmlspecialchars($thread['post_topic']).' >> Post new reply

'.htmlspecialchars($thread['post_topic']).'

'; $quote = isset($_REQUEST['quote']) ? (int) $_REQUEST['quote'] : NULL; - $text = isset($_REQUEST['text']) ? stripslashes(trim($_REQUEST['text'])) : NULL; - $char_id = (int) ($_REQUEST['char_id'] ?? 0); - $post_topic = isset($_REQUEST['topic']) ? stripslashes(trim($_REQUEST['topic'])) : ''; - $smile = (int)($_REQUEST['smile'] ?? 0); - $html = (int)($_REQUEST['html'] ?? 0); + $text = isset($_POST['text']) ? stripslashes(trim($_POST['text'])) : NULL; + $char_id = (int) ($_POST['char_id'] ?? 0); + $post_topic = isset($_POST['topic']) ? stripslashes(trim($_POST['topic'])) : ''; + $smile = (int)($_POST['smile'] ?? 0); + $html = (int)($_POST['html'] ?? 0); $saved = false; if (!superAdmin()) { @@ -60,10 +62,10 @@ if(Forum::canPost($account_logged)) { $text = '[i]Originally posted by ' . $quoted_post[0]['name'] . ' on ' . date('d.m.y H:i:s', $quoted_post[0]['post_date']) . ':[/i][quote]' . $quoted_post[0]['post_text'] . '[/quote]'; } } - elseif(isset($_REQUEST['save'])) { + elseif(isset($_POST['save'])) { $length = strlen($text); if($length < 1 || strlen($text) > 15000) { - $errors[] = 'Too short or too long post (Length: $length letters). Minimum 1 letter, maximum 15000 letters.'; + $errors[] = "Too short or too long post (Length: $length letters). Minimum 1 letter, maximum 15000 letters."; } if($char_id == 0) { @@ -79,15 +81,14 @@ if(Forum::canPost($account_logged)) { } if(!$player_on_account) { - $errors[] = 'Player with selected ID ' . $char_id . ' doesn\'t exist or isn\'t on your account'; + $errors[] = "Player with selected ID $char_id doesn't exist or isn't on your account"; } } if(count($errors) == 0) { $last_post = 0; $query = $db->query('SELECT post_date FROM ' . FORUM_TABLE_PREFIX . 'forum ORDER BY post_date DESC LIMIT 1'); - if($query->rowCount() > 0) - { + if($query->rowCount() > 0) { $query = $query->fetch(); $last_post = $query['post_date']; } diff --git a/system/pages/forum/new_thread.php b/system/pages/forum/new_thread.php index e6c8fe80..4f311977 100644 --- a/system/pages/forum/new_thread.php +++ b/system/pages/forum/new_thread.php @@ -28,6 +28,8 @@ if(!$logged) { return; } +csrfProtect(); + if(Forum::canPost($account_logged)) { $players_from_account = $db->query('SELECT `players`.`name`, `players`.`id` FROM `players` WHERE `players`.`account_id` = '.(int) $account_logged->getId())->fetchAll(); $section_id = $_REQUEST['section_id'] ?? null; @@ -38,19 +40,18 @@ if(Forum::canPost($account_logged)) { if ($sections[$section_id]['closed'] && !Forum::isModerator()) $errors[] = 'You cannot create topic on this board.'; - $quote = (int)(isset($_REQUEST['quote']) ? $_REQUEST['quote'] : 0); - $text = isset($_REQUEST['text']) ? stripslashes($_REQUEST['text']) : ''; - $char_id = (int)(isset($_REQUEST['char_id']) ? $_REQUEST['char_id'] : 0); - $post_topic = isset($_REQUEST['topic']) ? stripslashes($_REQUEST['topic']) : ''; - $smile = (isset($_REQUEST['smile']) ? (int)$_REQUEST['smile'] : 0); - $html = (isset($_REQUEST['html']) ? (int)$_REQUEST['html'] : 0); + $text = isset($_POST['text']) ? stripslashes($_POST['text']) : ''; + $char_id = (int)(isset($_POST['char_id']) ? $_POST['char_id'] : 0); + $post_topic = isset($_POST['topic']) ? stripslashes($_POST['topic']) : ''; + $smile = (isset($_POST['smile']) ? (int)$_POST['smile'] : 0); + $html = (isset($_POST['html']) ? (int)$_POST['html'] : 0); if (!superAdmin()) { $html = 0; } $saved = false; - if (isset($_REQUEST['save'])) { + if (isset($_POST['save'])) { $length = strlen($post_topic); if ($length < 1 || $length > 60) { $errors[] = "Too short or too long topic (Length: $length letters). Minimum 1 letter, maximum 60 letters."; diff --git a/system/pages/forum/remove_post.php b/system/pages/forum/remove_post.php index 690b3f75..ec3a38ec 100644 --- a/system/pages/forum/remove_post.php +++ b/system/pages/forum/remove_post.php @@ -23,11 +23,13 @@ if(!$logged) { return; } +csrfProtect(); + if(Forum::isModerator()) { - $id = (int) $_REQUEST['id']; + $id = (int) ($_POST['id'] ?? 0); $post = $db->query("SELECT `id`, `first_post`, `section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `id` = ".$id." LIMIT 1")->fetch(); - if($post['id'] == $id && Forum::hasAccess($post['section'])) { + if($post && $post['id'] == $id && Forum::hasAccess($post['section'])) { if($post['id'] == $post['first_post']) { $db->query("DELETE FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `first_post` = ".$post['id']); header('Location: ' . getForumBoardLink($post['section'])); @@ -36,7 +38,7 @@ if(Forum::isModerator()) { $post_page = $db->query("SELECT COUNT(`" . FORUM_TABLE_PREFIX . "forum`.`id`) AS posts_count FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`id` < ".$id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".(int) $post['first_post'])->fetch(); $_page = (int) ceil($post_page['posts_count'] / setting('core.forum_threads_per_page')) - 1; $db->query("DELETE FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `id` = ".$post['id']); - header('Location: ' . getForumThreadLink($post['first_post'], (int) $_page)); + header('Location: ' . getForumThreadLink($post['first_post'], $_page)); } } else { diff --git a/system/pages/forum/show_board.php b/system/pages/forum/show_board.php index 5997bdba..e899cc99 100644 --- a/system/pages/forum/show_board.php +++ b/system/pages/forum/show_board.php @@ -33,7 +33,7 @@ if(!Forum::hasAccess($section_id)) { return; } -$_page = (int) (isset($_REQUEST['page']) ? $_REQUEST['page'] : 0); +$_page = (int) ($_REQUEST['page'] ?? 0); $threads_count = $db->query("SELECT COUNT(`" . FORUM_TABLE_PREFIX . "forum`.`id`) AS threads_count FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`section` = ".(int) $section_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = `" . FORUM_TABLE_PREFIX . "forum`.`id`")->fetch(); for($i = 0; $i < $threads_count['threads_count'] / setting('core.forum_threads_per_page'); $i++) { if($i != $_page) @@ -50,7 +50,7 @@ if($logged && (!$sections[$section_id]['closed'] || Forum::isModerator())) { } echo '

Page: '.$links_to_pages.'
'; -$last_threads = $db->query("SELECT `players`.`id` as `player_id`, `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`last_post`, `" . FORUM_TABLE_PREFIX . "forum`.`replies`, `" . FORUM_TABLE_PREFIX . "forum`.`views`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`section` = ".$section_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = `" . FORUM_TABLE_PREFIX . "forum`.`id` ORDER BY `" . FORUM_TABLE_PREFIX . "forum`.`last_post` DESC LIMIT ".setting('core.forum_threads_per_page')." OFFSET ".($_page * setting('core.forum_threads_per_page')))->fetchAll(); +$last_threads = $db->query("SELECT `players`.`id` as `player_id`, `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`last_post`, `" . FORUM_TABLE_PREFIX . "forum`.`replies`, `" . FORUM_TABLE_PREFIX . "forum`.`views`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`section` = ".$section_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = `" . FORUM_TABLE_PREFIX . "forum`.`id` ORDER BY `" . FORUM_TABLE_PREFIX . "forum`.`last_post` DESC LIMIT ".setting('core.forum_threads_per_page')." OFFSET ".($_page * setting('core.forum_threads_per_page')))->fetchAll(PDO::FETCH_ASSOC); if(isset($last_threads[0])) { echo ' @@ -67,8 +67,8 @@ if(isset($last_threads[0])) { foreach($last_threads as $thread) { echo ' {% if canEdit %} {% endif %} diff --git a/system/templates/forum.move_thread.html.twig b/system/templates/forum.move_thread.html.twig index be62d9c7..c9480199 100644 --- a/system/templates/forum.move_thread.html.twig +++ b/system/templates/forum.move_thread.html.twig @@ -8,7 +8,8 @@
'; if(Forum::isModerator()) { - echo '[MOVE]'; - echo '[REMOVE] '; + echo ''; + $twig->display('forum.remove_post.html.twig', ['post' => $thread]); } $player->load($thread['player_id']); @@ -82,10 +82,13 @@ if(isset($last_threads[0])) { echo ''.htmlspecialchars($thread['post_topic']). '
'.($canEditForum ? substr(strip_tags($thread['post_text']), 0, 50) : htmlspecialchars(substr($thread['post_text'], 0, 50))).'...
' . getPlayerLink($thread['name']) . ''.(int) $thread['replies'].''.(int) $thread['views'].''; if($thread['last_post'] > 0) { $last_post = $db->query("SELECT `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".(int) $thread['id']." AND `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` ORDER BY `post_date` DESC LIMIT 1")->fetch(); - if(isset($last_post['name'])) - echo date('d.m.y H:i:s', $last_post['post_date']).'
by ' . getPlayerLink($last_post['name']); - else + + if(isset($last_post['name'])) { + echo date('d.m.y H:i:s', $last_post['post_date']) . '
by ' . getPlayerLink($last_post['name']); + } + else { echo 'No posts.'; + } } else { echo date('d.m.y H:i:s', $thread['post_date']) . '
by ' . getPlayerLink($thread['name']); diff --git a/system/pages/forum/show_thread.php b/system/pages/forum/show_thread.php index e4c53f16..ceeb2602 100644 --- a/system/pages/forum/show_thread.php +++ b/system/pages/forum/show_thread.php @@ -35,7 +35,7 @@ if(!Forum::hasAccess($thread_starter['section'])) { return; } -$posts_count = $db->query("SELECT COUNT(`" . FORUM_TABLE_PREFIX . "forum`.`id`) AS posts_count FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".(int) $thread_id)->fetch(); +$posts_count = $db->query("SELECT COUNT(`" . FORUM_TABLE_PREFIX . "forum`.`id`) AS posts_count FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".$thread_id)->fetch(); for($i = 0; $i < $posts_count['posts_count'] / setting('core.forum_threads_per_page'); $i++) { if($i != $_page) $links_to_pages .= ''.($i + 1).' '; @@ -46,7 +46,7 @@ for($i = 0; $i < $posts_count['posts_count'] / setting('core.forum_threads_per_p $posts = $db->query("SELECT `players`.`id` as `player_id`, `" . FORUM_TABLE_PREFIX . "forum`.`id`,`" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`section`,`" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` AS `date`, `" . FORUM_TABLE_PREFIX . "forum`.`post_smile`, `" . FORUM_TABLE_PREFIX . "forum`.`post_html`, `" . FORUM_TABLE_PREFIX . "forum`.`author_aid`, `" . FORUM_TABLE_PREFIX . "forum`.`author_guid`, `" . FORUM_TABLE_PREFIX . "forum`.`last_edit_aid`, `" . FORUM_TABLE_PREFIX . "forum`.`edit_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".$thread_id." ORDER BY `" . FORUM_TABLE_PREFIX . "forum`.`post_date` LIMIT " . setting('core.forum_posts_per_page') . " OFFSET ".($_page * setting('core.forum_posts_per_page')))->fetchAll(); if(isset($posts[0]['player_id'])) { - $db->query("UPDATE `" . FORUM_TABLE_PREFIX . "forum` SET `views`=`views`+1 WHERE `id` = ".(int) $thread_id); + $db->query("UPDATE `" . FORUM_TABLE_PREFIX . "forum` SET `views`=`views`+1 WHERE `id` = " . $thread_id); } $lookaddons = $db->hasColumn('players', 'lookaddons'); diff --git a/system/pages/guilds/accept_invite.php b/system/pages/guilds/accept_invite.php index bc782480..14c55c25 100644 --- a/system/pages/guilds/accept_invite.php +++ b/system/pages/guilds/accept_invite.php @@ -12,11 +12,11 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; -//set rights in guild +// set rights in guild $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; $name = isset($_REQUEST['name']) ? stripslashes($_REQUEST['name']) : null; if(!$logged) { - $errors[] = 'You are not logged in. You can\'t accept invitations.'; + $errors[] = "You are not logged in. You can't accept invitations."; } if(!Validator::guildName($guild_name)) { @@ -27,11 +27,11 @@ if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; + $errors[] = "Guild with name $guild_name doesn't exist."; } } -if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { +if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(!Validator::characterName($name)) { $errors[] = 'Invalid name format.'; } @@ -51,7 +51,7 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { } } -if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { +if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(empty($errors)) { $is_invited = false; include(SYSTEM . 'libs/pot/InvitesDriver.php'); @@ -104,7 +104,7 @@ if(!empty($errors)) { )); } else { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $guild->acceptInvite($player); $twig->display('success.html.twig', array( 'title' => 'Accept invitation', diff --git a/system/pages/guilds/add_rank.php b/system/pages/guilds/add_rank.php index e66ba49e..b24ff03d 100644 --- a/system/pages/guilds/add_rank.php +++ b/system/pages/guilds/add_rank.php @@ -13,7 +13,7 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; -$rank_name = isset($_REQUEST['rank_name']) ? $_REQUEST['rank_name'] : null; +$rank_name = $_POST['rank_name'] ?? null; if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); } @@ -35,7 +35,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { $guild_vice = true; diff --git a/system/pages/guilds/base.php b/system/pages/guilds/base.php index 07fc432d..e096c56e 100644 --- a/system/pages/guilds/base.php +++ b/system/pages/guilds/base.php @@ -15,3 +15,5 @@ else define('GUILD_MEMBERS_TABLE', 'guild_membership'); define('MOTD_EXISTS', $db->hasColumn('guilds', 'motd')); + +csrfProtect(); diff --git a/system/pages/guilds/change_description.php b/system/pages/guilds/change_description.php index 765665bf..e3c24522 100644 --- a/system/pages/guilds/change_description.php +++ b/system/pages/guilds/change_description.php @@ -31,7 +31,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild->getOwner()->getId() == $player->getId()) { $guild_vice = true; @@ -42,8 +42,8 @@ if(empty($errors)) { $saved = false; if($guild_leader) { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { - $description = htmlspecialchars(stripslashes(substr(trim($_REQUEST['description']),0, setting('core.guild_description_chars_limit')))); + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { + $description = htmlspecialchars(stripslashes(substr(trim($_POST['description']),0, setting('core.guild_description_chars_limit')))); $guild->setCustomField('description', $description); $saved = true; } diff --git a/system/pages/guilds/change_logo.php b/system/pages/guilds/change_logo.php index d8257e66..7fa72d99 100644 --- a/system/pages/guilds/change_logo.php +++ b/system/pages/guilds/change_logo.php @@ -30,7 +30,7 @@ if(empty($errors)) { if($logged) { $guild_leader_char = $guild->getOwner(); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { @@ -40,14 +40,13 @@ if(empty($errors)) { } } - if($guild_leader) - { + if($guild_leader) { $max_image_size_b = setting('core.guild_image_size_kb') * 1024; $allowed_ext = array('image/gif', 'image/jpg', 'image/pjpeg', 'image/jpeg', 'image/bmp', 'image/png', 'image/x-png'); $ext_name = array('image/gif' => 'gif', 'image/jpg' => 'jpg', 'image/jpeg' => 'jpg', 'image/pjpeg' => 'jpg', 'image/bmp' => 'bmp', 'image/png' => 'png', 'image/x-png' => 'png'); $save_file_name = str_replace(' ', '_', strtolower($guild->getName())); $save_path = GUILD_IMAGES_DIR . $save_file_name; - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $file = $_FILES['newlogo']; if(is_uploaded_file($file['tmp_name'])) @@ -97,13 +96,13 @@ if(empty($errors)) { $guild_logo = $guild->getCustomField('logo_name'); if(empty($guild_logo) || !file_exists(GUILD_IMAGES_DIR . $guild_logo)) { - $guild_logo = "default.gif"; + $guild_logo = 'default.gif'; } $twig->display('guilds.change_logo.html.twig', array( 'guild_logo' => $guild_logo, 'guild' => $guild, - 'max_image_size_b' => $max_image_size_b + //'max_image_size_b' => $max_image_size_b )); } diff --git a/system/pages/guilds/change_motd.php b/system/pages/guilds/change_motd.php index babb806c..8d478377 100644 --- a/system/pages/guilds/change_motd.php +++ b/system/pages/guilds/change_motd.php @@ -34,7 +34,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild->getOwner()->getId() == $player->getId()) { $guild_vice = true; @@ -45,8 +45,8 @@ if(empty($errors)) { $saved = false; if($guild_leader) { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { - $motd = htmlspecialchars(stripslashes(substr($_REQUEST['motd'],0, setting('core.guild_motd_chars_limit')))); + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { + $motd = htmlspecialchars(stripslashes(substr($_POST['motd'],0, setting('core.guild_motd_chars_limit')))); $guild->setCustomField('motd', $motd); $saved = true; } diff --git a/system/pages/guilds/change_nick.php b/system/pages/guilds/change_nick.php index bf773124..5016ef3e 100644 --- a/system/pages/guilds/change_nick.php +++ b/system/pages/guilds/change_nick.php @@ -20,17 +20,15 @@ if(!$logged) { } $name = isset($_REQUEST['name']) ? stripslashes($_REQUEST['name']) : null; -$new_nick = isset($_REQUEST['nick']) ? stripslashes($_REQUEST['nick']) : null; +$new_nick = isset($_POST['nick']) ? stripslashes($_POST['nick']) : null; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; if(!$name) { $errors[] = 'Please enter new name.'; - return; } if(!$new_nick) { $errors[] = 'Please enter new nick.'; - return; } if(empty($errors)) diff --git a/system/pages/guilds/change_rank.php b/system/pages/guilds/change_rank.php index 4341db16..6d36bdf1 100644 --- a/system/pages/guilds/change_rank.php +++ b/system/pages/guilds/change_rank.php @@ -17,8 +17,9 @@ if(!$logged) { } else { $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; - if(!Validator::guildName($guild_name)) + if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); + } } if(empty($errors)) @@ -42,7 +43,7 @@ $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; $guild_vice = false; -$account_players = $account_logged->getPlayers(); +$account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { $player_rank = $player->getRank(); @@ -65,22 +66,23 @@ foreach($account_players as $player) } } -if($guild_vice) -{ - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] === 'save') - { +if($guild_vice) { + if(isset($_POST['todo']) && $_POST['todo'] === 'save') { $player_name = stripslashes($_REQUEST['name']); - $new_rank = (int) $_REQUEST['rankid']; - if(!Validator::characterName($player_name)) + $new_rank = (int) $_POST['rankid']; + + if(!Validator::characterName($player_name)) { $errors[] = 'Invalid player name format.'; + } + $rank = new OTS_GuildRank(); $rank->load($new_rank); if(!$rank->isLoaded()) $errors[] = "Rank with this ID doesn't exist."; if($level_in_guild <= $rank->getLevel() && !$guild_leader) $errors[] = "You can't set ranks with equal or higher level than your."; - if(empty($errors)) - { + + if(empty($errors)) { $player_to_change = new OTS_Player(); $player_to_change->find($player_name); if(!$player_to_change->isLoaded()) @@ -108,8 +110,7 @@ if($guild_vice) $errors[] = 'This player has higher rank in guild than you. You can\'t change his/her rank.'; } - if(empty($errors)) - { + if(empty($errors)) { $player_to_change->setRank($rank); $twig->display('success.html.twig', array( 'title' => 'Rank Changed', @@ -125,7 +126,7 @@ if($guild_vice) $result = getPlayersWithLowerRank($rank_list, $guild_leader, $db, $level_in_guild, $guild); $twig->display('guilds.change_rank.html.twig', array( - 'players' => isset($result['players']) ? $result['players'] : array(), + 'players' => $result['players'] ?? [], 'guild_name' => $guild->getName(), 'ranks' => $result['ranks'] )); diff --git a/system/pages/guilds/cleanup_players.php b/system/pages/guilds/cleanup_players.php index 7e02fbeb..ad110feb 100644 --- a/system/pages/guilds/cleanup_players.php +++ b/system/pages/guilds/cleanup_players.php @@ -12,33 +12,27 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; -if(!$logged) -{ +if(!$logged) { echo "You are not logged in."; $twig->display('guilds.back_button.html.twig'); return; } -if(admin()) -{ +if(admin()) { $players_list = new OTS_Players_List(); $players_list->init(); } -else +else { $players_list = $account_logged->getPlayersList(); +} -if(count($players_list) > 0) -{ - foreach($players_list as $player) - { +if(count($players_list) > 0) { + foreach($players_list as $player) { $player_rank = $player->getRank(); - if($player_rank->isLoaded()) - { - if($player_rank->isLoaded()) - { + if($player_rank->isLoaded()) { + if($player_rank->isLoaded()) { $rank_guild = $player_rank->getGuild(); - if(!$rank_guild->isLoaded()) - { + if(!$rank_guild->isLoaded()) { $player->setRank(); $player->setGuildNick(''); $changed_ranks_of[] = $player->getName(); @@ -46,8 +40,7 @@ if(count($players_list) > 0) $player_rank->delete(); } } - else - { + else { $player->setRank(); $player->setGuildNick(''); $changed_ranks_of[] = $player->getName(); @@ -55,14 +48,20 @@ if(count($players_list) > 0) } } + echo "Deleted ranks (this ranks guilds doesn't exist [bug fix]):"; - if(!empty($deleted_ranks)) - foreach($deleted_ranks as $rank) - echo "
  • ".$rank; + if(!empty($deleted_ranks)) { + foreach ($deleted_ranks as $rank) { + echo "
  • " . $rank; + } + } echo "

    Changed ranks of players (rank or guild of rank doesn't exist [bug fix]):"; - if(!empty($changed_ranks_of)) - foreach($changed_ranks_of as $name) - echo "
  • ".$name; + + if(!empty($changed_ranks_of)) { + foreach ($changed_ranks_of as $name) { + echo "
  • " . $name; + } + } } else echo "0 players found."; diff --git a/system/pages/guilds/create.php b/system/pages/guilds/create.php index b404c494..08bc8817 100644 --- a/system/pages/guilds/create.php +++ b/system/pages/guilds/create.php @@ -14,15 +14,18 @@ use MyAAC\Models\GuildRank; require __DIR__ . '/base.php'; -$guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : NULL; -$name = isset($_REQUEST['name']) ? stripslashes($_REQUEST['name']) : NULL; -$todo = isset($_REQUEST['todo']) ? $_REQUEST['todo'] : NULL; +$guild_name = isset($_POST['guild']) ? urldecode($_POST['guild']) : NULL; +$name = isset($_POST['name']) ? stripslashes($_POST['name']) : NULL; +$todo = isset($_POST['todo']) ? $_POST['todo'] : NULL; if(!$logged) { - $guild_errors[] = 'You are not logged in. You can\'t create guild.'; + $errors[] = 'You are not logged in. You can\'t create guild.'; } +$configLuaFreePremium = configLua('freePremium'); +$freePremium = (isset($configLuaFreePremium) && getBoolean($configLuaFreePremium)) || ($logged && $account_logged->getPremDays() == OTS_Account::GRATIS_PREMIUM_DAYS); + $array_of_player_nig = array(); -if(empty($guild_errors)) +if(empty($errors)) { $account_players = $account_logged->getPlayersList(false); foreach($account_players as $player) @@ -31,7 +34,7 @@ if(empty($guild_errors)) if(!$player_rank->isLoaded()) { if($player->getLevel() >= setting('core.guild_need_level')) { - if(!setting('core.guild_need_premium') || $account_logged->isPremium()) { + if(!setting('core.guild_need_premium') || $account_logged->isPremium() || $freePremium) { $array_of_player_nig[] = $player->getName(); } } @@ -41,45 +44,44 @@ if(empty($guild_errors)) if(empty($todo)) { if(count($array_of_player_nig) == 0) { - $guild_errors[] = 'On your account all characters are in guilds, have too low level to create new guild' . (setting('core.guild_need_premium') ? ' or you don\' have a premium account' : '') . '.'; + $errors[] = 'On your account all characters are in guilds, have too low level to create new guild' . (setting('core.guild_need_premium') ? ' or you don\' have a premium account' : '') . '.'; } } if($todo == 'save') { if(!Validator::guildName($guild_name)) { - $guild_errors[] = Validator::getLastError(); + $errors[] = Validator::getLastError(); $guild_name = ''; } if(!Validator::characterName($name)) { - $guild_errors[] = 'Invalid character name format.'; + $errors[] = 'Invalid character name format.'; $name = ''; } - if(empty($guild_errors)) { + if(empty($errors)) { $player = new OTS_Player(); $player->find($name); if(!$player->isLoaded()) { - $guild_errors[] = 'Character '.$name.' doesn\'t exist.'; + $errors[] = 'Character '.$name.' doesn\'t exist.'; } } - - if(empty($guild_errors)) + if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if($guild->isLoaded()) { - $guild_errors[] = 'Guild '.$guild_name.' already exist. Select other name.'; + $errors[] = 'Guild '.$guild_name.' already exist. Select other name.'; } } - if(empty($guild_errors) && $player->isDeleted()) { - $guild_errors[] = "Character $name has been deleted."; + if(empty($errors) && $player->isDeleted()) { + $errors[] = "Character $name has been deleted."; } - if(empty($guild_errors)) + if(empty($errors)) { $bad_char = true; foreach($array_of_player_nig as $nick_from_list) { @@ -88,22 +90,22 @@ if($todo == 'save') } } if($bad_char) { - $guild_errors[] = 'Character '.$name.' isn\'t on your account or is already in guild.'; + $errors[] = 'Character '.$name.' isn\'t on your account or is already in guild.'; } } - if(empty($guild_errors)) { + if(empty($errors)) { if($player->getLevel() < setting('core.guild_need_level')) { - $guild_errors[] = 'Character '.$name.' has too low level. To create guild you need character with level ' . setting('core.guild_need_level') . '.'; + $errors[] = 'Character '.$name.' has too low level. To create guild you need character with level ' . setting('core.guild_need_level') . '.'; } - if(setting('core.guild_need_premium') && !$account_logged->isPremium()) { - $guild_errors[] = 'Character '.$name.' is on FREE account. To create guild you need PREMIUM account.'; + if(setting('core.guild_need_premium') && !$account_logged->isPremium() && !$freePremium) { + $errors[] = 'Character '.$name.' is on FREE account. To create guild you need PREMIUM account.'; } } } -if(!empty($guild_errors)) { - $twig->display('error_box.html.twig', array('errors' => $guild_errors)); +if(!empty($errors)) { + $twig->display('error_box.html.twig', array('errors' => $errors)); unset($todo); } diff --git a/system/pages/guilds/delete_by_admin.php b/system/pages/guilds/delete_by_admin.php index e403cbda..f453cd7a 100644 --- a/system/pages/guilds/delete_by_admin.php +++ b/system/pages/guilds/delete_by_admin.php @@ -45,7 +45,10 @@ if(empty($errors)) { $twig->display('success.html.twig', array( 'title' => 'Delete Guild', 'description' => 'Are you sure you want delete guild ' . $guild_name . '?
    -
    ', +
    + ' . csrf(true) . ' + +
    ', 'custom_buttons' => $twig->render('guilds.back_button.html.twig') )); } diff --git a/system/pages/guilds/delete_guild.php b/system/pages/guilds/delete_guild.php index 978ac513..0e4bd0ba 100644 --- a/system/pages/guilds/delete_guild.php +++ b/system/pages/guilds/delete_guild.php @@ -21,7 +21,7 @@ if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; + $errors[] = "Guild with name $guild_name doesn't exist."; } } @@ -31,7 +31,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild->getOwner()->getId() == $player->getId()) { diff --git a/system/pages/guilds/delete_invite.php b/system/pages/guilds/delete_invite.php index 7bf4067a..485ca9d0 100644 --- a/system/pages/guilds/delete_invite.php +++ b/system/pages/guilds/delete_invite.php @@ -15,47 +15,43 @@ require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; $name = stripslashes($_REQUEST['name']); -if(!$logged) +if(!$logged) { $errors[] = 'You are not logged in. You can\'t delete invitations.'; +} -if(!Validator::guildName($guild_name)) +if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); +} -if(!Validator::characterName($name)) +if(!Validator::characterName($name)) { $errors[] = 'Invalid name format.'; +} -if(empty($errors)) -{ +if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) $errors[] = "Guild with name " . $guild_name . " doesn't exist."; } -if(empty($errors)) -{ +if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; $guild_vice = false; - $account_players = $account_logged->getPlayers(); - foreach($account_players as $player) - { + $account_players = $account_logged->getPlayersList(); + foreach($account_players as $player) { $player_rank = $player->getRank(); - if($player_rank->isLoaded()) - { - foreach($rank_list as $rank_in_guild) - { - if($rank_in_guild->getId() == $player_rank->getId()) - { + if($player_rank->isLoaded()) { + foreach($rank_list as $rank_in_guild) { + if($rank_in_guild->getId() == $player_rank->getId()) { $players_from_account_in_guild[] = $player->getName(); - if($player_rank->getLevel() > 1) - { + if($player_rank->getLevel() > 1) { $guild_vice = true; $level_in_guild = $player_rank->getLevel(); } - if($guild->getOwner()->getId() == $player->getId()) - { + + if($guild->getOwner()->getId() == $player->getId()) { $guild_vice = true; $guild_leader = true; } @@ -64,44 +60,46 @@ if(empty($errors)) } } - if(!$guild_vice) + if(!$guild_vice) { $errors[] = 'You are not a leader or vice leader of guild ' . $guild_name . '.'; -} -if(empty($errors)) -{ - $player = new OTS_Player(); - $player->find($name); - if(!$player->isLoaded()) - $errors[] = 'Player with name ' . $name . ' doesn\'t exist.'; + } } -if(empty($errors)) -{ +if(empty($errors)) { + $player = new OTS_Player(); + $player->find($name); + if(!$player->isLoaded()) { + $errors[] = "Player with name $name doesn't exist."; + } +} + +if(empty($errors)) { include(SYSTEM . 'libs/pot/InvitesDriver.php'); new InvitesDriver($guild); $invited_list = $guild->listInvites(); - if(count($invited_list) > 0) - { + if(count($invited_list) > 0) { $is_invited = false; - foreach($invited_list as $invited) - if($invited->getName() == $player->getName()) + foreach($invited_list as $invited) { + if ($invited->getName() == $player->getName()) { $is_invited = true; - if(!$is_invited) - $errors[] = ''.$player->getName().' isn\'t invited to your guild.'; + } + } + if(!$is_invited) { + $errors[] = '' . $player->getName() . ' isn\'t invited to your guild.'; + } } - else + else { $errors[] = 'No one is invited to your guild.'; + } } -if(!empty($errors)) -{ + +if(!empty($errors)) { $twig->display('error_box.html.twig', array('errors' => $errors)); $twig->display('guilds.back_button.html.twig', array('action' => getLink('guilds') . '?action=show&guild=' . $guild_name)); } -else -{ - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') - { +else { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $guild->deleteInvite($player); $twig->display('success.html.twig', array( 'title' => 'Deleted player invitation', diff --git a/system/pages/guilds/delete_rank.php b/system/pages/guilds/delete_rank.php index 56322cd9..ce783137 100644 --- a/system/pages/guilds/delete_rank.php +++ b/system/pages/guilds/delete_rank.php @@ -13,25 +13,27 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; -$rank_to_delete = isset($_REQUEST['rankid']) ? (int) $_REQUEST['rankid'] : null; +$rank_to_delete = isset($_POST['rankid']) ? (int) $_POST['rankid'] : null; if(!Validator::guildName($guild_name)) { - $guild_errors[] = Validator::getLastError(); + $errors[] = Validator::getLastError(); } -if(empty($guild_errors)) { + +if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $guild_errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; + $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; } } -if(empty($guild_errors)) { + +if(empty($errors)) { if($logged) { $guild_leader_char = $guild->getOwner(); $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild->getOwner()->getId() == $player->getId()) { $guild_vice = true; @@ -39,21 +41,21 @@ if(empty($guild_errors)) { $level_in_guild = 3; } } + if($guild_leader) { $rank = new OTS_GuildRank(); $rank->load($rank_to_delete); if(!$rank->isLoaded()) { - $guild_errors2[] = 'Rank with ID '.$rank_to_delete.' doesn\'t exist.'; + $errors2[] = 'Rank with ID '.$rank_to_delete.' doesn\'t exist.'; } - else - { + else { if($rank->getGuild()->getId() != $guild->getId()) { - $guild_errors2[] = 'Rank with ID '.$rank_to_delete.' isn\'t from your guild.'; + $errors2[] = 'Rank with ID '.$rank_to_delete.' isn\'t from your guild.'; } else { if(count($rank_list) < 2) { - $guild_errors2[] = 'You have only 1 rank in your guild. You can\'t delete this rank.'; + $errors2[] = 'You have only 1 rank in your guild. You can\'t delete this rank.'; } else { @@ -87,19 +89,21 @@ if(empty($guild_errors)) { $player->setRank($new_rank); } } + $rank->delete(); $saved = true; } } } - if($saved) { + + if(isset($saved) && $saved) { $twig->display('success.html.twig', array( 'title' => 'Rank Deleted', 'description' => 'Rank '.$rank->getName().' has been deleted. Players with this rank has now other rank.', 'custom_buttons' => '' )); } else { - $twig->display('error_box.html.twig', array('errors' => $guild_errors2)); + $twig->display('error_box.html.twig', array('errors' => $errors2)); } $twig->display('guilds.back_button.html.twig', array( @@ -107,18 +111,16 @@ if(empty($guild_errors)) { 'action' => getLink('guilds') . '?guild='.$guild->getName().'&action=manager' )); } - else - { - $guild_errors[] = 'You are not a leader of guild!'; + else { + $errors[] = 'You are not a leader of guild!'; } } - else - { - $guild_errors[] = 'You are not logged. You can\'t manage guild.'; + else { + $errors[] = 'You are not logged. You can\'t manage guild.'; } } -if(!empty($guild_errors)) { - $twig->display('error_box.html.twig', array('errors' => $guild_errors)); +if(!empty($errors)) { + $twig->display('error_box.html.twig', array('errors' => $errors)); $twig->display('guilds.back_button.html.twig', array( 'new_line' => true, diff --git a/system/pages/guilds/invite.php b/system/pages/guilds/invite.php index 8fae8e27..0984fd0a 100644 --- a/system/pages/guilds/invite.php +++ b/system/pages/guilds/invite.php @@ -23,6 +23,12 @@ if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); } +if (!$db->hasTableAndColumns('guild_invites', ['player_id'])) { + $errors[] = "Guild invite is not possible on this website."; + $twig->display('error_box.html.twig', ['errors' => $errors]); + return; +} + if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); @@ -36,7 +42,7 @@ if(empty($errors)) { $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; $guild_vice = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { $player_rank = $player->getRank(); if($player_rank->isLoaded()) { @@ -58,11 +64,11 @@ if(empty($errors)) { } } -if(!$guild_vice) { +if(empty($errors) && !$guild_vice) { $errors[] = 'You are not a leader or vice leader of guild '.$guild_name.'.'.$level_in_guild; } -if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { +if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(!Validator::characterName($name)) { $errors[] = 'Invalid name format.'; } @@ -71,7 +77,7 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { $player = new OTS_Player(); $player->find($name); if(!$player->isLoaded()) { - $errors[] = 'Player with name ' . $name . ' doesn\'t exist.'; + $errors[] = "Player with name $name doesn't exist."; } else if ($player->isDeleted()) { $errors[] = "Character with name $name has been deleted."; } @@ -84,6 +90,7 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { } } } + if(empty($errors)) { include(SYSTEM . 'libs/pot/InvitesDriver.php'); new InvitesDriver($guild); @@ -102,8 +109,9 @@ if(!empty($errors)) { $twig->display('error_box.html.twig', array('errors' => $errors)); } else { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $guild->invite($player); + $twig->display('success.html.twig', array( 'title' => 'Invite player', 'description' => 'Player with name ' . $player->getName() . ' has been invited to your guild.', diff --git a/system/pages/guilds/kick_player.php b/system/pages/guilds/kick_player.php index 5ce79187..736617b0 100644 --- a/system/pages/guilds/kick_player.php +++ b/system/pages/guilds/kick_player.php @@ -41,7 +41,7 @@ if(empty($errors)) { $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; $guild_vice = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { $player_rank = $player->getRank(); if($player_rank->isLoaded()) { @@ -102,7 +102,7 @@ if(!empty($errors)) { } else { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $player->setRank(); $twig->display('success.html.twig', array( diff --git a/system/pages/guilds/leave.php b/system/pages/guilds/leave.php index 9a11595d..50f52a6c 100644 --- a/system/pages/guilds/leave.php +++ b/system/pages/guilds/leave.php @@ -34,7 +34,7 @@ if(empty($errors)) { $array_of_player_ig = array(); if(empty($errors)) { $guild_owner_name = $guild->getOwner()->getName(); - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(!Validator::characterName($name)) { $errors[] = 'Invalid name format.'; } @@ -72,7 +72,7 @@ if(empty($errors)) { } else { - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player_fac) { $player_rank = $player_fac->getRank(); if($player_rank->isLoaded()) { @@ -94,7 +94,7 @@ if(!empty($errors)) { } else { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $player->setRank(); $twig->display('success.html.twig', array( 'title' => 'Leave guild', diff --git a/system/pages/guilds/list.php b/system/pages/guilds/list.php index 96d7bf08..94c49854 100644 --- a/system/pages/guilds/list.php +++ b/system/pages/guilds/list.php @@ -14,31 +14,31 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; $guilds_list = new OTS_Guilds_List(); -$guilds_list->orderBy("name"); +$guilds_list->orderBy('name'); $guilds = array(); -if(count($guilds_list) > 0) -{ +if(count($guilds_list) > 0) { /** * @var OTS_Guild $guild */ foreach ($guilds_list as $guild) { $guild_logo = $guild->getCustomField('logo_name'); - if (empty($guild_logo) || !file_exists(GUILD_IMAGES_DIR . $guild_logo)) - $guild_logo = "default.gif"; + if (empty($guild_logo) || !file_exists(GUILD_IMAGES_DIR . $guild_logo)) { + $guild_logo = 'default.gif'; + } $description = $guild->getCustomField('description'); $description_with_lines = str_replace(array("\r\n", "\n", "\r"), '
    ', $description, $count); - if ($count < setting('core.guild_description_lines_limit')) + if ($count < setting('core.guild_description_lines_limit')) { $description = nl2br($description); + } $guildName = $guild->getName(); $guilds[] = array('name' => $guildName, 'logo' => $guild_logo, 'link' => getGuildLink($guildName, false), 'description' => $description); } -}; +} $twig->display('guilds.list.html.twig', array( 'guilds' => $guilds, - 'logged' => isset($logged) ? $logged : false, 'isAdmin' => admin(), )); diff --git a/system/pages/guilds/manager.php b/system/pages/guilds/manager.php index 4d59c22e..cfcc00c6 100644 --- a/system/pages/guilds/manager.php +++ b/system/pages/guilds/manager.php @@ -21,7 +21,7 @@ if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; + $errors[] = "Guild with name $guild_name doesn't exist."; } } @@ -31,7 +31,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { $guild_vice = true; @@ -39,22 +39,22 @@ if(empty($errors)) { $level_in_guild = 3; } } + if($guild_leader) { $twig->display('guilds.manager.html.twig', array( 'guild' => $guild, 'rank_list' => $rank_list )); } - else - { + else { $errors[] = 'You are not a leader of guild!'; } } - else - { - $errors[] = 'You are not logged. You can\'t manage guild.'; + else { + $errors[] = "You are not logged. You can't manage guild."; } } + if(!empty($errors)) { $twig->display('error_box.html.twig', array('errors' => $errors)); } diff --git a/system/pages/guilds/pass_leadership.php b/system/pages/guilds/pass_leadership.php index c09b4285..40633b8a 100644 --- a/system/pages/guilds/pass_leadership.php +++ b/system/pages/guilds/pass_leadership.php @@ -15,51 +15,52 @@ require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : NULL; $pass_to = isset($_REQUEST['player']) ? stripslashes($_REQUEST['player']) : NULL; if(!Validator::guildName($guild_name)) { - $guild_errors[] = Validator::getLastError(); + $errors[] = Validator::getLastError(); } -if(empty($guild_errors)) { +if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $guild_errors[] = "Guild with name " . $guild_name . " doesn't exist."; + $errors[] = "Guild with name " . $guild_name . " doesn't exist."; } } -if(empty($guild_errors)) { + +if(empty($errors)) { if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(!Validator::characterName($pass_to)) { - $guild_errors2[] = 'Invalid player name format.'; + $errors2[] = 'Invalid player name format.'; } - if(empty($guild_errors2)) { + if(empty($errors2)) { $to_player = new OTS_Player(); $to_player->find($pass_to); if(!$to_player->isLoaded()) { - $guild_errors2[] = 'Player with name '.$pass_to.' doesn\'t exist.'; + $errors2[] = 'Player with name '.$pass_to.' doesn\'t exist.'; } else if ($to_player->isDeleted()) { - $guild_errors2[] = "Character with name $pass_to has been deleted."; + $errors2[] = "Character with name $pass_to has been deleted."; } - if(empty($guild_errors2)) { + if(empty($errors2)) { $to_player_rank = $to_player->getRank(); if($to_player_rank->isLoaded()) { $to_player_guild = $to_player_rank->getGuild(); if($to_player_guild->getId() != $guild->getId()) { - $guild_errors2[] = 'Player with name '.$to_player->getName().' isn\'t from your guild.'; + $errors2[] = 'Player with name '.$to_player->getName().' isn\'t from your guild.'; } } else { - $guild_errors2[] = 'Player with name '.$to_player->getName().' isn\'t from your guild.'; + $errors2[] = 'Player with name '.$to_player->getName().' isn\'t from your guild.'; } } } } } -if(empty($guild_errors) && empty($guild_errors2)) { +if(empty($errors) && empty($errors2)) { if($logged) { $guild_leader_char = $guild->getOwner(); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { $guild_vice = true; @@ -99,23 +100,23 @@ if(empty($guild_errors) && empty($guild_errors2)) { } } else { - $guild_errors[] = 'You are not a leader of guild!'; + $errors[] = 'You are not a leader of guild!'; } } else { - $guild_errors[] = "You are not logged. You can't manage guild."; + $errors[] = "You are not logged. You can't manage guild."; } } -if(empty($guild_errors) && !empty($guild_errors2)) { - $twig->display('error_box.html.twig', array('errors' => $guild_errors2)); +if(empty($errors) && !empty($errors2)) { + $twig->display('error_box.html.twig', array('errors' => $errors2)); echo '
    ' . $twig->render('buttons.back.html.twig') . '
    '; } -if(!empty($guild_errors)) { - if(!empty($guild_errors2)) { - $guild_errors = array_merge($guild_errors, $guild_errors2); +if(!empty($errors)) { + if(!empty($errors2)) { + $errors = array_merge($errors, $errors2); } - $twig->display('error_box.html.twig', array('errors' => $guild_errors)); + $twig->display('error_box.html.twig', array('errors' => $errors)); echo '
    ' . $twig->render('buttons.back.html.twig') . '
    '; } diff --git a/system/pages/guilds/save_ranks.php b/system/pages/guilds/save_ranks.php index e1483659..2a36e595 100644 --- a/system/pages/guilds/save_ranks.php +++ b/system/pages/guilds/save_ranks.php @@ -31,7 +31,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { @@ -61,6 +61,7 @@ if(empty($errors)) { $rank->save(); } + //show errors or redirect if(empty($errors)) { header("Location: " . getLink('guilds') . "?action=manager&guild=".$guild->getName()); @@ -73,10 +74,10 @@ if(empty($errors)) { } else { - $errors[] = 'You are not logged. You can\'t manage guild.'; + $errors[] = "You are not logged. You can't manage guild."; } } if(!empty($errors)) { - $twig->display('error_box.html.twig', array('errors' => $errors)); + $twig->display('error_box.html.twig', ['errors' => $errors]); } diff --git a/system/pages/guilds/show.php b/system/pages/guilds/show.php index 33039ad3..99ac6599 100644 --- a/system/pages/guilds/show.php +++ b/system/pages/guilds/show.php @@ -16,19 +16,18 @@ $title = 'Guilds'; require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; -if(!Validator::guildName($guild_name)) +if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); +} -if(empty($errors)) -{ +if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; } -if(!empty($errors)) -{ +if(!empty($errors)) { $twig->display('error_box.html.twig', array('errors' => $errors)); $twig->display('guilds.back_button.html.twig'); return; @@ -47,9 +46,8 @@ $level_in_guild = 0; $players_from_account_in_guild = array(); $players_from_account_ids = array(); -if($logged) -{ - $account_players = $account_logged->getPlayers(); +if($logged) { + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { $players_from_account_ids[] = $player->getId(); @@ -123,25 +121,28 @@ foreach($rank_list as $rank) } } -include(SYSTEM . 'libs/pot/InvitesDriver.php'); -new InvitesDriver($guild); -$invited_list = $guild->listInvites(); +$invited_list = []; $show_accept_invite = 0; -if($logged && count($invited_list) > 0) -{ - foreach($invited_list as $invited_player) - { - if(count($account_players) > 0) - { - foreach($account_players as $player_from_acc) - { - if($player_from_acc->isLoaded() && $invited_player->isLoaded() && $player_from_acc->getName() == $invited_player->getName()) - $show_accept_invite++; + +if ($db->hasTableAndColumns('guild_invites', ['player_id'])) { + include(SYSTEM . 'libs/pot/InvitesDriver.php'); + new InvitesDriver($guild); + $invited_list = $guild->listInvites(); + + if($logged && count($invited_list) > 0) { + foreach($invited_list as $invited_player) { + if(count($account_players) > 0) { + foreach($account_players as $player_from_acc) { + if($player_from_acc->isLoaded() && $invited_player->isLoaded() && $player_from_acc->getName() == $invited_player->getName()) { + $show_accept_invite++; + } + } } } } } + $useGuildNick = $db->hasTable('guild_members') || $db->hasTable('guild_membership') || $db->hasColumn('players', 'guildnick'); $twig->display('guilds.view.html.twig', array( diff --git a/system/pages/highscores.php b/system/pages/highscores.php index 91ba2e2b..cec95d15 100644 --- a/system/pages/highscores.php +++ b/system/pages/highscores.php @@ -18,8 +18,11 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Highscores'; $settingHighscoresCountryBox = setting('core.highscores_country_box'); -if(config('account_country') && $settingHighscoresCountryBox) +if(config('account_country') && $settingHighscoresCountryBox) { require SYSTEM . 'countries.conf.php'; +} + +$highscoresTTL = setting('core.highscores_cache_ttl'); $list = urldecode($_GET['list'] ?? 'experience'); $page = $_GET['page'] ?? 1; @@ -120,16 +123,10 @@ if($db->hasColumn('players', 'promotion')) $promotion = ',players.promotion'; $outfit_addons = false; -$outfit = ''; - -$settingHighscoresOutfit = setting('core.highscores_outfit'); - -if($settingHighscoresOutfit) { - $outfit = ', lookbody, lookfeet, lookhead, looklegs, looktype'; - if($db->hasColumn('players', 'lookaddons')) { - $outfit .= ', lookaddons'; - $outfit_addons = true; - } +$outfit = ', lookbody, lookfeet, lookhead, looklegs, looktype'; +if($db->hasColumn('players', 'lookaddons')) { + $outfit .= ', lookaddons'; + $outfit_addons = true; } $configHighscoresPerPage = setting('core.highscores_per_page'); @@ -140,20 +137,27 @@ $needReCache = true; $cacheKey = 'highscores_' . $skill . '_' . $vocation . '_' . $page . '_' . $configHighscoresPerPage; $cache = Cache::getInstance(); -if ($cache->enabled()) { +if ($cache->enabled() && $highscoresTTL > 0) { $tmp = ''; if ($cache->fetch($cacheKey, $tmp)) { - $highscores = unserialize($tmp); + $data = unserialize($tmp); + $totalResults = $data['totalResults']; + $highscores = $data['highscores']; + $updatedAt = $data['updatedAt']; $needReCache = false; } } $offset = ($page - 1) * $configHighscoresPerPage; -$query->join('accounts', 'accounts.id', '=', 'players.account_id') - ->withOnlineStatus() +$query->withOnlineStatus() ->whereNotIn('players.id', setting('core.highscores_ids_hidden')) ->notDeleted() - ->where('players.group_id', '<', setting('core.highscores_groups_hidden')) + ->where('players.group_id', '<', setting('core.highscores_groups_hidden')); + +$totalResultsQuery = clone $query; + +$query + ->join('accounts', 'accounts.id', '=', 'players.account_id') ->limit($limit) ->offset($offset) ->selectRaw('accounts.country, players.id, players.name, players.account_id, players.level, players.vocation' . $outfit . $promotion) @@ -212,17 +216,24 @@ if (empty($highscores)) { return $tmp; })->toArray(); + + $updatedAt = time(); + $totalResults = $totalResultsQuery->count(); } -if ($cache->enabled() && $needReCache) { - $cache->set($cacheKey, serialize($highscores), setting('core.highscores_cache_ttl') * 60); +if ($highscoresTTL > 0 && $cache->enabled() && $needReCache) { + $cache->set($cacheKey, serialize( + [ + 'totalResults' => $totalResults, + 'highscores' => $highscores, + 'updatedAt' => $updatedAt, + ] + ), $highscoresTTL * 60); } $show_link_to_next_page = false; $i = 0; -$settingHighscoresVocation = setting('core.highscores_vocation'); - foreach($highscores as $id => &$player) { if(++$i <= $configHighscoresPerPage) @@ -236,10 +247,22 @@ foreach($highscores as $id => &$player) $player['link'] = getPlayerLink($player['name'], false); $player['flag'] = getFlagImage($player['country']); - if($settingHighscoresOutfit) { - $player['outfit'] = ''; + $player['outfit'] = ''; + + if ($skill != POT::SKILL__LEVEL) { + if (isset($lastValue) && $lastValue == $player['value']) { + $player['rank'] = $lastRank; + } + else { + $player['rank'] = $offset + $i; + } + + $lastRank = $player['rank'] ; + $lastValue = $player['value']; + } + else { + $player['rank'] = $offset + $i; } - $player['rank'] = $offset + $i; } else { unset($highscores[$id]); @@ -260,6 +283,8 @@ if($show_link_to_next_page) { $linkNextPage = getLink('highscores') . '/' . $list . ($vocation !== 'all' ? '/' . $vocation : '') . '/' . ($page + 1); } +$baseLink = getLink('highscores') . '/' . $list . ($vocation !== 'all' ? '/' . $vocation : '') . '/'; + $types = array( 'experience' => 'Experience', 'magic' => 'Magic', @@ -278,6 +303,10 @@ if(setting('core.highscores_frags')) { if(setting('core.highscores_balance')) $types['balance'] = 'Balance'; +if ($highscoresTTL > 0 && $cache->enabled()) { + echo '*Note: Highscores are updated every' . ($highscoresTTL > 1 ? ' ' . $highscoresTTL : '') . ' minute' . ($highscoresTTL > 1 ? 's' : '') . '.

    '; +} + /** @var Twig\Environment $twig */ $twig->display('highscores.html.twig', [ 'highscores' => $highscores, @@ -290,4 +319,8 @@ $twig->display('highscores.html.twig', [ 'types' => $types, 'linkPreviousPage' => $linkPreviousPage, 'linkNextPage' => $linkNextPage, + 'totalResults' => $totalResults, + 'page' => $page, + 'baseLink' => $baseLink, + 'updatedAt' => $updatedAt, ]); diff --git a/system/pages/online.php b/system/pages/online.php index 4f0baa7d..21f2ee0d 100644 --- a/system/pages/online.php +++ b/system/pages/online.php @@ -9,123 +9,140 @@ * @link https://my-aac.org */ +use MyAAC\Cache\Cache; use MyAAC\Models\ServerConfig; use MyAAC\Models\ServerRecord; defined('MYAAC') or die('Direct access not allowed!'); $title = 'Who is online?'; -if (setting('core.account_country')) +if (setting('core.account_country')) { require SYSTEM . 'countries.conf.php'; +} $promotion = ''; -if($db->hasColumn('players', 'promotion')) +if($db->hasColumn('players', 'promotion')) { $promotion = '`promotion`,'; - -$order = $_GET['order'] ?? 'name'; -if(!in_array($order, array('country', 'name', 'level', 'vocation'))) - $order = $db->fieldName('name'); -else if($order == 'country') - $order = $db->tableName('accounts') . '.' . $db->fieldName('country'); -else if($order == 'vocation') - $order = $promotion . 'vocation ASC'; - -$skull_type = 'skull'; -if($db->hasColumn('players', 'skull_type')) { - $skull_type = 'skull_type'; } -$skull_time = 'skulltime'; -if($db->hasColumn('players', 'skull_time')) { - $skull_time = 'skull_time'; +$order = $_GET['order'] ?? 'name_asc'; +if(!in_array($order, ['country_asc', 'country_desc', 'name_asc', 'name_desc', 'level_asc', 'level_desc', 'vocation_asc', 'vocation_desc'])) { + $order = 'name_asc'; +} +else if($order == 'vocation_asc' || $order == 'vocation_desc') { + $order = $promotion . 'vocation_' . (str_contains($order, 'asc') ? 'asc' : 'desc'); } -$outfit_addons = false; -$outfit = ''; -if (setting('core.online_outfit')) { +$cached = Cache::remember("online_$order", setting('core.online_cache_ttl') * 60, function() use($db, $promotion, $order) { + $orderExplode = explode('_', $order); + $orderSql = $orderExplode[0] . ' ' . $orderExplode[1]; + + $skull_type = 'skull'; + if($db->hasColumn('players', 'skull_type')) { + $skull_type = 'skull_type'; + } + + $skull_time = 'skulltime'; + if($db->hasColumn('players', 'skull_time')) { + $skull_time = 'skull_time'; + } + + $outfit_addons = false; $outfit = ', lookbody, lookfeet, lookhead, looklegs, looktype'; if($db->hasColumn('players', 'lookaddons')) { $outfit .= ', lookaddons'; $outfit_addons = true; } -} -$vocs = []; -if (setting('core.online_vocations')) { - foreach($config['vocations'] as $id => $name) { - $vocs[$id] = 0; - } -} + $vocations = array_map(function ($name) { + return 0; + }, setting('core.vocations')); -if($db->hasTable('players_online')) // tfs 1.0 - $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players`, `players_online` WHERE `players`.`id` = `players_online`.`player_id` AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $order); -else - $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', ' . $promotion . ' `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players` WHERE `players`.`online` > 0 AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $order); + if($db->hasTable('players_online')) // tfs 1.0 + $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players`, `players_online` WHERE `players`.`id` = `players_online`.`player_id` AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $orderSql); + else + $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', ' . $promotion . ' `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players` WHERE `players`.`online` > 0 AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $orderSql); -$players_data = array(); -$players = 0; -$data = ''; -foreach($playersOnline as $player) { - $skull = ''; - if (setting('core.online_skulls')) - { - if($player['skulltime'] > 0) - { - if($player['skull'] == 3) + $settingVocations = setting('core.vocations'); + $settingVocationsAmount = setting('core.vocations_amount'); + + $players = []; + foreach($playersOnline as $player) { + $skull = ''; + if($player['skulltime'] > 0) { + if($player['skull'] == 3) { $skull = ' '; - elseif($player['skull'] == 4) + } + elseif($player['skull'] == 4) { $skull = ' '; - elseif($player['skull'] == 5) + } + elseif($player['skull'] == 5) { $skull = ' '; - } - } - - if(isset($player['promotion'])) { - if((int)$player['promotion'] > 0) - $player['vocation'] += ($player['promotion'] * $config['vocations_amount']); - } - - $players_data[] = array( - 'name' => getPlayerLink($player['name']), - 'player' => $player, - 'level' => $player['level'], - 'vocation' => $config['vocations'][$player['vocation']], - 'country_image' => setting('core.account_country') ? getFlagImage($player['country']) : null, - 'outfit' => setting('core.online_outfit') ? setting('core.outfit_images_url') . '?id=' . $player['looktype'] . ($outfit_addons ? '&addons=' . $player['lookaddons'] : '') . '&head=' . $player['lookhead'] . '&body=' . $player['lookbody'] . '&legs=' . $player['looklegs'] . '&feet=' . $player['lookfeet'] : null - ); - - if (setting('core.online_vocations')) { - $vocs[($player['vocation'] > $config['vocations_amount'] ? $player['vocation'] - $config['vocations_amount'] : $player['vocation'])]++; - } -} - -$record = ''; -if(count($players_data) > 0) { - if( setting('core.online_record')) { - $result = null; - $timestamp = false; - if($db->hasTable('server_record')) { - $timestamp = true; - $result = ServerRecord::where('world_id', $config['lua']['worldId'])->orderByDesc('record')->first()->toArray(); - } else if($db->hasTable('server_config')) { // tfs 1.0 - $row = ServerConfig::where('config', 'players_record')->first(); - if ($row) { - $result = ['record' => $row->value]; } } - if($result) { - $record = 'The maximum on this game world was ' . $result['record'] . ' players' . ($timestamp ? ' on ' . date("M d Y, H:i:s", $result['timestamp']) . '.' : '.'); + if(isset($player['promotion'])) { + if((int)$player['promotion'] > 0) + $player['vocation'] += ($player['promotion'] * $settingVocationsAmount); + } + + $players[] = array( + 'name' => getPlayerLink($player['name']), + 'player' => $player, + 'level' => $player['level'], + 'vocation' => $settingVocations[$player['vocation']], + 'skull' => $skull, + 'country_image' => getFlagImage($player['country']), + 'outfit' => setting('core.outfit_images_url') . '?id=' . $player['looktype'] . ($outfit_addons ? '&addons=' . $player['lookaddons'] : '') . '&head=' . $player['lookhead'] . '&body=' . $player['lookbody'] . '&legs=' . $player['looklegs'] . '&feet=' . $player['lookfeet'], + ); + + $vocations[($player['vocation'] > $settingVocationsAmount ? $player['vocation'] - $settingVocationsAmount : $player['vocation'])]++; + } + + $record = ''; + if(count($players) > 0) { + if( setting('core.online_record')) { + $result = null; + $timestamp = false; + if($db->hasTable('server_record')) { + $timestamp = $db->hasColumn('server_record', 'timestamp'); + $serverRecordQuery = ServerRecord::query(); + + if ($db->hasColumn('server_record', 'world_id')) { + $serverRecordQuery->where('world_id', configLua('worldId')); + } + + $result = $serverRecordQuery->orderByDesc('record')->first(); + if ($result) { + $result = $result->toArray(); + } + } else if($db->hasTable('server_config')) { // tfs 1.0 + $row = ServerConfig::where('config', 'players_record')->first(); + if ($row) { + $result = ['record' => $row->value]; + } + } + + if($result) { + $record = $result['record'] . ' player' . ($result['record'] > 1 ? 's' : '') . ($timestamp ? ' (on ' . date("M d Y, H:i:s", $result['timestamp']) . ')' : ''); + } } } -} + + return [ + 'players' => $players, + 'record' => $record, + 'vocations' => $vocations, + ]; +}); $twig->display('online.html.twig', array( - 'players' => $players_data, - 'record' => $record, - 'vocs' => $vocs, + 'players' => $cached['players'], + 'record' => $cached['record'], + 'vocations' => $cached['vocations'], + 'vocs' => $cached['vocations'], // deprecated, to be removed + 'order' => $order, )); -//search bar -$twig->display('online.form.html.twig'); -?> +// search bar +$twig->display('characters.form.html.twig'); diff --git a/system/pages/ots-info.php b/system/pages/ots-info.php new file mode 100644 index 00000000..b750c3ee --- /dev/null +++ b/system/pages/ots-info.php @@ -0,0 +1,110 @@ + + * @author Slawkens + * @author whiteblXK + * @copyright 2019 MyAAC + * @link https://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'Server info'; + +if(isset($config['lua']['experience_stages'])) + $config['lua']['experienceStages'] = $config['lua']['experience_stages']; + +if(isset($config['lua']['min_pvp_level'])) + $config['lua']['protectionLevel'] = $config['lua']['min_pvp_level']; + +$rent = trim(strtolower($config['lua']['houseRentPeriod'])); +if($rent != 'yearly' && $rent != 'monthly' && $rent != 'weekly' && $rent != 'daily') + $rent = 'never'; + +if(isset($config['lua']['houseCleanOld'])) + $cleanOld = (int)(eval('return ' . $config['lua']['houseCleanOld'] . ';') / (24 * 60 * 60)); + +if(isset($config['lua']['rate_exp'])) + $config['lua']['rateExp'] = $config['lua']['rate_exp']; +if(isset($config['lua']['rateExperience'])) + $config['lua']['rateExp'] = $config['lua']['rateExperience']; +if(isset($config['lua']['rate_mag'])) + $config['lua']['rateMagic'] = $config['lua']['rate_mag']; +if(isset($config['lua']['rate_skill'])) + $config['lua']['rateSkill'] = $config['lua']['rate_skill']; +if(isset($config['lua']['rate_loot'])) + $config['lua']['rateLoot'] = $config['lua']['rate_loot']; +if(isset($config['lua']['rate_spawn'])) + $config['lua']['rateSpawn'] = $config['lua']['rate_spawn']; + +$house_level = NULL; +if(isset($config['lua']['levelToBuyHouse'])) + $house_level = $config['lua']['levelToBuyHouse']; +else if(isset($config['lua']['house_level'])) + $house_level = $config['lua']['house_level']; + +if(isset($config['lua']['in_fight_duration'])) + $config['lua']['pzLocked'] = $config['lua']['in_fight_duration']; + +$pzLocked = eval('return ' . $config['lua']['pzLocked'] . ';'); +$whiteSkullTime = isset($config['lua']['whiteSkullTime']) ? $config['lua']['whiteSkullTime'] : NULL; +if(!isset($whiteSkullTime) && isset($config['lua']['unjust_skull_duration'])) + $whiteSkullTime = $config['lua']['unjust_skull_duration']; + +if(isset($whiteSkullTime)) + $whiteSkullTime = eval('return ' . $whiteSkullTime . ';'); + +$redSkullLength = isset($config['lua']['redSkullLength']) ? $config['lua']['redSkullLength'] : NULL; +if(!isset($redSkullLength) && isset($config['lua']['red_skull_duration'])) + $redSkullLength = $config['lua']['red_skull_duration']; + +if(isset($redSkullLength)) + $redSkullLength = eval('return ' . $redSkullLength . ';'); + +$blackSkull = false; +$blackSkullLength = NULL; +if(isset($config['lua']['useBlackSkull']) && getBoolean($config['lua']['useBlackSkull'])) +{ + $blackSkullLength = $config['lua']['blackSkullLength']; + $blackSkull = true; +} +else if(isset($config['lua']['black_skull_duration'])) { + $blackSkullLength = eval('return ' . $config['lua']['blackSkullLength'] . ';'); + $blackSkull = true; +} + +$clientVersion = NULL; +if(isset($status['online'])) + $clientVersion = isset($status['clientVersion']) ? $status['clientVersion'] : null; + +$twig->display('serverinfo.html.twig', array( + 'experienceStages' => isset($config['lua']['experienceStages']) && getBoolean($config['lua']['experienceStages']) ? $config['lua']['experienceStages'] : null, + 'serverIp' => str_replace('/', '', str_replace('http://', '', $config['lua']['url'])), + 'clientVersion' => $clientVersion, + 'globalSaveHour' => isset($config['lua']['globalSaveEnabled']) && getBoolean($config['lua']['globalSaveEnabled']) ? $config['lua']['globalSaveHour'] : null, + 'protectionLevel' => $config['lua']['protectionLevel'], + 'houseRent' => $rent == 'never' ? 'disabled' : $rent, + 'houseOld' => isset($cleanOld) ? $cleanOld : null, + 'rateExp' => $config['lua']['rateExp'], + 'rateExpFromPlayers' => isset($config['lua']['rateExperienceFromPlayers']) ? $config['lua']['rateExperienceFromPlayers'] : null, + 'rateMagic' => $config['lua']['rateMagic'], + 'rateSkill' => $config['lua']['rateSkill'], + 'rateLoot' => $config['lua']['rateLoot'], + 'rateSpawn' => $config['lua']['rateSpawn'], + 'houseLevel' => $house_level, + 'pzLocked' => $pzLocked, + 'whiteSkullTime' => $whiteSkullTime, + 'redSkullLength' => $redSkullLength, + 'blackSkull' => $blackSkull, + 'blackSkullLength' => $blackSkullLength, + 'dailyFragsToRedSkull' => isset($config['lua']['dailyFragsToRedSkull']) ? $config['lua']['dailyFragsToRedSkull'] : (isset($config['lua']['kills_per_day_red_skull']) ? $config['lua']['kills_per_day_red_skull'] : null), + 'weeklyFragsToRedSkull' => isset($config['lua']['weeklyFragsToRedSkull']) ? $config['lua']['weeklyFragsToRedSkull'] : (isset($config['lua']['kills_per_week_red_skull']) ? $config['lua']['kills_per_week_red_skull'] : null), + 'monthlyFragsToRedSkull' => isset($config['lua']['monthlyFragsToRedSkull']) ? $config['lua']['monthlyFragsToRedSkull'] : (isset($config['lua']['kills_per_month_red_skull']) ? $config['lua']['kills_per_month_red_skull'] : null), + 'dailyFragsToBlackSkull' => isset($config['lua']['dailyFragsToBlackSkull']) ? $config['lua']['dailyFragsToBlackSkull'] : (isset($config['lua']['kills_per_day_black_skull']) ? $config['lua']['kills_per_day_black_skull'] : null), + 'weeklyFragsToBlackSkull' => isset($config['lua']['weeklyFragsToBlackSkull']) ? $config['lua']['weeklyFragsToBlackSkull'] : (isset($config['lua']['kills_per_week_black_skull']) ? $config['lua']['kills_per_week_black_skull'] : null), + 'monthlyFragsToBlackSkull' => isset($config['lua']['monthlyFragsToBlackSkull']) ? $config['lua']['monthlyFragsToBlackSkull'] : (isset($config['lua']['kills_per_month_black_skull']) ? $config['lua']['kills_per_month_black_skull'] : null), + 'banishmentLength' => isset($config['lua']['banishment_length']) ? eval('return (' . $config['lua']['banishment_length'] . ') / (24 * 60 * 60);') : null, + 'finalBanishmentLength' => isset($config['lua']['final_banishment_length']) ? eval('return (' . $config['lua']['final_banishment_length'] . ') / (24 * 60 * 60);') : null, + 'ipBanishmentLength' => isset($config['lua']['ip_banishment_length']) ? eval('return (' . $config['lua']['ip_banishment_length'] . ') / (24 * 60 * 60);') : null, +)); diff --git a/system/pages/rules.php b/system/pages/rules.php deleted file mode 100644 index 4ee0e4aa..00000000 --- a/system/pages/rules.php +++ /dev/null @@ -1,14 +0,0 @@ - - * @author Slawkens - * @copyright 2019 MyAAC - * @link https://my-aac.org - */ -defined('MYAAC') or die('Direct access not allowed!'); -$title = 'Server Rules'; - -$twig->display('rules.html.twig'); diff --git a/system/pages/server-info.php b/system/pages/server-info.php index b750c3ee..7f09422f 100644 --- a/system/pages/server-info.php +++ b/system/pages/server-info.php @@ -1,110 +1,3 @@ - * @author Slawkens - * @author whiteblXK - * @copyright 2019 MyAAC - * @link https://my-aac.org - */ -defined('MYAAC') or die('Direct access not allowed!'); -$title = 'Server info'; -if(isset($config['lua']['experience_stages'])) - $config['lua']['experienceStages'] = $config['lua']['experience_stages']; - -if(isset($config['lua']['min_pvp_level'])) - $config['lua']['protectionLevel'] = $config['lua']['min_pvp_level']; - -$rent = trim(strtolower($config['lua']['houseRentPeriod'])); -if($rent != 'yearly' && $rent != 'monthly' && $rent != 'weekly' && $rent != 'daily') - $rent = 'never'; - -if(isset($config['lua']['houseCleanOld'])) - $cleanOld = (int)(eval('return ' . $config['lua']['houseCleanOld'] . ';') / (24 * 60 * 60)); - -if(isset($config['lua']['rate_exp'])) - $config['lua']['rateExp'] = $config['lua']['rate_exp']; -if(isset($config['lua']['rateExperience'])) - $config['lua']['rateExp'] = $config['lua']['rateExperience']; -if(isset($config['lua']['rate_mag'])) - $config['lua']['rateMagic'] = $config['lua']['rate_mag']; -if(isset($config['lua']['rate_skill'])) - $config['lua']['rateSkill'] = $config['lua']['rate_skill']; -if(isset($config['lua']['rate_loot'])) - $config['lua']['rateLoot'] = $config['lua']['rate_loot']; -if(isset($config['lua']['rate_spawn'])) - $config['lua']['rateSpawn'] = $config['lua']['rate_spawn']; - -$house_level = NULL; -if(isset($config['lua']['levelToBuyHouse'])) - $house_level = $config['lua']['levelToBuyHouse']; -else if(isset($config['lua']['house_level'])) - $house_level = $config['lua']['house_level']; - -if(isset($config['lua']['in_fight_duration'])) - $config['lua']['pzLocked'] = $config['lua']['in_fight_duration']; - -$pzLocked = eval('return ' . $config['lua']['pzLocked'] . ';'); -$whiteSkullTime = isset($config['lua']['whiteSkullTime']) ? $config['lua']['whiteSkullTime'] : NULL; -if(!isset($whiteSkullTime) && isset($config['lua']['unjust_skull_duration'])) - $whiteSkullTime = $config['lua']['unjust_skull_duration']; - -if(isset($whiteSkullTime)) - $whiteSkullTime = eval('return ' . $whiteSkullTime . ';'); - -$redSkullLength = isset($config['lua']['redSkullLength']) ? $config['lua']['redSkullLength'] : NULL; -if(!isset($redSkullLength) && isset($config['lua']['red_skull_duration'])) - $redSkullLength = $config['lua']['red_skull_duration']; - -if(isset($redSkullLength)) - $redSkullLength = eval('return ' . $redSkullLength . ';'); - -$blackSkull = false; -$blackSkullLength = NULL; -if(isset($config['lua']['useBlackSkull']) && getBoolean($config['lua']['useBlackSkull'])) -{ - $blackSkullLength = $config['lua']['blackSkullLength']; - $blackSkull = true; -} -else if(isset($config['lua']['black_skull_duration'])) { - $blackSkullLength = eval('return ' . $config['lua']['blackSkullLength'] . ';'); - $blackSkull = true; -} - -$clientVersion = NULL; -if(isset($status['online'])) - $clientVersion = isset($status['clientVersion']) ? $status['clientVersion'] : null; - -$twig->display('serverinfo.html.twig', array( - 'experienceStages' => isset($config['lua']['experienceStages']) && getBoolean($config['lua']['experienceStages']) ? $config['lua']['experienceStages'] : null, - 'serverIp' => str_replace('/', '', str_replace('http://', '', $config['lua']['url'])), - 'clientVersion' => $clientVersion, - 'globalSaveHour' => isset($config['lua']['globalSaveEnabled']) && getBoolean($config['lua']['globalSaveEnabled']) ? $config['lua']['globalSaveHour'] : null, - 'protectionLevel' => $config['lua']['protectionLevel'], - 'houseRent' => $rent == 'never' ? 'disabled' : $rent, - 'houseOld' => isset($cleanOld) ? $cleanOld : null, - 'rateExp' => $config['lua']['rateExp'], - 'rateExpFromPlayers' => isset($config['lua']['rateExperienceFromPlayers']) ? $config['lua']['rateExperienceFromPlayers'] : null, - 'rateMagic' => $config['lua']['rateMagic'], - 'rateSkill' => $config['lua']['rateSkill'], - 'rateLoot' => $config['lua']['rateLoot'], - 'rateSpawn' => $config['lua']['rateSpawn'], - 'houseLevel' => $house_level, - 'pzLocked' => $pzLocked, - 'whiteSkullTime' => $whiteSkullTime, - 'redSkullLength' => $redSkullLength, - 'blackSkull' => $blackSkull, - 'blackSkullLength' => $blackSkullLength, - 'dailyFragsToRedSkull' => isset($config['lua']['dailyFragsToRedSkull']) ? $config['lua']['dailyFragsToRedSkull'] : (isset($config['lua']['kills_per_day_red_skull']) ? $config['lua']['kills_per_day_red_skull'] : null), - 'weeklyFragsToRedSkull' => isset($config['lua']['weeklyFragsToRedSkull']) ? $config['lua']['weeklyFragsToRedSkull'] : (isset($config['lua']['kills_per_week_red_skull']) ? $config['lua']['kills_per_week_red_skull'] : null), - 'monthlyFragsToRedSkull' => isset($config['lua']['monthlyFragsToRedSkull']) ? $config['lua']['monthlyFragsToRedSkull'] : (isset($config['lua']['kills_per_month_red_skull']) ? $config['lua']['kills_per_month_red_skull'] : null), - 'dailyFragsToBlackSkull' => isset($config['lua']['dailyFragsToBlackSkull']) ? $config['lua']['dailyFragsToBlackSkull'] : (isset($config['lua']['kills_per_day_black_skull']) ? $config['lua']['kills_per_day_black_skull'] : null), - 'weeklyFragsToBlackSkull' => isset($config['lua']['weeklyFragsToBlackSkull']) ? $config['lua']['weeklyFragsToBlackSkull'] : (isset($config['lua']['kills_per_week_black_skull']) ? $config['lua']['kills_per_week_black_skull'] : null), - 'monthlyFragsToBlackSkull' => isset($config['lua']['monthlyFragsToBlackSkull']) ? $config['lua']['monthlyFragsToBlackSkull'] : (isset($config['lua']['kills_per_month_black_skull']) ? $config['lua']['kills_per_month_black_skull'] : null), - 'banishmentLength' => isset($config['lua']['banishment_length']) ? eval('return (' . $config['lua']['banishment_length'] . ') / (24 * 60 * 60);') : null, - 'finalBanishmentLength' => isset($config['lua']['final_banishment_length']) ? eval('return (' . $config['lua']['final_banishment_length'] . ') / (24 * 60 * 60);') : null, - 'ipBanishmentLength' => isset($config['lua']['ip_banishment_length']) ? eval('return (' . $config['lua']['ip_banishment_length'] . ') / (24 * 60 * 60);') : null, -)); +require 'ots-info.php'; diff --git a/system/router.php b/system/router.php index b87a843d..f876a9b2 100644 --- a/system/router.php +++ b/system/router.php @@ -88,25 +88,38 @@ if($logged && $account_logged && $account_logged->isLoaded()) { /** * Routes loading */ +$routesFinal = []; $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) { - $routesFinal = []; + global $cache, $routesFinal; + foreach(getDatabasePages() as $page) { $routesFinal[] = ['*', $page, '__database__/' . $page, 100]; } + $routes = require SYSTEM . 'routes.php'; Plugins::clearWarnings(); - foreach (Plugins::getRoutes() as $route) { - $routesFinal[] = [$route[0], $route[1], $route[2], $route[3] ?? 1000]; + + foreach (Plugins::getRoutes() as $pluginRoute) { + + $routesFinal[] = [$pluginRoute[0], $pluginRoute[1], $pluginRoute[2], $pluginRoute[3] ?? 1000]; + + // Possibility to override routes with plugins pages, like characters.php + foreach ($routes as &$route) { + if (str_contains($pluginRoute[2], 'pages/' . $route[2])) { + $route[2] = $pluginRoute[2]; + } + } /* echo '
    ';
    -		var_dump($route[1], $route[3], $route[2]);
    +		var_dump($pluginRoute[1], $pluginRoute[3], $pluginRoute[2]);
     		echo '/
    ';
     */
     	}
     
    -	$routes = require SYSTEM . 'routes.php';
     	foreach ($routes as $route) {
    -		if (!str_contains($route[2], '__redirect__') && !str_contains($route[2], '__database__')) {
    +		if (!str_contains($route[2], '__redirect__') && !str_contains($route[2], '__database__')
    +			&& !str_contains($route[2], 'plugins/')
    +		) {
     			if (!is_file(BASE . 'system/pages/' . $route[2])) {
     				continue;
     			}
    @@ -129,14 +142,14 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r)
     		return ($a[3] < $b[3]) ? -1 : 1;
     	});
     
    +	$aliases = [
    +		[':int', ':string', ':alphanum'],
    +		[':\d+', ':[A-Za-z0-9-_%+\' ]+', ':[A-Za-z0-9]+'],
    +	];
    +
     	// remove duplicates
     	// if same route pattern, but different priority
    -	$routesFinal = array_filter($routesFinal, function ($a) {
    -		$aliases = [
    -			[':int', ':string', ':alphanum'],
    -			[':\d+', ':[A-Za-z0-9-_%+\' ]+', ':[A-Za-z0-9]+'],
    -		];
    -
    +	$routesFinal = array_filter($routesFinal, function ($a) use ($aliases) {
     		// apply aliases
     		$a[1] = str_replace($aliases[0], $aliases[1], $a[1]);
     
    @@ -154,7 +167,7 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r)
     	echo '
    '; die; */ - foreach ($routesFinal as $route) { + foreach ($routesFinal as &$route) { if ($route[0] === '*') { $route[0] = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD']; } @@ -171,15 +184,15 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) $route[0] = array_map($toUpperCase, $route[0]); } - $aliases = [ - [':int', ':string', ':alphanum'], - [':\d+', ':[A-Za-z0-9-_%+\' ]+', ':[A-Za-z0-9]+'], - ]; - // apply aliases $route[1] = str_replace($aliases[0], $aliases[1], $route[1]); - $r->addRoute($route[0], $route[1], $route[2]); + try { + $r->addRoute($route[0], $route[1], $route[2]); + } + catch (\Exception $e) { + // duplicated route, just ignore + } } if (config('env') === 'dev') { @@ -187,6 +200,10 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) log_append('router.log', $warning); } } + + if ($cache->enabled()) { + $cache->set('routes_final', serialize($routesFinal), 10 * 365 * 24 * 60 * 60); // 10 years / infinite + } }, [ 'cacheFile' => CACHE . 'route.cache', @@ -201,7 +218,7 @@ $found = true; // old support for pages like /?subtopic=accountmanagement $page = $_REQUEST['p'] ?? ($_REQUEST['subtopic'] ?? ''); -if(!empty($page) && preg_match('/^[A-z0-9\-]+$/', $page)) { +if(!empty($page) && preg_match('/^[A-z0-9\/\-]+$/', $page)) { if (isset($_REQUEST['p'])) { // some plugins may require this $_REQUEST['subtopic'] = $_REQUEST['p']; } @@ -210,9 +227,26 @@ if(!empty($page) && preg_match('/^[A-z0-9\-]+$/', $page)) { require SYSTEM . 'compat/pages.php'; } - $file = loadPageFromFileSystem($page, $found); - if(!$found) { - $file = false; + $foundRoute = false; + + $tmp = null; + if ($cache->enabled() && $cache->fetch('routes_final', $tmp)) { + $routesFinal = unserialize($tmp); + } + + foreach ($routesFinal as $route) { + if ($page === $route[1]) { + $file = $route[2]; + $foundRoute = true; + break; + } + } + + if (!$foundRoute) { + $file = loadPageFromFileSystem($page, $found); + if(!$found) { + $file = false; + } } } else { @@ -252,7 +286,7 @@ else { $success = false; $tmp_content = getCustomPage($pageName, $success); - if ($success) { + if ($success && $hooks->trigger(HOOK_BEFORE_PAGE_CUSTOM)) { $content .= $tmp_content; if (hasFlag(FLAG_CONTENT_PAGES) || superAdmin()) { $pageInfo = getCustomPageInfo($pageName); @@ -260,6 +294,8 @@ else { ) . $content; } + $hooks->trigger(HOOK_AFTER_PAGE_CUSTOM); + $page = $pageName; $file = false; } @@ -324,7 +360,9 @@ if (isset($_REQUEST['_page_only'])) { if(!isset($title)) { $title = str_replace('index.php/', '', $page); - $title = ucfirst($title); + $title = str_replace(['_', '-', '/'], ' ', $page); + + $title = ucwords($title); } if(setting('core.backward_support')) { diff --git a/system/routes.php b/system/routes.php index 13cee37f..b4af29f0 100644 --- a/system/routes.php +++ b/system/routes.php @@ -22,11 +22,11 @@ return [ ['GET', 'account/confirm-email/{hash:alphanum}', 'account/confirm-email.php'], ['GET', 'bans/{page:int}', 'bans.php'], - [['GET', 'POST'], 'characters[/{name:string}]', 'characters.php'], - ['GET', 'changelog[/{page:int}]', 'changelog.php'], - [['GET', 'POST'], 'monsters[/{name:string}]', 'monsters.php'], + [['GET', 'POST'], 'characters/{name:[A-Za-z0-9-_%+\' \[\]]+}', 'characters.php'], + ['GET', 'changelog/{page:int}', 'changelog.php'], + [['GET', 'POST'], 'monsters/{name:string}', 'monsters.php'], - [['GET', 'POST'], 'faq[/{action:string}]', 'faq.php'], + [['GET', 'POST'], 'faq/{action:string}', 'faq.php'], [['GET', 'POST'], 'forum/{action:string}', 'forum.php'], ['GET', 'forum/board/{id:int}', 'forum/show_board.php'], diff --git a/system/settings.php b/system/settings.php index 729527c0..73605530 100644 --- a/system/settings.php +++ b/system/settings.php @@ -19,6 +19,24 @@ $templates = Cache::remember('templates', 5 * 60, function () { }); $defaultTemplate = in_array('kathrine', $templates) ? 'kathrine' : $templates[0]; +global $db; + +if (!IS_CLI) { + require SYSTEM . 'base.php'; + + $serverUrl = 'http' . (isHttps() ? 's' : '') . '://' . $baseHost; + $siteURL = $serverUrl . $baseDir; +} + +$donateColumnOptions = [ + 'premium_points' => 'Premium Points', + 'coins' => 'Coins', +]; + +if (defined('HAS_ACCOUNT_COINS_TRANSFERABLE') && (HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS)) { + $donateColumnOptions[ACCOUNT_COINS_TRANSFERABLE_COLUMN] = 'Coins Transferable'; +} + return [ 'name' => 'MyAAC', 'settings' => [ @@ -30,6 +48,13 @@ return [ 'type' => 'section', 'title' => 'General' ], + 'site_url' => [ + 'name' => 'Website URL', + 'type' => 'text', + 'desc' => 'Website address of this MyAAC instance', + 'default' => IS_CLI ? '' : $siteURL, + 'is_config' => true, + ], 'env' => [ 'name' => 'App Environment', 'type' => 'options', @@ -674,6 +699,20 @@ Sent by MyAAC,
    'desc' => 'Default premium points on new account', 'default' => 0, ], + 'account_coins' => [ + 'name' => 'Default Account Coins', + 'type' => 'number', + 'desc' => 'Default coins on new account', + 'hidden' => ($db && !HAS_ACCOUNT_COINS), + 'default' => 0, + ], + 'account_coins_transferable' => [ + 'name' => 'Default Account Transferable Coins', + 'type' => 'number', + 'desc' => 'Default transferable coins on new account', + 'hidden' => ($db && !HAS_ACCOUNT_COINS_TRANSFERABLE && !HAS_ACCOUNT_TRANSFERABLE_COINS), + 'default' => 0, + ], 'account_mail_change' => [ 'name' => 'Account Mail Change Days', 'type' => 'number', @@ -1035,10 +1074,16 @@ Sent by MyAAC,
    'highscores_cache_ttl' => [ 'name' => 'Highscores Cache TTL (in minutes)', 'type' => 'number', - 'min' => 1, - 'desc' => 'How often to update highscores from database in minutes (default 15 minutes). Too low may cause lags on website.', + 'min' => 0, + 'desc' => 'How often to update highscores from database in minutes. Too low may slow down your website.
    0 to disable.', 'default' => 15, ], + 'highscores_skills_box' => [ + 'name' => 'Display Skills Box', + 'type' => 'boolean', + 'desc' => 'show "Choose a skill" box on the highscores (allowing peoples to sort highscores by skill)?', + 'default' => true, + ], 'highscores_vocation_box' => [ 'name' => 'Display Vocation Box', 'type' => 'boolean', @@ -1051,6 +1096,12 @@ Sent by MyAAC,
    'desc' => 'Show player vocation under his nickname?', 'default' => true, ], + 'highscores_online_status' => [ + 'name' => 'Display Online Status', + 'type' => 'boolean', + 'desc' => 'Show player status as red (offline) or green (online)', + 'default' => false, + ], 'highscores_frags' => [ 'name' => 'Display Top Frags', 'type' => 'boolean', @@ -1205,6 +1256,14 @@ Sent by MyAAC,
    'type' => 'section', 'title' => 'Online Page' ], + 'online_cache_ttl' => [ + 'name' => 'Online Cache TTL (in minutes)', + 'type' => 'number', + 'min' => 0, + 'desc' => 'How often to update online list from database in minutes. Too low may slow down your website.' . PHP_EOL . + '0 to disable.', + 'default' => 15, + ], 'online_record' => [ 'name' => 'Display Players Record', 'type' => 'boolean', @@ -1241,6 +1300,12 @@ Sent by MyAAC,
    'desc' => '', 'default' => false, ], + 'online_datacenter' => [ + 'name' => 'Data Center', + 'type' => 'text', + 'desc' => 'Server Location, will be shown on online page', + 'default' => 'Poland - Warsaw', + ], [ 'type' => 'section', 'title' => 'Team Page' @@ -1542,13 +1607,14 @@ Sent by MyAAC,
    'name' => 'Donate Column', 'type' => 'options', 'desc' => 'What to give to player after donation - what column in accounts table to use.', - 'options' => ['premium_points' => 'Premium Points', 'coins' => 'Coins'], + 'options' => $donateColumnOptions, 'default' => 'premium_points', 'callbacks' => [ 'beforeSave' => function($key, $value, &$errorMessage) { global $db; - if ($value == 'coins' && !$db->hasColumn('accounts', 'coins')) { - $errorMessage = "Shop: Donate Column: Cannot set column to coins, because it doesn't exist in database."; + + if (!$db->hasColumn('accounts', $value)) { + $errorMessage = "Shop: Donate Column: Cannot set column to $value, because it doesn't exist in database."; return false; } return true; diff --git a/system/src/Admin/Plugins.php b/system/src/Admin/Plugins.php new file mode 100644 index 00000000..f7b781f2 --- /dev/null +++ b/system/src/Admin/Plugins.php @@ -0,0 +1,49 @@ + $this->api_base_uri, + // You can set any number of default request options. + 'timeout' => 3.0, + ]); + + $plugins = get_plugins(true); + foreach ($plugins as &$plugin) { + if (str_contains($plugin, 'disabled.')) { + $plugin = str_replace('disabled.', '', $plugin); + } + } + + try { + $response = $client->get('get-latest-versions', [ + 'json' => ['plugins' => $plugins], + ]); + } + catch (\Exception $e) { + error('API Error. Please try again later.'); + return []; + } + + $statusCode = $response->getStatusCode(); + if ($statusCode != 200) { + throw new \Exception('Error getting info from plugins repository. Please try again later.'); + } + + $data = $response->getBody(); + return json_decode($data, true); + } + + public function setApiBaseUri(string $uri): void { + $this->api_base_uri = $uri; + } +} diff --git a/system/src/Cache/Cache.php b/system/src/Cache/Cache.php index 0a369202..1b7d284b 100644 --- a/system/src/Cache/Cache.php +++ b/system/src/Cache/Cache.php @@ -106,7 +106,7 @@ class Cache public static function remember($key, $ttl, $callback) { $cache = self::getInstance(); - if (!$cache->enabled()) { + if (!$cache->enabled() || $ttl == 0) { return $callback(); } @@ -115,6 +115,11 @@ class Cache return unserialize($value); } + // -1 for infinite cache + if ($ttl == -1) { + $ttl = 10 * 365 * 24 * 60 * 60; // 10 years should be enough + } + $value = $callback(); $cache->set($key, serialize($value), $ttl); return $value; diff --git a/system/src/Commands/CacheClearCommand.php b/system/src/Commands/CacheClearCommand.php index 3b052995..5f9bae0b 100644 --- a/system/src/Commands/CacheClearCommand.php +++ b/system/src/Commands/CacheClearCommand.php @@ -2,6 +2,7 @@ namespace MyAAC\Commands; +use MyAAC\Cache\Cache; use MyAAC\Hooks; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -17,10 +18,7 @@ class CacheClearCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { - global $hooks; - $hooks = new Hooks(); - $hooks->load(); - $hooks->trigger(HOOK_INIT); + require SYSTEM . 'init.php'; $io = new SymfonyStyle($input, $output); @@ -29,6 +27,13 @@ class CacheClearCommand extends Command return Command::FAILURE; } + $cacheEngine = config('cache_engine') == 'auto' ? + Cache::detect() : config('cache_engine'); + + if (config('env') !== 'dev' && $cacheEngine == 'apcu') { + $io->warning('APCu cache cannot be cleared in CLI. Please visit the Admin Panel and clear there.'); + } + $io->success('Cache cleared'); return Command::SUCCESS; } diff --git a/system/src/Commands/Env.php b/system/src/Commands/Env.php new file mode 100644 index 00000000..e3130806 --- /dev/null +++ b/system/src/Commands/Env.php @@ -0,0 +1,33 @@ +setName('mail:send') + $this->setName('email:send') + ->setAliases(['mail:send']) ->setDescription('This command sends E-Mail to single user. Message can be provided as follows: ' . PHP_EOL - . ' echo "Hello World" | php sa email:send --subject="This is the subject" test@test.com') + . ' echo "Hello World" | php aac email:send --subject="This is the subject" test@test.com') ->addArgument('recipient', InputArgument::REQUIRED, 'Email, Account Name, Account id or Player Name') ->addOption('subject', 's', InputOption::VALUE_REQUIRED, 'Subject'); } diff --git a/system/src/Commands/MigrateCommand.php b/system/src/Commands/MigrateCommand.php index a8a21016..fe110190 100644 --- a/system/src/Commands/MigrateCommand.php +++ b/system/src/Commands/MigrateCommand.php @@ -9,6 +9,8 @@ use Symfony\Component\Console\Style\SymfonyStyle; class MigrateCommand extends Command { + use Env; + protected function configure(): void { $this->setName('migrate') @@ -17,9 +19,19 @@ class MigrateCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { - require SYSTEM . 'init.php'; + $this->init(); $io = new SymfonyStyle($input, $output); + + $tmp = ''; + if(fetchDatabaseConfig('database_version', $tmp)) { // we got version + $tmp = (int)$tmp; + if ($tmp >= DATABASE_VERSION) { + $io->success('Already on latest version.'); + return Command::SUCCESS; + } + } + require SYSTEM . 'migrate.php'; $io->success('Migrated to latest version (' . DATABASE_VERSION . ')'); diff --git a/system/src/Commands/MigrateRunCommand.php b/system/src/Commands/MigrateRunCommand.php index 3bdb1452..2ea06938 100644 --- a/system/src/Commands/MigrateRunCommand.php +++ b/system/src/Commands/MigrateRunCommand.php @@ -10,6 +10,8 @@ use Symfony\Component\Console\Style\SymfonyStyle; class MigrateRunCommand extends Command { + use Env; + protected function configure(): void { $this->setName('migrate:run') @@ -23,12 +25,12 @@ 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'); + $this->init(); + // pre-check // in case one of the migrations doesn't exist - we won't execute any of them foreach ($ids as $id) { @@ -45,6 +47,22 @@ class MigrateRunCommand extends Command $down = $input->getOption('down') ?? false; + /** + * Sort according to $down option. + * Do we really want it? + * Or should we use order provided by user, + * even when it's not sorted correctly? + * Leaving it for consideration. + */ + /* + if ($down) { + rsort($ids); + } + else { + sort($ids); + } + */ + foreach ($ids as $id) { $this->executeMigration($id, $io, !$down); } diff --git a/system/src/Commands/MigrateToCommand.php b/system/src/Commands/MigrateToCommand.php index b82012ed..72be5730 100644 --- a/system/src/Commands/MigrateToCommand.php +++ b/system/src/Commands/MigrateToCommand.php @@ -11,6 +11,8 @@ use Symfony\Component\Console\Style\SymfonyStyle; class MigrateToCommand extends Command { + use Env; + protected function configure(): void { $this->setName('migrate:to') @@ -32,7 +34,7 @@ class MigrateToCommand extends Command return Command::FAILURE; } - $this->initEnv(); + $this->init(); $currentVersion = Config::where('name', 'database_version')->first()->value; if ($currentVersion > $versionDest) { @@ -80,29 +82,4 @@ class MigrateToCommand extends Command 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/PluginDisableCommand.php b/system/src/Commands/PluginDisableCommand.php new file mode 100644 index 00000000..baa268dd --- /dev/null +++ b/system/src/Commands/PluginDisableCommand.php @@ -0,0 +1,36 @@ +setName('plugin:disable') + ->setDescription('This command disables plugin') + ->addArgument('plugin-name', InputArgument::REQUIRED, 'Plugin that you want to disable'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + require SYSTEM . 'init.php'; + + $io = new SymfonyStyle($input, $output); + + $pluginName = $input->getArgument('plugin-name'); + + if (!Plugins::disable($pluginName)) { + $io->error('Error while disabling plugin ' . $pluginName . ': ' . Plugins::getError()); + return 2; + } + + $io->success('Successfully disabled plugin ' . $pluginName); + return Command::SUCCESS; + } +} diff --git a/system/src/Commands/PluginEnableCommand.php b/system/src/Commands/PluginEnableCommand.php new file mode 100644 index 00000000..ae1acea0 --- /dev/null +++ b/system/src/Commands/PluginEnableCommand.php @@ -0,0 +1,36 @@ +setName('plugin:enable') + ->setDescription('This command enables plugin') + ->addArgument('plugin-name', InputArgument::REQUIRED, 'Plugin that you want to enable'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + require SYSTEM . 'init.php'; + + $io = new SymfonyStyle($input, $output); + + $pluginName = $input->getArgument('plugin-name'); + + if (!Plugins::enable($pluginName)) { + $io->error('Error while enabling plugin ' . $pluginName . ': ' . Plugins::getError()); + return 2; + } + + $io->success('Successfully enabled plugin ' . $pluginName); + return Command::SUCCESS; + } +} diff --git a/system/src/Commands/PluginInstallInstallCommand.php b/system/src/Commands/PluginSetupCommand.php similarity index 89% rename from system/src/Commands/PluginInstallInstallCommand.php rename to system/src/Commands/PluginSetupCommand.php index fe1b4f14..8923360c 100644 --- a/system/src/Commands/PluginInstallInstallCommand.php +++ b/system/src/Commands/PluginSetupCommand.php @@ -8,11 +8,12 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -class PluginInstallInstallCommand extends Command +class PluginSetupCommand extends Command { protected function configure(): void { - $this->setName('plugin:install:install') + $this->setName('plugin:setup') + ->setAliases(['plugin:install:install']) ->setDescription('This command executes the "install" part of the plugin') ->addArgument('plugin', InputArgument::REQUIRED, 'Plugin name'); } diff --git a/system/src/Commands/PluginUninstallCommand.php b/system/src/Commands/PluginUninstallCommand.php new file mode 100644 index 00000000..a5cc00f5 --- /dev/null +++ b/system/src/Commands/PluginUninstallCommand.php @@ -0,0 +1,40 @@ +setName('plugin:uninstall') + ->setDescription('This command uninstalls plugin') + ->addArgument('plugin-name', InputArgument::REQUIRED, 'Plugin that you want to uninstall'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + require SYSTEM . 'init.php'; + + $io = new SymfonyStyle($input, $output); + + $pluginName = $input->getArgument('plugin-name'); + + if (!Plugins::uninstall($pluginName)) { + $io->error('Error while uninstalling plugin ' . $pluginName . ': ' . Plugins::getError()); + return 2; + } + + foreach(Plugins::getWarnings() as $warning) { + $io->warning($warning); + } + + $io->success('Successfully uninstalled plugin ' . $pluginName); + return Command::SUCCESS; + } +} diff --git a/system/src/Commands/SettingsResetCommand.php b/system/src/Commands/SettingsResetCommand.php index 78748b00..3e4d793c 100644 --- a/system/src/Commands/SettingsResetCommand.php +++ b/system/src/Commands/SettingsResetCommand.php @@ -3,6 +3,7 @@ namespace MyAAC\Commands; use MyAAC\Models\Settings as SettingsModel; +use MyAAC\Plugins; use MyAAC\Settings; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -34,7 +35,14 @@ class SettingsResetCommand extends Command return Command::FAILURE; } - if (!$name) { + // find by plugin name + foreach (Plugins::getAllPluginsSettings() as $key => $setting) { + if ($setting['pluginFilename'] === $name) { + $name = $key; + } + } + + if (empty($name)) { SettingsModel::truncate(); } else { diff --git a/system/src/Commands/SettingsSetCommand.php b/system/src/Commands/SettingsSetCommand.php index 4ad33227..eac0ecc5 100644 --- a/system/src/Commands/SettingsSetCommand.php +++ b/system/src/Commands/SettingsSetCommand.php @@ -3,6 +3,7 @@ namespace MyAAC\Commands; use MyAAC\Models\Settings as SettingsModel; +use MyAAC\Plugins; use MyAAC\Settings; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -17,7 +18,7 @@ class SettingsSetCommand extends Command ->setDescription('Updates the setting specified by argument in database') ->addArgument('key', InputArgument::REQUIRED, - 'Setting name/key' + 'Setting key in format name.key' ) ->addArgument('value', InputArgument::REQUIRED, @@ -34,6 +35,18 @@ class SettingsSetCommand extends Command $key = $input->getArgument('key'); $value = $input->getArgument('value'); + // format settings_name.key + // example: core.template + $explode = explode('.', $key); + + // find by plugin name + foreach (Plugins::getAllPluginsSettings() as $_key => $setting) { + if ($setting['pluginFilename'] === $explode[0]) { + $explode[0] = $_key; + $key = implode('.', $explode); + } + } + $settings = Settings::getInstance(); $settings->clearCache(); $settings->load(); @@ -44,10 +57,6 @@ class SettingsSetCommand extends Command return Command::FAILURE; } - // format plugin_name.key - // example: core.template - $explode = explode('.', $key); - $settings->updateInDatabase($explode[0], $explode[1], $value); $settings->clearCache(); diff --git a/system/src/CsrfToken.php b/system/src/CsrfToken.php index 7e002928..baa7c74d 100644 --- a/system/src/CsrfToken.php +++ b/system/src/CsrfToken.php @@ -25,8 +25,9 @@ class CsrfToken * * @access public * @static true + * @param bool $return * @return string - **/ + */ public static function create(bool $return = false): string { $input = ''; if ($return) { @@ -58,7 +59,7 @@ class CsrfToken * @static true * @return boolean **/ - public static function isValid($post): bool + public static function isValid(string|null $post): bool { if (!setting('core.csrf_protection')) { return true; diff --git a/system/src/Hook.php b/system/src/Hook.php index 161b2ffc..6acdf6ef 100644 --- a/system/src/Hook.php +++ b/system/src/Hook.php @@ -38,6 +38,8 @@ class Hook } public function executeFilter(&$args) { + global $db, $config, $template_path, $ots, $content, $twig; + return include BASE . $this->_file; } diff --git a/system/src/Items.php b/system/src/Items.php index 977aa602..0f92b005 100644 --- a/system/src/Items.php +++ b/system/src/Items.php @@ -76,10 +76,11 @@ class Items public static function get($id) { self::load(); - return isset(self::$items[$id]) ? self::$items[$id] : []; + return self::$items[$id] ?? []; } - public static function getDescription($id, $count = 1) { + public static function getDescription($id, $count = 1): string + { $item = self::get($id); $attr = $item['attributes']; @@ -112,15 +113,15 @@ class Items $s .= 'an item of type ' . $item['id']; if(isset($attr['type']) && strtolower($attr['type']) == 'rune') { - $item = Spell::where('item_id', $id)->first(); - if($item) { - if($item->level > 0 && $item->maglevel > 0) { - $s .= '. ' . ($count > 1 ? "They" : "It") . ' can only be used by '; + $spell = Spell::where('item_id', $id)->first(); + if($spell) { + if($spell->level > 0 && $spell->maglevel > 0) { + $s .= '. ' . ($count > 1 ? 'They' : 'It') . ' can only be used by '; } $configVocations = config('vocations'); - if(!empty(trim($item->vocations))) { - $vocations = json_decode($item->vocations); + if(!empty(trim($spell->vocations))) { + $vocations = json_decode($spell->vocations); if(count($vocations) > 0) { foreach($vocations as $voc => $show) { $vocations[$configVocations[$voc]] = $show; @@ -133,8 +134,39 @@ class Items $s .= ' with'; + if ($spell->level > 0) { + $s .= ' level ' . $spell->level; + } + + if ($spell->maglevel > 0) { + if ($spell->level > 0) { + $s .= ' and'; + } + + $s .= ' magic level ' . $spell->maglevel; + } + + $s .= ' or higher'; } } + + if (!empty($item['weaponType'])) { + if ($item['weaponType'] == 'distance' && isset($item['ammoType'])) { + $s .= ' (Range:' . $item['range']; + } + + if (isset($item['attack']) && $item['attack'] != 0) { + $s .= ', Atk ' . ($item['attack'] > 0 ? '+' . $item['attack'] : '-' . $item['attack']); + } + + if (isset($item['hitChance']) && $item['hitChance'] != -1) { + $s .= ', Hit% ' . ($item['hitChance'] > 0 ? '+' . $item['hitChance'] : '-' . $item['hitChance']); + } + elseif ($item['weaponType'] != 'ammo') { + + } + } + return $s; } } diff --git a/system/src/Models/Account.php b/system/src/Models/Account.php index 613b3029..4b44b153 100644 --- a/system/src/Models/Account.php +++ b/system/src/Models/Account.php @@ -5,11 +5,15 @@ namespace MyAAC\Models; use Illuminate\Database\Eloquent\Model; /** + * @property integer $premium_ends_at + * @property integer $premend * @property integer $lastday * @property integer $premdays */ class Account extends Model { + const GRATIS_PREMIUM_DAYS = 65535; + protected $table = 'accounts'; public $timestamps = false; @@ -33,38 +37,35 @@ class Account extends Model { public function getPremiumDaysAttribute() { - if(isset($this->premium_ends_at) || isset($this->premend)) { - $col = isset($this->premium_ends_at) ? 'premium_ends_at' : 'premend'; - $ret = ceil(($this->{$col}- time()) / (24 * 60 * 60)); - return $ret > 0 ? $ret : 0; + if(isset($this->premium_ends_at) || isset($this->premend) || + (isCanary() && isset($this->lastday))) { + $col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->lastday) ? 'lastday' : 'premend')); + $ret = ceil(($this->{$col} - time()) / (24 * 60 * 60)); + return max($ret, 0); } if($this->premdays == 0) { return 0; } - global $config; - if(isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium'])) return -1; - - if($this->premdays == 65535){ - return 65535; + if($this->premdays == self::GRATIS_PREMIUM_DAYS){ + return self::GRATIS_PREMIUM_DAYS; } $ret = ceil($this->premdays - ((int)date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->lastday))) - date("z", $this->lastday))); return max($ret, 0); } - public function getIsPremiumAttribute() + public function getIsPremiumAttribute(): bool { - global $config; - if(isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium'])) return true; + if(isset($this->premium_ends_at) || isset($this->premend) || + (isCanary() && isset($this->lastday))) { + $col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->lastday) ? 'lastday' : 'premend')); + return $this->{$col} > time(); + } - if(isset($this->premium_ends_at)) { - return $this->premium_ends_at > time(); - } - - if(isset($this->premend)) { - return $this->premend > time(); + if($this->premdays == self::GRATIS_PREMIUM_DAYS){ + return true; } return ($this->premdays - (date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->lastday))) - date("z", $this->lastday)) > 0); diff --git a/system/src/Models/AccountEmailVerify.php b/system/src/Models/AccountEmailVerify.php new file mode 100644 index 00000000..8773750f --- /dev/null +++ b/system/src/Models/AccountEmailVerify.php @@ -0,0 +1,15 @@ +where('hide', '!=', 1); } + + public function player() { + return $this->belongsTo(Player::class); + } } diff --git a/system/src/Models/ForumBoard.php b/system/src/Models/ForumBoard.php new file mode 100644 index 00000000..ee03fde9 --- /dev/null +++ b/system/src/Models/ForumBoard.php @@ -0,0 +1,16 @@ +belongsTo(Player::class); diff --git a/system/src/Models/Visitor.php b/system/src/Models/Visitor.php index 93d5f2be..0c78b0b0 100644 --- a/system/src/Models/Visitor.php +++ b/system/src/Models/Visitor.php @@ -10,6 +10,6 @@ class Visitor extends Model { public $timestamps = false; - protected $fillable = ['ip', 'lastivist', 'page', 'user_agent']; + protected $fillable = ['ip', 'lastvisit', 'page', 'user_agent']; } diff --git a/system/src/Plugins.php b/system/src/Plugins.php index 4acca75e..e1a58620 100644 --- a/system/src/Plugins.php +++ b/system/src/Plugins.php @@ -11,6 +11,25 @@ class Plugins { private static $error = null; private static $plugin_json = []; + public static function getInits() + { + return Cache::remember('plugins_inits', 10 * 60, function () { + $inits = []; + foreach(self::getAllPluginsJson() as $plugin) { + if (!self::getAutoLoadOption($plugin, 'init', false)) { + continue; + } + + $pluginInits = glob(PLUGINS . $plugin['filename'] . '/init.php'); + foreach ($pluginInits as $path) { + $inits[] = $path; + } + } + + return $inits; + }); + } + public static function getAdminPages() { return Cache::remember('plugins_admin_pages', 10 * 60, function () { @@ -346,6 +365,25 @@ class Plugins { } $settings = []; + foreach (self::getAllPluginsJson() as $plugin) { + if (!self::getAutoLoadOption($plugin, 'settings', true)) { + continue; + } + + $settingsFileName = PLUGINS . $plugin['filename'] . '/settings.php'; + if (!is_file($settingsFileName)) { + continue; + } + + $settingsFile = require $settingsFileName; + if (!isset($settingsFile['key'])) { + warning("Settings file for plugin - {$plugin['name']} does not contain 'key' field"); + continue; + } + + $settings[$settingsFile['key']] = ['pluginFilename' => $plugin['filename'], 'settingsFilename' => 'plugins/' . $plugin['filename'] . '/settings.php']; + } + foreach (self::getAllPluginsJson() as $plugin) { if (isset($plugin['settings'])) { $settingsFile = require BASE . $plugin['settings']; @@ -401,8 +439,14 @@ class Plugins { return false; } - if (!isset($plugin_json['settings']) || !file_exists(BASE . $plugin_json['settings'])) { - return false; + $settingsFileName = PLUGINS . $plugin_json['filename'] . '/settings.php'; + if (!is_file($settingsFileName)) { + if (!isset($plugin_json['settings']) || !is_file(BASE . $plugin_json['settings'])) { + return false; + } + } + else { + return 'plugins/' . $plugin_json['filename'] . '/settings.php'; } return $plugin_json['settings']; @@ -432,6 +476,8 @@ class Plugins { return false; } + $plugin_json['filename'] = $filename; + return $plugin_json; } @@ -486,187 +532,192 @@ class Plugins { self::$plugin_json = $plugin_json; if ($plugin_json == null) { self::$warnings[] = 'Cannot load ' . $file_name . '. File might be not a valid json code.'; + return false; } - else { - $continue = true; - if(!isset($plugin_json['name']) || empty(trim($plugin_json['name']))) { - self::$error = 'Plugin "name" tag is not set.'; + $continue = true; + + if(!isset($plugin_json['name']) || empty(trim($plugin_json['name']))) { + self::$error = 'Plugin "name" tag is not set.'; + return false; + } + + if(!isset($plugin_json['version']) || empty(trim($plugin_json['version']))) { + self::$warnings[] = 'Plugin "version" tag is not set.'; + } + + if(isset($plugin_json['require'])) { + $require = $plugin_json['require']; + + $myaac_satified = true; + if(isset($require['myaac_'])) { + $require_myaac = $require['myaac_']; + if(!Semver::satisfies(MYAAC_VERSION, $require_myaac)) { + $myaac_satified = false; + } + } + else if(isset($require['myaac'])) { + $require_myaac = $require['myaac']; + if(version_compare(MYAAC_VERSION, $require_myaac, '<')) { + $myaac_satified = false; + } + } + + if(!$myaac_satified) { + self::$error = "Your AAC version doesn't meet the requirement of this plugin. Required version is: " . $require_myaac . ", and you're using version " . MYAAC_VERSION . "."; return false; } - if(!isset($plugin_json['version']) || empty(trim($plugin_json['version']))) { - self::$warnings[] = 'Plugin "version" tag is not set.'; + $php_satisfied = true; + if(isset($require['php_'])) { + $require_php = $require['php_']; + if(!Semver::satisfies(phpversion(), $require_php)) { + $php_satisfied = false; + } + } + else if(isset($require['php'])) { + $require_php = $require['php']; + if(version_compare(phpversion(), $require_php, '<')) { + $php_satisfied = false; + } } - if(isset($plugin_json['require'])) { - $require = $plugin_json['require']; + if(!$php_satisfied) { + self::$error = "Your PHP version doesn't meet the requirement of this plugin. Required version is: " . $require_php . ", and you're using version " . phpversion() . "."; + $continue = false; + } - $myaac_satified = true; - if(isset($require['myaac_'])) { - $require_myaac = $require['myaac_']; - if(!Semver::satisfies(MYAAC_VERSION, $require_myaac)) { - $myaac_satified = false; + $database_satisfied = true; + if(isset($require['database_'])) { + $require_database = $require['database_']; + if(!Semver::satisfies(DATABASE_VERSION, $require_database)) { + $database_satisfied = false; + } + } + else if(isset($require['database'])) { + $require_database = $require['database']; + if(version_compare(DATABASE_VERSION, $require_database, '<')) { + $database_satisfied = false; + } + } + + if(!$database_satisfied) { + self::$error = "Your database version doesn't meet the requirement of this plugin. Required version is: " . $require_database . ", and you're using version " . DATABASE_VERSION . "."; + $continue = false; + } + + if($continue) { + foreach($require as $req => $version) { + $req = strtolower(trim($req)); + $version = trim($version); + + if(in_array($req, array('myaac', 'myaac_', 'php', 'php_', 'database', 'database_'))) { + continue; } - } - else if(isset($require['myaac'])) { - $require_myaac = $require['myaac']; - if(version_compare(MYAAC_VERSION, $require_myaac, '<')) { - $myaac_satified = false; - } - } - if(!$myaac_satified) { - self::$error = "Your AAC version doesn't meet the requirement of this plugin. Required version is: " . $require_myaac . ", and you're using version " . MYAAC_VERSION . "."; - return false; - } + if(in_array($req, array('php-ext', 'php-extension'))) { // require php extension + $tmpDisplayError = false; + $explode = explode(',', $version); - $php_satisfied = true; - if(isset($require['php_'])) { - $require_php = $require['php_']; - if(!Semver::satisfies(phpversion(), $require_php)) { - $php_satisfied = false; - } - } - else if(isset($require['php'])) { - $require_php = $require['php']; - if(version_compare(phpversion(), $require_php, '<')) { - $php_satisfied = false; - } - } - - if(!$php_satisfied) { - self::$error = "Your PHP version doesn't meet the requirement of this plugin. Required version is: " . $require_php . ", and you're using version " . phpversion() . "."; - $continue = false; - } - - $database_satisfied = true; - if(isset($require['database_'])) { - $require_database = $require['database_']; - if(!Semver::satisfies(DATABASE_VERSION, $require_database)) { - $database_satisfied = false; - } - } - else if(isset($require['database'])) { - $require_database = $require['database']; - if(version_compare(DATABASE_VERSION, $require_database, '<')) { - $database_satisfied = false; - } - } - - if(!$database_satisfied) { - self::$error = "Your database version doesn't meet the requirement of this plugin. Required version is: " . $require_database . ", and you're using version " . DATABASE_VERSION . "."; - $continue = false; - } - - if($continue) { - foreach($require as $req => $version) { - $req = strtolower(trim($req)); - $version = trim($version); - - if(in_array($req, array('myaac', 'myaac_', 'php', 'php_', 'database', 'database_'))) { - continue; + foreach ($explode as $item) { + if(!extension_loaded($item)) { + $errors[] = "This plugin requires php extension: " . $item . " to be installed."; + $tmpDisplayError = true; + } } - if(in_array($req, array('php-ext', 'php-extension'))) { // require php extension - $tmpDisplayError = false; - $explode = explode(',', $version); - - foreach ($explode as $item) { - if(!extension_loaded($item)) { - $errors[] = "This plugin requires php extension: " . $item . " to be installed."; - $tmpDisplayError = true; - } - } - - if ($tmpDisplayError) { - self::$error = implode('
    ', $errors); - $continue = false; - break; - } - } - else if($req == 'table') { - $tmpDisplayError = false; - $explode = explode(',', $version); - foreach ($explode as $item) { - if(!$db->hasTable($item)) { - $errors[] = "This plugin requires table: " . $item . " to exist in the database."; - $tmpDisplayError = true; - } - } - - if ($tmpDisplayError) { - self::$error = implode('
    ', $errors); - $continue = false; - break; - } - } - else if($req == 'column') { - $tmpDisplayError = false; - $explode = explode(',', $version); - foreach ($explode as $item) { - $tmp = explode('.', $item); - - if(count($tmp) == 2) { - if(!$db->hasColumn($tmp[0], $tmp[1])) { - $errors[] = "This plugin requires database column: " . $tmp[0] . "." . $tmp[1] . " to exist in database."; - $tmpDisplayError = true; - } - } - else { - self::$warnings[] = "Invalid plugin require column: " . $item; - } - } - - if ($tmpDisplayError) { - self::$error = implode('
    ', $errors); - $continue = false; - break; - } - } - else if(strpos($req, 'ext-') !== false) { - $tmp = explode('-', $req); - if(count($tmp) == 2) { - if(!extension_loaded($tmp[1]) || !Semver::satisfies(phpversion($tmp[1]), $version)) { - self::$error = "This plugin requires php extension: " . $tmp[1] . ", version " . $version . " to be installed."; - $continue = false; - break; - } - } - } - else if(!self::is_installed($req, $version)) { - self::$error = "This plugin requires another plugin to run correctly. The another plugin is: " . $req . ", with version " . $version . "."; + if ($tmpDisplayError) { + self::$error = implode('
    ', $errors); $continue = false; break; } } - } - } + else if($req == 'table') { + $tmpDisplayError = false; + $explode = explode(',', $version); + foreach ($explode as $item) { + if(!$db->hasTable($item)) { + $errors[] = "This plugin requires table: " . $item . " to exist in the database."; + $tmpDisplayError = true; + } + } - if($continue) { - if(!$zip->extractTo(BASE)) { // "Real" Install - self::$error = 'There was a problem with extracting zip archive to base directory.'; - $zip->close(); - return false; - } - - if (isset($plugin_json['install'])) { - if (file_exists(BASE . $plugin_json['install'])) { - $db->revalidateCache(); - require BASE . $plugin_json['install']; - $db->revalidateCache(); + if ($tmpDisplayError) { + self::$error = implode('
    ', $errors); + $continue = false; + break; + } + } + else if($req == 'column') { + $tmpDisplayError = false; + $explode = explode(',', $version); + foreach ($explode as $item) { + $tmp = explode('.', $item); + + if(count($tmp) == 2) { + if(!$db->hasColumn($tmp[0], $tmp[1])) { + $errors[] = "This plugin requires database column: " . $tmp[0] . "." . $tmp[1] . " to exist in database."; + $tmpDisplayError = true; + } + } + else { + self::$warnings[] = "Invalid plugin require column: " . $item; + } + } + + if ($tmpDisplayError) { + self::$error = implode('
    ', $errors); + $continue = false; + break; + } + } + else if(strpos($req, 'ext-') !== false) { + $tmp = explode('-', $req); + if(count($tmp) == 2) { + if(!extension_loaded($tmp[1]) || !Semver::satisfies(phpversion($tmp[1]), $version)) { + self::$error = "This plugin requires php extension: " . $tmp[1] . ", version " . $version . " to be installed."; + $continue = false; + break; + } + } + } + else if(!self::is_installed($req, $version)) { + self::$error = "This plugin requires another plugin to run correctly. The another plugin is: " . $req . ", with version " . $version . "."; + $continue = false; + break; } - else - self::$warnings[] = 'Cannot load install script. Your plugin might be not working correctly.'; } - - clearCache(); - - return true; } } - return false; + if(!$continue) { + return false; + } + + if(!$zip->extractTo(BASE)) { // "Real" Install + self::$error = 'There was a problem with extracting zip archive to base directory.'; + $zip->close(); + return false; + } + + $install = $plugin_json['install'] ?? ''; + if (self::getAutoLoadOption($plugin_json, 'install', true) && is_file(PLUGINS . $pluginFilename . '/install.php')) { + $install = 'plugins/' . $pluginFilename . '/install.php'; + } + + if (!empty($install)) { + if (file_exists(BASE . $install)) { + $db->revalidateCache(); + require BASE . $install; + $db->revalidateCache(); + } + else { + self::$warnings[] = 'Cannot load install script. Your plugin might be not working correctly.'; + } + } + + clearCache(); + return true; } public static function isEnabled($pluginFileName): bool @@ -729,15 +780,20 @@ class Plugins { return false; } - if(!isset($plugin_json['install'])) { - self::$error = "Plugin doesn't have install options defined. Skipping..."; + $install = $plugin_json['install'] ?? ''; + if (self::getAutoLoadOption($plugin_json, 'install', true) && is_file(PLUGINS . $plugin_name . '/install.php')) { + $install = 'plugins/' . $plugin_name . '/install.php'; + } + + if (empty($install)) { + self::$error = "This plugin doesn't seem to have install script defined."; return false; } global $db; - if (file_exists(BASE . $plugin_json['install'])) { + if (file_exists(BASE . $install)) { $db->revalidateCache(); - require BASE . $plugin_json['install']; + require BASE . $install; $db->revalidateCache(); } else { diff --git a/system/src/Settings.php b/system/src/Settings.php index 0df8fa81..ec4a83fa 100644 --- a/system/src/Settings.php +++ b/system/src/Settings.php @@ -7,16 +7,13 @@ use MyAAC\Models\Settings as ModelsSettings; class Settings implements \ArrayAccess { - static private $instance; - private $settingsFile = []; - private $settingsDatabase = []; - private $cache = []; - private $valuesAsked = []; - private $errors = []; + static private ?Settings $instance = null; + private array $settingsFile = []; + private array $settingsDatabase = []; + private array $cache = []; + private array $valuesAsked = []; + private array $errors = []; - /** - * @return Settings - */ public static function getInstance(): Settings { if (!self::$instance) { @@ -26,28 +23,21 @@ class Settings implements \ArrayAccess return self::$instance; } - public function load() + public function load(): void { - $cache = Cache::getInstance(); - if ($cache->enabled()) { - $tmp = ''; - if ($cache->fetch('settings', $tmp)) { - $this->settingsDatabase = unserialize($tmp); - return; + $this->settingsDatabase = Cache::remember('settings', 10 * 60, function () { + $settingsDatabase = []; + + $settings = ModelsSettings::all(); + foreach ($settings as $setting) { + $settingsDatabase[$setting->name][$setting->key] = $setting->value; } - } - $settings = ModelsSettings::all(); - foreach ($settings as $setting) { - $this->settingsDatabase[$setting->name][$setting->key] = $setting->value; - } - - if ($cache->enabled()) { - $cache->set('settings', serialize($this->settingsDatabase), 600); - } + return $settingsDatabase; + }); } - public function save($pluginName, $values) + public function save($pluginName, $values): bool { $this->loadPlugin($pluginName); @@ -104,7 +94,7 @@ class Settings implements \ArrayAccess return true; } - public function updateInDatabase($pluginName, $key, $value) + public function updateInDatabase($pluginName, $key, $value): void { if (ModelsSettings::where(['name' => $pluginName, 'key' => $key])->exists()) { ModelsSettings::where(['name' => $pluginName, 'key' => $key])->update(['value' => $value]); @@ -117,7 +107,7 @@ class Settings implements \ArrayAccess $this->clearCache(); } - public function deleteFromDatabase($pluginName, $key = null) + public function deleteFromDatabase($pluginName, $key = null): void { if (!isset($key)) { ModelsSettings::where('name', $pluginName)->delete(); @@ -217,7 +207,7 @@ class Settings implements \ArrayAccess if (isset($setting['hidden']) && $setting['hidden']) { $value = ''; if ($setting['type'] === 'boolean') { - $value = ($setting['default'] ? 'true' : 'false'); + $value = (getBoolean($setting['default']) ? 'true' : 'false'); } else if (in_array($setting['type'], ['text', 'number', 'float', 'double', 'email', 'password', 'textarea'])) { $value = $setting['default']; @@ -230,12 +220,7 @@ class Settings implements \ArrayAccess } else if ($setting['type'] === 'boolean') { if(isset($settingsDb[$key])) { - if($settingsDb[$key] === 'true') { - $value = true; - } - else { - $value = false; - } + $value = getBoolean($settingsDb[$key]); } else { $value = ($setting['default'] ?? false); @@ -383,7 +368,7 @@ class Settings implements \ArrayAccess } #[\ReturnTypeWillChange] - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if (is_null($offset)) { throw new \RuntimeException("Settings: You cannot set empty offset with value: $value!"); @@ -423,7 +408,7 @@ class Settings implements \ArrayAccess } #[\ReturnTypeWillChange] - public function offsetUnset($offset) + public function offsetUnset($offset): void { $this->loadPlugin($offset); @@ -455,7 +440,7 @@ class Settings implements \ArrayAccess * @return array|mixed */ #[\ReturnTypeWillChange] - public function offsetGet($offset) + public function offsetGet($offset): mixed { // try cache hit if(isset($this->cache[$offset])) { @@ -472,24 +457,22 @@ class Settings implements \ArrayAccess if (!isset($this->settingsFile[$pluginKeyName]['settings'])) { throw new \RuntimeException('Unknown plugin settings: ' . $pluginKeyName); } + return $this->settingsFile[$pluginKeyName]['settings']; } - $ret = []; - if(isset($this->settingsFile[$pluginKeyName]['settings'][$key])) { - $ret = $this->settingsFile[$pluginKeyName]['settings'][$key]; + if (!isset($this->settingsFile[$pluginKeyName]['settings'][$key])) { + return null; } + $ret = $this->settingsFile[$pluginKeyName]['settings'][$key]; + if(isset($this->settingsDatabase[$pluginKeyName][$key])) { $value = $this->settingsDatabase[$pluginKeyName][$key]; $ret['value'] = $value; } else { - if (!isset($this->settingsFile[$pluginKeyName]['settings'][$key])) { - return null; - } - $ret['value'] = $this->settingsFile[$pluginKeyName]['settings'][$key]['default']; } @@ -523,7 +506,7 @@ class Settings implements \ArrayAccess return $ret; } - private function updateValuesAsked($offset) + private function updateValuesAsked($offset): void { $pluginKeyName = $offset; if (strpos($offset, '.')) { @@ -539,7 +522,7 @@ class Settings implements \ArrayAccess } } - private function loadPlugin($offset) + private function loadPlugin($offset): void { $this->updateValuesAsked($offset); @@ -560,15 +543,15 @@ class Settings implements \ArrayAccess $settingsFilePath = BASE . $settings[$pluginKeyName]['settingsFilename']; } - if (!file_exists($settingsFilePath)) { - throw new \RuntimeException('Failed to load settings file for plugin: ' . $pluginKeyName); + if (!is_file($settingsFilePath)) { + throw new \RuntimeException('Failed to load settings file for plugin: ' . $pluginKeyName . ' (Tried: ' . $settingsFilePath . ')'); } $this->settingsFile[$pluginKeyName] = require $settingsFilePath; } } - public static function saveConfig($config, $filename, &$content = '') + public static function saveConfig($config, $filename, &$content = ''): bool|int { $content = "setTimeout(setting('core.status_timeout')); + $serverStatus = $serverInfo->status(); if(!$serverStatus) { diff --git a/system/template.php b/system/template.php index f051e640..30cb5535 100644 --- a/system/template.php +++ b/system/template.php @@ -91,7 +91,7 @@ else { $file = BASE . $template_path . '/layout_config.ini'; } - $template_ini = parse_ini_file($file); + $template_ini = parse_ini_file($file, true); unset($file); if ($cache->enabled()) { @@ -148,7 +148,7 @@ function get_template_menus(): array { global $template_name; - $result = Cache::remember('template_menus', 10 * 60, function () use ($template_name) { + $result = Cache::remember('template_menus_' . $template_name, 10 * 60, function () use ($template_name) { $result = Menu::select(['name', 'link', 'blank', 'color', 'category']) ->where('template', $template_name) ->orderBy('category') diff --git a/system/templates/account.change-email.html.twig b/system/templates/account.change-email.html.twig index ea627cc7..ab2a8c06 100644 --- a/system/templates/account.change-email.html.twig +++ b/system/templates/account.change-email.html.twig @@ -28,7 +28,7 @@ Please enter your password and the new email address. Make sure that you enter a
  • - diff --git a/system/templates/account.change-password.html.twig b/system/templates/account.change-password.html.twig index 318d393f..03f82d9b 100644 --- a/system/templates/account.change-password.html.twig +++ b/system/templates/account.change-password.html.twig @@ -9,23 +9,29 @@ Please enter your current password and a new password. For your security, please Current Password: + + {{ hook('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_OLD_PASSWORD') }} + + + {{ hook('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_NEW_PASSWORD') }} +
    +
    {{ csrf() }} @@ -40,14 +40,14 @@ Please enter your password and the new email address. Make sure that you enter a
    - - {{ csrf() }} - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.back.html.twig') }} -
    - +
    New Password: - +
    New Password Again: - +
    @@ -37,7 +43,7 @@ Please enter your current password and a new password. For your security, please
    -
    +
    {{ csrf() }} {{ include('buttons.submit.html.twig') }} diff --git a/system/templates/account.characters.change-comment.html.twig b/system/templates/account.characters.change-comment.html.twig index 8bb94c80..ab8fb384 100644 --- a/system/templates/account.characters.change-comment.html.twig +++ b/system/templates/account.characters.change-comment.html.twig @@ -88,7 +88,7 @@ If you do not want to specify a certain field, just leave it blank.

    - + +
    + {{ include('buttons.submit.html.twig') }} @@ -99,15 +99,15 @@ If you do not want to specify a certain field, just leave it blank.

    - - {{ csrf() }} - - + - - -
    +
    + + {{ csrf() }} {{ include('buttons.back.html.twig') }} -
    + +
    diff --git a/system/templates/account.characters.change-name.html.twig b/system/templates/account.characters.change-name.html.twig index 7c0d18f3..7a0cfe22 100644 --- a/system/templates/account.characters.change-name.html.twig +++ b/system/templates/account.characters.change-name.html.twig @@ -35,7 +35,7 @@ To change a name of character select player and choose a new name.
    -
    +
    {{ csrf() }} @@ -48,7 +48,7 @@ To change a name of character select player and choose a new name.
    -
    + {{ csrf() }} {{ include('buttons.back.html.twig') }} diff --git a/system/templates/account.characters.delete.html.twig b/system/templates/account.characters.delete.html.twig index 8593f7ed..b946d221 100644 --- a/system/templates/account.characters.delete.html.twig +++ b/system/templates/account.characters.delete.html.twig @@ -24,7 +24,7 @@ To delete a character enter the name of the character and your password.

    - diff --git a/system/templates/account.generate_recovery_key.html.twig b/system/templates/account.generate_recovery_key.html.twig index 29ed1ec5..526d4659 100644 --- a/system/templates/account.generate_recovery_key.html.twig +++ b/system/templates/account.generate_recovery_key.html.twig @@ -32,14 +32,14 @@ To generate recovery key for your account please enter your password.

    diff --git a/system/templates/account.login.html.twig b/system/templates/account.login.html.twig index fe52d7f9..a264e488 100644 --- a/system/templates/account.login.html.twig +++ b/system/templates/account.login.html.twig @@ -2,9 +2,11 @@ Please enter your account {{ account|lower }} and your password.
    Create an account if you do not have one yet.

    {{ csrf() }} + {% if redirect is not null %} {% endif %} +
    + {{ csrf() }} @@ -36,14 +36,14 @@ To delete a character enter the name of the character and your password.

    - - {{ csrf() }} - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.back.html.twig') }} -
    - - {{ csrf() }} - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.back.html.twig') }} -
    @@ -64,7 +66,7 @@ Please enter your account {{ account|lower }} and your password.
    - @@ -73,7 +75,7 @@ Please enter your account {{ account|lower }} and your password.
    -
    + {{ include('buttons.submit.html.twig') }}
    + {{ include('buttons.account_lost.html.twig') }} diff --git a/system/templates/account.management.html.twig b/system/templates/account.management.html.twig index 2db1e57c..03e2c2a6 100644 --- a/system/templates/account.management.html.twig +++ b/system/templates/account.management.html.twig @@ -228,5 +228,7 @@
    +
    + {{ hook('HOOK_ACCOUNT_MANAGE_AFTER_CHARACTERS') }} diff --git a/system/templates/account.resend-email-verify.html.twig b/system/templates/account.resend-email-verify.html.twig new file mode 100644 index 00000000..7dd9cc98 --- /dev/null +++ b/system/templates/account.resend-email-verify.html.twig @@ -0,0 +1,45 @@ +Please enter your account Email address.

    +{% set title = 'Resend Email' %} +{% set background = config('darkborder') %} +{% set content %} + + + + + +
    + + + +
    +{% endset %} +{% include 'tables.headline.html.twig' %} +
    + + + + + +
    + + + + +
    + + {{ csrf() }} + + {{ include('buttons.submit.html.twig') }} + +
    +
    + + + + +
    +
    + {{ include('buttons.back.html.twig') }} +
    +
    +
    diff --git a/system/templates/admin.mailer.html.twig b/system/templates/admin.mailer.html.twig index 0b77ccb3..1dd2eb30 100644 --- a/system/templates/admin.mailer.html.twig +++ b/system/templates/admin.mailer.html.twig @@ -16,6 +16,13 @@ + {% if setting('core.account_mail_verify') %} +
    + + +
    + {% endif %} +
    diff --git a/system/templates/admin.plugins.form.html.twig b/system/templates/admin.plugins.form.html.twig index aec82a8a..f8eddd41 100644 --- a/system/templates/admin.plugins.form.html.twig +++ b/system/templates/admin.plugins.form.html.twig @@ -1,7 +1,9 @@
    {{ csrf() }} diff --git a/system/templates/admin.plugins.outdated.html.twig b/system/templates/admin.plugins.outdated.html.twig new file mode 100644 index 00000000..95421edc --- /dev/null +++ b/system/templates/admin.plugins.outdated.html.twig @@ -0,0 +1,18 @@ + + + + + + + + + + {% for plugin in plugins %} + + + + + + + {% endfor %} +
    Plugin NameYour VersionLatest VersionDownload Link
    {{ plugin.name }}{{ plugin.yourVersion }}{{ plugin.latestVersion }}{{ plugin.download_link }}
    diff --git a/system/templates/characters.form.html.twig b/system/templates/characters.form.html.twig index d731b4e2..0fd85608 100644 --- a/system/templates/characters.form.html.twig +++ b/system/templates/characters.form.html.twig @@ -1,17 +1,23 @@ - - - - - - -
    Search Character
    - - - - - -
    Name: - {{ include('buttons.submit.html.twig') }} -
    -
    -
    \ No newline at end of file +
    +
    + {% set title = 'Search Character' %} + {% set tableClass = 'Table1' %} + {% set background = config('darkborder') %} + {% set content %} + + + + + + +
    + Character Name: + + + + {% set button_name = 'Submit' %} + {{ include('buttons.base.html.twig') }} +
    + {% endset %} + {{ include('tables.headline.html.twig') }} +
    diff --git a/system/templates/characters.html.twig b/system/templates/characters.html.twig index 2e09bd26..75e15b68 100644 --- a/system/templates/characters.html.twig +++ b/system/templates/characters.html.twig @@ -9,7 +9,7 @@
    - {{ hook(constant('HOOK_CHARACTERS_BEFORE_INFORMATIONS')) }} + {{ hook('HOOK_CHARACTERS_BEFORE_INFORMATIONS') }} {% if canEdit %} Edit @@ -153,11 +153,11 @@ {% if account.isPremium() %}Premium Account{% else %}Free Account{% endif %}
    - {{ hook(constant('HOOK_CHARACTERS_AFTER_INFORMATIONS')) }} + {{ hook('HOOK_CHARACTERS_AFTER_INFORMATIONS') }}
    - {{ hook(constant('HOOK_CHARACTERS_BEFORE_SKILLS')) }} + {{ hook('HOOK_CHARACTERS_BEFORE_SKILLS') }} {% if config.characters.skills %} @@ -179,7 +179,7 @@ {% endif %} - {{ hook(constant('HOOK_CHARACTERS_AFTER_SKILLS')) }} + {{ hook('HOOK_CHARACTERS_AFTER_SKILLS') }} {% if quests_enabled %} @@ -201,7 +201,7 @@ {% endif %} - {{ hook(constant('HOOK_CHARACTERS_AFTER_QUESTS')) }} + {{ hook('HOOK_CHARACTERS_AFTER_QUESTS') }} {% if config.characters.equipment %} @@ -239,11 +239,11 @@ {% endif %} - {{ hook(constant('HOOK_CHARACTERS_AFTER_EQUIPMENT')) }} + {{ hook('HOOK_CHARACTERS_AFTER_EQUIPMENT') }}
    - {{ hook(constant('HOOK_CHARACTERS_BEFORE_DEATHS')) }} + {{ hook('HOOK_CHARACTERS_BEFORE_DEATHS') }} {% if deaths|length > 0 %} @@ -283,7 +283,7 @@ {% endif %} - {{ hook(constant('HOOK_CHARACTERS_BEFORE_SIGNATURE')) }} + {{ hook('HOOK_CHARACTERS_BEFORE_SIGNATURE') }} {% if setting('core.signature_enabled') %} @@ -327,7 +327,7 @@
    {% endif %} - {{ hook(constant('HOOK_CHARACTERS_AFTER_SIGNATURE')) }} + {{ hook('HOOK_CHARACTERS_AFTER_SIGNATURE') }} {% if not player.isHidden() %} {% set rows = 0 %} @@ -377,7 +377,7 @@
    - {{ hook(constant('HOOK_CHARACTERS_AFTER_ACCOUNT')) }} + {{ hook('HOOK_CHARACTERS_AFTER_ACCOUNT') }}

    @@ -421,7 +421,7 @@
    {% endif %} - {{ hook(constant('HOOK_CHARACTERS_AFTER_CHARACTERS')) }} + {{ hook('HOOK_CHARACTERS_AFTER_CHARACTERS') }} {% if canEdit %} Edit diff --git a/system/templates/error_box.html.twig b/system/templates/error_box.html.twig index e6ed4992..ba9a2263 100644 --- a/system/templates/error_box.html.twig +++ b/system/templates/error_box.html.twig @@ -9,7 +9,7 @@
    The Following Errors Have Occurred:
    {% for error in errors %} -
  • {{ error|striptags('')|raw }}
  • +
  • {{ error|striptags('')|raw }}
  • {% endfor %}
    @@ -17,4 +17,4 @@
    -
    \ No newline at end of file +
    diff --git a/system/templates/forum.admin.links.html.twig b/system/templates/forum.admin.links.html.twig new file mode 100644 index 00000000..2449e616 --- /dev/null +++ b/system/templates/forum.admin.links.html.twig @@ -0,0 +1,43 @@ + + + + +
    +
    + {{ csrf() }} + + + +
    + +
    + {{ csrf() }} + + + +
    + +
    + {{ csrf() }} + + + +
    + + {% if i != 1 %} +
    + {{ csrf() }} + + + +
    + {% endif %} + {% if i != loop.last %} +
    + {{ csrf() }} + + + +
    + {% endif %} +
    diff --git a/system/templates/forum.boards.html.twig b/system/templates/forum.boards.html.twig index 5ac3e88b..aa2772f9 100644 --- a/system/templates/forum.boards.html.twig +++ b/system/templates/forum.boards.html.twig @@ -39,25 +39,7 @@
    - - Edit - - - Delete - - - {% if board.hide != 1 %}Hide{% else %}Show{% endif %} - - {% if i != 1 %} - - Move up - - {% endif %} - {% if i != last %} - - Move down - - {% endif %} + {{ include('forum.admin.links.html.twig', {id: board.id, hide: board.hide, i: i }) }}
    diff --git a/system/templates/forum.new_thread.html.twig b/system/templates/forum.new_thread.html.twig index 3b5e080d..e37bda08 100644 --- a/system/templates/forum.new_thread.html.twig +++ b/system/templates/forum.new_thread.html.twig @@ -1,4 +1,4 @@ - + {{ csrf() }} diff --git a/system/templates/forum.remove_post.html.twig b/system/templates/forum.remove_post.html.twig new file mode 100644 index 00000000..85684e41 --- /dev/null +++ b/system/templates/forum.remove_post.html.twig @@ -0,0 +1,12 @@ + + {{ csrf() }} + + + + diff --git a/system/templates/forum.show_thread.html.twig b/system/templates/forum.show_thread.html.twig index 2626c2de..71812be7 100644 --- a/system/templates/forum.show_thread.html.twig +++ b/system/templates/forum.show_thread.html.twig @@ -53,15 +53,16 @@ Page: {{ links_to_pages|raw }}
    + {% if setting('core.highscores_skills_box') or setting('core.highscores_vocation_box') %} - - -
    -
    + + {{ csrf() }} @@ -25,7 +26,6 @@
    - {{ csrf() }}
    {% if is_moderator %} {% if post.first_post != post.id %} - + {{ include('forum.remove_post.html.twig') }} {% else %} - + {{ include('forum.remove_post.html.twig') }} {% endif %} {% endif %} {% if logged and (post.player.getAccount().getId() == account_logged.getId() or is_moderator) %} - + + {% endif %} {% if logged %} diff --git a/system/templates/guilds.accept_invite.html.twig b/system/templates/guilds.accept_invite.html.twig index 0c2d0dc3..7a3acff5 100644 --- a/system/templates/guilds.accept_invite.html.twig +++ b/system/templates/guilds.accept_invite.html.twig @@ -7,12 +7,15 @@
    -
    + {{ csrf() }} + + + {% set i = 0 %} {% for player in invited_players %} - - {% set i = i + 1 %} + + {% set i = i + 1 %} {% endfor %} {{ include('buttons.submit.html.twig') }}
    diff --git a/system/templates/guilds.change_description.html.twig b/system/templates/guilds.change_description.html.twig index 9c656920..33b1db84 100644 --- a/system/templates/guilds.change_description.html.twig +++ b/system/templates/guilds.change_description.html.twig @@ -5,7 +5,7 @@
    Here you can change description of your guild.
    -
    + {{ csrf() }}
    diff --git a/system/templates/guilds.change_logo.html.twig b/system/templates/guilds.change_logo.html.twig index 13813e9b..5cdc8eda 100644 --- a/system/templates/guilds.change_logo.html.twig +++ b/system/templates/guilds.change_logo.html.twig @@ -8,7 +8,7 @@ {{ csrf() }} - + Select new logo:
    diff --git a/system/templates/guilds.change_motd.html.twig b/system/templates/guilds.change_motd.html.twig index 4313c4c9..e827a4ac 100644 --- a/system/templates/guilds.change_motd.html.twig +++ b/system/templates/guilds.change_motd.html.twig @@ -5,7 +5,7 @@
    Here you can change MOTD (Message of the Day, showed in game!) of your guild.
    -
    + {{ csrf() }}
    diff --git a/system/templates/guilds.change_rank.html.twig b/system/templates/guilds.change_rank.html.twig index 13ad7cf4..bbeb4602 100644 --- a/system/templates/guilds.change_rank.html.twig +++ b/system/templates/guilds.change_rank.html.twig @@ -1,5 +1,6 @@ - + {{ csrf() }} + diff --git a/system/templates/guilds.create.html.twig b/system/templates/guilds.create.html.twig index c2326416..1f016567 100644 --- a/system/templates/guilds.create.html.twig +++ b/system/templates/guilds.create.html.twig @@ -1,5 +1,6 @@ - + {{ csrf() }} +
    Change Rank
    diff --git a/system/templates/guilds.delete_invite.html.twig b/system/templates/guilds.delete_invite.html.twig index 012f7d46..7367ccf2 100644 --- a/system/templates/guilds.delete_invite.html.twig +++ b/system/templates/guilds.delete_invite.html.twig @@ -7,9 +7,10 @@
    Create a {{ config.lua.serverName }} Guild
    diff --git a/system/templates/guilds.invite.html.twig b/system/templates/guilds.invite.html.twig index b0a35ac7..ee6af769 100644 --- a/system/templates/guilds.invite.html.twig +++ b/system/templates/guilds.invite.html.twig @@ -1,5 +1,6 @@ - + {{ csrf() }} + Invite player with name:       {{ include('buttons.submit.html.twig') }} diff --git a/system/templates/guilds.kick_player.html.twig b/system/templates/guilds.kick_player.html.twig index ded31cc8..521631c2 100644 --- a/system/templates/guilds.kick_player.html.twig +++ b/system/templates/guilds.kick_player.html.twig @@ -7,8 +7,9 @@
    - - {{ csrf() }} - {{ include('buttons.submit.html.twig') }} + + {{ csrf() }} + + {{ include('buttons.submit.html.twig') }}
    diff --git a/system/templates/guilds.leave_guild.html.twig b/system/templates/guilds.leave_guild.html.twig index 86642156..4d865cef 100644 --- a/system/templates/guilds.leave_guild.html.twig +++ b/system/templates/guilds.leave_guild.html.twig @@ -1,5 +1,6 @@ - + {{ csrf() }} +
    -
    + {{ csrf() }} + {{ include('buttons.submit.html.twig') }}
    diff --git a/system/templates/guilds.manager.html.twig b/system/templates/guilds.manager.html.twig index c932ce2b..adebdff2 100644 --- a/system/templates/guilds.manager.html.twig +++ b/system/templates/guilds.manager.html.twig @@ -101,7 +101,12 @@ Here you can change names of ranks, delete and add ranks, pass leadership to oth {% set i = 0 %} {% for rank in rank_list %} - @@ -61,6 +62,7 @@ {{ hook('HOOK_GUILDS_AFTER_GUILD_INFORMATION') }} {% set title = 'Guild Members' %} + {% set background = config('lightborder') %} {% set content %}
    Leave guild
    {{ rank.getId() }} // Delete Rank + {{ rank.getId() }} // + + {{ csrf() }} + + + diff --git a/system/templates/guilds.view.html.twig b/system/templates/guilds.view.html.twig index a25d9570..33dc1d3d 100644 --- a/system/templates/guilds.view.html.twig +++ b/system/templates/guilds.view.html.twig @@ -49,6 +49,7 @@ {% include('buttons.base.html.twig') %} {% endif %} + {{ hook('HOOK_GUILDS_AFTER_MANAGE_BUTTON') }}
    @@ -151,6 +153,7 @@ {{ hook('HOOK_GUILDS_AFTER_GUILD_MEMBERS') }} {% set title = 'Invited Characters' %} + {% set background = config('lightborder') %} {% set content %}
    @@ -232,14 +235,16 @@ {% endif %} {% if isVice %} - - {{ csrf() }} - - + {% if db.hasTableAndColumns('guild_invites', ['player_id']) %} + + {{ csrf() }} + + + {% endif %} {{ csrf() }} diff --git a/system/templates/highscores.html.twig b/system/templates/highscores.html.twig index 86599b90..88bf579b 100644 --- a/system/templates/highscores.html.twig +++ b/system/templates/highscores.html.twig @@ -66,7 +66,7 @@
    - {% set button_name = 'Invite Character' %} - {% set button_image = '_sbutton_invitecharacter' %} - {% include('buttons.base.html.twig') %} -
    + {% set button_name = 'Invite Character' %} + {% set button_image = '_sbutton_invitecharacter' %} + {% include('buttons.base.html.twig') %} +
    - {{ player.name }} + {{ player.name }} {% if setting('core.highscores_vocation') %}
    {{ player.vocation }} @@ -94,8 +94,10 @@ {% endif %}
    + {% if setting('core.highscores_skills_box') %} @@ -109,7 +111,8 @@
    Choose a skill

    - {% if config.highscores_vocation_box %} + {% endif %} + {% if setting('core.highscores_vocation_box') %} @@ -126,5 +129,6 @@ {% endif %} + {% endif %}
    Choose a vocation
    diff --git a/system/templates/install.config.html.twig b/system/templates/install.config.html.twig index ab4fc361..8c0aa50a 100644 --- a/system/templates/install.config.html.twig +++ b/system/templates/install.config.html.twig @@ -9,7 +9,7 @@ - {% for value in ['server_path'] %} + {% for value in ['site_url', 'server_path'] %}
    diff --git a/system/templates/mail.account.resend-email-verify.html.twig b/system/templates/mail.account.resend-email-verify.html.twig new file mode 100644 index 00000000..75bdab8b --- /dev/null +++ b/system/templates/mail.account.resend-email-verify.html.twig @@ -0,0 +1,7 @@ +Hello {{ account }}!
    +
    +You requested to resend the verify Email on {{ config.lua.serverName }}!
    +
    + +To verify your email address please click the link below:
    +{{ verify_url|raw }} diff --git a/system/templates/online.form.html.twig b/system/templates/online.form.html.twig deleted file mode 100644 index 82c6f7b2..00000000 --- a/system/templates/online.form.html.twig +++ /dev/null @@ -1,25 +0,0 @@ -
    - - - - - - - - -
    - Search Character -
    - - - - - - -
    Name: - - - {{ include('buttons.submit.html.twig') }} -
    -
    - \ No newline at end of file diff --git a/system/templates/online.html.twig b/system/templates/online.html.twig index 0210d80f..6f798740 100644 --- a/system/templates/online.html.twig +++ b/system/templates/online.html.twig @@ -1,39 +1,13 @@ - - - - -{% if players|length == 0 %} -
    Server Status
    Currently no one is playing on {{ config.lua.serverName }}.
    -{% else %} -
    - {% if not status.online %} - Server is offline.
    - {% else %} - {% if setting('core.online_afk') %} - {% set players_count = players|length %} - {% set afk = players_count - status.players %} - {% if afk < 0 %} - {% set players_count = players_count + afk|abs %} - {% set afk = 0 %} - {% endif %} - Currently there are {{ status.players }} active and {{ afk }} AFK players.
    - Total number of players: {{ players_count }}.
    - {% else %} - Currently {{ players|length }} players are online.
    - {% endif %} - {% endif %} - {% if setting('core.online_record') %} - {{ record }} - {% endif %} -
    +{% set onlineTTL = setting('core.online_cache_ttl') %} +{% if onlineTTL > 0 and cache.enabled() %} +*Note: Online List is updated every {{ onlineTTL > 1 ? ' ' ~ onlineTTL : '' }} minute{{ onlineTTL > 1 ? 's' : '' }}.
    - {# vocation statistics #} - {% if setting('core.online_vocations') %} +{% endif %} + +{# vocation statistics #} +{% if setting('core.online_vocations') %}
    - {% if setting('core.online_vocations_images') %} + {% if setting('core.online_vocations_images') %} @@ -69,11 +43,13 @@ {% endfor %}

    - {% endif %} {% endif %} +{% endif %} - {# show skulls #} - {% if setting('core.online_skulls') %} +
    + +{# show skulls #} +{% if setting('core.online_skulls') %}
    @@ -83,34 +59,114 @@
    +{% endif %} + +
    + +{% set title = 'World Information' %} +{% set tableClass = 'Table3' %} +{% set background = config('darkborder') %} +{% set content %} + + + + + + + + + + + {% if setting('core.online_record') and record|length > 0 %} + + + + {% endif %} -
    Status:{% if not status.online %}Offline{% else %}Online{% endif %}
    Players Online: + {% if setting('core.online_afk') %} + {% set players_count = players|length %} + {% set afk = players_count - status.players %} + {% if afk < 0 %} + {% set players_count = players_count + afk|abs %} + {% set afk = 0 %} + {% endif %} + Currently there are {{ status.players }} active and {{ afk }} AFK players.
    + Total number of players: {{ players_count }}.
    + {% else %} + {{ players|length }} + {% endif %} +
    Online Record: + {{ record }} +
    - + + + + + + + + +
    Location Datacenter:{{ setting('core.online_datacenter')|raw }} (Server date & time: - {{ "now"|date("d/m/Y H:i:s") }})
    PvP Type: + {% set worldType = config('lua')['worldType']|lower %} + {% if worldType in ['pvp','2','normal','open','openpvp'] %} + Open PvP + {% elseif worldType in ['no-pvp','nopvp','non-pvp','nonpvp','1','safe','optional','optionalpvp'] %} + Optional PvP + {% elseif worldType in ['pvp-enforced','pvpenforced','pvp-enfo','pvpenfo','pvpe','enforced','enfo','3','war','hardcore','hardcorepvp'] %} + Hardcore PvP + {% endif %} +
    +{% endset %} +{% include 'tables.headline.html.twig' %} +
    +
    + +{% set title = 'Players Online' %} +{% set tableClass = 'Table2' %} +{% set content %} + + {% if setting('core.account_country') %} - + {% endif %} {% if setting('core.online_outfit') %} - + {% endif %} - - - + + + + {% set i = 0 %} {% for player in players %} {% set i = i + 1 %} - - {% if setting('core.account_country') %} - - {% endif %} - {% if setting('core.online_outfit') %} - - {% endif %} - - - + + + {% if setting('core.account_country') %} + + {% endif %} + + {% if setting('core.online_outfit') %} + + {% endif %} + + + + {% endfor %}
    ##   + OutfitOutfitNameLevelVocationName   + [sort] + Level   + [sort] + + Vocation   + [sort] + +
    {{ player.country_image|raw }}player outfit{{ player.name|raw }}{{ player.skull }}{{ player.level }}{{ player.vocation }}
    {{ player.country_image|raw }}player outfit + {{ player.name|raw }}{{ player.skull|raw }} + {{ player.level }}{{ player.vocation }}
    -{% endif %} +{% endset %} +{{ include('tables.headline.html.twig') }} diff --git a/system/templates/rules.html.twig b/system/templates/rules.html.twig deleted file mode 100644 index 55490047..00000000 --- a/system/templates/rules.html.twig +++ /dev/null @@ -1,2 +0,0 @@ -{{ config.lua.serverName }} Rules
    -{{ getCustomPage('rules_on_the_page') | nl2br }} diff --git a/system/templates/success.html.twig b/system/templates/success.html.twig index 5d9a9b8b..3c69dad6 100644 --- a/system/templates/success.html.twig +++ b/system/templates/success.html.twig @@ -18,13 +18,14 @@ {% else %}
    - - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.back.html.twig') }} -
    {% endif %} diff --git a/system/templates/tables.style.html.twig b/system/templates/tables.style.html.twig index 479db426..8aa6305b 100644 --- a/system/templates/tables.style.html.twig +++ b/system/templates/tables.style.html.twig @@ -1,6 +1,9 @@ diff --git a/system/templates/tinymce.html.twig b/system/templates/tinymce.html.twig index effea162..00f1638a 100644 --- a/system/templates/tinymce.html.twig +++ b/system/templates/tinymce.html.twig @@ -8,7 +8,7 @@ selector: "#editor", content_css: '{{ constant('ADMIN_URL') }}template/style.css', theme: "silver", - plugins: 'preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help code emoticons', + plugins: 'preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help code emoticons', toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor | emoticons link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat code', resize: 'both', image_advtab: true, @@ -23,6 +23,8 @@ {title: 'Colored Table', value: 'myaac-table'}, ], + license_key: 'gpl', + setup: function (ed) { ed.on('NodeChange', function (e) { if (ed.getContent() !== lastContent) { diff --git a/system/twig.php b/system/twig.php index f59230e3..89f25939 100644 --- a/system/twig.php +++ b/system/twig.php @@ -36,7 +36,11 @@ $twig->addExtension(new MyAAC\Twig\Extension\TypeCastingExtension()); $filter = new TwigFilter('timeago', function ($datetime) { - $time = time() - strtotime($datetime); + if (!is_int($datetime)) { + $datetime = strtotime($datetime); + } + + $time = time() - $datetime; $units = array ( 31536000 => 'year', @@ -97,6 +101,10 @@ $twig->addFunction($function); $function = new TwigFunction('hook', function ($context, $hook, array $params = []) { global $hooks; + if (config('hooks_debug')) { + note($hook); + } + if(is_string($hook)) { if (defined($hook)) { $hook = constant($hook); @@ -152,3 +160,5 @@ $twig->addFilter($filter); unset($function, $filter); $hooks->trigger(HOOK_TWIG, ['twig' => $twig, 'twig_loader' => $twig_loader]); + +$twig->addGlobal('cache', $cache); diff --git a/templates/kathrine/config.php b/templates/kathrine/config.php index 63847317..52835ff4 100644 --- a/templates/kathrine/config.php +++ b/templates/kathrine/config.php @@ -1,12 +1,18 @@ array('id' => 'news', 'name' => 'Latest News'), - MENU_CATEGORY_ACCOUNT => array('id' => 'account', 'name' => 'Account'), - MENU_CATEGORY_COMMUNITY => array('id' => 'community', 'name' => 'Community'), - MENU_CATEGORY_LIBRARY => array('id' => 'library', 'name' => 'Library'), - MENU_CATEGORY_SHOP => array('id' => 'shops', 'name' => 'Shop') -); +// max 7 menus for kathrine +$config['menu_categories'] = [ + MENU_CATEGORY_NEWS => ['id' => 'news', 'name' => 'Latest News'], + // you can add custom menu by uncommenting this + // after doing it, go to admin panel -> Menus and add your entries for this category + // tip: you can move it up/down to show it on specific position + //7 => array('id' => 'testing', 'name' => 'Test Menu 1'), + //8 => array('id' => 'testing2', 'name' => 'Test Menu 2'), + MENU_CATEGORY_ACCOUNT => ['id' => 'account', 'name' => 'Account'], + MENU_CATEGORY_COMMUNITY => ['id' => 'community', 'name' => 'Community'], + MENU_CATEGORY_LIBRARY => ['id' => 'library', 'name' => 'Library'], + MENU_CATEGORY_SHOP => ['id' => 'shops', 'name' => 'Shop'] +]; $config['menus'] = require __DIR__ . '/menus.php'; diff --git a/templates/kathrine/javascript.php b/templates/kathrine/javascript.php index a092b7c2..32fcf53d 100644 --- a/templates/kathrine/javascript.php +++ b/templates/kathrine/javascript.php @@ -1,42 +1,40 @@ -var category = ' $info) { + $templatePages = get_template_pages($id); + + if ($id == MENU_CATEGORY_ACCOUNT) { + $templatePages = array_merge($templatePages, ['account']); + } + + if (in_array($tmp[0], $templatePages)) { + echo $info['id']; + break; + } } ?>'; diff --git a/templates/kathrine/menu.js.html.twig b/templates/kathrine/menu.js.html.twig index adf7ceb0..ae8ad3bf 100644 --- a/templates/kathrine/menu.js.html.twig +++ b/templates/kathrine/menu.js.html.twig @@ -1,10 +1,10 @@ var list = new Array(); {% set i = 0 %} -{% for cat in categories %} - {% if cat.id != 'shops' or setting('core.gifts_system') %} - list[{{ i }}] = '{{ cat.id }}'; +{% for id, cat in config('menu_categories') %} + {% if (cat.id != 'shops' or setting('core.gifts_system')) and menus[id]|length > 0 %} + list[{{ i }}] = '{{ cat.id }}'; + {% set i = i + 1 %} {% endif %} -{% set i = i + 1 %} {% endfor %} function initMenu() diff --git a/templates/kathrine/menus.php b/templates/kathrine/menus.php index f2ef20ed..aaa40f59 100644 --- a/templates/kathrine/menus.php +++ b/templates/kathrine/menus.php @@ -4,7 +4,7 @@ return [ MENU_CATEGORY_NEWS => [ 'Latest News' => 'news', 'News Archive' => 'news/archive', - 'Changelog' => 'changelog', + 'Changelog' => 'change-log', ], MENU_CATEGORY_ACCOUNT => [ 'Account Management' => 'account/manage', @@ -28,7 +28,7 @@ return [ MENU_CATEGORY_LIBRARY => [ 'Monsters' => 'monsters', 'Spells' => 'spells', - 'Server Info' => 'server-info', + 'Server Info' => 'ots-info', 'Commands' => 'commands', 'Exp Stages' => 'exp-stages', 'Gallery' => 'gallery', diff --git a/templates/kathrine/style.css b/templates/kathrine/style.css index a021b1d9..cc212685 100644 --- a/templates/kathrine/style.css +++ b/templates/kathrine/style.css @@ -27,11 +27,13 @@ body #tabs { - width: 580px; + width: 99%; height: 32px; background: url('images/tabs-bg.png') no-repeat; - float: left; padding-left: 200px; + position: relative; + display: inline-flex; + right: 0; } #tabs .tab @@ -453,6 +455,27 @@ a:hover white-space: nowrap; vertical-align: top; } +.LabelV120 { + font-weight: bold; + padding-right: 10px; + white-space: nowrap; + vertical-align: top; + width: 120px; +} +.LabelV150 { + font-weight: bold; + padding-right: 10px; + white-space: nowrap; + vertical-align: top; + width: 150px; +} +.LabelV200 { + font-weight: bold; + padding-right: 10px; + white-space: nowrap; + vertical-align: top; + width: 200px; +} .LabelH { font-weight: bold; padding-right: 10px; diff --git a/templates/kathrine/template.php b/templates/kathrine/template.php index af03b3c9..ffa2195a 100644 --- a/templates/kathrine/template.php +++ b/templates/kathrine/template.php @@ -8,7 +8,9 @@ defined('MYAAC') or die('Direct access not allowed!'); @@ -28,11 +30,24 @@ defined('MYAAC') or die('Direct access not allowed!'); + + 6) { + $tabsStyle .= 'padding-left: 4px;'; + $tabsStyle .= 'padding-right: 12px;'; + } + elseif ($menusCount > 5) { + $tabsStyle .= 'padding-left: 90px;'; + } + ?> + -
    +
    $cat) { - if($id != MENU_CATEGORY_SHOP || $config['gifts_system']) { ?> + if (($id != MENU_CATEGORY_SHOP || $config['gifts_system']) && isset($menus[$id])) { ?> +
    + {{ csrf() }} + {% if redirect is not null %} {% endif %} +
    @@ -20,9 +23,9 @@ @@ -127,6 +130,7 @@
    {% apply spaceless %} + {{ csrf() }}
    diff --git a/templates/tibiacom/account.management.html.twig b/templates/tibiacom/account.management.html.twig index 5125f3ed..649eba36 100644 --- a/templates/tibiacom/account.management.html.twig +++ b/templates/tibiacom/account.management.html.twig @@ -11,13 +11,14 @@
    @@ -59,13 +60,14 @@
    -
    - - +
    +
    + - +
    @@ -30,7 +33,7 @@
    - +
    - + {{ hook('HOOK_ACCOUNT_LOGIN_AFTER_PASSWORD') }} @@ -67,7 +70,7 @@ - +
    @@ -45,7 +48,7 @@ {{ hook('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT') }}
    Password:
    @@ -79,7 +82,7 @@
    - - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.logout.html.twig') }} -
    - - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.register_account.html.twig') }} -
    @@ -94,13 +96,14 @@
    - - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.edit.html.twig') }} -
    @@ -177,26 +180,29 @@ - - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.change_password.html.twig') }} -
    - - - + - - + + +
    +
    + + {{ csrf() }} + {{ include('buttons.change_email.html.twig') }} -
    @@ -204,13 +210,14 @@ {% if recovery_key is empty %} - - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.register_account.html.twig') }} -
    {% endif %} @@ -258,13 +265,14 @@ - - - + - - + + +
    +
    + + {{ csrf() }} {{ include('buttons.edit.html.twig') }} -
    @@ -398,8 +406,9 @@ - @@ -410,8 +419,9 @@
    +
    + {{ csrf() }} {{ include('buttons.create_character.html.twig') }}
    - @@ -423,8 +433,9 @@
    +
    + {{ csrf() }} {{ include('buttons.change_name.html.twig') }}
    - @@ -436,8 +447,9 @@ diff --git a/templates/tibiacom/tables.headline.html.twig b/templates/tibiacom/tables.headline.html.twig index 5db3dedb..3eb1bc4f 100644 --- a/templates/tibiacom/tables.headline.html.twig +++ b/templates/tibiacom/tables.headline.html.twig @@ -5,7 +5,7 @@ -
    {{ title|raw }}
    +
    {{ title|raw }}
    diff --git a/tools/basic.js b/tools/basic.js index 8fa21fa9..c5f84618 100644 --- a/tools/basic.js +++ b/tools/basic.js @@ -1,11 +1,11 @@ function MouseOverBigButton(source) { - if (source?.firstChild?.style) { - source.firstChild.style.visibility = "visible"; + if (source?.firstElementChild?.style) { + source.firstElementChild.style.visibility = "visible"; } } function MouseOutBigButton(source) { - if (source?.firstChild?.style) { - source.firstChild.style.visibility = "hidden"; + if (source?.firstElementChild?.style) { + source.firstElementChild.style.visibility = "hidden"; } } function BigButtonAction(path) { diff --git a/tools/generate_account_number.php b/tools/generate_account_number.php index a53ba9a3..643bb2c2 100644 --- a/tools/generate_account_number.php +++ b/tools/generate_account_number.php @@ -9,6 +9,8 @@ * @link https://my-aac.org */ +const IGNORE_SET_LAST_VISIT = true; + // we need some functions require '../common.php'; require SYSTEM . 'functions.php'; diff --git a/tools/status.php b/tools/status.php index ae0ee49d..9e9c8a29 100644 --- a/tools/status.php +++ b/tools/status.php @@ -1,4 +1,7 @@
    +
    + {{ csrf() }} {{ include('buttons.change_sex.html.twig') }}
    - @@ -451,4 +463,7 @@
    +
    + {{ csrf() }} {{ include('buttons.delete_character.html.twig') }}
    {% endset %} {% include 'tables.headline.html.twig' %} -

    +
    +{{ hook('HOOK_ACCOUNT_MANAGE_AFTER_CHARACTERS') }} + +
    diff --git a/templates/tibiacom/basic.css b/templates/tibiacom/basic.css index 4633c5ed..a4f0fc24 100644 --- a/templates/tibiacom/basic.css +++ b/templates/tibiacom/basic.css @@ -1446,6 +1446,27 @@ img { white-space: nowrap; vertical-align: top; } +.LabelV120 { + font-weight: bold; + padding-right: 10px; + white-space: nowrap; + vertical-align: top; + width: 120px; +} +.LabelV150 { + font-weight: bold; + padding-right: 10px; + white-space: nowrap; + vertical-align: top; + width: 150px; +} +.LabelV200 { + font-weight: bold; + padding-right: 10px; + white-space: nowrap; + vertical-align: top; + width: 200px; +} .LabelH { font-weight: bold; padding-right: 10px; diff --git a/templates/tibiacom/boxes/templates/poll.html.twig b/templates/tibiacom/boxes/templates/poll.html.twig index 0b643ee5..25f10865 100644 --- a/templates/tibiacom/boxes/templates/poll.html.twig +++ b/templates/tibiacom/boxes/templates/poll.html.twig @@ -1,6 +1,6 @@
    {{ poll.question }}
    -
    +
    diff --git a/templates/tibiacom/index.php b/templates/tibiacom/index.php index 6d0d1e63..a6b57841 100644 --- a/templates/tibiacom/index.php +++ b/templates/tibiacom/index.php @@ -27,24 +27,18 @@ if(isset($config['boxes'])) var loginStatus=""; "; } else { window.location = ""; } } function LoginstatusTextAction(source) { - if(loginStatus == "false") { + if(loginStatus === "false") { window.location = ""; } else { window.location = ""; @@ -164,6 +158,10 @@ if(isset($config['boxes'])) function InitializeMenu() { for(menuItemName in menu[0]) { + if (!document.getElementById(menuItemName+"_Submenu")) { + continue; + } + if(menu[0][menuItemName] == "0") { document.getElementById(menuItemName+"_Submenu").style.visibility = "hidden"; document.getElementById(menuItemName+"_Submenu").style.display = "none"; @@ -222,11 +220,11 @@ if(isset($config['boxes'])) // mouse-over effects of menubuttons and submenuitems function MouseOverMenuItem(source) { - source.firstChild.style.visibility = "visible"; + source.firstElementChild.style.visibility = "visible"; } function MouseOutMenuItem(source) { - source.firstChild.style.visibility = "hidden"; + source.firstElementChild.style.visibility = "hidden"; } function MouseOverSubmenuItem(source) { @@ -332,7 +330,7 @@ if(isset($config['boxes']))
    - + $cat) { + @@ -454,7 +453,7 @@ foreach($config['menu_categories'] as $id => $cat) { foreach($config['boxes'] as $box) { /** @var string $template_name */ - $file = TEMPLATES . $template_name . '/boxes/' . $box . '.php'; + $file = __DIR__ . '/boxes/' . $box . '.php'; if(file_exists($file)) { include($file); ?> [ 'Latest News' => 'news', 'News Archive' => 'news/archive', - 'Changelog' => 'changelog', + 'Changelog' => 'change-log', ], MENU_CATEGORY_ACCOUNT => [ 'Account Management' => 'account/manage', @@ -33,7 +33,7 @@ return [ 'Commands' => 'commands', 'Exp Stages' => 'exp-stages', 'Gallery' => 'gallery', - 'Server Info' => 'server-info', + 'Server Info' => 'ots-info', 'Exp Table' => 'exp-table', 'FAQ' => 'faq', ], diff --git a/templates/tibiacom/success.html.twig b/templates/tibiacom/success.html.twig index 4aac4acb..c87a1971 100644 --- a/templates/tibiacom/success.html.twig +++ b/templates/tibiacom/success.html.twig @@ -35,6 +35,7 @@
    + {{ csrf() }} {{ include('buttons.back.html.twig') }}