Compare commits

..

25 Commits

Author SHA1 Message Date
slawkens
8ec08b5a61 This is always true 2023-11-11 08:41:40 +01:00
slawkens
19346efc38 More info to confirm dialog 2023-11-11 08:38:15 +01:00
slawkens
c9d5c6cfd7 Add new changelog link 2023-11-11 08:37:32 +01:00
slawkens
4461c03d48 Fix changelog link 2023-11-11 08:33:44 +01:00
slawkens
60c7ef2391 Fix news type 2023-11-11 08:32:55 +01:00
slawkens
d6c35bcbb5 Formatting 2023-11-11 08:28:00 +01:00
slawkens
4e87e7e9dc clear_cache & maintenance csrf 2023-11-11 08:27:48 +01:00
slawkens
08a19158b3 Fix new page/news links 2023-11-11 08:12:02 +01:00
slawkens
9a306886fb Update mailer.php 2023-11-11 08:02:02 +01:00
slawkens
719c542757 add info function, same as note($message) 2023-11-11 08:01:58 +01:00
slawkens
1ed24afc7d Move definitions 2023-11-11 08:01:39 +01:00
slawkens
66479e64ed Plugins csrf 2023-11-11 07:53:24 +01:00
slawkens
4e26f07ab6 Menus: better csrf + add success message on reset colors 2023-11-11 07:41:43 +01:00
slawkens
13e6eb5666 Admin panel: Pages csrf 2023-11-11 07:37:21 +01:00
slawkens
56306dfb0a Use admin.links instead 2023-11-11 07:22:58 +01:00
slawkens
f27172691c Refactor admin newses + add csrf 2023-11-11 07:22:43 +01:00
slawkens
5578dbaa83 news/id route 2023-11-11 06:31:28 +01:00
slawkens
549c08c096 Admin Panel: changelogs csrf protection 2023-11-11 06:08:09 +01:00
slawkens
0127a4f417 Fix token generate 2023-11-11 06:07:33 +01:00
slawkens
08074d8d4f Merge branch 'develop' into feature/csrf 2023-11-11 05:40:17 +01:00
slawkens
198cc5a09d Cosmetics 2023-09-16 11:30:35 +02:00
slawkens
3e7cbbb63b Merge branch 'develop' into feature/csrf 2023-09-16 11:09:34 +02:00
slawkens
8e3a71b36b Merge branch 'develop' into feature/csrf 2023-09-16 10:25:49 +02:00
slawkens
0e33fd103c feature: csrf protection 2023-09-16 09:23:51 +02:00
slawkens
046c0b5cf4 Fix alert class name 2023-09-16 07:12:04 +02:00
434 changed files with 11928 additions and 13848 deletions

View File

@@ -1,9 +1,9 @@
name: Cypress name: Cypress
on: on:
pull_request: pull_request:
branches: [main] branches: [develop]
push: push:
branches: [main] branches: [develop]
jobs: jobs:
cypress: cypress:
@@ -22,9 +22,8 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: [ '8.1', '8.2', '8.3' ] php-versions: [ '7.4', '8.0', '8.1' ]
ots: ['tfs-1.4', 'canary-3.1.2'] # TODO: add 'tfs-master' (actually doesn't work cause AAC doesn't support reading .env configuration) name: MyAAC on PHP ${{ matrix.php-versions }}
name: Cypress (PHP ${{ matrix.php-versions }}, ${{ matrix.ots }})
steps: steps:
- name: 📌 MySQL Start & init & show db - name: 📌 MySQL Start & init & show db
run: | run: |
@@ -33,81 +32,47 @@ jobs:
mysql -e "SHOW DATABASES" -uroot -proot mysql -e "SHOW DATABASES" -uroot -proot
- name: Checkout MyAAC - name: Checkout MyAAC
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
ref: main ref: 0.9
- uses: actions/setup-node@v4
with:
node-version: 18
- run: npm ci
- name: Checkout TFS - name: Checkout TFS
uses: actions/checkout@v4 uses: actions/checkout@v3
if: matrix.ots == 'tfs-1.4'
with: with:
repository: otland/forgottenserver repository: otland/forgottenserver
ref: 1.4 ref: 1.4
path: ots path: tfs
- name: Checkout TFS - name: Import TFS Schema
uses: actions/checkout@v4
if: matrix.ots == 'tfs-master'
with:
repository: otland/forgottenserver
ref: master
path: ots
- name: Checkout Canary
uses: actions/checkout@v4
if: matrix.ots == 'canary-3.1.2'
with:
repository: opentibiabr/canary
ref: v3.1.2
path: ots
- name: Import OTS Schema
run: | run: |
mysql -uroot -proot myaac < ots/schema.sql mysql -uroot -proot myaac < tfs/schema.sql
- name: Rename config.lua - name: Rename config.lua
run: mv ots/config.lua.dist ots/config.lua run: mv tfs/config.lua.dist tfs/config.lua
- name: Replace mysqlUser (TFS 1.4) - name: Replace mysqlUser
uses: jacobtomlinson/gha-find-replace@v3 uses: jacobtomlinson/gha-find-replace@v2
if: matrix.ots == 'tfs-1.4'
with: with:
find: 'mysqlUser = "forgottenserver"' find: 'mysqlUser = "forgottenserver"'
replace: 'mysqlUser = "root"' replace: 'mysqlUser = "root"'
regex: false regex: false
include: 'ots/config.lua' include: 'tfs/config.lua'
- name: Replace mysqlPass (TFS 1.4) - name: Replace mysqlPass
uses: jacobtomlinson/gha-find-replace@v3 uses: jacobtomlinson/gha-find-replace@v2
if: matrix.ots == 'tfs-1.4'
with: with:
find: 'mysqlPass = ""' find: 'mysqlPass = ""'
replace: 'mysqlPass = "root"' replace: 'mysqlPass = "root"'
regex: false regex: false
include: 'ots/config.lua' include: 'tfs/config.lua'
- name: Replace mysqlDatabase (TFS 1.4) - name: Replace mysqlDatabase
uses: jacobtomlinson/gha-find-replace@v3 uses: jacobtomlinson/gha-find-replace@v2
if: matrix.ots == 'tfs-1.4'
with: with:
find: 'mysqlDatabase = "forgottenserver"' find: 'mysqlDatabase = "forgottenserver"'
replace: 'mysqlDatabase = "myaac"' replace: 'mysqlDatabase = "myaac"'
regex: false regex: false
include: 'ots/config.lua' include: 'tfs/config.lua'
- name: Replace mysqlDatabase (Canary)
uses: jacobtomlinson/gha-find-replace@v3
if: matrix.ots == 'canary-3.1.2'
with:
find: 'mysqlDatabase = "otservbr-global"'
replace: 'mysqlDatabase = "myaac"'
regex: false
include: 'ots/config.lua'
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
@@ -120,13 +85,13 @@ jobs:
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache composer dependencies - name: Cache composer dependencies
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: ${{ steps.composer-cache.outputs.dir }} path: ${{ steps.composer-cache.outputs.dir }}
# Use composer.json for key, if composer.lock is not committed. # Use composer.json for key, if composer.lock is not committed.
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
#key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies - name: Install Composer dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader run: composer install --no-progress --prefer-dist --optimize-autoloader
@@ -135,28 +100,21 @@ jobs:
run: nohup php -S localhost:8080 > php.log 2>&1 & run: nohup php -S localhost:8080 > php.log 2>&1 &
- name: Cypress Run - name: Cypress Run
uses: cypress-io/github-action@v6 uses: cypress-io/github-action@v5
env: env:
CYPRESS_URL: http://localhost:8080 CYPRESS_URL: http://localhost:8080
CYPRESS_SERVER_PATH: /home/runner/work/myaac/myaac/ots CYPRESS_SERVER_PATH: /home/runner/work/myaac/myaac/tfs
- name: Save screenshots - name: Save screenshots
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
if: always() if: always()
with: with:
name: cypress-screenshots-${{ matrix.php-versions }}-${{ matrix.ots }} name: cypress-screenshots
path: cypress/screenshots path: cypress/screenshots
- name: Upload Cypress Videos - name: Upload Cypress Videos
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
if: always() if: always()
with: with:
name: cypress-videos-${{ matrix.php-versions }}-${{ matrix.ots }} name: cypress-videos
path: cypress/videos path: cypress/videos
- name: Upload PHP Logs
uses: actions/upload-artifact@v4
if: always()
with:
name: php-log-${{ matrix.php-versions }}-${{ matrix.ots }}
path: php.log

View File

@@ -1,9 +1,9 @@
name: PHP Linting name: PHP Linting
on: on:
pull_request: pull_request:
branches: [main] branches: [develop]
push: push:
branches: [main] branches: [develop]
jobs: jobs:
phplint: phplint:

View File

@@ -1,46 +0,0 @@
name: "PHPStan"
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
tests:
name: PhpStan on PHP ${{ matrix.php-versions }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-versions: [ '8.1', '8.2', '8.3' ]
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
extensions: "intl, zip"
ini-values: "memory_limit=-1"
php-version: "${{ matrix.php-version }}"
- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache composer dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
# Use composer.json for key, if composer.lock is not committed.
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
- name: "Install composer dependencies"
run: "composer install"
- name: "Run PHPStan"
run: "/usr/bin/php vendor/bin/phpstan analyse"

9
.gitignore vendored
View File

@@ -4,20 +4,17 @@ Thumbs.db
# #
/.htaccess /.htaccess
lua
# composer # composer
composer.phar composer.lock
vendor vendor
# npm # npm
node_modules node_modules
tools/ext
# cypress # cypress
cypress.env.json cypress.env.json
cypress/e2e/2-advanced-examples cypress/e2e/2-advanced-examples
cypress/screenshots
# created by release.sh # created by release.sh
releases releases
@@ -50,7 +47,6 @@ system/cache/*
!system/cache/twig/index.html !system/cache/twig/index.html
!system/cache/signatures/index.html !system/cache/signatures/index.html
!system/cache/plugins/index.html !system/cache/plugins/index.html
!system/cache/persistent/index.html
# logs # logs
system/logs/* system/logs/*
@@ -76,3 +72,6 @@ landing
# system # system
system/functions_custom.php system/functions_custom.php
# others/rest
system/pages/downloads.php

View File

@@ -1,245 +0,0 @@
# Changelog
## [1.3.3 - 04.04.2025]
### Fixed
* Fix uninstall plugin when plugin is disabled (https://github.com/slawkens/myaac/commit/6c568fd36a271270684fc412ccd556b230273a6d)
### Changed
* Display more useful info when error parsing config.lua (https://github.com/slawkens/myaac/commit/fa6b6aa153ffc131e0d1631a4dcd9012a5850c2e)
### Other
* Small adjustments (https://github.com/slawkens/myaac/commit/35e2483de86e295bdf089cceffa25842eeb2e34c, https://github.com/slawkens/myaac/commit/ae639d65b0bfa491e747e907e2ebc77f83f47981)
## [1.3.2 - 01.04.2025]
### Fixed
* Fix debugBar/admin panel menu when using custom base_dir (https://github.com/slawkens/myaac/commit/65696f63e3aac02ff952ea81279e7cb2fa7570fb)
### Changed
* Settings: Show/hide IP Ban Protection options depending on the value (enabled/disabled) (https://github.com/slawkens/myaac/commit/dbf73d0b61b45601ae95e51b23c051c2704169c5)
* Do not require init.php in cache:clear command (https://github.com/slawkens/myaac/commit/d25c71857f767834239bbffacd00fdc671adb157)
## [1.3.1 - 19.03.2025]
### Fixed
* Fixed migrate:run command (https://github.com/slawkens/myaac/commit/1a5771ad51e595fe13368a0721b059c4ecefb17d)
### Changed
* Small adjustments (https://github.com/slawkens/myaac/commit/6fac883659f581baac1361826d046410156f1e58, https://github.com/slawkens/myaac/commit/4a6896b4469968b9904292734cf6c14ba5eeef14)
## [1.3 - 10.03.2025]
### Changed
* Use latest outfit-images host from @gesior (https://github.com/slawkens/myaac/commit/529bdcf016dd0f9dffbc34d81f99a046a9ddb70d)
* Change monster link to $_GET ?name= (https://github.com/slawkens/myaac/commit/4c5cc8b573b2b3e7ec00a22b7ede30a68083a924)
### Fixed
* Fixed house links (https://github.com/slawkens/myaac/commit/887b5068ad11c4cdab614afd34525caba785ce13)
* Fixed long title on headline.php (https://github.com/slawkens/myaac/commit/3e3f4bb5a514158ec8777684ca6c7f1c2a37bed5)
* Fixed menu colors once again, plus add !important tag (https://github.com/slawkens/myaac/commit/aa52df6e2ec92cafc25b655ae907bf2e1746d9cc)
* Fix: add possibility to remove all menu items in admin panel (https://github.com/slawkens/myaac/commit/00fe1adc15ea7646596d755f6e6e1f7854ffc1d5, https://github.com/slawkens/myaac/commit/9239a4f4198c3ad260802ac3b47e9c41b80b754e)
## [1.2 - 09.02.2025]
### Added
* Twig session(key) function + reworked session functions to accept multi-array like in Laravel (https://github.com/slawkens/myaac/commit/b46ddb43d03ef7e5fc34e555e92e856bdc905691)
* add template_name to twig variables (https://github.com/slawkens/myaac/commit/ae1161d77050bda181802b4496c9de920a7bb1bc)
* add HOOK_INIT, executed just after $hooks are loaded (https://github.com/slawkens/myaac/commit/19686725dc810f63a07f049f82c66cf336d90ca6)
### Changed
* settings: password input hide/show, enable Save button only if changes has been made, save settings in transaction (https://github.com/slawkens/myaac/commit/4fda4f643b60a151179e5dd4f04912fb2618d98f, https://github.com/slawkens/myaac/commit/28fef952f857b79d64bc7495ffa5e1999e68e192, https://github.com/slawkens/myaac/commit/4b6024dc451accadb6c469fa282a9a764c1c0a81)
* rework menus: Different categories can have different colors + Option to reset menus (https://github.com/slawkens/myaac/commit/73de93a561f6b13111e019075724357d8a617249, https://github.com/slawkens/myaac/commit/3da3e62c5b12390d75de9b3320729bcca6e0b458)
### Fixed
* highscores: Fix online status + vocation for TFS 0.x (https://github.com/slawkens/myaac/commit/ea51ad27c38be88d86514cb979bb394fcfbef1f0)
* clear cache button in admin bar needed to be clicked twice until it worked (https://github.com/slawkens/myaac/commit/ea51ad27c38be88d86514cb979bb394fcfbef1f0)
* HOOK_STARTUP location (https://github.com/slawkens/myaac/commit/a73fb1003ee3f812cf182d1834d65f08e6f60d1f)
* if vocation name has more words (https://github.com/slawkens/myaac/commit/9d7fc98e1e0a96b59ecc1a7c39800a64445db364)
### Updated
* Bump twig/twig from 3.18.0 to 3.19.0 (#284)
## [1.1 - 27.01.2025]
### Changed
* adjust mailer settings descriptions to latest gmail (https://github.com/slawkens/myaac/commit/c5d5bb80671db135e6b503f53684771c7272e05d)
* optimize $player->isOnline() function, thanks @gesior (https://github.com/slawkens/myaac/commit/10dd818b139d5e1bb1ca9ec81edfb083ba9316b4)
* make players.comment and guilds.description VARCHAR (https://github.com/slawkens/myaac/commit/a45ceab83a74bee2b89cdb72baceda75e577e3cf)
* add lua/ folder to .gitignore (https://github.com/slawkens/myaac/commit/07012f786b1114cb6ab2f064f82c645b136a375a)
### Fixed
* general fixes in the tibiacom template menus, better support for custom menus
* make functions_custom.php optional (https://github.com/slawkens/myaac/commit/dc2b5afd9980984e2b259c9fc99f2ade46f70a5a)
* error in CLI, where BASE_URL is not defined (https://github.com/slawkens/myaac/commit/4d749b881582f64b5a46196dbbb5ee8097127f03)
* hook ACCOUNT_LOGIN_BEFORE_ACCOUNT location (https://github.com/slawkens/myaac/commit/669c447fca8643ce56d9ef8c1374ec647c780998)
## [1.0.1 - 14.01.2025]
### Fixed
* tibiacom account & news menu links not auto expanding
### Updated (Thanks dependabot)
* twig from ^2.0 to ^3.11
* tinymce from ^6.8.3 to ^7.2.0
* cypress from ^12.12.0 to ^13.17.0
* nesbot/carbon from 2.72.5 to 2.72.6
## [1.0 - 12.01.2025]
First stable release in the v1.0 series.
Minimum PHP 8.1 is required.
Changes since RC.2:
### Added
* feature: migrations up/down. Allows to downgrade/upgrade database to specified version (https://github.com/slawkens/myaac/commit/3f6ff3a3326b0475d28d11ffd7fff51f362d799f)
* new hooks for news management (https://github.com/slawkens/myaac/commit/011a85d8ae34283ded6999882833f9d4797028ec, https://github.com/slawkens/myaac/commit/36bd3eb846e829b45313e10f7568dc4e95841143)
* None Vocation to highscores (can be changed to RookStayer in Admin Panel) (https://github.com/slawkens/myaac/commit/a4a248099521bb5b8b2aa5bd592138debd2f19d5)
* support for button_color (green, red, blue) (https://github.com/slawkens/myaac/commit/d8b6b749ee62e88b6af4a05d3d7557f90b94d94e)
* add $whoopsHandler as variable, can be used by plugins (https://github.com/slawkens/myaac/commit/b0c8cf2ecda23045d725aaf43cfb3852ed766a4b)
* PlayerModel->outfit_url attribute (https://github.com/slawkens/myaac/commit/3b5be1a8db5dceecaa388e2925a5536d13b38881)
* support for selecting plugin themes in Admin menus.php (https://github.com/slawkens/myaac/commit/77a2c1cec343ffe4be5c2c2503ee81bc32a14ca1)
### Changed
* schema: Change character set to utf8mb4 (support for Emojis in Menus/Pages/News/Forum etc.) (https://github.com/slawkens/myaac/commit/27c44f1bdfb6234cf0c9d5b4b491123bb205b08f)
* prefer get_browser_real_ip() over REMOTE_ADDR (https://github.com/slawkens/myaac/commit/941846605c00cee83168d2f916410b8ba8d4b7b9)
* automatically set selected current one on highscores filters (https://github.com/slawkens/myaac/commit/e96227fbe41ae281783b2d49edb169a603601813)
* rewrite towns loading code, removed OTBM loader (was too slow) (https://github.com/slawkens/myaac/commit/c980a0914632e7b27f718464f669a200707d217e)
* allow OTS_Player to be passed as object to getPlayerLink (https://github.com/slawkens/myaac/commit/84d37c5a8f2c4535a41c8aa8264752969d3f3a3d)
* do not clear menus by default on install (https://github.com/slawkens/myaac/commit/12d8faa3eda5e798f97b71e941c035187daad96e)
* display warning in admin panel - plugins - if zip extension is not installed (https://github.com/slawkens/myaac/commit/e3ffe5d9e11d78ab064a370d8541bac351c9bcd9)
* set default_socket_timeout for ipinfo.io checkup to 5 seconds (https://github.com/slawkens/myaac/commit/783d96fc6568a607d3198b832fed3a0dd06c4ebb)
* refactor getTopPlayers function (support for balance) (https://github.com/slawkens/myaac/commit/c769962e39fe8dfb72ecd5be1864e145696be794)
### Fixed
* XSS in forum (https://github.com/slawkens/myaac/commit/c2b7286d20d4b579171540f7a774e8a0995d5e8f, https://github.com/slawkens/myaac/commit/8fb643596f9586005976e7bdb484a541a9d8715e)
* price deducted when changing sex (https://github.com/slawkens/myaac/commit/16671ea40b72dcf74037c359ad572f9eb825edf9)
* move_thread by unauthorized user (https://github.com/slawkens/myaac/commit/d6c40c836a53cb1710f911f77f45f28b54ea1b54, thanks @anyeor)
* TFS 1.4.2 where conditions is NULL (https://github.com/slawkens/myaac/commit/b8396d4c8482e951da538b13f2296123732c4545)
* do not show forum new thread show button if not logged in (https://github.com/slawkens/myaac/commit/507402171ba3b6e7ee184bd7fa73e0d55e0cad7a, @anyeor)
* login if limiter is disabled (https://github.com/slawkens/myaac/commit/a0f1971583f0f790013e2145fb5ac573c59fbdef)
* fixes to installMenus function (https://github.com/slawkens/myaac/commit/a2fadc5945fe0a5e39f740827f6ffbda1bb501e2)
* many PHP exceptions in different places
* fixes to tibiacom menus ActiveSubmenuItem
### Removed
* bugtracker SQL table code as the page has been removed/moved to plugins (https://github.com/slawkens/myaac/commit/5782772b901b05fb814bc718d062f6e2cd71df8c)
## [1.0-RC.2 - 25.10.2024]
Still waiting for your reports about bugs found in this release. We are very close to stable release.
### Added
* feat: rate limit settings for blocking accounts login attempts (@gpedro, #266)
* search by email in accounts editor (https://github.com/slawkens/myaac/commit/c2ec46824621468f2a1cb4046805c485ed13fea5)
* New hooks in account manage + create (https://github.com/slawkens/myaac/commit/93641fc68ac9a5f1479329e2bd41380c19534d5d)
### Changed
* chore: drop raw queries + accounts - search by email + accounts - required min size for search by account number (@gpedro, #266)
* Use https for outfit & item images (https://github.com/slawkens/myaac/commit/71c00aa5e01fbdfd88802912e200dd1025976231)
* Do not require players & guilds tables on install (https://github.com/slawkens/myaac/commit/779aa152fa940261c9b161533946f44e288597a2)
* Do not create player if there is no players table in db (https://github.com/slawkens/myaac/commit/201f95caa8b70e88fa651eac8c3c3aa7cd765bd0)
### Fixed
* Highscore frags fixed for TFS 0.3 (@Scrollog, #263)
* Missing groups variable #262. thanks, @Scrollog for reporting (https://github.com/slawkens/myaac/commit/8d8bdb6dac6df21672ac77288fff2f2f8d6eb665)
* Verified email for login.php (@gpedro, #265)
* Warning if core.account_country is disabled (https://github.com/slawkens/myaac/commit/ab73d60c61e14a1cacdb6cfbf7f89f4bf3be0833)
## [1.0-RC.1 - 23.07.2024]
Changes since 1.0-beta:
### Added
* Feat: Hooks priority (https://github.com/slawkens/myaac/commit/dc17b701da053e04bfa64e21be9247a4f07505e1)
* Make autoload of pages, commands and themes configurable (https://github.com/slawkens/myaac/commit/c1d4b4f80cd6bb85507ee9471e47013955a26a91)
* Fraggers in characters page for TFS 1.x and canary (https://github.com/slawkens/myaac/commit/42f99c3edc8de39cccc5632cb42e88b24579c5a6)
* New hooks: HOOK_INSTALL_FINISH, HOOK_ACCOUNT_CREATE_CHARACTER_* (https://github.com/slawkens/myaac/commit/08ac8ebade106521a5c7396faa5ce7006e629f7c, https://github.com/slawkens/myaac/commit/45dda5e834ff2059faea6ef9be2efa76f1723cbd)
### Changed
* Allow account_create_character_create even if account_mail_verify is activated (https://github.com/slawkens/myaac/commit/203e411b626fe62401a4b74a48420769e512aa39)
* Create guild_rank entries, in case MySQL trigger not loaded (https://github.com/slawkens/myaac/commit/d9c1b2507c81f306970642b35e4bf5f7cc04a6f2, https://github.com/slawkens/myaac/commit/47a19e85dd84e9f3b39a1b29cfc2c04b004832b9)
* Set Admin Account verified by default (https://github.com/slawkens/myaac/commit/cd49dfc79942f3301ce9c0b8d899b9f39bda9a41)
* Refactor account routes into sub folders (https://github.com/slawkens/myaac/commit/bdc0c43d3fd3a51030c3e916bdb9f008468f5ecd)
* Order towns by id (https://github.com/slawkens/myaac/commit/9ea2a5067fc4b75de395f381577b18914132ad84)
* Do not create news about myaac, if any news already exist (on installation (https://github.com/slawkens/myaac/commit/504242fb846b73b56b87bc1e39d070687ad7f5b4)
### Fixed
* Not working google recaptcha plugin (https://github.com/slawkens/myaac/commit/a1bcb217ecf4e21fd58da4ba491da1852029898a)
* Not working account create if account_country is disabled (https://github.com/slawkens/myaac/commit/933b681a9fcdbb6283e0469b3806d2ded492d232)
* Account verify - do not allow login without verified email (Thanks @anyeor, https://github.com/slawkens/myaac/commit/fcb13f3c0fb8ceafda0bd614a229a26a269432bd)
* Detect tools/ext exists on install to prevent broken installs (https://github.com/slawkens/myaac/commit/10a739773c4f2911876bc802a0ee0537c3e00a92)
* Cache reloading each time page refreshes (https://github.com/slawkens/myaac/commit/ec96985872057340112f65073efc0c4bf86dddb0)
* Highscores frags for TFS 1.x and canary (https://github.com/slawkens/myaac/commit/a04d186c22912915f0a7873dfe677ef3b5a23c79)
* Monsters page: monster not found exception (https://github.com/slawkens/myaac/commit/ef79b99b8acc179f14b8475547347d9daca27512)
* Fixed bug if \<flags\> are not present in monster.xml (https://github.com/slawkens/myaac/commit/57b47ab7983f625c7c0ef4f5303a4d07ef172786)
* fastRoute duplicate errors (https://github.com/slawkens/myaac/commit/4c0739d3e93812dff0c33849ea3f38e4e49113ac)
* useGuildNick displaying (https://github.com/slawkens/myaac/commit/0db0ec1aa47e044c26bc403ff5078a2115d086f8)
## [1.0-beta - 18.05.2024]
Minimum PHP version for this release is 8.1.
### Added
* reworked Admin Panel (@Leesneaks, @gpedro, @slawkens)
* updated to Bootstrap v4
* new Menu
* new Dashboard: statistics, server status
* new Admin Bar showed on top when admin logged in
* new page: Server Data, to reload server data
* Towns, NPCs & Items are stored in permanent cache
* new pages: mass account & teleport tools
* changelogs editor
* revised Accounts & Players editors
* option to add/modify admin menus with plugins
* option to enable/disable plugins
* better, updated TinyMCE editor (v6.x)
* with option to upload images
* list of open source libraries used in project page
* auto-loading of themes, commands & pages from plugins/ folder. You need just to place them in correct folder and they will be loaded automatically - this allows better customization, without interfering with core AAC folders. This will allow in the future automatic updates for plugins as well the AAC as whole.
* config.php moved to Admin Panel -> Settings page
* new console script: aac - using symfony/console
* usage: `php aac` (will list all commands by default)
* example: `php aac cache:clear`
* example: `php aac plugin:install theme-example.zip`
* replace POT Query Builder to Eloquent ORM. Not 100% yet - in some places there is still old $db approach used (@gpedro) (https://github.com/slawkens/myaac/pull/230)
* brand new charming installation page (by @fernandomatos)
* using Bootstrap
* new pages router: nikic/fast-route, allowing for better customisation
* Plugin cronjobs: central control of the cronjobs
* Guild Wars support (available as plugin)
* support for login and create account only by email (configurable)
* with no need for account name
* Google ReCAPTCHA v3 support (available as plugin)
* support for Account Number
* suggest account number option
* many new functions, hooks and configurables
* better Exception Handler (Whoops - https://github.com/filp/whoops)
* automated website tests (using Cypress)
* csrf protection (https://github.com/slawkens/myaac/pull/235)
* option to restrict Page view to specified group of users (Not-Logged in, logged-in players, tutors, gamemasters etc.)
* phpdebug bar (http://phpdebugbar.com/). Activated if env == 'dev', can be also activated in production by enabling "enable_debugbar" in local config
### Changed
* Composer and NPM is now used for external libraries like: Twig, PHPMailer, fast-route, jQuery, Bootstrap etc.
* mail support is disabled on fresh install, can be manually enabled by user
* disable add php pages in admin panel for security. Option to disable plugins upload
* visitors counter shows now user browser, and also if its bot
* changes in required and optional PHP extensions
* reworked Pages:
* Bans
* works now for TFS 1.x
* Highscores
* frags works for TFS 1.x
* cached
* Monsters
* moved pages to Twig:
* experience stages
* update player_deaths entries on name change
* change_password email to be more informal
### Fixed
* hundreds of bug fixes, mostly patched from 0.8, so it makes no sense writing them again here

55
CHANGELOG.md Normal file
View File

@@ -0,0 +1,55 @@
# Changelog
## [0.9.0-alpha - 02.06.2023]
Minimum PHP version for this release is 7.2.5.
### Added
* reworked Admin Panel (@Leesneaks, @gpedro, @slawkens)
* updated to Bootstrap v4
* new Menu
* new Dashboard: statistics, server status
* new Admin Bar showed on top when admin logged in
* new page: Server Data, to reload server data
* new pages: mass account & teleport tools
* changelogs editor
* revised Accounts & Players editors
* option to add/modify menus with plugins
* option to enable/disable plugins
* better, updated TinyMCE editor (v6.x)
* with option to upload images
* list of open source libraries used in project
* brand new charming installation page (by @fernandomatos)
* using Bootstrap
* new pages router: nikic/fast-route, allowing for better customisation
* Guild Wars support (available as plugin)
* support for login and create account only by email (configurable)
* with no need for account name
* Google ReCAPTCHA v3 support (available as plugin)
* automatically load towns names from .OTBM file
* support for Account Number
* suggest account number option
* many new functions, hooks and configurables
* better Exception Handler (Whoops - https://github.com/filp/whoops)
* add Cypress testing
### Changed
* Composer is now used for external libraries like: Twig, PHPMailer, fast-route etc.
* mail support is disabled on fresh install, can be manually enabled by user
* disable add php pages in admin panel for security. Option to disable plugins upload
* visitors counter shows now user browser, and also if its bot
* changes in required and optional PHP extensions
* reworked Pages:
* Bans
* works now for TFS 1.x
* Highscores
* frags works for TFS 1.x
* cached
* creatures
* moved pages to Twig:
* experience stages
* update player_deaths entries on name change
* change_password email to be more informal
### Fixed
* hundrets of bug fixes, mostly patched from 0.8, so it makes no sense writing them again here

View File

@@ -8,11 +8,7 @@ Fernando Matos <fernando@pixele.com.br>
Lee <42119604+Leesneaks@users.noreply.github.com> Lee <42119604+Leesneaks@users.noreply.github.com>
caio <caio.zucoli@gmail.com> caio <caio.zucoli@gmail.com>
slawkens <slawkens@gmail.com> slawkens <slawkens@gmail.com>
tobi132 <tobi132@gmx.net> tobi132 <52947952+tobi132@users.noreply.github.com>
vankk <nwtr.otland@hotmail.com> vankk <nwtr.otland@hotmail.com>
whiteblXK <krzys16001@gmail.com> whiteblXK <krzys16001@gmail.com>
xitobuh <jonas.hockert92@gmail.com> xitobuh <jonas.hockert92@gmail.com>
Danilo Pucci <dnlps@hotmail.com>
gpedro <gpedro831@gmail.com>
Matheus Collier <matheuscollier@gmail.com>
SRNT-GG <95472530+SRNT-GG@users.noreply.github.com>

View File

@@ -1,3 +1,3 @@
* Gesior.pl (2007 - 2008) * Gesior.pl (2007 - 2008)
* Slawkens (2009 - 2025) * Slawkens (2009 - 2023)
* Contributors listed in CONTRIBUTORS.txt * Contributors listed in CONTRIBUTORS.txt

View File

@@ -11,19 +11,20 @@ Official website: https://my-aac.org
[![Closed Issues](https://img.shields.io/github/issues-closed-raw/slawkens/myaac)](https://github.com/slawkens/myaac/issues?q=is%3Aissue+is%3Aclosed) [![Closed Issues](https://img.shields.io/github/issues-closed-raw/slawkens/myaac)](https://github.com/slawkens/myaac/issues?q=is%3Aissue+is%3Aclosed)
| Version | Status | Branch | Requirements | | Version | Status | Branch | Requirements |
|:--------|:-----------------------|:-------|:---------------| |:-----------|:------------------------------------------|:--------|:---------------|
| **1.x** | **Active development** | master | **PHP >= 8.1** | | **0.10.x** | **Active development** | develop | **PHP >= 8.0** |
| 0.9.x | Not developed anymore | 0.9 | PHP >= 7.2.5 | | 0.9.x | Active support | 0.9 | PHP >= 7.2.5 |
| 0.8.x | Active support | 0.8 | PHP >= 7.2.5 | | 0.8.x | Active support | master | PHP >= 7.2.5 |
| 0.7.x | End Of Life | 0.7 | PHP >= 5.3.3 | | 0.7.x | End Of Life | 0.7 | PHP >= 5.3.3 |
### Requirements ### Requirements
- PHP 8.0 or later
- MySQL database - MySQL database
- PHP Extensions: pdo, xml, json - PDO PHP Extension
- (optional) apache2 mod_rewrite (to use friendly_urls) - XML PHP Extension
- (optional) zip PHP Extension (to install plugins) - (optional) ZIP PHP Extension
- (optional) gd PHP Extension (for generating signature images) - (optional) mod_rewrite to use friendly_urls
### Installation ### Installation
@@ -47,8 +48,7 @@ Official website: https://my-aac.org
### Configuration ### Configuration
Check *config.php* to get more informations. (Notice: MyAAC 1.0+ doesn't use config.php anymore, it has been moved to Admin Panel - Settings page). Check *config.php* to get more informations.
Use *config.local.php* for your local configuration changes. Use *config.local.php* for your local configuration changes.
### Branches ### Branches

36
aac
View File

@@ -1,36 +0,0 @@
#!/usr/bin/env php
<?php
require_once __DIR__ . '/common.php';
if(!IS_CLI) {
echo 'This script can be run only in command line mode.';
exit(1);
}
require_once SYSTEM . 'functions.php';
define('SELF_NAME', basename(__FILE__));
use MyAAC\Plugins;
use Symfony\Component\Console\Application;
$application = new Application('MyAAC', MYAAC_VERSION);
$commandsGlob = glob(SYSTEM . 'src/Commands/*.php');
foreach ($commandsGlob as $item) {
$name = pathinfo($item, PATHINFO_FILENAME);
if ($name == 'Command') { // ignore base Command class
continue;
}
$commandPre = '\\MyAAC\Commands\\';
$application->add(new ($commandPre . $name));
}
$pluginCommands = Plugins::getCommands();
foreach ($pluginCommands as $item) {
$application->add(require $item);
}
$application->run();

View File

@@ -1,22 +0,0 @@
<?php
$hooks->register('debugbar_admin_head_end', HOOK_ADMIN_HEAD_END, function ($params) {
global $debugBar;
if (!isset($debugBar)) {
return;
}
$debugBarRenderer = $debugBar->getJavascriptRenderer(BASE_URL . 'vendor/maximebf/debugbar/src/DebugBar/Resources/');
echo $debugBarRenderer->renderHead();
});
$hooks->register('debugbar_admin_body_end', HOOK_ADMIN_BODY_END, function ($params) {
global $debugBar;
if (!isset($debugBar)) {
return;
}
$debugBarRenderer = $debugBar->getJavascriptRenderer(BASE_URL . 'vendor/maximebf/debugbar/src/DebugBar/Resources/');
echo $debugBarRenderer->render();
});

View File

@@ -1,7 +1,5 @@
<?php <?php
use MyAAC\Plugins;
$order = 10; $order = 10;
$settingsMenu = []; $settingsMenu = [];

View File

@@ -25,7 +25,11 @@ define('PAGE', $page);
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';
require SYSTEM . 'init.php'; require SYSTEM . 'init.php';
require __DIR__ . '/includes/debugbar.php'; // verify myaac tables exists in database
if(!$db->hasTable('myaac_account_actions')) {
throw new RuntimeException('Seems that the table <strong>myaac_account_actions</strong> of MyAAC doesn\'t exist in the database. This is a fatal error. You can try to reinstall MyAAC by visiting <a href="' . BASE_URL . 'install">this</a> url.');
}
require SYSTEM . 'status.php'; require SYSTEM . 'status.php';
require SYSTEM . 'login.php'; require SYSTEM . 'login.php';
require __DIR__ . '/includes/functions.php'; require __DIR__ . '/includes/functions.php';
@@ -45,7 +49,7 @@ if(!$logged || !admin()) {
// include our page // include our page
$file = __DIR__ . '/pages/' . $page . '.php'; $file = __DIR__ . '/pages/' . $page . '.php';
if(!@file_exists($file)) { if(!@file_exists($file)) {
if (str_contains($page, 'plugins/')) { if (strpos($page, 'plugins/') !== false) {
$file = BASE . $page; $file = BASE . $page;
} }
else { else {

View File

@@ -8,7 +8,6 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Models\Account as AccountModel;
use MyAAC\Models\Player; use MyAAC\Models\Player;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -23,7 +22,10 @@ $use_datatable = true;
if (setting('core.account_country')) if (setting('core.account_country'))
require SYSTEM . 'countries.conf.php'; require SYSTEM . 'countries.conf.php';
$nameOrNumberColumn = getAccountIdentityColumn(); $nameOrNumberColumn = 'name';
if (USE_ACCOUNT_NUMBER) {
$nameOrNumberColumn = 'number';
}
$hasSecretColumn = $db->hasColumn('accounts', 'secret'); $hasSecretColumn = $db->hasColumn('accounts', 'secret');
$hasCoinsColumn = $db->hasColumn('accounts', 'coins'); $hasCoinsColumn = $db->hasColumn('accounts', 'coins');
@@ -49,51 +51,36 @@ $acc_type = setting('core.account_types');
<?php <?php
$id = 0; $id = 0;
$search_account = $search_account_email = ''; $search_account = '';
if (isset($_REQUEST['id'])) if (isset($_REQUEST['id']))
$id = (int)$_REQUEST['id']; $id = (int)$_REQUEST['id'];
else if (isset($_REQUEST['search_email'])) {
$search_account_email = $_REQUEST['search_email'];
$accountModel = AccountModel::where('email', $search_account_email)->limit(11)->get(['email', 'id']);
if (count($accountModel) == 0) {
echo_error('No entries found.');
} else if (count($accountModel) == 1) {
$id = $accountModel->first()->getKey();
} else if (count($accountModel) > 10) {
echo_error('Specified e-mail resulted with too many accounts.');
}
}
else if (isset($_REQUEST['search'])) { else if (isset($_REQUEST['search'])) {
$search_account = $_REQUEST['search']; $search_account = $_REQUEST['search'];
$min_size = 3; if (strlen($search_account) < 3 && !Validator::number($search_account)) {
if (in_array($nameOrNumberColumn, ['id', 'number'])) { echo_error('Player name is too short.');
$min_size = 1;
}
if (strlen($search_account) < $min_size && !Validator::number($search_account)) {
echo_error('Account ' . $nameOrNumberColumn . ' is too short.');
} else { } else {
$query = AccountModel::where($nameOrNumberColumn, '=', $search_account)->limit(11)->get(['id', $nameOrNumberColumn]); $query = $db->query('SELECT `id` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` = ' . $db->quote($search_account));
if (count($query) == 0) { if ($query->rowCount() == 1) {
echo_error('No entries found.'); $query = $query->fetch();
} else if (count($query) == 1) { $id = (int)$query['id'];
$id = $query->first()->getKey();
} else if (count($query) > 10) {
echo_error('Specified name resulted with too many accounts.');
} else { } else {
$query = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` LIKE ' . $db->quote('%' . $search_account . '%'));
if ($query->rowCount() > 0 && $query->rowCount() <= 10) {
$str_construct = 'Do you mean?<ul class="mb-0">'; $str_construct = 'Do you mean?<ul class="mb-0">';
foreach ($query as $row) { foreach ($query as $row)
$str_construct .= '<li><a href="' . $admin_base . '&id=' . $row->getKey() . '">' . $row->attributes[$nameOrNumberColumn] . '</a></li>'; $str_construct .= '<li><a href="' . $admin_base . '&id=' . $row['id'] . '">' . $row[$nameOrNumberColumn] . '</a></li>';
}
$str_construct .= '</ul>'; $str_construct .= '</ul>';
echo_error($str_construct); echo_error($str_construct);
} else if ($query->rowCount() > 10)
echo_error('Specified name resulted with too many accounts.');
else
echo_error('No entries found.');
} }
} }
} }
?> ?>
<div class="row"> <div class="row">
<?php <?php
$groups = new OTS_Groups_List();
if ($id > 0) { if ($id > 0) {
$account = new OTS_Account(); $account = new OTS_Account();
$account->load($id); $account->load($id);
@@ -156,9 +143,7 @@ else if (isset($_REQUEST['search'])) {
$rl_loca = $_POST['rl_loca']; $rl_loca = $_POST['rl_loca'];
//country //country
if(setting('core.account_country')) {
$rl_country = $_POST['rl_country']; $rl_country = $_POST['rl_country'];
}
$web_flags = $_POST['web_flags']; $web_flags = $_POST['web_flags'];
verify_number($web_flags, 'Web Flags', 1); verify_number($web_flags, 'Web Flags', 1);
@@ -205,11 +190,7 @@ else if (isset($_REQUEST['search'])) {
} }
$account->setRLName($rl_name); $account->setRLName($rl_name);
$account->setLocation($rl_loca); $account->setLocation($rl_loca);
if(setting('core.account_country')) {
$account->setCountry($rl_country); $account->setCountry($rl_country);
}
$account->setCustomField('created', $created); $account->setCustomField('created', $created);
$account->setWebFlags($web_flags); $account->setWebFlags($web_flags);
$account->setCustomField('web_lastlogin', $web_lastlogin); $account->setCustomField('web_lastlogin', $web_lastlogin);
@@ -233,7 +214,7 @@ else if (isset($_REQUEST['search'])) {
} }
} }
} else if ($id == 0) { } else if ($id == 0) {
$accounts_db = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '`' . ($hasTypeColumn ? ',type' : ($hasGroupColumn ? ',group_id' : '')) . ', email FROM `accounts` ORDER BY `id` ASC'); $accounts_db = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '`' . ($hasTypeColumn ? ',type' : ($hasGroupColumn ? ',group_id' : '')) . ' FROM `accounts` ORDER BY `id` ASC');
?> ?>
<div class="col-12 col-sm-12 col-lg-10"> <div class="col-12 col-sm-12 col-lg-10">
<div class="card card-info card-outline"> <div class="card card-info card-outline">
@@ -245,9 +226,8 @@ else if (isset($_REQUEST['search'])) {
<thead> <thead>
<tr> <tr>
<th>ID</th> <th>ID</th>
<th><?= ($nameOrNumberColumn == 'name' ? 'Name' : 'Number'); ?></th> <th><?= ($nameOrNumberColumn == 'number' ? 'Number' : 'Name'); ?></th>
<?php if($hasTypeColumn || $hasGroupColumn): ?> <?php if($hasTypeColumn || $hasGroupColumn): ?>
<th>E-Mail</th>
<th>Position</th> <th>Position</th>
<?php endif; ?> <?php endif; ?>
<th style="width: 40px">Edit</th> <th style="width: 40px">Edit</th>
@@ -258,7 +238,6 @@ else if (isset($_REQUEST['search'])) {
<tr> <tr>
<th><?php echo $account_lst['id']; ?></th> <th><?php echo $account_lst['id']; ?></th>
<td><?php echo $account_lst[$nameOrNumberColumn]; ?></a></td> <td><?php echo $account_lst[$nameOrNumberColumn]; ?></a></td>
<td><?php echo $account_lst['email']; ?></td>
<?php if($hasTypeColumn || $hasGroupColumn): ?> <?php if($hasTypeColumn || $hasGroupColumn): ?>
<td> <td>
<?php if ($hasTypeColumn) { <?php if ($hasTypeColumn) {
@@ -312,7 +291,7 @@ else if (isset($_REQUEST['search'])) {
<div class="card-body"> <div class="card-body">
<div class="tab-content" id="accounts-tabContent"> <div class="tab-content" id="accounts-tabContent">
<div class="tab-pane fade active show" id="accounts-acc"> <div class="tab-pane fade active show" id="accounts-acc">
<form action="<?php echo $admin_base . ($id > 0 ? '&id=' . $id : ''); ?>" method="post"> <form action="<?php echo $admin_base . ((isset($id) && $id > 0) ? '&id=' . $id : ''); ?>" method="post">
<?php csrf(); ?> <?php csrf(); ?>
<div class="form-group row"> <div class="form-group row">
<?php if (USE_ACCOUNT_NAME): ?> <?php if (USE_ACCOUNT_NAME): ?>
@@ -425,7 +404,6 @@ else if (isset($_REQUEST['search'])) {
autocomplete="off" maxlength="20" autocomplete="off" maxlength="20"
value="<?php echo $account->getLocation(); ?>"/> value="<?php echo $account->getLocation(); ?>"/>
</div> </div>
<?php if(setting('core.account_country')): ?>
<div class="col-12 col-sm-12 col-lg-4"> <div class="col-12 col-sm-12 col-lg-4">
<label for="rl_country">Country:</label> <label for="rl_country">Country:</label>
<select name="rl_country" id="rl_country" class="form-control"> <select name="rl_country" id="rl_country" class="form-control">
@@ -434,7 +412,6 @@ else if (isset($_REQUEST['search'])) {
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
</div> </div>
<?php endif; ?>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
@@ -606,16 +583,6 @@ else if (isset($_REQUEST['search'])) {
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="row"> <div class="row">
<div class="col-6 col-lg-12">
<form action="<?php echo $admin_base; ?>" method="post">
<?php csrf(); ?>
<label for="search">Account E-Mail:</label>
<div class="input-group input-group-sm">
<input type="email" class="form-control" id="search_email" name="search_email" value="<?= escapeHtml($search_account_email); ?>" maxlength="255" size="255">
<span class="input-group-append"><button type="submit" class="btn btn-info btn-flat">Search</button></span>
</div>
</form>
</div>
<div class="col-6 col-lg-12"> <div class="col-6 col-lg-12">
<form action="<?php echo $admin_base; ?>" method="post"> <form action="<?php echo $admin_base; ?>" method="post">
<?php csrf(); ?> <?php csrf(); ?>

View File

@@ -9,7 +9,6 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Changelog;
use MyAAC\Models\Changelog as ModelsChangelog; use MyAAC\Models\Changelog as ModelsChangelog;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -27,8 +26,9 @@ $use_datatable = true;
const CL_LIMIT = 600; // maximum changelog body length const CL_LIMIT = 600; // maximum changelog body length
$id = $_GET['id'] ?? 0; $id = $_GET['id'] ?? 0;
require_once LIBS . 'changelog.php';
if(!empty($action) && isRequestMethod('post')) if(!empty($action))
{ {
$id = $_POST['id'] ?? null; $id = $_POST['id'] ?? null;
$body = isset($_POST['body']) ? stripslashes($_POST['body']) : null; $body = isset($_POST['body']) ? stripslashes($_POST['body']) : null;
@@ -73,7 +73,7 @@ if(!empty($action) && isRequestMethod('post'))
} }
} }
else if($action == 'hide') { else if($action == 'hide') {
if (Changelog::toggleHide($id, $errors, $status)) { if (Changelog::toggleHidden($id, $errors, $status)) {
success(($status == 1 ? 'Hide' : 'Show') . ' successful.'); success(($status == 1 ? 'Hide' : 'Show') . ' successful.');
} }
} }

View File

@@ -7,9 +7,6 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Models\Account;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Mailer'; $title = 'Mailer';
@@ -64,15 +61,15 @@ if (!empty($mail_content) && !empty($mail_subject) && empty($mail_to)) {
$add = ' AND `email_verified` = 1'; $add = ' AND `email_verified` = 1';
} }
$query = Account::where('email', '!=', '')->get(['email']); $query = $db->query('SELECT `email` FROM `accounts` WHERE `email` != ""' . $add);
foreach ($query as $email) { foreach ($query as $email) {
if (_mail($email->email, $mail_subject, $mail_content)) { if (_mail($email['email'], $mail_subject, $mail_content)) {
$success++; $success++;
} }
else { else {
$failed++; $failed++;
echo '<br />'; echo '<br />';
error('An error occorred while sending email to <b>' . $email->email . '</b>. For Admin: More info can be found in system/logs/mailer-error.log'); error('An error occorred while sending email to <b>' . $email['email'] . '</b>. For Admin: More info can be found in system/logs/mailer-error.log');
} }
} }

View File

@@ -24,13 +24,20 @@ $freePremium = $config['lua']['freePremium'];
function admin_give_points($points) function admin_give_points($points)
{ {
global $hasPointsColumn; global $db, $hasPointsColumn;
if (!$hasPointsColumn) { if (!$hasPointsColumn) {
displayMessage('Points not supported.'); displayMessage('Points not supported.');
return; return;
} }
$statement = $db->prepare('UPDATE `accounts` SET `premium_points` = `premium_points` + :points');
if (!$statement) {
displayMessage('Failed to prepare query statement.');
return;
}
if (!Account::query()->increment('premium_points', $points)) { if (!Account::query()->increment('premium_points', $points)) {
displayMessage('Failed to add points.'); displayMessage('Failed to add points.');
return; return;
@@ -40,7 +47,7 @@ function admin_give_points($points)
function admin_give_coins($coins) function admin_give_coins($coins)
{ {
global $hasCoinsColumn; global $db, $hasCoinsColumn;
if (!$hasCoinsColumn) { if (!$hasCoinsColumn) {
displayMessage('Coins not supported.'); displayMessage('Coins not supported.');
@@ -55,6 +62,24 @@ function admin_give_coins($coins)
displayMessage($coins . ' coins added to all accounts.', true); displayMessage($coins . ' coins added to all accounts.', true);
} }
function query_add_premium($column, $value_query, $condition_query = '1=1', $params = [])
{
global $db;
$statement = $db->prepare("UPDATE `accounts` SET `{$column}` = $value_query WHERE $condition_query");
if (!$statement) {
displayMessage('Failed to prepare query statement.');
return false;
}
if (!$statement->execute($params)) {
displayMessage('Failed to add premium days.');
return false;
}
return true;
}
function admin_give_premdays($days) function admin_give_premdays($days)
{ {
global $db, $freePremium; global $db, $freePremium;
@@ -69,9 +94,9 @@ function admin_give_premdays($days)
// othire // othire
if ($db->hasColumn('accounts', 'premend')) { if ($db->hasColumn('accounts', 'premend')) {
// append premend // append premend
if (Account::where('premend', '>', $now)->increment('premend', $value)) { if (query_add_premium('premend', '`premend` + :value', '`premend` > :now', ['value' => $value, 'now' => $now])) {
// set premend // set premend
if (Account::where('premend', '<=', $now)->update(['premend' => $now + $value])) { if (query_add_premium('premend', ':value', '`premend` <= :now', ['value' => $now + $value, 'now' => $now])) {
displayMessage($days . ' premium days added to all accounts.', true); displayMessage($days . ' premium days added to all accounts.', true);
return; return;
} else { } else {
@@ -89,11 +114,11 @@ function admin_give_premdays($days)
// tfs 0.x // tfs 0.x
if ($db->hasColumn('accounts', 'premdays')) { if ($db->hasColumn('accounts', 'premdays')) {
// append premdays // append premdays
if (Account::query()->update(['premdays' => $days])) { if (query_add_premium('premdays', '`premdays` + :value', '1=1', ['value' => $days])) {
// append lastday // append lastday
if (Account::where('lastday', '>', $now)->increment('lastday', $value)) { if (query_add_premium('lastday', '`lastday` + :value', '`lastday` > :now', ['value' => $value, 'now' => $now])) {
// set lastday // set lastday
if (Account::where('lastday', '<=', $now)->update(['lastday' => $now + $value])) { if (query_add_premium('lastday', ':value', '`lastday` <= :now', ['value' => $now + $value, 'now' => $now])) {
displayMessage($days . ' premium days added to all accounts.', true); displayMessage($days . ' premium days added to all accounts.', true);
return; return;
} else { } else {
@@ -117,9 +142,9 @@ function admin_give_premdays($days)
// tfs 1.x // tfs 1.x
if ($db->hasColumn('accounts', 'premium_ends_at')) { if ($db->hasColumn('accounts', 'premium_ends_at')) {
// append premium_ends_at // append premium_ends_at
if (Account::where('premium_ends_at', '>', $now)->increment('premium_ends_at', $value)) { if (query_add_premium('premium_ends_at', '`premium_ends_at` + :value', '`premium_ends_at` > :now', ['value' => $value, 'now' => $now])) {
// set premium_ends_at // set premium_ends_at
if (Account::where('premium_ends_at', '<=', $now)->update(['premium_ends_at' => $now + $value])) { if (query_add_premium('premium_ends_at', ':value', '`premium_ends_at` <= :now', ['value' => $now + $value, 'now' => $now])) {
displayMessage($days . ' premium days added to all accounts.', true); displayMessage($days . ' premium days added to all accounts.', true);
return; return;
} else { } else {
@@ -137,9 +162,9 @@ function admin_give_premdays($days)
displayMessage('Premium Days not supported.'); displayMessage('Premium Days not supported.');
} }
if (!empty(ACTION) && isRequestMethod('post')) { if (isset($_POST['action']) && $_POST['action']) {
$action = ACTION; $action = $_POST['action'];
if (preg_match("/[^A-z0-9_\-]/", $action)) { if (preg_match("/[^A-z0-9_\-]/", $action)) {
displayMessage('Invalid action.'); displayMessage('Invalid action.');

View File

@@ -40,9 +40,9 @@ function admin_teleport_town($town_id) {
displayMessage('Player\'s town updated.', true); displayMessage('Player\'s town updated.', true);
} }
if (!empty(ACTION) && isRequestMethod('post')) { if (isset($_POST['action']) && $_POST['action']) {
$action = ACTION; $action = $_POST['action'];
if (preg_match("/[^A-z0-9_\-]/", $action)) { if (preg_match("/[^A-z0-9_\-]/", $action)) {
displayMessage('Invalid action.'); displayMessage('Invalid action.');

View File

@@ -8,9 +8,7 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Cache\Cache;
use MyAAC\Models\Menu; use MyAAC\Models\Menu;
use MyAAC\Plugins;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Menus'; $title = 'Menus';
@@ -22,16 +20,14 @@ if (!hasFlag(FLAG_CONTENT_MENUS) && !superAdmin()) {
return; return;
} }
$pluginThemes = Plugins::getThemes();
if (isset($_POST['template'])) { if (isset($_POST['template'])) {
$template = $_POST['template']; $template = $_POST['template'];
if (isset($_POST['save'])) { if (isset($_POST['menu'])) {
$post_menu = $_POST['menu'] ?? []; $post_menu = $_POST['menu'];
$post_menu_link = $_POST['menu_link'] ?? []; $post_menu_link = $_POST['menu_link'];
$post_menu_blank = $_POST['menu_blank'] ?? []; $post_menu_blank = $_POST['menu_blank'];
$post_menu_color = $_POST['menu_color'] ?? []; $post_menu_color = $_POST['menu_color'];
if (count($post_menu) != count($post_menu_link)) { if (count($post_menu) != count($post_menu_link)) {
echo 'Menu count is not equal menu links. Something went wrong when sending form.'; echo 'Menu count is not equal menu links. Something went wrong when sending form.';
return; return;
@@ -59,67 +55,54 @@ if (isset($_POST['template'])) {
} }
} }
onTemplateMenusChange(); $cache = Cache::getInstance();
if ($cache->enabled()) {
$cache->delete('template_menus');
}
success('Saved at ' . date('H:i')); success('Saved at ' . date('H:i'));
} }
$path = TEMPLATES . $template; $file = TEMPLATES . $template . '/config.php';
if (file_exists($file)) {
if (isset($pluginThemes[$template])) { require_once $file;
$path = BASE . $pluginThemes[$template];
}
$path .= '/config.php';
if (file_exists($path)) {
require_once $path;
} else { } else {
echo 'Cannot find template config.php file.'; echo 'Cannot find template config.php file.';
return; return;
} }
if (isset($_GET['reset_colors'])) {
if (isset($config['menu_default_color'])) {
Menu::where('template', $template)->update(['color' => str_replace('#', '', $config['menu_default_color'])]);
success('Colors has been reset.');
}
else {
warning('There is no default color defined, cannot reset colors.');
}
}
if (!isset($config['menu_categories'])) { if (!isset($config['menu_categories'])) {
echo "No menu categories set in template config.php.<br/>This template doesn't support dynamic menus."; echo "No menu categories set in template config.php.<br/>This template doesn't support dynamic menus.";
return; return;
} }
if (isset($_GET['reset_colors'])) {
foreach ($config['menu_categories'] as $id => $options) {
$color = $options['default_links_color'] ?? ($config['menu_default_links_color'] ?? ($config['menu_default_color'] ?? '#ffffff'));
Menu::where('template', $template)->where('category', $id)->update(['color' => str_replace('#', '', $color)]);
}
onTemplateMenusChange();
success('Colors has been reset at ' . date('H:i'));
}
if (isset($_GET['reset_menus'])) {
$configMenus = config('menus');
if (isset($configMenus)) {
Plugins::installMenus($template, config('menus'), true);
onTemplateMenusChange();
success('Menus has been reset at ' . date('H:i'));
}
else {
error("This template don't support reinstalling menus.");
}
}
$title = 'Menus - ' . $template; $title = 'Menus - ' . $template;
$canResetColors = isset($config['menu_default_color']) || isset($config['menu_default_links_color']);
foreach ($config['menu_categories'] as $id => $options) {
if (isset($options['default_links_color'])) {
$canResetColors = true;
}
}
$twig->display('admin.menus.header.html.twig', [
'template' => $template,
'canResetColors' => $canResetColors
]);
?> ?>
<div align="center" class="text-center">
<p class="note">You are editing: <?= $template ?><br/><br/>
Hint: You can drag menu items.<br/>
Hint: Add links to external sites using: <b>http://</b> or <b>https://</b> prefix.<br/>
Not all templates support blank and colorful links.
</p>
<?php if (isset($config['menu_default_color'])) {?>
<form method="post" action="?p=menus&reset_colors" onsubmit="return confirm('Do you really want to reset colors?');">
<?php csrf(); ?>
<input type="hidden" name="template" value="<?php echo $template ?>"/>
<button type="submit" class="btn btn-danger">Reset Colors to default</button>
</form>
<br/>
<?php } ?>
</div>
<?php <?php
$menus = Menu::query() $menus = Menu::query()
->select('name', 'link', 'blank', 'color', 'category', 'ordering') ->select('name', 'link', 'blank', 'color', 'category', 'ordering')
@@ -135,7 +118,7 @@ if (isset($_POST['template'])) {
<form method="post" id="menus-form" action="?p=menus"> <form method="post" id="menus-form" action="?p=menus">
<?php csrf(); ?> <?php csrf(); ?>
<input type="hidden" name="template" value="<?php echo $template ?>"/> <input type="hidden" name="template" value="<?php echo $template ?>"/>
<button type="submit" name="save" class="btn btn-info">Save</button><br/><br/> <button type="submit" class="btn btn-info">Save</button><br/><br/>
<div class="row"> <div class="row">
<?php foreach ($config['menu_categories'] as $id => $cat): ?> <?php foreach ($config['menu_categories'] as $id => $cat): ?>
<div class="col-md-12 col-lg-6"> <div class="col-md-12 col-lg-6">
@@ -149,13 +132,12 @@ if (isset($_POST['template'])) {
if (isset($menus[$id])) { if (isset($menus[$id])) {
$i = 0; $i = 0;
foreach ($menus[$id] as $menu): foreach ($menus[$id] as $menu):
$color = (empty($menu['color']) ? ($cat['default_links_color'] ?? ($config['menu_default_links_color'] ?? ($config['menu_default_color'] ?? '#ffffff'))) : '#' . $menu['color']);
?> ?>
<li class="ui-state-default" id="list-<?php echo $id ?>-<?php echo $i ?>"><label>Name:</label> <input type="text" name="menu[<?php echo $id ?>][]" value="<?php echo escapeHtml($menu['name']); ?>"/> <li class="ui-state-default" id="list-<?php echo $id ?>-<?php echo $i ?>"><label>Name:</label> <input type="text" name="menu[<?php echo $id ?>][]" value="<?php echo escapeHtml($menu['name']); ?>"/>
<label>Link:</label> <input type="text" name="menu_link[<?php echo $id ?>][]" value="<?php echo $menu['link'] ?>"/> <label>Link:</label> <input type="text" name="menu_link[<?php echo $id ?>][]" value="<?php echo $menu['link'] ?>"/>
<input type="hidden" name="menu_blank[<?php echo $id ?>][]" value="0"/> <input type="hidden" name="menu_blank[<?php echo $id ?>][]" value="0"/>
<label><input class="blank-checkbox" type="checkbox" <?php echo($menu['blank'] == 1 ? 'checked' : '') ?>/><span title="Open in New Window">New Window</span></label> <label><input class="blank-checkbox" type="checkbox" <?php echo($menu['blank'] == 1 ? 'checked' : '') ?>/><span title="Open in New Window">New Window</span></label>
<input class="color-picker" type="text" name="menu_color[<?php echo $id ?>][]" value="<?php echo $color; ?>"/> <input class="color-picker" type="text" name="menu_color[<?php echo $id ?>][]" value="<?php echo (empty($menu['color']) ? ($config['menu_default_color'] ?? '#ffffff') : $menu['color']); ?>"/>
<a class="remove-button" id="remove-button-<?php echo $id ?>-<?php echo $i ?>"><i class="fas fa-trash"></a></i></li> <a class="remove-button" id="remove-button-<?php echo $id ?>-<?php echo $i ?>"><i class="fas fa-trash"></a></i></li>
<?php $i++; $last_id[$id] = $i; <?php $i++; $last_id[$id] = $i;
endforeach; endforeach;
@@ -168,7 +150,7 @@ if (isset($_POST['template'])) {
</div> </div>
<div class="row pb-2"> <div class="row pb-2">
<div class="col-md-12"> <div class="col-md-12">
<button type="submit" name="save" class="btn btn-info">Save</button> <button type="submit" class="btn btn-info">Save</button>
<?php <?php
echo '<button type="button" class="btn btn-danger float-right" value="Cancel" onclick="window.location = \'' . ADMIN_URL . '?p=menus\';"><i class="fas fa-cancel"></i> Cancel</button>'; echo '<button type="button" class="btn btn-danger float-right" value="Cancel" onclick="window.location = \'' . ADMIN_URL . '?p=menus\';"><i class="fas fa-cancel"></i> Cancel</button>';
?> ?>
@@ -179,19 +161,15 @@ if (isset($_POST['template'])) {
$twig->display('admin.menus.js.html.twig', array( $twig->display('admin.menus.js.html.twig', array(
'menus' => $menus, 'menus' => $menus,
'last_id' => $last_id, 'last_id' => $last_id,
'menu_default_color' => $config['menu_default_color'] ?? '#ffffff'
)); ));
?> ?>
<?php <?php
} else { } else {
$templates = Menu::select('template')->distinct()->get()->toArray(); $templates = Menu::select('template')->distinct()->get()->toArray();
foreach ($templates as $key => $value) { foreach ($templates as $key => $value) {
$path = TEMPLATES . $value['template']; $file = TEMPLATES . $value['template'] . '/config.php';
if (!file_exists($file)) {
if (isset($pluginThemes[$value['template']])) {
$path = BASE . $pluginThemes[$value['template']];
}
if (!file_exists($path . '/config.php')) {
unset($templates[$key]); unset($templates[$key]);
} }
} }
@@ -200,11 +178,3 @@ if (isset($_POST['template'])) {
'templates' => $templates 'templates' => $templates
)); ));
} }
function onTemplateMenusChange(): void
{
$cache = Cache::getInstance();
if ($cache->enabled()) {
$cache->delete('template_menus');
}
}

View File

@@ -7,7 +7,7 @@ defined('MYAAC') or die('Direct access not allowed!');
$accounts = 0; $accounts = 0;
if ($db->hasColumn('accounts', 'created')) { if ($db->hasColumn('accounts', 'created')) {
$accounts = Account::orderByDesc('created')->limit(10)->get(['id', 'created'])->toArray(); $accounts = Account::orderByDesc('created')->limit(10)->get(['created', (USE_ACCOUNT_NAME ? 'name' : 'id')])->toArray();
} }
$twig->display('created.html.twig', array( $twig->display('created.html.twig', array(

View File

@@ -19,7 +19,7 @@
{% set i = i + 1 %} {% set i = i + 1 %}
<tr> <tr>
<th>{{ i }}</th> <th>{{ i }}</th>
<td><a href="?p=accounts&id={{ result.id }}">{{ result.id }}</a></td> <td><a href="?p=accounts&search_name={{ result.name }}">{{ result.name }}</a></td>
<td>{{ result.created|date("M d Y, H:i:s") }}</td> <td>{{ result.created|date("M d Y, H:i:s") }}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@@ -7,10 +7,6 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Forum;
use MyAAC\News;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'News Panel'; $title = 'News Panel';
@@ -19,6 +15,9 @@ csrfProtect();
$use_datatable = true; $use_datatable = true;
require_once LIBS . 'forum.php';
require_once LIBS . 'news.php';
if (!hasFlag(FLAG_CONTENT_PAGES) && !superAdmin()) { if (!hasFlag(FLAG_CONTENT_PAGES) && !superAdmin()) {
echo 'Access denied.'; echo 'Access denied.';
return; return;
@@ -26,7 +25,7 @@ if (!hasFlag(FLAG_CONTENT_PAGES) && !superAdmin()) {
header('X-XSS-Protection:0'); header('X-XSS-Protection:0');
// some constants, used mainly by database (cannot be modified without schema changes) // some constants, used mainly by database (cannot by modified without schema changes)
const NEWS_TITLE_LIMIT = 100; const NEWS_TITLE_LIMIT = 100;
const NEWS_BODY_LIMIT = 65535; // maximum news body length const NEWS_BODY_LIMIT = 65535; // maximum news body length
const ARTICLE_TEXT_LIMIT = 300; const ARTICLE_TEXT_LIMIT = 300;
@@ -47,24 +46,26 @@ if(!empty($action))
$forum_section = $_POST['forum_section'] ?? null; $forum_section = $_POST['forum_section'] ?? null;
$errors = []; $errors = [];
if (isRequestMethod('post')) { if($action == 'new') {
if ($action == 'new') { if(isset($forum_section) && $forum_section != '-1') {
if (isset($forum_section) && $forum_section != '-1') {
$forum_add = Forum::add_thread($p_title, $body, $forum_section, $player_id, $account_logged->getId(), $errors); $forum_add = Forum::add_thread($p_title, $body, $forum_section, $player_id, $account_logged->getId(), $errors);
} }
if (isset($p_title) && News::add($p_title, $body, $type, $category, $player_id, isset($forum_add) && $forum_add != 0 ? $forum_add : 0, $article_text, $article_image, $errors)) { if(isset($p_title) && News::add($p_title, $body, $type, $category, $player_id, isset($forum_add) && $forum_add != 0 ? $forum_add : 0, $article_text, $article_image, $errors)) {
$p_title = $body = $comments = $article_text = $article_image = ''; $p_title = $body = $comments = $article_text = $article_image = '';
$type = $category = $player_id = 0; $type = $category = $player_id = 0;
success('Added successful.'); success('Added successful.');
} }
} else if ($action == 'delete') { }
else if($action == 'delete') {
if (News::delete($id, $errors)) { if (News::delete($id, $errors)) {
success('Deleted successful.'); success('Deleted successful.');
} }
} else if ($action == 'edit') { }
if (isset($id) && !isset($p_title)) { else if($action == 'edit')
{
if(isset($id) && !isset($p_title)) {
$news = News::get($id); $news = News::get($id);
$p_title = $news['title']; $p_title = $news['title'];
$body = $news['body']; $body = $news['body'];
@@ -74,11 +75,12 @@ if(!empty($action))
$player_id = $news['player_id']; $player_id = $news['player_id'];
$article_text = $news['article_text']; $article_text = $news['article_text'];
$article_image = $news['article_image']; $article_image = $news['article_image'];
} else { }
if (News::update($id, $p_title, $body, $type, $category, $player_id, $forum_section, $article_text, $article_image, $errors)) { else {
if(News::update($id, $p_title, $body, $type, $category, $player_id, $forum_section, $article_text, $article_image, $errors)) {
// update forum thread if exists // update forum thread if exists
if (isset($forum_section) && Validator::number($forum_section)) { if(isset($forum_section) && Validator::number($forum_section)) {
$db->query("UPDATE `" . TABLE_PREFIX . "forum` SET `author_guid` = " . (int)$player_id . ", `post_text` = " . $db->quote($body) . ", `post_topic` = " . $db->quote($p_title) . ", `edit_date` = " . time() . " WHERE `id` = " . $db->quote($forum_section)); $db->query("UPDATE `" . TABLE_PREFIX . "forum` SET `author_guid` = ".(int) $player_id.", `post_text` = ".$db->quote($body).", `post_topic` = ".$db->quote($p_title).", `edit_date` = " . time() . " WHERE `id` = " . $db->quote($forum_section));
} }
$action = $p_title = $body = $comments = $article_text = $article_image = ''; $action = $p_title = $body = $comments = $article_text = $article_image = '';
@@ -87,10 +89,10 @@ if(!empty($action))
success('Updated successful.'); success('Updated successful.');
} }
} }
} else if ($action == 'hide') {
if (News::toggleHide($id, $errors, $status)) {
success(($status == 1 ? 'Hide' : 'Show') . ' successful.');
} }
else if($action == 'hide') {
if (News::toggleHidden($id, $errors, $status)) {
success(($status == 1 ? 'Hide' : 'Show') . ' successful.');
} }
} }
@@ -99,7 +101,7 @@ if(!empty($action))
} }
$categories = array(); $categories = array();
foreach($db->query('SELECT `id`, `name`, `icon_id` FROM `' . TABLE_PREFIX . 'news_categories` WHERE `hide` != 1') as $cat) foreach($db->query('SELECT `id`, `name`, `icon_id` FROM `' . TABLE_PREFIX . 'news_categories` WHERE `hidden` != 1') as $cat)
{ {
$categories[$cat['id']] = array( $categories[$cat['id']] = array(
'name' => $cat['name'], 'name' => $cat['name'],
@@ -136,27 +138,18 @@ if($action == 'edit' || $action == 'new') {
$query = $db->query('SELECT * FROM ' . $db->tableName(TABLE_PREFIX . 'news')); $query = $db->query('SELECT * FROM ' . $db->tableName(TABLE_PREFIX . 'news'));
$newses = array(); $newses = array();
$cachePlayers = [];
foreach ($query as $_news) { foreach ($query as $_news) {
$playerId = $_news['player_id'];
if (isset($cachePlayers[$playerId])) {
$_player = $cachePlayers[$playerId];
}
else {
$_player = new OTS_Player(); $_player = new OTS_Player();
$_player->load($playerId); $_player->load($_news['player_id']);
$cachePlayers[$playerId] = $_player;
}
$newses[$_news['type']][] = array( $newses[$_news['type']][] = array(
'id' => $_news['id'], 'id' => $_news['id'],
'hide' => $_news['hide'], 'hidden' => $_news['hidden'],
'archive_link' => getLink('news') . '/archive/' . $_news['id'], 'archive_link' => getLink('news') . '/archive/' . $_news['id'],
'title' => $_news['title'], 'title' => $_news['title'],
'date' => $_news['date'], 'date' => $_news['date'],
'player_name' => $_player->isLoaded() ? $_player->getName() : '', 'player_name' => isset($_player) && $_player->isLoaded() ? $_player->getName() : '',
'player_link' => $_player->isLoaded() ? getPlayerLink($_player, false) : '', 'player_link' => isset($_player) && $_player->isLoaded() ? getPlayerLink($_player->getName(), false) : '',
); );
} }

View File

@@ -16,7 +16,7 @@ $title = 'Notepad';
csrfProtect(); csrfProtect();
/** /**
* @var OTS_Account $account_logged * @var $account_logged OTS_Account
*/ */
$_content = ''; $_content = '';
$notepad = ModelsNotepad::where('account_id', $account_logged->getId())->first(); $notepad = ModelsNotepad::where('account_id', $account_logged->getId())->first();

View File

@@ -36,7 +36,7 @@ const PAGE_TITLE_LIMIT = 30;
const PAGE_NAME_LIMIT = 30; const PAGE_NAME_LIMIT = 30;
const PAGE_BODY_LIMIT = 65535; // maximum page body length const PAGE_BODY_LIMIT = 65535; // maximum page body length
if (!empty($action) && isRequestMethod('post')) { if (!empty($action)) {
if ($action == 'delete' || $action == 'edit' || $action == 'hide') { if ($action == 'delete' || $action == 'edit' || $action == 'hide') {
$id = $_POST['id']; $id = $_POST['id'];
} }
@@ -50,7 +50,7 @@ if (!empty($action) && isRequestMethod('post')) {
} }
$php = isset($_POST['php']) && $_POST['php'] == 1; $php = isset($_POST['php']) && $_POST['php'] == 1;
$enable_tinymce = (isset($_POST['enable_tinymce']) && $_POST['enable_tinymce'] == 1) ?: $enable_tinymce; $enable_tinymce = isset($_POST['enable_tinymce']) && $_POST['enable_tinymce'] == 1;
if ($php) { if ($php) {
$body = $_POST['body']; $body = $_POST['body'];
} }
@@ -97,7 +97,7 @@ if (!empty($action) && isRequestMethod('post')) {
} }
} }
} else if ($action == 'hide') { } else if ($action == 'hide') {
if (Pages::toggleHide($id, $errors, $status)) { if (Pages::toggleHidden($id, $errors, $status)) {
success(($status == 0 ? 'Show' : 'Hide') . ' successful.'); success(($status == 0 ? 'Show' : 'Hide') . ' successful.');
} }
} }
@@ -112,7 +112,7 @@ $pages = ModelsPages::all()->map(function ($e) {
'title' => substr($e->title, 0, 20), 'title' => substr($e->title, 0, 20),
'php' => $e->php == '1', 'php' => $e->php == '1',
'id' => $e->id, 'id' => $e->id,
'hide' => $e->hide 'hidden' => $e->hidden
]; ];
})->toArray(); })->toArray();

View File

@@ -8,7 +8,6 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Forum;
use MyAAC\Models\Player; use MyAAC\Models\Player;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -20,6 +19,7 @@ csrfProtect();
$player_base = ADMIN_URL . '?p=players'; $player_base = ADMIN_URL . '?p=players';
$use_datatable = true; $use_datatable = true;
require_once LIBS . 'forum.php';
$skills = array( $skills = array(
POT::SKILL_FIST => array('Fist fighting', 'fist'), POT::SKILL_FIST => array('Fist fighting', 'fist'),
@@ -51,20 +51,22 @@ else if (isset($_REQUEST['search'])) {
if (strlen($search_player) < 3 && !Validator::number($search_player)) { if (strlen($search_player) < 3 && !Validator::number($search_player)) {
echo_error('Player name is too short.'); echo_error('Player name is too short.');
} else { } else {
$query = Player::where('name', 'like', '%' . $search_player . '%')->orderBy('name')->limit(11)->get(['id', 'name']); $query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($search_player));
if (count($query) == 0) { if ($query->rowCount() == 1) {
echo_error('No entries found.'); $query = $query->fetch();
} else if (count($query) == 1) { $id = (int)$query['id'];
$id = $query->first()->getKey();
} else if (count($query) > 10) {
echo_error('Specified name resulted with too many players.');
} else { } else {
$query = $db->query('SELECT `id`, `name` FROM `players` WHERE `name` LIKE ' . $db->quote('%' . $search_player . '%'));
if ($query->rowCount() > 0 && $query->rowCount() <= 10) {
$str_construct = 'Do you mean?<ul>'; $str_construct = 'Do you mean?<ul>';
foreach ($query as $row) { foreach ($query as $row)
$str_construct .= '<li><a href="' . $player_base . '&id=' . $row->getKey() . '">' . $row->name . '</a></li>'; $str_construct .= '<li><a href="' . $player_base . '&id=' . $row['id'] . '">' . $row['name'] . '</a></li>';
}
$str_construct .= '</ul>'; $str_construct .= '</ul>';
echo_error($str_construct); echo_error($str_construct);
} else if ($query->rowCount() > 10)
echo_error('Specified name resulted with too many players.');
else
echo_error('No entries found.');
} }
} }
} }
@@ -200,7 +202,7 @@ else if (isset($_REQUEST['search'])) {
if ($hasBlessingsColumn) { if ($hasBlessingsColumn) {
$blessings = $_POST['blessings']; $blessings = $_POST['blessings'];
verify_number($blessings, 'Blessings', 3); verify_number($blessings, 'Blessings', 2);
} }
$balance = $_POST['balance']; $balance = $_POST['balance'];
@@ -211,7 +213,7 @@ else if (isset($_REQUEST['search'])) {
} }
$deleted = (isset($_POST['deleted']) && $_POST['deleted'] == 'true'); $deleted = (isset($_POST['deleted']) && $_POST['deleted'] == 'true');
$hide = (isset($_POST['hide']) && $_POST['hide'] == 'true'); $hidden = (isset($_POST['hidden']) && $_POST['hidden'] == 'true');
$created = strtotime($_POST['created']); $created = strtotime($_POST['created']);
verify_number($created, 'Created', 11); verify_number($created, 'Created', 11);
@@ -272,7 +274,7 @@ else if (isset($_REQUEST['search'])) {
$player->setLossContainers($loss_containers); $player->setLossContainers($loss_containers);
$player->setLossItems($loss_items); $player->setLossItems($loss_items);
} }
if ($hasBlessingsColumn) if ($db->hasColumn('players', 'blessings'))
$player->setBlessings($blessings); $player->setBlessings($blessings);
if ($hasBlessingColumn) { if ($hasBlessingColumn) {
@@ -288,7 +290,7 @@ else if (isset($_REQUEST['search'])) {
$player->setCustomField('deletion', $deleted ? '1' : '0'); $player->setCustomField('deletion', $deleted ? '1' : '0');
else else
$player->setCustomField('deleted', $deleted ? '1' : '0'); $player->setCustomField('deleted', $deleted ? '1' : '0');
$player->setCustomField('hide', $hide ? '1' : '0'); $player->setCustomField('hidden', $hidden ? '1' : '0');
$player->setCustomField('created', $created); $player->setCustomField('created', $created);
if (isset($comment)) if (isset($comment))
$player->setCustomField('comment', $comment); $player->setCustomField('comment', $comment);
@@ -305,7 +307,7 @@ else if (isset($_REQUEST['search'])) {
} }
} }
} else if ($id == 0) { } else if ($id == 0) {
$players_db = Player::orderBy('id')->get(['id','name', 'level']); $players_db = $db->query('SELECT `id`, `name`, `level` FROM `players` ORDER BY `id` asc');
?> ?>
<div class="col-12 col-sm-12 col-lg-10"> <div class="col-12 col-sm-12 col-lg-10">
<div class="card card-info card-outline"> <div class="card card-info card-outline">
@@ -325,11 +327,11 @@ else if (isset($_REQUEST['search'])) {
<tbody> <tbody>
<?php foreach ($players_db as $player_db): ?> <?php foreach ($players_db as $player_db): ?>
<tr> <tr>
<th><?php echo $player_db->id; ?></th> <th><?php echo $player_db['id']; ?></th>
<td><?php echo $player_db->name; ?></a></td> <td><?php echo $player_db['name']; ?></a></td>
<td><?php echo $player_db->level; ?></a></td> <td><?php echo $player_db['level']; ?></a></td>
<td><a href="?p=players&id=<?php echo $player_db->id; ?>" class="btn btn-success btn-sm" title="Edit"> <td><a href="?p=players&id=<?php echo $player_db['id']; ?>" class="btn btn-success btn-sm" title="Edit">
<i class="fas fa-pencil-alt"></i> <i class="fas fa-pencil-alt"></i>
</a> </a>
</td> </td>
@@ -373,7 +375,7 @@ else if (isset($_REQUEST['search'])) {
</li> </li>
</ul> </ul>
</div> </div>
<form action="<?php echo $player_base . ($id > 0 ? '&id=' . $id : ''); ?>" method="post"> <form action="<?php echo $player_base . ((isset($id) && $id > 0) ? '&id=' . $id : ''); ?>" method="post">
<?php csrf(); ?> <?php csrf(); ?>
<div class="card-body"> <div class="card-body">
<div class="tab-content" id="tabs-tabContent"> <div class="tab-content" id="tabs-tabContent">
@@ -483,8 +485,8 @@ else if (isset($_REQUEST['search'])) {
</div> </div>
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
<div class="custom-control custom-switch custom-switch-on-success"> <div class="custom-control custom-switch custom-switch-on-success">
<input type="checkbox" class="custom-control-input" name="hide" id="hide" value="true" <?php echo($player->isHidden() ? ' checked' : ''); ?>> <input type="checkbox" class="custom-control-input" name="hidden" id="hidden" value="true" <?php echo($player->isHidden() ? ' checked' : ''); ?>>
<label class="custom-control-label" for="hide">Hidden</label> <label class="custom-control-label" for="hidden">Hidden</label>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -7,9 +7,6 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Plugins;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Plugin manager'; $title = 'Plugin manager';
@@ -17,17 +14,13 @@ csrfProtect();
$use_datatable = true; $use_datatable = true;
require_once LIBS . 'plugins.php';
if (!getBoolean(setting('core.admin_plugins_manage_enable'))) { if (!getBoolean(setting('core.admin_plugins_manage_enable'))) {
warning('Plugin installation and management is disabled in Settings.<br/>If you wish to enable, go to Settings and enable <strong>Enable Plugins Manage</strong>.'); warning('Plugin installation and management is disabled in Settings.<br/>If you wish to enable, go to Settings and enable <strong>Enable Plugins Manage</strong>.');
} }
else { else {
$pluginUploadEnabled = true; $twig->display('admin.plugins.form.html.twig');
if(!\class_exists('\ZipArchive')) {
error('Please install PHP zip extension. Plugins upload disabled until then.');
$pluginUploadEnabled = false;
}
$twig->display('admin.plugins.form.html.twig', ['pluginUploadEnabled' => $pluginUploadEnabled]);
if (isset($_POST['uninstall'])) { if (isset($_POST['uninstall'])) {
$uninstall = $_POST['uninstall']; $uninstall = $_POST['uninstall'];

View File

@@ -7,10 +7,6 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Plugins;
use MyAAC\Settings;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Settings'; $title = 'Settings';
@@ -48,7 +44,7 @@ if (!is_array($settingsFile)) {
$settingsKeyName = ($plugin == 'core' ? $plugin : $settingsFile['key']); $settingsKeyName = ($plugin == 'core' ? $plugin : $settingsFile['key']);
$title = ($plugin == 'core' ? 'Settings' : 'Plugin Settings - ' . $settingsFile['name']); $title = ($plugin == 'core' ? 'Settings' : 'Plugin Settings - ' . $plugin);
$settingsParsed = Settings::display($settingsKeyName, $settingsFile['settings']); $settingsParsed = Settings::display($settingsKeyName, $settingsFile['settings']);

View File

@@ -12,7 +12,6 @@ defined('MYAAC') or die('Direct access not allowed!');
use DeviceDetector\DeviceDetector; use DeviceDetector\DeviceDetector;
use DeviceDetector\Parser\Client\Browser; use DeviceDetector\Parser\Client\Browser;
use DeviceDetector\Parser\OperatingSystem; use DeviceDetector\Parser\OperatingSystem;
use MyAAC\Visitors;
$title = 'Visitors'; $title = 'Visitors';
$use_datatable = true; $use_datatable = true;
@@ -25,6 +24,7 @@ if (!setting('core.visitors_counter')): ?>
return; return;
endif; endif;
require SYSTEM . 'libs/visitors.php';
$visitors = new Visitors(setting('core.visitors_counter_ttl')); $visitors = new Visitors(setting('core.visitors_counter_ttl'));
function compare($a, $b): int { function compare($a, $b): int {

View File

@@ -1,6 +1,6 @@
<?php <?php
$menus = [ return [
['name' => 'Dashboard', 'icon' => 'tachometer-alt', 'order' => 10, 'link' => 'dashboard'], ['name' => 'Dashboard', 'icon' => 'tachometer-alt', 'order' => 10, 'link' => 'dashboard'],
['name' => 'Settings', 'icon' => 'edit', 'order' => 19, 'link' => ['name' => 'Settings', 'icon' => 'edit', 'order' => 19, 'link' =>
require ADMIN . 'includes/settings_menus.php' require ADMIN . 'includes/settings_menus.php'

View File

@@ -8,8 +8,3 @@
.sidebar-mini.sidebar-collapse .menu-text { .sidebar-mini.sidebar-collapse .menu-text {
display: none; display: none;
} }
.myaac-table tbody tr:nth-child(even) {background: #FFF} /* light border */
.myaac-table tbody tr:nth-child(odd) {background: #CCC} /* dark border */
.myaac-table thead td {background: #000000; color: #ffffff !important;} /* vdark border */
.myaac-table tfoot td {background: #000000; color: #ffffff !important;} /* vdark border */

View File

@@ -191,8 +191,8 @@ if ($logged && admin()) {
]); ]);
} }
?> ?>
<script src="<?php echo BASE_URL; ?>tools/ext/bootstrap/js/bootstrap.min.js"></script> <script src="<?php echo BASE_URL; ?>tools/js/bootstrap.min.js"></script>
<script src="<?php echo BASE_URL; ?>tools/ext/jquery-ui/jquery-ui.min.js"></script> <script src="<?php echo BASE_URL; ?>tools/js/jquery-ui.min.js"></script>
<?php if (isset($use_datatable)) { ?> <?php if (isset($use_datatable)) { ?>
<script src="<?php echo BASE_URL; ?>tools/js/datatables.min.js"></script> <script src="<?php echo BASE_URL; ?>tools/js/datatables.min.js"></script>
<script src="<?php echo BASE_URL; ?>tools/js/datatables.bs.min.js"></script> <script src="<?php echo BASE_URL; ?>tools/js/datatables.bs.min.js"></script>

View File

@@ -22,10 +22,7 @@
* @copyright 2020 MyAAC * @copyright 2020 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
define('MYAAC_ADMIN', true);
use MyAAC\DataLoader;
const MYAAC_ADMIN = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';
@@ -37,9 +34,11 @@ if (!admin())
ini_set('max_execution_time', 300); ini_set('max_execution_time', 300);
ob_implicit_flush(); ob_implicit_flush();
@ob_end_flush(); ob_end_flush();
header('X-Accel-Buffering: no'); header('X-Accel-Buffering: no');
require LIBS . 'DataLoader.php';
require LOCALE . 'en/main.php'; require LOCALE . 'en/main.php';
require LOCALE . 'en/install.php'; require LOCALE . 'en/install.php';

View File

@@ -1,8 +1,4 @@
<?php <?php
use MyAAC\Hooks;
use MyAAC\Settings;
const MYAAC_ADMIN = true; const MYAAC_ADMIN = true;
require '../../common.php'; require '../../common.php';
@@ -10,6 +6,11 @@ require SYSTEM . 'functions.php';
require SYSTEM . 'init.php'; require SYSTEM . 'init.php';
require SYSTEM . 'login.php'; require SYSTEM . 'login.php';
// event system
require_once SYSTEM . 'hooks.php';
$hooks = new Hooks();
$hooks->load();
if(!admin()) { if(!admin()) {
http_response_code(500); http_response_code(500);
die('Access denied.'); die('Access denied.');

View File

@@ -20,14 +20,14 @@
* *
* @package MyAAC * @package MyAAC
* @author Slawkens <slawkens@gmail.com> * @author Slawkens <slawkens@gmail.com>
* @copyright 2024 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.'); if (version_compare(phpversion(), '8.0', '<')) die('PHP version 8.0 or higher is required.');
const MYAAC = true; const MYAAC = true;
const MYAAC_VERSION = '1.3.3'; const MYAAC_VERSION = '0.10.0-dev';
const DATABASE_VERSION = 43; const DATABASE_VERSION = 36;
const TABLE_PREFIX = 'myaac_'; const TABLE_PREFIX = 'myaac_';
define('START_TIME', microtime(true)); define('START_TIME', microtime(true));
define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX')); define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX'));
@@ -156,7 +156,7 @@ if (file_exists(BASE . 'config.local.php')) {
/** @var array $config */ /** @var array $config */
ini_set('log_errors', 1); ini_set('log_errors', 1);
if(@$config['env'] === 'dev' || defined('MYAAC_INSTALL')) { if(@$config['env'] === 'dev') {
ini_set('display_errors', 1); ini_set('display_errors', 1);
ini_set('display_startup_errors', 1); ini_set('display_startup_errors', 1);
error_reporting(E_ALL); error_reporting(E_ALL);

View File

@@ -1,6 +1,6 @@
{ {
"require": { "require": {
"php": "^8.1", "php": "^8.0",
"ext-pdo": "*", "ext-pdo": "*",
"ext-pdo_mysql": "*", "ext-pdo_mysql": "*",
"ext-json": "*", "ext-json": "*",
@@ -8,25 +8,19 @@
"ext-dom": "*", "ext-dom": "*",
"phpmailer/phpmailer": "^6.1", "phpmailer/phpmailer": "^6.1",
"composer/semver": "^3.2", "composer/semver": "^3.2",
"twig/twig": "^3.11", "twig/twig": "^2.0",
"erusev/parsedown": "^1.7", "erusev/parsedown": "^1.7",
"nikic/fast-route": "^1.3", "nikic/fast-route": "^1.3",
"matomo/device-detector": "^6.0", "matomo/device-detector": "^6.0",
"illuminate/database": "^10.18", "illuminate/database": "^10.18",
"peppeocchi/php-cron-scheduler": "4.*", "peppeocchi/php-cron-scheduler": "4.*"
"symfony/console": "^6.4",
"symfony/string": "^6.4",
"symfony/var-dumper": "^6.4",
"filp/whoops": "^2.15",
"maximebf/debugbar": "1.*"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "^1.10" "filp/whoops": "^2.15"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"MyAAC\\": "system/src" "MyAAC\\": "system/src"
}, }
"files": ["system/src/global.php"]
} }
} }

2926
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,7 @@ describe('Install MyAAC', () => {
cy.contains('Basic configuration'); cy.contains('Basic configuration');
cy.get('#vars_server_path').click().clear().type(Cypress.env('SERVER_PATH')) cy.get('#vars_server_path').click().clear().type(Cypress.env('SERVER_PATH'))
cy.get('#vars_mail_admin').click().clear().type('noone@example.net')
cy.get('[type="checkbox"]').uncheck() // usage statistics uncheck cy.get('[type="checkbox"]').uncheck() // usage statistics uncheck
@@ -67,9 +68,7 @@ describe('Install MyAAC', () => {
cy.get('form').submit() cy.get('form').submit()
cy.contains('[class="alert alert-success"]', 'Congratulations', { timeout: 60000 }).should('be.visible') cy.contains('[class="alert alert-success"]', 'Congratulations', { timeout: 30000 }).should('be.visible')
cy.wait(2000);
cy.screenshot('install-finish') cy.screenshot('install-finish')
}) })

View File

@@ -82,7 +82,7 @@ describe('Check Public Pages', () => {
it('Go to last kills page', () => { it('Go to last kills page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/last-kills', url: Cypress.env('URL') + '/lastkills',
method: 'GET', method: 'GET',
}) })
}) })
@@ -116,9 +116,9 @@ describe('Check Public Pages', () => {
}) })
// library // library
it('Go to monsters page', () => { it('Go to creatures page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/monsters', url: Cypress.env('URL') + '/creatures',
method: 'GET', method: 'GET',
}) })
}) })
@@ -132,7 +132,7 @@ describe('Check Public Pages', () => {
it('Go to server info page', () => { it('Go to server info page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/server-info', url: Cypress.env('URL') + '/serverInfo',
method: 'GET', method: 'GET',
}) })
}) })
@@ -160,7 +160,7 @@ describe('Check Public Pages', () => {
it('Go to experience table page', () => { it('Go to experience table page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/exp-table', url: Cypress.env('URL') + '/experienceTable',
method: 'GET', method: 'GET',
}) })
}) })

View File

@@ -4,7 +4,7 @@ const YOU_ARE_NOT_LOGGEDIN = 'You are not logged in.';
describe('Check Protected Pages', () => { describe('Check Protected Pages', () => {
// character actions // character actions
it('Go to account character creation page', () => { it('Go to accouht character creation page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/character/create', url: Cypress.env('URL') + '/account/character/create',
method: 'GET', method: 'GET',
@@ -12,7 +12,7 @@ describe('Check Protected Pages', () => {
cy.contains(REQUIRED_LOGIN_MESSAGE) cy.contains(REQUIRED_LOGIN_MESSAGE)
}) })
it('Go to account character deletion page', () => { it('Go to accouht character deletion page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/character/delete', url: Cypress.env('URL') + '/account/character/delete',
method: 'GET', method: 'GET',
@@ -21,7 +21,7 @@ describe('Check Protected Pages', () => {
}) })
// account actions // account actions
it('Go to account email change page', () => { it('Go to accouht email change page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/email', url: Cypress.env('URL') + '/account/email',
method: 'GET', method: 'GET',
@@ -29,7 +29,7 @@ describe('Check Protected Pages', () => {
cy.contains(REQUIRED_LOGIN_MESSAGE) cy.contains(REQUIRED_LOGIN_MESSAGE)
}) })
it('Go to account password change page', () => { it('Go to accouht password change page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/password', url: Cypress.env('URL') + '/account/password',
method: 'GET', method: 'GET',
@@ -37,7 +37,7 @@ describe('Check Protected Pages', () => {
cy.contains(REQUIRED_LOGIN_MESSAGE) cy.contains(REQUIRED_LOGIN_MESSAGE)
}) })
it('Go to account info change page', () => { it('Go to accouht info change page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/info', url: Cypress.env('URL') + '/account/info',
method: 'GET', method: 'GET',
@@ -45,7 +45,7 @@ describe('Check Protected Pages', () => {
cy.contains(REQUIRED_LOGIN_MESSAGE) cy.contains(REQUIRED_LOGIN_MESSAGE)
}) })
it('Go to account logout change page', () => { it('Go to accouht logout change page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/logout', url: Cypress.env('URL') + '/account/logout',
method: 'GET', method: 'GET',

102
index.php
View File

@@ -24,18 +24,15 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\UsageStatistics;
use MyAAC\Visitors;
require_once 'common.php'; require_once 'common.php';
require_once SYSTEM . 'functions.php'; require_once SYSTEM . 'functions.php';
$uri = $_SERVER['REQUEST_URI']; $uri = $_SERVER['REQUEST_URI'];
if(str_contains($uri, 'index.php')) { if(false !== strpos($uri, 'index.php')) {
$uri = str_replace_first('/index.php', '', $uri); $uri = str_replace_first('/index.php', '', $uri);
} }
if(str_starts_with($uri, '/')) { if(0 === strpos($uri, '/')) {
$uri = str_replace_first('/', '', $uri); $uri = str_replace_first('/', '', $uri);
} }
@@ -62,13 +59,18 @@ if(preg_match("/^(.*)\.(gif|jpg|png|jpeg|tiff|bmp|css|js|less|map|html|zip|rar|g
if((!isset($config['installed']) || !$config['installed']) && file_exists(BASE . 'install')) if((!isset($config['installed']) || !$config['installed']) && file_exists(BASE . 'install'))
{ {
header('Location: ' . BASE_URL . 'install/'); header('Location: ' . BASE_URL . 'install/');
exit(); throw new RuntimeException('Setup detected that <b>install/</b> directory exists. Please visit <a href="' . BASE_URL . 'install">this</a> url to start MyAAC Installation.<br/>Delete <b>install/</b> directory if you already installed MyAAC.<br/>Remember to REFRESH this page when you\'re done!');
} }
$template_place_holders = array(); $template_place_holders = array();
require_once SYSTEM . 'init.php'; require_once SYSTEM . 'init.php';
// verify myaac tables exists in database
if(!$db->hasTable('myaac_account_actions')) {
throw new RuntimeException('Seems that the table <strong>myaac_account_actions</strong> of MyAAC doesn\'t exist in the database. This is a fatal error. You can try to reinstall MyAAC by visiting <a href="' . BASE_URL . 'install">this</a> url.');
}
require_once SYSTEM . 'template.php'; require_once SYSTEM . 'template.php';
require_once SYSTEM . 'login.php'; require_once SYSTEM . 'login.php';
require_once SYSTEM . 'status.php'; require_once SYSTEM . 'status.php';
@@ -76,8 +78,53 @@ require_once SYSTEM . 'status.php';
$twig->addGlobal('config', $config); $twig->addGlobal('config', $config);
$twig->addGlobal('status', $status); $twig->addGlobal('status', $status);
require_once SYSTEM . 'router.php';
$hooks->trigger(HOOK_STARTUP); $hooks->trigger(HOOK_STARTUP);
// anonymous usage statistics
// sent only when user agrees
if(setting('core.anonymous_usage_statistics')) {
$report_time = 30 * 24 * 60 * 60; // report one time per 30 days
$should_report = true;
$value = '';
if($cache->enabled() && $cache->fetch('last_usage_report', $value)) {
$should_report = time() > (int)$value + $report_time;
}
else {
$value = '';
if(fetchDatabaseConfig('last_usage_report', $value)) {
$should_report = time() > (int)$value + $report_time;
if($cache->enabled()) {
$cache->set('last_usage_report', $value);
}
}
else {
registerDatabaseConfig('last_usage_report', time() - ($report_time - (7 * 24 * 60 * 60))); // first report after a week
$should_report = false;
}
}
if($should_report) {
require_once LIBS . 'usage_statistics.php';
Usage_Statistics::report();
updateDatabaseConfig('last_usage_report', time());
if($cache->enabled()) {
$cache->set('last_usage_report', time());
}
}
}
if(setting('core.views_counter'))
require_once SYSTEM . 'counter.php';
if(setting('core.visitors_counter')) {
require_once SYSTEM . 'libs/visitors.php';
$visitors = new Visitors(setting('core.visitors_counter_ttl'));
}
// backward support for gesior // backward support for gesior
if(setting('core.backward_support')) { if(setting('core.backward_support')) {
define('INITIALIZED', true); define('INITIALIZED', true);
@@ -117,49 +164,6 @@ if(setting('core.backward_support')) {
$config['status']['serverStatus_' . $key] = $value; $config['status']['serverStatus_' . $key] = $value;
} }
require_once SYSTEM . 'router.php';
// anonymous usage statistics
// sent only when user agrees
if(setting('core.anonymous_usage_statistics')) {
$report_time = 30 * 24 * 60 * 60; // report one time per 30 days
$should_report = true;
$value = '';
if($cache->enabled() && $cache->fetch('last_usage_report', $value)) {
$should_report = time() > (int)$value + $report_time;
}
else {
$value = '';
if(fetchDatabaseConfig('last_usage_report', $value)) {
$should_report = time() > (int)$value + $report_time;
if($cache->enabled()) {
$cache->set('last_usage_report', $value, 60 * 60);
}
}
else {
registerDatabaseConfig('last_usage_report', time() - ($report_time - (7 * 24 * 60 * 60))); // first report after a week
$should_report = false;
}
}
if($should_report) {
UsageStatistics::report();
updateDatabaseConfig('last_usage_report', time());
if($cache->enabled()) {
$cache->set('last_usage_report', time(), 60 * 60);
}
}
}
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 * @var OTS_Account $account_logged
*/ */

View File

@@ -17,7 +17,7 @@ function query($query)
// define php version id if its not already // define php version id if its not already
if(!defined('PHP_VERSION_ID')) { if(!defined('PHP_VERSION_ID')) {
$version = array_map('intval', explode('.', PHP_VERSION)); $version = explode('.', PHP_VERSION);
define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2])); define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
} }

View File

@@ -1,4 +1,4 @@
SET @myaac_database_version = 43; SET @myaac_database_version = 36;
CREATE TABLE `myaac_account_actions` CREATE TABLE `myaac_account_actions`
( (
@@ -8,7 +8,7 @@ CREATE TABLE `myaac_account_actions`
`date` INT(11) NOT NULL DEFAULT 0, `date` INT(11) NOT NULL DEFAULT 0,
`action` VARCHAR(255) NOT NULL DEFAULT '', `action` VARCHAR(255) NOT NULL DEFAULT '',
KEY (`account_id`) KEY (`account_id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_admin_menu` CREATE TABLE `myaac_admin_menu`
( (
@@ -19,7 +19,22 @@ CREATE TABLE `myaac_admin_menu`
`flags` INT(11) NOT NULL DEFAULT 0, `flags` INT(11) NOT NULL DEFAULT 0,
`enabled` INT(1) NOT NULL DEFAULT 1, `enabled` INT(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_bugtracker`
(
`account` VARCHAR(255) NOT NULL,
`type` INT(11) NOT NULL DEFAULT 0,
`status` INT(11) NOT NULL DEFAULT 0,
`text` text NOT NULL,
`id` INT(11) NOT NULL DEFAULT 0,
`subject` VARCHAR(255) NOT NULL DEFAULT '',
`reply` INT(11) NOT NULL DEFAULT 0,
`who` INT(11) NOT NULL DEFAULT 0,
`uid` INT(11) NOT NULL AUTO_INCREMENT,
`tag` INT(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_changelog` CREATE TABLE `myaac_changelog`
( (
@@ -29,11 +44,11 @@ CREATE TABLE `myaac_changelog`
`where` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - server, 2 - site', `where` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - server, 2 - site',
`date` INT(11) NOT NULL DEFAULT 0, `date` INT(11) NOT NULL DEFAULT 0,
`player_id` INT(11) NOT NULL DEFAULT 0, `player_id` INT(11) NOT NULL DEFAULT 0,
`hide` TINYINT(1) NOT NULL DEFAULT 0, `hidden` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
INSERT INTO `myaac_changelog` (`id`, `type`, `where`, `date`, `body`, `hide`) VALUES (1, 3, 2, UNIX_TIMESTAMP(), 'MyAAC installed. (:', 0); INSERT INTO `myaac_changelog` (`id`, `type`, `where`, `date`, `body`, `hidden`) VALUES (1, 3, 2, UNIX_TIMESTAMP(), 'MyAAC installed. (:', 0);
CREATE TABLE `myaac_config` CREATE TABLE `myaac_config`
( (
@@ -42,7 +57,7 @@ CREATE TABLE `myaac_config`
`value` VARCHAR(1000) NOT NULL, `value` VARCHAR(1000) NOT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE (`name`) UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
INSERT INTO `myaac_config` (`name`, `value`) VALUES ('database_version', @myaac_database_version); INSERT INTO `myaac_config` (`name`, `value`) VALUES ('database_version', @myaac_database_version);
@@ -52,9 +67,9 @@ CREATE TABLE `myaac_faq`
`question` VARCHAR(255) NOT NULL DEFAULT '', `question` VARCHAR(255) NOT NULL DEFAULT '',
`answer` VARCHAR(1020) NOT NULL DEFAULT '', `answer` VARCHAR(1020) NOT NULL DEFAULT '',
`ordering` INT(11) NOT NULL DEFAULT 0, `ordering` INT(11) NOT NULL DEFAULT 0,
`hide` TINYINT(1) NOT NULL DEFAULT 0, `hidden` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_forum_boards` CREATE TABLE `myaac_forum_boards`
( (
@@ -65,9 +80,9 @@ CREATE TABLE `myaac_forum_boards`
`guild` INT(11) NOT NULL DEFAULT 0, `guild` INT(11) NOT NULL DEFAULT 0,
`access` INT(11) NOT NULL DEFAULT 0, `access` INT(11) NOT NULL DEFAULT 0,
`closed` TINYINT(1) NOT NULL DEFAULT 0, `closed` TINYINT(1) NOT NULL DEFAULT 0,
`hide` TINYINT(1) NOT NULL DEFAULT 0, `hidden` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
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`, `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, '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, 'Quests', 'Quest making.', 2);
@@ -91,12 +106,12 @@ CREATE TABLE `myaac_forum`
`post_date` int(20) NOT NULL default '0', `post_date` int(20) NOT NULL default '0',
`last_edit_aid` int(20) NOT NULL default '0', `last_edit_aid` int(20) NOT NULL default '0',
`edit_date` int(20) NOT NULL default '0', `edit_date` int(20) NOT NULL default '0',
`post_ip` varchar(45) NOT NULL default '0.0.0.0', `post_ip` varchar(32) NOT NULL default '0.0.0.0',
`sticked` tinyint(1) NOT NULL DEFAULT '0', `sticked` tinyint(1) NOT NULL DEFAULT '0',
`closed` tinyint(1) NOT NULL DEFAULT '0', `closed` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `section` (`section`) KEY `section` (`section`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_menu` CREATE TABLE `myaac_menu`
( (
@@ -110,11 +125,11 @@ CREATE TABLE `myaac_menu`
`ordering` INT(11) NOT NULL DEFAULT 0, `ordering` INT(11) NOT NULL DEFAULT 0,
`enabled` INT(1) NOT NULL DEFAULT 1, `enabled` INT(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_monsters` ( CREATE TABLE `myaac_monsters` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`hide` tinyint(1) NOT NULL default 0, `hidden` tinyint(1) NOT NULL default 0,
`name` varchar(255) NOT NULL, `name` varchar(255) NOT NULL,
`mana` int(11) NOT NULL DEFAULT 0, `mana` int(11) NOT NULL DEFAULT 0,
`exp` int(11) NOT NULL, `exp` int(11) NOT NULL,
@@ -143,7 +158,7 @@ CREATE TABLE `myaac_monsters` (
`loot` text NOT NULL, `loot` text NOT NULL,
`summons` TEXT NOT NULL, `summons` TEXT NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_news` CREATE TABLE `myaac_news`
( (
@@ -159,9 +174,9 @@ CREATE TABLE `myaac_news`
`comments` VARCHAR(50) NOT NULL DEFAULT '', `comments` VARCHAR(50) NOT NULL DEFAULT '',
`article_text` VARCHAR(300) NOT NULL DEFAULT '', `article_text` VARCHAR(300) NOT NULL DEFAULT '',
`article_image` VARCHAR(100) NOT NULL DEFAULT '', `article_image` VARCHAR(100) NOT NULL DEFAULT '',
`hide` TINYINT(1) NOT NULL DEFAULT 0, `hidden` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_news_categories` CREATE TABLE `myaac_news_categories`
( (
@@ -169,9 +184,9 @@ CREATE TABLE `myaac_news_categories`
`name` VARCHAR(50) NOT NULL DEFAULT "", `name` VARCHAR(50) NOT NULL DEFAULT "",
`description` VARCHAR(50) NOT NULL DEFAULT "", `description` VARCHAR(50) NOT NULL DEFAULT "",
`icon_id` INT(2) NOT NULL DEFAULT 0, `icon_id` INT(2) NOT NULL DEFAULT 0,
`hide` TINYINT(1) NOT NULL DEFAULT 0, `hidden` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 0); 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, 1);
@@ -187,7 +202,7 @@ CREATE TABLE `myaac_notepad`
`content` TEXT NOT NULL, `content` TEXT NOT NULL,
/*`public` TINYINT(1) NOT NULL DEFAULT 0*/ /*`public` TINYINT(1) NOT NULL DEFAULT 0*/
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_pages` CREATE TABLE `myaac_pages`
( (
@@ -200,10 +215,10 @@ CREATE TABLE `myaac_pages`
`php` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '0 - plain html, 1 - php', `php` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '0 - plain html, 1 - php',
`enable_tinymce` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '1 - enabled, 0 - disabled', `enable_tinymce` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '1 - enabled, 0 - disabled',
`access` TINYINT(2) NOT NULL DEFAULT 0, `access` TINYINT(2) NOT NULL DEFAULT 0,
`hide` TINYINT(1) NOT NULL DEFAULT 0, `hidden` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE (`name`) UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_gallery` CREATE TABLE `myaac_gallery`
( (
@@ -213,9 +228,9 @@ CREATE TABLE `myaac_gallery`
`thumb` VARCHAR(255) NOT NULL, `thumb` VARCHAR(255) NOT NULL,
`author` VARCHAR(50) NOT NULL DEFAULT '', `author` VARCHAR(50) NOT NULL DEFAULT '',
`ordering` INT(11) NOT NULL DEFAULT 0, `ordering` INT(11) NOT NULL DEFAULT 0,
`hide` TINYINT(1) NOT NULL DEFAULT 0, `hidden` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
INSERT INTO `myaac_gallery` (`id`, `ordering`, `comment`, `image`, `thumb`, `author`) VALUES (NULL, 1, 'Demon', 'images/gallery/demon.jpg', 'images/gallery/demon_thumb.gif', 'MyAAC'); INSERT INTO `myaac_gallery` (`id`, `ordering`, `comment`, `image`, `thumb`, `author`) VALUES (NULL, 1, 'Demon', 'images/gallery/demon.jpg', 'images/gallery/demon_thumb.gif', 'MyAAC');
@@ -227,7 +242,7 @@ CREATE TABLE `myaac_settings`
`value` TEXT NOT NULL, `value` TEXT NOT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `key` (`key`) KEY `key` (`key`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_spells` CREATE TABLE `myaac_spells`
( (
@@ -247,10 +262,10 @@ CREATE TABLE `myaac_spells`
`item_id` INT(11) NOT NULL DEFAULT 0, `item_id` INT(11) NOT NULL DEFAULT 0,
`premium` TINYINT(1) NOT NULL DEFAULT 0, `premium` TINYINT(1) NOT NULL DEFAULT 0,
`vocations` VARCHAR(100) NOT NULL DEFAULT '', `vocations` VARCHAR(100) NOT NULL DEFAULT '',
`hide` TINYINT(1) NOT NULL DEFAULT 0, `hidden` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE (`name`) UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_visitors` CREATE TABLE `myaac_visitors`
( (
@@ -259,7 +274,7 @@ CREATE TABLE `myaac_visitors`
`page` VARCHAR(2048) NOT NULL, `page` VARCHAR(2048) NOT NULL,
`user_agent` VARCHAR(255) NOT NULL DEFAULT '', `user_agent` VARCHAR(255) NOT NULL DEFAULT '',
UNIQUE (`ip`) UNIQUE (`ip`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_weapons` CREATE TABLE `myaac_weapons`
( (
@@ -268,4 +283,4 @@ CREATE TABLE `myaac_weapons`
`maglevel` INT(11) NOT NULL DEFAULT 0, `maglevel` INT(11) NOT NULL DEFAULT 0,
`vocations` VARCHAR(100) NOT NULL DEFAULT '', `vocations` VARCHAR(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;

View File

@@ -3,15 +3,16 @@
use Twig\Environment as Twig_Environment; use Twig\Environment as Twig_Environment;
use Twig\Loader\FilesystemLoader as Twig_FilesystemLoader; use Twig\Loader\FilesystemLoader as Twig_FilesystemLoader;
const MYAAC_INSTALL = true;
require '../common.php'; require '../common.php';
define('MYAAC_INSTALL', true);
// includes // includes
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';
require BASE . 'install/includes/functions.php'; require BASE . 'install/includes/functions.php';
require BASE . 'install/includes/locale.php'; require BASE . 'install/includes/locale.php';
require SYSTEM . 'clients.conf.php'; require SYSTEM . 'clients.conf.php';
require LIBS . 'Settings.php';
// ignore undefined index from Twig autoloader // ignore undefined index from Twig autoloader
$config['env'] = 'prod'; $config['env'] = 'prod';
@@ -114,7 +115,7 @@ else if($step == 'finish') {
$email = $_SESSION['var_email']; $email = $_SESSION['var_email'];
$password = $_SESSION['var_password']; $password = $_SESSION['var_password'];
$password_confirm = $_SESSION['var_password_confirm']; $password_confirm = $_SESSION['var_password_confirm'];
$player_name = $_SESSION['var_player_name'] ?? null; $player_name = $_SESSION['var_player_name'];
// email check // email check
if(empty($email)) { if(empty($email)) {
@@ -125,18 +126,7 @@ else if($step == 'finish') {
} }
// account check // account check
if(isset($_SESSION['var_account_id'])) { if(isset($_SESSION['var_account'])) {
if(empty($_SESSION['var_account_id'])) {
$errors[] = $locale['step_admin_account_id_error_empty'];
}
else if(!Validator::accountId($_SESSION['var_account_id'])) {
$errors[] = $locale['step_admin_account_id_error_format'];
}
else if($_SESSION['var_account_id'] == $password) {
$errors[] = $locale['step_admin_account_id_error_same'];
}
}
else if(isset($_SESSION['var_account'])) {
if(empty($_SESSION['var_account'])) { if(empty($_SESSION['var_account'])) {
$errors[] = $locale['step_admin_account_error_empty']; $errors[] = $locale['step_admin_account_error_empty'];
} }
@@ -147,6 +137,17 @@ else if($step == 'finish') {
$errors[] = $locale['step_admin_account_error_same']; $errors[] = $locale['step_admin_account_error_same'];
} }
} }
else if(isset($_SESSION['var_account_id'])) {
if(empty($_SESSION['var_account_id'])) {
$errors[] = $locale['step_admin_account_id_error_empty'];
}
else if(!Validator::accountId($_SESSION['var_account_id'])) {
$errors[] = $locale['step_admin_account_id_error_format'];
}
else if($_SESSION['var_account_id'] == $password) {
$errors[] = $locale['step_admin_account_id_error_same'];
}
}
// password check // password check
if(empty($password)) { if(empty($password)) {
@@ -159,13 +160,12 @@ else if($step == 'finish') {
$errors[] = $locale['step_admin_password_confirm_error_not_same']; $errors[] = $locale['step_admin_password_confirm_error_not_same'];
} }
if (isset($player_name)) {
// player name check // player name check
if (empty($player_name)) { if(empty($player_name)) {
$errors[] = $locale['step_admin_player_name_error_empty']; $errors[] = $locale['step_admin_player_name_error_empty'];
} else if (!Validator::characterName($player_name)) {
$errors[] = $locale['step_admin_player_name_error_format'];
} }
else if(!Validator::characterName($player_name)) {
$errors[] = $locale['step_admin_player_name_error_format'];
} }
if(!empty($errors)) { if(!empty($errors)) {
@@ -183,14 +183,14 @@ clearstatcache();
if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) { if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) {
if(!file_exists(BASE . 'install/ip.txt')) { if(!file_exists(BASE . 'install/ip.txt')) {
$content = warning('AAC installation is disabled. To enable it make file <b>ip.txt</b> in install/ directory and put there your IP.<br/> $content = warning('AAC installation is disabled. To enable it make file <b>ip.txt</b> in install/ directory and put there your IP.<br/>
Your IP is:<br /><b>' . get_browser_real_ip() . '</b>', true); Your IP is:<br /><b>' . $_SERVER['REMOTE_ADDR'] . '</b>', true);
} }
else { else {
$file_content = trim(file_get_contents(BASE . 'install/ip.txt')); $file_content = trim(file_get_contents(BASE . 'install/ip.txt'));
$allow = false; $allow = false;
$listIP = preg_split('/\s+/', $file_content); $listIP = preg_split('/\s+/', $file_content);
foreach($listIP as $ip) { foreach($listIP as $ip) {
if(get_browser_real_ip() == $ip) { if($_SERVER['REMOTE_ADDR'] == $ip) {
$allow = true; $allow = true;
} }
} }
@@ -199,7 +199,7 @@ if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) {
{ {
$content = warning('In file <b>install/ip.txt</b> must be your IP!<br/> $content = warning('In file <b>install/ip.txt</b> must be your IP!<br/>
In file is:<br /><b>' . nl2br($file_content) . '</b><br/> In file is:<br /><b>' . nl2br($file_content) . '</b><br/>
Your IP is:<br /><b>' . get_browser_real_ip() . '</b>', true); Your IP is:<br /><b>' . $_SERVER['REMOTE_ADDR'] . '</b>', true);
} }
else { else {
ob_start(); ob_start();

View File

@@ -2,15 +2,10 @@
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
// configuration // configuration
$dirs_required_writable = [ $dirs_required = [
'system/logs', 'system/logs',
'system/cache', 'system/cache',
]; ];
$dirs_required = [
'tools/ext' => $locale['step_requirements_folder_not_exists_tools_ext'],
];
$dirs_optional = [ $dirs_optional = [
GUILD_IMAGES_DIR => $locale['step_requirements_warning_images_guilds'], GUILD_IMAGES_DIR => $locale['step_requirements_warning_images_guilds'],
GALLERY_DIR => $locale['step_requirements_warning_images_gallery'], GALLERY_DIR => $locale['step_requirements_warning_images_gallery'],
@@ -23,7 +18,6 @@ $extensions_optional = [
'gd' => $locale['step_requirements_warning_player_signatures'], 'gd' => $locale['step_requirements_warning_player_signatures'],
'zip' => $locale['step_requirements_warning_install_plugins'], 'zip' => $locale['step_requirements_warning_install_plugins'],
]; ];
/* /*
* *
* @param string $name * @param string $name
@@ -47,7 +41,7 @@ $failed = false;
// start validating // start validating
version_check($locale['step_requirements_php_version'], (PHP_VERSION_ID >= 50500), PHP_VERSION); version_check($locale['step_requirements_php_version'], (PHP_VERSION_ID >= 50500), PHP_VERSION);
foreach ($dirs_required_writable as $value) foreach ($dirs_required as $value)
{ {
$is_writable = is_writable(BASE . $value) && (MYAAC_OS != 'WINDOWS' || win_is_writable(BASE . $value)); $is_writable = is_writable(BASE . $value) && (MYAAC_OS != 'WINDOWS' || win_is_writable(BASE . $value));
version_check($locale['step_requirements_write_perms'] . ': ' . $value, $is_writable); version_check($locale['step_requirements_write_perms'] . ': ' . $value, $is_writable);
@@ -58,12 +52,6 @@ foreach ($dirs_optional as $dir => $errorMsg) {
version_check($locale['step_requirements_write_perms'] . ': ' . $dir, $is_writable, $is_writable ? '' : $errorMsg, true); version_check($locale['step_requirements_write_perms'] . ': ' . $dir, $is_writable, $is_writable ? '' : $errorMsg, true);
} }
foreach ($dirs_required as $dir => $errorMsg)
{
$exists = is_dir(BASE . $dir);
version_check($locale['step_requirements_folder_exists'] . ': ' . $dir, $exists, $exists ? '' : $errorMsg);
}
$ini_register_globals = ini_get_bool('register_globals'); $ini_register_globals = ini_get_bool('register_globals');
version_check('register_long_arrays', !$ini_register_globals, $ini_register_globals ? $locale['on'] : $locale['off']); version_check('register_long_arrays', !$ini_register_globals, $ini_register_globals ? $locale['on'] : $locale['off']);
@@ -90,3 +78,4 @@ if($failed) {
} }
echo '</div>'; echo '</div>';
?>

View File

@@ -1,7 +1,4 @@
<?php <?php
use MyAAC\Settings;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
//ini_set('display_errors', false); //ini_set('display_errors', false);
@@ -40,40 +37,50 @@ if(!$error) {
$configToSave['gzip_output'] = false; $configToSave['gzip_output'] = false;
$configToSave['cache_engine'] = 'auto'; $configToSave['cache_engine'] = 'auto';
$configToSave['cache_prefix'] = 'myaac_' . generateRandomString(8, true, false, true); $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;
require BASE . 'config.local.php';
require BASE . 'install/includes/config.php'; require BASE . 'install/includes/config.php';
if (!$error) { if(!$error) {
require BASE . 'install/includes/database.php'; require BASE . 'install/includes/database.php';
if (isset($database_error)) { // we failed connect to the database $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']);
success($locale['step_database_importing']);
if(isset($database_error)) { // we failed connect to the database
error($database_error); error($database_error);
} }
else { else {
if (!$db->hasTable('accounts')) { if(!$db->hasTable('accounts')) {
$tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']); $tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']);
error($tmp); error($tmp);
$error = true; $error = true;
} }
if (!$error) { if(!$db->hasTable('players')) {
$tmp = str_replace('$TABLE$', 'players', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
if(!$db->hasTable('guilds')) {
$tmp = str_replace('$TABLE$', 'guilds', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
if(!$error) {
$twig->display('install.installer.html.twig', array( $twig->display('install.installer.html.twig', array(
'url' => 'tools/5-database.php', 'url' => 'tools/5-database.php',
'message' => $locale['loading_spinner'] 'message' => $locale['loading_spinner']
)); ));
$content = '';
$saved = Settings::saveConfig($configToSave, BASE . 'config.local.php', $content);
if($saved) {
success($locale['step_database_config_saved']);
$_SESSION['saved'] = true;
} }
} else {
}
} else {
$_SESSION['config_content'] = $content; $_SESSION['config_content'] = $content;
unset($_SESSION['saved']); unset($_SESSION['saved']);
@@ -82,6 +89,8 @@ if(!$error) {
<textarea cols="70" rows="10">' . $content . '</textarea>'); <textarea cols="70" rows="10">' . $content . '</textarea>');
} }
} }
}
}
} }
?> ?>

View File

@@ -18,7 +18,6 @@ if(!$error) {
'locale' => $locale, 'locale' => $locale,
'session' => $_SESSION, 'session' => $_SESSION,
'account' => $account, 'account' => $account,
'hasTablePlayers' => $db->hasTable('players'),
'errors' => isset($errors) ? $errors : null, 'errors' => isset($errors) ? $errors : null,
'buttons' => next_buttons(true, $error ? false : true) 'buttons' => next_buttons(true, $error ? false : true)
)); ));

View File

@@ -1,48 +1,32 @@
<?php <?php
use MyAAC\Cache\Cache;
use MyAAC\Models\News;
use MyAAC\Settings;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
ini_set('max_execution_time', 300); ini_set('max_execution_time', 300);
if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) { if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) {
warning($locale['already_installed']); warning($locale['already_installed']);
return;
} }
else {
require SYSTEM . 'init.php';
if(!$error) {
if(USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER)
$account = isset($_SESSION['var_account']) ? $_SESSION['var_account'] : null;
else
$account_id = isset($_SESSION['var_account_id']) ? $_SESSION['var_account_id'] : null;
$cache = Cache::getInstance(); $password = $_SESSION['var_password'];
if ($cache->enabled()) {
// clear plugin_hooks to have fresh hooks
$cache->delete('plugins_hooks');
}
require SYSTEM . 'init.php'; if(USE_ACCOUNT_SALT)
if($error) { {
return;
}
if(USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER)
$account = $_SESSION['var_account'] ?? null;
else
$account_id = $_SESSION['var_account_id'] ?? null;
$password = $_SESSION['var_password'];
if(USE_ACCOUNT_SALT)
{
$salt = generateRandomString(10, false, true, true); $salt = generateRandomString(10, false, true, true);
$password = $salt . $password; $password = $salt . $password;
} }
$account_db = new OTS_Account(); $account_db = new OTS_Account();
if(isset($account)) if(isset($account))
$account_db->find($account); $account_db->find($account);
else else
$account_db->load($account_id); $account_db->load($account_id);
if ($db->hasTable('players')) {
$player_name = $_SESSION['var_player_name']; $player_name = $_SESSION['var_player_name'];
$player_db = new OTS_Player(); $player_db = new OTS_Player();
$player_db->find($player_name); $player_db->find($player_name);
@@ -60,17 +44,16 @@ if ($db->hasTable('players')) {
$groups = new OTS_Groups_List(); $groups = new OTS_Groups_List();
$player_used->setGroupId($groups->getHighestId()); $player_used->setGroupId($groups->getHighestId());
}
$email = $_SESSION['var_email']; $email = $_SESSION['var_email'];
if($account_db->isLoaded()) { if($account_db->isLoaded()) {
$account_db->setPassword(encrypt($password)); $account_db->setPassword(encrypt($password));
$account_db->setEMail($email); $account_db->setEMail($email);
$account_db->save(); $account_db->save();
$account_used = &$account_db; $account_used = &$account_db;
} }
else { else {
$new_account = new OTS_Account(); $new_account = new OTS_Account();
if(USE_ACCOUNT_NAME) { if(USE_ACCOUNT_NAME) {
$new_account->create($account); $new_account->create($account);
@@ -88,74 +71,53 @@ else {
$new_account->logAction('Account created.'); $new_account->logAction('Account created.');
$account_used = &$new_account; $account_used = &$new_account;
} }
if(USE_ACCOUNT_SALT) if(USE_ACCOUNT_SALT)
$account_used->setCustomField('salt', $salt); $account_used->setCustomField('salt', $salt);
$account_used->setCustomField('web_flags', FLAG_ADMIN + FLAG_SUPER_ADMIN); $account_used->setCustomField('web_flags', FLAG_ADMIN + FLAG_SUPER_ADMIN);
$account_used->setCustomField('country', 'us'); $account_used->setCustomField('country', 'us');
$account_used->setCustomField('email_verified', 1); if($db->hasColumn('accounts', 'group_id'))
if($db->hasColumn('accounts', 'group_id'))
$account_used->setCustomField('group_id', $groups->getHighestId()); $account_used->setCustomField('group_id', $groups->getHighestId());
if($db->hasColumn('accounts', 'type')) if($db->hasColumn('accounts', 'type'))
$account_used->setCustomField('type', 6); $account_used->setCustomField('type', 6);
if ($db->hasTable('players')) { if(!$player_db->isLoaded())
if(!$player_db->isLoaded()) {
$player->setAccountId($account_used->getId()); $player->setAccountId($account_used->getId());
$player->save(); else
}
else {
$player_db->setAccountId($account_used->getId()); $player_db->setAccountId($account_used->getId());
success($locale['step_database_created_account']);
setSession('account', $account_used->getId());
setSession('password', encrypt($password));
setSession('remember_me', true);
if($player_db->isLoaded()) {
$player_db->save(); $player_db->save();
} }
} else {
$player->save();
}
success($locale['step_database_created_account']);
setSession('account', $account_used->getId());
setSession('password', encrypt($password));
setSession('remember_me', true);
if(!News::all()->count()) {
$player_id = 0; $player_id = 0;
$query = $db->query("SELECT `id` FROM `players` WHERE `name` = " . $db->quote($player_name) . ";");
if ($db->hasTable('players')) { if($query->rowCount() == 1) {
$tmpNewsPlayer = \MyAAC\Models\Player::where('name', $player_name)->first(); $query = $query->fetch();
if($tmpNewsPlayer) { $player_id = $query['id'];
$player_id = $tmpNewsPlayer->id;
}
} }
News::create([ $query = $db->query("SELECT `id` FROM `" . TABLE_PREFIX ."news` WHERE `title` LIKE 'Hello!';");
'type' => 1, if($query->rowCount() == 0) {
'date' => time(), if(query("INSERT INTO `" . TABLE_PREFIX ."news` (`id`, `type`, `date`, `category`, `title`, `body`, `player_id`, `comments`, `hidden`) VALUES (NULL, '1', UNIX_TIMESTAMP(), '2', 'Hello!', 'MyAAC is just READY to use!', " . $player_id . ", 'https://my-aac.org', '0');
'category' => 2, INSERT INTO `myaac_news` (`id`, `type`, `date`, `category`, `title`, `body`, `player_id`, `comments`, `hidden`) VALUES (NULL, '2', UNIX_TIMESTAMP(), '4', 'Hello tickets!', 'https://my-aac.org', " . $player_id . ", '', '0');")) {
'title' => 'Hello!',
'body' => 'MyAAC is just READY to use!',
'player_id' => $player_id,
'comments' => 'https://my-aac.org',
'hide' => 0,
]);
News::create([
'type' => 2,
'date' => time(),
'category' => 4,
'title' => 'Hello tickers!',
'body' => 'https://my-aac.org',
'player_id' => $player_id,
'comments' => '',
'hide' => 0,
]);
success($locale['step_database_created_news']); success($locale['step_database_created_news']);
} }
}
$settings = Settings::getInstance(); $settings = Settings::getInstance();
foreach($_SESSION as $key => $value) { foreach($_SESSION as $key => $value) {
if (in_array($key, ['var_usage', 'var_date_timezone', 'var_client'])) { if (in_array($key, ['var_usage', 'var_date_timezone', 'var_client'])) {
if ($key == 'var_usage') { if ($key == 'var_usage') {
$key = 'anonymous_usage_statistics'; $key = 'anonymous_usage_statistics';
@@ -168,15 +130,15 @@ foreach($_SESSION as $key => $value) {
$settings->updateInDatabase('core', $key, $value); $settings->updateInDatabase('core', $key, $value);
} }
} }
success('Settings saved.'); success('Settings saved.');
$twig->display('install.installer.html.twig', array( $twig->display('install.installer.html.twig', array(
'url' => 'tools/7-finish.php', 'url' => 'tools/7-finish.php',
'message' => $locale['importing_spinner'] 'message' => $locale['importing_spinner']
)); ));
if(!isset($_SESSION['installed'])) { if(!isset($_SESSION['installed'])) {
if (!array_key_exists('CI', getenv())) { if (!array_key_exists('CI', getenv())) {
$report_url = 'https://my-aac.org/report_install.php?v=' . MYAAC_VERSION . '&b=' . urlencode(BASE_URL); $report_url = 'https://my-aac.org/report_install.php?v=' . MYAAC_VERSION . '&b=' . urlencode(BASE_URL);
if (function_exists('curl_version')) if (function_exists('curl_version'))
@@ -193,15 +155,15 @@ if(!isset($_SESSION['installed'])) {
} }
$_SESSION['installed'] = true; $_SESSION['installed'] = true;
} }
foreach($_SESSION as $key => $value) { foreach($_SESSION as $key => $value) {
if(strpos($key, 'var_') !== false) if(strpos($key, 'var_') !== false)
unset($_SESSION[$key]); unset($_SESSION[$key]);
} }
unset($_SESSION['saved']); unset($_SESSION['saved']);
if(file_exists(CACHE . 'install.txt')) { if(file_exists(CACHE . 'install.txt')) {
unlink(CACHE . 'install.txt'); unlink(CACHE . 'install.txt');
}
}
} }
$hooks->trigger(HOOK_INSTALL_FINISH_END);

View File

@@ -1,4 +1,3 @@
<?php defined('MYAAC') or die('Direct access not allowed!'); ?>
<!DOCTYPE html> <!DOCTYPE html>
<html dir="<?php echo $locale['direction']; ?>" lang="<?php echo $locale['lang']; ?>" xml:lang="<?php echo $locale['lang']; ?>"> <html dir="<?php echo $locale['direction']; ?>" lang="<?php echo $locale['lang']; ?>" xml:lang="<?php echo $locale['lang']; ?>">
<head> <head>
@@ -7,7 +6,7 @@
<title>MyAAC - <?php echo $locale['installation']; ?></title> <title>MyAAC - <?php echo $locale['installation']; ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="template/style.css" /> <link rel="stylesheet" type="text/css" href="template/style.css" />
<script type="text/javascript" src="<?php echo BASE_URL; ?>tools/ext/jquery/jquery.min.js"></script> <script type="text/javascript" src="<?php echo BASE_URL; ?>tools/js/jquery.min.js"></script>
</head> </head>
<body> <body>

View File

@@ -11,10 +11,8 @@ $error = false;
require BASE . 'install/includes/config.php'; require BASE . 'install/includes/config.php';
ini_set('max_execution_time', 300); ini_set('max_execution_time', 300);
@ob_end_flush();
ob_implicit_flush(); ob_implicit_flush();
ob_end_flush();
header('X-Accel-Buffering: no'); header('X-Accel-Buffering: no');
if(!$error) { if(!$error) {
@@ -32,9 +30,6 @@ if($db->hasTable(TABLE_PREFIX . 'account_actions')) {
else { else {
// import schema // import schema
try { 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->query(file_get_contents(BASE . 'install/includes/schema.sql'));
$locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']);
@@ -141,86 +136,75 @@ if(!$db->hasColumn('accounts', 'premium_points')) {
success($locale['step_database_adding_field'] . ' accounts.premium_points...'); success($locale['step_database_adding_field'] . ' accounts.premium_points...');
} }
if ($db->hasTable('guilds')) { if($db->hasColumn('guilds', 'checkdata')) {
if ($db->hasColumn('guilds', 'checkdata')) { if(query("ALTER TABLE `guilds` MODIFY `checkdata` INT NOT NULL DEFAULT 0;"))
if (query("ALTER TABLE `guilds` MODIFY `checkdata` INT NOT NULL DEFAULT 0;"))
success($locale['step_database_modifying_field'] . ' guilds.checkdata...'); success($locale['step_database_modifying_field'] . ' guilds.checkdata...');
} }
if (!$db->hasColumn('guilds', 'motd')) { if(!$db->hasColumn('guilds', 'motd')) {
if (query("ALTER TABLE `guilds` ADD `motd` VARCHAR(255) NOT NULL DEFAULT '';")) if(query("ALTER TABLE `guilds` ADD `motd` VARCHAR(255) NOT NULL DEFAULT '';"))
success($locale['step_database_adding_field'] . ' guilds.motd...'); success($locale['step_database_adding_field'] . ' guilds.motd...');
} else { }
if (query("ALTER TABLE `guilds` MODIFY `motd` VARCHAR(255) NOT NULL DEFAULT '';")) else {
if(query("ALTER TABLE `guilds` MODIFY `motd` VARCHAR(255) NOT NULL DEFAULT '';"))
success($locale['step_database_modifying_field'] . ' guilds.motd...'); success($locale['step_database_modifying_field'] . ' guilds.motd...');
} }
if (!$db->hasColumn('guilds', 'description')) { if(!$db->hasColumn('guilds', 'description')) {
if (query("ALTER TABLE `guilds` ADD `description` VARCHAR(5000) NOT NULL DEFAULT '';")) if(query("ALTER TABLE `guilds` ADD `description` TEXT NOT NULL;"))
success($locale['step_database_adding_field'] . ' guilds.description...'); success($locale['step_database_adding_field'] . ' guilds.description...');
} }
else {
if (query("ALTER TABLE `guilds` MODIFY `description` VARCHAR(5000) NOT NULL DEFAULT '';")) {
success($locale['step_database_modifying_field'] . ' guilds.description...');
}
}
if ($db->hasColumn('guilds', 'logo_gfx_name')) { if($db->hasColumn('guilds', 'logo_gfx_name')) {
if (query("ALTER TABLE `guilds` CHANGE `logo_gfx_name` `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) { if(query("ALTER TABLE `guilds` CHANGE `logo_gfx_name` `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) {
$tmp = str_replace('$FIELD$', 'guilds.logo_gfx_name', $locale['step_database_changing_field']); $tmp = str_replace('$FIELD$', 'guilds.logo_gfx_name', $locale['step_database_changing_field']);
$tmp = str_replace('$FIELD_NEW$', 'guilds.logo_name', $tmp); $tmp = str_replace('$FIELD_NEW$', 'guilds.logo_name', $tmp);
success($tmp); success($tmp);
} }
} else if (!$db->hasColumn('guilds', 'logo_name')) { }
if (query("ALTER TABLE `guilds` ADD `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) else if(!$db->hasColumn('guilds', 'logo_name')) {
if(query("ALTER TABLE `guilds` ADD `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';"))
success($locale['step_database_adding_field'] . ' guilds.logo_name...'); success($locale['step_database_adding_field'] . ' guilds.logo_name...');
}
} }
if ($db->hasTable('players')) { if(!$db->hasColumn('players', 'created')) {
if (!$db->hasColumn('players', 'created')) { if(query("ALTER TABLE `players` ADD `created` INT(11) NOT NULL DEFAULT 0;"))
if (query("ALTER TABLE `players` ADD `created` INT(11) NOT NULL DEFAULT 0;"))
success($locale['step_database_adding_field'] . ' players.created...'); success($locale['step_database_adding_field'] . ' players.created...');
} }
if (!$db->hasColumn('players', 'deleted') && !$db->hasColumn('players', 'deletion')) { if(!$db->hasColumn('players', 'deleted') && !$db->hasColumn('players', 'deletion')) {
if (query("ALTER TABLE `players` ADD `deleted` TINYINT(1) NOT NULL DEFAULT 0;")) if(query("ALTER TABLE `players` ADD `deleted` TINYINT(1) NOT NULL DEFAULT 0;"))
success($locale['step_database_adding_field'] . ' players.deleted...'); success($locale['step_database_adding_field'] . ' players.deleted...');
} }
if ($db->hasColumn('players', 'hide_char')) { if($db->hasColumn('players', 'hide_char')) {
if (!$db->hasColumn('players', 'hide')) { if(!$db->hasColumn('players', 'hidden')) {
if (query("ALTER TABLE `players` CHANGE `hide_char` `hide` TINYINT(1) NOT NULL DEFAULT 0;")) { if(query("ALTER TABLE `players` CHANGE `hide_char` `hidden` TINYINT(1) NOT NULL DEFAULT 0;")) {
$tmp = str_replace('$FIELD$', 'players.hide_char', $locale['step_database_changing_field']); $tmp = str_replace('$FIELD$', 'players.hide_char', $locale['step_database_changing_field']);
$tmp = str_replace('$FIELD_NEW$', 'players.hide', $tmp); $tmp = str_replace('$FIELD_NEW$', 'players.hidden', $tmp);
success($tmp); success($tmp);
} }
} }
} else if (!$db->hasColumn('players', 'hide')) { }
if (query("ALTER TABLE `players` ADD `hide` TINYINT(1) NOT NULL DEFAULT 0;")) else if(!$db->hasColumn('players', 'hidden')) {
success($locale['step_database_adding_field'] . ' players.hide...'); if(query("ALTER TABLE `players` ADD `hidden` TINYINT(1) NOT NULL DEFAULT 0;"))
} success($locale['step_database_adding_field'] . ' players.hidden...');
}
if (!$db->hasColumn('players', 'comment')) { if(!$db->hasColumn('players', 'comment')) {
if (query("ALTER TABLE `players` ADD `comment` VARCHAR(5000) NOT NULL DEFAULT '';")) if(query("ALTER TABLE `players` ADD `comment` TEXT NOT NULL;"))
success($locale['step_database_adding_field'] . ' players.comment...'); success($locale['step_database_adding_field'] . ' players.comment...');
} }
else {
if (query("ALTER TABLE `players` MODIFY `comment` VARCHAR(5000) NOT NULL DEFAULT '';")) {
success($locale['step_database_modifying_field'] . ' players.comment...');
}
}
if ($db->hasColumn('players', 'rank_id')) { if($db->hasColumn('players', 'rank_id')) {
if (query("ALTER TABLE players MODIFY `rank_id` INT(11) NOT NULL DEFAULT 0;")) if(query("ALTER TABLE players MODIFY `rank_id` INT(11) NOT NULL DEFAULT 0;"))
success($locale['step_database_modifying_field'] . ' players.rank_id...'); success($locale['step_database_modifying_field'] . ' players.rank_id...');
if ($db->hasColumn('players', 'guildnick')) { if($db->hasColumn('players', 'guildnick')) {
if (query("ALTER TABLE players MODIFY `guildnick` VARCHAR(255) NOT NULL DEFAULT '';")) { if(query("ALTER TABLE players MODIFY `guildnick` VARCHAR(255) NOT NULL DEFAULT '';")) {
success($locale['step_database_modifying_field'] . ' players.guildnick...'); success($locale['step_database_modifying_field'] . ' players.guildnick...');
} }
} }
}
} }
if($db->hasTable('z_forum')) { if($db->hasTable('z_forum')) {

View File

@@ -1,10 +1,6 @@
<?php <?php
define('MYAAC_INSTALL', true); define('MYAAC_INSTALL', true);
use MyAAC\DataLoader;
use MyAAC\Models\FAQ as ModelsFAQ;
use MyAAC\Plugins;
require_once '../../common.php'; require_once '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';
@@ -12,10 +8,8 @@ require BASE . 'install/includes/functions.php';
require BASE . 'install/includes/locale.php'; require BASE . 'install/includes/locale.php';
ini_set('max_execution_time', 300); ini_set('max_execution_time', 300);
@ob_end_flush();
ob_implicit_flush(); ob_implicit_flush();
ob_end_flush();
header('X-Accel-Buffering: no'); header('X-Accel-Buffering: no');
/* /*
if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) { if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) {
@@ -25,59 +19,51 @@ if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['save
require SYSTEM . 'init.php'; require SYSTEM . 'init.php';
if ($db->hasTable('players')) { $deleted = 'deleted';
$deleted = 'deleted'; if($db->hasColumn('players', 'deletion'))
if ($db->hasColumn('players', 'deletion'))
$deleted = 'deletion'; $deleted = 'deletion';
$time = time(); $time = time();
function insert_sample_if_not_exist($p) function insert_sample_if_not_exist($p) {
{
global $db, $success, $deleted, $time; global $db, $success, $deleted, $time;
$query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($p['name'])); $query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($p['name']));
if ($query->rowCount() == 0) { if($query->rowCount() == 0) {
if (!query("INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `lastlogout`, `balance`, `$deleted`, `created`, `hide`, `comment`) VALUES (null, " . $db->quote($p['name']) . ", 1, " . getSession('account') . ", " . $p['level'] . ", " . $p['vocation_id'] . ", " . $p['health'] . ", " . $p['healthmax'] . ", " . $p['experience'] . ", 118, 114, 38, 57, " . $p['looktype'] . ", 0, " . $p['mana'] . ", " . $p['manamax'] . ", 0, " . $p['soul'] . ", 1, 1000, 1000, 7, '', " . $p['cap'] . ", 1, " . $time . ", 2130706433, 1, " . $time . ", 0, 0, " . $time . ", 1, '');")) if(!query("INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `lastlogout`, `balance`, `$deleted`, `created`, `hidden`, `comment`) VALUES (null, " . $db->quote($p['name']) . ", 1, " . getSession('account') . ", " . $p['level'] . ", " . $p['vocation_id'] . ", " . $p['health'] . ", " . $p['healthmax'] . ", " . $p['experience'] . ", 118, 114, 38, 57, " . $p['looktype'] . ", 0, " . $p['mana'] . ", " . $p['manamax'] . ", 0, " . $p['soul'] . ", 1, 1000, 1000, 7, '', " . $p['cap'] . ", 1, " . $time . ", 2130706433, 1, " . $time . ", 0, 0, " . $time . ", 1, '');"))
$success = false; $success = false;
} }
}
$success = true;
insert_sample_if_not_exist(array('name' => 'Rook Sample', 'level' => 1, 'vocation_id' => 0, 'health' => 150, 'healthmax' => 150, 'experience' => 0, 'looktype' => 130, 'mana' => 0, 'manamax' => 0, 'soul' => 100, 'cap' => 400));
insert_sample_if_not_exist(array('name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
if ($success) {
success($locale['step_database_imported_players']);
}
} }
$success = true;
insert_sample_if_not_exist(array('name' => 'Rook Sample', 'level' => 1, 'vocation_id' => 0, 'health' => 150, 'healthmax' => 150, 'experience' => 0, 'looktype' => 130, 'mana' => 0, 'manamax' => 0, 'soul' => 100, 'cap' => 400));
insert_sample_if_not_exist(array('name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
if($success) {
success($locale['step_database_imported_players']);
}
require_once LIBS . 'plugins.php';
Plugins::installMenus('kathrine', require TEMPLATES . 'kathrine/menus.php'); Plugins::installMenus('kathrine', require TEMPLATES . 'kathrine/menus.php');
Plugins::installMenus('tibiacom', require TEMPLATES . 'tibiacom/menus.php'); Plugins::installMenus('tibiacom', require TEMPLATES . 'tibiacom/menus.php');
require LIBS . 'DataLoader.php';
DataLoader::setLocale($locale); DataLoader::setLocale($locale);
DataLoader::load(); DataLoader::load();
// update config.highscores_ids_hidden // update config.highscores_ids_hidden
require_once SYSTEM . 'migrations/20.php'; require_once SYSTEM . 'migrations/20.php';
$up();
// add z_polls tables // add z_polls tables
require_once SYSTEM . 'migrations/22.php'; require_once SYSTEM . 'migrations/22.php';
$up();
// add myaac_pages pages // add myaac_pages pages
require_once SYSTEM . 'migrations/27.php'; require_once SYSTEM . 'migrations/27.php';
$up();
require_once SYSTEM . 'migrations/30.php'; require_once SYSTEM . 'migrations/30.php';
$up();
// new monster columns
require_once SYSTEM . 'migrations/31.php';
$up();
use MyAAC\Models\FAQ as ModelsFAQ;
if(ModelsFAQ::count() == 0) { if(ModelsFAQ::count() == 0) {
ModelsFAQ::create([ ModelsFAQ::create([
'question' => 'What is this?', 'question' => 'What is this?',
@@ -85,10 +71,6 @@ if(ModelsFAQ::count() == 0) {
]); ]);
} }
$hooks->trigger(HOOK_INSTALL_FINISH);
$db->setClearCacheAfter(true);
$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('$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('$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']); $locale['step_finish_desc'] = str_replace('$LINK$', generateLink('https://my-aac.org', 'https://my-aac.org', true), $locale['step_finish_desc']);

View File

@@ -4,7 +4,6 @@ use MyAAC\Models\BoostedCreature;
use MyAAC\Models\PlayerOnline; use MyAAC\Models\PlayerOnline;
use MyAAC\Models\Account; use MyAAC\Models\Account;
use MyAAC\Models\Player; use MyAAC\Models\Player;
use MyAAC\RateLimit;
require_once 'common.php'; require_once 'common.php';
require_once SYSTEM . 'functions.php'; require_once SYSTEM . 'functions.php';
@@ -131,29 +130,12 @@ switch ($action) {
} }
$account = $account->first(); $account = $account->first();
$ip = get_browser_real_ip();
$limiter = new RateLimit('failed_logins', setting('core.account_login_attempts_limit'), setting('core.account_login_ban_time'));
$limiter->enabled = setting('core.account_login_ipban_protection');
$limiter->load();
$ban_msg = 'A wrong account, password or secret has been entered ' . setting('core.account_login_attempts_limit') . ' times in a row. You are unable to log into your account for the next ' . setting('core.account_login_ban_time') . ' minutes. Please wait.';
if (!$account) { if (!$account) {
$limiter->increment($ip);
if ($limiter->exceeded($ip)) {
sendError($ban_msg);
}
sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.'); sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.');
} }
$current_password = encrypt((USE_ACCOUNT_SALT ? $account->salt : '') . $request->password); $current_password = encrypt((USE_ACCOUNT_SALT ? $account->salt : '') . $request->password);
if (!$account || $account->password != $current_password) { if (!$account || $account->password != $current_password) {
$limiter->increment($ip);
if ($limiter->exceeded($ip)) {
sendError($ban_msg);
}
sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.'); sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.');
} }
@@ -163,30 +145,16 @@ switch ($action) {
if ($accountSecret != null && $accountSecret != '') { if ($accountSecret != null && $accountSecret != '') {
$accountHasSecret = true; $accountHasSecret = true;
if ($inputToken === false) { if ($inputToken === false) {
$limiter->increment($ip);
if ($limiter->exceeded($ip)) {
sendError($ban_msg);
}
sendError('Submit a valid two-factor authentication token.', 6); sendError('Submit a valid two-factor authentication token.', 6);
} else { } else {
require_once LIBS . 'rfc6238.php'; require_once LIBS . 'rfc6238.php';
if (TokenAuth6238::verify($accountSecret, $inputToken) !== true) { if (TokenAuth6238::verify($accountSecret, $inputToken) !== true) {
$limiter->increment($ip);
if ($limiter->exceeded($ip)) {
sendError($ban_msg);
}
sendError('Two-factor authentication failed, token is wrong.', 6); sendError('Two-factor authentication failed, token is wrong.', 6);
} }
} }
} }
} }
$limiter->reset($ip);
if (setting('core.account_mail_verify') && $account->email_verified !== 1) {
sendError('You need to verify your account, enter in our site and resend verify e-mail!');
}
// common columns // common columns
$columns = 'id, name, level, sex, vocation, looktype, lookhead, lookbody, looklegs, lookfeet, lookaddons'; $columns = 'id, name, level, sex, vocation, looktype, lookhead, lookbody, looklegs, lookfeet, lookaddons';

View File

@@ -1,6 +1,6 @@
server { server {
listen 80; listen 80;
root /var/www/html; root /home/otserv/www/public;
index index.php; index index.php;
server_name your-domain.com; server_name your-domain.com;
@@ -10,21 +10,22 @@ server {
# this is very important, be sure its in your nginx conf - it prevents access to logs etc. # this is very important, be sure its in your nginx conf - it prevents access to logs etc.
location ~ /system { location ~ /system {
deny all; deny all;
return 404;
} }
# block .htaccess, CHANGELOG.md, composer.json etc. # block .htaccess
# this is to prevent finding software versions location ~ /\.ht {
location ~\.(ht|md|json|dist)$ {
deny all; deny all;
} }
# block git files and folders # block git files and folders
location ~ /\.git { location ~ /\.git {
return 404;
deny all; deny all;
} }
location / { location / {
try_files $uri $uri/ /index.php?$query_string; try_files $uri $uri/ /index.php;
} }
location ~ \.php$ { location ~ \.php$ {

View File

@@ -1,16 +0,0 @@
const fse = require('fs-extra');
const path = require('path');
const nodeModulesDir = path.join(__dirname, 'node_modules');
const publicDir = path.join(__dirname, 'tools/ext');
fse.emptyDirSync(path.join(publicDir, 'jquery'));
fse.emptyDirSync(path.join(publicDir, 'jquery-ui'));
fse.emptyDirSync(path.join(publicDir, 'bootstrap'));
fse.emptyDirSync(path.join(publicDir, 'tinymce'));
fse.emptyDirSync(path.join(publicDir, 'tinymce-jquery'));
fse.copySync(path.join(nodeModulesDir, 'jquery', 'dist'), path.join(publicDir, 'jquery'), { overwrite: true });
fse.copySync(path.join(nodeModulesDir, 'jquery-ui', 'dist'), path.join(publicDir, 'jquery-ui'), { overwrite: true });
fse.copySync(path.join(nodeModulesDir, 'bootstrap', 'dist'), path.join(publicDir, 'bootstrap'), { overwrite: true });
fse.copySync(path.join(nodeModulesDir, 'tinymce'), path.join(publicDir, 'tinymce'), { overwrite: true });
fse.copySync(path.join(nodeModulesDir, '@tinymce', 'tinymce-jquery', 'dist'), path.join(publicDir, 'tinymce-jquery'), { overwrite: true });

994
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,8 @@
{ {
"scripts": { "scripts": {
"cypress:open": "cypress open", "cypress:open": "cypress open"
"postinstall": "node ./npm-post-install.js"
}, },
"devDependencies": { "devDependencies": {
"cypress": "^13.17.0" "cypress": "^12.12.0"
},
"dependencies": {
"@tinymce/tinymce-jquery": "^2.1.0",
"bootstrap": "^4.6.2",
"fs-extra": "^11.2.0",
"jquery": "^3.7.1",
"jquery-ui": "^1.13.2",
"tinymce": "^7.2.0"
} }
} }

View File

@@ -1,13 +0,0 @@
<?php
require __DIR__ . '/system/libs/pot/OTS.php';
$ots = POT::getInstance();
require __DIR__ . '/system/libs/pot/InvitesDriver.php';
require __DIR__ . '/system/libs/rfc6238.php';
require __DIR__ . '/common.php';
const ACTION = '';
const PAGE = '';
const URI = '';
define('SELF_NAME', basename(__FILE__));

View File

@@ -1,39 +0,0 @@
parameters:
level: 3
paths:
- .
- templates/tibiacom
- templates/kathrine
excludePaths:
- system/cache/*
- vendor/*
- plugins/*
- system/libs
- tools/signature/mango.php
- tools/signature/gd.class.php
bootstrapFiles:
- phpstan-bootstrap.php
ignoreErrors:
- '#Variable \$db might not be defined#'
- '#Variable \$twig might not be defined#'
- '#Variable \$hooks might not be defined#'
- '#Variable \$account_logged might not be defined#'
- '#Variable \$logged might not be defined#'
- '#Variable \$config might not be defined#'
- '#Variable \$action might not be defined#'
- '#Variable \$errors might not be defined#'
- '#Variable \$cache might not be defined#'
- '#Variable \$status might not be defined#'
- '#Variable \$player might not be defined#'
- '#Variable \$guild might not be defined#'
- '#Variable \$[a-zA-Z0-9\\_]+ might not be defined#'
# Eloquent models
- '#Call to an undefined static method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+\(\)#'
- '#Call to an undefined 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#'
-
message: '#Variable \$tmp in empty\(\) always exists and is always falsy#'
path: templates\kathrine\javascript.php

View File

@@ -1,6 +1,6 @@
{ {
"name": "create-account-hint", "name": "create-account-hint",
"description": "This plugin display text 'To play on Forgotten you need an account. All you have to do to create your new account is to enter an account name, password, country and your email address. Also you have to agree to the terms presented below. If you have done so, your account name will be shown on the following page and your account password will be sent to your email address along with further instructions. If you do not receive the email with your password, please check your spam filter.' on the create account page.", "description": "This plugin display text 'To play on Forgotten you need an account. All you have to do to create your new account is to enter an account name, password, country and your email address. Also you have to agree to the terms presented below. If you have done so, your account name will be shown on the following page and your account password will be sent to your email address along with further instructions. If you do not receive the email with your password, please check your spam filter.' on the create account page. <strong>Be careful when uninstalling this!</strong>",
"version": "1.0", "version": "1.0",
"author": "slawkens", "author": "slawkens",
"contact": "slawkens@gmail.com", "contact": "slawkens@gmail.com",

View File

@@ -9,4 +9,7 @@
*/ */
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$twig->display('account-create-hint/hint.html.twig'); global $twig_loader;
$twig_loader->prependPath(BASE . 'plugins/account-create-hint');
$twig->display('hint.html.twig');

View File

@@ -1,6 +1,8 @@
<?php <?php
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$reward = setting('core.account_mail_confirmed_reward');
$hasCoinsColumn = $db->hasColumn('accounts', 'coins'); $hasCoinsColumn = $db->hasColumn('accounts', 'coins');
$rewardCoins = setting('core.account_mail_confirmed_reward_coins'); $rewardCoins = setting('core.account_mail_confirmed_reward_coins');
if ($rewardCoins > 0 && !$hasCoinsColumn) { if ($rewardCoins > 0 && !$hasCoinsColumn) {

View File

@@ -25,8 +25,7 @@
"hooks": { "hooks": {
"Example Hook": { "Example Hook": {
"type": "BEFORE_PAGE", "type": "BEFORE_PAGE",
"file": "plugins/example/before.php", "file": "plugins/example/before.php"
"priority": 1000
} }
}, },
"routes": { "routes": {
@@ -34,20 +33,12 @@
"pattern": "/YourAwesomePage/{name:string}/{page:int}", "pattern": "/YourAwesomePage/{name:string}/{page:int}",
"file": "plugins/your-plugin/your-awesome-page.php", "file": "plugins/your-plugin/your-awesome-page.php",
"method": "GET", "method": "GET",
"priority": 130 "priority": "130"
}, },
"Redirect Example": { "Redirect Example": {
"redirect_from": "/redirectExample", "redirect_from": "/redirectExample",
"redirect_to": "account/manage" "redirect_to": "account/manage"
} }
}, },
"routes-default-priority": 1000, "settings": "plugins/your-plugin-folder/settings.php"
"pages-default-priority": 1000,
"settings": "plugins/your-plugin-folder/settings.php",
"autoload": {
"pages": true,
"pagesSubFolders": false,
"commands": true,
"themes": true
}
} }

View File

@@ -22,7 +22,7 @@ if [ $1 = "prepare" ]; then
mkdir -p tmp mkdir -p tmp
# get myaac from git archive # get myaac from git archive
git archive --format zip --output tmp/myaac.zip main git archive --format zip --output tmp/myaac.zip develop
cd tmp/ || exit cd tmp/ || exit
@@ -38,11 +38,7 @@ if [ $1 = "prepare" ]; then
cd $dir || exit cd $dir || exit
# dependencies # dependencies
composer install --no-dev --prefer-dist --optimize-autoloader composer install --no-dev
npm install
# node_modules is useless, we already have copy in tools/ext
rm -R node_modules
echo "Now you can make changes to $dir. When you are ready, type 'release.sh pack'" echo "Now you can make changes to $dir. When you are ready, type 'release.sh pack'"
exit exit

View File

@@ -0,0 +1,18 @@
<?php
if(PHP_SAPI !== 'cli') {
echo 'This script can be run only in command line mode.';
exit(1);
}
require_once __DIR__ . '/../../common.php';
require_once SYSTEM . 'functions.php';
require_once SYSTEM . 'init.php';
if(clearCache()) {
echo 'Cache cleared.' . PHP_EOL;
}
else {
echo 'Unexpected error.' . PHP_EOL;
exit(2);
}

19
system/bin/cronjob.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
require_once __DIR__ . '/../../common.php';
require_once SYSTEM . 'functions.php';
require_once SYSTEM . 'init.php';
require_once SYSTEM . 'hooks.php';
$hooks = new Hooks();
$hooks->load();
use GO\Scheduler;
// Create a new scheduler
$scheduler = new Scheduler();
$hooks->trigger(HOOK_CRONJOB, ['scheduler' => $scheduler]);
// Let the scheduler execute jobs which are due.
$scheduler->run();

View File

@@ -0,0 +1,50 @@
<?php
require_once __DIR__ . '/../../common.php';
require_once SYSTEM . 'functions.php';
require_once SYSTEM . 'init.php';
if(!IS_CLI) {
echo 'This script can be run only in command line mode.' . PHP_EOL;
exit(1);
}
if (MYAAC_OS !== 'LINUX') {
echo 'This script can be run only on linux.' . PHP_EOL;
exit(1);
}
$job = '* * * * * /usr/bin/php ' . SYSTEM . 'bin/cronjob.php >> ' . SYSTEM . 'logs/cron.log 2>&1';
if (cronjob_exists($job)) {
echo 'MyAAC cronjob already installed.' . PHP_EOL;
exit(0);
}
exec ('crontab -l', $content);
$content = implode(' ', $content);
$content .= PHP_EOL . $job;
file_put_contents(CACHE . 'cronjob', $content . PHP_EOL);
exec('crontab ' . CACHE. 'cronjob');
echo 'Installed crontab successfully.' . PHP_EOL;
function cronjob_exists($command)
{
$cronjob_exists=false;
exec('crontab -l', $crontab);
if(isset($crontab)&&is_array($crontab)) {
$crontab = array_flip($crontab);
if(isset($crontab[$command])){
$cronjob_exists = true;
}
}
return $cronjob_exists;
}

View File

@@ -0,0 +1,42 @@
<?php
if(PHP_SAPI !== 'cli') {
echo 'This script can be run only in command line mode.';
exit(1);
}
require_once __DIR__ . '/../../common.php';
require_once SYSTEM . 'functions.php';
require_once SYSTEM . 'init.php';
require_once SYSTEM . 'hooks.php';
require_once LIBS . 'plugins.php';
if($argc !== 2) {
echo 'This command expects one parameter: zip file name (plugin)' . PHP_EOL;
exit(2);
}
$path_to_file = $argv[1];
$ext = strtolower(pathinfo($path_to_file, PATHINFO_EXTENSION));
if($ext !== 'zip') {// check if it is zipped/compressed file
echo 'Please install only .zip files.' . PHP_EOL;
exit(3);
}
if(!file_exists($path_to_file)) {
echo 'ERROR: File ' . $path_to_file . ' does not exist' . PHP_EOL;
exit(4);
}
if(Plugins::install($path_to_file)) {
foreach(Plugins::getWarnings() as $warning) {
echo 'WARNING: ' . $warning;
}
$info = Plugins::getPluginJson();
echo (isset($info['name']) ? $info['name'] . ' p' : 'P') . 'lugin has been successfully installed.' . PHP_EOL;
}
else {
echo 'ERROR: ' . Plugins::getError() . PHP_EOL;
exit(5);
}

61
system/bin/send_email.php Normal file
View File

@@ -0,0 +1,61 @@
<?php
if(PHP_SAPI !== 'cli') {
echo 'This script can be run only in command line mode.';
exit(1);
}
require_once __DIR__ . '/../../common.php';
require_once SYSTEM . 'functions.php';
require_once SYSTEM . 'init.php';
if($argc !== 3) {
echo 'This command expects two parameters: account_name_or_id|player_name|email address, subject.' . PHP_EOL;
exit(2);
}
$email_account_name = $argv[1];
$subject = $argv[2];
$message = file_get_contents('php://stdin');
if(strpos($email_account_name, '@') === false) {
$account = new OTS_Account();
if(USE_ACCOUNT_NAME) {
$account->find($email_account_name);
}
else {
$account->load($email_account_name);
}
if($account->isLoaded()) {
$email_account_name = $account->getEMail();
}
else {
$player = new OTS_Player();
$player->find($email_account_name);
if($player->isLoaded()) {
$email_account_name = $player->getAccount()->getEMail();
}
else {
echo 'Cannot find player or account with name: ' . $email_account_name . '.' . PHP_EOL;
exit(3);
}
}
}
if(!Validator::email($email_account_name)) {
echo 'Invalid E-Mail format.' . PHP_EOL;
exit(4);
}
if(strlen($subject) > 255) {
echo 'Subject max length is 255 characters.' . PHP_EOL;
exit(5);
}
if(!_mail($email_account_name, $subject, $message)) {
echo 'An error occurred while sending email. More info can be found in system/logs/mailer-error.log';
exit(6);
}
echo 'Mail sent to ' . $email_account_name . '.' . PHP_EOL;

View File

@@ -105,8 +105,4 @@ $config['clients'] = [
1316, 1316,
1320, 1320,
1321, 1321,
1322,
1330,
1332,
1340,
]; ];

View File

@@ -9,8 +9,6 @@
*/ */
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
class Validator extends \MyAAC\Validator {}
function check_name($name, &$errors = '') { function check_name($name, &$errors = '') {
if(Validator::characterName($name)) if(Validator::characterName($name))
return true; return true;
@@ -74,7 +72,4 @@ function fieldExist($field, $table)
global $db; global $db;
return $db->hasColumn($table, $field); return $db->hasColumn($table, $field);
} }
?>
function getCreatureImgPath($creature): string {
return getMonsterImgPath($creature);
}

View File

@@ -36,5 +36,3 @@ class Guild extends OTS_Guild {
} }
class GuildRank extends OTS_GuildRank {} class GuildRank extends OTS_GuildRank {}
class House extends OTS_House {} class House extends OTS_House {}
class Cache extends \MyAAC\Cache\Cache {}

View File

@@ -44,7 +44,7 @@ switch($page)
break; break;
case 'killstatistics': case 'killstatistics':
$page = 'last-kills'; $page = 'lastkills';
break; break;
case 'buypoints': case 'buypoints':

View File

@@ -7,9 +7,6 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Cache\Cache;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
define('COUNTER_SYNC', 10); // how often counter is synchronized with database (each x site refreshes) define('COUNTER_SYNC', 10); // how often counter is synchronized with database (each x site refreshes)

View File

@@ -106,7 +106,6 @@ try {
'persistent' => @$config['database_persistent'] 'persistent' => @$config['database_persistent']
)); ));
global $db;
$db = POT::getInstance()->getDBHandle(); $db = POT::getInstance()->getDBHandle();
$capsule = new Capsule; $capsule = new Capsule;
$capsule->addConnection([ $capsule->addConnection([
@@ -128,7 +127,6 @@ try {
} }
if(defined('MYAAC_INSTALL')) { if(defined('MYAAC_INSTALL')) {
$error = $e->getMessage();
return; // installer will take care of this return; // installer will take care of this
} }

View File

@@ -8,21 +8,21 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Exceptions\SensitiveException; if (class_exists(\Whoops\Run::class)) {
use Whoops\Handler\PlainTextHandler; $whoops = new \Whoops\Run;
use Whoops\Handler\PrettyPageHandler; if(IS_CLI) {
use Whoops\Run; $whoops->pushHandler(new \Whoops\Handler\PlainTextHandler);
}
else {
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
}
if (class_exists(Run::class)) {
$whoops = new Run;
$whoopsHandler = IS_CLI ? (new PlainTextHandler()) : (new PrettyPageHandler());
$whoops->pushHandler($whoopsHandler);
$whoops->register(); $whoops->register();
return; return;
} }
require LIBS . 'SensitiveException.php';
/** /**
* @param Exception $exception * @param Exception $exception
*/ */

View File

@@ -9,17 +9,12 @@
*/ */
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Cache\Cache;
use MyAAC\CsrfToken; use MyAAC\CsrfToken;
use MyAAC\Items;
use MyAAC\Models\Config; use MyAAC\Models\Config;
use MyAAC\Models\Guild; use MyAAC\Models\Guild;
use MyAAC\Models\House; use MyAAC\Models\House;
use MyAAC\Models\Pages; use MyAAC\Models\Pages;
use MyAAC\Models\Player; use MyAAC\Models\Player;
use MyAAC\News;
use MyAAC\Plugins;
use MyAAC\Settings;
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use Twig\Loader\ArrayLoader as Twig_ArrayLoader; use Twig\Loader\ArrayLoader as Twig_ArrayLoader;
@@ -49,7 +44,7 @@ function warning($message, $return = false) {
return message($message, 'warning', $return); return message($message, 'warning', $return);
} }
function note($message, $return = false) { function note($message, $return = false) {
return message($message, 'note', $return); return info($message, $return);
} }
function info($message, $return = false) { function info($message, $return = false) {
return message($message, 'info', $return); return message($message, 'info', $return);
@@ -87,41 +82,25 @@ function getForumBoardLink($board_id, $page = NULL): string {
return BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'forum/board/' . (int)$board_id . (isset($page) ? '/' . $page : ''); return BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'forum/board/' . (int)$board_id . (isset($page) ? '/' . $page : '');
} }
function getPlayerLink($name, $generate = true, bool $colored = false): string function getPlayerLink($name, $generate = true): string
{ {
if (is_object($name) and $name instanceof OTS_Player) { if(is_numeric($name))
$player = $name; {
}
else {
$player = new OTS_Player(); $player = new OTS_Player();
if(is_numeric($name)) {
$player->load((int)$name); $player->load((int)$name);
} if($player->isLoaded())
else {
$player->find($name);
}
}
if (!$player->isLoaded()) {
return '(error)';
}
$name = $player->getName(); $name = $player->getName();
}
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'characters/' . urlencode($name); $url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'characters/' . urlencode($name);
if ($colored) {
$name = '<span style="color: ' . ($player->isOnline() ? 'green' : 'red') . ';">' . $name . '</span>';
}
if(!$generate) return $url; if(!$generate) return $url;
return generateLink($url, $name); return generateLink($url, $name);
} }
function getMonsterLink($name, $generate = true): string function getMonsterLink($name, $generate = true): string
{ {
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'monsters?name=' . urlencode($name); $url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'creatures/' . urlencode($name);
if(!$generate) return $url; if(!$generate) return $url;
return generateLink($url, $name); return generateLink($url, $name);
@@ -129,14 +108,16 @@ function getMonsterLink($name, $generate = true): string
function getHouseLink($name, $generate = true): string function getHouseLink($name, $generate = true): string
{ {
if(is_numeric($name)) { if(is_numeric($name))
{
$house = House::find(intval($name), ['name']); $house = House::find(intval($name), ['name']);
if ($house) { if ($house) {
$name = $house->name; $name = $house->name;
} }
} }
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'houses?name=' . urlencode($name);
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'houses/' . urlencode($name);
if(!$generate) return $url; if(!$generate) return $url;
return generateLink($url, $name); return generateLink($url, $name);
@@ -156,6 +137,7 @@ function getGuildLink($name, $generate = true): string
} }
function getItemNameById($id) { function getItemNameById($id) {
require_once LIBS . 'items.php';
$item = Items::get($id); $item = Items::get($id);
return !empty($item['name']) ? $item['name'] : ''; return !empty($item['name']) ? $item['name'] : '';
} }
@@ -215,7 +197,7 @@ function getFlagImage($country): string
* @param mixed $v Variable to check. * @param mixed $v Variable to check.
* @return bool Value boolean status. * @return bool Value boolean status.
*/ */
function getBoolean(mixed $v): bool function getBoolean($v): bool
{ {
if(is_bool($v)) { if(is_bool($v)) {
return $v; return $v;
@@ -224,10 +206,6 @@ function getBoolean(mixed $v): bool
if(is_numeric($v)) if(is_numeric($v))
return (int)$v > 0; return (int)$v > 0;
if (is_null($v)) {
return false;
}
$v = strtolower($v); $v = strtolower($v);
return $v === 'yes' || $v === 'true'; return $v === 'yes' || $v === 'true';
} }
@@ -275,7 +253,7 @@ function generateRandomString($length, $lowCase = true, $upCase = false, $numeri
function getForumBoards() function getForumBoards()
{ {
global $db, $canEdit; global $db, $canEdit;
$sections = $db->query('SELECT `id`, `name`, `description`, `closed`, `guild`, `access`' . ($canEdit ? ', `hide`, `ordering`' : '') . ' FROM `' . TABLE_PREFIX . 'forum_boards` ' . (!$canEdit ? ' WHERE `hide` != 1' : '') . $sections = $db->query('SELECT `id`, `name`, `description`, `closed`, `guild`, `access`' . ($canEdit ? ', `hidden`, `ordering`' : '') . ' FROM `' . TABLE_PREFIX . 'forum_boards` ' . (!$canEdit ? ' WHERE `hidden` != 1' : '') .
' ORDER BY `ordering`;'); ' ORDER BY `ordering`;');
if($sections) if($sections)
return $sections->fetchAll(); return $sections->fetchAll();
@@ -432,10 +410,7 @@ function delete_guild($id)
if(count($rank_list) > 0) { if(count($rank_list) > 0) {
$rank_list->orderBy('level'); $rank_list->orderBy('level');
global $db; global $db, $ots;
/**
* @var OTS_GuildRank $rank_in_guild
*/
foreach($rank_list as $rank_in_guild) { foreach($rank_list as $rank_in_guild) {
if($db->hasTable('guild_members')) if($db->hasTable('guild_members'))
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_members`.`rank_id` as `rank_id` FROM `players`, `guild_members` WHERE `guild_members`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_members`.`player_id` ORDER BY `name`;'); $players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_members`.`rank_id` as `rank_id` FROM `players`, `guild_members` WHERE `guild_members`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_members`.`player_id` ORDER BY `name`;');
@@ -494,30 +469,20 @@ function tickers()
*/ */
function template_place_holder($type): string function template_place_holder($type): string
{ {
global $twig, $template_place_holders, $debugBar; global $twig, $template_place_holders;
$ret = ''; $ret = '';
if (isset($debugBar)) {
$debugBarRenderer = $debugBar->getJavascriptRenderer();
}
if(array_key_exists($type, $template_place_holders) && is_array($template_place_holders[$type])) if(array_key_exists($type, $template_place_holders) && is_array($template_place_holders[$type]))
$ret = implode($template_place_holders[$type]); $ret = implode($template_place_holders[$type]);
if($type === 'head_start') { if($type === 'head_start') {
$ret .= template_header(); $ret .= template_header();
if (isset($debugBar)) {
$ret .= $debugBarRenderer->renderHead();
}
} }
elseif ($type === 'body_start') { elseif ($type === 'body_start') {
$ret .= $twig->render('browsehappy.html.twig'); $ret .= $twig->render('browsehappy.html.twig');
} }
elseif($type === 'body_end') { elseif($type === 'body_end') {
$ret .= template_ga_code(); $ret .= template_ga_code();
if (isset($debugBar)) {
$ret .= $debugBarRenderer->render();
}
} }
return $ret; return $ret;
@@ -587,12 +552,24 @@ function template_form()
{ {
global $template_name; global $template_name;
$templates = Cache::remember('templates', 5 * 60, function() { $cache = Cache::getInstance();
return get_templates(); if($cache->enabled())
}); {
$tmp = '';
if($cache->fetch('templates', $tmp)) {
$templates = unserialize($tmp);
}
else
{
$templates = get_templates();
$cache->set('templates', serialize($templates), 30);
}
}
else
$templates = get_templates();
$options = ''; $options = '';
foreach($templates as $value) foreach($templates as $key => $value)
$options .= '<option ' . ($template_name == $value ? 'SELECTED' : '') . '>' . $value . '</option>'; $options .= '<option ' . ($template_name == $value ? 'SELECTED' : '') . '>' . $value . '</option>';
global $twig; global $twig;
@@ -715,8 +692,11 @@ function getSkillName($skillId, $suffix = true)
/** /**
* Performs flag check on the current logged in user. * Performs flag check on the current logged in user.
* Table in database: accounts, field: website_flags * Table in database: accounts, field: website_flags
*
* @param int @flag Flag to be verified.
* @return bool If user got flag.
*/ */
function hasFlag(int $flag): bool { function hasFlag($flag) {
global $logged, $logged_flags; global $logged, $logged_flags;
return ($logged && ($logged_flags & $flag) == $flag); return ($logged && ($logged_flags & $flag) == $flag);
} }
@@ -789,7 +769,7 @@ function get_browser_languages()
$languages = str_replace(' ', '', $languages); $languages = str_replace(' ', '', $languages);
foreach(explode(',', $languages) as $language_list) foreach(explode(',', $languages) as $language_list)
$ret[] = substr($language_list, 0, 2); $ret[] .= substr($language_list, 0, 2);
return $ret; return $ret;
} }
@@ -808,10 +788,6 @@ function get_templates()
$ret[] = $file; $ret[] = $file;
} }
foreach (Plugins::getThemes() as $name => $path) {
$ret[] = $name;
}
return $ret; return $ret;
} }
@@ -982,29 +958,31 @@ function load_config_lua($filename)
continue; continue;
} }
$tmp_exp = explode('=', $line, 2); $tmp_exp = explode('=', $line, 2);
if(str_contains($line, 'dofile')) { if(strpos($line, 'dofile') !== false)
{
$delimiter = '"'; $delimiter = '"';
if(!str_contains($line, $delimiter)) { if(strpos($line, $delimiter) === false)
$delimiter = "'"; $delimiter = "'";
}
$tmp = explode($delimiter, $line); $tmp = explode($delimiter, $line);
$result = array_merge($result, load_config_lua($config['server_path'] . $tmp[1])); $result = array_merge($result, load_config_lua($config['server_path'] . $tmp[1]));
} }
else if(count($tmp_exp) >= 2) { else if(count($tmp_exp) >= 2)
{
$key = trim($tmp_exp[0]); $key = trim($tmp_exp[0]);
if(!str_starts_with($key, '--')) { if(0 !== strpos($key, '--'))
{
$value = trim($tmp_exp[1]); $value = trim($tmp_exp[1]);
if(str_contains($value, '--')) {// found some deep comment if(strpos($value, '--') !== false) {// found some deep comment
$value = preg_replace('/--.*$/i', '', $value); $value = preg_replace('/--.*$/i', '', $value);
} }
if(is_numeric($value)) if(is_numeric($value))
$result[$key] = (float) $value; $result[$key] = (float) $value;
elseif(in_array(@$value[0], array("'", '"')) && in_array(@$value[strlen($value) - 1], array("'", '"'))) elseif(in_array(@$value[0], array("'", '"')) && in_array(@$value[strlen($value) - 1], array("'", '"')))
$result[$key] = substr(substr($value, 1), 0, -1); $result[$key] = (string) substr(substr($value, 1), 0, -1);
elseif(in_array($value, array('true', 'false'))) elseif(in_array($value, array('true', 'false')))
$result[$key] = $value === 'true'; $result[$key] = ($value === 'true') ? true : false;
elseif(@$value[0] === '{') { elseif(@$value[0] === '{') {
// arrays are not supported yet // arrays are not supported yet
// just ignore the error // just ignore the error
@@ -1012,19 +990,12 @@ function load_config_lua($filename)
} }
else else
{ {
foreach($result as $tmp_key => $tmp_value) { // load values defined by other keys, like: dailyFragsToBlackSkull = dailyFragsToRedSkull foreach($result as $tmp_key => $tmp_value) // load values definied by other keys, like: dailyFragsToBlackSkull = dailyFragsToRedSkull
$value = str_replace($tmp_key, $tmp_value, $value); $value = str_replace($tmp_key, $tmp_value, $value);
} $ret = @eval("return $value;");
if((string) $ret == '' && trim($value) !== '""') // = parser error
try { {
$ret = eval("return $value;"); throw new RuntimeException('ERROR: Loading config.lua file. Line <b>' . ($ln + 1) . '</b> of LUA config file is not valid [key: <b>' . $key . '</b>]');
}
catch (Throwable $e) {
throw new RuntimeException('ERROR: Loading config.lua file. Line: ' . ($ln + 1) . ' - Unable to parse value "' . $value . '" - ' . $e->getMessage());
}
if((string) $ret == '' && trim($value) !== '""') {
throw new RuntimeException('ERROR: Loading config.lua file. Line ' . ($ln + 1) . ' is not valid [key: ' . $key . ']');
} }
$result[$key] = $ret; $result[$key] = $ret;
} }
@@ -1033,10 +1004,11 @@ function load_config_lua($filename)
} }
} }
return array_merge($result, $config['lua'] ?? []); $result = array_merge($result, isset($config['lua']) ? $config['lua'] : array());
return $result;
} }
function str_replace_first($search,$replace, $subject) { function str_replace_first($search, $replace, $subject) {
$pos = strpos($subject, $search); $pos = strpos($subject, $search);
if ($pos !== false) { if ($pos !== false) {
return substr_replace($subject, $replace, $pos, strlen($search)); return substr_replace($subject, $replace, $pos, strlen($search));
@@ -1059,38 +1031,19 @@ function get_browser_real_ip() {
return '0'; return '0';
} }
function setSession($key, $value = null): void { function setSession($key, $data) {
if (!is_array($key)) { $_SESSION[setting('core.session_prefix') . $key] = $data;
$key = [$key => $value];
}
foreach ($key as $arrayKey => $arrayValue) {
if (is_null($arrayValue)) {
unsetSession($arrayKey);
}
else {
$_SESSION[setting('core.session_prefix') . $arrayKey] = $arrayValue;
}
}
} }
function getSession($key) { function getSession($key) {
return $_SESSION[setting('core.session_prefix') . $key] ?? null; $key = setting('core.session_prefix') . $key;
return isset($_SESSION[$key]) ? $_SESSION[$key] : false;
} }
function unsetSession($key): void { function unsetSession($key) {
unset($_SESSION[setting('core.session_prefix') . $key]); unset($_SESSION[setting('core.session_prefix') . $key]);
} }
function session($key): mixed { function csrf(): void {
if (is_array($key)) { CsrfToken::create();
setSession($key);
return null;
}
return getSession($key);
}
function csrf(bool $return = false): string {
return CsrfToken::create($return);
} }
function csrfToken(): string { function csrfToken(): string {
@@ -1099,7 +1052,7 @@ function csrfToken(): string {
function isValidToken(): bool { function isValidToken(): bool {
$token = $_POST['csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? null; $token = $_POST['csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? null;
return (!isRequestMethod('post') || (isset($token) && CsrfToken::isValid($token))); return ($_SERVER['REQUEST_METHOD'] !== 'POST' || (isset($token) && CsrfToken::isValid($token)));
} }
function csrfProtect(): void function csrfProtect(): void
@@ -1111,16 +1064,20 @@ function csrfProtect(): void
} }
} }
function getTopPlayers($limit = 5, $skill = 'level') { function getTopPlayers($limit = 5) {
global $db; global $db;
if ($skill === 'level') { $cache = Cache::getInstance();
$skill = 'experience'; if($cache->enabled()) {
$tmp = '';
if($cache->fetch('top_' . $limit . '_level', $tmp)) {
$players = unserialize($tmp);
}
} }
return Cache::remember("top_{$limit}_{$skill}", 2 * 60, function () use ($db, $limit, $skill) { if (!isset($players)) {
$columns = [ $columns = [
'id', 'name', 'level', 'vocation', 'experience', 'balance', 'id', 'name', 'level', 'vocation', 'experience',
'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet' 'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet'
]; ];
@@ -1128,27 +1085,36 @@ function getTopPlayers($limit = 5, $skill = 'level') {
$columns[] = 'lookaddons'; $columns[] = 'lookaddons';
} }
return Player::query() if ($db->hasColumn('players', 'online')) {
$columns[] = 'online';
}
$players = Player::query()
->select($columns) ->select($columns)
->withOnlineStatus() ->withOnlineStatus()
->notDeleted() ->notDeleted()
->where('group_id', '<', setting('core.highscores_groups_hidden')) ->where('group_id', '<', setting('core.highscores_groups_hidden'))
->whereNotIn('id', setting('core.highscores_ids_hidden')) ->whereNotIn('id', setting('core.highscores_ids_hidden'))
->where('account_id', '!=', 1) ->where('account_id', '!=', 1)
->orderByDesc($skill) ->orderByDesc('experience')
->limit($limit) ->limit($limit)
->get() ->get()
->map(function ($e, $i) { ->map(function ($e, $i) {
$row = $e->toArray(); $row = $e->toArray();
$row['online'] = $e->online_status; $row['online'] = $e->online_status;
$row['rank'] = $i + 1; $row['rank'] = $i + 1;
$row['outfit_url'] = $e->outfit_url;
unset($row['online_table']); unset($row['online_table']);
return $row; return $row;
})->toArray(); })->toArray();
});
if($cache->enabled()) {
$cache->set('top_' . $limit . '_level', serialize($players), 120);
}
}
return $players;
} }
function deleteDirectory($dir, $ignore = array(), $contentOnly = false) { function deleteDirectory($dir, $ignore = array(), $contentOnly = false) {
@@ -1215,70 +1181,86 @@ function setting($key)
function clearCache() function clearCache()
{ {
require_once LIBS . 'news.php';
News::clearCache(); News::clearCache();
$cache = Cache::getInstance(); $cache = Cache::getInstance();
if($cache->enabled()) { if($cache->enabled()) {
$keysToClear = [ $tmp = '';
'status', 'templates',
'config_lua', if ($cache->fetch('status', $tmp))
'towns', 'groups', 'vocations', $cache->delete('status');
'visitors', 'views_counter', 'failed_logins',
'template_menus', if ($cache->fetch('templates', $tmp))
'last_kills', $cache->delete('templates');
'hooks', 'plugins_hooks', 'plugins_routes', 'plugins_settings', 'plugins_themes', 'plugins_commands',
'settings', if ($cache->fetch('config_lua', $tmp))
]; $cache->delete('config_lua');
if ($cache->fetch('vocations', $tmp))
$cache->delete('vocations');
if ($cache->fetch('towns', $tmp))
$cache->delete('towns');
if ($cache->fetch('groups', $tmp))
$cache->delete('groups');
if ($cache->fetch('visitors', $tmp))
$cache->delete('visitors');
if ($cache->fetch('views_counter', $tmp))
$cache->delete('views_counter');
if ($cache->fetch('failed_logins', $tmp))
$cache->delete('failed_logins');
foreach (get_templates() as $template) { foreach (get_templates() as $template) {
$keysToClear[] = 'template_ini_' . $template; if ($cache->fetch('template_ini_' . $template, $tmp)) {
} $cache->delete('template_ini_' . $template);
// highscores cache
$configHighscoresPerPage = setting('core.highscores_per_page');
$skills = [POT::SKILL_FIST, POT::SKILL_CLUB, POT::SKILL_SWORD, POT::SKILL_AXE, POT::SKILL_DIST, POT::SKILL_SHIELD, POT::SKILL_FISH, POT::SKILL_LEVEL, POT::SKILL__MAGLEVEL, SKILL_FRAGS, SKILL_BALANCE];
foreach ($skills as $skill) {
// config('vocations') may be empty after previous cache clear
$vocations = (config('vocations') ?? []) + ['all'];
foreach ($vocations as $vocation) {
for($page = 0; $page < 10; $page++) {
$cacheKey = 'highscores_' . $skill . '_' . strtolower($vocation) . '_' . $page . '_' . $configHighscoresPerPage;
$keysToClear[] = $cacheKey;
}
}
}
foreach ($keysToClear as $item) {
$tmp = '';
if ($cache->fetch($item, $tmp)) {
$cache->delete($item);
} }
} }
global $db; if ($cache->fetch('template_menus', $tmp)) {
$db->setClearCacheAfter(true); $cache->delete('template_menus');
}
if ($cache->fetch('database_tables', $tmp)) {
$cache->delete('database_tables');
}
if ($cache->fetch('database_columns', $tmp)) {
$cache->delete('database_columns');
}
if ($cache->fetch('database_checksum', $tmp)) {
$cache->delete('database_checksum');
}
if ($cache->fetch('last_kills', $tmp)) {
$cache->delete('last_kills');
}
if ($cache->fetch('hooks', $tmp)) {
$cache->delete('hooks');
}
if ($cache->fetch('plugins_hooks', $tmp)) {
$cache->delete('plugins_hooks');
}
if ($cache->fetch('plugins_routes', $tmp)) {
$cache->delete('plugins_routes');
}
} }
deleteDirectory(CACHE . 'signatures', ['index.html'], true); deleteDirectory(CACHE . 'signatures', ['index.html'], true);
deleteDirectory(CACHE . 'twig', ['index.html'], true); deleteDirectory(CACHE . 'twig', ['index.html'], true);
deleteDirectory(CACHE . 'plugins', ['index.html'], true); deleteDirectory(CACHE . 'plugins', ['index.html'], true);
deleteDirectory(CACHE, ['signatures', 'twig', 'plugins', 'index.html', 'persistent'], true); deleteDirectory(CACHE, ['signatures', 'twig', 'plugins', 'index.html'], true);
// routes cache // routes cache
clearRouteCache();
global $hooks;
$hooks->trigger(HOOK_CACHE_CLEAR, ['cache' => Cache::getInstance()]);
return true;
}
function clearRouteCache(): void
{
$routeCacheFile = CACHE . 'route.cache'; $routeCacheFile = CACHE . 'route.cache';
if (file_exists($routeCacheFile)) { if (file_exists($routeCacheFile)) {
unlink($routeCacheFile); unlink($routeCacheFile);
} }
return true;
} }
function getCustomPageInfo($name) function getCustomPageInfo($name)
@@ -1320,6 +1302,13 @@ function getCustomPage($name, &$success): string
else else
$tmp = $page['body']; $tmp = $page['body'];
$php_errors = array();
function error_handler($errno, $errstr) {
global $php_errors;
$php_errors[] = array('errno' => $errno, 'errstr' => $errstr);
}
set_error_handler('error_handler');
global $config; global $config;
if(setting('core.backward_support')) { if(setting('core.backward_support')) {
global $SQL, $main_content, $subtopic; global $SQL, $main_content, $subtopic;
@@ -1329,6 +1318,11 @@ function getCustomPage($name, &$success): string
eval($tmp); eval($tmp);
$content .= ob_get_contents(); $content .= ob_get_contents();
ob_end_clean(); ob_end_clean();
restore_error_handler();
if(isset($php_errors[0]) && superAdmin()) {
var_dump($php_errors);
}
} }
else { else {
$oldLoader = $twig->getLoader(); $oldLoader = $twig->getLoader();
@@ -1572,19 +1566,18 @@ function right($str, $length) {
return substr($str, -$length); return substr($str, -$length);
} }
function getMonsterImgPath($monster): string function getCreatureImgPath($creature){
{ $creature_path = setting('core.monsters_images_url');
$monster_path = setting('core.monsters_images_url'); $creature_gfx_name = trim(strtolower($creature)) . setting('core.monsters_images_extension');
$monster_gfx_name = trim(strtolower($monster)) . setting('core.monsters_images_extension'); if (!file_exists($creature_path . $creature_gfx_name)) {
if (!file_exists($monster_path . $monster_gfx_name)) { $creature_gfx_name = str_replace(" ", "", $creature_gfx_name);
$monster_gfx_name = str_replace(" ", "", $monster_gfx_name); if (file_exists($creature_path . $creature_gfx_name)) {
if (file_exists($monster_path . $monster_gfx_name)) { return $creature_path . $creature_gfx_name;
return $monster_path . $monster_gfx_name;
} else { } else {
return $monster_path . 'nophoto.png'; return $creature_path . 'nophoto.png';
} }
} else { } else {
return $monster_path . $monster_gfx_name; return $creature_path . $creature_gfx_name;
} }
} }
@@ -1635,7 +1628,7 @@ function removeIfFirstSlash(&$text) {
}; };
function escapeHtml($html) { function escapeHtml($html) {
return htmlspecialchars($html); return htmlentities($html, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
} }
function getGuildNameById($id) function getGuildNameById($id)
@@ -1672,31 +1665,9 @@ function displayErrorBoxWithBackButton($errors, $action = null) {
]); ]);
} }
function makeLinksClickable($text, $blank = true) {
return preg_replace('!(((f|ht)tp(s)?://)[-a-zA-Zа-яА-Я()0-9@:%_+.~#?&;//=]+)!i', '<a href="$1"' . (!$blank ?: ' target="_blank"') . '>$1</a>', $text);
}
function isRequestMethod(string $method): bool {
return strtolower($_SERVER['REQUEST_METHOD']) == strtolower($method);
}
function getAccountIdentityColumn(): string
{
if (USE_ACCOUNT_NAME) {
return 'name';
}
elseif (USE_ACCOUNT_NUMBER) {
return 'number';
}
return 'id';
}
// validator functions // validator functions
require_once LIBS . 'validator.php';
require_once SYSTEM . 'compat/base.php'; require_once SYSTEM . 'compat/base.php';
// custom functions // custom functions
$customFunctions = SYSTEM . 'functions_custom.php'; require SYSTEM . 'functions_custom.php';
if (is_file($customFunctions)) {
require $customFunctions;
}

View File

@@ -1,11 +1,15 @@
<?php <?php
/**
const SKILL_FRAGS = -1; * Events system
const SKILL_BALANCE = -2; *
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
$i = 0; $i = 0;
define('HOOK_INIT', ++$i);
define('HOOK_STARTUP', ++$i); define('HOOK_STARTUP', ++$i);
define('HOOK_BEFORE_PAGE', ++$i); define('HOOK_BEFORE_PAGE', ++$i);
define('HOOK_AFTER_PAGE', ++$i); define('HOOK_AFTER_PAGE', ++$i);
@@ -46,12 +50,6 @@ define('HOOK_ACCOUNT_CREATE_AFTER_TOWNS', ++$i);
define('HOOK_ACCOUNT_CREATE_BEFORE_SUBMIT_BUTTON', ++$i); define('HOOK_ACCOUNT_CREATE_BEFORE_SUBMIT_BUTTON', ++$i);
define('HOOK_ACCOUNT_CREATE_AFTER_FORM', ++$i); define('HOOK_ACCOUNT_CREATE_AFTER_FORM', ++$i);
define('HOOK_ACCOUNT_CREATE_POST', ++$i); define('HOOK_ACCOUNT_CREATE_POST', ++$i);
define('HOOK_ACCOUNT_CREATE_AFTER_SUBMIT', ++$i);
define('HOOK_ACCOUNT_CREATE_AFTER_SAVED', ++$i);
define('HOOK_ACCOUNT_MANAGE_BEFORE_GENERAL_INFORMATION', ++$i);
define('HOOK_ACCOUNT_MANAGE_BEFORE_PUBLIC_INFORMATION', ++$i);
define('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS', ++$i);
define('HOOK_ACCOUNT_MANAGE_BEFORE_CHARACTERS', ++$i);
define('HOOK_ACCOUNT_LOGIN_BEFORE_PAGE', ++$i); define('HOOK_ACCOUNT_LOGIN_BEFORE_PAGE', ++$i);
define('HOOK_ACCOUNT_LOGIN_BEFORE_ACCOUNT', ++$i); define('HOOK_ACCOUNT_LOGIN_BEFORE_ACCOUNT', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT', ++$i); define('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT', ++$i);
@@ -60,26 +58,12 @@ define('HOOK_ACCOUNT_LOGIN_AFTER_PASSWORD', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_REMEMBER_ME', ++$i); define('HOOK_ACCOUNT_LOGIN_AFTER_REMEMBER_ME', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_PAGE', ++$i); define('HOOK_ACCOUNT_LOGIN_AFTER_PAGE', ++$i);
define('HOOK_ACCOUNT_LOGIN_POST', ++$i); define('HOOK_ACCOUNT_LOGIN_POST', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_AFTER', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_BEFORE_FIRST_TABLE', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_BEFORE_VOCATIONS', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_BEFORE_TOWNS', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_AFTER_TOWNS', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_AFTER_SECOND_TABLE', ++$i);
define('HOOK_ADMIN_HEAD_END', ++$i); define('HOOK_ADMIN_HEAD_END', ++$i);
define('HOOK_ADMIN_HEAD_START', ++$i); define('HOOK_ADMIN_HEAD_START', ++$i);
define('HOOK_ADMIN_BODY_START', ++$i); define('HOOK_ADMIN_BODY_START', ++$i);
define('HOOK_ADMIN_BODY_END', ++$i); define('HOOK_ADMIN_BODY_END', ++$i);
define('HOOK_ADMIN_BEFORE_PAGE', ++$i); define('HOOK_ADMIN_BEFORE_PAGE', ++$i);
define('HOOK_ADMIN_MENU', ++$i); define('HOOK_ADMIN_MENU', ++$i);
define('HOOK_ADMIN_NEWS_ADD_PRE', ++$i);
define('HOOK_ADMIN_NEWS_ADD', ++$i);
define('HOOK_ADMIN_NEWS_UPDATE_PRE', ++$i);
define('HOOK_ADMIN_NEWS_UPDATE', ++$i);
define('HOOK_ADMIN_NEWS_DELETE_PRE', ++$i);
define('HOOK_ADMIN_NEWS_DELETE', ++$i);
define('HOOK_ADMIN_NEWS_TOGGLE_HIDE_PRE', ++$i);
define('HOOK_ADMIN_NEWS_TOGGLE_HIDE', ++$i);
define('HOOK_ADMIN_LOGIN_AFTER_ACCOUNT', ++$i); define('HOOK_ADMIN_LOGIN_AFTER_ACCOUNT', ++$i);
define('HOOK_ADMIN_LOGIN_AFTER_PASSWORD', ++$i); define('HOOK_ADMIN_LOGIN_AFTER_PASSWORD', ++$i);
define('HOOK_ADMIN_LOGIN_AFTER_SIGN_IN', ++$i); define('HOOK_ADMIN_LOGIN_AFTER_SIGN_IN', ++$i);
@@ -93,37 +77,87 @@ define('HOOK_GUILDS_AFTER_GUILD_INFORMATION', ++$i);
define('HOOK_GUILDS_AFTER_GUILD_MEMBERS', ++$i); define('HOOK_GUILDS_AFTER_GUILD_MEMBERS', ++$i);
define('HOOK_GUILDS_AFTER_INVITED_CHARACTERS', ++$i); define('HOOK_GUILDS_AFTER_INVITED_CHARACTERS', ++$i);
define('HOOK_TWIG', ++$i); define('HOOK_TWIG', ++$i);
define('HOOK_CACHE_CLEAR', ++$i);
define('HOOK_INSTALL_FINISH', ++$i);
define('HOOK_INSTALL_FINISH_END', ++$i);
const HOOK_FIRST = HOOK_INIT; const HOOK_FIRST = HOOK_STARTUP;
define('HOOK_LAST', $i); define('HOOK_LAST', $i);
function is_sub_dir($path = NULL, $parent_folder = BASE): bool|string require_once LIBS . 'plugins.php';
class Hook
{ {
//Get directory path minus last folder private $_name, $_type, $_file;
$dir = dirname($path);
$folder = substr($path, strlen($dir));
//Check the base dir is valid public function __construct($name, $type, $file) {
$dir = realpath($dir); $this->_name = $name;
$this->_type = $type;
//Only allow valid filename characters $this->_file = $file;
$folder = preg_replace('/[^a-z0-9\.\-_]/i', '', $folder);
//If this is a bad path or a bad end folder name
if( !$dir OR !$folder OR $folder === '.') {
return false;
} }
//Rebuild path public function execute($params)
$path = $dir. '/' . $folder; {
global $db, $config, $template_path, $ots, $content, $twig;
//If this path is higher than the parent folder if(is_callable($this->_file))
if( strcasecmp($path, $parent_folder) > 0 ) { {
return $path; $params['db'] = $db;
$params['config'] = $config;
$params['template_path'] = $template_path;
$params['ots'] = $ots;
$params['content'] = $content;
$params['twig'] = $twig;
$tmp = $this->_file;
$ret = $tmp($params);
}
else {
extract($params);
$ret = include BASE . $this->_file;
} }
return false; return !isset($ret) || $ret == 1 || $ret;
}
public function name() {return $this->_name;}
public function type() {return $this->_type;}
}
class Hooks
{
private static $_hooks = array();
public function register($hook, $type = '', $file = null) {
if(!($hook instanceof Hook))
$hook = new Hook($hook, $type, $file);
self::$_hooks[$hook->type()][] = $hook;
}
public function trigger($type, $params = array())
{
$ret = true;
if(isset(self::$_hooks[$type]))
{
foreach(self::$_hooks[$type] as $name => $hook) {
/** @var $hook Hook */
if (!$hook->execute($params)) {
$ret = false;
}
}
}
return $ret;
}
public function exist($type) {
return isset(self::$_hooks[$type]);
}
public function load()
{
foreach(Plugins::getHooks() as $hook) {
$this->register($hook['name'], $hook['type'], $hook['file']);
}
Plugins::clearWarnings();
}
} }

View File

@@ -8,16 +8,10 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use DebugBar\StandardDebugBar;
use MyAAC\Cache\Cache;
use MyAAC\CsrfToken; use MyAAC\CsrfToken;
use MyAAC\Hooks;
use MyAAC\Models\Town;
use MyAAC\Settings;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
global $config;
if(!isset($config['installed']) || !$config['installed']) { if(!isset($config['installed']) || !$config['installed']) {
throw new RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.'); throw new RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.');
} }
@@ -26,10 +20,6 @@ if(config('env') === 'dev') {
require SYSTEM . 'exception.php'; require SYSTEM . 'exception.php';
} }
if (config('env') === 'dev' || getBoolean(config('enable_debugbar'))) {
$debugBar = new StandardDebugBar();
}
if(empty($config['server_path'])) { if(empty($config['server_path'])) {
throw new RuntimeException('Server Path has been not set. Go to config.php and set it.'); throw new RuntimeException('Server Path has been not set. Go to config.php and set it.');
} }
@@ -39,18 +29,17 @@ if($config['server_path'][strlen($config['server_path']) - 1] !== '/')
$config['server_path'] .= '/'; $config['server_path'] .= '/';
// enable gzip compression if supported by the browser // enable gzip compression if supported by the browser
if(isset($config['gzip_output']) && $config['gzip_output'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && str_contains($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('ob_gzhandler')) if(isset($config['gzip_output']) && $config['gzip_output'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false && function_exists('ob_gzhandler'))
ob_start('ob_gzhandler'); ob_start('ob_gzhandler');
// cache // cache
global $cache; require_once SYSTEM . 'libs/cache.php';
$cache = Cache::getInstance(); $cache = Cache::getInstance();
// event system // event system
global $hooks; require_once SYSTEM . 'hooks.php';
$hooks = new Hooks(); $hooks = new Hooks();
$hooks->load(); $hooks->load();
$hooks->trigger(HOOK_INIT);
// twig // twig
require_once SYSTEM . 'twig.php'; require_once SYSTEM . 'twig.php';
@@ -59,24 +48,28 @@ require_once SYSTEM . 'twig.php';
$action = $_REQUEST['action'] ?? ''; $action = $_REQUEST['action'] ?? '';
define('ACTION', $action); define('ACTION', $action);
// errors, is also often used
$errors = [];
// trim values we receive // trim values we receive
foreach($_POST as $var => $value) { if(isset($_POST))
{
foreach($_POST as $var => $value) {
if(is_string($value)) { if(is_string($value)) {
$_POST[$var] = trim($value); $_POST[$var] = trim($value);
} }
}
} }
if(isset($_GET))
foreach($_GET as $var => $value) { {
foreach($_GET as $var => $value) {
if(is_string($value)) if(is_string($value))
$_GET[$var] = trim($value); $_GET[$var] = trim($value);
}
} }
if(isset($_REQUEST))
foreach($_REQUEST as $var => $value) { {
foreach($_REQUEST as $var => $value) {
if(is_string($value)) if(is_string($value))
$_REQUEST[$var] = trim($value); $_REQUEST[$var] = trim($value);
}
} }
// load otserv config file // load otserv config file
@@ -97,8 +90,8 @@ if($config_lua_reload) {
// cache config // cache config
if($cache->enabled()) { if($cache->enabled()) {
$cache->set('config_lua', serialize($config['lua']), 2 * 60); $cache->set('config_lua', serialize($config['lua']), 120);
$cache->set('server_path', $config['server_path'], 10 * 60); $cache->set('server_path', $config['server_path']);
} }
} }
unset($tmp); unset($tmp);
@@ -132,24 +125,18 @@ if(!isset($foundValue)) {
$config['data_path'] = $foundValue; $config['data_path'] = $foundValue;
unset($foundValue); unset($foundValue);
// POT // POT
require_once SYSTEM . 'libs/pot/OTS.php'; require_once SYSTEM . 'libs/pot/OTS.php';
$ots = POT::getInstance(); $ots = POT::getInstance();
$eloquentConnection = null; $eloquentConnection = null;
require_once SYSTEM . 'database.php'; require_once SYSTEM . 'database.php';
// 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');
}
// execute migrations // execute migrations
$configDatabaseAutoMigrate = config('database_auto_migrate'); require SYSTEM . 'migrate.php';
if (!isset($configDatabaseAutoMigrate) || $configDatabaseAutoMigrate) {
require SYSTEM . 'migrate.php';
}
// settings // settings
require_once LIBS . 'Settings.php';
$settings = Settings::getInstance(); $settings = Settings::getInstance();
$settings->load(); $settings->load();
@@ -162,15 +149,12 @@ if (!isset($token) || !$token) {
// deprecated config values // deprecated config values
require_once SYSTEM . 'compat/config.php'; require_once SYSTEM . 'compat/config.php';
// deprecated classes
require_once SYSTEM . 'compat/classes.php';
date_default_timezone_set(setting('core.date_timezone')); date_default_timezone_set(setting('core.date_timezone'));
setting( setting(
[ [
'core.account_mail_verify', 'core.account_create_character_create',
setting('core.account_mail_verify') && setting('core.mail_enabled') setting('core.account_create_character_create') && (!setting('core.mail_enabled') || !setting('core.account_mail_verify'))
] ]
); );
@@ -183,17 +167,5 @@ define('USE_ACCOUNT_NAME', $db->hasColumn('accounts', 'name'));
define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number')); define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number'));
define('USE_ACCOUNT_SALT', $db->hasColumn('accounts', 'salt')); define('USE_ACCOUNT_SALT', $db->hasColumn('accounts', 'salt'));
$towns = Cache::remember('towns', 10 * 60, function () use ($db) { require LIBS . 'Towns.php';
if ($db->hasTable('towns') && Town::count() > 0) { Towns::load();
return Town::orderBy('id', 'ASC')->pluck('name', 'id')->toArray();
}
return [];
});
if (count($towns) <= 0) {
$towns = setting('core.towns');
}
config(['towns', $towns]);
unset($towns);

View File

@@ -1,7 +1,5 @@
<?php <?php
namespace MyAAC;
use MyAAC\Models\Player; use MyAAC\Models\Player;
/** /**
@@ -23,13 +21,37 @@ class CreateCharacter
*/ */
public function checkName($name, &$errors) public function checkName($name, &$errors)
{ {
if (!\Validator::characterName($name)) { $minLength = setting('core.create_character_name_min_length');
$errors['name'] = \Validator::getLastError(); $maxLength = setting('core.create_character_name_max_length');
if(empty($name)) {
$errors['name'] = 'Please enter a name for your character!';
return false; return false;
} }
if(!admin() && !\Validator::newCharacterName($name)) { if(strlen($name) > $maxLength) {
$errors['name'] = \Validator::getLastError(); $errors['name'] = 'Name is too long. Max. length <b>' . $maxLength . '</b> letters.';
return false;
}
if(strlen($name) < $minLength) {
$errors['name'] = 'Name is too short. Min. length <b>' . $minLength . '</b> letters.';
return false;
}
$name_length = strlen($name);
if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- '") != $name_length) {
$errors['name'] = 'This name contains invalid letters, words or format. Please use only a-Z, - , \' and space.';
return false;
}
if(!preg_match("/[A-z ']/", $name)) {
$errors['name'] = 'Your name contains illegal characters.';
return false;
}
if(!admin() && !Validator::newCharacterName($name)) {
$errors['name'] = Validator::getLastError();
return false; return false;
} }
@@ -49,7 +71,7 @@ class CreateCharacter
* @param array $errors * @param array $errors
* @return bool * @return bool
*/ */
public function check($name, $sex, ?int &$vocation, ?int &$town, &$errors) public function check($name, $sex, &$vocation, &$town, &$errors)
{ {
$this->checkName($name, $errors); $this->checkName($name, $errors);
@@ -101,10 +123,13 @@ class CreateCharacter
* @param int $sex * @param int $sex
* @param int $vocation * @param int $vocation
* @param int $town * @param int $town
* @param \OTS_Account $account * @param OTS_Account $account
* @param array $errors * @param array $errors
* @return bool * @return bool
* @throws \E_OTS_NotLoaded * @throws E_OTS_NotLoaded
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
*/ */
public function doCreate($name, $sex, $vocation, $town, $account, &$errors) public function doCreate($name, $sex, $vocation, $town, $account, &$errors)
{ {
@@ -122,9 +147,9 @@ class CreateCharacter
if(empty($errors)) if(empty($errors))
{ {
$char_to_copy_name = config('character_samples')[$vocation]; $char_to_copy_name = config('character_samples')[$vocation];
$playerSample = new \OTS_Player(); $char_to_copy = new OTS_Player();
$playerSample->find($char_to_copy_name); $char_to_copy->find($char_to_copy_name);
if(!$playerSample->isLoaded()) if(!$char_to_copy->isLoaded())
$errors[] = 'Wrong characters configuration. Try again or contact with admin. ADMIN: Go to Admin Panel -> Settings -> Create Character and set valid characters to copy names. Character to copy: <b>'.$char_to_copy_name.'</b> doesn\'t exist.'; $errors[] = 'Wrong characters configuration. Try again or contact with admin. ADMIN: Go to Admin Panel -> Settings -> Create Character and set valid characters to copy names. Character to copy: <b>'.$char_to_copy_name.'</b> doesn\'t exist.';
} }
@@ -135,78 +160,78 @@ class CreateCharacter
global $db; global $db;
if($sex == "0") if($sex == "0")
$playerSample->setLookType(136); $char_to_copy->setLookType(136);
$player = new \OTS_Player(); $player = new OTS_Player();
$player->setName($name); $player->setName($name);
$player->setAccount($account); $player->setAccount($account);
$player->setGroupId(1); $player->setGroupId(1);
$player->setSex($sex); $player->setSex($sex);
$player->setVocation($playerSample->getVocation()); $player->setVocation($char_to_copy->getVocation());
if($db->hasColumn('players', 'promotion')) if($db->hasColumn('players', 'promotion'))
$player->setPromotion($playerSample->getPromotion()); $player->setPromotion($char_to_copy->getPromotion());
if($db->hasColumn('players', 'direction')) if($db->hasColumn('players', 'direction'))
$player->setDirection($playerSample->getDirection()); $player->setDirection($char_to_copy->getDirection());
$player->setConditions($playerSample->getConditions()); $player->setConditions($char_to_copy->getConditions());
$rank = $playerSample->getRank(); $rank = $char_to_copy->getRank();
if($rank->isLoaded()) { if($rank->isLoaded()) {
$player->setRank($playerSample->getRank()); $player->setRank($char_to_copy->getRank());
} }
if($db->hasColumn('players', 'lookaddons')) if($db->hasColumn('players', 'lookaddons'))
$player->setLookAddons($playerSample->getLookAddons()); $player->setLookAddons($char_to_copy->getLookAddons());
$player->setTownId($town); $player->setTownId($town);
$player->setExperience($playerSample->getExperience()); $player->setExperience($char_to_copy->getExperience());
$player->setLevel($playerSample->getLevel()); $player->setLevel($char_to_copy->getLevel());
$player->setMagLevel($playerSample->getMagLevel()); $player->setMagLevel($char_to_copy->getMagLevel());
$player->setHealth($playerSample->getHealth()); $player->setHealth($char_to_copy->getHealth());
$player->setHealthMax($playerSample->getHealthMax()); $player->setHealthMax($char_to_copy->getHealthMax());
$player->setMana($playerSample->getMana()); $player->setMana($char_to_copy->getMana());
$player->setManaMax($playerSample->getManaMax()); $player->setManaMax($char_to_copy->getManaMax());
$player->setManaSpent($playerSample->getManaSpent()); $player->setManaSpent($char_to_copy->getManaSpent());
$player->setSoul($playerSample->getSoul()); $player->setSoul($char_to_copy->getSoul());
for($skill = \POT::SKILL_FIRST; $skill <= \POT::SKILL_LAST; $skill++) { for($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++) {
$value = 10; $value = 10;
if (setting('core.use_character_sample_skills')) { if (setting('core.use_character_sample_skills')) {
$value = $playerSample->getSkill($skill); $value = $char_to_copy->getSkill($skill);
} }
$player->setSkill($skill, $value); $player->setSkill($skill, $value);
} }
$player->setLookBody($playerSample->getLookBody()); $player->setLookBody($char_to_copy->getLookBody());
$player->setLookFeet($playerSample->getLookFeet()); $player->setLookFeet($char_to_copy->getLookFeet());
$player->setLookHead($playerSample->getLookHead()); $player->setLookHead($char_to_copy->getLookHead());
$player->setLookLegs($playerSample->getLookLegs()); $player->setLookLegs($char_to_copy->getLookLegs());
$player->setLookType($playerSample->getLookType()); $player->setLookType($char_to_copy->getLookType());
$player->setCap($playerSample->getCap()); $player->setCap($char_to_copy->getCap());
$player->setBalance(0); $player->setBalance(0);
$player->setPosX(0); $player->setPosX(0);
$player->setPosY(0); $player->setPosY(0);
$player->setPosZ(0); $player->setPosZ(0);
if($db->hasColumn('players', 'stamina')) { if($db->hasColumn('players', 'stamina')) {
$player->setStamina($playerSample->getStamina()); $player->setStamina($char_to_copy->getStamina());
} }
if($db->hasColumn('players', 'loss_experience')) { if($db->hasColumn('players', 'loss_experience')) {
$player->setLossExperience($playerSample->getLossExperience()); $player->setLossExperience($char_to_copy->getLossExperience());
$player->setLossMana($playerSample->getLossMana()); $player->setLossMana($char_to_copy->getLossMana());
$player->setLossSkills($playerSample->getLossSkills()); $player->setLossSkills($char_to_copy->getLossSkills());
} }
if($db->hasColumn('players', 'loss_items')) { if($db->hasColumn('players', 'loss_items')) {
$player->setLossItems($playerSample->getLossItems()); $player->setLossItems($char_to_copy->getLossItems());
$player->setLossContainers($playerSample->getLossContainers()); $player->setLossContainers($char_to_copy->getLossContainers());
} }
$player->save(); $player->save();
$player->setCustomField('created', time()); $player->setCustomField('created', time());
$player = new \OTS_Player(); $player = new OTS_Player();
$player->find($name); $player->find($name);
if(!$player->isLoaded()) { if(!$player->isLoaded()) {
@@ -215,10 +240,10 @@ class CreateCharacter
} }
if($db->hasTable('player_skills')) { if($db->hasTable('player_skills')) {
for($skill = \POT::SKILL_FIRST; $skill <= \POT::SKILL_LAST; $skill++) { for($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++) {
$value = 10; $value = 10;
if (setting('core.use_character_sample_skills')) { if (setting('core.use_character_sample_skills')) {
$value = $playerSample->getSkill($skill); $value = $char_to_copy->getSkill($skill);
} }
$skillExists = $db->query('SELECT `skillid` FROM `player_skills` WHERE `player_id` = ' . $player->getId() . ' AND `skillid` = ' . $skill); $skillExists = $db->query('SELECT `skillid` FROM `player_skills` WHERE `player_id` = ' . $player->getId() . ' AND `skillid` = ' . $skill);
if($skillExists->rowCount() <= 0) { if($skillExists->rowCount() <= 0) {
@@ -228,28 +253,13 @@ class CreateCharacter
} }
if ($db->hasTable('player_items') && $db->hasColumn('player_items', 'pid') && $db->hasColumn('player_items', 'sid') && $db->hasColumn('player_items', 'itemtype')) { if ($db->hasTable('player_items') && $db->hasColumn('player_items', 'pid') && $db->hasColumn('player_items', 'sid') && $db->hasColumn('player_items', 'itemtype')) {
$loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$playerSample->getId().""); $loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$char_to_copy->getId()."");
foreach($loaded_items_to_copy as $save_item) { foreach($loaded_items_to_copy as $save_item) {
$blob = $db->quote($save_item['attributes']); $blob = $db->quote($save_item['attributes']);
$db->query("INSERT INTO `player_items` (`player_id` ,`pid` ,`sid` ,`itemtype`, `count`, `attributes`) VALUES ('".$player->getId()."', '".$save_item['pid']."', '".$save_item['sid']."', '".$save_item['itemtype']."', '".$save_item['count']."', $blob);"); $db->query("INSERT INTO `player_items` (`player_id` ,`pid` ,`sid` ,`itemtype`, `count`, `attributes`) VALUES ('".$player->getId()."', '".$save_item['pid']."', '".$save_item['sid']."', '".$save_item['itemtype']."', '".$save_item['count']."', $blob);");
} }
} }
global $hooks;
if (!$hooks->trigger(HOOK_ACCOUNT_CREATE_CHARACTER_AFTER,
[
'account' => $account,
'player' => $player,
'playerSample' => $playerSample,
'name' => $name,
'sex' => $sex,
'vocation' => $vocation,
'town' => $town,
]
)) {
return false;
}
global $twig; global $twig;
$twig->display('success.html.twig', array( $twig->display('success.html.twig', array(
'title' => 'Character Created', 'title' => 'Character Created',

View File

@@ -23,11 +23,9 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
namespace MyAAC; /**
* Class DataLoader
use MyAAC\Cache\Cache; */
use MyAAC\Models\Town;
class DataLoader class DataLoader
{ {
private static $locale; private static $locale;
@@ -40,6 +38,7 @@ class DataLoader
{ {
self::$startTime = microtime(true); self::$startTime = microtime(true);
require LIBS . 'items.php';
if(Items::loadFromXML()) { if(Items::loadFromXML()) {
success(self::$locale['step_database_loaded_items'] . self::getLoadedTime()); success(self::$locale['step_database_loaded_items'] . self::getLoadedTime());
} }
@@ -49,20 +48,22 @@ class DataLoader
self::$startTime = microtime(true); self::$startTime = microtime(true);
if(Monsters::loadFromXML()) { require LIBS . 'creatures.php';
if(Creatures::loadFromXML()) {
success(self::$locale['step_database_loaded_monsters'] . self::getLoadedTime()); success(self::$locale['step_database_loaded_monsters'] . self::getLoadedTime());
if(Monsters::getMonstersList()->hasErrors()) { if(Creatures::getMonstersList()->hasErrors()) {
self::$locale['step_database_error_monsters'] = str_replace('$LOG$', 'system/logs/error.log', self::$locale['step_database_error_monsters']); self::$locale['step_database_error_monsters'] = str_replace('$LOG$', 'system/logs/error.log', self::$locale['step_database_error_monsters']);
warning(self::$locale['step_database_error_monsters']); warning(self::$locale['step_database_error_monsters']);
} }
} }
else { else {
error(Monsters::getLastError()); error(Creatures::getLastError());
} }
self::$startTime = microtime(true); self::$startTime = microtime(true);
require_once LIBS . 'npc.php';
if(NPCs::loadFromXML()) { if(NPCs::loadFromXML()) {
success(self::$locale['step_database_loaded_npcs'] . self::getLoadedTime()); success(self::$locale['step_database_loaded_npcs'] . self::getLoadedTime());
} }
@@ -72,6 +73,7 @@ class DataLoader
self::$startTime = microtime(true); self::$startTime = microtime(true);
require LIBS . 'spells.php';
if(Spells::loadFromXML()) { if(Spells::loadFromXML()) {
success(self::$locale['step_database_loaded_spells'] . self::getLoadedTime()); success(self::$locale['step_database_loaded_spells'] . self::getLoadedTime());
} }
@@ -81,13 +83,7 @@ class DataLoader
self::$startTime = microtime(true); self::$startTime = microtime(true);
$cache = Cache::getInstance(); if (Towns::save()) {
if ($cache->enabled()) {
$cache->delete('towns'); // will be reloaded after next page load
}
global $db;
if ($db->hasTable('towns') && Town::count() > 0) {
success(self::$locale['step_database_loaded_towns'] . self::getLoadedTime()); success(self::$locale['step_database_loaded_towns'] . self::getLoadedTime());
} }
else { else {
@@ -96,6 +92,7 @@ class DataLoader
self::$startTime = microtime(true); self::$startTime = microtime(true);
require LIBS . 'weapons.php';
if(Weapons::loadFromXML()) { if(Weapons::loadFromXML()) {
success(self::$locale['step_database_loaded_weapons'] . self::getLoadedTime()); success(self::$locale['step_database_loaded_weapons'] . self::getLoadedTime());
} }

View File

@@ -0,0 +1,3 @@
<?php
class SensitiveException extends Exception {}

View File

@@ -1,11 +1,17 @@
<?php <?php
namespace MyAAC;
use MyAAC\Cache\Cache;
use MyAAC\Models\Settings as ModelsSettings; use MyAAC\Models\Settings as ModelsSettings;
class Settings implements \ArrayAccess /**
* CreateCharacter
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2020 MyAAC
* @link https://my-aac.org
*/
class Settings implements ArrayAccess
{ {
static private $instance; static private $instance;
private $settingsFile = []; private $settingsFile = [];
@@ -38,7 +44,8 @@ class Settings implements \ArrayAccess
} }
$settings = ModelsSettings::all(); $settings = ModelsSettings::all();
foreach ($settings as $setting) { foreach ($settings as $setting)
{
$this->settingsDatabase[$setting->name][$setting->key] = $setting->value; $this->settingsDatabase[$setting->name][$setting->key] = $setting->value;
} }
@@ -47,12 +54,9 @@ class Settings implements \ArrayAccess
} }
} }
public function save($pluginName, $values) public function save($pluginName, $values) {
{
$this->loadPlugin($pluginName);
if (!isset($this->settingsFile[$pluginName])) { if (!isset($this->settingsFile[$pluginName])) {
throw new \RuntimeException("Error on save settings: plugin $pluginName does not exist"); throw new RuntimeException('Error on save settings: plugin does not exist');
} }
$settings = $this->settingsFile[$pluginName]; $settings = $this->settingsFile[$pluginName];
@@ -72,11 +76,6 @@ class Settings implements \ArrayAccess
} }
} }
global $db;
try {
$db->beginTransaction();
$this->errors = []; $this->errors = [];
ModelsSettings::where('name', $pluginName)->delete(); ModelsSettings::where('name', $pluginName)->delete();
foreach ($values as $key => $value) { foreach ($values as $key => $value) {
@@ -86,36 +85,29 @@ class Settings implements \ArrayAccess
continue; continue;
} }
try {
ModelsSettings::create([ ModelsSettings::create([
'name' => $pluginName, 'name' => $pluginName,
'key' => $key, 'key' => $key,
'value' => $value 'value' => $value
]); ]);
} catch (PDOException $error) {
$this->errors[] = 'Error while saving setting (' . $pluginName . ' - ' . $key . '): ' . $error->getMessage();
}
} }
$db->commit(); $cache = Cache::getInstance();
} catch (\Exception $error) { if ($cache->enabled()) {
$db->rollBack(); $cache->delete('settings');
$this->errors[] = 'Error while saving settings (' . $pluginName . ')<br/>' . $error->getMessage();
return false;
} }
$this->clearCache();
return true; return true;
} }
public function updateInDatabase($pluginName, $key, $value) public function updateInDatabase($pluginName, $key, $value)
{ {
if (ModelsSettings::where(['name' => $pluginName, 'key' => $key])->exists()) {
ModelsSettings::where(['name' => $pluginName, 'key' => $key])->update(['value' => $value]); ModelsSettings::where(['name' => $pluginName, 'key' => $key])->update(['value' => $value]);
} }
else {
// insert new
ModelsSettings::create(['name' => $pluginName, 'key' => $key, 'value' => $value]);
}
$this->clearCache();
}
public function deleteFromDatabase($pluginName, $key = null) public function deleteFromDatabase($pluginName, $key = null)
{ {
@@ -125,8 +117,6 @@ class Settings implements \ArrayAccess
else { else {
ModelsSettings::where('name', $pluginName)->where('key', $key)->delete(); ModelsSettings::where('name', $pluginName)->where('key', $key)->delete();
} }
$this->clearCache();
} }
public static function display($plugin, $settings): array public static function display($plugin, $settings): array
@@ -139,9 +129,6 @@ class Settings implements \ArrayAccess
if (is_bool($value)) { if (is_bool($value)) {
$settingsDb[$key] = $value ? 'true' : 'false'; $settingsDb[$key] = $value ? 'true' : 'false';
} }
elseif (is_array($value)) {
$settingsDb[$key] = $value;
}
else { else {
$settingsDb[$key] = (string)$value; $settingsDb[$key] = (string)$value;
} }
@@ -255,22 +242,10 @@ class Settings implements \ArrayAccess
$min = $max = $step = ''; $min = $max = $step = '';
} }
if ($setting['type'] === 'password') {
echo '<div class="input-group" id="show-hide-' . $key . '">';
}
echo '<input class="form-control" type="' . $setting['type'] . '" name="settings[' . $key . ']" value="' . ($settingsDb[$key] ?? ($setting['default'] ?? '')) . '" id="' . $key . '"' . $min . $max . $step . '/>'; echo '<input class="form-control" type="' . $setting['type'] . '" name="settings[' . $key . ']" value="' . ($settingsDb[$key] ?? ($setting['default'] ?? '')) . '" id="' . $key . '"' . $min . $max . $step . '/>';
if ($setting['type'] === 'password') {
echo '<div class="input-group-append input-group-text"><a href=""><i class="fas fa-eye-slash" ></i></a></div></div>';
}
} }
else if($setting['type'] === 'textarea') { else if($setting['type'] === 'textarea') {
if (isset($settingsDb[$key]) && is_array($settingsDb[$key])) {
$settingsDb[$key] = implode(',', $settingsDb[$key]);
}
$value = ($settingsDb[$key] ?? ($setting['default'] ?? '')); $value = ($settingsDb[$key] ?? ($setting['default'] ?? ''));
$valueWithSpaces = array_map('trim', preg_split('/\r\n|\r|\n/', trim($value))); $valueWithSpaces = array_map('trim', preg_split('/\r\n|\r|\n/', trim($value)));
$rows = count($valueWithSpaces); $rows = count($valueWithSpaces);
@@ -305,7 +280,7 @@ class Settings implements \ArrayAccess
} }
else if ($setting['options'] == '$timezones') { else if ($setting['options'] == '$timezones') {
$timezones = []; $timezones = [];
foreach (\DateTimeZone::listIdentifiers() as $value) { foreach (DateTimeZone::listIdentifiers() as $value) {
$timezones[$value] = $value; $timezones[$value] = $value;
} }
@@ -344,7 +319,7 @@ class Settings implements \ArrayAccess
</td> </td>
<td> <td>
<div class="well setting-default"><?php <div class="well setting-default"><?php
echo (isset($setting['desc']) ? makeLinksClickable($setting['desc']) : ''); echo ($setting['desc'] ?? '');
echo '<br/>'; echo '<br/>';
echo '<strong>Default:</strong> '; echo '<strong>Default:</strong> ';
@@ -355,7 +330,7 @@ class Settings implements \ArrayAccess
echo $setting['default']; echo $setting['default'];
} }
else if ($setting['type'] === 'options') { else if ($setting['type'] === 'options') {
if (is_int($setting['default']) || !empty($setting['default'])) { if (!empty($setting['default'])) {
echo $setting['options'][$setting['default']]; echo $setting['options'][$setting['default']];
} }
} }
@@ -398,8 +373,7 @@ class Settings implements \ArrayAccess
} }
$this->settingsDatabase[$pluginKeyName][$key] = $value; $this->settingsDatabase[$pluginKeyName][$key] = $value;
// invalidate cache $this->updateInDatabase($pluginKeyName, $key, $value);
unset($this->cache[$offset]);
} }
#[\ReturnTypeWillChange] #[\ReturnTypeWillChange]
@@ -440,6 +414,7 @@ class Settings implements \ArrayAccess
unset($this->settingsFile[$pluginKeyName]['settings'][$key]); unset($this->settingsFile[$pluginKeyName]['settings'][$key]);
unset($this->settingsDatabase[$pluginKeyName][$key]); unset($this->settingsDatabase[$pluginKeyName][$key]);
$this->deleteFromDatabase($pluginKeyName, $key);
} }
/** /**
@@ -466,7 +441,7 @@ class Settings implements \ArrayAccess
// return specified plugin settings (all) // return specified plugin settings (all)
if(!isset($key)) { if(!isset($key)) {
if (!isset($this->settingsFile[$pluginKeyName]['settings'])) { if (!isset($this->settingsFile[$pluginKeyName]['settings'])) {
throw new \RuntimeException('Unknown plugin settings: ' . $pluginKeyName); throw new RuntimeException('Unknown plugin settings: ' . $pluginKeyName);
} }
return $this->settingsFile[$pluginKeyName]['settings']; return $this->settingsFile[$pluginKeyName]['settings'];
} }
@@ -482,15 +457,9 @@ class Settings implements \ArrayAccess
$ret['value'] = $value; $ret['value'] = $value;
} }
else { else {
if (!isset($this->settingsFile[$pluginKeyName]['settings'][$key])) {
return null;
}
$ret['value'] = $this->settingsFile[$pluginKeyName]['settings'][$key]['default']; $ret['value'] = $this->settingsFile[$pluginKeyName]['settings'][$key]['default'];
} }
$ret['key'] = $key;
if(isset($ret['type'])) { if(isset($ret['type'])) {
switch($ret['type']) { switch($ret['type']) {
case 'boolean': case 'boolean':
@@ -563,11 +532,8 @@ class Settings implements \ArrayAccess
public static function saveConfig($config, $filename, &$content = '') public static function saveConfig($config, $filename, &$content = '')
{ {
$content = "<?php" . PHP_EOL; $content = "<?php" . PHP_EOL .
"\$config['installed'] = true;" . PHP_EOL;
unset($config['installed']);
$content .= "\$config['installed'] = true;" . PHP_EOL;
foreach ($config as $key => $value) { foreach ($config as $key => $value) {
$content .= "\$config['$key'] = "; $content .= "\$config['$key'] = ";
@@ -575,10 +541,10 @@ class Settings implements \ArrayAccess
$content .= ';' . PHP_EOL; $content .= ';' . PHP_EOL;
} }
$success = @file_put_contents($filename, $content); $success = file_put_contents($filename, $content);
// we saved new config.php, need to revalidate cache (only if opcache is enabled) // we saved new config.php, need to revalidate cache (only if opcache is enabled)
if ($success && function_exists('opcache_invalidate')) { if (function_exists('opcache_invalidate')) {
opcache_invalidate($filename); opcache_invalidate($filename);
} }
@@ -612,10 +578,10 @@ class Settings implements \ArrayAccess
} }
try { try {
$connectionTest = new \PDO('mysql:' . implode(';', $dns), $user, $password); $connectionTest = new PDO('mysql:' . implode(';', $dns), $user, $password);
$connectionTest->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); $connectionTest->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} }
catch(\PDOException $error) { catch(PDOException $error) {
error('MySQL connection failed. Settings has been reverted.'); error('MySQL connection failed. Settings has been reverted.');
error($error->getMessage()); error($error->getMessage());
return false; return false;
@@ -624,15 +590,7 @@ class Settings implements \ArrayAccess
return true; return true;
} }
public function getErrors(): array { public function getErrors() {
return $this->errors; return $this->errors;
} }
public function clearCache(): void
{
$cache = Cache::getInstance();
if ($cache->enabled()) {
$cache->delete('settings');
}
}
} }

131
system/libs/Towns.php Normal file
View File

@@ -0,0 +1,131 @@
<?php
/**
* Project: MyAAC
* Automatic Account Creator for Open Tibia Servers
*
* This is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2020 MyAAC
* @link https://my-aac.org
*/
use MyAAC\Models\Town;
/**
* Class Towns
*/
class Towns
{
/**
* @var string
*/
private static $filename = CACHE . 'towns.php';
/**
* Determine towns
*
* @return array
*/
public static function determine()
{
global $db;
if($db->hasTable('towns')) {
return self::getFromDatabase();
}
return self::getFromOTBM();
}
/**
* Load cached towns file
*/
public static function load()
{
$towns = config('towns');
if (file_exists(self::$filename)) {
$towns = require self::$filename;
}
config(['towns', $towns]);
}
/**
* Save into cache file
*
* @return bool
*/
public static function save()
{
$towns = self::determine();
if (count($towns) > 0) {
file_put_contents(self::$filename, '<?php return ' . var_export($towns, true) . ';', LOCK_EX);
return true;
}
return false;
}
/**
* Load from OTBM map file
*
* @return array
*/
public static function getFromOTBM()
{
$mapName = configLua('mapName');
if (!isset($mapName)) {
$mapName = configLua('map');
$mapFile = config('server_path') . $mapName;
}
if (strpos($mapName, '.otbm') === false) {
$mapName .= '.otbm';
}
if (!isset($mapFile)) {
$mapFile = config('data_path') . 'world/' . $mapName;
}
if (strpos($mapFile, '.gz') !== false) {
$mapFile = str_replace('.gz', '', $mapFile);
}
$towns = [];
if (file_exists($mapFile)) {
ini_set('memory_limit', '-1');
require LIBS . 'TownsReader.php';
$townsReader = new TownsReader($mapFile);
$townsReader->load();
$towns = $townsReader->get();
}
return $towns;
}
/**
* Load from database
*
* @return array
*/
public static function getFromDatabase()
{
return Town::pluck('name', 'id')->toArray();
}
}

View File

@@ -0,0 +1,82 @@
<?php
/*
This file is part of OTSCMS (http://www.otscms.com/) project.
Copyright (C) 2005 - 2007 Wrzasq (wrzasq@gmail.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
This code bases on oryginal OTServ code for .otbm files - file iomapotbm.cpp rev.2141
*/
class TownsReader
{
// node bytes
const ESCAPE_CHAR = 0xFD;
const NODE_START = 0xFE;
// map node types
const OTBM_TOWN = 13;
// file handler
protected $file;
// towns
private $towns = [];
// loads map .otbm file
public function __construct($file)
{
// opens file for reading
$this->file = fopen($file, 'rb');
}
public function load()
{
// checks if file is opened correctly
if ($this->file) {
// skips version
fseek($this->file, 4);
// reads nodes chain
while (!feof($this->file)) {
// reads byte
switch (ord(fgetc($this->file))) {
// maybe a town node
case self::NODE_START:
// reads node type
if (ord(fgetc($this->file)) == self::OTBM_TOWN) {
$id = unpack('L', fread($this->file, 4));
$length = unpack('S', fread($this->file, 2));
// reads town name
$this->towns[$id[1]] = fread($this->file, $length[1]);
}
break;
// escape next character - it might be NODE_START character which is in fact not
case self::ESCAPE_CHAR:
fgetc($this->file);
break;
}
}
}
}
public function get() {
return $this->towns;
}
}

View File

@@ -8,8 +8,7 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC\Cache;
/** /**
* Class Cache * Class Cache
@@ -42,30 +41,40 @@ class Cache
*/ */
public static function generateInstance($engine = '', $prefix = '') public static function generateInstance($engine = '', $prefix = '')
{ {
if (config('env') === 'dev') { if(config('env') === 'dev') {
self::$instance = new self(); self::$instance = new self();
return self::$instance; return self::$instance;
} }
switch (strtolower($engine)) { switch(strtolower($engine)) {
case 'apc': case 'apc':
self::$instance = new APC($prefix); require 'cache_apc.php';
self::$instance = new Cache_APC($prefix);
break; break;
case 'apcu': case 'apcu':
self::$instance = new APCu($prefix); require 'cache_apcu.php';
self::$instance = new Cache_APCu($prefix);
break;
case 'eaccelerator':
require 'cache_eaccelerator.php';
self::$instance = new Cache_eAccelerator($prefix);
break; break;
case 'xcache': case 'xcache':
self::$instance = new XCache($prefix); require 'cache_xcache.php';
self::$instance = new Cache_XCache($prefix);
break; break;
case 'file': case 'file':
self::$instance = new File($prefix, CACHE); require 'cache_file.php';
self::$instance = new Cache_File($prefix, CACHE);
break; break;
case 'php': case 'php':
self::$instance = new PHP($prefix, CACHE); require 'cache_php.php';
self::$instance = new Cache_PHP($prefix, CACHE);
break; break;
case 'auto': case 'auto':
@@ -85,11 +94,13 @@ class Cache
*/ */
public static function detect() public static function detect()
{ {
if (function_exists('apc_fetch')) if(function_exists('apc_fetch'))
return 'apc'; return 'apc';
else if (function_exists('apcu_fetch')) else if(function_exists('apcu_fetch'))
return 'apcu'; return 'apcu';
else if (function_exists('xcache_get') && ini_get('xcache.var_size')) else if(function_exists('eaccelerator_get'))
return 'eaccelerator';
else if(function_exists('xcache_get') && ini_get('xcache.var_size'))
return 'xcache'; return 'xcache';
return 'file'; return 'file';
@@ -98,15 +109,12 @@ class Cache
/** /**
* @return bool * @return bool
*/ */
public function enabled() public function enabled() {return false;}
{
return false;
}
public static function remember($key, $ttl, $callback) public static function remember($key, $ttl, $callback)
{ {
$cache = self::getInstance(); $cache = self::getInstance();
if (!$cache->enabled()) { if(!$cache->enabled()) {
return $callback(); return $callback();
} }
@@ -116,7 +124,7 @@ class Cache
} }
$value = $callback(); $value = $callback();
$cache->set($key, serialize($value), $ttl); $cache->set($key, serialize($value),$ttl);
return $value; return $value;
} }
} }

View File

@@ -8,10 +8,9 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC\Cache; class Cache_APC
class APC
{ {
private $prefix; private $prefix;
private $enabled; private $enabled;
@@ -32,25 +31,22 @@ class APC
public function get($key) public function get($key)
{ {
$tmp = ''; $tmp = '';
if ($this->fetch($this->prefix . $key, $tmp)) { if($this->fetch($this->prefix . $key, $tmp)) {
return $tmp; return $tmp;
} }
return ''; return '';
} }
public function fetch($key, &$var) public function fetch($key, &$var) {
{
return ($var = apc_fetch($this->prefix . $key)) !== false; return ($var = apc_fetch($this->prefix . $key)) !== false;
} }
public function delete($key) public function delete($key) {
{
apc_delete($this->prefix . $key); apc_delete($this->prefix . $key);
} }
public function enabled() public function enabled() {
{
return $this->enabled; return $this->enabled;
} }
} }

View File

@@ -8,10 +8,9 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC\Cache; class Cache_APCu
class APCu
{ {
private $prefix; private $prefix;
private $enabled; private $enabled;
@@ -32,25 +31,22 @@ class APCu
public function get($key) public function get($key)
{ {
$tmp = ''; $tmp = '';
if ($this->fetch($this->prefix . $key, $tmp)) { if($this->fetch($this->prefix . $key, $tmp)) {
return $tmp; return $tmp;
} }
return ''; return '';
} }
public function fetch($key, &$var) public function fetch($key, &$var) {
{
return ($var = apcu_fetch($this->prefix . $key)) !== false; return ($var = apcu_fetch($this->prefix . $key)) !== false;
} }
public function delete($key) public function delete($key) {
{
apcu_delete($this->prefix . $key); apcu_delete($this->prefix . $key);
} }
public function enabled() public function enabled() {
{
return $this->enabled; return $this->enabled;
} }
} }

View File

@@ -0,0 +1,51 @@
<?php
/**
* Cache eAccelerator class
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @author Mark Samman (Talaturen) <marksamman@gmail.com>
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
class Cache_eAccelerator
{
private $prefix;
private $enabled;
public function __construct($prefix = '') {
$this->prefix = $prefix;
$this->enabled = function_exists('eaccelerator_get');
}
public function set($key, $var, $ttl = 0)
{
$key = $this->prefix . $key;
eaccelerator_rm($key);
eaccelerator_put($key, $var, $ttl);
}
public function get($key)
{
$tmp = '';
if($this->fetch($this->prefix . $key, $tmp)) {
return $tmp;
}
return '';
}
public function fetch($key, &$var) {
return ($var = eaccelerator_get($this->prefix . $key)) !== null;
}
public function delete($key) {
eaccelerator_rm($this->prefix . $key);
}
public function enabled() {
return $this->enabled;
}
}

View File

@@ -7,17 +7,15 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC\Cache; class Cache_File
class File
{ {
private $prefix; private $prefix;
private $dir; private $dir;
private $enabled; private $enabled;
public function __construct($prefix = '', $dir = '') public function __construct($prefix = '', $dir = '') {
{
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dir = $dir; $this->dir = $dir;
$this->enabled = (file_exists($this->dir) && is_dir($this->dir) && is_writable($this->dir)); $this->enabled = (file_exists($this->dir) && is_dir($this->dir) && is_writable($this->dir));
@@ -38,7 +36,7 @@ class File
public function get($key) public function get($key)
{ {
$tmp = ''; $tmp = '';
if ($this->fetch($key, $tmp)) { if($this->fetch($key, $tmp)) {
return $tmp; return $tmp;
} }
@@ -48,7 +46,7 @@ class File
public function fetch($key, &$var) public function fetch($key, &$var)
{ {
$file = $this->_name($key); $file = $this->_name($key);
if (!file_exists($file) || filemtime($file) < time()) { if(!file_exists($file) || filemtime($file) < time()) {
return false; return false;
} }
@@ -59,18 +57,16 @@ class File
public function delete($key) public function delete($key)
{ {
$file = $this->_name($key); $file = $this->_name($key);
if (file_exists($file)) { if(file_exists($file)) {
unlink($file); unlink($file);
} }
} }
public function enabled() public function enabled() {
{
return $this->enabled; return $this->enabled;
} }
private function _name($key) private function _name($key) {
{
return sprintf('%s%s%s', $this->dir, $this->prefix, sha1($key)); return sprintf('%s%s%s', $this->dir, $this->prefix, sha1($key));
} }
} }

View File

@@ -7,17 +7,15 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC\Cache; class Cache_PHP
class PHP
{ {
private $prefix; private $prefix;
private $dir; private $dir;
private $enabled; private $enabled;
public function __construct($prefix = '', $dir = '') public function __construct($prefix = '', $dir = '') {
{
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dir = $dir; $this->dir = $dir;
$this->enabled = (file_exists($this->dir) && is_dir($this->dir) && is_writable($this->dir)); $this->enabled = (file_exists($this->dir) && is_dir($this->dir) && is_writable($this->dir));
@@ -44,7 +42,7 @@ class PHP
public function get($key) public function get($key)
{ {
$tmp = ''; $tmp = '';
if ($this->fetch($key, $tmp)) { if($this->fetch($key, $tmp)) {
return $tmp; return $tmp;
} }
@@ -54,7 +52,7 @@ class PHP
public function fetch($key, &$var) public function fetch($key, &$var)
{ {
$file = $this->_name($key); $file = $this->_name($key);
if (!file_exists($file) || filemtime($file) < time()) { if(!file_exists($file) || filemtime($file) < time()) {
return false; return false;
} }
@@ -66,18 +64,16 @@ class PHP
public function delete($key) public function delete($key)
{ {
$file = $this->_name($key); $file = $this->_name($key);
if (file_exists($file)) { if(file_exists($file)) {
unlink($file); unlink($file);
} }
} }
public function enabled() public function enabled() {
{
return $this->enabled; return $this->enabled;
} }
private function _name($key) private function _name($key) {
{
return sprintf('%s%s%s', $this->dir, $this->prefix, sha1($key) . '.php'); return sprintf('%s%s%s', $this->dir, $this->prefix, sha1($key) . '.php');
} }
} }

View File

@@ -8,16 +8,14 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC\Cache; class Cache_XCache
class XCache
{ {
private $prefix; private $prefix;
private $enabled; private $enabled;
public function __construct($prefix = '') public function __construct($prefix = '') {
{
$this->prefix = $prefix; $this->prefix = $prefix;
$this->enabled = function_exists('xcache_get') && ini_get('xcache.var_size'); $this->enabled = function_exists('xcache_get') && ini_get('xcache.var_size');
} }
@@ -32,7 +30,7 @@ class XCache
public function get($key) public function get($key)
{ {
$tmp = ''; $tmp = '';
if ($this->fetch($this->prefix . $key, $tmp)) { if($this->fetch($this->prefix . $key, $tmp)) {
return $tmp; return $tmp;
} }
@@ -42,7 +40,7 @@ class XCache
public function fetch($key, &$var) public function fetch($key, &$var)
{ {
$key = $this->prefix . $key; $key = $this->prefix . $key;
if (!xcache_isset($key)) { if(!xcache_isset($key)) {
return false; return false;
} }
@@ -50,13 +48,11 @@ class XCache
return true; return true;
} }
public function delete($key) public function delete($key) {
{
xcache_unset($this->prefix . $key); xcache_unset($this->prefix . $key);
} }
public function enabled() public function enabled() {
{
return $this->enabled; return $this->enabled;
} }
} }

View File

@@ -1,8 +1,5 @@
<?php <?php
namespace MyAAC;
use MyAAC\Cache\Cache;
use MyAAC\Models\Changelog as ModelsChangelog; use MyAAC\Models\Changelog as ModelsChangelog;
class Changelog class Changelog
@@ -88,17 +85,17 @@ class Changelog
return true; return true;
} }
static public function toggleHide($id, &$errors, &$status) static public function toggleHidden($id, &$errors, &$status)
{ {
if(isset($id)) if(isset($id))
{ {
$row = ModelsChangelog::find($id); $row = ModelsChangelog::find($id);
if ($row) { if ($row) {
$row->hide = $row->hide == 1 ? 0 : 1; $row->hidden = $row->hidden == 1 ? 0 : 1;
if (!$row->save()) { if (!$row->save()) {
$errors[] = 'Fail during toggle hide Changelog.'; $errors[] = 'Fail during toggle hidden Changelog.';
} }
$status = $row->hide; $status = $row->hidden;
} else { } else {
$errors[] = 'Changelog with id ' . $id . ' does not exists.'; $errors[] = 'Changelog with id ' . $id . ' does not exists.';
} }

View File

@@ -9,13 +9,14 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
namespace MyAAC;
use MyAAC\Models\Monster; use MyAAC\Models\Monster;
class Monsters { defined('MYAAC') or die('Direct access not allowed!');
require_once LIBS . 'items.php';
class Creatures {
/** /**
* @var \OTS_MonstersList * @var OTS_MonstersList
*/ */
private static $monstersList; private static $monstersList;
private static $lastError = ''; private static $lastError = '';
@@ -23,7 +24,7 @@ class Monsters {
public static function loadFromXML($show = false) { public static function loadFromXML($show = false) {
try { try {
Monster::query()->delete(); Monster::query()->delete();
} catch(\Exception $error) {} } catch(Exception $error) {}
if($show) { if($show) {
echo '<h2>Reload monsters.</h2>'; echo '<h2>Reload monsters.</h2>';
@@ -31,9 +32,9 @@ class Monsters {
} }
try { try {
self::$monstersList = new \OTS_MonstersList(config('data_path') . 'monster/'); self::$monstersList = new OTS_MonstersList(config('data_path') . 'monster/');
} }
catch(\Exception $e) { catch(Exception $e) {
self::$lastError = $e->getMessage(); self::$lastError = $e->getMessage();
return false; return false;
} }
@@ -118,7 +119,7 @@ class Monsters {
$summons = $monster->getSummons(); $summons = $monster->getSummons();
$loot = $monster->getLoot(); $loot = $monster->getLoot();
foreach($loot as &$item) { foreach($loot as &$item) {
if(!\Validator::number($item['id'])) { if(!Validator::number($item['id'])) {
if(isset($items[$item['id']])) { if(isset($items[$item['id']])) {
$item['id'] = $items[$item['id']]; $item['id'] = $items[$item['id']];
} }
@@ -160,7 +161,7 @@ class Monsters {
success('Added: ' . $name . '<br/>'); success('Added: ' . $name . '<br/>');
} }
} }
catch(\Exception $error) { catch(Exception $error) {
if($show) { if($show) {
warning('Error while adding monster (' . $name . '): ' . $error->getMessage()); warning('Error while adding monster (' . $name . '): ' . $error->getMessage());
} }

View File

@@ -7,8 +7,7 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC;
class Data class Data
{ {

View File

@@ -8,13 +8,12 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC;
$settingForumTablePrefix = setting('core.forum_table_prefix'); $settingForumTablePrefix = setting('core.forum_table_prefix');
if(null !== $settingForumTablePrefix && !empty(trim($settingForumTablePrefix))) { if(null !== $settingForumTablePrefix && !empty(trim($settingForumTablePrefix))) {
if(!in_array($settingForumTablePrefix, array('myaac_', 'z_'))) { if(!in_array($settingForumTablePrefix, array('myaac_', 'z_'))) {
throw new \RuntimeException('Invalid value for forum_table_prefix in config.php. Can be only: "myaac_" or "z_".'); throw new RuntimeException('Invalid value for forum_table_prefix in config.php. Can be only: "myaac_" or "z_".');
} }
define('FORUM_TABLE_PREFIX', $settingForumTablePrefix); define('FORUM_TABLE_PREFIX', $settingForumTablePrefix);
@@ -31,9 +30,9 @@ else {
class Forum class Forum
{ {
/** /**
* @param \OTS_Account $account * @param OTS_Account $account
* @return bool * @return bool
* @throws \E_OTS_NotLoaded * @throws E_OTS_NotLoaded
*/ */
public static function canPost($account) public static function canPost($account)
{ {
@@ -72,7 +71,7 @@ class Forum
'post_smile' => 0, 'post_html' => 1, 'post_smile' => 0, 'post_html' => 1,
'post_date' => time(), 'post_date' => time(),
'last_edit_aid' => 0, 'edit_date' => 0, 'last_edit_aid' => 0, 'edit_date' => 0,
'post_ip' => get_browser_real_ip() 'post_ip' => $_SERVER['REMOTE_ADDR']
))) { ))) {
$thread_id = $db->lastInsertId(); $thread_id = $db->lastInsertId();
$db->query("UPDATE `" . FORUM_TABLE_PREFIX . "forum` SET `first_post`=".(int) $thread_id." WHERE `id` = ".(int) $thread_id); $db->query("UPDATE `" . FORUM_TABLE_PREFIX . "forum` SET `first_post`=".(int) $thread_id." WHERE `id` = ".(int) $thread_id);
@@ -94,7 +93,7 @@ class Forum
'post_smile' => $smile, 'post_smile' => $smile,
'post_html' => $html, 'post_html' => $html,
'post_date' => time(), 'post_date' => time(),
'post_ip' => get_browser_real_ip() 'post_ip' => $_SERVER['REMOTE_ADDR']
)); ));
} }
public static function add_board($name, $description, $access, $guild, &$errors) public static function add_board($name, $description, $access, $guild, &$errors)
@@ -155,14 +154,14 @@ class Forum
return !count($errors); return !count($errors);
} }
public static function toggleHide_board($id, &$errors) public static function toggleHidden_board($id, &$errors)
{ {
global $db; global $db;
if(isset($id)) if(isset($id))
{ {
$query = self::get_board($id); $query = self::get_board($id);
if($query !== false) if($query !== false)
$db->update(TABLE_PREFIX . 'forum_boards', array('hide' => ($query['hide'] == 1 ? 0 : 1)), array('id' => $id)); $db->update(TABLE_PREFIX . 'forum_boards', array('hidden' => ($query['hidden'] == 1 ? 0 : 1)), array('id' => $id));
else else
$errors[] = 'Forum board with id ' . $id . ' does not exists.'; $errors[] = 'Forum board with id ' . $id . ' does not exists.';
} }
@@ -295,7 +294,7 @@ class Forum
$section = $sections[$board_id]; $section = $sections[$board_id];
if($section['guild'] > 0) { if($section['guild'] > 0) {
if($logged) { if($logged) {
$guild = new \OTS_Guild(); $guild = new OTS_Guild();
$guild->load($section['guild']); $guild->load($section['guild']);
$status = false; $status = false;
if($guild->isLoaded()) { if($guild->isLoaded()) {
@@ -323,3 +322,4 @@ class Forum
return $hasAccess; return $hasAccess;
} }
} }
?>

View File

@@ -8,11 +8,7 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC;
use MyAAC\Cache\PHP as CachePHP;
use MyAAC\Models\Spell;
class Items class Items
{ {
@@ -27,7 +23,7 @@ class Items
return false; return false;
} }
$xml = new \DOMDocument; $xml = new DOMDocument;
$xml->load($file_path); $xml->load($file_path);
$items = array(); $items = array();
@@ -43,7 +39,8 @@ class Items
} }
} }
$cache_php = new CachePHP(config('cache_prefix'), CACHE . 'persistent/'); require_once LIBS . 'cache_php.php';
$cache_php = new Cache_PHP(config('cache_prefix'), CACHE);
$cache_php->set('items', $items, 5 * 365 * 24 * 60 * 60); $cache_php->set('items', $items, 5 * 365 * 24 * 60 * 60);
return true; return true;
} }
@@ -70,7 +67,8 @@ class Items
return; return;
} }
$cache_php = new CachePHP(config('cache_prefix'), CACHE . 'persistent/'); require_once LIBS . 'cache_php.php';
$cache_php = new Cache_PHP(config('cache_prefix'), CACHE);
self::$items = $cache_php->get('items'); self::$items = $cache_php->get('items');
} }
@@ -112,7 +110,7 @@ class Items
$s .= 'an item of type ' . $item['id']; $s .= 'an item of type ' . $item['id'];
if(isset($attr['type']) && strtolower($attr['type']) == 'rune') { if(isset($attr['type']) && strtolower($attr['type']) == 'rune') {
$item = Spell::where('item_id', $id)->first(); $item = Spells::where('item_id', $id)->first();
if($item) { if($item) {
if($item->level > 0 && $item->maglevel > 0) { if($item->level > 0 && $item->maglevel > 0) {
$s .= '. ' . ($count > 1 ? "They" : "It") . ' can only be used by '; $s .= '. ' . ($count > 1 ? "They" : "It") . ' can only be used by ';

View File

@@ -1,8 +1,5 @@
<?php <?php
namespace MyAAC;
use MyAAC\Cache\Cache;
use MyAAC\Models\News as ModelsNews; use MyAAC\Models\News as ModelsNews;
class News class News
@@ -37,29 +34,17 @@ class News
if(!self::verify($title, $body, $article_text, $article_image, $errors)) if(!self::verify($title, $body, $article_text, $article_image, $errors))
return false; return false;
$currentTime = time(); ModelsNews::create([
'title' => $title,
$params = [ 'body' => $body,
'title' => $title, 'body' => $body, 'type' => $type,
'type' => $type, 'category' => $category, 'date' => time(),
'date' => $currentTime, 'category' => $category,
'player_id' => $player_id ?? 0, 'player_id' => isset($player_id) ? $player_id : 0,
'comments' => $comments, 'comments' => $comments,
'article_text' => ($type == 3 ? $article_text : ''), 'article_text' => ($type == 3 ? $article_text : ''),
'article_image' => ($type == 3 ? $article_image : '') 'article_image' => ($type == 3 ? $article_image : '')
]; ]);
global $hooks;
if (!$hooks->trigger(HOOK_ADMIN_NEWS_ADD_PRE, $params)) {
return false;
}
$newsModel = ModelsNews::create($params);
$hooks->trigger(HOOK_ADMIN_NEWS_ADD,
$params + ['id' => $newsModel->id],
);
self::clearCache(); self::clearCache();
return true; return true;
} }
@@ -70,55 +55,30 @@ class News
static public function update($id, $title, $body, $type, $category, $player_id, $comments, $article_text, $article_image, &$errors) static public function update($id, $title, $body, $type, $category, $player_id, $comments, $article_text, $article_image, &$errors)
{ {
if(!self::verify($title, $body, $article_text, $article_image, $errors)) { if(!self::verify($title, $body, $article_text, $article_image, $errors))
return false; return false;
}
$currentTime = time(); ModelsNews::where('id', $id)->update([
'title' => $title,
$params = [ 'body' => $body,
'id' => $id, 'type' => $type,
'title' => $title, 'body' => $body, 'category' => $category,
'type' => $type, 'category' => $category, 'last_modified_by' => isset($player_id) ? $player_id : 0,
'last_modified_by' => $player_id ?? 0, 'last_modified_date' => $currentTime, 'last_modified_date' => time(),
'comments' => $comments, 'comments' => $comments,
'article_text' => ($type == 3 ? $article_text : ''), 'article_text' => $article_text,
'article_image' => ($type == 3 ? $article_image : ''), 'article_image' => $article_image
]; ]);
global $hooks;
if (!$hooks->trigger(HOOK_ADMIN_NEWS_UPDATE_PRE, $params)) {
return false;
}
unset($params['id']);
ModelsNews::where('id', $id)->update($params);
$hooks->trigger(HOOK_ADMIN_NEWS_UPDATE,
$params + ['id' => $id]
);
self::clearCache(); self::clearCache();
return true; return true;
} }
static public function delete($id, &$errors) static public function delete($id, &$errors)
{ {
global $hooks;
if(isset($id)) { if(isset($id)) {
$row = ModelsNews::find($id); $row = ModelsNews::find($id);
if($row) { if($row) {
$params = ['id' => $id]; if (!$row->delete()) {
if (!$hooks->trigger(HOOK_ADMIN_NEWS_DELETE_PRE, $params)) {
return false;
}
if ($row->delete()) {
$hooks->trigger(HOOK_ADMIN_NEWS_DELETE, $params);
} else {
$errors[] = 'Fail during delete News.'; $errors[] = 'Fail during delete News.';
} }
} }
@@ -138,37 +98,24 @@ class News
return true; return true;
} }
static public function toggleHide($id, &$errors, &$status) static public function toggleHidden($id, &$errors, &$status)
{
if(isset($id))
{ {
global $hooks;
if(isset($id)) {
$row = ModelsNews::find($id); $row = ModelsNews::find($id);
if($row) { if($row)
$row->hide = ($row->hide == 1 ? 0 : 1); {
$row->hidden = $row->hidden == 1 ? 0 : 1;
$params = ['hide' => $row->hide]; if (!$row->save()) {
$errors[] = 'Fail during toggle hidden News.';
if (!$hooks->trigger(HOOK_ADMIN_NEWS_TOGGLE_HIDE_PRE, $params)) {
return false;
} }
$status = $row->hidden;
if ($row->save()) {
$hooks->trigger(HOOK_ADMIN_NEWS_TOGGLE_HIDE, $params);
} }
else { else
$errors[] = 'Fail during toggle hide News.';
}
$status = $row->hide;
}
else {
$errors[] = 'News with id ' . $id . ' does not exists.'; $errors[] = 'News with id ' . $id . ' does not exists.';
} }
} else
else {
$errors[] = 'News id not set.'; $errors[] = 'News id not set.';
}
if(count($errors)) { if(count($errors)) {
return false; return false;

View File

@@ -9,10 +9,7 @@
* @copyright 2021 MyAAC * @copyright 2021 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC;
use MyAAC\Cache\PHP as CachePHP;
class NPCs class NPCs
{ {
@@ -25,7 +22,7 @@ class NPCs
return false; return false;
$npcs = []; $npcs = [];
$xml = new \DOMDocument(); $xml = new DOMDocument();
foreach (preg_grep('~\.(xml)$~i', scandir($npc_path)) as $npc) { foreach (preg_grep('~\.(xml)$~i', scandir($npc_path)) as $npc) {
$xml->load($npc_path . $npc); $xml->load($npc_path . $npc);
if ($xml) { if ($xml) {
@@ -43,7 +40,8 @@ class NPCs
return false; return false;
} }
$cache_php = new CachePHP(config('cache_prefix'), CACHE . 'persistent/'); require_once LIBS . 'cache_php.php';
$cache_php = new Cache_PHP(config('cache_prefix'), CACHE);
$cache_php->set('npcs', $npcs, 5 * 365 * 24 * 60 * 60); $cache_php->set('npcs', $npcs, 5 * 365 * 24 * 60 * 60);
return true; return true;
} }
@@ -54,7 +52,8 @@ class NPCs
return; return;
} }
$cache_php = new CachePHP(config('cache_prefix'), CACHE . 'persistent/'); require_once LIBS . 'cache_php.php';
$cache_php = new Cache_PHP(config('cache_prefix'), CACHE);
self::$npcs = $cache_php->get('npcs'); self::$npcs = $cache_php->get('npcs');
} }
} }

View File

@@ -1,9 +1,44 @@
<?php <?php
/**
* Plugins class
*
* @package MyAAC
* @author Gesior <jerzyskalski@wp.pl>
* @author Slawkens <slawkens@gmail.com>
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
namespace MyAAC; function is_sub_dir($path = NULL, $parent_folder = BASE) {
//Get directory path minus last folder
$dir = dirname($path);
$folder = substr($path, strlen($dir));
//Check the the base dir is valid
$dir = realpath($dir);
//Only allow valid filename characters
$folder = preg_replace('/[^a-z0-9\.\-_]/i', '', $folder);
//If this is a bad path or a bad end folder name
if( !$dir OR !$folder OR $folder === '.') {
return FALSE;
}
//Rebuild path
$path = $dir. '/' . $folder;
//If this path is higher than the parent folder
if( strcasecmp($path, $parent_folder) > 0 ) {
return $path;
}
return FALSE;
}
use Composer\Semver\Semver; use Composer\Semver\Semver;
use MyAAC\Cache\Cache;
use MyAAC\Models\Menu; use MyAAC\Models\Menu;
class Plugins { class Plugins {
@@ -23,15 +58,10 @@ class Plugins {
$routes = []; $routes = [];
foreach(self::getAllPluginsJson() as $plugin) { foreach(self::getAllPluginsJson() as $plugin) {
$routesDefaultPriority = 1000;
if (isset($plugin['routes-default-priority'])) {
$routesDefaultPriority = $plugin['routes-default-priority'];
}
$warningPreTitle = 'Plugin: ' . $plugin['name'] . ' - '; $warningPreTitle = 'Plugin: ' . $plugin['name'] . ' - ';
if (isset($plugin['routes'])) { if (isset($plugin['routes'])) {
foreach ($plugin['routes'] as $info) { foreach ($plugin['routes'] as $_name => $info) {
// default method: get // default method: get
$method = $info['method'] ?? ['GET']; $method = $info['method'] ?? ['GET'];
if ($method !== '*') { if ($method !== '*') {
@@ -48,7 +78,7 @@ class Plugins {
} }
if (!isset($info['priority'])) { if (!isset($info['priority'])) {
$info['priority'] = $routesDefaultPriority; // default priority taken from plugin.json $info['priority'] = 100; // default priority
} }
if (isset($info['redirect_from'])) { if (isset($info['redirect_from'])) {
@@ -64,63 +94,27 @@ class Plugins {
} }
} }
// replace first occurrence of / in pattern if found (will be auto-added later) // replace first occurence of / in pattern if found (will be auto-added later)
removeIfFirstSlash($info['pattern']); removeIfFirstSlash($info['pattern']);
foreach ($routes as $id => &$route) {
if($route[1] == $info['pattern']) {
if($info['priority'] < $route[3]) {
self::$warnings[] = $warningPreTitle . "Duplicated route with lower priority: {$info['pattern']}. Disabling this route...";
continue 2;
}
else {
self::$warnings[] = $warningPreTitle . "Duplicated route with lower priority: {$route[1]} ({$route[3]}). Disabling this route...";
unset($routes[$id]);
}
}
}
$routes[] = [$methods, $info['pattern'], $info['file'], $info['priority']]; $routes[] = [$methods, $info['pattern'], $info['file'], $info['priority']];
} }
} }
$pagesDefaultPriority = 1000;
if (isset($plugin['pages-default-priority'])) {
$pagesDefaultPriority = $plugin['pages-default-priority'];
} }
/*
if (self::getAutoLoadOption($plugin, 'pages', true)) {
//
// Get all plugins/*/pages/*.php pages
//
$pluginPages = glob(PLUGINS . $plugin['filename'] . '/pages/*.php');
foreach ($pluginPages as $file) {
$file = str_replace(PLUGINS, 'plugins/', $file);
$name = pathinfo($file, PATHINFO_FILENAME);
$routes[] = [['get', 'post'], $name, $file, $pagesDefaultPriority];
}
}
if (self::getAutoLoadOption($plugin, 'pagesSubFolders', true)) {
//
// Get all plugins/*/pages/subFolder/*.php pages
//
$pluginPagesSubFolders = glob(PLUGINS . $plugin['filename'] . '/pages/*', GLOB_ONLYDIR);
foreach ($pluginPagesSubFolders as $folder) {
$folderName = pathinfo($folder, PATHINFO_FILENAME);
$subFiles = glob(PLUGINS . $plugin['filename'] . '/pages/' . $folderName . '/*.php');
foreach ($subFiles as $file) {
$file = str_replace(PLUGINS, 'plugins/', $file);
$name = $folderName . '/' . pathinfo($file, PATHINFO_FILENAME);
$routes[] = [['get', 'post'], $name, $file, $pagesDefaultPriority];
}
$subFolders = glob(PLUGINS . $plugin['filename'] . '/pages/' . $folderName . '/*', GLOB_ONLYDIR);
foreach ($subFolders as $subFolder) {
$subFolderName = pathinfo($subFolder, PATHINFO_FILENAME);
$subSubFiles = glob(PLUGINS . $plugin['filename'] . '/pages/' . $folderName . '/' . $subFolderName . '/*.php');
foreach ($subSubFiles as $subSubFile) {
$subSubFile = str_replace(PLUGINS, 'plugins/', $subSubFile);
$name = $folderName . '/' . $subFolderName . '/' . pathinfo($subSubFile, PATHINFO_FILENAME);
$routes[] = [['get', 'post'], $name, $subSubFile, $pagesDefaultPriority];
}
}
}
}
}
usort($routes, function ($a, $b) usort($routes, function ($a, $b)
{ {
// key 3 is priority // key 3 is priority
@@ -128,14 +122,14 @@ class Plugins {
return 0; return 0;
} }
return ($a[3] < $b[3]) ? -1 : 1; return ($a[3] > $b[3]) ? -1 : 1;
}); });
*/
// cleanup before passing back // cleanup before passing back
// priority is not needed anymore // priority is not needed anymore
//foreach ($routes as &$route) { foreach ($routes as &$route) {
// unset($route[3]); unset($route[3]);
//} }
if ($cache->enabled()) { if ($cache->enabled()) {
$cache->set('plugins_routes', serialize($routes), 600); $cache->set('plugins_routes', serialize($routes), 600);
@@ -144,67 +138,6 @@ class Plugins {
return $routes; return $routes;
} }
public static function getThemes()
{
$cache = Cache::getInstance();
if ($cache->enabled()) {
$tmp = '';
if ($cache->fetch('plugins_themes', $tmp)) {
return unserialize($tmp);
}
}
$themes = [];
foreach(self::getAllPluginsJson() as $plugin) {
if (!self::getAutoLoadOption($plugin, 'themes', true)) {
continue;
}
$pluginThemes = glob(PLUGINS . $plugin['filename'] . '/themes/*', GLOB_ONLYDIR);
foreach ($pluginThemes as $path) {
$path = str_replace(PLUGINS, 'plugins/', $path);
$name = pathinfo($path, PATHINFO_FILENAME);
$themes[$name] = $path;
}
}
if ($cache->enabled()) {
$cache->set('plugins_themes', serialize($themes), 600);
}
return $themes;
}
public static function getCommands()
{
$cache = Cache::getInstance();
if ($cache->enabled()) {
$tmp = '';
if ($cache->fetch('plugins_commands', $tmp)) {
return unserialize($tmp);
}
}
$commands = [];
foreach(self::getAllPluginsJson() as $plugin) {
if (!self::getAutoLoadOption($plugin, 'commands', true)) {
continue;
}
$pluginCommands = glob(PLUGINS . $plugin['filename'] . '/commands/*.php');
foreach ($pluginCommands as $path) {
$commands[] = $path;
}
}
if ($cache->enabled()) {
$cache->set('plugins_commands', serialize($commands), 600);
}
return $commands;
}
public static function getHooks() public static function getHooks()
{ {
$cache = Cache::getInstance(); $cache = Cache::getInstance();
@@ -219,19 +152,13 @@ class Plugins {
foreach(self::getAllPluginsJson() as $plugin) { foreach(self::getAllPluginsJson() as $plugin) {
if (isset($plugin['hooks'])) { if (isset($plugin['hooks'])) {
foreach ($plugin['hooks'] as $_name => $info) { foreach ($plugin['hooks'] as $_name => $info) {
$priority = 1000;
if (str_contains($info['type'], 'HOOK_')) { if (str_contains($info['type'], 'HOOK_')) {
$info['type'] = str_replace('HOOK_', '', $info['type']); $info['type'] = str_replace('HOOK_', '', $info['type']);
} }
if (isset($info['priority'])) {
$priority = (int)$info['priority'];
}
if (defined('HOOK_'. $info['type'])) { if (defined('HOOK_'. $info['type'])) {
$hook = constant('HOOK_'. $info['type']); $hook = constant('HOOK_'. $info['type']);
$hooks[] = ['name' => $_name, 'type' => $hook, 'file' => $info['file'], 'priority' => $priority]; $hooks[] = ['name' => $_name, 'type' => $hook, 'file' => $info['file']];
} else { } else {
self::$warnings[] = 'Plugin: ' . $plugin['name'] . '. Unknown event type: ' . $info['type']; self::$warnings[] = 'Plugin: ' . $plugin['name'] . '. Unknown event type: ' . $info['type'];
} }
@@ -239,15 +166,6 @@ class Plugins {
} }
} }
usort($hooks, function ($a, $b)
{
if ($a['priority'] == $b['priority']) {
return 0;
}
return ($a['priority'] < $b['priority']) ? -1 : 1;
});
if ($cache->enabled()) { if ($cache->enabled()) {
$cache->set('plugins_hooks', serialize($hooks), 600); $cache->set('plugins_hooks', serialize($hooks), 600);
} }
@@ -359,11 +277,11 @@ class Plugins {
{ {
global $db; global $db;
if(!\class_exists('\ZipArchive')) { if(!\class_exists('ZipArchive')) {
throw new \RuntimeException('Please install PHP zip extension. Plugins upload disabled until then.'); throw new RuntimeException('Please install PHP zip extension. Plugins upload disabled until then.');
} }
$zip = new \ZipArchive(); $zip = new ZipArchive();
if($zip->open($file) !== true) { if($zip->open($file) !== true) {
self::$error = 'There was a problem with opening zip archive.'; self::$error = 'There was a problem with opening zip archive.';
return false; return false;
@@ -587,7 +505,12 @@ class Plugins {
self::$warnings[] = 'Cannot load install script. Your plugin might be not working correctly.'; self::$warnings[] = 'Cannot load install script. Your plugin might be not working correctly.';
} }
clearCache(); $cache = Cache::getInstance();
if($cache->enabled()) {
$cache->delete('templates');
$cache->delete('hooks');
$cache->delete('template_menus');
}
return true; return true;
} }
@@ -634,82 +557,28 @@ class Plugins {
return true; return true;
} }
/**
* This function is to execute the "install" part of the plugin
*
* @param $plugin_name
* @return bool
*/
public static function executeInstall($plugin_name): bool
{
$filename = BASE . 'plugins/' . $plugin_name . '.json';
if(!file_exists($filename)) {
self::$error = 'Plugin ' . $plugin_name . ' does not exist.';
return false;
}
$string = file_get_contents($filename);
$plugin_json = json_decode($string, true);
if(!$plugin_json) {
self::$error = 'Cannot load plugin info ' . $plugin_name . '.json';
return false;
}
if(!isset($plugin_json['install'])) {
self::$error = "Plugin doesn't have install options defined. Skipping...";
return false;
}
global $db;
if (file_exists(BASE . $plugin_json['install'])) {
$db->revalidateCache();
require BASE . $plugin_json['install'];
$db->revalidateCache();
}
else {
self::$warnings[] = 'Cannot load install script. Your plugin might be not working correctly.';
}
return true;
}
public static function uninstall($plugin_name): bool public static function uninstall($plugin_name): bool
{ {
$isDisabled = self::existDisabled($plugin_name);
if($isDisabled) {
self::enable($plugin_name);
}
$revertEnable = function() use ($isDisabled, $plugin_name) {
if($isDisabled) {
self::disable($plugin_name);
}
};
$filename = BASE . 'plugins/' . $plugin_name . '.json'; $filename = BASE . 'plugins/' . $plugin_name . '.json';
if(!file_exists($filename)) { if(!file_exists($filename)) {
self::$error = 'Plugin ' . $plugin_name . ' does not exist.'; self::$error = 'Plugin ' . $plugin_name . ' does not exist.';
$revertEnable();
return false; return false;
} }
$string = file_get_contents($filename); $string = file_get_contents($filename);
$plugin_info = json_decode($string, true); $plugin_info = json_decode($string, true);
if(!$plugin_info) { if(!$plugin_info) {
self::$error = 'Cannot load plugin info ' . $plugin_name . '.json'; self::$error = 'Cannot load plugin info ' . $plugin_name . '.json';
$revertEnable();
return false; return false;
} }
if(!isset($plugin_info['uninstall'])) { if(!isset($plugin_info['uninstall'])) {
self::$error = "Plugin doesn't have uninstall options defined. Skipping..."; self::$error = "Plugin doesn't have uninstall options defined. Skipping...";
$revertEnable();
return false; return false;
} }
$success = true; $success = true;
foreach($plugin_info['uninstall'] as $file) { foreach($plugin_info['uninstall'] as $file) {
if(str_starts_with($file, '/')) { if(strpos($file, '/') === 0) {
$success = false; $success = false;
self::$error = "You cannot use absolute paths (starting with slash - '/'): " . $file; self::$error = "You cannot use absolute paths (starting with slash - '/'): " . $file;
break; break;
@@ -741,7 +610,6 @@ class Plugins {
return true; return true;
} }
$revertEnable();
return false; return false;
} }
@@ -782,23 +650,19 @@ class Plugins {
* Helper function for plugins * Helper function for plugins
* *
* @param string $templateName * @param string $templateName
* @param array $menus * @param array $categories
*/ */
public static function installMenus($templateName, $menus, $clearOld = false) public static function installMenus($templateName, $categories)
{ {
global $db; // check if menus already exist
$menuInstalled = Menu::where('template', $templateName)->select('id')->first();
if ($clearOld) { if ($menuInstalled) {
Menu::where('template', $templateName)->delete();
}
if (Menu::where('template', $templateName)->count()) {
return; return;
} }
foreach ($menus as $category => $_menus) { foreach ($categories as $category => $menus) {
$i = 0; $i = 0;
foreach ($_menus as $name => $link) { foreach ($menus as $name => $link) {
$color = ''; $color = '';
$blank = 0; $blank = 0;
@@ -822,33 +686,12 @@ class Plugins {
'link' => $link, 'link' => $link,
'category' => $category, 'category' => $category,
'ordering' => $i++, 'ordering' => $i++,
'blank' => $blank,
'color' => $color,
]; ];
// support for color and blank attributes
if($db->hasColumn(TABLE_PREFIX . 'menu', 'blank') && $db->hasColumn(TABLE_PREFIX . 'menu', 'color')) {
$insert_array['blank'] = $blank;
$insert_array['color'] = $color;
}
Menu::create($insert_array); Menu::create($insert_array);
} }
} }
} }
private static function getAutoLoadOption(array $plugin, string $optionName, bool $default = true)
{
if (isset($plugin['autoload'])) {
$autoload = $plugin['autoload'];
if (is_array($autoload)) {
if (isset($autoload[$optionName])) {
return getBoolean($autoload[$optionName]);
}
}
else if (is_bool($autoload)) {
return $autoload;
}
}
return $default;
}
} }

View File

@@ -370,14 +370,7 @@ class POT
throw new RuntimeException('Please install PHP pdo extension. MyAAC will not work without it.'); throw new RuntimeException('Please install PHP pdo extension. MyAAC will not work without it.');
} }
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));
}
else {
$this->db = new OTS_DB_MySQL($params); $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);
} }

Some files were not shown because too many files have changed in this diff Show More