Compare commits
303 Commits
v0.8.12
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44a6400fcf | ||
|
|
847c3db625 | ||
|
|
f30181d485 | ||
|
|
118e8c487e | ||
|
|
c73e476e88 | ||
|
|
ac5b864ea9 | ||
|
|
42d531838c | ||
|
|
2321cf84b0 | ||
|
|
a570363fe0 | ||
|
|
616b8eb61a | ||
|
|
e1d486c8c8 | ||
|
|
b841c9f631 | ||
|
|
e6c72efd18 | ||
|
|
9693fd260c | ||
|
|
717b5fdd15 | ||
|
|
32cf487128 | ||
|
|
a9941dea8a | ||
|
|
5c9737f281 | ||
|
|
87a98531d9 | ||
|
|
6d142dcbfe | ||
|
|
90f00e9960 | ||
|
|
8711e178e9 | ||
|
|
eb28b38709 | ||
|
|
afea618867 | ||
|
|
0abb9384a6 | ||
|
|
2563583f84 | ||
|
|
6acbbe3fa1 | ||
|
|
6c157f3f6c | ||
|
|
c4737eca72 | ||
|
|
5428f5e2cf | ||
|
|
7d6d77cfbc | ||
|
|
87eacd17c5 | ||
|
|
dd4420dcfd | ||
|
|
b8843a29eb | ||
|
|
a12262df55 | ||
|
|
091828e8f1 | ||
|
|
8bca099037 | ||
|
|
a43d641b5f | ||
|
|
46c058df25 | ||
|
|
fa7c6497e6 | ||
|
|
82b41d4df5 | ||
|
|
fd2c2d552a | ||
|
|
78ae456b45 | ||
|
|
7e5528b7e1 | ||
|
|
a97f55e189 | ||
|
|
50dd65c6de | ||
|
|
16aeb12111 | ||
|
|
96a7c43cb5 | ||
|
|
ee20ee2ecd | ||
|
|
efdd156d5e | ||
|
|
be41023005 | ||
|
|
d143f05bb1 | ||
|
|
fdc229b196 | ||
|
|
f6a5552296 | ||
|
|
62a4b4d3ec | ||
|
|
ef24d6739a | ||
|
|
1831198349 | ||
|
|
ddf764e308 | ||
|
|
988c757ca6 | ||
|
|
cedcd14550 | ||
|
|
0ff290f868 | ||
|
|
1764ce0519 | ||
|
|
f3b49d7cba | ||
|
|
6d19d69d20 | ||
|
|
9ad367370a | ||
|
|
eb091e487d | ||
|
|
a5ccc794bc | ||
|
|
1427dc3ede | ||
|
|
e47bb11883 | ||
|
|
6f3ba9c34b | ||
|
|
0f3d2424ce | ||
|
|
8ecd8a10c0 | ||
|
|
3cc3e3a8e9 | ||
|
|
be1086bcba | ||
|
|
f9abe9a8e3 | ||
|
|
632ecb6d20 | ||
|
|
db554df041 | ||
|
|
7300e4f1ad | ||
|
|
9b84532e57 | ||
|
|
14870d74df | ||
|
|
9c7794fe13 | ||
|
|
d9526d4021 | ||
|
|
454e09ec3d | ||
|
|
c687f64ced | ||
|
|
80623580f2 | ||
|
|
135f393fc4 | ||
|
|
e03da2876c | ||
|
|
44fff9dcd1 | ||
|
|
02f993baea | ||
|
|
f9302d4f9d | ||
|
|
780f8d193f | ||
|
|
4e85f857a4 | ||
|
|
ea035136e1 | ||
|
|
9d8f398d9f | ||
|
|
31f0050f4e | ||
|
|
7ce005341e | ||
|
|
84447ef178 | ||
|
|
b99d3b4960 | ||
|
|
0fc64478e0 | ||
|
|
e7a3d563aa | ||
|
|
bda020ef93 | ||
|
|
f0c136c421 | ||
|
|
5fa1321619 | ||
|
|
792ec17d18 | ||
|
|
19ffd57b34 | ||
|
|
ebda456862 | ||
|
|
5bd5aa0edf | ||
|
|
6b07d56627 | ||
|
|
15d381adfd | ||
|
|
23b44d6c8a | ||
|
|
e3f2abc06e | ||
|
|
3d73de13d8 | ||
|
|
71f7bb2e75 | ||
|
|
ebe900fca8 | ||
|
|
5a8bcec014 | ||
|
|
a1c7c2768c | ||
|
|
565e6e3a3d | ||
|
|
855e9aa3b9 | ||
|
|
a271edec47 | ||
|
|
81b293a5a6 | ||
|
|
8b41e144f8 | ||
|
|
a41f653e05 | ||
|
|
f24ff295e8 | ||
|
|
b399bee3ac | ||
|
|
8f88c82a13 | ||
|
|
d8ac88b7d9 | ||
|
|
443c5a80b4 | ||
|
|
ba56ef5e33 | ||
|
|
b24370e7ed | ||
|
|
b2b0b31168 | ||
|
|
1e969f8d8a | ||
|
|
bca098e074 | ||
|
|
98bd51436b | ||
|
|
1fa4b1e660 | ||
|
|
04a36b1d11 | ||
|
|
611d6f505d | ||
|
|
62b485abf9 | ||
|
|
61eae7d7c4 | ||
|
|
af161b5143 | ||
|
|
d5880eac8c | ||
|
|
02d6ab5fe7 | ||
|
|
5547ccffd6 | ||
|
|
8c06bd1738 | ||
|
|
469a8c1017 | ||
|
|
bb3602073c | ||
|
|
6c6af59b22 | ||
|
|
a8a36c73e6 | ||
|
|
98b1d854f9 | ||
|
|
1ada2317fd | ||
|
|
40722c8c30 | ||
|
|
ff9e255f1b | ||
|
|
fbe9c31d10 | ||
|
|
0aed705a6a | ||
|
|
06e864c954 | ||
|
|
1d68d013df | ||
|
|
8e6bc73ca6 | ||
|
|
7e0fded595 | ||
|
|
c8443228fb | ||
|
|
64fe0062ee | ||
|
|
3b78516ef2 | ||
|
|
8f345126f7 | ||
|
|
daaa472dfe | ||
|
|
87f35da3b6 | ||
|
|
6f42a60e59 | ||
|
|
3beedc1747 | ||
|
|
6603815a81 | ||
|
|
c1027d3663 | ||
|
|
6cec5ba5bf | ||
|
|
d70b70b63c | ||
|
|
7d73e3cd98 | ||
|
|
5087fc4a00 | ||
|
|
30cdb1ba73 | ||
|
|
0f6612904e | ||
|
|
e5b5b4d3ef | ||
|
|
9bc63bb55c | ||
|
|
dcf83d5608 | ||
|
|
8fe82bb5c0 | ||
|
|
6f74029d76 | ||
|
|
01e3d366ba | ||
|
|
41d5b4a22f | ||
|
|
7814636caf | ||
|
|
cf2c5e36bc | ||
|
|
5d5875d540 | ||
|
|
95c2adc02e | ||
|
|
73f1ba10f9 | ||
|
|
9fe419cfe7 | ||
|
|
41e24ca535 | ||
|
|
42a628731d | ||
|
|
2ba702df21 | ||
|
|
0171962306 | ||
|
|
2daa42e124 | ||
|
|
abfd2c94f5 | ||
|
|
fd51fa7779 | ||
|
|
1a36aa8904 | ||
|
|
881a28138a | ||
|
|
26fb1698b8 | ||
|
|
13d7dd98bd | ||
|
|
672a9f1712 | ||
|
|
2e560ac081 | ||
|
|
39d1127cf1 | ||
|
|
13586e664f | ||
|
|
6e6db543f7 | ||
|
|
ea8ae2372e | ||
|
|
928de13459 | ||
|
|
e213c3e7d8 | ||
|
|
65b4b2d183 | ||
|
|
94b145b215 | ||
|
|
6c9e6af154 | ||
|
|
b5736ad559 | ||
|
|
ab3912b378 | ||
|
|
3090989dea | ||
|
|
92314b8dac | ||
|
|
a52396008d | ||
|
|
ae7350e3a0 | ||
|
|
c30300c368 | ||
|
|
ed3d415c05 | ||
|
|
bb353d617a | ||
|
|
d7f41748ad | ||
|
|
915ae47971 | ||
|
|
40b151b4c5 | ||
|
|
1992410a7b | ||
|
|
48874f5b07 | ||
|
|
2144a4eb7c | ||
|
|
cbdbf11edc | ||
|
|
515db04023 | ||
|
|
d3811f1bf1 | ||
|
|
815fedf8e7 | ||
|
|
929a7b9cfa | ||
|
|
f85361dbc5 | ||
|
|
cb6509d09d | ||
|
|
f09c129c6d | ||
|
|
602a4aa835 | ||
|
|
14d5c6311b | ||
|
|
289dd3c170 | ||
|
|
60eac97945 | ||
|
|
de1d6b9629 | ||
|
|
722264a083 | ||
|
|
357d487af7 | ||
|
|
1b802b040d | ||
|
|
25afbd935c | ||
|
|
e61bfd2722 | ||
|
|
fe571cbef3 | ||
|
|
a7c5cb8f5a | ||
|
|
dedb96ef4a | ||
|
|
ee49efd215 | ||
|
|
56a35eb864 | ||
|
|
d478fe0c71 | ||
|
|
03467ea64e | ||
|
|
3368fbd058 | ||
|
|
e84c6f7a24 | ||
|
|
a0006bad73 | ||
|
|
2458393d22 | ||
|
|
787416e552 | ||
|
|
1c6b241239 | ||
|
|
7469d520c9 | ||
|
|
7e00e62427 | ||
|
|
0e39a969c3 | ||
|
|
0ad1647930 | ||
|
|
d7fc45a72d | ||
|
|
54dfb642b1 | ||
|
|
40626d0f42 | ||
|
|
523afccb51 | ||
|
|
1087aefe0a | ||
|
|
9b66edc148 | ||
|
|
2c09b0ae86 | ||
|
|
8de8ad13bf | ||
|
|
70bd442bb0 | ||
|
|
5250b3189b | ||
|
|
2534651e20 | ||
|
|
f46a42023f | ||
|
|
e2ab301340 | ||
|
|
700f835243 | ||
|
|
9ce7162a04 | ||
|
|
af85a8b711 | ||
|
|
cd58008a0f | ||
|
|
1f6bd975d0 | ||
|
|
b3556c008e | ||
|
|
dbe83f8a74 | ||
|
|
d1c50f00a0 | ||
|
|
bd9d3154db | ||
|
|
1f0b4425a4 | ||
|
|
47bfea4c56 | ||
|
|
416de6b584 | ||
|
|
3d3d141b25 | ||
|
|
2ff56c17e3 | ||
|
|
fb326d0354 | ||
|
|
e84933cf26 | ||
|
|
8e04328482 | ||
|
|
d148b71f0f | ||
|
|
4e68838172 | ||
|
|
d281fc588b | ||
|
|
1799ef42a7 | ||
|
|
a0d5a863e0 | ||
|
|
df59b104db | ||
|
|
e7e327c238 | ||
|
|
ee6e68d0bf | ||
|
|
d7333b3f21 | ||
|
|
375bd58a0c | ||
|
|
cddd915adf | ||
|
|
9e0ad271f6 | ||
|
|
a0afeb2a7a | ||
|
|
7c208b38ed | ||
|
|
eaa11c68f3 |
@@ -11,4 +11,9 @@ insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
indent_style = tab
|
||||
|
||||
[{composer.json,package.json}]
|
||||
indent_style = space
|
||||
|
||||
[package.json]
|
||||
indent_size = 2
|
||||
1
.gitattributes
vendored
@@ -8,4 +8,3 @@ _config.yml export-ignore
|
||||
release.sh export-ignore
|
||||
|
||||
*.sh text eol=lf
|
||||
VERSION text eol=lf
|
||||
|
||||
9
.github/workflows/phplint.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: PHP Linting
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
branches: [master, develop]
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
@@ -9,8 +9,5 @@ jobs:
|
||||
phplint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: overtrue/phplint@7.4
|
||||
with:
|
||||
path: .
|
||||
options: --exclude="system/libs/polyfill-mbstring/bootstrap80.php"
|
||||
- uses: actions/checkout@v1
|
||||
- uses: michaelw90/PHP-Lint@master
|
||||
|
||||
24
.gitignore
vendored
@@ -2,9 +2,6 @@ Thumbs.db
|
||||
.DS_Store
|
||||
.idea
|
||||
|
||||
#
|
||||
/.htaccess
|
||||
|
||||
# composer
|
||||
composer.lock
|
||||
vendor
|
||||
@@ -12,10 +9,6 @@ vendor
|
||||
# npm
|
||||
node_modules
|
||||
|
||||
# cypress
|
||||
cypress.env.json
|
||||
cypress/e2e/2-advanced-examples
|
||||
|
||||
# created by release.sh
|
||||
releases
|
||||
tmp
|
||||
@@ -31,10 +24,6 @@ templates/*
|
||||
images/guilds/*
|
||||
!images/guilds/default.gif
|
||||
|
||||
# editor images
|
||||
images/editor/*
|
||||
!images/editor/index.html
|
||||
|
||||
# cache
|
||||
system/cache/*
|
||||
!system/cache/index.html
|
||||
@@ -42,10 +31,6 @@ system/cache/*
|
||||
!system/cache/signatures/index.html
|
||||
!system/cache/plugins/index.html
|
||||
|
||||
# php sessions
|
||||
system/php_sessions/*
|
||||
!system/php_sessions/index.html
|
||||
|
||||
# logs
|
||||
system/logs/*
|
||||
!system/logs/index.html
|
||||
@@ -54,15 +39,20 @@ system/logs/*
|
||||
system/data/*
|
||||
!system/data/index.html
|
||||
|
||||
# php sessions
|
||||
system/php_sessions/*
|
||||
!system/php_sessions/index.html
|
||||
|
||||
# plugins
|
||||
plugins/*
|
||||
!plugins/.htaccess
|
||||
!plugins/example.json
|
||||
!plugins/account-create-hint.json
|
||||
!plugins/account-create-hint
|
||||
!plugins/email-confirmed-reward.json
|
||||
!plugins/email-confirmed-reward
|
||||
landing
|
||||
|
||||
# system
|
||||
system/functions_custom.php
|
||||
|
||||
# others/rest
|
||||
system/pages/downloads.php
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
language: php
|
||||
php:
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
@@ -17,4 +15,4 @@ before_script:
|
||||
- composer require php-parallel-lint/php-parallel-lint --no-suggest --no-progress --no-interaction --no-ansi --quiet --optimize-autoloader
|
||||
|
||||
script:
|
||||
- php vendor/bin/parallel-lint --no-progress --no-colors --exclude vendor --exclude "system/libs/pot/OTS_DB_PDOQuery_PHP71.php" .
|
||||
- php vendor/bin/parallel-lint --no-progress --no-colors --exclude vendor --exclude "system/libs/pot/OTS_DB_PDOQuery.php" .
|
||||
|
||||
863
CHANGELOG.md
@@ -1,868 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## [0.8.12 - 07.08.2023]
|
||||
I've moved the repository back to my personal account. (Just so you know!)
|
||||
|
||||
I will also try to add git commits pointed to each change, lets see if you like it or not - you can comment in discussion, that will be created just after releasing this version :)
|
||||
## [0.9.0 - x.x.2020]
|
||||
|
||||
### Added
|
||||
* forum: better error messages (Suggested by @anyeor) (https://github.com/slawkens/myaac/commit/34725e0257684fe5fa43875cc3a8f587ba04642e)
|
||||
* more support for GesiorAAC classes, so some of them will work with MyAAC (https://github.com/slawkens/myaac/commit/a8172a518ff8939c4402349b16c064fcaf855d31)
|
||||
* word-break on forum thread & reply (Suggested by @anyeor) (https://github.com/slawkens/myaac/commit/ce4aed0f1719d2aadc749e5238e883e3c10e2686)
|
||||
|
||||
### Fixed
|
||||
* not working pages/links from database, introduced in 0.8.10 (Thanks to OtLand user - https://otland.net/members/0lo.99657/ for report) (https://github.com/slawkens/myaac/commit/1e874c7027769bd09e772a1cdac75d7e37991256)
|
||||
* it was possible to create topic in board that was closed, ommiting the error check (Thanks to @anyeor for report) (https://github.com/slawkens/myaac/commit/0d52978d9fb99869500d35e7676f454ca5eaba14)
|
||||
* PHP 8.2 compatibility - removed deprecated functions utf8_encode & utf8_decode (https://github.com/slawkens/myaac/commit/a338fd967cdbcc89e86be4e6b66b2cad2ff23251)
|
||||
* guild description not being correctly shown (Reported by @anyeor) (https://github.com/slawkens/myaac/commit/f2a3ec1185df64ad9084d4ff55790ae4a5b3e5fd, https://github.com/slawkens/myaac/commit/df321154f63d458a4bc7d83bac5e3447b67317a4)
|
||||
|
||||
### Removed
|
||||
* Some old code for verifying messages length (Reported by @anyeor) (https://github.com/slawkens/myaac/commit/df48363ea4ced4350fd90ffddf57d464ba5afa8b)
|
||||
* some info about config failed to load, was never working (https://github.com/slawkens/myaac/commit/7a546e5a41036b0e9e926d337c6f2e3c41c591d2)
|
||||
|
||||
## [0.8.11 - 30.06.2023]
|
||||
|
||||
### Added
|
||||
* new function from 0.9 - Cache::remember($key, $ttl, $callback)
|
||||
* new characters page hooks
|
||||
* line number & file to exception handler, to easier localize exceptions
|
||||
|
||||
### Changed
|
||||
* rename to .htaccess.dist, causes some problems on default setup
|
||||
* removing unneccessary PHP closing tags to prevent potential issues (by @SRNT-GG)
|
||||
* display warning if hook file does not exist
|
||||
|
||||
### Fixed
|
||||
* important: Not allow create char if limit is exceeded (by @anyeor) could have been used to spam database
|
||||
* deleted chars: cannot change comment, name, gender, cannot create guild, cannot be invited, cannot accept invite, cannot be passed leadership to
|
||||
* forum: quote and edit post buttons not being shown
|
||||
* twig exception thrown when player does not exist, on character change comment (thanks @anyeor)
|
||||
* BASE_DIR when accessing /tools
|
||||
* do not display warning if HTTP_ACCEPT_LANGUAGE is not set
|
||||
|
||||
## [0.8.10 - 18.05.2023]
|
||||
|
||||
### Changed
|
||||
* PHP 7.2.5 is now required, cause of Twig 2.x
|
||||
* allow pages to be placed in templates folder, under pages/ subfolder
|
||||
|
||||
### Fixed
|
||||
* Twig error with global variable on create account
|
||||
* links/redirects from facebook, etc. like ?fbclid=x
|
||||
* do not allow to continue install when there is no server database imported
|
||||
* cannot go forward when config.local.php cannot be saved
|
||||
* when server uses another items serializer
|
||||
* small bug on install - please fill all input
|
||||
|
||||
## [0.8.9 - 16.03.2023]
|
||||
|
||||
### Added
|
||||
* You can now disable server status checking for testing purposes, useful for local testing when there is no server running
|
||||
* with this, the page won't need 2 seconds to load
|
||||
* set status_enabled to false in config.php
|
||||
* new buttons code for tibiacom template, can create button with any text
|
||||
* patched some small changes from develop branch
|
||||
|
||||
### Changed
|
||||
* add .git to denied folders in nginx-sample.conf
|
||||
* plugins folder is now accessible from outside
|
||||
* add plugins folder to twig search paths
|
||||
|
||||
### Fixed
|
||||
* player save on tfs 1.5 with new ipv6
|
||||
* more php 8.x compatibility
|
||||
* rel path for exception message, causing message to be not in red background
|
||||
|
||||
## [0.8.8 - 18.02.2023]
|
||||
|
||||
### Added
|
||||
* mail confirmed reward
|
||||
* support for latest group changes in TFS
|
||||
* new function: escapeHtml
|
||||
|
||||
### Updated
|
||||
* TinyMCE to v4.9.1 (latest release in 4.x series)
|
||||
* Twig to v2.15.4
|
||||
|
||||
### Changed
|
||||
* you can now place custom pages in your template directory under pages/ folder
|
||||
* HOOK_LOGOUT parameters, now only account_id is passed
|
||||
|
||||
### Fixed
|
||||
* ipv6 introduced in latest TFS
|
||||
* config.account_premium_days for TFS 1.4+
|
||||
* better compatibility with GesiorAAC
|
||||
* PHP 8.1 compatibility
|
||||
* myaac_ db table detection failure
|
||||
* reload creatures error, when items cache has been cleared
|
||||
|
||||
### Removed
|
||||
* accounts.blocked column, which is not used by AAC
|
||||
|
||||
## [0.8.7 - 31.08.2022]
|
||||
|
||||
### Added
|
||||
* login.php for client 12.x is now part of official repo
|
||||
* browsehappy code
|
||||
* config use character sample skill (#201, @gpedro)
|
||||
* custom words blocked (#190, @gpedro)
|
||||
|
||||
### Changed
|
||||
* save php sessions in myaac dir
|
||||
* don't count deleted players when creating new character
|
||||
|
||||
### Fixed
|
||||
* patch vulnerability in change_rank.php (#194, @gesior, @thatmichaelguy)
|
||||
* fix guild invite page (#196, @worthdavi)
|
||||
* players not showing on highscores page (#195)
|
||||
* highscores page bug with high pages
|
||||
* $player->getStorage() does not work at all (#169, @gesior)
|
||||
* copying sample character when it have items with quotes (#200, @gpedro)
|
||||
* IPv6 issue when env is set to dev (#171)
|
||||
* admin page changed feet to match body colour (#174, @silic0nalph4)
|
||||
* exception being thrown when creating duplicated character name (#191)
|
||||
* rules page formatting (#177, @silic0nalph4)
|
||||
* account character create if auto_login is enabled
|
||||
* undefined variable notice on database_log enabled
|
||||
* removed VERSION file
|
||||
|
||||
## [0.8.6 - 10.07.2021]
|
||||
This update contains very important security fix.
|
||||
|
||||
Please update your MyAAC instances to this version.
|
||||
|
||||
## [0.8.5 - 08.06.2021]
|
||||
|
||||
### Changed
|
||||
* bcmath module is not required anymore
|
||||
* Gratis premium account fixes (#156, by @czbadaro)
|
||||
* Update 404 response (#163, by @anyeor)
|
||||
|
||||
### Fixed
|
||||
* compatibility with PHP 7.0 and lower
|
||||
* deleting ranks in guilds (#158, by @Misztrz)
|
||||
* guild back buttons (change logo & motd)
|
||||
* forum table style (boards & thread view)
|
||||
* guild list description new lines `<br>` being ignored (Thanks @anyeor for reporting)
|
||||
|
||||
|
||||
## [0.8.4 - 18.02.2021]
|
||||
|
||||
### Added
|
||||
* support for accounts.premium_ends_at (Latest TFS 1.x)
|
||||
* more clients to clients.conf.php
|
||||
|
||||
### Changed
|
||||
* minimum PHP 5.6 is now required
|
||||
* password can now contain any characters
|
||||
* add SSL on external image requests of items and outfits (@fernandomatos)
|
||||
* Use local storage for saving menu items (tibiacom template) - fixes bug with some websites like wykop.pl (browser freeze)
|
||||
* increase size of myaac_visitors.page column to 2048 (Thanks to OtLand user kaleuui)
|
||||
|
||||
### Fixed
|
||||
* compatibility with PHP 8.0 (latest XAMPP)
|
||||
* displaying PHP errors on env = "prod"
|
||||
* the Guildnick not showing in the guild pages (@leesneaks)
|
||||
* you cannot delete character more than twice (Thanks Okke)
|
||||
* ignore arrays in config.lua (fixes experienceStages loading)
|
||||
* parsing empty strings in config.lua (with comments)
|
||||
* headling.php cannot find font
|
||||
|
||||
## [0.8.3 - 27.10.2020]
|
||||
|
||||
### Added
|
||||
* pdo_mysql as required extension
|
||||
* some notice about Email validation in create account
|
||||
|
||||
### Changed
|
||||
* Move register DATABASE_VERSION into schema.sql
|
||||
* Caused migrations being fired when user manually imported database
|
||||
|
||||
### Fixed
|
||||
* creating very uncommon (bugged) account names
|
||||
* XSS in character search
|
||||
* Admin menu news editing warning when leaving page without touching the inputs
|
||||
* Guild Invite not working on otservbr-global
|
||||
* two boxes being show on email_change_cancel
|
||||
* when adding poll = template tibiacom broken
|
||||
* houses: Unknown column 'guild' in 'where clause (https://github.com/slawkens/myaac/issues/131)
|
||||
* account create when account_mail_verify is enabled
|
||||
* CloudFlare IP detection
|
||||
* network_twitter link in tibiacom template
|
||||
|
||||
## [0.8.2 - 03.06.2020]
|
||||
|
||||
### Added
|
||||
* Log query time in database_log (can be used for benchmarking)
|
||||
* new PHP constant: IS_CLI
|
||||
* $_SERVER['REQUEST_URI'] to database.log
|
||||
* outfit to highscores box in tibiacom template
|
||||
* system/data to .gitignore
|
||||
* error_reporting in admin panel (when in dev mode), so it shows php notices and warnings
|
||||
* example quests in config.php
|
||||
|
||||
### Changed
|
||||
* account_login input type from password to text
|
||||
|
||||
### Fixed
|
||||
* Guild Invite not working on otservbr-global (#123)
|
||||
* news not updating after adding in admin panel
|
||||
* wrong mana of character samples (#125)
|
||||
* missing rules page on clean install
|
||||
* double space character name creation (@Lee, #121)
|
||||
* creatures page: Max count and chance not shown on hovered items
|
||||
* exception being thrown when characters.frags enabled on TFS 1.x
|
||||
* TFS 0.4 guilds creation (Where guilds.checkdata and motd doesn't have default value)
|
||||
* ERR_TOO_MANY_REDIRECTS browser error on template change
|
||||
* updating template menus on template change
|
||||
* Account change info when config.account_country is disabled
|
||||
* cancel change email request
|
||||
* config.character_name_min/max_length being ignored in change_name.php
|
||||
* some rare bugs when database is no up-to-date and someone enters admin panel
|
||||
* extra line that is added when using a newer version than official release (@Lee)
|
||||
* admin links in featured article
|
||||
* some PHP Notice when HTTP_HOST is not set (Can happen on some old versions of HTTP protocol)
|
||||
* Show character indicator in check_name.js
|
||||
* Houses list View button was wrong (was from bootstrap)
|
||||
* OTS_House __construct - not loading by houseid parameter
|
||||
* message() function when executed in CLI
|
||||
|
||||
### Removed
|
||||
* unused myaac_commands table from schema
|
||||
* MyISAM engine from migration scripts (#128)
|
||||
|
||||
## [0.8.1 - 10.03.2020]
|
||||
|
||||
### Added
|
||||
* Support for Nostalrius OTS
|
||||
|
||||
### Changed
|
||||
* Move TODO to wiki
|
||||
* .tooltip css class to .item_image (bootstrap conflict)
|
||||
|
||||
### Fixed
|
||||
* Reloading of creatures/monsters throwing an exception
|
||||
* Loading custom pages with old Gesior variables [#108](https://github.com/slawkens/myaac/issues/107)
|
||||
* Some weird behaviour with installation of plugins
|
||||
* CHANGELOG.md loading in Admin Panel
|
||||
* spells displaying when level = 0
|
||||
* Some PHP warnings and notices
|
||||
|
||||
## [0.8.0 - 19.02.2020]
|
||||
|
||||
### Added:
|
||||
* new Awesome Bootstrap Admin Panel by Lee (@Leesneaks)
|
||||
* using Bootstrap 3
|
||||
* all existing pages were adjusted
|
||||
* new editor: Accounts
|
||||
* improved editor: Players
|
||||
* new Reports View page
|
||||
* Modules directory, which can be added using Plugins (@Leesneaks, @whiteblXK)
|
||||
* move News Management here (@whiteblXK)
|
||||
* interactive player outfit chooser (@tobi132)
|
||||
* added Highscores by balance
|
||||
* possibility to define colors and "Open in New Tab" on Template Menus (needs to be supported by Template)
|
||||
* support for database persistent and socket connections (performance boost)
|
||||
* Team page - display outfits of the players (configurable)
|
||||
* added clear_cache.php, send_email.php bin commands (@slawkens, @tobi132)
|
||||
* added locale pt_br (@ivenspontes)
|
||||
* added load time into items & weapons loading admin page
|
||||
* new, beautiful exception handler
|
||||
* added travisci to prevent mistype (@gpedro, #89)
|
||||
* added showing database name into installation script (@tobi132)
|
||||
* compatibility with old z_ gesior table (@tobi132, #46)
|
||||
* added nginx-sample.conf, .editorconfig, VERSION
|
||||
* database towns table support for TFS 1.3 (@tobi132)
|
||||
* added enable_tinymce option to Pages editor
|
||||
|
||||
### Fixed:
|
||||
* account login redirect with special chars (like '&' and '?')
|
||||
* black skull info at serverInfo (@tornadia)
|
||||
* set correct limit at lastkills page from config (anyeor from OtLand)
|
||||
* myaac_monsters table column loot problem (#79)
|
||||
* players column deleted install description (@gpedro, #91)
|
||||
* experience table being to wide and buggy on some templates (@tobi132, #90)
|
||||
* fix errors with .htaccess files
|
||||
* added index.html to prevent indexing the folder by mod_index
|
||||
|
||||
### Changed:
|
||||
* Environment is now configurable by env setting (Significantly better load times with 'prod')
|
||||
* replace spells, monsters tables with JavaScript Sortable Tables - DataTables (@Leesneaks)
|
||||
* change default MySQL Storage Engine to InnoDB and Default Character Set to utf8
|
||||
* updated OTS_House class to support latest TFS 1.x (new columns)
|
||||
* updated monster images to the original ones from tibia.com
|
||||
* increased the minimum length (3 -> 4) and decreased the maximum length (25 -> 21) of the New Character Name (by @vankk)
|
||||
* use $db->exec instead of $db->query optimisation
|
||||
* move items from database to Cache_PHP (Much more faster load time)
|
||||
* allow simultaneous loading of config.ini and config.php in templates
|
||||
* updated copyright year and SSL link (@EPuncker, #88)
|
||||
* move commands, rules and downloads pages into database (@tobi132)
|
||||
* better view of guilds (new buttons, table look and feel) (@tobi132)
|
||||
* remove stupid alerts on account create
|
||||
* remove .dist extension from .htaccess
|
||||
|
||||
### New Configurables (config.php)
|
||||
* env (Environment)
|
||||
* account_create_auto_login (Auto Login after Create Account - Registration)
|
||||
* account_create_character_create (Create Character directly on Create Account page) (@tobi132)
|
||||
* footer_show_load_time (display load time of the page in the footer)
|
||||
* database_socket (Connection via Unix Socket)
|
||||
* database_persistent (Database Persistent Connection)
|
||||
* database_log (Logging of Database Queries)
|
||||
* admin_panel_modules (Modules displayed in Admin Panel Dashboard)
|
||||
* status_timeout, status_interval
|
||||
* smtp_debug (More info about SMTP errors in error.log)
|
||||
* team_display_outfit (Display outfit of the team members on teams page)
|
||||
* highscores_balance (Display highscores by balance)
|
||||
* character_name_min/max_length (Minimum and maximum length of character name)
|
||||
* characters.deleted (display deleted characters on characters page)
|
||||
|
||||
### Forum:
|
||||
* show image in full screen on click
|
||||
* show user avatar (outfit) in posts
|
||||
* replaced forum actions links (move, remove, edit, quote) with images
|
||||
* redirect directly to the thread on user login (on new reply)
|
||||
|
||||
### Installer:
|
||||
* AJAX loader for the important stuff
|
||||
* create admin account: ask for e-mail + character name
|
||||
* load items & weapons
|
||||
* check user IP on install to prevent install by random user
|
||||
* remember status of the installation
|
||||
* remember language on first step (welcome)
|
||||
* ask user for timezone
|
||||
* auto detected browser language in select language
|
||||
|
||||
### Plugins
|
||||
* sandbox for plugins, don't install when requirements are not satisfied
|
||||
* allow comments inside plugin json file (php style)
|
||||
* new require options for plugins: (look into example.json)
|
||||
* require database version, table or column of the MyAAC schema
|
||||
* require php-extension
|
||||
* require semantic-version (like in composer.json)
|
||||
* new hooks: LOGIN, LOGIN_ATTEMPT, LOGOUT, HOOK_ACCOUNT_CREATE_*
|
||||
|
||||
### Cache
|
||||
* php 7.x APCu cache support (faster cache engine)
|
||||
* new cache engine: plain PHP (is good with pure php 7.0+ and opcache)
|
||||
* cache lastkills.php, $db->hasTable, $db->hasColumn, hooks and template menus
|
||||
* stop using global $cache variable, use Singleton pattern instead
|
||||
|
||||
### Twig
|
||||
* move pages to Twig templates: team, lastkills, serverinfo, houses, guilds.list, guild.view, admin.logs, admin.reports (@whiteblXK, @tobi132)
|
||||
* replace "$twig->render()" with "$this->display"
|
||||
* move Twig functions to separate file
|
||||
* move tibiacom boxes to Twig templates
|
||||
* allow Pages to be loaded as Twig template (this allows using Twig variables in Pages) (@tobi132)
|
||||
* allow string to be passed to hook twig function
|
||||
|
||||
### Functions
|
||||
* config($key), configLua($key)
|
||||
* clearCache()
|
||||
* OTS_Account:
|
||||
* getCountry()
|
||||
* setLastLogin($lastlogin) (@Leesneaks)
|
||||
* setWebFlags(webflags) (@Leesneaks)
|
||||
* OTS_Player:
|
||||
* getAccountId()
|
||||
* countBlessings() (@Leesneaks)
|
||||
* checkBlessings($count) (@Leesneaks)
|
||||
* is_sub_dir (in system/libs/plugins.php)
|
||||
* Twig:
|
||||
* getPlayerLink($name, $generate = true)
|
||||
* removed SQLquote and SQLquery from OTS_Base_DB
|
||||
* Add optional $params param into log_append (will log arrays) (@tobi132)
|
||||
|
||||
### Internal
|
||||
* moved clients list to the new file (clients.conf.php)
|
||||
* changed tableExist and fieldExist to $db->hasTable(table) + $db->hasColumn(table, column)
|
||||
* changed deprecated $ots->createObject() functions with their OTS_ equivalents
|
||||
* add global helper config($key) function + twig binding
|
||||
* use config() instead of global $config
|
||||
* remove unnecessary parentheses in include/require PHP functions
|
||||
* use __DIR__ instead of dirname(__FILE__) - since PHP 5.3.0
|
||||
* change intval() function to (int) casting (up to 6x faster)
|
||||
* add release.sh script (for GitHub releases)
|
||||
* use curl as alternative option for reporting install
|
||||
|
||||
### Libraries
|
||||
* updated Twig to version v1.35.0
|
||||
* updated TinyMCE to version v4.7.4
|
||||
|
||||
### Deprecations
|
||||
* change deprecated HTML <center> tag to <div style="text-align:center">
|
||||
* replace deprecated HTML <font> tag with <span>
|
||||
|
||||
## [0.7.11 - 04.05.2019]
|
||||
### Added:
|
||||
* support for some old servers, where arrays are used in config.lua
|
||||
* an additional text to the install page informing that user can reinstall MyAAC by deleting config.local.php
|
||||
|
||||
### Fixed:
|
||||
* XSS in forum show_thread
|
||||
* guilds - "Add new rank" function
|
||||
* multiple mail recipients when using admin mailer function
|
||||
* Admin Panel - MyAAC logs not shown if servers logs directory doesn't exist (#47)
|
||||
* missing prefix for cache get() and delete() functions
|
||||
* add fatal error message when myaac tables in database do not exist
|
||||
* the mystical defect where "Create Account" button was not highlighted (on the account/manage page)
|
||||
* bug where server_config table does not exist (OTHire as an example)
|
||||
* database_name in Usage_Statistics
|
||||
* forgot to open <head> in install template
|
||||
|
||||
### Changed:
|
||||
* do not display software version
|
||||
|
||||
## [0.7.10 - 03.03.2018]
|
||||
### Added:
|
||||
* new configurable: smtp_secure
|
||||
* robots.txt
|
||||
|
||||
### Fixed:
|
||||
* editing an existing page that had php enabled
|
||||
* chrome bug on save (when editing page) ERR_BLOCKED_BY_XSS_AUDITOR
|
||||
* showing IP and Port in admin panel (#44, by miqueiaspenha)
|
||||
* deleting plugin showing "You don't have rights to delete"
|
||||
* some bug with PHPMailer not finding its language file
|
||||
* default accounts.vote value
|
||||
* saving some really high long ip addresses
|
||||
|
||||
### Changed:
|
||||
* update config.highscores_ids_hidden on install when there are samples already in database
|
||||
* auto add z_polls table on install
|
||||
|
||||
### Internal:
|
||||
* changed mb_strtolower functions to strtolower()
|
||||
* added new function: $hooks->exist($type)
|
||||
|
||||
## [0.7.9 - 13.01.2018]
|
||||
* removed 6mb of trash (some useless things)
|
||||
* (fix) TFS 1.x not showing promoted vocations in highscores
|
||||
* otserv 0.6.x: fixed some warning (on the characters page) and fatal mysql error (on the mango signature)
|
||||
* fixed default stamina on otserv 0.6.x engine (and some others perhaps)
|
||||
* install: change permission check to is_writable
|
||||
* changed highscores_groups_hidden to 3 (for TFS 1.x)
|
||||
* updated background-artwork (tibiacom template) to the latest version, removed other ones
|
||||
|
||||
## [0.7.8 - 12.01.2018]
|
||||
* fixed installation error " call to undefined method OTS_DB_MySQL::hasColumn()"
|
||||
* updated tinymce to the latest (4.7.4) version
|
||||
* enabled emoticons plugin in tinymce :)
|
||||
* some security fixes
|
||||
|
||||
## [0.7.7 - 08.01.2018]
|
||||
* important fix for servers with promotion column (caused player.vocation to be resetted when saving player, for example: on change name, accept invite to guild, leave guild)
|
||||
* immediately reload config.lua when there's change in config.server_path detected
|
||||
* added new forum option: "Enable HTML" (only for moderators)
|
||||
* fixed othire default column value (#26)
|
||||
* fixed saving custom vocations in admin panel (#36)
|
||||
* fixed warning in highscores when vocation doesn't exist
|
||||
* fixed characters page - config.characters.frags "Notice: Use of undefined constant"
|
||||
* fixed getBoolean function when boolean is passed
|
||||
* fixed empty success message on leave guild
|
||||
* fixed displaying premium account days
|
||||
* function OTS_Account:getPremDays will now return -1 if there's freePremium configurable enabled on the server
|
||||
* fixed tr bgcolor in characters view (Frags) (#38)
|
||||
* fixed some warning in guild show
|
||||
* fixed PHP warning about country not existing on online and characters pages
|
||||
* fixed forum bbcode parsing
|
||||
* don't add extra <br/> to the TinyMCE news forum posts
|
||||
* (internal) using $player->getVocationName() where possible instead of older method
|
||||
|
||||
## [0.7.6 - 05.01.2017]
|
||||
* fixed othire account creating/installation
|
||||
* fixed table name players -> players_online
|
||||
* fixed unexpected error logging about email fail
|
||||
* added max_execution_time to the install finish step
|
||||
* some small fix regarding highscores vocation box
|
||||
|
||||
## [0.7.5 - 04.01.2017]
|
||||
* fixed bug on othire with config.account_premium_days
|
||||
* fixed bug on TFS 1.x when online_afk is enabled
|
||||
* warning about leaving news page with changes
|
||||
* added player status to tibiacom top 5 highscores box
|
||||
* save detected country on create account in session
|
||||
* fixed getPremDays and isPremium functions (newest 11.x engines are bugged when it comes to PACC, its not fault of MyAAC)
|
||||
* fix when there are no changelogs or highscores yet
|
||||
* small fix regarding getTopPlayers function which was ignoring $limit variable
|
||||
* fixed news adding when type != ARTICLE
|
||||
* fixed template path finding
|
||||
* fixed displaying article_text when it was empty saved
|
||||
|
||||
## [0.7.4 - 24.12.2017]
|
||||
* fixed mysql fatal error on tibiacom template - top 5 box
|
||||
* fixed displaying of level percent bar on tibian signature
|
||||
* inform user about Twig cache failure on installation, instead of http 500 error
|
||||
* when dir system/cache is not writable by the webserver, then show some nice notice to the user about it instead of http 500 error
|
||||
* remember client version select and usage stats checkbox in session on install
|
||||
* automatically update highscores_ids_hidden for users who installed myaac before (migration)
|
||||
|
||||
## [0.7.3 - 18.12.2017]
|
||||
* auto generate myaac cache & session prefix on install to be unique across installations
|
||||
* fixed hiding shop system menu on tibiacom template when disabled in config
|
||||
* prevent adding duplicated newses with installation
|
||||
* some changes to sample characters: chanced town_id to 1, posx: 1000, posy: 1000, posz: 1000 and default group_id to 1 so you can change in-game outfits and they will be used
|
||||
* added version 772 constant to install client choose (OTHire)
|
||||
* better solution for hidding samples (configurable) - highscores_ids_hidden
|
||||
* fixed account.login redirect not working on tibiacom template
|
||||
* installation: warn about wrong admin account name/id and password
|
||||
* fixed last menu closing in tibiacom template
|
||||
* updated polish locale (translation) on install
|
||||
* (internal) removed some duplicated code on install finish
|
||||
* (internal) renamed installation step files to be in correct order
|
||||
* added TODO file
|
||||
|
||||
## [0.7.1 - 13.12.2017]
|
||||
* added changelog menu item to kathrine template
|
||||
* fixed some php short tag in changelogs page
|
||||
* fixed guild change description back button
|
||||
* removed duplicated "Support List" menu item from tibiacom template
|
||||
* changed some notice when version check is failed
|
||||
* (internal) moved changelog to twig
|
||||
|
||||
## [0.7.0 - 20.11.2017]
|
||||
* moved template menus to database, they're now dynamically loaded
|
||||
* added anonymous usage statistics reporting (only if user agrees, first usage report will be send after 7 days)
|
||||
* you can edit them in Admin Panel under 'Menus' option
|
||||
* you can also add custom links, like http://google.pl
|
||||
* added networks (facebook and twitter) and highscores (top 5) boxes to tibiacom template, configurable in templates/tibiacom/config.php
|
||||
* added news ticker for kathrine template
|
||||
* added featured article to tibiacom template (you can add them with add news button)
|
||||
* added tinymce editor to 'Pages' in admin panel
|
||||
* added links to edit/delete/hide custom page directly from page
|
||||
* update forum post after editing news (when forum post has been created)
|
||||
* enabled code plugin for tinymce which enabled raw html code editing
|
||||
* removed videos pages, as it can be easily added using custom Menus and Pages with insert Media
|
||||
* removed bug_report configurable, its now enabled by default
|
||||
* log some error info when mail cannot be send on account create
|
||||
* twig getLink function will now return with full url (BASE_URL included)
|
||||
* verify install post values directly on config page and display error
|
||||
* updated tinymce to version 4.7.2 (from 4.7.0)
|
||||
* updated phpmailer to version 5.2.26 (from 5.2.23)
|
||||
* (#30) (fix) recovering account on servers that doesn't support salts
|
||||
* (fix) account email confirm function
|
||||
* (fix) showing changelog with urls in Admin Panel
|
||||
* (fix) uninstalling plugin
|
||||
* (fix) polls box in tibiacom template
|
||||
* (fix) remove hooks from db on plugin deinstall
|
||||
* (fix) some weird include possibilities with forum and account actions (verify action name)
|
||||
* (fix) loading hooks from plugin installed from command line
|
||||
* (fix) some changelog PHP Notice warning
|
||||
* (internal) moved uninstall logic to Plugins class
|
||||
* (internal) moved tibiacom boxes to separate directory
|
||||
* (internal) moved news tickers to twig template
|
||||
* (internal) moved Forum class to separate file
|
||||
* (internal) moved deprecated functions to compat.php
|
||||
* (internal) added some compat functions that are used by shop system
|
||||
* (internal) renamed constant TICKET -> TICKER
|
||||
* (internal) shortened message functions
|
||||
|
||||
## [0.6.6 - 22.10.2017]
|
||||
* fixed some php fatal error on spells page
|
||||
* changed spells.vocations field in db size to 300
|
||||
* please reload your spells after this update!
|
||||
|
||||
## [0.6.5 - 21.10.2017]
|
||||
* fixed displaying custom pages
|
||||
* fixed adding new group forum board
|
||||
|
||||
## [0.6.4 - 20.10.2017]
|
||||
* reverted OTS_Account::getLastLogin() cause its used by tibia11-login plugin
|
||||
|
||||
## [0.6.3 - 20.10.2017]
|
||||
* fixed creating account
|
||||
* fixed viewing thread without being logged
|
||||
* fixed showing premium account status
|
||||
|
||||
## [0.6.2 - 20.10.2017]
|
||||
* added forums for guilds and groups
|
||||
* added nice looking menu for my account page in default template
|
||||
* new command line tool: install_plugin.php - can be used to install plugins from command line. Usage: "php install_plugin.php path_to_file"
|
||||
* added new tooltip to view characters equipment item name and monster loot
|
||||
* added items.xml loader class and weapons.xml loader class
|
||||
* minimum PHP version to install AAC is now 5.3.0 cause of Anonymous functions used by Twig
|
||||
* Added 'Are you sure?' popup when uninstalling plugin
|
||||
* added some warnings when plugin json file is incomplete
|
||||
* fixed showing in characters ban expires when is unlimited
|
||||
* fixed displaying monster loot when item.name in loot is used instead of item.id
|
||||
* load also runes into spells table
|
||||
* display plugin uninstall option only if its possible
|
||||
* after changing template you will be redirected to latest viewed page
|
||||
* display gallery add image form only on main gallery page
|
||||
* (internal) moved most of guilds html-in-php code to twig
|
||||
* (internal) moved spells page to twig template
|
||||
* (internal) removed useless spells.spell column that was duplicate of spells.words
|
||||
* (internal) save monster loot in database in json format instead loading it every time from xml file
|
||||
* (internal) store monster voices and immunities in json format
|
||||
* (internal) moved buttons to separate template
|
||||
* (internal) moved online search form to twig
|
||||
* (internal) added new function getItemNameById($id)
|
||||
* (internal) Moved plugin install logic to a new class: Plugins
|
||||
* (internal) changed spells.vocations database field to store json data instead of comma separated
|
||||
* (internal) removed $hook_types array, using defined() and constant() functions now
|
||||
* (internal) removed useless monsters.gfx_name field from database
|
||||
* (internal) renamed database field monsters.hide_creature to hidden
|
||||
* (internal) renamed existing Items class to Items_Images
|
||||
* (internal) optimized Spells class
|
||||
* (internal) new function: OTS_Guild::hasMember(OTS_Player $player)
|
||||
* (internal) new function: Forum::hasAccess($board_id)
|
||||
|
||||
## [0.6.1 - 17.10.2017]
|
||||
* fixed signatures loading
|
||||
* new configurable: session_prefix, to allow more websites on one machine (must be unique for every website on your dedicated server!)
|
||||
* better error handling for monsters and spells loader (save errors to system/logs/error.log)
|
||||
* check if file exist before loading (monsters and spells)
|
||||
* (internal) Account::getAccess() = Account::getGroupId()
|
||||
* (internal) moved account actions (pages) to account/ directory
|
||||
* (internal) moved forum actions (pages) to forum/ directory
|
||||
* (internal) moved forum.edit_post to twig templates
|
||||
|
||||
## [0.6.0 - 16.10.2017]
|
||||
* added faq management - add/edit/move/hide/delete from website
|
||||
* new account.login view for tibiacom template
|
||||
* monsters and spells are now being loaded at the installation of the AAC
|
||||
* fix for php versions under 5.5 where empty() function supported only variables
|
||||
* added missing change email and change info buttons to account.management default template
|
||||
* added new indicator icons for create account, create character and change character name
|
||||
* fixed config loader when some inline comments are present
|
||||
* fixed editing page in admin panel that contains some html code
|
||||
* fixed forum new post on mac os and some specific mysql versions
|
||||
* attempt to fix incorrect views counter behavior (its resetting to 0 in some cases)
|
||||
* enabled cache http headers for signatures
|
||||
* check if monster file exist before loading it
|
||||
* fixed if plugin zip file name contains dot (.)
|
||||
* renamed screenshots to gallery and movies to videos
|
||||
* moved install pages to twig
|
||||
* fixed Account::getGuildAccess function
|
||||
* removed never used library from sources - dwoo
|
||||
* moved check_* functions to class Validator
|
||||
* from now all validators ajax requests will fire onblur instead of onkeyup
|
||||
* ajax requests returns now json instead of xml
|
||||
* added 404 response when file is not found
|
||||
|
||||
## [0.5.1 - 11.10.2017]
|
||||
* fixed forum add/edit board
|
||||
* new configurable: highscores_length, how much highscores to display
|
||||
* fixed highscores links (ALL, previous and next page)
|
||||
* update templates cache when installing/uninstalling plugin
|
||||
* moved character deaths and frags table generation to twig
|
||||
* fixed some bug when you uninstall plugin and then try to install again on the same page
|
||||
* check if plugin exist before uninstalling
|
||||
* fixed some warning in OTS_Base_DB
|
||||
|
||||
## [0.5.0 - 10.10.2017]
|
||||
* moved .htaccess rules to plain php (index.php)
|
||||
* updated tinymce to the latest (4.7.0) version, you can now embed code, for example youtube videos
|
||||
* added option to uninstall plugin
|
||||
* added option to require specified myaac, php or database version for plugins, without that plugin won't be installed
|
||||
* change accountmanagement links to use friendly_urls
|
||||
* fixed creating new forum thread
|
||||
* sample characters are now assigned to admin account and have group_id 4 to not be shown on highscores
|
||||
* added links loaded from database to admin panel - for future plugins
|
||||
* print some info to error.log when can't find config.lua
|
||||
* some fixes in account changecomment action
|
||||
* show info when account name/number or password is empty on login
|
||||
* fixed showing account login errors
|
||||
* added few characters hooks
|
||||
* fixed some kathrine template js bug when shop is disabled
|
||||
* you can now use slash '/' in custom pages loaded from database
|
||||
* added new twig function getLink that convert link taking into account config.friendly_urls
|
||||
* internalLayoutLink -> getLink
|
||||
|
||||
## [0.4.3 - 05.10.2017]
|
||||
* better config loader taken from latest gesior, you can now include files in your config by doing dofile('config.local.lua')
|
||||
* fixed country detection in create account
|
||||
* fixed showing of character deaths and frags
|
||||
* fixed https://otland.net/threads/myaac-v0-0-1.251454/page-13#post-2466303
|
||||
* fixed https://otland.net/threads/myaac-v0-0-1.251454/page-13#post-2466313
|
||||
* fixed rook sample, which will now have level 1, 150 health, 0 mana, and 400 cap.
|
||||
* fixed samples being deleted by tfs 1.0+ cause of 'deletion' field set to 1
|
||||
* pages loaded from database have higher priority than normal .php pages, so they will be loaded first if they exist
|
||||
* moved many pages to twig templates
|
||||
* change download client links from clients.halfaway.net to tibia-clients.com
|
||||
* added bugtracker to kathrine template
|
||||
* added CREDITS file
|
||||
|
||||
## [0.4.2 - 14.09.2017]
|
||||
* updated version number
|
||||
|
||||
## [0.4.1 - 13.09.2017]
|
||||
* fixed log in to admin panel
|
||||
* fixed File is not .zip plugin upload error
|
||||
|
||||
## [0.4.0 - 13.09.2017
|
||||
* added option to add/edit/delete/hide/move forum boards
|
||||
* moved some of HTML-in-PHP code to Twig templates
|
||||
* added bug_report configurable which can enable/disable bug tracker
|
||||
* log errors instead of showing them to users with system directories
|
||||
* fix when $_SERVER['HTTP_ACCEPT_ENCODING'] is not set
|
||||
* when it fails to load config.lua it will output error also to error.log
|
||||
* automatically detect json file in .zip instead of basing on filename (admin panel - plugins)
|
||||
* hopefully fixed the error with "The file you are trying to upload is not a .zip file. Please try again."
|
||||
* fixed wrong name of table in bugtracker
|
||||
* fixed some bugs in bugtracker
|
||||
* added report bug link in templates
|
||||
* fixed some rare error when user is logged in for longer than 15 minutes and tries to login again
|
||||
* fixed some grammar errors
|
||||
* some small improvements
|
||||
* fixed some separators in kathrine template
|
||||
|
||||
## [0.3.0 - 28.08.2017]
|
||||
* added administration panel for screenshots management with auto thumbnail generator and image auto-resizing
|
||||
* added Twig template engine and moved some html-in-php code to it
|
||||
* automatically detect player country based on user location (IP) on create account
|
||||
* player sex (gender) is now configurable at $config['genders']
|
||||
* fixed recovering account and changing password when salt is enabled
|
||||
* fixed installing samples when for example Rook Sample already exist and other samples not
|
||||
* fixed some mysql error when character you trying to create already exist
|
||||
* fixed some warning when you select nonexistent country
|
||||
* password change minimal/maximal length notice is now more precise
|
||||
* added 'enabled' field in myaac_hooks table, which can enable or disable specified hook
|
||||
* removed DEFAULT '' for TEXT field. It didn't worked under some systems like MAC OS X.
|
||||
* minimum PHP version to install the MyAAC is now 5.2.0 cause of pathinfo (extension) function
|
||||
* removed unused admin stylish template
|
||||
* removed some unused cities field from myaac_spells table
|
||||
* moved news adding at installation from schema.sql to finish.php
|
||||
* some optimizations
|
||||
|
||||
## [0.2.4 - 09.06.2017]
|
||||
* fixed invite to guild
|
||||
* added id field on monsters, so you can delete them in phpmyadmin
|
||||
* fixed adding some creatures with ' and "
|
||||
* fixed when there are spaces at beginning of the file (creatures)
|
||||
* fixed when file is unable to parse (creatures)
|
||||
* fixed typo loss_items => loss_containers
|
||||
* more elegant way of showing message on reload creatures and spells
|
||||
|
||||
## [0.2.3 - 31.05.2017]
|
||||
* fixed guild management on OTHire 0.0.3
|
||||
* set default skills to 10 when creating new character
|
||||
* fixed displaying of "Create forum thread" in newses
|
||||
* fixed deleting guild on servers that use players.rank_id field
|
||||
* fixed phpmailer class loading (https://otland.net/threads/myaac-v0-0-1.251454/page-8#post-2445222)
|
||||
* fixed displaying vocation amount on online page
|
||||
* better support for custom vocations, you just need to set in config vocations_amount to yours.
|
||||
* fixed huge space in player name (https://otland.net/threads/myaac-v0-0-1.251454/page-7#post-2444328)
|
||||
* fixed Undefined variable (https://otland.net/threads/myaac-v0-0-1.251454/page-7#post-2444034)
|
||||
* fixed Undefined offset (https://otland.net/threads/myaac-v0-0-1.251454/page-7#post-2444035)
|
||||
|
||||
## [0.2.2 - 22.05.2017]
|
||||
* added missing cache/signature directory
|
||||
* fixed https://otland.net/threads/myaac-v0-0-1.251454/page-7#post-2443868
|
||||
|
||||
## [0.2.1 - 21.05.2017]
|
||||
* added Swedish translation by Sizaro
|
||||
* fixed some bugs with installlation & characters & houses
|
||||
|
||||
## [0.2.0 - 21.05.2017]
|
||||
* added option to change character sex for premium points
|
||||
* moved site_closed to database, now you can close your site through admin panel
|
||||
* added option to admin panel: clear cache
|
||||
* added experiencetable_rows configurable
|
||||
* optimized OTS_Account->getGroupId(), now its using like 20 queries less
|
||||
* optimized OTS_Player->load($id) function, should be much faster now
|
||||
* fixed displaying on highscores special outfits
|
||||
* fixed skull images displaying
|
||||
* fixed displaying unlimited premium account
|
||||
* fixed bug where players.lookaddons doesn't exist (OTHire etc.) (https://otland.net/threads/myaac-v0-0-1.251454/page-6#post-2442407)
|
||||
* fixed signature tibian for OTHire and other servers that doesnt use accounts.premdays field
|
||||
* fixed when player name in signature containst space
|
||||
* don't show "Create forum thread" when editing
|
||||
* fixed red color table after create account
|
||||
* updated download links, as clients.halfaway.net isn't working anymore
|
||||
* fixed some bugs while installing when field `email_next` or `hidden` already exist
|
||||
* fixed movies unexpected comment
|
||||
* added template_place_holder('center_top') to kathrine template
|
||||
|
||||
## [0.1.5 - 13.05.2017]
|
||||
* fixed bug with "Integrity constraint violation: 1048 Column 'ip' cannot be null"
|
||||
|
||||
## [0.1.4 - 13.05.2017]
|
||||
* added outfit shower, in characters, online, and highscores
|
||||
* updated database to version 2
|
||||
* fixed item images (now using item-images.ots.me host by default)
|
||||
* fixed news ticket and posting long newses (https://otland.net/threads/myaac-v0-0-1.251454/page-5#post-2442026)
|
||||
* news body limit increased to 65535 (mysql text field)
|
||||
* removed some unused code from my old server
|
||||
* added spells & monsters to kathrine template
|
||||
|
||||
## [0.1.3 - 11.05.2017]
|
||||
* this is just release to update version number
|
||||
|
||||
## [0.1.2 - 11.05.2017]
|
||||
* forgot to update CHANGELOG and MYAAC_VERSION
|
||||
|
||||
## [0.1.1 - 11.05.2017]
|
||||
* fixed updating myaac_config with database_version to 1
|
||||
* fixed database updater
|
||||
|
||||
## [0.1.0 - 11.05.2017]
|
||||
* added new feature: change character name for premium points (disabled by default, you can enable it in config under account_change_character_name in config.php)
|
||||
* added automatic database updater (data migrations)
|
||||
* renamed events to hooks
|
||||
* moved hooks to database
|
||||
* now you can use hooks in plugins
|
||||
* set account.type field to 5 on install, if TFS 1.0+
|
||||
* added example plugin
|
||||
* new, latest google analytics code
|
||||
* fixed bug with loading account.name that has numbers in it
|
||||
* fixed many bugs in player editor in admin panel
|
||||
* added error handling to plugin manager and some more verification in
|
||||
* file has been correctly unpacked/uploaded
|
||||
* fixed Statistics page in admin panel when using account.number
|
||||
* fixed bug when creating/recovering account on servers with
|
||||
* account.salt field (TFS 0.3 for example)
|
||||
* fixed forum showing thread with html tags (added from news manager)
|
||||
* new, latest code for youtube videos in movies page
|
||||
* fixed showing vocation images when using $config['online_vocations_images']
|
||||
* many fixes in polls (also importing proper schema)
|
||||
* fixed hovering on buttons in kathrine template (on accountmanagement page)
|
||||
* fixed signatures (many fixes)
|
||||
* added missing gesior signature system
|
||||
|
||||
## [0.0.6 - 06.05.2017]
|
||||
* fixed bug while installing (https://otland.net/threads/myaac-v0-0-1.251454/page-3#post-2440543)
|
||||
* fixed bug when creating character (not showing errors) (one more time)
|
||||
* fixed support for TFS 0.2 series
|
||||
* added FAQ link
|
||||
|
||||
## [0.0.5 - 05.05.2017]
|
||||
* fixed bug when creating character (not showing errors)
|
||||
* Fixed characters loading with names that has been created with other AAC
|
||||
* fixed links to shop in default template
|
||||
* fixed some weird PHP 7.1 warnings/notices
|
||||
* Fixed config loading with some weird comments
|
||||
* fixed bug with status info utf8 encoding (https://otland.net/threads/myaac-v0-0-1.251454/page-2#post-2440259)
|
||||
* fixed when ip in log_action is NULL (https://otland.net/threads/myaac-v0-0-1.251454/page-2#post-2440357)
|
||||
* fixed bug when guild doesn't exist on characters page (https://otland.net/threads/myaac-v0-0-1.251454/page-2#post-2440320)
|
||||
* disabled friendly_urls by default
|
||||
* fixes when $config['database_*'] is set
|
||||
* added CHANGELOG
|
||||
|
||||
## [0.0.3 - 03.05.2017]
|
||||
* Full support for OTHire 0.0.3
|
||||
* added support for otservers that doesn't use account.name field, instead just account number will be used
|
||||
* fixed encryption detection on TFS 0.3
|
||||
* fixed bug when server_config table doesn't exist
|
||||
* (install) moved admin account creation to new step
|
||||
* fixed news comment link
|
||||
* by default, the installer creates now the Admin player, for admin account
|
||||
* fixed installation errors
|
||||
* fixed config.lua loading with some weird comments
|
||||
|
||||
## [0.0.2 - 02.05.2017]
|
||||
* updated forum links to use friendly_urls
|
||||
* some more info will be shown when cannot connect to database
|
||||
* show more error infos when creating character
|
||||
* fixed forum link on newses
|
||||
* fixed spells loading when there's vocation name instead of id
|
||||
* fixed bug when you have changed template but it doesn't exist anymore
|
||||
* fixed vocations with promotion loading
|
||||
* fixed support for gesior pages and templates
|
||||
* added function OTS_Acount:getGroupId()
|
||||
|
||||
## [0.0.1 - 01.05.2017]
|
||||
This is first official release of MyAAC.
|
||||
Features are listed here
|
||||
|
||||
For more information, see the release announcement on OTLand: https://otland.net/threads/myaac-v0-0-1.251454/
|
||||
### Fixed
|
||||
2
CREDITS
@@ -1,3 +1,3 @@
|
||||
* Gesior.pl (2007 - 2008)
|
||||
* Slawkens (2009 - 2023)
|
||||
* Slawkens (2009 - 2022)
|
||||
* Contributors listed in CONTRIBUTORS.txt
|
||||
|
||||
@@ -13,7 +13,7 @@ Official website: https://my-aac.org
|
||||
|
||||
### Requirements
|
||||
|
||||
- PHP 7.2.5 or later
|
||||
- PHP 5.6 or later
|
||||
- MySQL database
|
||||
- PDO PHP Extension
|
||||
- XML PHP Extension
|
||||
@@ -36,7 +36,7 @@ Official website: https://my-aac.org
|
||||
chmod 660 images/guilds
|
||||
chmod 660 images/houses
|
||||
chmod 660 images/gallery
|
||||
chmod -R 760 system/cache
|
||||
chmod -R 770 system/cache
|
||||
|
||||
Visit http://your_domain/install (http://localhost/install) and follow instructions in the browser.
|
||||
|
||||
@@ -71,7 +71,7 @@ Look: [Contributing](https://github.com/otsoft/myaac/wiki/Contributing) in our w
|
||||
|
||||
### Other Notes
|
||||
|
||||
If you have a great idea or want contribute to the project - visit our website at https://www.my-aac.org
|
||||
If you have a great idea or want contribute to the project - visit our website at https://www.my-aac.org
|
||||
|
||||
### License
|
||||
|
||||
|
||||
BIN
admin/images/logo.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
@@ -1,2 +1 @@
|
||||
<?php
|
||||
// nothing yet here
|
||||
<?php
|
||||
@@ -53,7 +53,7 @@ if(!$logged || !admin()) {
|
||||
}
|
||||
|
||||
// include our page
|
||||
$file = ADMIN . 'pages/' . $page . '.php';
|
||||
$file = SYSTEM . 'pages/admin/' . $page . '.php';
|
||||
if(!@file_exists($file)) {
|
||||
$page = '404';
|
||||
$file = SYSTEM . 'pages/404.php';
|
||||
@@ -68,4 +68,4 @@ ob_end_clean();
|
||||
// template
|
||||
$template_path = 'template/';
|
||||
require ADMIN . $template_path . 'template.php';
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,490 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Account editor
|
||||
*
|
||||
* @package MyAAC
|
||||
* @author Lee
|
||||
* @copyright 2019 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
$title = 'Account editor';
|
||||
$base = BASE_URL . 'admin/?p=accounts';
|
||||
|
||||
if ($config['account_country'])
|
||||
require SYSTEM . 'countries.conf.php';
|
||||
|
||||
function echo_success($message)
|
||||
{
|
||||
echo '<p class="success">' . $message . '</p>';
|
||||
}
|
||||
|
||||
function echo_error($message)
|
||||
{
|
||||
global $error;
|
||||
echo '<p class="error">' . $message . '</p>';
|
||||
$error = true;
|
||||
}
|
||||
|
||||
function verify_number($number, $name, $max_length)
|
||||
{
|
||||
if (!Validator::number($number))
|
||||
echo_error($name . ' can contain only numbers.');
|
||||
|
||||
$number_length = strlen($number);
|
||||
if ($number_length <= 0 || $number_length > $max_length)
|
||||
echo_error($name . ' cannot be longer than ' . $max_length . ' digits.');
|
||||
}
|
||||
|
||||
$hasSecretColumn = $db->hasColumn('accounts', 'secret');
|
||||
$hasCoinsColumn = $db->hasColumn('accounts', 'coins');
|
||||
$hasPointsColumn = $db->hasColumn('accounts', 'premium_points');
|
||||
$hasTypeColumn = $db->hasColumn('accounts', 'type');
|
||||
$hasGroupColumn = $db->hasColumn('accounts', 'group_id');
|
||||
|
||||
if ($config['account_country']) {
|
||||
$countries = array();
|
||||
foreach (array('pl', 'se', 'br', 'us', 'gb') as $c)
|
||||
$countries[$c] = $config['countries'][$c];
|
||||
|
||||
$countries['--'] = '----------';
|
||||
foreach ($config['countries'] as $code => $c)
|
||||
$countries[$code] = $c;
|
||||
}
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo BASE_URL; ?>tools/css/jquery.datetimepicker.css"/ >
|
||||
<script src="<?php echo BASE_URL; ?>tools/js/jquery.datetimepicker.js"></script>
|
||||
|
||||
<?php
|
||||
$id = 0;
|
||||
if (isset($_REQUEST['id']))
|
||||
$id = (int)$_REQUEST['id'];
|
||||
else if (isset($_REQUEST['search_name'])) {
|
||||
if (strlen($_REQUEST['search_name']) < 3 && !Validator::number($_REQUEST['search_name'])) {
|
||||
echo 'Player name is too short.';
|
||||
} else {
|
||||
if (Validator::number($_REQUEST['search_name']))
|
||||
$id = $_REQUEST['search_name'];
|
||||
else {
|
||||
$query = $db->query('SELECT `id` FROM `accounts` WHERE `name` = ' . $db->quote($_REQUEST['search_name']));
|
||||
if ($query->rowCount() == 1) {
|
||||
$query = $query->fetch();
|
||||
$id = $query['id'];
|
||||
} else {
|
||||
$query = $db->query('SELECT `id`, `name` FROM `accounts` WHERE `name` LIKE ' . $db->quote('%' . $_REQUEST['search_name'] . '%'));
|
||||
if ($query->rowCount() > 0 && $query->rowCount() <= 10) {
|
||||
echo 'Do you mean?<ul>';
|
||||
foreach ($query as $row)
|
||||
echo '<li><a href="' . $base . '&id=' . $row['id'] . '">' . $row['name'] . '</a></li>';
|
||||
echo '</ul>';
|
||||
} else if ($query->rowCount() > 10)
|
||||
echo 'Specified name resulted with too many accounts.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$groups = new OTS_Groups_List();
|
||||
if ($id > 0) {
|
||||
$account = new OTS_Account();
|
||||
$account->load($id);
|
||||
|
||||
if (isset($account, $_POST['save']) && $account->isLoaded()) {// we want to save
|
||||
$error = false;
|
||||
|
||||
$_error = '';
|
||||
$account_db = new OTS_Account();
|
||||
if(USE_ACCOUNT_NAME) {
|
||||
$name = $_POST['name'];
|
||||
|
||||
$account_db->find($name);
|
||||
if ($account_db->isLoaded() && $account->getName() != $name)
|
||||
echo_error('This name is already used. Please choose another name!');
|
||||
}
|
||||
|
||||
$account_db->load($id);
|
||||
if (!$account_db->isLoaded())
|
||||
echo_error('Account with this id doesn\'t exist.');
|
||||
|
||||
//type/group
|
||||
if($hasTypeColumn || $hasGroupColumn) {
|
||||
$group = $_POST['group'];
|
||||
}
|
||||
|
||||
$password = ((!empty($_POST["pass"]) ? $_POST['pass'] : null));
|
||||
if (!Validator::password($password)) {
|
||||
$errors['password'] = Validator::getLastError();
|
||||
}
|
||||
|
||||
//secret
|
||||
if($hasSecretColumn) {
|
||||
$secret = $_POST['secret'];
|
||||
}
|
||||
|
||||
//key
|
||||
$key = $_POST['key'];
|
||||
$email = $_POST['email'];
|
||||
if (!Validator::email($email))
|
||||
$errors['email'] = Validator::getLastError();
|
||||
|
||||
//tibia coins
|
||||
if ($hasCoinsColumn) {
|
||||
$t_coins = $_POST['t_coins'];
|
||||
verify_number($t_coins, 'Tibia coins', 12);
|
||||
}
|
||||
// prem days
|
||||
$p_days = (int)$_POST['p_days'];
|
||||
verify_number($p_days, 'Prem days', 11);
|
||||
|
||||
//prem points
|
||||
$p_points = $_POST['p_points'];
|
||||
verify_number($p_points, 'Prem Points', 11);
|
||||
|
||||
//rl name
|
||||
$rl_name = $_POST['rl_name'];
|
||||
|
||||
//location
|
||||
$rl_loca = $_POST['rl_loca'];
|
||||
|
||||
//country
|
||||
$rl_country = $_POST['rl_country'];
|
||||
|
||||
$web_flags = $_POST['web_flags'];
|
||||
verify_number($web_flags, 'Web Flags', 1);
|
||||
|
||||
//created
|
||||
$created = $_POST['created'];
|
||||
verify_number($created, 'Created', 11);
|
||||
|
||||
//web last login
|
||||
$web_lastlogin = $_POST['web_lastlogin'];
|
||||
verify_number($web_lastlogin, 'Web Last logout', 11);
|
||||
|
||||
if (!$error) {
|
||||
if(USE_ACCOUNT_NAME) {
|
||||
$account->setName($name);
|
||||
}
|
||||
|
||||
if ($hasTypeColumn) {
|
||||
$account->setCustomField('type', $group);
|
||||
} elseif ($hasGroupColumn) {
|
||||
$account->setCustomField('group_id', $group);
|
||||
}
|
||||
|
||||
if($hasSecretColumn) {
|
||||
$account->setCustomField('secret', $secret);
|
||||
}
|
||||
$account->setCustomField('key', $key);
|
||||
$account->setEMail($email);
|
||||
if ($hasCoinsColumn) {
|
||||
$account->setCustomField('coins', $t_coins);
|
||||
}
|
||||
|
||||
$lastDay = 0;
|
||||
if($p_days != 0 && $p_days != OTS_Account::GRATIS_PREMIUM_DAYS) {
|
||||
$lastDay = time();
|
||||
} else if ($lastDay != 0) {
|
||||
$lastDay = 0;
|
||||
}
|
||||
|
||||
$account->setPremDays($p_days);
|
||||
$account->setLastLogin($lastDay);
|
||||
if ($hasPointsColumn) {
|
||||
$account->setCustomField('premium_points', $p_points);
|
||||
}
|
||||
$account->setRLName($rl_name);
|
||||
$account->setLocation($rl_loca);
|
||||
$account->setCountry($rl_country);
|
||||
$account->setCustomField('created', $created);
|
||||
$account->setWebFlags($web_flags);
|
||||
$account->setCustomField('web_lastlogin', $web_lastlogin);
|
||||
|
||||
if (isset($password)) {
|
||||
$config_salt_enabled = $db->hasColumn('accounts', 'salt');
|
||||
if ($config_salt_enabled) {
|
||||
$salt = generateRandomString(10, false, true, true);
|
||||
$password = $salt . $password;
|
||||
$account_logged->setCustomField('salt', $salt);
|
||||
}
|
||||
|
||||
$password = encrypt($password);
|
||||
$account->setPassword($password);
|
||||
|
||||
if ($config_salt_enabled)
|
||||
$account->setCustomField('salt', $salt);
|
||||
}
|
||||
|
||||
$account->save();
|
||||
echo_success('Account saved at: ' . date('G:i'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$search_account = '';
|
||||
if (isset($_REQUEST['search_name']))
|
||||
$search_account = $_REQUEST['search_name'];
|
||||
else if (isset($_REQUEST['search_account']))
|
||||
$search_account = $_REQUEST['search_account'];
|
||||
else if ($id > 0 && isset($account) && $account->isLoaded()) {
|
||||
if(USE_ACCOUNT_NAME) {
|
||||
$search_account = $account->getName();
|
||||
}
|
||||
else {
|
||||
$search_account = $account->getId();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="row">
|
||||
<?php if (isset($account) && $account->isLoaded()) { ?>
|
||||
|
||||
<form action="<?php echo $base . ((isset($id) && $id > 0) ? '&id=' . $id : ''); ?>" method="post"
|
||||
class="form-horizontal">
|
||||
<div class="col-md-8">
|
||||
<div class="box box-primary">
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<?php if(USE_ACCOUNT_NAME): ?>
|
||||
<div class="col-xs-4">
|
||||
<label for="name" class="control-label">Account Name:</label>
|
||||
<input type="text" class="form-control" id="name" name="name"
|
||||
autocomplete="off" style="cursor: auto;"
|
||||
value="<?php echo $account->getName(); ?>"/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-xs-5">
|
||||
<label for="c_pass" class="control-label">Password: (check to change)</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">
|
||||
<input type="checkbox"
|
||||
name="c_pass"
|
||||
id="c_pass"
|
||||
value="false"
|
||||
class="input_control"/>
|
||||
</span>
|
||||
<input type="text" class="form-control" id="pass" name="pass"
|
||||
autocomplete="off" maxlength="20"
|
||||
value=""/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<label for="account_id" class="control-label">Account ID:</label>
|
||||
<input type="text" class="form-control" id="account_id" name="account_id"
|
||||
autocomplete="off" style="cursor: auto;" size="8" maxlength="11" disabled
|
||||
value="<?php echo $account->getId(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php
|
||||
$acc_group = $account->getAccGroupId();
|
||||
if ($hasTypeColumn) {
|
||||
$groups = new OTS_Groups_List();
|
||||
|
||||
$acc_type = array("Normal", "Tutor", "Senior Tutor", "Gamemaster", "God");
|
||||
if ($groups->getHighestId() == 6) {
|
||||
$acc_type = array("Normal", "Tutor", "Senior Tutor", "Gamemaster", "Community Manager", "God");
|
||||
}
|
||||
?>
|
||||
<div class="col-xs-6">
|
||||
<label for="group" class="control-label">Account Type:</label>
|
||||
<select name="group" id="group" class="form-control">
|
||||
<?php foreach ($acc_type as $id => $a_type): ?>
|
||||
<option value="<?php echo($id + 1); ?>" <?php echo($acc_group == ($id + 1) ? 'selected' : ''); ?>><?php echo $a_type; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php
|
||||
} elseif ($hasGroupColumn) {
|
||||
?>
|
||||
<div class="col-xs-6">
|
||||
<label for="group" class="control-label">Account Type:</label>
|
||||
<select name="group" id="group" class="form-control">
|
||||
<?php
|
||||
foreach ($groups->getGroups() as $id => $group): ?>
|
||||
<option value="<?php echo $id; ?>" <?php echo($acc_group == $id ? 'selected' : ''); ?>><?php echo $group->getName(); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="web_flags" class="control-label">Website Access:</label>
|
||||
<select name="web_flags" id="web_flags" class="form-control">
|
||||
<?php $web_acc = array("None", "Admin", "Super Admin", "(Admin + Super Admin)");
|
||||
foreach ($web_acc as $id => $a_type): ?>
|
||||
<option value="<?php echo($id); ?>" <?php echo($account->getWebFlags() == ($id) ? 'selected' : ''); ?>><?php echo $a_type; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php if($hasSecretColumn): ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="secret" class="control-label">Secret:</label>
|
||||
<input type="text" class="form-control" id="secret" name="secret"
|
||||
autocomplete="off" style="cursor: auto;" size="8" maxlength="11"
|
||||
value="<?php echo $account->getCustomField('secret'); ?>"/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="key" class="control-label">Key:</label>
|
||||
<input type="text" class="form-control" id="key" name="key"
|
||||
autocomplete="off" style="cursor: auto;" size="8" maxlength="11"
|
||||
value="<?php echo $account->getCustomField('key'); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="email" class="control-label">Email:</label>
|
||||
<input type="text" class="form-control" id="email" name="email"
|
||||
autocomplete="off" maxlength="20"
|
||||
value="<?php echo $account->getEMail(); ?>"/>
|
||||
</div>
|
||||
<?php if ($hasCoinsColumn): ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="t_coins" class="control-label">Tibia Coins:</label>
|
||||
<input type="text" class="form-control" id="t_coins" name="t_coins"
|
||||
autocomplete="off" maxlength="8"
|
||||
value="<?php echo $account->getCustomField('coins') ?>"/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="p_days" class="control-label">Premium Days:</label>
|
||||
<input type="text" class="form-control" id="p_days" name="p_days"
|
||||
autocomplete="off" maxlength="11"
|
||||
value="<?php echo $account->getPremDays(); ?>"/>
|
||||
</div>
|
||||
<?php if ($hasPointsColumn): ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="p_points" class="control-label">Premium Points:</label>
|
||||
<input type="text" class="form-control" id="p_points" name="p_points"
|
||||
autocomplete="off" maxlength="8"
|
||||
value="<?php echo $account->getCustomField('premium_points') ?>"/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-4">
|
||||
<label for="rl_name" class="control-label">RL Name:</label>
|
||||
<input type="text" class="form-control" id="rl_name" name="rl_name"
|
||||
autocomplete="off" maxlength="20"
|
||||
value="<?php echo $account->getRLName(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<label for="rl_loca" class="control-label">Location:</label>
|
||||
<input type="text" class="form-control" id="rl_loca" name="rl_loca"
|
||||
autocomplete="off" maxlength="20"
|
||||
value="<?php echo $account->getLocation(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<label for="rl_country" class="control-label">Country:</label>
|
||||
<select name="rl_country" id="rl_country" class="form-control">
|
||||
<?php foreach ($countries as $id => $a_type): ?>
|
||||
<option value="<?php echo($id); ?>" <?php echo($account->getCountry() == ($id) ? 'selected' : ''); ?>><?php echo $a_type; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-4">
|
||||
<label for="created" class="control-label">Created:</label>
|
||||
<input type="text" class="form-control" id="created" name="created"
|
||||
autocomplete="off" maxlength="20"
|
||||
value="<?php echo $account->getCustomField('created'); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<label for="web_lastlogin" class="control-label">Web Last Login:</label>
|
||||
<input type="text" class="form-control" id="web_lastlogin" name="web_lastlogin"
|
||||
autocomplete="off" maxlength="20"
|
||||
value="<?php echo $account->getCustomField('web_lastlogin'); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="save" value="yes"/>
|
||||
<div class="box-footer">
|
||||
<a href="<?php echo ADMIN_URL; ?>?p=accounts"><span class="btn btn-danger">Cancel</span></a>
|
||||
<div class="pull-right">
|
||||
<input type="submit" class="btn btn-primary" value="Update">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<div class="col-md-4">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Search Account:</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<form action="<?php echo $base; ?>" method="post">
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control" name="search_name" value="<?php echo $search_account; ?>"
|
||||
maxlength="32" size="32">
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" type="button" class="btn btn-info btn-flat">Search</button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if (isset($account) && $account->isLoaded()) {
|
||||
$account_players = array();
|
||||
$query = $db->query('SELECT `name`,`level`,`vocation` FROM `players` WHERE `account_id` = ' . $account->getId() . ' ORDER BY `name`')->fetchAll();
|
||||
if (isset($query)) {
|
||||
?>
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Character List:</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th style="width: 10px">#</th>
|
||||
<th>Name</th>
|
||||
<th>Level</th>
|
||||
<th style="width: 40px">Edit</th>
|
||||
</tr>
|
||||
<?php
|
||||
$i = 1;
|
||||
foreach ($query as $p) {
|
||||
$account_players[] = $p;
|
||||
echo '<tr>
|
||||
<td>' . $i . '.</td>
|
||||
<td>' . $p['name'] . '</td>
|
||||
<td>' . $p['level'] . '</td>
|
||||
<td><a href="?p=players&search_name=' . $p['name'] . '"><span class="btn btn-success btn-sm edit btn-flat"><i class="fa fa-edit"></i></span></a></span></td>
|
||||
</tr>';
|
||||
$i++;
|
||||
} ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
};
|
||||
};
|
||||
?>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('#lastlogout').datetimepicker({format: 'unixtime'});
|
||||
$('#created').datetimepicker({format: 'unixtime'});
|
||||
$('#web_lastlogin').datetimepicker({format: 'unixtime'});
|
||||
$(document).ready(function () {
|
||||
$('.input_control').change(function () {
|
||||
$('input[name=pass]')[0].disabled = !this.checked;
|
||||
$('input[name=pass]')[0].value = '';
|
||||
}).change();
|
||||
});
|
||||
</script>
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Load items.xml
|
||||
*
|
||||
* @package MyAAC
|
||||
* @author Slawkens <slawkens@gmail.com>
|
||||
* @copyright 2019 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
$title = 'Load items.xml';
|
||||
|
||||
require LIBS . 'items.php';
|
||||
require LIBS . 'weapons.php';
|
||||
|
||||
$twig->display('admin.items.html.twig');
|
||||
|
||||
$reload = isset($_REQUEST['reload']) && (int)$_REQUEST['reload'] === 1;
|
||||
if ($reload) {
|
||||
$items_start_time = microtime(true);
|
||||
if (Items::loadFromXML(true)) {
|
||||
success('Successfully loaded items (in ' . round(microtime(true) - $items_start_time, 4) . ' seconds).');
|
||||
}
|
||||
else {
|
||||
error(Items::getError());
|
||||
}
|
||||
|
||||
$weapons_start_time = microtime(true);
|
||||
if (Weapons::loadFromXML(true)) {
|
||||
success('Successfully loaded weapons (in ' . round(microtime(true) - $weapons_start_time, 4) . ' seconds).');
|
||||
}
|
||||
else {
|
||||
error(Weapons::getError());
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Mailer
|
||||
*
|
||||
* @package MyAAC
|
||||
* @author Slawkens <slawkens@gmail.com>
|
||||
* @copyright 2019 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
$title = 'Mailer';
|
||||
|
||||
if (!hasFlag(FLAG_CONTENT_MAILER) && !superAdmin()) {
|
||||
echo 'Access denied.';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$config['mail_enabled']) {
|
||||
echo 'Mail support disabled.';
|
||||
return;
|
||||
}
|
||||
|
||||
$mail_content = isset($_POST['mail_content']) ? stripslashes($_POST['mail_content']) : NULL;
|
||||
$mail_subject = isset($_POST['mail_subject']) ? stripslashes($_POST['mail_subject']) : NULL;
|
||||
$preview = isset($_REQUEST['preview']);
|
||||
|
||||
$preview_done = false;
|
||||
if ($preview) {
|
||||
if (!empty($mail_content) && !empty($mail_subject)) {
|
||||
$preview_done = _mail($account_logged->getCustomField('email'), $mail_subject, $mail_content);
|
||||
|
||||
if (!$preview_done)
|
||||
error('Error while sending preview mail. More info can be found in system/logs/mailer-error.log');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$twig->display('admin.mailer.html.twig', array(
|
||||
'mail_subject' => $mail_subject,
|
||||
'mail_content' => $mail_content,
|
||||
'preview_done' => $preview_done
|
||||
));
|
||||
|
||||
if (empty($mail_content) || empty($mail_subject) || $preview)
|
||||
return;
|
||||
|
||||
$success = 0;
|
||||
$failed = 0;
|
||||
|
||||
$add = '';
|
||||
if ($config['account_mail_verify']) {
|
||||
note('Note: Sending only to users with verified E-Mail.');
|
||||
$add = ' AND ' . $db->fieldName('email_verified') . ' = 1';
|
||||
}
|
||||
|
||||
$query = $db->query('SELECT ' . $db->fieldName('email') . ' FROM ' . $db->tableName('accounts') . ' WHERE ' . $db->fieldName('email') . ' != ""' . $add);
|
||||
foreach ($query as $email) {
|
||||
if (_mail($email['email'], $mail_subject, $mail_content))
|
||||
$success++;
|
||||
else {
|
||||
$failed++;
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
success('Mailing finished.');
|
||||
success("$success emails delivered.");
|
||||
warning("$failed emails failed.");
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
if ($db->hasColumn('accounts', 'coins')) {
|
||||
$coins = $db->query('SELECT `coins`, `' . (USE_ACCOUNT_NAME ? 'name' : 'id') . '` as `name` FROM `accounts` ORDER BY `coins` DESC LIMIT 10;');
|
||||
} else {
|
||||
$coins = 0;
|
||||
}
|
||||
|
||||
$twig->display('coins.html.twig', array(
|
||||
'coins' => $coins
|
||||
));
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
if ($db->hasColumn('players', 'lastlogin')) {
|
||||
$players = $db->query('SELECT name, level, lastlogin FROM players ORDER BY lastlogin DESC LIMIT 10;');
|
||||
} else {
|
||||
$players = 0;
|
||||
}
|
||||
|
||||
$twig->display('lastlogin.html.twig', array(
|
||||
'players' => $players,
|
||||
));
|
||||
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
if ($db->hasColumn('accounts', 'premium_points')) {
|
||||
$points = $db->query('SELECT `premium_points`, `' . (USE_ACCOUNT_NAME ? 'name' : 'id') . '` as `name` FROM `accounts` ORDER BY `premium_points` DESC LIMIT 10;');
|
||||
} else {
|
||||
$points = 0;
|
||||
}
|
||||
|
||||
$twig->display('points.html.twig', array(
|
||||
'points' => $points,
|
||||
));
|
||||
@@ -1,29 +0,0 @@
|
||||
{% if coins is iterable %}
|
||||
<div class="col-md-3">
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Top 10 - Most coins</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-condensed">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Account {{ account_type }}</th>
|
||||
<th>Tibia coins</th>
|
||||
</tr>
|
||||
{% set i = 0 %}
|
||||
{% for result in coins %}
|
||||
{% set i = i + 1 %}
|
||||
<tr>
|
||||
<td>{{ i }}</td>
|
||||
<td>{{ result.name }}</td>
|
||||
<td>{{ result.coins }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -1,29 +0,0 @@
|
||||
{% if players is iterable %}
|
||||
<div class="col-md-3">
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Last 10 Logins</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-condensed">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Player</th>
|
||||
<th>Login Date</th>
|
||||
</tr>
|
||||
{% set i = 0 %}
|
||||
{% for result in players %}
|
||||
{% set i = i + 1 %}
|
||||
<tr>
|
||||
<td>{{ i }}</td>
|
||||
<td>{{ result.name }}</td>
|
||||
<td>{{ result.lastlogin|date("M d Y, H:i:s") }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -1,29 +0,0 @@
|
||||
{% if points is iterable %}
|
||||
<div class="col-md-3">
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Top 10 - Most premium points</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-condensed">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Account {{ account_type }}</th>
|
||||
<th>Premium points</th>
|
||||
</tr>
|
||||
{% set i = 0 %}
|
||||
{% for result in points %}
|
||||
{% set i = i + 1 %}
|
||||
<tr>
|
||||
<td>{{ i }}</td>
|
||||
<td>{{ result.name }}</td>
|
||||
<td>{{ result.premium_points }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -1,904 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Players editor
|
||||
*
|
||||
* @package MyAAC
|
||||
* @author Slawkens <slawkens@gmail.com>
|
||||
* @copyright 2019 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
$title = 'Player editor';
|
||||
$base = BASE_URL . 'admin/?p=players';
|
||||
|
||||
function echo_success($message)
|
||||
{
|
||||
echo '<p class="success">' . $message . '</p>';
|
||||
}
|
||||
|
||||
function echo_error($message)
|
||||
{
|
||||
global $error;
|
||||
echo '<p class="error">' . $message . '</p>';
|
||||
$error = true;
|
||||
}
|
||||
|
||||
function verify_number($number, $name, $max_length)
|
||||
{
|
||||
if (!Validator::number($number))
|
||||
echo_error($name . ' can contain only numbers.');
|
||||
|
||||
$number_length = strlen($number);
|
||||
if ($number_length <= 0 || $number_length > $max_length)
|
||||
echo_error($name . ' cannot be longer than ' . $max_length . ' digits.');
|
||||
}
|
||||
|
||||
$skills = array(
|
||||
POT::SKILL_FIST => array('Fist fighting', 'fist'),
|
||||
POT::SKILL_CLUB => array('Club fighting', 'club'),
|
||||
POT::SKILL_SWORD => array('Sword fighting', 'sword'),
|
||||
POT::SKILL_AXE => array('Axe fighting', 'axe'),
|
||||
POT::SKILL_DIST => array('Distance fighting', 'dist'),
|
||||
POT::SKILL_SHIELD => array('Shielding', 'shield'),
|
||||
POT::SKILL_FISH => array('Fishing', 'fish')
|
||||
);
|
||||
|
||||
|
||||
$hasBlessingsColumn = $db->hasColumn('players', 'blessings');
|
||||
$hasBlessingColumn = $db->hasColumn('players', 'blessings1');
|
||||
$hasLookAddons = $db->hasColumn('players', 'lookaddons');
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo BASE_URL; ?>tools/css/jquery.datetimepicker.css"/ >
|
||||
<script src="<?php echo BASE_URL; ?>tools/js/jquery.datetimepicker.js"></script>
|
||||
|
||||
<?php
|
||||
$id = 0;
|
||||
if (isset($_REQUEST['id']))
|
||||
$id = (int)$_REQUEST['id'];
|
||||
else if (isset($_REQUEST['search_name'])) {
|
||||
if (strlen($_REQUEST['search_name']) < 3 && !Validator::number($_REQUEST['search_name'])) {
|
||||
echo 'Player name is too short.';
|
||||
} else {
|
||||
if (Validator::number($_REQUEST['search_name']))
|
||||
$id = $_REQUEST['search_name'];
|
||||
else {
|
||||
$query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($_REQUEST['search_name']));
|
||||
if ($query->rowCount() == 1) {
|
||||
$query = $query->fetch();
|
||||
$id = $query['id'];
|
||||
} else {
|
||||
$query = $db->query('SELECT `id`, `name` FROM `players` WHERE `name` LIKE ' . $db->quote('%' . $_REQUEST['search_name'] . '%'));
|
||||
if ($query->rowCount() > 0 && $query->rowCount() <= 10) {
|
||||
echo 'Do you mean?<ul>';
|
||||
foreach ($query as $row)
|
||||
echo '<li><a href="' . $base . '&id=' . $row['id'] . '">' . $row['name'] . '</a></li>';
|
||||
echo '</ul>';
|
||||
} else if ($query->rowCount() > 10)
|
||||
echo 'Specified name resulted with too many players.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$groups = new OTS_Groups_List();
|
||||
if ($id > 0) {
|
||||
$player = new OTS_Player();
|
||||
$player->load($id);
|
||||
|
||||
if (isset($player) && $player->isLoaded() && isset($_POST['save'])) {// we want to save
|
||||
$error = false;
|
||||
|
||||
if ($player->isOnline())
|
||||
echo_error('This player is actually online. You can\'t edit online players.');
|
||||
|
||||
$name = $_POST['name'];
|
||||
$_error = '';
|
||||
if (!Validator::characterName($name))
|
||||
echo_error(Validator::getLastError());
|
||||
|
||||
//if(!Validator::newCharacterName($name)
|
||||
// echo_error(Validator::getLastError());
|
||||
|
||||
$player_db = new OTS_Player();
|
||||
$player_db->find($name);
|
||||
if ($player_db->isLoaded() && $player->getName() != $name)
|
||||
echo_error('This name is already used. Please choose another name!');
|
||||
|
||||
$account_id = $_POST['account_id'];
|
||||
verify_number($account_id, 'Account id', 11);
|
||||
|
||||
$account_db = new OTS_Account();
|
||||
$account_db->load($account_id);
|
||||
if (!$account_db->isLoaded())
|
||||
echo_error('Account with this id doesn\'t exist.');
|
||||
|
||||
$group = $_POST['group'];
|
||||
if ($groups->getGroup($group) == false)
|
||||
echo_error('Group with this id doesn\'t exist');
|
||||
|
||||
$level = $_POST['level'];
|
||||
verify_number($level, 'Level', 11);
|
||||
|
||||
$experience = $_POST['experience'];
|
||||
verify_number($experience, 'Experience', 20);
|
||||
|
||||
$vocation = $_POST['vocation'];
|
||||
verify_number($vocation, 'Vocation id', 11);
|
||||
|
||||
if (!isset($config['vocations'][$vocation])) {
|
||||
echo_error("Vocation with this id doesn't exist.");
|
||||
}
|
||||
|
||||
// health
|
||||
$health = $_POST['health'];
|
||||
verify_number($health, 'Health', 11);
|
||||
$health_max = $_POST['health_max'];
|
||||
verify_number($health_max, 'Health max', 11);
|
||||
|
||||
// mana
|
||||
$magic_level = $_POST['magic_level'];
|
||||
verify_number($magic_level, 'Magic_level', 11);
|
||||
$mana = $_POST['mana'];
|
||||
verify_number($mana, 'Mana', 11);
|
||||
$mana_max = $_POST['mana_max'];
|
||||
verify_number($mana_max, 'Mana max', 11);
|
||||
$mana_spent = $_POST['mana_spent'];
|
||||
verify_number($mana_spent, 'Mana spent', 11);
|
||||
|
||||
// look
|
||||
$look_body = $_POST['look_body'];
|
||||
verify_number($look_body, 'Look body', 11);
|
||||
$look_feet = $_POST['look_feet'];
|
||||
verify_number($look_feet, 'Look feet', 11);
|
||||
$look_head = $_POST['look_head'];
|
||||
verify_number($look_head, 'Look head', 11);
|
||||
$look_legs = $_POST['look_legs'];
|
||||
verify_number($look_legs, 'Look legs', 11);
|
||||
$look_type = $_POST['look_type'];
|
||||
verify_number($look_type, 'Look type', 11);
|
||||
if ($hasLookAddons) {
|
||||
$look_addons = $_POST['look_addons'];
|
||||
verify_number($look_addons, 'Look addons', 11);
|
||||
}
|
||||
|
||||
// pos
|
||||
$pos_x = $_POST['pos_x'];
|
||||
verify_number($pos_x, 'Position x', 11);
|
||||
$pos_y = $_POST['pos_y'];
|
||||
verify_number($pos_y, 'Position y', 11);
|
||||
$pos_z = $_POST['pos_z'];
|
||||
verify_number($pos_z, 'Position z', 11);
|
||||
|
||||
$soul = $_POST['soul'];
|
||||
verify_number($soul, 'Soul', 10);
|
||||
$town = $_POST['town'];
|
||||
verify_number($town, 'Town', 11);
|
||||
|
||||
$capacity = $_POST['capacity'];
|
||||
verify_number($capacity, 'Capacity', 11);
|
||||
$sex = $_POST['sex'];
|
||||
verify_number($sex, 'Sex', 1);
|
||||
|
||||
$lastlogin = $_POST['lastlogin'];
|
||||
verify_number($lastlogin, 'Last login', 20);
|
||||
$lastlogout = $_POST['lastlogout'];
|
||||
verify_number($lastlogout, 'Last logout', 20);
|
||||
|
||||
$skull = $_POST['skull'];
|
||||
verify_number($skull, 'Skull', 1);
|
||||
$skull_time = $_POST['skull_time'];
|
||||
verify_number($skull_time, 'Skull time', 11);
|
||||
|
||||
if ($db->hasColumn('players', 'loss_experience')) {
|
||||
$loss_experience = $_POST['loss_experience'];
|
||||
verify_number($loss_experience, 'Loss experience', 11);
|
||||
$loss_mana = $_POST['loss_mana'];
|
||||
verify_number($loss_mana, 'Loss mana', 11);
|
||||
$loss_skills = $_POST['loss_skills'];
|
||||
verify_number($loss_skills, 'Loss skills', 11);
|
||||
$loss_containers = $_POST['loss_containers'];
|
||||
verify_number($loss_containers, 'Loss loss_containers', 11);
|
||||
$loss_items = $_POST['loss_items'];
|
||||
verify_number($loss_items, 'Loss items', 11);
|
||||
}
|
||||
if ($db->hasColumn('players', 'offlinetraining_time')) {
|
||||
$offlinetraining = $_POST['offlinetraining'];
|
||||
verify_number($offlinetraining, 'Offline Training time', 11);
|
||||
}
|
||||
|
||||
if ($hasBlessingsColumn) {
|
||||
$blessings = $_POST['blessings'];
|
||||
verify_number($blessings, 'Blessings', 2);
|
||||
}
|
||||
|
||||
$balance = $_POST['balance'];
|
||||
verify_number($balance, 'Balance', 20);
|
||||
if ($db->hasColumn('players', 'stamina')) {
|
||||
$stamina = $_POST['stamina'];
|
||||
verify_number($stamina, 'Stamina', 20);
|
||||
}
|
||||
|
||||
$deleted = (isset($_POST['deleted']) && $_POST['deleted'] == 'true');
|
||||
$hidden = (isset($_POST['hidden']) && $_POST['hidden'] == 'true');
|
||||
|
||||
$created = $_POST['created'];
|
||||
verify_number($created, 'Created', 11);
|
||||
|
||||
$comment = isset($_POST['comment']) ? htmlspecialchars(stripslashes(substr($_POST['comment'], 0, 2000))) : NULL;
|
||||
|
||||
foreach ($_POST['skills'] as $skill => $value)
|
||||
verify_number($value, $skills[$skill][0], 10);
|
||||
foreach ($_POST['skills_tries'] as $skill => $value)
|
||||
verify_number($value, $skills[$skill][0] . ' tries', 10);
|
||||
|
||||
if ($hasBlessingColumn) {
|
||||
$bless_count = $_POST['blesscount'];
|
||||
for ($i = 1; $i <= $bless_count; $i++) {
|
||||
$a = 'blessing' . $i;
|
||||
${'blessing' . $i} = (isset($_POST[$a]) && $_POST[$a] == 'true');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
$player->setName($name);
|
||||
$player->setAccount($account_db);
|
||||
$player->setGroup($groups->getGroup($group));
|
||||
$player->setLevel($level);
|
||||
$player->setExperience($experience);
|
||||
$player->setVocation($vocation);
|
||||
$player->setHealth($health);
|
||||
$player->setHealthMax($health_max);
|
||||
$player->setMagLevel($magic_level);
|
||||
$player->setMana($mana);
|
||||
$player->setManaMax($mana_max);
|
||||
$player->setManaSpent($mana_spent);
|
||||
$player->setLookBody($look_body);
|
||||
$player->setLookFeet($look_feet);
|
||||
$player->setLookHead($look_head);
|
||||
$player->setLookLegs($look_legs);
|
||||
$player->setLookType($look_type);
|
||||
if ($hasLookAddons)
|
||||
$player->setLookAddons($look_addons);
|
||||
if ($db->hasColumn('players', 'offlinetraining_time'))
|
||||
$player->setCustomField('offlinetraining_time', $offlinetraining);
|
||||
$player->setPosX($pos_x);
|
||||
$player->setPosY($pos_y);
|
||||
$player->setPosZ($pos_z);
|
||||
$player->setSoul($soul);
|
||||
$player->setTownId($town);
|
||||
$player->setCap($capacity);
|
||||
$player->setSex($sex);
|
||||
$player->setLastLogin($lastlogin);
|
||||
$player->setLastLogout($lastlogout);
|
||||
//$player->setLastIP(ip2long($lastip));
|
||||
$player->setSkull($skull);
|
||||
$player->setSkullTime($skull_time);
|
||||
if ($db->hasColumn('players', 'loss_experience')) {
|
||||
$player->setLossExperience($loss_experience);
|
||||
$player->setLossMana($loss_mana);
|
||||
$player->setLossSkills($loss_skills);
|
||||
$player->setLossContainers($loss_containers);
|
||||
$player->setLossItems($loss_items);
|
||||
}
|
||||
if ($db->hasColumn('players', 'blessings'))
|
||||
$player->setBlessings($blessings);
|
||||
|
||||
if ($hasBlessingColumn) {
|
||||
for ($i = 1; $i <= $bless_count; $i++) {
|
||||
$a = 'blessing' . $i;
|
||||
$player->setCustomField('blessings' . $i, ${'blessing' . $i} ? '1' : '0');
|
||||
}
|
||||
}
|
||||
$player->setBalance($balance);
|
||||
if ($db->hasColumn('players', 'stamina'))
|
||||
$player->setStamina($stamina);
|
||||
if ($db->hasColumn('players', 'deletion'))
|
||||
$player->setCustomField('deletion', $deleted ? '1' : '0');
|
||||
else
|
||||
$player->setCustomField('deleted', $deleted ? '1' : '0');
|
||||
$player->setCustomField('hidden', $hidden ? '1' : '0');
|
||||
$player->setCustomField('created', $created);
|
||||
if (isset($comment))
|
||||
$player->setCustomField('comment', $comment);
|
||||
|
||||
foreach ($_POST['skills'] as $skill => $value) {
|
||||
$player->setSkill($skill, $value);
|
||||
}
|
||||
foreach ($_POST['skills_tries'] as $skill => $value) {
|
||||
$player->setSkillTries($skill, $value);
|
||||
}
|
||||
$player->save();
|
||||
echo_success('Player saved at: ' . date('G:i'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$search_name = '';
|
||||
if (isset($_REQUEST['search_name']))
|
||||
$search_name = $_REQUEST['search_name'];
|
||||
else if ($id > 0 && isset($player) && $player->isLoaded())
|
||||
$search_name = $player->getName();
|
||||
|
||||
?>
|
||||
<div class="row">
|
||||
|
||||
<?php
|
||||
if (isset($player) && $player->isLoaded()) {
|
||||
$account = $player->getAccount();
|
||||
?>
|
||||
|
||||
<form action="<?php echo $base . ((isset($id) && $id > 0) ? '&id=' . $id : ''); ?>" method="post"
|
||||
class="form-horizontal">
|
||||
<div class="col-md-8">
|
||||
<div class="box box-primary">
|
||||
<div class="box-body">
|
||||
<div class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#tab_1" data-toggle="tab" aria-expanded="true">Player</a>
|
||||
</li>
|
||||
<li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false">Stats</a></li>
|
||||
<li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false">Skills</a></li>
|
||||
<li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false">Pos/Look</a></li>
|
||||
<li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false">Misc</a></li>
|
||||
<li class="pull-right"><a
|
||||
href="<?php echo ADMIN_URL; ?>?p=accounts&search_name=<?php echo $account->getId(); ?>"
|
||||
class="text-muted"><i class="fa fa-gear" title="Edit Account"></i></a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="tab_1">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="name" class="control-label">Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name"
|
||||
autocomplete="off" style="cursor: auto;"
|
||||
value="<?php echo $player->getName(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="account_id" class="control-label">Account id:</label>
|
||||
<input type="text" class="form-control" id="account_id" name="account_id"
|
||||
autocomplete="off" style="cursor: auto;" size="8" maxlength="11"
|
||||
value="<?php echo $account->getId(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 ">
|
||||
<label for="group" class="control-label">Group:</label>
|
||||
<select name="group" id="group" class="form-control">
|
||||
<?php foreach ($groups->getGroups() as $id => $group): ?>
|
||||
<option value="<?php echo $id; ?>" <?php echo($player->getGroup()->getId() == $id ? 'selected' : ''); ?>><?php echo $group->getName(); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="vocation" class="control-label">Vocation</label>
|
||||
<select name="vocation" id="vocation" class="form-control">
|
||||
<?php
|
||||
foreach ($config['vocations'] as $id => $name) {
|
||||
echo '<option value=' . $id . ($id == $player->getVocation() ? ' selected' : '') . '>' . $name . '</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="sex" class="control-label">Sex:</label>
|
||||
<select name="sex" id="sex" class="form-control">>
|
||||
<?php foreach ($config['genders'] as $id => $sex): ?>
|
||||
<option value="<?php echo $id; ?>" <?php echo($player->getSex() == $id ? 'selected' : ''); ?>><?php echo strtolower($sex); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="town" class="control-label">Town:</label>
|
||||
<select name="town" id="town" class="form-control">
|
||||
<?php foreach ($config['towns'] as $id => $town): ?>
|
||||
<option value="<?php echo $id; ?>" <?php echo($player->getTownId() == $id ? 'selected' : ''); ?>><?php echo $town; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="skull" class="control-label">Skull:</label>
|
||||
<select name="skull" id="skull" class="form-control">
|
||||
<?php
|
||||
$skull_type = array("None", "Yellow", "Green", "White", "Red", "Black", "Orange");
|
||||
foreach ($skull_type as $id => $s_name) {
|
||||
echo '<option value=' . $id . ($id == $player->getSkull() ? ' selected' : '') . '>' . $s_name . '</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="skull_time" class="control-label">Skull time:</label>
|
||||
<input type="text" class="form-control" id="skull_time" name="skull_time"
|
||||
autocomplete="off" maxlength="11"
|
||||
value="<?php echo $player->getSkullTime(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php if ($hasBlessingColumn):
|
||||
$blesscount = $player->countBlessings();
|
||||
$bless = $player->checkBlessings($blesscount);
|
||||
?>
|
||||
<input type="hidden" name="blesscount" value="<?php echo $blesscount; ?>"/>
|
||||
<div class="col-xs-6">
|
||||
<label for="blessings" class="control-label">Blessings:</label>
|
||||
<div class="checkbox">
|
||||
<?php
|
||||
for ($i = 1; $i <= $blesscount; $i++) {
|
||||
echo '<label><input style="margin-left: -16px;" type="checkbox" name="blessing' . $i . '" id="blessing' . $i . '"
|
||||
value="true" ' . (($bless[$i - 1] == 1) ? ' checked' : '') . '/>' . $i . '</label>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($hasBlessingsColumn): ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="blessings" class="control-label">Blessings:</label>
|
||||
<input type="text" class="form-control" id="blessings" name="blessings"
|
||||
autocomplete="off" maxlength="11"
|
||||
value="<?php echo $player->getBlessings(); ?>"/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="col-xs-6">
|
||||
<label for="balance" class="control-label">Bank Balance:</label>
|
||||
<input type="text" class="form-control" id="balance" name="balance"
|
||||
autocomplete="off" maxlength="20"
|
||||
value="<?php echo $player->getBalance(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="deleted" class="control-label">Deleted:</label>
|
||||
<input type="checkbox" name="deleted" id="deleted"
|
||||
value="true" <?php echo($player->getCustomField($db->hasColumn('players', 'deletion') ? 'deletion' : 'deleted') == '1' ? ' checked' : ''); ?>/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="hidden" class="control-label">Hidden:</label>
|
||||
<input type="checkbox" name="hidden" id="hidden"
|
||||
value="true" <?php echo($player->isHidden() ? ' checked' : ''); ?>/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="tab_2">
|
||||
<div class="row">
|
||||
<div class="col-xs-6 ">
|
||||
<label for="level" class="control-label">Level:</label>
|
||||
|
||||
<input type="text" class="form-control" id="level" name="level"
|
||||
autocomplete="off"
|
||||
style="cursor: auto;" value="<?php echo $player->getLevel(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="magic_level" class="control-label">Magic level:</label>
|
||||
<input type="text" class="form-control" id="magic_level" name="magic_level"
|
||||
autocomplete="off" size="8" maxlength="11" style="cursor: auto;"
|
||||
value="<?php echo $player->getMagLevel(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 ">
|
||||
<label for="experience" class="control-label">Experience:</label>
|
||||
<input type="text" class="form-control" id="experience" name="experience"
|
||||
autocomplete="off"
|
||||
style="cursor: auto;"
|
||||
value="<?php echo $player->getExperience(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="mana_spent" class="control-label">Mana spent:</label>
|
||||
<input type="text" class="form-control" id="mana_spent" name="mana_spent"
|
||||
autocomplete="off"
|
||||
size="3" maxlength="11" style="cursor: auto;"
|
||||
value="<?php echo $player->getManaSpent(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 ">
|
||||
<label for="health" class="control-label">Health:</label>
|
||||
<input type="text" class="form-control" id="health" name="health"
|
||||
autocomplete="off"
|
||||
size="5" maxlength="11" style="cursor: auto;"
|
||||
value="<?php echo $player->getHealth(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="health_max" class="control-label">Health max:</label>
|
||||
<input type="text" class="form-control" id="health_max" name="health_max"
|
||||
autocomplete="off"
|
||||
size="5" maxlength="11" style="cursor: auto;"
|
||||
value="<?php echo $player->getHealthMax(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 ">
|
||||
<label for="mana" class="control-label">Mana:</label>
|
||||
<input type="text" class="form-control" id="mana" name="mana"
|
||||
autocomplete="off" size="3"
|
||||
maxlength="11" style="cursor: auto;"
|
||||
value="<?php echo $player->getMana(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="mana_max" class="control-label">Mana max:</label>
|
||||
<input type="text" class="form-control" id="mana_max" name="mana_max"
|
||||
autocomplete="off"
|
||||
size="3" maxlength="11" style="cursor: auto;"
|
||||
value="<?php echo $player->getManaMax(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="capacity" class="control-label">Capacity:</label>
|
||||
<input type="text" class="form-control" id="capacity" name="capacity"
|
||||
autocomplete="off"
|
||||
size="3" maxlength="11" style="cursor: auto;"
|
||||
value="<?php echo $player->getCap(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6 ">
|
||||
<label for="soul" class="control-label">Soul:</label>
|
||||
<input type="text" class="form-control" id="soul" name="soul"
|
||||
autocomplete="off" size="3"
|
||||
maxlength="10" style="cursor: auto;"
|
||||
value="<?php echo $player->getSoul(); ?>"/>
|
||||
</div>
|
||||
<?php if ($db->hasColumn('players', 'stamina')): ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="stamina" class="control-label">Stamina:</label>
|
||||
<input type="text" class="form-control" id="stamina" name="stamina"
|
||||
autocomplete="off"
|
||||
maxlength="20" style="cursor: auto;"
|
||||
value="<?php echo $player->getStamina(); ?>"/>
|
||||
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($db->hasColumn('players', 'offlinetraining_time')): ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="offlinetraining" class="control-label">Offline Training
|
||||
Time:</label>
|
||||
<input type="text" class="form-control" id="offlinetraining"
|
||||
name="offlinetraining" autocomplete="off"
|
||||
maxlength="11"
|
||||
value="<?php echo $player->getCustomField('offlinetraining_time'); ?>"/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="tab_3">
|
||||
<?php
|
||||
$i = 0;
|
||||
foreach ($skills as $id => $info) {
|
||||
if ($i == 0 || $i++ == 2) {
|
||||
$i = 0;
|
||||
}
|
||||
echo '
|
||||
<div class="row">
|
||||
<div class="col-xs-6 ">
|
||||
<label for="skills[' . $id . ']" class="control-label">' . $info[0] . '</label>
|
||||
<input type="text" class="form-control" id="skills[' . $id . ']" name="skills[' . $id . ']" maxlength="10" autocomplete="off" style="cursor: auto;" value="' . $player->getSkill($id) . '"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="skills_tries[' . $id . ']" class="control-label">' . $info[0] . ' tries</label>
|
||||
<input type="text" class="form-control" id="skills_tries[' . $id . ']" name="skills_tries[' . $id . ']" maxlength="10" autocomplete="off" style="cursor: auto;" value="' . $player->getSkillTries($id) . '"/>
|
||||
</div>
|
||||
</div>';
|
||||
if ($i == 0)
|
||||
echo '';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="tab-pane" id="tab_4">
|
||||
<?php $outfit = $config['outfit_images_url'] . '?id=' . $player->getLookType() . ($hasLookAddons ? '&addons=' . $player->getLookAddons() : '') . '&head=' . $player->getLookHead() . '&body=' . $player->getLookBody() . '&legs=' . $player->getLookLegs() . '&feet=' . $player->getLookFeet(); ?>
|
||||
<div id="imgchar"
|
||||
style="width:64px;height:64px;position:absolute; top:30px; right:30px"><img id="player_outfit"
|
||||
style="margin-left:0;margin-top:0px;width:64px;height:64px;"
|
||||
src="<?php echo $outfit; ?>"
|
||||
alt="player outfit"/></div>
|
||||
<?php ?>
|
||||
<td>Position:</td>
|
||||
<div class="row">
|
||||
<div class="col-xs-4">
|
||||
<label for="pos_x" class="control-label">X:</label>
|
||||
<input type="text" class="form-control" id="pos_x" name="pos_x"
|
||||
autocomplete="off"
|
||||
maxlength="11" style="cursor: auto;"
|
||||
value="<?php echo $player->getPosX(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<label for="pos_y" class="control-label">Y:</label>
|
||||
<input type="text" class="form-control" id="pos_y" name="pos_y"
|
||||
autocomplete="off"
|
||||
maxlength="11" value="<?php echo $player->getPosY(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<label for="pos_z" class="control-label">Z:</label>
|
||||
<input type="text" class="form-control" id="pos_z" name="pos_z"
|
||||
autocomplete="off"
|
||||
maxlength="11" value="<?php echo $player->getPosZ(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<td>Look:</td>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<label for="look_head" class="control-label">Head: <span
|
||||
id="look_head_val"></span></label>
|
||||
<input type="range" min="0" max="132"
|
||||
value="<?php echo $player->getLookHead(); ?>"
|
||||
class="slider form-control" id="look_head" name="look_head">
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<label for="look_body" class="control-label">Body: <span
|
||||
id="look_body_val"></span></label>
|
||||
<input type="range" min="0" max="132"
|
||||
value="<?php echo $player->getLookBody(); ?>"
|
||||
class="slider form-control" id="look_body" name="look_body">
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<label for="look_legs" class="control-label">Legs: <span
|
||||
id="look_legs_val"></span></label>
|
||||
<input type="range" min="0" max="132"
|
||||
value="<?php echo $player->getLookLegs(); ?>"
|
||||
class="slider form-control" id="look_legs" name="look_legs">
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<label for="look_feet" class="control-label">Feet: <span
|
||||
id="look_feet_val"></span></label>
|
||||
<input type="range" min="0" max="132"
|
||||
value="<?php echo $player->getLookFeet(); ?>"
|
||||
class="slider form-control" id="look_feet" name="look_feet">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="look_type" class="control-label">Type:</label>
|
||||
<input type="text" class="form-control" id="look_type" name="look_type"
|
||||
autocomplete="off"
|
||||
maxlength="11" style="cursor: auto;"
|
||||
value="<?php echo $player->getLookType(); ?>"/>
|
||||
</div>
|
||||
<?php if ($hasLookAddons): ?>
|
||||
<div class="col-xs-6">
|
||||
<label for="look_addons" class="control-label">Addons:</label>
|
||||
<input type="text" class="form-control" id="look_addons"
|
||||
name="look_addons" autocomplete="off"
|
||||
maxlength="11" value="<?php echo $player->getLookAddons(); ?>"/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="tab_5">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="created" class="control-label">Created:</label>
|
||||
<input type="text" class="form-control" id="created" name="created"
|
||||
autocomplete="off"
|
||||
maxlength="10"
|
||||
value="<?php echo $player->getCustomField('created'); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="lastlogin" class="control-label">Last login:</label>
|
||||
<input type="text" class="form-control" id="lastlogin" name="lastlogin"
|
||||
autocomplete="off"
|
||||
maxlength="20" value="<?php echo $player->getLastLogin(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="lastlogout" class="control-label">Last logout:</label>
|
||||
<input type="text" class="form-control" id="lastlogout" name="lastlogout"
|
||||
autocomplete="off"
|
||||
maxlength="20" value="<?php echo $player->getLastLogout(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="lastip" class="control-label">Last IP:</label>
|
||||
<input type="text" class="form-control" id="lastip" name="lastip"
|
||||
autocomplete="off"
|
||||
maxlength="10" value="<?php
|
||||
if (strlen($player->getLastIP()) > 11) {
|
||||
echo inet_ntop($player->getLastIP());
|
||||
}
|
||||
else {
|
||||
echo longToIp($player->getLastIP());
|
||||
}
|
||||
?>"
|
||||
readonly/>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($db->hasColumn('players', 'loss_experience')): ?>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="loss_experience" class="control-label">Experience
|
||||
Loss:</label>
|
||||
<input type="text" class="form-control" id="loss_experience"
|
||||
name="loss_experience" autocomplete="off"
|
||||
maxlength="11"
|
||||
value="<?php echo $player->getLossExperience(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="loss_mana" class="control-label">Mana Loss:</label>
|
||||
<input type="text" class="form-control" id="loss_mana"
|
||||
name="loss_mana" autocomplete="off"
|
||||
maxlength="11" value="<?php echo $player->getLossMana(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="loss_skills" class="control-label">Skills Loss:</label>
|
||||
<input type="text" class="form-control" id="loss_skills"
|
||||
name="loss_skills" autocomplete="off"
|
||||
maxlength="11" value="<?php echo $player->getLossSkills(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="loss_containers" class="control-label">Containers
|
||||
Loss:</label>
|
||||
<input type="text" class="form-control" id="loss_containers"
|
||||
name="loss_containers" autocomplete="off"
|
||||
maxlength="11"
|
||||
value="<?php echo $player->getLossContainers(); ?>"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="loss_items" class="control-label">Items Loss:</label>
|
||||
<input type="text" class="form-control" id="loss_items"
|
||||
name="loss_items" autocomplete="off"
|
||||
maxlength="11" value="<?php echo $player->getLossItems(); ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<label for="comment" class="control-label">Comment:</label>
|
||||
<textarea class="form-control" name="comment" rows="10" cols="50"
|
||||
wrap="virtual"><?php echo $player->getCustomField("comment"); ?></textarea>
|
||||
<small>[max.
|
||||
length: 2000 chars, 50 lines (ENTERs)]
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="save" value="yes"/>
|
||||
<div class="box-footer">
|
||||
<a href="<?php echo ADMIN_URL; ?>?p=players"><span class="btn btn-danger">Cancel</span></a>
|
||||
<div class="pull-right">
|
||||
<input type="submit" class="btn btn-primary" value="Update">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php } ?>
|
||||
<div class="col-md-4">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Search Player:</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<form action="<?php echo $base; ?>" method="post">
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control" name="search_name" value="<?php echo $search_name; ?>"
|
||||
maxlength="32" size="32">
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" type="button" class="btn btn-info btn-flat">Search</button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if (isset($account) && $account->isLoaded()) {
|
||||
$account_players = array();
|
||||
$query = $db->query('SELECT `name`,`level`,`vocation` FROM `players` WHERE `account_id` = ' . $account->getId() . ' ORDER BY `name`')->fetchAll();
|
||||
if (isset($query)) {
|
||||
?>
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Character List:</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th style="width: 10px">#</th>
|
||||
<th>Name</th>
|
||||
<th>Level</th>
|
||||
<th style="width: 40px">Edit</th>
|
||||
</tr>
|
||||
<?php
|
||||
$i = 1;
|
||||
foreach ($query as $p) {
|
||||
$account_players[] = $p;
|
||||
echo '<tr>
|
||||
<td>' . $i . '.</td>
|
||||
<td>' . $p['name'] . '</td>
|
||||
<td>' . $p['level'] . '</td>
|
||||
<td><a href="?p=players&search_name=' . $p['name'] . '"><span class="btn btn-success btn-sm edit btn-flat"><i class="fa fa-edit"></i></span></a></span></td>
|
||||
</tr>';
|
||||
$i++;
|
||||
} ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
};
|
||||
};
|
||||
?>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
$('#lastlogin').datetimepicker({
|
||||
format: 'unixtime'
|
||||
});
|
||||
$('#lastlogout').datetimepicker({
|
||||
format: 'unixtime'
|
||||
});
|
||||
$('#created').datetimepicker({
|
||||
format: 'unixtime'
|
||||
});
|
||||
|
||||
var slider_head = document.getElementById("look_head");
|
||||
var output_head = document.getElementById("look_head_val");
|
||||
|
||||
var slider_body = document.getElementById("look_body");
|
||||
var output_body = document.getElementById("look_body_val");
|
||||
|
||||
var slider_legs = document.getElementById("look_legs");
|
||||
var output_legs = document.getElementById("look_legs_val");
|
||||
|
||||
var slider_feet = document.getElementById("look_feet");
|
||||
var output_feet = document.getElementById("look_feet_val");
|
||||
output_head.innerHTML = slider_head.value;
|
||||
output_body.innerHTML = slider_body.value;
|
||||
output_legs.innerHTML = slider_legs.value;
|
||||
output_feet.innerHTML = slider_feet.value;
|
||||
|
||||
slider_head.oninput = function () {
|
||||
output_head.innerHTML = this.value;
|
||||
}
|
||||
slider_body.oninput = function () {
|
||||
output_body.innerHTML = this.value;
|
||||
}
|
||||
slider_legs.oninput = function () {
|
||||
output_legs.innerHTML = this.value;
|
||||
}
|
||||
slider_feet.oninput = function () {
|
||||
output_feet.innerHTML = this.value;
|
||||
}
|
||||
|
||||
$('#look_head').change(function() {updateOutfit()});
|
||||
$('#look_body').change(function() {updateOutfit()});
|
||||
$('#look_legs').change(function() {updateOutfit()});
|
||||
$('#look_feet').change(function() {updateOutfit()});
|
||||
$('#look_type').change(function() {updateOutfit()});
|
||||
<?php if($hasLookAddons): ?>
|
||||
$('#look_addons').change(function() {updateOutfit()});
|
||||
<?php endif; ?>
|
||||
|
||||
function updateOutfit()
|
||||
{
|
||||
var look_head = $('#look_head').val();
|
||||
var look_body = $('#look_body').val();
|
||||
var look_legs = $('#look_legs').val();
|
||||
var look_feet = $('#look_feet').val();
|
||||
var look_type = $('#look_type').val();
|
||||
|
||||
var look_addons = '';
|
||||
<?php if($hasLookAddons): ?>
|
||||
look_addons = '&addons=' + $('#look_addons').val();
|
||||
<?php endif; ?>
|
||||
|
||||
new_outfit = '<?= $config['outfit_images_url']; ?>?id=' + look_type + look_addons + '&head=' + look_head + '&body=' + look_body + '&legs=' + look_legs + '&feet=' + look_feet;
|
||||
$("#player_outfit").attr("src", new_outfit);
|
||||
console.log(new_outfit);
|
||||
}
|
||||
</script>
|
||||
48
admin/template/menus.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
['name' => 'Dashboard', 'icon' => 'tachometer-alt', 'link' => 'dashboard'],
|
||||
['name' => 'News', 'icon' => 'newspaper', 'link' =>
|
||||
[
|
||||
['name' => 'View', 'link' => 'news'],
|
||||
['name' => 'Add news', 'link' => 'news&action=new&type=1'],
|
||||
['name' => 'Add ticker', 'link' => 'news&action=new&type=2'],
|
||||
['name' => 'Add article', 'link' => 'news&action=new&type=3'],
|
||||
],
|
||||
],
|
||||
['name' => 'Changelogs', 'icon' => 'newspaper', 'link' =>
|
||||
[
|
||||
['name' => 'View', 'link' => 'changelog'],
|
||||
['name' => 'Add', 'link' => 'changelog&action=new'],
|
||||
],
|
||||
],
|
||||
['name' => 'Mailer', 'icon' => 'envelope', 'link' => 'mailer', 'disabled' => !config('mail_enabled')],
|
||||
['name' => 'Pages', 'icon' => 'book', 'link' =>
|
||||
[
|
||||
['name' => 'View', 'link' => 'pages'],
|
||||
['name' => 'Add', 'link' => 'pages&action=new'],
|
||||
],
|
||||
],
|
||||
['name' => 'Menus', 'icon' => 'list', 'link' => 'menus'],
|
||||
['name' => 'Plugins', 'icon' => 'plug', 'link' => 'plugins'],
|
||||
['name' => 'Server Data', 'icon' => 'gavel', 'link' => 'data'],
|
||||
['name' => 'Editor', 'icon' => 'edit', 'link' =>
|
||||
[
|
||||
['name' => 'Accounts', 'link' => 'accounts'],
|
||||
['name' => 'Players', 'link' => 'players'],
|
||||
],
|
||||
],
|
||||
['name' => 'Tools', 'icon' => 'tools', 'link' =>
|
||||
[
|
||||
['name' => 'Notepad', 'link' => 'notepad'],
|
||||
['name' => 'phpinfo', 'link' => 'phpinfo'],
|
||||
],
|
||||
],
|
||||
['name' => 'Logs', 'icon' => 'bug', 'link' =>
|
||||
[
|
||||
['name' => 'Logs', 'link' => 'logs'],
|
||||
['name' => 'Reports', 'link' => 'reports'],
|
||||
['name' => 'Visitors', 'icon' => 'user', 'link' => 'visitors'],
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -1,44 +1,10 @@
|
||||
.slidecontainer {
|
||||
width: 100%;
|
||||
.menu-text-li {color: #4b646f; background: #1a2226;}
|
||||
.menu-text {
|
||||
display: block;
|
||||
padding: .5rem 1rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.slider {
|
||||
-webkit-appearance: none;
|
||||
width: 100%;
|
||||
|
||||
outline: none;
|
||||
opacity: 0.7;
|
||||
-webkit-transition: .2s;
|
||||
transition: opacity .2s;
|
||||
}
|
||||
|
||||
.slider:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 15px;
|
||||
height: 25px;
|
||||
background: #3c8dbc;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.slider::-moz-range-thumb {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
background: #3c8dbc;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
td.details-control {
|
||||
text-align: center;
|
||||
color: forestgreen;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
tr.shown td.details-control {
|
||||
text-align: center;
|
||||
color: red;
|
||||
.sidebar-mini.sidebar-collapse .menu-text {
|
||||
display: none;
|
||||
}
|
||||
@@ -1,229 +1,196 @@
|
||||
<?php defined('MYAAC') or die('Direct access not allowed!'); ?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<?php echo template_header(true);
|
||||
$title_full = (isset($title) ? $title . $config['title_separator'] : '') . $config['lua']['serverName'];
|
||||
?>
|
||||
|
||||
<title><?php echo $title_full ?></title>
|
||||
<link rel="shortcut icon" href="<?php echo BASE_URL; ?>images/favicon.ico" type="image/x-icon" />
|
||||
<link rel="icon" href="<?php echo BASE_URL; ?>images/favicon.ico" type="image/x-icon" />
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
|
||||
<link rel="stylesheet" href="<?php echo BASE_URL; ?>tools/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="<?php echo BASE_URL; ?>tools/css/AdminLTE.min.css">
|
||||
<link rel="stylesheet" href="<?php echo BASE_URL; ?>tools/css/skins/skin-blue.min.css">
|
||||
<?php echo template_header(true); ?>
|
||||
<title><?php echo (isset($title) ? $title . ' - ' : '') . $config['lua']['serverName'];?></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="<?php echo BASE_URL; ?>tools/css/adminlte.min.css">
|
||||
<link rel="stylesheet" href="<?php echo BASE_URL; ?>tools/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="<?php echo BASE_URL; ?>tools/css/ionicons.min.css">
|
||||
<link rel="stylesheet" href="<?php echo BASE_URL; ?>tools/css/jquery.dataTables.min.css">
|
||||
<?php if (isset($use_datatable)) { ?>
|
||||
<link rel="stylesheet" href="<?php echo BASE_URL; ?>tools/css/datatables.bs.min.css">
|
||||
<?php } ?>
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo $template_path; ?>style.css"/>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<script src="<?php echo BASE_URL; ?>tools/js/html5shiv.min.js"></script>
|
||||
<script src="<?php echo BASE_URL; ?>tools/js/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
<link rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
|
||||
</head>
|
||||
<body class="hold-transition skin-blue sidebar-mini">
|
||||
<div class="wrapper">
|
||||
<?php
|
||||
if ($logged && admin()) {
|
||||
?>
|
||||
<header class="main-header">
|
||||
<a href="." class="logo">
|
||||
<span class="logo-mini"><b>M</b>A</span>
|
||||
<span class="logo-lg"><b>My</b>AAC</span>
|
||||
</a>
|
||||
|
||||
<nav class="navbar navbar-static-top" role="navigation">
|
||||
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
<li>
|
||||
<a href="#" data-toggle="control-sidebar"><i class="fa fa-gears"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<body class="sidebar-mini ">
|
||||
<?php if ($logged && admin()) { ?>
|
||||
<div class="wrapper">
|
||||
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-widget="pushmenu" href="#"><i class="fas fa-bars"></i></a>
|
||||
</li>
|
||||
<li class="nav-item d-none d-sm-inline-block">
|
||||
<a href="<?php echo ADMIN_URL; ?>" class="nav-link">Home</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-widget="control-sidebar" data-slide="true" href="#"><i class="fas fa-th-large"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<aside class="main-sidebar">
|
||||
<section class="sidebar">
|
||||
<ul class="sidebar-menu" data-widget="tree">
|
||||
<li class="header">MyAAC</li>
|
||||
<aside class="main-sidebar sidebar-dark-info elevation-4">
|
||||
<a href="<?php echo ADMIN_URL; ?>" class="brand-link navbar-info">
|
||||
<img src="<?php echo ADMIN_URL; ?>images/logo.png" class="brand-image img-circle elevation-3" style="opacity: .8">
|
||||
<span class="brand-text"><b>My</b>AAC</span>
|
||||
</a>
|
||||
<div class="sidebar">
|
||||
<nav class="mt-1">
|
||||
<ul class="nav nav-pills nav-sidebar flex-column nav-legacy nav-child-indent" data-widget="treeview" data-accordion="false">
|
||||
<li class="menu-text-li">
|
||||
<span class="menu-text">
|
||||
<a class="text-info" href="<?php echo BASE_URL; ?>" target="_blank">
|
||||
<?php echo $config['lua']['serverName'] ?>
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<?php
|
||||
// name = Display name of link
|
||||
// icon = fontawesome icon name without "fas fa-"
|
||||
// link = Page link or use as array for sub items
|
||||
$menus = require __DIR__ . '/menus.php';
|
||||
|
||||
<?php
|
||||
$icons_a = array(
|
||||
'dashboard','newspaper-o', 'envelope',
|
||||
'book', 'list',
|
||||
'plug', 'user',
|
||||
'edit', 'gavel',
|
||||
'wrench', 'edit', 'book', 'book',
|
||||
);
|
||||
|
||||
$menus = array(
|
||||
'Dashboard' => 'dashboard',
|
||||
'News' => 'news',
|
||||
'Mailer' => 'mailer',
|
||||
'Pages' => 'pages',
|
||||
'Menus' => 'menus',
|
||||
'Plugins' => 'plugins',
|
||||
'Visitors' => 'visitors',
|
||||
'Editor' => array(
|
||||
'Accounts' => 'accounts',
|
||||
'Players' => 'players',
|
||||
),
|
||||
'Items' => 'items',
|
||||
'Tools' => array(
|
||||
'Notepad' => 'notepad',
|
||||
'phpinfo' => 'phpinfo',
|
||||
),
|
||||
'Logs' => array(
|
||||
'Logs' => 'logs',
|
||||
'Reports' => 'reports',
|
||||
),
|
||||
);
|
||||
|
||||
$i = 0;
|
||||
foreach ($menus as $_name => $_page) {
|
||||
$has_child = is_array($_page);
|
||||
if (!$has_child) {
|
||||
echo '<li ';
|
||||
if ($page == $_page) echo ' class="active"';
|
||||
echo ">";
|
||||
echo '<a href="?p=' . $_page . '"><i class="fa fa-' . (isset($icons_a[$i]) ? $icons_a[$i] : 'link') . '"></i> <span>' . $_name . '</span></a></li>';
|
||||
}
|
||||
|
||||
if ($has_child) {
|
||||
$used_menu = "";
|
||||
$nav_construct = '';
|
||||
foreach ($_page as $__name => $__page) {
|
||||
$nav_construct = $nav_construct . '<li';
|
||||
|
||||
if ($page == $__page) {
|
||||
$nav_construct = $nav_construct . ' class="active"';
|
||||
$used_menu = true;
|
||||
foreach ($menus as $category => $menu) {
|
||||
if (isset($menu['disabled']) && $menu['disabled']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$has_child = is_array($menu['link']);
|
||||
if (!$has_child) { ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link<?php echo(strpos($menu['link'], $page) !== false ? ' active' : '') ?>" href="?p=<?php echo $menu['link'] ?>">
|
||||
<i class="nav-icon fas fa-<?php echo(isset($menu['icon']) ? $menu['icon'] : 'link') ?>"></i>
|
||||
<p><?php echo $menu['name'] ?></p>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
} else if ($has_child) {
|
||||
$used_menu = null;
|
||||
$nav_construct = '';
|
||||
foreach ($menu['link'] as $category => $sub_menu) {
|
||||
$nav_construct .= '<li class="nav-item"><a href="?p=' . $sub_menu['link'] . '" class="nav-link';
|
||||
if ($page == $sub_menu['link']) {
|
||||
$nav_construct .= ' active';
|
||||
$used_menu = true;
|
||||
}
|
||||
$nav_construct .= '"><i class="far fa-' . (isset($sub_menu['icon']) ? $sub_menu['icon'] : 'circle') . ' nav-icon"></i><p>' . $sub_menu['name'] . '</p></a></li>';
|
||||
}
|
||||
?>
|
||||
<li class="nav-item has-treeview<?php echo($used_menu ? ' menu-open' : '') ?>">
|
||||
<a href="#" class="nav-link<?php echo($used_menu ? ' active' : '') ?>">
|
||||
<i class="nav-icon fas fa-<?php echo(isset($menu['icon']) ? $menu['icon'] : 'link') ?>"></i>
|
||||
<p><?php echo $menu['name'] ?></p><i class="right fas fa-angle-left"></i>
|
||||
</a>
|
||||
<ul class="nav nav-treeview">
|
||||
<?php echo $nav_construct; ?>
|
||||
</ul>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
$nav_construct = $nav_construct . '><a href="?p=' . $__page . '"><i class="fa fa-circle-o"></i> ' . $__name . '</a></li>';
|
||||
}
|
||||
|
||||
echo '<li class="treeview' . (($used_menu) ? ' menu-open' : '') . '">
|
||||
<a href="#"><i class="fa fa-' . (isset($icons_a[$i]) ? $icons_a[$i] : 'link') . '"></i> <span>' . $_name . '</span>
|
||||
<span class="pull-right-container"><i class="fa fa-angle-left pull-right"></i></span></a>
|
||||
<ul class="treeview-menu" style="' . (($used_menu) ? ' display: block' : ' display: none') . '">';
|
||||
echo $nav_construct;
|
||||
echo '</ul>
|
||||
</li>';
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$query = $db->query('SELECT `name`, `page`, `flags` FROM `' . TABLE_PREFIX . 'admin_menu` ORDER BY `ordering`');
|
||||
$menu_db = $query->fetchAll();
|
||||
foreach ($menu_db as $item) {
|
||||
if ($item['flags'] == 0 || hasFlag($item['flags'])) { ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link<?php echo($page == $item['page'] ? ' active' : '') ?>" href="?p=<?php echo $item['page'] ?>">
|
||||
<i class="nav-icon fas fa-link"></i>
|
||||
<p><?php echo $item['name'] ?></p>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
$query = $db->query('SELECT `name`, `page`, `flags` FROM `' . TABLE_PREFIX . 'admin_menu` ORDER BY `ordering`');
|
||||
$menu_db = $query->fetchAll();
|
||||
foreach ($menu_db as $item) {
|
||||
if ($item['flags'] == 0 || hasFlag($item['flags'])) {
|
||||
echo '<li ';
|
||||
if ($page == $item['page']) echo ' class="active"';
|
||||
echo ">";
|
||||
echo '<a href="?p=' . $item['page'] . '"><i class="fa fa-link"></i> <span>' . $item['name'] . '</span></a></li>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<section class="content-header">
|
||||
<h1><?php echo(isset($title) ? $title : ''); ?>
|
||||
<small> - Admin Panel</small>
|
||||
<div class="pull-right">
|
||||
<span class="label label-<?php echo(($status['online']) ? 'success' : 'danger'); ?>"><?php echo $config['lua']['serverName'] ?></span>
|
||||
<div class="content-wrapper" style="min-height: 823px;">
|
||||
<div class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h3 class="m-0 text-dark"><?php echo(isset($title) ? $title : ''); ?><small> - Admin Panel</small></h3>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="float-sm-right d-none d-sm-inline">
|
||||
<span class="p-2 right badge badge-<?php echo((isset($status['online']) and $status['online']) ? 'success' : 'danger'); ?>"><?php echo $config['lua']['serverName'] ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h1>
|
||||
</section>
|
||||
<section class="content">
|
||||
<?php echo $content; ?>
|
||||
</section>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<?php echo $content; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="control-sidebar control-sidebar-dark">
|
||||
<div class="p-3">
|
||||
<h4>Account:</h4>
|
||||
<p><h5><a href="?action=logout"><i class="fas fa-sign-out-alt text-danger"></i> Log out</h5></a>
|
||||
<small>This will log you out</small></p>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<h4>Site:</h4>
|
||||
<p><h5><a href="<?php echo BASE_URL; ?>" target="_blank"><i class="far fa-eye text-blue"></i> Preview</a></h5>
|
||||
<small>This will open a new tab</small></p>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<h4>Version:</h4>
|
||||
<p><h5><a href="?p=version"><i class="fas fa-code-branch"></i> <?php echo MYAAC_VERSION; ?></a></h5>
|
||||
<small>Check for updates</small></p>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<h4>Site:</h4>
|
||||
<p><h5><a href="https://github.com/slawkens/myaac" target="_blank"><i class="fab fa-github"></i> Github</a></h5>
|
||||
<small>Goto GitHub Page</small></p>
|
||||
|
||||
<p><h5><a href="http://my-aac.org/" target="_blank"><i class="fas fa-shoe-prints"></i> MyAAC Official</a></h5>
|
||||
<small>Goto MyAAC Official Website</small></p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<footer class="main-footer">
|
||||
<div class="float-sm-right d-none d-sm-inline">
|
||||
<span class="p-2 right badge badge-<?php echo((isset($status['online']) and $status['online']) ? 'success' : 'danger'); ?>"><?php echo $config['lua']['serverName'] ?></span>
|
||||
</div>
|
||||
<?php echo base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4='); ?>
|
||||
</footer>
|
||||
<div id="sidebar-overlay"></div>
|
||||
</div>
|
||||
|
||||
<footer class="main-footer">
|
||||
|
||||
<div class="pull-right hidden-xs">
|
||||
<div id="status">
|
||||
<?php if ($status['online']): ?>
|
||||
<p class="success" style="width: 120px; text-align: center;">Server Online</p>
|
||||
<?php else: ?>
|
||||
<p class="error" style="width: 120px; text-align: center;">Server Offline</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4='); ?>
|
||||
</footer>
|
||||
|
||||
<aside class="control-sidebar control-sidebar-dark">
|
||||
<ul class="nav nav-tabs nav-justified control-sidebar-tabs">
|
||||
<li class="active"><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li>
|
||||
<li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="control-sidebar-home-tab">
|
||||
<h3 class="control-sidebar-heading">Account</h3>
|
||||
<ul class="control-sidebar-menu">
|
||||
<li>
|
||||
<a href="?action=logout">
|
||||
<i class="menu-icon fa fa-sign-out bg-red"></i>
|
||||
<div class="menu-info">
|
||||
<h4 class="control-sidebar-subheading">Log out</h4>
|
||||
<p>This will log you out
|
||||
of <?php echo(USE_ACCOUNT_NAME ? $account_logged->getName() : $account_logged->getId()); ?></p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 class="control-sidebar-heading">Site</h3>
|
||||
<ul class="control-sidebar-menu">
|
||||
<li>
|
||||
<a href="<?php echo BASE_URL; ?>" target="_blank">
|
||||
<i class="menu-icon fa fa-eye bg-blue"></i>
|
||||
<div class="menu-info">
|
||||
<h4 class="control-sidebar-subheading">Preview</h4>
|
||||
<p>This will open a new tab</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-pane" id="control-sidebar-settings-tab">
|
||||
<form method="post">
|
||||
<h3 class="control-sidebar-heading">Version</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-sidebar-subheading">
|
||||
<?php echo MYAAC_VERSION; ?> (<a href="?p=version">Check for updates</a>)<br/>
|
||||
</label>
|
||||
<label class="control-sidebar-subheading">
|
||||
<p><a href="https://github.com/slawkens/myaac" target="_blank">Github</a></p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="control-sidebar-bg"></div>
|
||||
</div>
|
||||
|
||||
<?php }
|
||||
if (!$logged && !admin()) {
|
||||
<?php } else if (!$logged && !admin()) {
|
||||
echo $content;
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @var OTS_Account $account_logged
|
||||
*/
|
||||
if ($logged && admin()) {
|
||||
$twig->display('admin-bar.html.twig', [
|
||||
'username' => USE_ACCOUNT_NAME ? $account_logged->getName() : $account_logged->getId()
|
||||
]);
|
||||
}
|
||||
?>
|
||||
<script src="<?php echo BASE_URL; ?>tools/js/bootstrap.min.js"></script>
|
||||
<script src="<?php echo BASE_URL; ?>tools/js/jquery-ui.min.js"></script>
|
||||
<script src="<?php echo BASE_URL; ?>tools/js/jquery.dataTables.min.js"></script>
|
||||
<?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.bs.min.js"></script>
|
||||
<?php } ?>
|
||||
<script src="<?php echo BASE_URL; ?>tools/js/adminlte.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -13,3 +13,4 @@ if(!function_exists('phpinfo'))
|
||||
die('phpinfo() disabled on this web server.');
|
||||
|
||||
phpinfo();
|
||||
?>
|
||||
|
||||
46
admin/tools/reload_data.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?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
|
||||
*/
|
||||
define('MYAAC_ADMIN', true);
|
||||
|
||||
require '../../common.php';
|
||||
require SYSTEM . 'functions.php';
|
||||
require SYSTEM . 'init.php';
|
||||
require SYSTEM . 'login.php';
|
||||
|
||||
if (!admin())
|
||||
die('Access denied.');
|
||||
|
||||
ini_set('max_execution_time', 300);
|
||||
ob_implicit_flush();
|
||||
ob_end_flush();
|
||||
header('X-Accel-Buffering: no');
|
||||
|
||||
require LIBS . 'DataLoader.php';
|
||||
|
||||
require LOCALE . 'en/main.php';
|
||||
require LOCALE . 'en/install.php';
|
||||
|
||||
DataLoader::setLocale($locale);
|
||||
DataLoader::load();
|
||||
114
common.php
@@ -23,72 +23,74 @@
|
||||
* @copyright 2019 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
if (version_compare(phpversion(), '7.2.5', '<')) die('PHP version 7.2.5 or higher is required.');
|
||||
if (version_compare(phpversion(), '7.1', '<')) die('PHP version 7.1 or higher is required.');
|
||||
|
||||
define('MYAAC', true);
|
||||
define('MYAAC_VERSION', '0.8.12');
|
||||
define('DATABASE_VERSION', 33);
|
||||
define('TABLE_PREFIX', 'myaac_');
|
||||
const MYAAC = true;
|
||||
const MYAAC_VERSION = '0.9.0-dev';
|
||||
const DATABASE_VERSION = 33;
|
||||
const TABLE_PREFIX = 'myaac_';
|
||||
define('START_TIME', microtime(true));
|
||||
define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX'));
|
||||
define('IS_CLI', in_array(php_sapi_name(), ['cli', 'phpdb']));
|
||||
|
||||
// account flags
|
||||
define('FLAG_ADMIN', 1);
|
||||
define('FLAG_SUPER_ADMIN', 2);
|
||||
define('FLAG_CONTENT_PAGES', 4);
|
||||
define('FLAG_CONTENT_MAILER', 8);
|
||||
define('FLAG_CONTENT_NEWS', 16);
|
||||
define('FLAG_CONTENT_FORUM', 32);
|
||||
define('FLAG_CONTENT_COMMANDS', 64);
|
||||
define('FLAG_CONTENT_SPELLS', 128);
|
||||
define('FLAG_CONTENT_MONSTERS', 256);
|
||||
define('FLAG_CONTENT_GALLERY', 512);
|
||||
define('FLAG_CONTENT_VIDEOS', 1024);
|
||||
define('FLAG_CONTENT_FAQ', 2048);
|
||||
define('FLAG_CONTENT_MENUS', 4096);
|
||||
define('FLAG_CONTENT_PLAYERS', 8192);
|
||||
const FLAG_ADMIN = 1;
|
||||
const FLAG_SUPER_ADMIN = 2;
|
||||
const FLAG_CONTENT_PAGES = 4;
|
||||
const FLAG_CONTENT_MAILER = 8;
|
||||
const FLAG_CONTENT_NEWS = 16;
|
||||
const FLAG_CONTENT_FORUM = 32;
|
||||
const FLAG_CONTENT_COMMANDS = 64;
|
||||
const FLAG_CONTENT_SPELLS = 128;
|
||||
const FLAG_CONTENT_MONSTERS = 256;
|
||||
const FLAG_CONTENT_GALLERY = 512;
|
||||
const FLAG_CONTENT_VIDEOS = 1024;
|
||||
const FLAG_CONTENT_FAQ = 2048;
|
||||
const FLAG_CONTENT_MENUS = 4096;
|
||||
const FLAG_CONTENT_PLAYERS = 8192;
|
||||
|
||||
// news
|
||||
define('NEWS', 1);
|
||||
define('TICKER', 2);
|
||||
define('ARTICLE', 3);
|
||||
const NEWS = 1;
|
||||
const TICKER = 2;
|
||||
const ARTICLE = 3;
|
||||
|
||||
// directories
|
||||
define('BASE', __DIR__ . '/');
|
||||
define('ADMIN', BASE . 'admin/');
|
||||
define('SYSTEM', BASE . 'system/');
|
||||
define('CACHE', SYSTEM . 'cache/');
|
||||
define('LOCALE', SYSTEM . 'locale/');
|
||||
define('LIBS', SYSTEM . 'libs/');
|
||||
define('LOGS', SYSTEM . 'logs/');
|
||||
define('PAGES', SYSTEM . 'pages/');
|
||||
define('PLUGINS', BASE . 'plugins/');
|
||||
define('TEMPLATES', BASE . 'templates/');
|
||||
define('TOOLS', BASE . 'tools/');
|
||||
const BASE = __DIR__ . '/';
|
||||
const ADMIN = BASE . 'admin/';
|
||||
const SYSTEM = BASE . 'system/';
|
||||
const CACHE = SYSTEM . 'cache/';
|
||||
const LOCALE = SYSTEM . 'locale/';
|
||||
const LIBS = SYSTEM . 'libs/';
|
||||
const LOGS = SYSTEM . 'logs/';
|
||||
const PAGES = SYSTEM . 'pages/';
|
||||
const PLUGINS = BASE . 'plugins/';
|
||||
const TEMPLATES = BASE . 'templates/';
|
||||
const TOOLS = BASE . 'tools/';
|
||||
const VENDOR = BASE . 'vendor/';
|
||||
|
||||
// menu categories
|
||||
define('MENU_CATEGORY_NEWS', 1);
|
||||
define('MENU_CATEGORY_ACCOUNT', 2);
|
||||
define('MENU_CATEGORY_COMMUNITY', 3);
|
||||
define('MENU_CATEGORY_FORUM', 4);
|
||||
define('MENU_CATEGORY_LIBRARY', 5);
|
||||
define('MENU_CATEGORY_SHOP', 6);
|
||||
const MENU_CATEGORY_NEWS = 1;
|
||||
const MENU_CATEGORY_ACCOUNT = 2;
|
||||
const MENU_CATEGORY_COMMUNITY = 3;
|
||||
const MENU_CATEGORY_FORUM = 4;
|
||||
const MENU_CATEGORY_LIBRARY = 5;
|
||||
const MENU_CATEGORY_SHOP = 6;
|
||||
|
||||
// otserv versions
|
||||
define('OTSERV', 1);
|
||||
define('OTSERV_06', 2);
|
||||
define('OTSERV_FIRST', OTSERV);
|
||||
define('OTSERV_LAST', OTSERV_06);
|
||||
define('TFS_02', 3);
|
||||
define('TFS_03', 4);
|
||||
define('TFS_FIRST', TFS_02);
|
||||
define('TFS_LAST', TFS_03);
|
||||
const OTSERV = 1;
|
||||
const OTSERV_06 = 2;
|
||||
const OTSERV_FIRST = OTSERV;
|
||||
const OTSERV_LAST = OTSERV_06;
|
||||
const TFS_02 = 3;
|
||||
const TFS_03 = 4;
|
||||
const TFS_FIRST = TFS_02;
|
||||
const TFS_LAST = TFS_03;
|
||||
|
||||
if (!IS_CLI) {
|
||||
session_save_path(SYSTEM . 'php_sessions');
|
||||
session_start();
|
||||
}
|
||||
// other definitions
|
||||
const ACCOUNT_NUMBER_LENGTH = 10;
|
||||
|
||||
session_save_path(SYSTEM . 'php_sessions');
|
||||
session_start();
|
||||
|
||||
// basedir
|
||||
$basedir = '';
|
||||
@@ -97,7 +99,7 @@ $size = count($tmp) - 1;
|
||||
for($i = 1; $i < $size; $i++)
|
||||
$basedir .= '/' . $tmp[$i];
|
||||
|
||||
$basedir = str_replace(array('/admin', '/install', '/tools'), '', $basedir);
|
||||
$basedir = str_replace(array('/admin', '/install'), '', $basedir);
|
||||
define('BASE_DIR', $basedir);
|
||||
|
||||
if(!IS_CLI) {
|
||||
@@ -119,4 +121,10 @@ if(!IS_CLI) {
|
||||
|
||||
require SYSTEM . 'exception.php';
|
||||
}
|
||||
require SYSTEM . 'autoload.php';
|
||||
|
||||
$autoloadFile = VENDOR . 'autoload.php';
|
||||
if (!is_file($autoloadFile)) {
|
||||
throw new RuntimeException('The vendor folder is missing. Please download Composer: <a href="https://getcomposer.org/download">https://getcomposer.org/download</a>, install it and execute in the main MyAAC directory this command: <b>composer install</b>. Or download MyAAC from <a href="https://github.com/slawkens/myaac/releases">GitHub releases</a>, which includes Vendor folder.');
|
||||
}
|
||||
|
||||
require $autoloadFile;
|
||||
|
||||
14
composer.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"ext-pdo": "*",
|
||||
"ext-pdo_mysql": "*",
|
||||
"ext-json": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-dom": "*",
|
||||
"phpmailer/phpmailer": "^6.1",
|
||||
"composer/semver": "^3.2",
|
||||
"twig/twig": "^1.0",
|
||||
"erusev/parsedown": "^1.7"
|
||||
}
|
||||
}
|
||||
60
config.php
@@ -52,7 +52,6 @@ $config = array(
|
||||
// head options (html)
|
||||
'meta_description' => 'Tibia is a free massive multiplayer online role playing game (MMORPG).', // description of the site
|
||||
'meta_keywords' => 'free online game, free multiplayer game, ots, open tibia server', // keywords list separated by commas
|
||||
'title_separator' => ' - ',
|
||||
|
||||
// footer
|
||||
'footer' => ''/*'<br/>Your Server © 2016. All rights reserved.'*/,
|
||||
@@ -87,21 +86,26 @@ $config = array(
|
||||
|
||||
// images
|
||||
'outfit_images_url' => 'https://outfit-images.ots.me/outfit.php', // set to animoutfit.php for animated outfit
|
||||
'outfit_images_wrong_looktypes' => [75, 126, 127, 266, 302], // this looktypes needs to have different margin-top and margin-left because they are wrong positioned
|
||||
'item_images_url' => 'https://item-images.ots.me/1092/', // set to images/items if you host your own items in images folder
|
||||
'item_images_extension' => '.gif',
|
||||
|
||||
// creatures
|
||||
'creatures_images_url' => 'images/monsters/', // set to images/monsters if you host your own creatures in images folder
|
||||
'creatures_images_extension' => '.gif',
|
||||
'creatures_images_preview' => false, // set to true to allow picture previews for creatures
|
||||
'creatures_items_url' => 'https://tibia.fandom.com/wiki/', // set to website which shows details about items.
|
||||
'creatures_loot_percentage' => true, // set to true to show the loot tooltip percent
|
||||
|
||||
// account
|
||||
'account_management' => true, // disable if you're using other method to manage users (fe. tfs account manager)
|
||||
'account_login_by_email' => false, // use email instead of Account Name like in latest Tibia
|
||||
'account_login_by_email_fallback' => false, // allow also additionally login by Account Name/Number (for users that might forget their email)
|
||||
'account_create_auto_login' => false, // auto login after creating account?
|
||||
'account_create_character_create' => true, // allow directly to create character on create account page?
|
||||
'account_mail_verify' => false, // force users to confirm their email addresses when registering
|
||||
'account_mail_confirmed_reward' => [ // reward users for confirming their E-Mails
|
||||
// account_mail_verify needs to be enabled too
|
||||
'premium_days' => 0,
|
||||
'premium_points' => 0,
|
||||
'coins' => 0,
|
||||
'message' => 'You received %d %s for confirming your E-Mail address.' // example: You received 20 premium points for confirming your E-Mail address.
|
||||
],
|
||||
'account_mail_verify' => false, // force users to confirm their email addresses when registering account
|
||||
'account_mail_unique' => true, // email addresses cannot be duplicated? (one account = one email)
|
||||
'account_mail_block_plus_sign' => true, // block email with '+' signs like test+box@gmail.com (help protect against spamming accounts)
|
||||
'account_premium_days' => 0, // default premium days on new account
|
||||
'account_premium_points' => 0, // default premium points on new account
|
||||
'account_welcome_mail' => true, // send welcome email when user registers
|
||||
@@ -131,11 +135,17 @@ $config = array(
|
||||
'smtp_secure' => '', // What kind of encryption to use on the SMTP connection. Options: '', 'ssl' (GMail) or 'tls' (Microsoft Outlook)
|
||||
'smtp_debug' => false, // set true to debug (you will see more info in error.log)
|
||||
|
||||
// reCAPTCHA (prevent spam bots)
|
||||
// Google reCAPTCHA (prevent spam bots)
|
||||
'recaptcha_enabled' => false, // enable recaptcha verification code
|
||||
'recaptcha_type' => 'v3', // 'v2-checkbox', 'v2-invisible', 'v3'
|
||||
'recaptcha_site_key' => '', // get your own site and secret keys at https://www.google.com/recaptcha
|
||||
'recaptcha_secret_key' => '',
|
||||
'recaptcha_theme' => 'light', // light, dark
|
||||
// following option apply only for ReCaptcha v2-checkbox
|
||||
'recaptcha_v2_theme' => 'light', // light, dark
|
||||
// following option apply only for ReCaptcha v3
|
||||
// min score for validation, between 0 - 1.0
|
||||
// https://developers.google.com/recaptcha/docs/v3#interpreting_the_score
|
||||
'recaptcha_v3_min_score' => 0.5,
|
||||
|
||||
//
|
||||
'generate_new_reckey' => true, // let player generate new recovery key, he will receive e-mail with new rec key (not display on page, hacker can't generate rec key)
|
||||
@@ -171,9 +181,12 @@ $config = array(
|
||||
// This is the minimum and the maximum length that a player can create a character. It is highly recommend the maximum length to be 21.
|
||||
'character_name_min_length' => 4,
|
||||
'character_name_max_length' => 21,
|
||||
'character_name_npc_check' => true,
|
||||
|
||||
// list of towns
|
||||
// if you use TFS 1.3 with support for 'towns' table in database, then you can ignore this - it will be configured automatically (generated from your .OTBM map)
|
||||
// if you use TFS 1.3 with support for 'towns' table in database, then you can ignore this - it will be configured automatically (from MySQL database - Table - towns)
|
||||
// otherwise it will try to load from your .OTBM map file
|
||||
// if you don't see towns on website, then you need to fill this out
|
||||
'towns' => array(
|
||||
0 => 'No town',
|
||||
1 => 'Sample town'
|
||||
@@ -184,6 +197,7 @@ $config = array(
|
||||
'guild_need_level' => 1, // min. level to form a guild
|
||||
'guild_need_premium' => true, // require premium account to form a guild?
|
||||
'guild_image_size_kb' => 80, // maximum size of the guild logo image in KB (kilobytes)
|
||||
'guild_description_default' => 'New guild. Leader must edit this text :)',
|
||||
'guild_description_chars_limit' => 1000, // limit of guild description
|
||||
'guild_description_lines_limit' => 6, // limit of lines, if description has more lines it will be showed as long text, without 'enters'
|
||||
'guild_motd_chars_limit' => 150, // limit of MOTD (message of the day) that is shown later in the game on the guild channel
|
||||
@@ -204,19 +218,19 @@ $config = array(
|
||||
'team_display_outfit' => true,
|
||||
|
||||
// bans page
|
||||
'bans_limit' => 50,
|
||||
'bans_display_all' => true, // should all bans be displayed? (sorted page by page)
|
||||
'bans_per_page' => 20,
|
||||
|
||||
// highscores page
|
||||
'highscores_vocation_box' => true, // show 'Choose a vocation' box on the highscores (allowing peoples to sort highscores by vocation)?
|
||||
'highscores_vocation' => true, // show player vocation under his nickname?
|
||||
'highscores_frags' => false, // show 'Frags' tab (best fraggers on the server)? Only 0.3
|
||||
'highscores_frags' => false, // show 'Frags' tab (best fraggers on the server)?
|
||||
'highscores_balance' => false, // show 'Balance' tab (richest players on the server)
|
||||
'highscores_outfit' => true, // show player outfit?
|
||||
'highscores_country_box' => false, // doesnt work yet! (not implemented)
|
||||
'highscores_groups_hidden' => 3, // this group id and higher won't be shown on the highscores
|
||||
'highscores_ids_hidden' => array(0), // this ids of players will be hidden on the highscores (should be ids of samples)
|
||||
'highscores_length' => 100, // how many records per page on highscores
|
||||
'highscores_per_page' => 100, // how many records per page on highscores
|
||||
'highscores_cache_ttl' => 15, // how often to update highscores from database in minutes (default 15 minutes)
|
||||
|
||||
// characters page
|
||||
'characters' => array( // what things to display on character view page (true/false in each option)
|
||||
@@ -270,7 +284,7 @@ $config = array(
|
||||
'status_enabled' => true, // you can disable status checking by settings this to "false"
|
||||
'status_ip' => '',
|
||||
'status_port' => '',
|
||||
'status_timeout' => 2, // how long to wait for the initial response from the server (default: 2 seconds)
|
||||
'status_timeout' => 2.0, // how long to wait for the initial response from the server (default: 2 seconds)
|
||||
|
||||
// how often to connect to server and update status (default: every minute)
|
||||
// if your status timeout in config.lua is bigger, that it will be used instead
|
||||
@@ -278,7 +292,7 @@ $config = array(
|
||||
'status_interval' => 60,
|
||||
|
||||
// admin panel
|
||||
'admin_panel_modules' => 'lastlogin,points,coins',
|
||||
'admin_panel_modules' => 'statistics,web_status,server_status,lastlogin,created,points,coins,balance', // default - statistics,web_status,server_status,lastlogin,created,points,coins,balance
|
||||
|
||||
// other
|
||||
'anonymous_usage_statistics' => true,
|
||||
@@ -289,13 +303,5 @@ $config = array(
|
||||
'date_timezone' => 'Europe/Berlin', // more info at http://php.net/manual/en/timezones.php
|
||||
'footer_show_load_time' => true, // display load time of the page in the footer
|
||||
|
||||
'npc' => array(),
|
||||
|
||||
// character name blocked
|
||||
'character_name_blocked' => array(
|
||||
'prefix' => array(),
|
||||
'names' => array(),
|
||||
'words' => array(),
|
||||
),
|
||||
|
||||
'npc' => array()
|
||||
);
|
||||
|
||||
BIN
images/del.png
|
Before Width: | Height: | Size: 433 B After Width: | Height: | Size: 318 B |
BIN
images/druid.png
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 10 KiB |
BIN
images/edit.png
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 363 B |
BIN
images/error.png
|
Before Width: | Height: | Size: 706 B After Width: | Height: | Size: 592 B |
BIN
images/false.png
|
Before Width: | Height: | Size: 1004 B After Width: | Height: | Size: 845 B |
BIN
images/hist.png
|
Before Width: | Height: | Size: 117 B After Width: | Height: | Size: 110 B |
BIN
images/info.png
|
Before Width: | Height: | Size: 783 B After Width: | Height: | Size: 631 B |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 1005 B |
|
Before Width: | Height: | Size: 789 B After Width: | Height: | Size: 735 B |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 8.2 KiB |
BIN
images/plus.png
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 615 B After Width: | Height: | Size: 463 B |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 816 B After Width: | Height: | Size: 633 B |
BIN
images/trash.png
|
Before Width: | Height: | Size: 476 B After Width: | Height: | Size: 474 B |
BIN
images/true.png
|
Before Width: | Height: | Size: 809 B After Width: | Height: | Size: 709 B |
57
index.php
@@ -74,14 +74,6 @@ if((!isset($config['installed']) || !$config['installed']) && file_exists(BASE .
|
||||
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!');
|
||||
}
|
||||
|
||||
require_once SYSTEM . 'init.php';
|
||||
require_once SYSTEM . 'template.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.');
|
||||
}
|
||||
|
||||
$found = false;
|
||||
if(empty($uri) || isset($_REQUEST['template'])) {
|
||||
$_REQUEST['p'] = 'news';
|
||||
@@ -89,11 +81,7 @@ if(empty($uri) || isset($_REQUEST['template'])) {
|
||||
}
|
||||
else {
|
||||
$tmp = strtolower($uri);
|
||||
if (!preg_match('/[^A-z0-9_\-]/', $uri) && file_exists(TEMPLATES . $template_name . '/pages/' . $tmp . '.php')) {
|
||||
$_REQUEST['p'] = $uri;
|
||||
$found = true;
|
||||
}
|
||||
else if (!preg_match('/[^A-z0-9_\-]/', $uri) && file_exists(SYSTEM . 'pages/' . $tmp . '.php')) {
|
||||
if(!preg_match('/[^A-z0-9_\-]/', $uri) && file_exists(SYSTEM . 'pages/' . $tmp . '.php')) {
|
||||
$_REQUEST['p'] = $uri;
|
||||
$found = true;
|
||||
}
|
||||
@@ -115,10 +103,12 @@ else {
|
||||
'/^account\/character\/comment\/[A-Za-z0-9-_%+\']+\/?$/' => array('subtopic' => 'accountmanagement', 'action' => 'change_comment', 'name' => '$3'),
|
||||
'/^account\/character\/comment\/?$/' => array('subtopic' => 'accountmanagement', 'action' => 'change_comment'),
|
||||
'/^account\/confirm_email\/[A-Za-z0-9-_]+\/?$/' => array('subtopic' => 'accountmanagement', 'action' => 'confirm_email', 'v' => '$2'),
|
||||
'/^bans\/[0-9]+\/?$/' => array('subtopic' => 'bans', 'page' => '$1'),
|
||||
'/^characters\/[A-Za-z0-9-_%+\']+$/' => array('subtopic' => 'characters', 'name' => '$1'),
|
||||
'/^changelog\/[0-9]+\/?$/' => array('subtopic' => 'changelog', 'page' => '$1'),
|
||||
'/^commands\/add\/?$/' => array('subtopic' => 'commands', 'action' => 'add'),
|
||||
'/^commands\/edit\/?$/' => array('subtopic' => 'commands', 'action' => 'edit'),
|
||||
'/^creatures\/[A-Za-z0-9-_%+\']+$/' => array('subtopic' => 'creatures', 'creature' => '$1'),
|
||||
'/^faq\/add\/?$/' => array('subtopic' => 'faq', 'action' => 'add'),
|
||||
'/^faq\/edit\/?$/' => array('subtopic' => 'faq', 'action' => 'edit'),
|
||||
'/^forum\/add_board\/?$/' => array('subtopic' => 'forum', 'action' => 'add_board'),#
|
||||
@@ -145,13 +135,13 @@ else {
|
||||
'/^houses\/view\/?$/' => array('subtopic' => 'houses', 'page' => 'view')
|
||||
);
|
||||
|
||||
foreach ($rules as $rule => $redirect) {
|
||||
foreach($rules as $rule => $redirect) {
|
||||
if (preg_match($rule, $uri)) {
|
||||
$tmp = explode('/', $uri);
|
||||
/* @var $redirect array */
|
||||
foreach ($redirect as $key => $value) {
|
||||
foreach($redirect as $key => $value) {
|
||||
|
||||
if (strpos($value, '$') !== false) {
|
||||
if(strpos($value, '$') !== false) {
|
||||
$value = str_replace('$' . $value[1], $tmp[$value[1]], $value);
|
||||
}
|
||||
|
||||
@@ -166,12 +156,6 @@ else {
|
||||
}
|
||||
}
|
||||
|
||||
// handle ?fbclid=x, etc. (show news page)
|
||||
if (!$found && count($_GET) > 0 && !isset($_REQUEST['subtopic']) && !isset($_REQUEST['p']) && !in_array($_SERVER['QUERY_STRING'], getDatabasePages())) {
|
||||
$_REQUEST['p'] = $_REQUEST['subtopic'] = 'news';
|
||||
$found = true;
|
||||
}
|
||||
|
||||
// define page visited, so it can be used within events system
|
||||
$page = isset($_REQUEST['subtopic']) ? $_REQUEST['subtopic'] : (isset($_REQUEST['p']) ? $_REQUEST['p'] : '');
|
||||
if(empty($page) || !preg_match('/^[A-z0-9\_\-]+$/', $page)) {
|
||||
@@ -192,10 +176,18 @@ define('PAGE', $page);
|
||||
|
||||
$template_place_holders = array();
|
||||
|
||||
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.');
|
||||
}
|
||||
|
||||
// event system
|
||||
require_once SYSTEM . 'hooks.php';
|
||||
$hooks = new Hooks();
|
||||
$hooks->load();
|
||||
require_once SYSTEM . 'template.php';
|
||||
require_once SYSTEM . 'login.php';
|
||||
require_once SYSTEM . 'status.php';
|
||||
|
||||
@@ -298,7 +290,6 @@ if($config['backward_support']) {
|
||||
$config['site'] = &$config;
|
||||
$config['server'] = &$config['lua'];
|
||||
$config['site']['shop_system'] = $config['gifts_system'];
|
||||
$config['site']['gallery_page'] = true;
|
||||
|
||||
if(!isset($config['vdarkborder']))
|
||||
$config['vdarkborder'] = '#505050';
|
||||
@@ -346,10 +337,12 @@ if($load_it)
|
||||
)) . $content;
|
||||
}
|
||||
} else {
|
||||
$file = TEMPLATES . "$template_name/pages/$page.php";
|
||||
if(!@file_exists($file) || preg_match('/[^A-z0-9_\-]/', $page)) {
|
||||
$file = SYSTEM . "pages/$page.php";
|
||||
if(!@file_exists($file) || preg_match('/[^A-z0-9_\-]/', $page)) {
|
||||
$file = $template_path . '/pages/' . $page . '.php';
|
||||
if(!@file_exists($file))
|
||||
{
|
||||
$file = SYSTEM . 'pages/' . $page . '.php';
|
||||
if(!@file_exists($file))
|
||||
{
|
||||
$page = '404';
|
||||
$file = SYSTEM . 'pages/404.php';
|
||||
}
|
||||
@@ -378,7 +371,15 @@ if($config['backward_support']) {
|
||||
$topic = $title;
|
||||
}
|
||||
|
||||
$title_full = (isset($title) ? $title . $config['title_separator'] : '') . $config['lua']['serverName'];
|
||||
/**
|
||||
* @var OTS_Account $account_logged
|
||||
*/
|
||||
if ($logged && admin()) {
|
||||
$content .= $twig->render('admin-bar.html.twig', [
|
||||
'username' => USE_ACCOUNT_NAME ? $account_logged->getName() : $account_logged->getId()
|
||||
]);
|
||||
}
|
||||
$title_full = (isset($title) ? $title . ' - ' : '') . $config['lua']['serverName'];
|
||||
require $template_path . '/' . $template_index;
|
||||
|
||||
echo base64_decode('PCEtLSBQb3dlcmVkIGJ5IE15QUFDIDo6IGh0dHBzOi8vd3d3Lm15LWFhYy5vcmcvIC0tPg==') . PHP_EOL;
|
||||
|
||||
@@ -38,3 +38,4 @@ if(!isset($error) || !$error) {
|
||||
$error = true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -6,12 +6,18 @@ $ots = POT::getInstance();
|
||||
require SYSTEM . 'database.php';
|
||||
|
||||
if(!isset($db)) {
|
||||
$database_error = $locale['step_database_error_mysql_connect'] . '<br/>' .
|
||||
$locale['step_database_error_mysql_connect_2'] .
|
||||
'<ul>' .
|
||||
'<li>' . $locale['step_database_error_mysql_connect_3'] . '</li>' .
|
||||
'<li>' . $locale['step_database_error_mysql_connect_4'] . '</li>' .
|
||||
'</ul>' . '<br/>' . $error;
|
||||
$database_error = '<p class="lead">' . $locale['step_database_error_mysql_connect'] . '</p>';
|
||||
|
||||
$database_error .= '<p>' . $locale['step_database_error_mysql_connect_2'] . '</p>';
|
||||
|
||||
$database_error .= '<ul class="list-group">' .
|
||||
'<li class="list-group-item list-group-item-warning">' . $locale['step_database_error_mysql_connect_3'] . '</li>' .
|
||||
'<li class="list-group-item list-group-item-warning">' . $locale['step_database_error_mysql_connect_4'] . '</li>' .
|
||||
'</ul>';
|
||||
|
||||
$database_error .= '<div class="alert alert-danger mt-4">
|
||||
<span>' . $error . '</span>
|
||||
</div>';
|
||||
}
|
||||
else {
|
||||
if($db->hasTable('accounts'))
|
||||
|
||||
@@ -62,9 +62,9 @@ function next_buttons($previous = true, $next = true)
|
||||
$ret .= '<input class="button" type="submit" onclick="document.getElementById(\'step\').value=\'' . $steps[$i + 1] . '\';" value="' . $locale['next'] . '" />';
|
||||
*/
|
||||
if($previous)
|
||||
$ret .= '<input type="button" class="button" onclick="document.getElementById(\'step\').value=\'' . $steps[$i - 1] . '\'; this.form.submit();" value="« ' . $locale['previous'] . '" />';
|
||||
$ret .= '<input type="button" class="button btn btn-primary m-2" onclick="document.getElementById(\'step\').value=\'' . $steps[$i - 1] . '\'; this.form.submit();" value="« ' . $locale['previous'] . '" />';
|
||||
if($next)
|
||||
$ret .= '<input type="button" class="button" onclick="document.getElementById(\'step\').value=\'' . $steps[$i + 1] . '\'; this.form.submit(); " value="' . $locale['next'] . ' »" />';
|
||||
$ret .= '<input type="button" class="button btn btn-primary m-2" onclick="document.getElementById(\'step\').value=\'' . $steps[$i + 1] . '\'; this.form.submit(); " value="' . $locale['next'] . ' »" />';
|
||||
|
||||
$ret .= '</div>';
|
||||
return $ret;
|
||||
|
||||
@@ -207,21 +207,24 @@ CREATE TABLE `myaac_monsters` (
|
||||
`use_haste` tinyint(1) NOT NULL,
|
||||
`voices` text NOT NULL,
|
||||
`immunities` varchar(255) NOT NULL,
|
||||
`elements` TEXT NOT NULL,
|
||||
`summonable` tinyint(1) NOT NULL,
|
||||
`convinceable` tinyint(1) NOT NULL,
|
||||
`pushable` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`canpushitems` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`canwalkonenergy` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`canwalkonpoison` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`canwalkonfire` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`runonhealth` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`hostile` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`attackable` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`rewardboss` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`defense` INT(11) NOT NULL DEFAULT '0',
|
||||
`armor` INT(11) NOT NULL DEFAULT '0',
|
||||
`canpushcreatures` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
`race` varchar(255) NOT NULL,
|
||||
`loot` text NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
|
||||
|
||||
CREATE TABLE `myaac_videos`
|
||||
(
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`title` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`youtube_id` VARCHAR(20) NOT NULL,
|
||||
`author` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`ordering` INT(11) NOT NULL DEFAULT 0,
|
||||
`hidden` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`summons` TEXT NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
We have detected that you don't have access to write to the system/cache directory. Under linux you can fix it by using this two command, where first one should be enough (for apache):<br/><br/><span class="console">chown -R www-data.www-data /var/www/*</span><br/><span class="console">chmod -R 760 system/cache</span>
|
||||
We have detected that you don't have access to write to the system/cache directory. Under linux you can fix it by using this two command, where first one should be enough (for apache):<br/><br/><span class="console">chown -R www-data.www-data /var/www/*</span><br/><span class="console">chmod -R 660 system/cache</span>
|
||||
|
||||
<style type="text/css">
|
||||
.console {
|
||||
@@ -8,4 +8,4 @@ We have detected that you don't have access to write to the system/cache directo
|
||||
border: 3px double #CCCCCC;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -70,7 +70,7 @@ if($step == 'database') {
|
||||
|
||||
$key = str_replace('var_', '', $key);
|
||||
|
||||
if(in_array($key, array('account', 'account_id', 'password', 'email', 'player_name'))) {
|
||||
if(in_array($key, array('account', 'password', 'email', 'player_name'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -95,10 +95,6 @@ if($step == 'database') {
|
||||
$errors[] = $locale['step_config_mail_admin_error'];
|
||||
break;
|
||||
}
|
||||
else if($key == 'mail_address' && !Validator::email($value)) {
|
||||
$errors[] = $locale['step_config_mail_address_error'];
|
||||
break;
|
||||
}
|
||||
else if($key == 'timezone' && !in_array($value, DateTimeZone::listIdentifiers())) {
|
||||
$errors[] = $locale['step_config_timezone_error'];
|
||||
break;
|
||||
@@ -114,11 +110,13 @@ if($step == 'database') {
|
||||
}
|
||||
}
|
||||
else if($step == 'admin') {
|
||||
if(!file_exists(BASE . 'config.local.php') || !isset($config['installed']) || !$config['installed']) {
|
||||
$step = 'database';
|
||||
$config_failed = true;
|
||||
if(file_exists(BASE . 'config.local.php') && isset($config['installed']) && $config['installed'] && isset($_SESSION['saved'])) {
|
||||
$config_failed = false;
|
||||
}
|
||||
else {
|
||||
$_SESSION['saved'] = true;
|
||||
|
||||
if($config_failed) {
|
||||
$step = 'database';
|
||||
}
|
||||
}
|
||||
else if($step == 'finish') {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) {
|
||||
echo '<p class="warning">' . $locale['already_installed'] . '</p>';
|
||||
echo '<div class="alert alert-warning"><span>' . $locale['already_installed'] . '</span></div>';
|
||||
}
|
||||
else {
|
||||
unset($_SESSION['saved']);
|
||||
|
||||
@@ -5,3 +5,4 @@ $twig->display('install.license.html.twig', array(
|
||||
'license' => file_get_contents(BASE . 'LICENSE'),
|
||||
'buttons' => next_buttons()
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -2,8 +2,21 @@
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
// configuration
|
||||
$dirs_required = [
|
||||
'system/logs',
|
||||
'system/cache',
|
||||
];
|
||||
$dirs_optional = [
|
||||
'images/guilds' => $locale['step_requirements_warning_images_guilds'],
|
||||
'images/gallery' => $locale['step_requirements_warning_images_gallery'],
|
||||
];
|
||||
|
||||
$extensions_required = [
|
||||
'pdo', 'pdo_mysql', 'xml', 'zip'
|
||||
'pdo', 'pdo_mysql', 'json', 'xml'
|
||||
];
|
||||
$extensions_optional = [
|
||||
'gd' => $locale['step_requirements_warning_player_signatures'],
|
||||
'zip' => $locale['step_requirements_warning_install_plugins'],
|
||||
];
|
||||
/*
|
||||
*
|
||||
@@ -14,11 +27,11 @@ $extensions_required = [
|
||||
function version_check($name, $ok, $info = '', $warning = false)
|
||||
{
|
||||
global $failed;
|
||||
echo '<p class="' . ($ok ? 'success' : ($warning ? 'warning' : 'error')) . '">' . $name;
|
||||
echo '<div class="alert alert-' . ($ok ? 'success' : ($warning ? 'warning' : 'danger')) . '">' . $name;
|
||||
if(!empty($info))
|
||||
echo ': <b>' . $info . '</b>';
|
||||
|
||||
echo '</p>';
|
||||
echo '</div>';
|
||||
if(!$ok && !$warning)
|
||||
$failed = true;
|
||||
}
|
||||
@@ -27,12 +40,18 @@ $failed = false;
|
||||
|
||||
// start validating
|
||||
version_check($locale['step_requirements_php_version'], (PHP_VERSION_ID >= 50500), PHP_VERSION);
|
||||
foreach(array('images/guilds', 'images/houses', 'images/gallery') as $value)
|
||||
|
||||
foreach ($dirs_required as $value)
|
||||
{
|
||||
$is_writable = 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);
|
||||
}
|
||||
|
||||
foreach ($dirs_optional as $dir => $errorMsg) {
|
||||
$is_writable = is_writable(BASE . $dir) && (MYAAC_OS != 'WINDOWS' || win_is_writable(BASE . $dir));
|
||||
version_check($locale['step_requirements_write_perms'] . ': ' . $dir, $is_writable, $is_writable ? '' : $errorMsg, true);
|
||||
}
|
||||
|
||||
$ini_register_globals = ini_get_bool('register_globals');
|
||||
version_check('register_long_arrays', !$ini_register_globals, $ini_register_globals ? $locale['on'] : $locale['off']);
|
||||
|
||||
@@ -44,12 +63,19 @@ foreach ($extensions_required as $ext) {
|
||||
version_check(str_replace('$EXTENSION$', strtoupper($ext), $locale['step_requirements_extension']) , $loaded, $loaded ? $locale['loaded'] : $locale['not_loaded']);
|
||||
}
|
||||
|
||||
|
||||
if($failed)
|
||||
{
|
||||
echo '<br/><b>' . $locale['step_requirements_failed'];
|
||||
echo next_form(true, false);
|
||||
foreach ($extensions_optional as $ext => $errorMsg) {
|
||||
$loaded = extension_loaded($ext);
|
||||
version_check(str_replace('$EXTENSION$', strtoupper($ext), $locale['step_requirements_extension']) , $loaded, $loaded ? $locale['loaded'] : $locale['not_loaded'] . '. ' . $errorMsg, true);
|
||||
}
|
||||
else
|
||||
|
||||
echo '<div class="text-center m-3">';
|
||||
|
||||
if($failed) {
|
||||
echo '<div class="alert alert-warning"><span>' . $locale['step_requirements_failed'] . '</span></div>';
|
||||
echo next_form(true, false);
|
||||
}else {
|
||||
echo next_form(true, true);
|
||||
?>
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
?>
|
||||
|
||||
@@ -18,3 +18,4 @@ $twig->display('install.config.html.twig', array(
|
||||
'errors' => isset($errors) ? $errors : null,
|
||||
'buttons' => next_buttons()
|
||||
));
|
||||
?>
|
||||
@@ -21,8 +21,6 @@ if(!$error) {
|
||||
// user can disable when he wants
|
||||
$content .= '$config[\'env\'] = \'prod\'; // dev or prod';
|
||||
$content .= PHP_EOL;
|
||||
$content .= '$config[\'mail_enabled\'] = true;';
|
||||
$content .= PHP_EOL;
|
||||
foreach($_SESSION as $key => $value)
|
||||
{
|
||||
if(strpos($key, 'var_') !== false)
|
||||
@@ -57,40 +55,17 @@ if(!$error) {
|
||||
error($database_error);
|
||||
}
|
||||
else {
|
||||
if(!$db->hasTable('accounts')) {
|
||||
$tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']);
|
||||
error($tmp);
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if(!$db->hasTable('players')) {
|
||||
$tmp = str_replace('$TABLE$', 'players', $locale['step_database_error_table']);
|
||||
error($tmp);
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if(!$db->hasTable('guilds')) {
|
||||
$tmp = str_replace('$TABLE$', 'guilds', $locale['step_database_error_table']);
|
||||
error($tmp);
|
||||
$error = true;
|
||||
}
|
||||
$twig->display('install.installer.html.twig', array(
|
||||
'url' => 'tools/5-database.php',
|
||||
'message' => $locale['loading_spinner']
|
||||
));
|
||||
|
||||
if(!$error) {
|
||||
$twig->display('install.installer.html.twig', array(
|
||||
'url' => 'tools/5-database.php',
|
||||
'message' => $locale['loading_spinner']
|
||||
));
|
||||
|
||||
if(!Validator::email($_SESSION['var_mail_admin'])) {
|
||||
error($locale['step_config_mail_admin_error']);
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if(!Validator::email($_SESSION['var_mail_address'])) {
|
||||
error($locale['step_config_mail_address_error']);
|
||||
$error = true;
|
||||
}
|
||||
|
||||
$content .= '$config[\'session_prefix\'] = \'myaac_' . generateRandomString(8, true, false, true, false) . '_\';';
|
||||
$content .= PHP_EOL;
|
||||
$content .= '$config[\'cache_prefix\'] = \'myaac_' . generateRandomString(8, true, false, true, false) . '_\';';
|
||||
@@ -111,7 +86,7 @@ if(!$error) {
|
||||
unset($_SESSION['saved']);
|
||||
|
||||
$locale['step_database_error_file'] = str_replace('$FILE$', '<b>' . BASE . 'config.local.php</b>', $locale['step_database_error_file']);
|
||||
error($locale['step_database_error_file'] . '<br/>
|
||||
warning($locale['step_database_error_file'] . '<br/>
|
||||
<textarea cols="70" rows="10">' . $content . '</textarea>');
|
||||
}
|
||||
}
|
||||
@@ -120,8 +95,10 @@ if(!$error) {
|
||||
}
|
||||
?>
|
||||
|
||||
<form action="<?php echo BASE_URL; ?>install/" method="post">
|
||||
<input type="hidden" name="step" id="step" value="admin" />
|
||||
<?php echo next_buttons(true, !$error);
|
||||
?>
|
||||
</form>
|
||||
<div class="text-center m-3">
|
||||
<form action="<?php echo BASE_URL; ?>install/" method="post">
|
||||
<input type="hidden" name="step" id="step" value="admin" />
|
||||
<?php echo next_buttons(true, $error ? false : true);
|
||||
?>
|
||||
</form>
|
||||
</div>
|
||||
@@ -66,6 +66,7 @@ else {
|
||||
$new_account->setPassword(encrypt($password));
|
||||
$new_account->setEMail($email);
|
||||
|
||||
$new_account->unblock();
|
||||
$new_account->save();
|
||||
|
||||
$new_account->setCustomField('created', time());
|
||||
@@ -82,7 +83,7 @@ else {
|
||||
if($db->hasColumn('accounts', 'group_id'))
|
||||
$account_used->setCustomField('group_id', $groups->getHighestId());
|
||||
if($db->hasColumn('accounts', 'type'))
|
||||
$account_used->setCustomField('type', 6);
|
||||
$account_used->setCustomField('type', 5);
|
||||
|
||||
if(!$player_db->isLoaded())
|
||||
$player->setAccountId($account_used->getId());
|
||||
|
||||
@@ -1,299 +1,13 @@
|
||||
* {
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400&display=swap');
|
||||
|
||||
body {
|
||||
text-align: center;
|
||||
font: 12px Verdana;
|
||||
color: #000000;
|
||||
background-color: #000000;
|
||||
}
|
||||
img {
|
||||
border: 0;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
.break {
|
||||
font-size: 0;
|
||||
width: 0; height: 0;
|
||||
clear: both;
|
||||
}
|
||||
.alignleft {
|
||||
float: left;
|
||||
margin: 4px 10px 5px 0;
|
||||
}
|
||||
.alignright {
|
||||
float: right;
|
||||
margin: 4px 0 5px 10px;
|
||||
}
|
||||
.aligncenter {
|
||||
text-align: center;
|
||||
h1{
|
||||
font-weight: 100 !important;
|
||||
}
|
||||
|
||||
/** BEGIN wrapper **/
|
||||
#wrapper {
|
||||
background: #ffffff url(images/background.jpg) repeat-x 0 0;
|
||||
width: 980px;
|
||||
}
|
||||
|
||||
#header {
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
margin-top: 10px;
|
||||
text-align: right;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#header span {
|
||||
font-size: 25px;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
padding-left: 40px;
|
||||
line-height: 80px;
|
||||
}
|
||||
|
||||
#version {
|
||||
float: right;
|
||||
color: #000;
|
||||
font-size: 17px;
|
||||
padding-top: 25px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
/** BEGIN body **/
|
||||
#body {
|
||||
background: url(images/wrapper.gif) repeat-y 0 0;
|
||||
}
|
||||
/** END body **/
|
||||
|
||||
/** BEGIN content **/
|
||||
#content {
|
||||
width: 642px;
|
||||
float: left;
|
||||
padding: 20px 18px 20px 20px;
|
||||
color: #434242;
|
||||
}
|
||||
|
||||
/** begin headers **/
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: Tahoma;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
h2, h3, h4, h5, h6 {
|
||||
margin-top: 30px;
|
||||
}
|
||||
h1 { font-size: 2em; }
|
||||
h2 { font-size: 1.6em; }
|
||||
h3 { font-size: 1.3em; }
|
||||
h4, h5, h6 { font-size: 1em; }
|
||||
/** end headers **/
|
||||
|
||||
/** begin messages **/
|
||||
.error, .success, .note, .warning {
|
||||
font-weight: bold;
|
||||
font-size: 0.9em;
|
||||
padding: 4px 10px 4px 24px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 5px 6px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
line-height: 1.6em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.error {
|
||||
background-color: #FDD9D9;
|
||||
background-image: url(images/error.gif);
|
||||
border-color: #FBA3A3;
|
||||
color: #D80303;
|
||||
}
|
||||
.success {
|
||||
background-color: #E4FCD9;
|
||||
background-image: url(images/success.gif);
|
||||
border-color: #BFFDA3;
|
||||
color: #35A502;
|
||||
}
|
||||
.note {
|
||||
background-color: #DDEAFA;
|
||||
background-image: url(images/note.gif);
|
||||
border-color: #A3D8FD;
|
||||
color: #026DA5;
|
||||
}
|
||||
.warning {
|
||||
background-color: #FBF0B3;
|
||||
background-image: url(images/warning.gif);
|
||||
border-color: #FBBB95;
|
||||
color: #FD6002;
|
||||
}
|
||||
/** end messages **/
|
||||
|
||||
/** begin form **/
|
||||
form {
|
||||
border: 1px solid #DDDDDD;
|
||||
padding: 16px;
|
||||
}
|
||||
form .input {
|
||||
padding-top: 12px;
|
||||
clear: both;
|
||||
}
|
||||
form .first {
|
||||
padding-top: 0;
|
||||
}
|
||||
form .input p {
|
||||
margin-bottom: 7px !important;
|
||||
}
|
||||
form input {
|
||||
margin-right: 5px;
|
||||
}
|
||||
form label {
|
||||
margin-right: 10px;
|
||||
color: #8B8B8B;
|
||||
}
|
||||
form input.text, form textarea {
|
||||
border: 1px solid #BEBDBD;
|
||||
font-size: 1em;
|
||||
font-family: Verdana;
|
||||
background-color: #F3F3F3;
|
||||
color: #808080;
|
||||
padding: 2px;
|
||||
max-width: 100%;
|
||||
}
|
||||
.positive, .negative {
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
padding: 1px 0 0 20px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
display: inline;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.positive {
|
||||
background-image: url(images/positive.gif);
|
||||
color: #35A502;
|
||||
}
|
||||
.negative {
|
||||
background-image: url(images/negative.gif);
|
||||
color: #D80303;
|
||||
}
|
||||
form textarea {
|
||||
line-height: 1.6em;
|
||||
}
|
||||
form button, form input.button {
|
||||
font-size: 0.9em;
|
||||
font-family: Verdana;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
background: #B6B4B4 url(images/button.gif) repeat-x 0 0;
|
||||
border: 1px solid #B6B4B4;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
/** end form **/
|
||||
|
||||
/** begin table **/
|
||||
table {
|
||||
|
||||
}
|
||||
table th {
|
||||
font-size: 0.9em;
|
||||
color: #ffffff;
|
||||
background-color: #679BC5;
|
||||
padding: 2px 4px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
table td {
|
||||
line-height: 1.6em;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
table tr.odd td { background-color: #EEEEEE; }
|
||||
table tr.even td { background-color: #E5E5E5; }
|
||||
|
||||
/** end table **/
|
||||
|
||||
/** begin paragraphs, lists, etc. **/
|
||||
#content p {
|
||||
line-height: 1.6em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#content ul, #content ol {
|
||||
list-style-position: inside;
|
||||
}
|
||||
#content li {
|
||||
line-height: 1.6em;
|
||||
padding: 2px 0 2px 0;
|
||||
}
|
||||
a {
|
||||
color: #679BC5;
|
||||
}
|
||||
a:hover {
|
||||
color: #ff0000;
|
||||
text-decoration: none;
|
||||
}
|
||||
blockquote {
|
||||
padding: 10px;
|
||||
background-color: #eeeeee;
|
||||
line-height: 1.6em;
|
||||
border-width: 2px 0 1px;
|
||||
border-style: solid;
|
||||
border-color: #e0e0e0;
|
||||
}
|
||||
/** end paragraphs, lists, etc. **/
|
||||
|
||||
/** END content **/
|
||||
|
||||
/** BEGIN sidebar **/
|
||||
#sidebar {
|
||||
width: 300px;
|
||||
float: right;
|
||||
padding: 10px 0;
|
||||
}
|
||||
#sidebar h2 {
|
||||
background: green url(images/sidehead.gif) no-repeat 0 0;
|
||||
margin: 0 10px;
|
||||
font-size: 1em;
|
||||
color: #ffffff;
|
||||
padding: 7px 10px;
|
||||
}
|
||||
#sidebar ul {
|
||||
list-style-type: none;
|
||||
background: #E0E0E0 url(images/sidebody.gif) no-repeat 0 bottom;
|
||||
padding: 10px;
|
||||
margin: 0 10px 10px;
|
||||
}
|
||||
#sidebar ul li {
|
||||
padding: 4px 0 4px 14px;
|
||||
background: none;
|
||||
line-height: 1.6em;
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
}
|
||||
#sidebar ul li a {
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
}
|
||||
#sidebar ul li a:hover {
|
||||
text-decoration: none;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
#sidebar ul li a:active {
|
||||
text-decoration: none;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
#sidebar ul li current {
|
||||
text-decoration: none;
|
||||
color: #ff0000;
|
||||
}
|
||||
.current {
|
||||
text-decoration: none;
|
||||
color: #ff0000;
|
||||
}
|
||||
h3 {
|
||||
font-weight: 300 !important;
|
||||
}
|
||||
@@ -1,48 +1,74 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" dir="<?php echo $locale['direction']; ?>" lang="<?php echo $locale['lang']; ?>" xml:lang="<?php echo $locale['lang']; ?>">
|
||||
<!DOCTYPE html>
|
||||
<html dir="<?php echo $locale['direction']; ?>" lang="<?php echo $locale['lang']; ?>" xml:lang="<?php echo $locale['lang']; ?>">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $locale['encoding']; ?>" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>MyAAC - <?php echo $locale['installation']; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
|
||||
<link rel="stylesheet" type="text/css" href="template/style.css" />
|
||||
<script type="text/javascript" src="<?php echo BASE_URL; ?>tools/js/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<!--div class="buffer"-->
|
||||
<div id="header">
|
||||
<h1>MyAAC <?php echo $locale['installation']; ?></h1>
|
||||
</div>
|
||||
|
||||
<div id="body">
|
||||
<div id="body" class="container">
|
||||
|
||||
<header id="header" class="pt-5 pb-4 pb-sm-5">
|
||||
<h1>MyAAC <?php echo $locale['installation']; ?></h1>
|
||||
</header>
|
||||
|
||||
<div id="sidebar">
|
||||
<h2><?php echo $locale['steps']; ?></h2>
|
||||
<ul>
|
||||
<?php
|
||||
$i = 0;
|
||||
foreach($steps as $key => $value)
|
||||
echo '<li' . ($step == $value ? ' class="current"' : '') . '>' . ++$i . '. ' . $locale['step_' . $value] . '</li>';
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
<div id="content">
|
||||
<div id="sidebar" class="col-md-3">
|
||||
<h3><?php echo $locale['steps']; ?></h3>
|
||||
<ul class="list-group mt-4">
|
||||
<?php
|
||||
if(isset($locale['step_' . $step . '_title']))
|
||||
echo '<h1>' . $locale['step_' . $step . '_title'] . '</h1>';
|
||||
else
|
||||
echo '<h1>' . $locale['step_' . $step] . '</h1>';
|
||||
echo $content;
|
||||
$i = 0;
|
||||
foreach($steps as $key => $value){
|
||||
|
||||
if ($step == $value) {
|
||||
$progress = ($i == 6) ? 100 : $i * 16;
|
||||
}
|
||||
|
||||
echo '<li' . ($step == $value ? ' class="list-group-item active"' : ' class="list-group-item"') . '>' . ++$i . '. ' . $locale['step_' . $value] . '</li>';
|
||||
}
|
||||
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="break"></div>
|
||||
</ul>
|
||||
</div>
|
||||
<!--/div-->
|
||||
|
||||
<div id="content" class="col-md-9">
|
||||
|
||||
<?php
|
||||
if(isset($locale['step_' . $step . '_title']))
|
||||
echo '<h3 class="mb-4 mt-4 mt-md-0">' . $locale['step_' . $step . '_title'] . '</h3>';
|
||||
else
|
||||
echo '<h3 class="mb-4 mt-4 mt-md-0">' . $locale['step_' . $step] . '</h3>';
|
||||
?>
|
||||
|
||||
<?php
|
||||
if(!isset($config['installed'])):
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="progress mb-2">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated" style="width: <?php echo $progress; ?>%" role="progressbar" aria-valuenow="<?php echo $progress; ?>" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php echo $content; ?>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<footer id="footer" class="p-4">
|
||||
<p style="text-align: center;"><?php echo base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4='); ?></p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -23,6 +23,24 @@ if(!$error) {
|
||||
}
|
||||
}
|
||||
|
||||
if(!$db->hasTable('accounts')) {
|
||||
$locale['step_database_error_table'] = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']);
|
||||
error($locale['step_database_error_table']);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$db->hasTable('players')) {
|
||||
$locale['step_database_error_table'] = str_replace('$TABLE$', 'players', $locale['step_database_error_table']);
|
||||
error($locale['step_database_error_table']);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$db->hasTable('guilds')) {
|
||||
$locale['step_database_error_table'] = str_replace('$TABLE$', 'guilds', $locale['step_database_error_table']);
|
||||
error($locale['step_database_error_table']);
|
||||
return;
|
||||
}
|
||||
|
||||
if($db->hasTable(TABLE_PREFIX . 'account_actions')) {
|
||||
$locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']);
|
||||
warning($locale['step_database_error_table_exist']);
|
||||
@@ -55,8 +73,13 @@ else {
|
||||
success($locale['step_database_adding_field'] . ' accounts.key...');
|
||||
}
|
||||
|
||||
if(!$db->hasColumn('accounts', 'blocked')) {
|
||||
if(query("ALTER TABLE `accounts` ADD `blocked` TINYINT(1) NOT NULL DEFAULT FALSE COMMENT 'internal usage' AFTER `key`;"))
|
||||
success($locale['step_database_adding_field'] . ' accounts.blocked...');
|
||||
}
|
||||
|
||||
if(!$db->hasColumn('accounts', 'created')) {
|
||||
if(query("ALTER TABLE `accounts` ADD `created` INT(11) NOT NULL DEFAULT 0 AFTER `" . ($db->hasColumn('accounts', 'group_id') ? 'group_id' : 'email') . "`;"))
|
||||
if(query("ALTER TABLE `accounts` ADD `created` INT(11) NOT NULL DEFAULT 0 AFTER `" . ($db->hasColumn('accounts', 'group_id') ? 'group_id' : 'blocked') . "`;"))
|
||||
success($locale['step_database_adding_field'] . ' accounts.created...');
|
||||
}
|
||||
|
||||
|
||||
@@ -45,38 +45,9 @@ if($success) {
|
||||
success($locale['step_database_imported_players']);
|
||||
}
|
||||
|
||||
require LIBS . 'items.php';
|
||||
if(Items::loadFromXML())
|
||||
success($locale['step_database_loaded_items']);
|
||||
else
|
||||
error(Items::getError());
|
||||
|
||||
require LIBS . 'weapons.php';
|
||||
if(Weapons::loadFromXML())
|
||||
success($locale['step_database_loaded_weapons']);
|
||||
else
|
||||
error(Weapons::getError());
|
||||
|
||||
require LIBS . 'creatures.php';
|
||||
if(Creatures::loadFromXML()) {
|
||||
success($locale['step_database_loaded_monsters']);
|
||||
|
||||
if(Creatures::getMonstersList()->hasErrors()) {
|
||||
$locale['step_database_error_monsters'] = str_replace('$LOG$', 'system/logs/error.log', $locale['step_database_error_monsters']);
|
||||
warning($locale['step_database_error_monsters']);
|
||||
}
|
||||
}
|
||||
else {
|
||||
error(Creatures::getLastError());
|
||||
}
|
||||
|
||||
require LIBS . 'spells.php';
|
||||
if(Spells::loadFromXML()) {
|
||||
success($locale['step_database_loaded_spells']);
|
||||
}
|
||||
else {
|
||||
error(Spells::getLastError());
|
||||
}
|
||||
require LIBS . 'DataLoader.php';
|
||||
DataLoader::setLocale($locale);
|
||||
DataLoader::load();
|
||||
|
||||
// update config.highscores_ids_hidden
|
||||
require_once SYSTEM . 'migrations/20.php';
|
||||
@@ -99,4 +70,4 @@ $locale['step_finish_desc'] = str_replace('$ADMIN_PANEL$', generateLink(str_repl
|
||||
$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']);
|
||||
|
||||
success($locale['step_finish_desc']);
|
||||
success($locale['step_finish_desc']);
|
||||
|
||||
@@ -1,37 +1,25 @@
|
||||
server {
|
||||
listen 80;
|
||||
root /home/otserv/www/public;
|
||||
index index.php;
|
||||
server_name your-domain.com;
|
||||
listen 80;
|
||||
root /home/otserv/www/public;
|
||||
index index.php;
|
||||
server_name your-domain.com;
|
||||
|
||||
# increase max file upload
|
||||
client_max_body_size 10M;
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php;
|
||||
}
|
||||
|
||||
# this is very important, be sure its in your nginx conf - it prevents access to logs etc.
|
||||
location ~ /system {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
location ~ \.php$ {
|
||||
include snippets/fastcgi-php.conf;
|
||||
fastcgi_read_timeout 240;
|
||||
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
|
||||
}
|
||||
|
||||
# block .htaccess
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
|
||||
# block git files and folders
|
||||
location ~ /\.git {
|
||||
return 404;
|
||||
deny all;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
include snippets/fastcgi-php.conf;
|
||||
fastcgi_read_timeout 240;
|
||||
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
|
||||
# for ubuntu 22.04+ it will be php8.1-fpm.sock
|
||||
}
|
||||
}
|
||||
location /system {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
<IfModule mod_autoindex.c>
|
||||
Options -Indexes
|
||||
</IfModule>
|
||||
|
||||
<IfVersion < 2.4>
|
||||
order allow,deny
|
||||
deny from all
|
||||
</IfVersion>
|
||||
<IfVersion >= 2.4>
|
||||
Require all denied
|
||||
</IfVersion>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "EMail Confirmed Reward",
|
||||
"description": "Reward users for confirming their E-Mail.",
|
||||
"version": "1.0",
|
||||
"author": "MyAAC Authors",
|
||||
"contact": "www.my-aac.org",
|
||||
"hooks": {
|
||||
"mail-confirmed-reward": {
|
||||
"type": "EMAIL_CONFIRMED",
|
||||
"file": "plugins/email-confirmed-reward/reward.php"
|
||||
}
|
||||
},
|
||||
"uninstall": [
|
||||
"plugins/email-confirmed-reward.json",
|
||||
"plugins/email-confirmed-reward"
|
||||
]
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
$reward = config('account_mail_confirmed_reward');
|
||||
|
||||
$hasCoinsColumn = $db->hasColumn('accounts', 'coins');
|
||||
if ($reward['coins'] > 0 && $hasCoinsColumn) {
|
||||
log_append('email_confirm_error.log', 'accounts.coins column does not exist.');
|
||||
}
|
||||
|
||||
if (!isset($account) || !$account->isLoaded()) {
|
||||
log_append('email_confirm_error.log', 'Account not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($reward['premium_points'] > 0) {
|
||||
$account->setCustomField('premium_points', (int)$account->getCustomField('premium_points') + $reward['premium_points']);
|
||||
|
||||
success(sprintf($reward['message'], $reward['premium_points'], 'premium points'));
|
||||
}
|
||||
|
||||
if ($reward['coins'] > 0 && $hasCoinsColumn) {
|
||||
$account->setCustomField('coins', (int)$account->getCustomField('coins') + $reward['coins']);
|
||||
|
||||
success(sprintf($reward['message'], $reward['coins'], 'coins'));
|
||||
}
|
||||
|
||||
if ($reward['premium_days'] > 0) {
|
||||
$account->setPremDays($account->getPremDays() + $reward['premium_days']);
|
||||
$account->save();
|
||||
|
||||
success(sprintf($reward['message'], $reward['premium_days'], 'premium days'));
|
||||
}
|
||||
@@ -62,4 +62,4 @@ if [ $1 = "pack" ]; then
|
||||
echo "Done. Released files can be found in 'releases' directory."
|
||||
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
@@ -9,11 +9,6 @@ $loader->register();
|
||||
// register the base directories for the namespace prefix
|
||||
$loader->addNamespace('Composer\Semver', LIBS . 'semver');
|
||||
$loader->addNamespace('Twig', LIBS . 'Twig');
|
||||
$loader->addNamespace('Symfony\Polyfill\Mbstring', LIBS . 'polyfill-mbstring');
|
||||
|
||||
// load polyfill-mbstring bootstrap
|
||||
require LIBS . 'polyfill-mbstring/bootstrap.php';
|
||||
|
||||
/**
|
||||
* An example of a general-purpose implementation that includes the optional
|
||||
* functionality of allowing multiple base directories for a single namespace
|
||||
@@ -208,4 +203,4 @@ class Psr4AutoloaderClass
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,30 +9,7 @@
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
class Account extends OTS_Account {
|
||||
public function loadById($id) {
|
||||
$this->load($id);
|
||||
}
|
||||
public function loadByName($name) {
|
||||
$this->find($name);
|
||||
}
|
||||
}
|
||||
|
||||
class Player extends OTS_Player {
|
||||
public function loadById($id) {
|
||||
$this->load($id);
|
||||
}
|
||||
public function loadByName($name) {
|
||||
$this->find($name);
|
||||
}
|
||||
}
|
||||
class Guild extends OTS_Guild {
|
||||
public function loadById($id) {
|
||||
$this->load($id);
|
||||
}
|
||||
public function loadByName($name) {
|
||||
$this->find($name);
|
||||
}
|
||||
}
|
||||
class Player extends OTS_Player {}
|
||||
class Guild extends OTS_Guild {}
|
||||
class GuildRank extends OTS_GuildRank {}
|
||||
class House extends OTS_House {}
|
||||
|
||||
@@ -10,14 +10,6 @@
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
switch($page)
|
||||
{
|
||||
case 'adminpanel':
|
||||
header('Location: ' . ADMIN_URL);
|
||||
die;
|
||||
|
||||
case 'archive':
|
||||
$page = 'newsarchive';
|
||||
break;
|
||||
|
||||
case 'whoisonline':
|
||||
$page = 'online';
|
||||
break;
|
||||
@@ -45,3 +37,4 @@ switch($page)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -51,3 +51,4 @@ else
|
||||
updateDatabaseConfig('views_counter', $views_counter); // update counter
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -9,35 +9,10 @@
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
if(!isset($config['database_user'][0], $config['database_password'][0], $config['database_name'][0]))
|
||||
{
|
||||
if(isset($config['lua']['sqlType'])) {// tfs 0.3
|
||||
if(isset($config['lua']['mysqlHost'])) {// tfs 0.2
|
||||
$config['otserv_version'] = TFS_02;
|
||||
$config['database_type'] = 'mysql';
|
||||
$config['database_host'] = $config['lua']['mysqlHost'];
|
||||
$config['database_port'] = $config['lua']['mysqlPort'];
|
||||
$config['database_user'] = $config['lua']['mysqlUser'];
|
||||
$config['database_password'] = $config['lua']['mysqlPass'];
|
||||
$config['database_name'] = $config['lua']['mysqlDatabase'];
|
||||
$config['database_encryption'] = $config['lua']['passwordType'];
|
||||
}
|
||||
else {
|
||||
$config['otserv_version'] = TFS_03;
|
||||
$config['database_type'] = $config['lua']['sqlType'];
|
||||
$config['database_host'] = $config['lua']['sqlHost'];
|
||||
$config['database_port'] = $config['lua']['sqlPort'];
|
||||
$config['database_user'] = $config['lua']['sqlUser'];
|
||||
$config['database_password'] = $config['lua']['sqlPass'];
|
||||
$config['database_name'] = $config['lua']['sqlDatabase'];
|
||||
|
||||
$config['database_encryption'] = $config['lua']['encryptionType'];
|
||||
if(!isset($config['database_encryption']) || empty($config['database_encryption'])) // before 0.3.6
|
||||
$config['database_encryption'] = $config['lua']['passwordType'];
|
||||
}
|
||||
}
|
||||
else if(isset($config['lua']['mysqlHost'])) // tfs 1.0
|
||||
{
|
||||
if(!isset($config['database_user'][0], $config['database_password'][0], $config['database_name'][0]))
|
||||
{
|
||||
if(isset($config['lua']['sqlType'])) {// tfs 0.3
|
||||
if(isset($config['lua']['mysqlHost'])) {// tfs 0.2
|
||||
$config['otserv_version'] = TFS_02;
|
||||
$config['database_type'] = 'mysql';
|
||||
$config['database_host'] = $config['lua']['mysqlHost'];
|
||||
@@ -45,75 +20,100 @@ defined('MYAAC') or die('Direct access not allowed!');
|
||||
$config['database_user'] = $config['lua']['mysqlUser'];
|
||||
$config['database_password'] = $config['lua']['mysqlPass'];
|
||||
$config['database_name'] = $config['lua']['mysqlDatabase'];
|
||||
if(!isset($config['database_socket'][0])) {
|
||||
$config['database_socket'] = isset($config['lua']['mysqlSock']) ? trim($config['lua']['mysqlSock']) : '';
|
||||
}
|
||||
$config['database_encryption'] = 'sha1';
|
||||
$config['database_encryption'] = $config['lua']['passwordType'];
|
||||
}
|
||||
else if(isset($config['lua']['database_type'])) // otserv
|
||||
{
|
||||
$config['otserv_version'] = OTSERV;
|
||||
$config['database_type'] = $config['lua']['database_type'];
|
||||
$config['database_host'] = $config['lua']['database_host'];
|
||||
$config['database_port'] = $config['lua']['database_port'];
|
||||
$config['database_user'] = $config['lua']['database_username'];
|
||||
$config['database_password'] = $config['lua']['database_password'];
|
||||
$config['database_name'] = $config['lua']['database_schema'];
|
||||
$config['database_encryption'] = isset($config['lua']['passwordtype']) ? $config['lua']['passwordtype'] : $config['lua']['password_type'];
|
||||
$config['database_salt'] = isset($config['lua']['passwordsalt']) ? $config['lua']['passwordsalt'] : $config['lua']['password_salt'];
|
||||
}
|
||||
else if(isset($config['lua']['sql_host'])) // otserv 0.6.3 / 0.6.4
|
||||
{
|
||||
$config['otserv_version'] = OTSERV_06;
|
||||
$config['database_type'] = $config['lua']['sql_type'];
|
||||
$config['database_host'] = $config['lua']['sql_host'];
|
||||
$config['database_port'] = $config['lua']['sql_port'];
|
||||
$config['database_user'] = $config['lua']['sql_user'];
|
||||
$config['database_password'] = $config['lua']['sql_pass'];
|
||||
$config['database_name'] = $config['lua']['sql_db'];
|
||||
$config['database_encryption'] = isset($config['lua']['passwordtype']) ? $config['lua']['passwordtype'] : $config['lua']['password_type'];
|
||||
$config['database_salt'] = isset($config['lua']['passwordsalt']) ? $config['lua']['passwordsalt'] : $config['lua']['password_salt'];
|
||||
else {
|
||||
$config['otserv_version'] = TFS_03;
|
||||
$config['database_type'] = $config['lua']['sqlType'];
|
||||
$config['database_host'] = $config['lua']['sqlHost'];
|
||||
$config['database_port'] = $config['lua']['sqlPort'];
|
||||
$config['database_user'] = $config['lua']['sqlUser'];
|
||||
$config['database_password'] = $config['lua']['sqlPass'];
|
||||
$config['database_name'] = $config['lua']['sqlDatabase'];
|
||||
|
||||
$config['database_encryption'] = $config['lua']['encryptionType'];
|
||||
if(!isset($config['database_encryption']) || empty($config['database_encryption'])) // before 0.3.6
|
||||
$config['database_encryption'] = $config['lua']['passwordType'];
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($config['lua']['useMD5Passwords']) && getBoolean($config['lua']['useMD5Passwords']))
|
||||
$config['database_encryption'] = 'md5';
|
||||
|
||||
if(!isset($config['database_log'])) {
|
||||
$config['database_log'] = false;
|
||||
}
|
||||
|
||||
if(!isset($config['database_socket'])) {
|
||||
$config['database_socket'] = '';
|
||||
}
|
||||
|
||||
try {
|
||||
$ots->connect(array(
|
||||
'host' => $config['database_host'],
|
||||
'user' => $config['database_user'],
|
||||
'password' => $config['database_password'],
|
||||
'database' => $config['database_name'],
|
||||
'log' => $config['database_log'],
|
||||
'socket' => @$config['database_socket'],
|
||||
'persistent' => @$config['database_persistent']
|
||||
)
|
||||
);
|
||||
|
||||
$db = POT::getInstance()->getDBHandle();
|
||||
}
|
||||
catch(PDOException $error) {
|
||||
if(isset($cache) && $cache->enabled()) {
|
||||
$cache->delete('config_lua');
|
||||
else if(isset($config['lua']['mysqlHost'])) // tfs 1.0
|
||||
{
|
||||
$config['otserv_version'] = TFS_02;
|
||||
$config['database_type'] = 'mysql';
|
||||
$config['database_host'] = $config['lua']['mysqlHost'];
|
||||
$config['database_port'] = $config['lua']['mysqlPort'];
|
||||
$config['database_user'] = $config['lua']['mysqlUser'];
|
||||
$config['database_password'] = $config['lua']['mysqlPass'];
|
||||
$config['database_name'] = $config['lua']['mysqlDatabase'];
|
||||
if(!isset($config['database_socket'][0])) {
|
||||
$config['database_socket'] = isset($config['lua']['mysqlSock']) ? trim($config['lua']['mysqlSock']) : '';
|
||||
}
|
||||
$config['database_encryption'] = 'sha1';
|
||||
}
|
||||
else if(isset($config['lua']['database_type'])) // otserv
|
||||
{
|
||||
$config['otserv_version'] = OTSERV;
|
||||
$config['database_type'] = $config['lua']['database_type'];
|
||||
$config['database_host'] = $config['lua']['database_host'];
|
||||
$config['database_port'] = $config['lua']['database_port'];
|
||||
$config['database_user'] = $config['lua']['database_username'];
|
||||
$config['database_password'] = $config['lua']['database_password'];
|
||||
$config['database_name'] = $config['lua']['database_schema'];
|
||||
$config['database_encryption'] = isset($config['lua']['passwordtype']) ? $config['lua']['passwordtype'] : $config['lua']['password_type'];
|
||||
$config['database_salt'] = isset($config['lua']['passwordsalt']) ? $config['lua']['passwordsalt'] : $config['lua']['password_salt'];
|
||||
}
|
||||
else if(isset($config['lua']['sql_host'])) // otserv 0.6.3 / 0.6.4
|
||||
{
|
||||
$config['otserv_version'] = OTSERV_06;
|
||||
$config['database_type'] = $config['lua']['sql_type'];
|
||||
$config['database_host'] = $config['lua']['sql_host'];
|
||||
$config['database_port'] = $config['lua']['sql_port'];
|
||||
$config['database_user'] = $config['lua']['sql_user'];
|
||||
$config['database_password'] = $config['lua']['sql_pass'];
|
||||
$config['database_name'] = $config['lua']['sql_db'];
|
||||
$config['database_encryption'] = isset($config['lua']['passwordtype']) ? $config['lua']['passwordtype'] : $config['lua']['password_type'];
|
||||
$config['database_salt'] = isset($config['lua']['passwordsalt']) ? $config['lua']['passwordsalt'] : $config['lua']['password_salt'];
|
||||
}
|
||||
}
|
||||
|
||||
if(defined('MYAAC_INSTALL')) {
|
||||
return; // installer will take care of this
|
||||
}
|
||||
if(isset($config['lua']['useMD5Passwords']) && getBoolean($config['lua']['useMD5Passwords']))
|
||||
$config['database_encryption'] = 'md5';
|
||||
|
||||
throw new RuntimeException('ERROR: Cannot connect to MySQL database.<br/>' .
|
||||
'Possible reasons:' .
|
||||
'<ul>' .
|
||||
'<li>MySQL is not configured propertly in <i>config.lua</i>.</li>' .
|
||||
'<li>MySQL server is not running.</li>' .
|
||||
'</ul>' . $error->getMessage());
|
||||
}
|
||||
if(!isset($config['database_log'])) {
|
||||
$config['database_log'] = false;
|
||||
}
|
||||
|
||||
if(!isset($config['database_socket'])) {
|
||||
$config['database_socket'] = '';
|
||||
}
|
||||
|
||||
try {
|
||||
$ots->connect(array(
|
||||
'host' => $config['database_host'],
|
||||
'user' => $config['database_user'],
|
||||
'password' => $config['database_password'],
|
||||
'database' => $config['database_name'],
|
||||
'log' => $config['database_log'],
|
||||
'socket' => @$config['database_socket'],
|
||||
'persistent' => @$config['database_persistent']
|
||||
)
|
||||
);
|
||||
|
||||
$db = POT::getInstance()->getDBHandle();
|
||||
}
|
||||
catch(PDOException $error) {
|
||||
if(isset($cache) && $cache->enabled()) {
|
||||
$cache->delete('config_lua');
|
||||
}
|
||||
|
||||
if(defined('MYAAC_INSTALL')) {
|
||||
return; // installer will take care of this
|
||||
}
|
||||
|
||||
throw new RuntimeException('ERROR: Cannot connect to MySQL database.<br/>' .
|
||||
'Possible reasons:' .
|
||||
'<ul>' .
|
||||
'<li>MySQL is not configured propertly in <i>config.lua</i>.</li>' .
|
||||
'<li>MySQL server is not running.</li>' .
|
||||
'</ul>' . $error->getMessage());
|
||||
}
|
||||
@@ -23,8 +23,6 @@ function exception_handler($exception) {
|
||||
|
||||
$backtrace_formatted = nl2br($exception->getTraceAsString());
|
||||
|
||||
$message = $message . "<br/><br/>File: {$exception->getFile()}<br/>Line: {$exception->getLine()}";
|
||||
|
||||
// display basic error message without template
|
||||
// template is missing, why? probably someone deleted templates dir, or it wasn't downloaded right
|
||||
$template_file = SYSTEM . 'templates/exception.html.twig';
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
* @copyright 2019 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use Twig\Loader\ArrayLoader as Twig_ArrayLoader;
|
||||
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
function message($message, $type, $return)
|
||||
{
|
||||
if(IS_CLI) {
|
||||
@@ -22,10 +24,12 @@ function message($message, $type, $return)
|
||||
return true;
|
||||
}
|
||||
|
||||
if($return)
|
||||
return '<div class="' . $type . '" style="margin-bottom:10px;">' . $message . '</div>';
|
||||
if($return) {
|
||||
// for install and admin pages use bootstrap classes
|
||||
return '<div class="' . ((defined('MYAAC_INSTALL') || defined('MYAAC_ADMIN')) ? 'alert alert-' : '') . $type . '" style="margin-bottom:10px;">' . $message . '</div>';
|
||||
}
|
||||
|
||||
echo '<div class="' . $type . '" style="margin-bottom:10px;">' . $message . '</div>';
|
||||
echo '<div class="' . ((defined('MYAAC_INSTALL') || defined('MYAAC_ADMIN')) ? 'alert alert-' : '') . $type . '" style="margin-bottom:10px;">' . $message . '</div>';
|
||||
return true;
|
||||
}
|
||||
function success($message, $return = false) {
|
||||
@@ -38,28 +42,9 @@ function note($message, $return = false) {
|
||||
return message($message, 'note', $return);
|
||||
}
|
||||
function error($message, $return = false) {
|
||||
return message($message, 'error', $return);
|
||||
return message($message, ((defined('MYAAC_INSTALL') || defined('MYAAC_ADMIN')) ? 'danger' : 'error'), $return);
|
||||
}
|
||||
function message1($head, $message, $type, $icon , $return)
|
||||
{//return '<div class="' . $type . '">' . $message . '</div>';
|
||||
if($return)
|
||||
return '<div class="alert alert-'.$type.' alert-dismissible"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button><h4><i class="icon fa fa-'.$icon.'"></i> '.$head.':</h4>'.$message.'</div>';
|
||||
|
||||
echo '<div class="alert alert-'.$type.' alert-dismissible"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button><h4><i class="icon fa fa-'.$icon.'"></i> '.$head.':</h4>'.$message.'</div>';
|
||||
return true;
|
||||
}
|
||||
function success1($message, $return = false) {
|
||||
return message('Info', $message, 'success','success', $return);
|
||||
}
|
||||
function warning1($message, $return = false) {
|
||||
return message('Warning',$message, 'warning','ban', $return);
|
||||
}
|
||||
function note1($message, $return = false) {
|
||||
return message('Info',$message, 'info','info', $return);
|
||||
}
|
||||
function error1($message, $return = false) {
|
||||
return message("Alert", $message, 'danger','check', $return);
|
||||
}
|
||||
function longToIp($ip)
|
||||
{
|
||||
$exp = explode(".", long2ip($ip));
|
||||
@@ -111,6 +96,16 @@ function getPlayerLink($name, $generate = true)
|
||||
return generateLink($url, $name);
|
||||
}
|
||||
|
||||
function getMonsterLink($name, $generate = true)
|
||||
{
|
||||
global $config;
|
||||
|
||||
$url = BASE_URL . ($config['friendly_urls'] ? '' : '?') . 'creatures/' . urlencode($name);
|
||||
|
||||
if(!$generate) return $url;
|
||||
return generateLink($url, $name);
|
||||
}
|
||||
|
||||
function getHouseLink($name, $generate = true)
|
||||
{
|
||||
global $db, $config;
|
||||
@@ -167,7 +162,24 @@ function getItemImage($id, $count = 1)
|
||||
$file_name .= '-' . $count;
|
||||
|
||||
global $config;
|
||||
return '<img src="' . $config['item_images_url'] . $file_name . '.gif"' . $tooltip . ' width="32" height="32" border="0" alt="' .$id . '" />';
|
||||
return '<img src="' . $config['item_images_url'] . $file_name . config('item_images_extension') . '"' . $tooltip . ' width="32" height="32" border="0" alt="' .$id . '" />';
|
||||
}
|
||||
|
||||
function getItemRarity($chance) {
|
||||
if ($chance >= 21) {
|
||||
return "common";
|
||||
} elseif (between($chance, 8, 21)) {
|
||||
return "uncommon";
|
||||
} elseif (between($chance, 1.1, 8)) {
|
||||
return "semi rare";
|
||||
} elseif (between($chance, 0.4, 1.1)) {
|
||||
return "rare";
|
||||
} elseif (between($chance, 0.8, 0.4)) {
|
||||
return "very rare";
|
||||
} elseif ($chance <= 0.8) {
|
||||
return "extremely rare";
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function getFlagImage($country)
|
||||
@@ -474,33 +486,16 @@ function template_place_holder($type)
|
||||
*/
|
||||
function template_header($is_admin = false)
|
||||
{
|
||||
global $title_full, $config;
|
||||
global $title_full, $config, $twig;
|
||||
$charset = isset($config['charset']) ? $config['charset'] : 'utf-8';
|
||||
|
||||
$ret = '
|
||||
<meta charset="' . $charset . '">
|
||||
<meta http-equiv="content-language" content="' . $config['language'] . '" />
|
||||
<meta http-equiv="content-type" content="text/html; charset=' . $charset . '" />';
|
||||
if(!$is_admin)
|
||||
$ret .= '
|
||||
<base href="' . BASE_URL . '" />
|
||||
<title>' . $title_full . '</title>';
|
||||
|
||||
$ret .= '
|
||||
<meta name="description" content="' . $config['meta_description'] . '" />
|
||||
<meta name="keywords" content="' . $config['meta_keywords'] . ', myaac, wodzaac" />
|
||||
<meta name="generator" content="MyAAC" />
|
||||
<link rel="stylesheet" type="text/css" href="' . BASE_URL . 'tools/css/messages.css" />
|
||||
<script type="text/javascript" src="' . BASE_URL . 'tools/js/jquery.min.js"></script>
|
||||
<noscript>
|
||||
<div class="warning" style="text-align: center; font-size: 14px;">Your browser does not support JavaScript or its disabled!<br/>
|
||||
Please turn it on, or be aware that some features on this website will not work correctly.</div>
|
||||
</noscript>
|
||||
';
|
||||
|
||||
if($config['recaptcha_enabled'])
|
||||
$ret .= "<script src='https://www.google.com/recaptcha/api.js'></script>";
|
||||
return $ret;
|
||||
return $twig->render('templates.header.html.twig',
|
||||
[
|
||||
'charset' => $charset,
|
||||
'title' => $title_full,
|
||||
'is_admin' => $is_admin
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,10 +562,8 @@ function template_form()
|
||||
foreach($templates as $key => $value)
|
||||
$options .= '<option ' . ($template_name == $value ? 'SELECTED' : '') . '>' . $value . '</option>';
|
||||
|
||||
return '<form method="get" action="' . BASE_URL . '">
|
||||
<hidden name="subtopic" value="' . PAGE . '"/>
|
||||
<select name="template" onchange="this.form.submit()">' . $options . '</select>
|
||||
</form>';
|
||||
global $twig;
|
||||
return $twig->render('forms.change_template.html.twig', ['options' => $options]);
|
||||
}
|
||||
|
||||
function getStyle($i)
|
||||
@@ -756,10 +749,10 @@ function get_browser_languages()
|
||||
{
|
||||
$ret = array();
|
||||
|
||||
if(empty($_SERVER['HTTP_ACCEPT_LANGUAGE']))
|
||||
$acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
|
||||
if(!isset($acceptLang[0]))
|
||||
return $ret;
|
||||
|
||||
$acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
|
||||
$languages = strtolower($acceptLang);
|
||||
// $languages = 'pl,en-us;q=0.7,en;q=0.3 ';
|
||||
// need to remove spaces from strings to avoid error
|
||||
@@ -797,7 +790,7 @@ function get_plugins()
|
||||
$ret = array();
|
||||
|
||||
$path = PLUGINS;
|
||||
foreach(scandir($path, SCANDIR_SORT_ASCENDING) as $file) {
|
||||
foreach(scandir($path, 0) as $file) {
|
||||
$file_ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
$file_name = pathinfo($file, PATHINFO_FILENAME);
|
||||
if ($file === '.' || $file === '..' || $file === 'disabled' || $file === 'example.json' || $file_ext !== 'json' || is_dir($path . $file))
|
||||
@@ -829,13 +822,16 @@ function getWorldName($id)
|
||||
*/
|
||||
function _mail($to, $subject, $body, $altBody = '', $add_html_tags = true)
|
||||
{
|
||||
/** @var PHPMailer $mailer */
|
||||
global $mailer, $config;
|
||||
|
||||
if (!config('mail_enabled')) {
|
||||
log_append('mailer-error.log', '_mail() function has been used, but config.mail_enabled is disabled.');
|
||||
}
|
||||
|
||||
if(!$mailer)
|
||||
{
|
||||
require SYSTEM . 'libs/phpmailer/PHPMailerAutoload.php';
|
||||
$mailer = new PHPMailer();
|
||||
$mailer->setLanguage('en', LIBS . 'phpmailer/language/');
|
||||
//$mailer->setLanguage('en', LIBS . 'phpmailer/language/');
|
||||
}
|
||||
else {
|
||||
$mailer->clearAllRecipients();
|
||||
@@ -923,8 +919,8 @@ function load_config_lua($filename)
|
||||
$config_file = $filename;
|
||||
if(!@file_exists($config_file))
|
||||
{
|
||||
log_append('error.log', '[load_config_file] Fatal error: Cannot load config.lua (' . $filename . ').');
|
||||
throw new RuntimeException('ERROR: Cannot find ' . $filename . ' file.');
|
||||
log_append('error.log', '[load_config_file] Fatal error: Cannot load config.lua (' . $filename . '). Error: ' . print_r(error_get_last(), true));
|
||||
throw new RuntimeException('ERROR: Cannot find ' . $filename . ' file. More info in system/logs/error.log');
|
||||
}
|
||||
|
||||
$result = array();
|
||||
@@ -1243,35 +1239,246 @@ function getCustomPage($page, &$success)
|
||||
return $content;
|
||||
}
|
||||
|
||||
function escapeHtml($html) {
|
||||
return htmlentities($html, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
}
|
||||
|
||||
function displayErrorBoxWithBackButton($errors, $action = null) {
|
||||
global $twig;
|
||||
$twig->display('error_box.html.twig', ['errors' => $errors]);
|
||||
$twig->display('account.back_button.html.twig', [
|
||||
'action' => $action ?: getLink('')
|
||||
]);
|
||||
}
|
||||
|
||||
function getDatabasePages($withHidden = false): array
|
||||
function getBanReason($reasonId)
|
||||
{
|
||||
global $db, $logged_access;
|
||||
|
||||
if (!isset($logged_access)) {
|
||||
$logged_access = 1;
|
||||
switch($reasonId)
|
||||
{
|
||||
case 0:
|
||||
return "Offensive Name";
|
||||
case 1:
|
||||
return "Invalid Name Format";
|
||||
case 2:
|
||||
return "Unsuitable Name";
|
||||
case 3:
|
||||
return "Name Inciting Rule Violation";
|
||||
case 4:
|
||||
return "Offensive Statement";
|
||||
case 5:
|
||||
return "Spamming";
|
||||
case 6:
|
||||
return "Illegal Advertising";
|
||||
case 7:
|
||||
return "Off-Topic Public Statement";
|
||||
case 8:
|
||||
return "Non-English Public Statement";
|
||||
case 9:
|
||||
return "Inciting Rule Violation";
|
||||
case 10:
|
||||
return "Bug Abuse";
|
||||
case 11:
|
||||
return "Game Weakness Abuse";
|
||||
case 12:
|
||||
return "Using Unofficial Software to Play";
|
||||
case 13:
|
||||
return "Hacking";
|
||||
case 14:
|
||||
return "Multi-Clienting";
|
||||
case 15:
|
||||
return "Account Trading or Sharing";
|
||||
case 16:
|
||||
return "Threatening Gamemaster";
|
||||
case 17:
|
||||
return "Pretending to Have Influence on Rule Enforcement";
|
||||
case 18:
|
||||
return "False Report to Gamemaster";
|
||||
case 19:
|
||||
return "Destructive Behaviour";
|
||||
case 20:
|
||||
return "Excessive Unjustified Player Killing";
|
||||
case 21:
|
||||
return "Invalid Payment";
|
||||
case 22:
|
||||
return "Spoiling Auction";
|
||||
}
|
||||
|
||||
$pages = $db->query('SELECT `name` FROM ' . TABLE_PREFIX . 'pages WHERE ' . ($withHidden ? '' : '`hidden` != 1 AND ') . '`access` <= ' . $db->quote($logged_access));
|
||||
$ret = [];
|
||||
return "Unknown Reason";
|
||||
}
|
||||
|
||||
if ($pages->rowCount() < 1) {
|
||||
return $ret;
|
||||
function getBanType($typeId)
|
||||
{
|
||||
switch($typeId)
|
||||
{
|
||||
case 1:
|
||||
return "IP Banishment";
|
||||
case 2:
|
||||
return "Namelock";
|
||||
case 3:
|
||||
return "Banishment";
|
||||
case 4:
|
||||
return "Notation";
|
||||
case 5:
|
||||
return "Deletion";
|
||||
}
|
||||
|
||||
foreach($pages->fetchAll() as $page) {
|
||||
$ret[] = $page['name'];
|
||||
return "Unknown Type";
|
||||
}
|
||||
|
||||
function getChangelogType($v)
|
||||
{
|
||||
switch($v) {
|
||||
case 1:
|
||||
return 'added';
|
||||
case 2:
|
||||
return 'removed';
|
||||
case 3:
|
||||
return 'changed';
|
||||
case 4:
|
||||
return 'fixed';
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
function getChangelogWhere($v)
|
||||
{
|
||||
switch($v) {
|
||||
case 1:
|
||||
return 'server';
|
||||
case 2:
|
||||
return 'website';
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
function getPlayerNameByAccount($id)
|
||||
{
|
||||
global $vowels, $ots, $db;
|
||||
if(is_numeric($id))
|
||||
{
|
||||
$player = new OTS_Player();
|
||||
$player->load($id);
|
||||
if($player->isLoaded())
|
||||
return $player->getName();
|
||||
else
|
||||
{
|
||||
$playerQuery = $db->query('SELECT `id` FROM `players` WHERE `account_id` = ' . $id . ' ORDER BY `lastlogin` DESC LIMIT 1;')->fetch();
|
||||
|
||||
$tmp = "*Error*";
|
||||
/*
|
||||
$acco = new OTS_Account();
|
||||
$acco->load($id);
|
||||
if(!$acco->isLoaded())
|
||||
return "Unknown name";
|
||||
|
||||
foreach($acco->getPlayersList() as $p)
|
||||
{
|
||||
$player= new OTS_Player();
|
||||
$player->find($p);*/
|
||||
$player->load($playerQuery['id']);
|
||||
//echo 'id gracza = ' . $p . '<br/>';
|
||||
if($player->isLoaded())
|
||||
$tmp = $player->getName();
|
||||
// break;
|
||||
//}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function echo_success($message)
|
||||
{
|
||||
echo '<div class="col-12 success mb-2">' . $message . '</div>';
|
||||
}
|
||||
|
||||
function echo_error($message)
|
||||
{
|
||||
global $error;
|
||||
echo '<div class="col-12 error mb-2">' . $message . '</div>';
|
||||
$error = true;
|
||||
}
|
||||
|
||||
function verify_number($number, $name, $max_length)
|
||||
{
|
||||
if (!Validator::number($number))
|
||||
echo_error($name . ' can contain only numbers.');
|
||||
|
||||
$number_length = strlen($number);
|
||||
if ($number_length <= 0 || $number_length > $max_length)
|
||||
echo_error($name . ' cannot be longer than ' . $max_length . ' digits.');
|
||||
}
|
||||
|
||||
function Outfits_loadfromXML()
|
||||
{
|
||||
global $config;
|
||||
$file_path = $config['data_path'] . 'XML/outfits.xml';
|
||||
if (!file_exists($file_path)) { return null; }
|
||||
|
||||
$xml = new DOMDocument;
|
||||
$xml->load($file_path);
|
||||
|
||||
$outfits = null;
|
||||
foreach ($xml->getElementsByTagName('outfit') as $outfit) {
|
||||
$outfits[] = Outfit_parseNode($outfit);
|
||||
}
|
||||
return $outfits;
|
||||
}
|
||||
|
||||
function Outfit_parseNode($node) {
|
||||
$looktype = (int)$node->getAttribute('looktype');
|
||||
$type = (int)$node->getAttribute('type');
|
||||
$lookname = $node->getAttribute('name');
|
||||
$premium = $node->getAttribute('premium');
|
||||
$unlocked = $node->getAttribute('unlocked');
|
||||
$enabled = $node->getAttribute('enabled');
|
||||
return array('id' => $looktype, 'type' => $type, 'name' => $lookname, 'premium' => $premium, 'unlocked' => $unlocked, 'enabled' => $enabled);
|
||||
}
|
||||
|
||||
function left($str, $length) {
|
||||
return substr($str, 0, $length);
|
||||
}
|
||||
|
||||
function right($str, $length) {
|
||||
return substr($str, -$length);
|
||||
}
|
||||
|
||||
function getCreatureImgPath($creature){
|
||||
$creature_path = config('creatures_images_url');
|
||||
$creature_gfx_name = trim(strtolower($creature)) . config('creatures_images_extension');
|
||||
if (!file_exists($creature_path . $creature_gfx_name)) {
|
||||
$creature_gfx_name = str_replace(" ", "", $creature_gfx_name);
|
||||
if (file_exists($creature_path . $creature_gfx_name)) {
|
||||
return $creature_path . $creature_gfx_name;
|
||||
} else {
|
||||
return $creature_path . 'nophoto.png';
|
||||
}
|
||||
} else {
|
||||
return $creature_path . $creature_gfx_name;
|
||||
}
|
||||
}
|
||||
|
||||
function between($x, $lim1, $lim2) {
|
||||
if ($lim1 < $lim2) {
|
||||
$lower = $lim1; $upper = $lim2;
|
||||
}
|
||||
else {
|
||||
$lower = $lim2; $upper = $lim1;
|
||||
}
|
||||
return (($x >= $lower) && ($x <= $upper));
|
||||
}
|
||||
|
||||
function truncate($string, $length)
|
||||
{
|
||||
if (strlen($string) > $length) {
|
||||
$string = substr($string, 0, $length) . '...';
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
function getAccountLoginByLabel()
|
||||
{
|
||||
$ret = '';
|
||||
if (config('account_login_by_email')) {
|
||||
$ret = 'Email Address';
|
||||
if (config('account_login_by_email_fallback')) {
|
||||
$ret .= ' or ';
|
||||
}
|
||||
}
|
||||
|
||||
if (!config('account_login_by_email') || config('account_login_by_email_fallback')) {
|
||||
$ret .= 'Account ' . (USE_ACCOUNT_NAME ? 'Name' : 'Number');
|
||||
}
|
||||
|
||||
return $ret;
|
||||
@@ -1280,3 +1487,6 @@ function getDatabasePages($withHidden = false): array
|
||||
// validator functions
|
||||
require_once LIBS . 'validator.php';
|
||||
require_once SYSTEM . 'compat/base.php';
|
||||
|
||||
// custom functions
|
||||
require SYSTEM . 'functions_custom.php';
|
||||
|
||||
11
system/functions_custom.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* Custom functions
|
||||
*
|
||||
* @package MyAAC
|
||||
* @author Slawkens <slawkens@gmail.com>, Lee
|
||||
* @copyright 2020 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
|
||||
// Insert your custom functions here.
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/../common.php';
|
||||
if (IS_CLI) {
|
||||
if(IS_CLI) {
|
||||
echo MYAAC_VERSION;
|
||||
}
|
||||
|
||||
@@ -49,9 +49,8 @@ define('HOOK_ACCOUNT_CREATE_AFTER_TOWNS', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_SUBMIT_BUTTON', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_FORM', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_SUBMIT', ++$i);
|
||||
define('HOOK_EMAIL_CONFIRMED', ++$i);
|
||||
define('HOOK_FIRST', HOOK_STARTUP);
|
||||
define('HOOK_LAST', HOOK_EMAIL_CONFIRMED);
|
||||
define('HOOK_LAST', HOOK_ACCOUNT_CREATE_AFTER_SUBMIT);
|
||||
|
||||
require_once LIBS . 'plugins.php';
|
||||
class Hook
|
||||
@@ -74,7 +73,9 @@ class Hook
|
||||
}*/
|
||||
|
||||
global $db, $config, $template_path, $ots, $content, $twig;
|
||||
$ret = include BASE . $this->_file;
|
||||
if(file_exists(BASE . $this->_file)) {
|
||||
$ret = require BASE . $this->_file;
|
||||
}
|
||||
|
||||
return !isset($ret) || $ret == 1 || $ret;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ if($config['gzip_output'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($
|
||||
require_once SYSTEM . 'libs/cache.php';
|
||||
$cache = Cache::getInstance();
|
||||
|
||||
// twig
|
||||
require_once SYSTEM . 'twig.php';
|
||||
|
||||
// trim values we receive
|
||||
if(isset($_POST))
|
||||
{
|
||||
@@ -111,7 +114,7 @@ if(!isset($foundValue)) {
|
||||
$config['data_path'] = $foundValue;
|
||||
unset($foundValue);
|
||||
|
||||
// new config values for compatibility
|
||||
// new config values for compability
|
||||
if(!isset($config['highscores_ids_hidden']) || count($config['highscores_ids_hidden']) == 0) {
|
||||
$config['highscores_ids_hidden'] = array(0);
|
||||
}
|
||||
@@ -123,10 +126,9 @@ require_once SYSTEM . 'libs/pot/OTS.php';
|
||||
$ots = POT::getInstance();
|
||||
require_once SYSTEM . 'database.php';
|
||||
|
||||
// twig
|
||||
require_once SYSTEM . 'twig.php';
|
||||
|
||||
define('USE_ACCOUNT_NAME', $db->hasColumn('accounts', 'name'));
|
||||
define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number'));
|
||||
|
||||
// load vocation names
|
||||
$tmp = '';
|
||||
if($cache->enabled() && $cache->fetch('vocations', $tmp)) {
|
||||
@@ -157,54 +159,5 @@ else {
|
||||
}
|
||||
unset($tmp, $id, $vocation);
|
||||
|
||||
// load towns
|
||||
/* TODO: doesnt work
|
||||
ini_set('memory_limit', '-1');
|
||||
$tmp = '';
|
||||
|
||||
if($cache->enabled() && $cache->fetch('towns', $tmp)) {
|
||||
$config['towns'] = unserialize($tmp);
|
||||
}
|
||||
else {
|
||||
$towns = new OTS_OTBMFile();
|
||||
$towns->loadFile('D:/Projekty/opentibia/wodzislawski/data/world/wodzislawski.otbm');
|
||||
|
||||
$config['towns'] = $towns->getTownsList();
|
||||
if($cache->enabled()) {
|
||||
$cache->set('towns', serialize($config['towns']), 120);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
////////////////////////////////////////
|
||||
// load towns from database (TFS 1.3) //
|
||||
////////////////////////////////////////
|
||||
|
||||
$tmp = '';
|
||||
$towns = [];
|
||||
if($cache->enabled() && $cache->fetch('towns', $tmp)) {
|
||||
$towns = unserialize($tmp);
|
||||
}
|
||||
else {
|
||||
if($db->hasTable('towns')) {
|
||||
$query = $db->query('SELECT `id`, `name` FROM `towns`;')->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach($query as $town) {
|
||||
$towns[$town['id']] = $town['name'];
|
||||
}
|
||||
|
||||
unset($query);
|
||||
}
|
||||
else {
|
||||
$towns = config('towns');
|
||||
}
|
||||
|
||||
if($cache->enabled()) {
|
||||
$cache->set('towns', serialize($towns), 600);
|
||||
}
|
||||
}
|
||||
|
||||
config(['towns', $towns]);
|
||||
//////////////////////////////////////////////
|
||||
// END - load towns from database (TFS 1.3) //
|
||||
//////////////////////////////////////////////
|
||||
require LIBS . 'Towns.php';
|
||||
Towns::load();
|
||||
|
||||
@@ -58,3 +58,4 @@ function outputItem($id = 100, $count = 1)
|
||||
$file_name = Items_Images::$outputDir . $file_name . '.gif';
|
||||
readfile($file_name);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -138,7 +138,7 @@ class CreateCharacter
|
||||
|
||||
if(empty($errors))
|
||||
{
|
||||
$number_of_players_on_account = $account->getPlayersList(true)->count();
|
||||
$number_of_players_on_account = $account->getPlayersList(false)->count();
|
||||
if($number_of_players_on_account >= config('characters_per_account'))
|
||||
$errors[] = 'You have too many characters on your account <b>('.$number_of_players_on_account.'/'.config('characters_per_account').')</b>!';
|
||||
}
|
||||
@@ -239,7 +239,6 @@ class CreateCharacter
|
||||
}
|
||||
|
||||
if($db->hasTable('player_skills')) {
|
||||
|
||||
for($i=0; $i<7; $i++) {
|
||||
$value = 10;
|
||||
if (config('use_character_sample_skills')) {
|
||||
@@ -252,12 +251,10 @@ class CreateCharacter
|
||||
}
|
||||
}
|
||||
|
||||
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 = ".$char_to_copy->getId()."");
|
||||
foreach($loaded_items_to_copy as $save_item) {
|
||||
$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);");
|
||||
}
|
||||
$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) {
|
||||
$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);");
|
||||
}
|
||||
|
||||
global $twig;
|
||||
|
||||
113
system/libs/DataLoader.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class DataLoader
|
||||
*/
|
||||
class DataLoader
|
||||
{
|
||||
private static $locale;
|
||||
private static $startTime;
|
||||
|
||||
/**
|
||||
* Load data from server
|
||||
*/
|
||||
public static function load()
|
||||
{
|
||||
self::$startTime = microtime(true);
|
||||
|
||||
require LIBS . 'items.php';
|
||||
if(Items::loadFromXML()) {
|
||||
success(self::$locale['step_database_loaded_items'] . self::getLoadedTime());
|
||||
}
|
||||
else {
|
||||
error(Items::getError());
|
||||
}
|
||||
|
||||
self::$startTime = microtime(true);
|
||||
|
||||
require LIBS . 'creatures.php';
|
||||
if(Creatures::loadFromXML()) {
|
||||
success(self::$locale['step_database_loaded_monsters'] . self::getLoadedTime());
|
||||
|
||||
if(Creatures::getMonstersList()->hasErrors()) {
|
||||
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']);
|
||||
}
|
||||
}
|
||||
else {
|
||||
error(Creatures::getLastError());
|
||||
}
|
||||
|
||||
self::$startTime = microtime(true);
|
||||
|
||||
require_once LIBS . 'npc.php';
|
||||
if(NPCs::loadFromXML()) {
|
||||
success(self::$locale['step_database_loaded_npcs'] . self::getLoadedTime());
|
||||
}
|
||||
else {
|
||||
error(self::$locale['step_database_error_npcs']);
|
||||
}
|
||||
|
||||
self::$startTime = microtime(true);
|
||||
|
||||
require LIBS . 'spells.php';
|
||||
if(Spells::loadFromXML()) {
|
||||
success(self::$locale['step_database_loaded_spells'] . self::getLoadedTime());
|
||||
}
|
||||
else {
|
||||
error(Spells::getLastError());
|
||||
}
|
||||
|
||||
self::$startTime = microtime(true);
|
||||
|
||||
if (Towns::save()) {
|
||||
success(self::$locale['step_database_loaded_towns'] . self::getLoadedTime());
|
||||
}
|
||||
else {
|
||||
warning(self::$locale['step_database_error_towns']);
|
||||
}
|
||||
|
||||
self::$startTime = microtime(true);
|
||||
|
||||
require LIBS . 'weapons.php';
|
||||
if(Weapons::loadFromXML()) {
|
||||
success(self::$locale['step_database_loaded_weapons'] . self::getLoadedTime());
|
||||
}
|
||||
else {
|
||||
error(Weapons::getError());
|
||||
}
|
||||
}
|
||||
|
||||
public static function setLocale($locale) {
|
||||
self::$locale = $locale;
|
||||
}
|
||||
|
||||
private static function getLoadedTime()
|
||||
{
|
||||
$endTime = round(microtime(true) - self::$startTime, 3);
|
||||
return ' (' . str_replace('$TIME$', $endTime, self::$locale['loaded_in_ms']) . ')';
|
||||
}
|
||||
}
|
||||
84
system/libs/GoogleReCAPTCHA.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
class GoogleReCAPTCHA
|
||||
{
|
||||
private static $errorMessage = '';
|
||||
private static $errorType;
|
||||
|
||||
const ERROR_MISSING_RESPONSE = 1;
|
||||
const ERROR_INVALID_ACTION = 2;
|
||||
const ERROR_LOW_SCORE = 3;
|
||||
const ERROR_NO_SUCCESS = 4;
|
||||
|
||||
public static function verify($action = '')
|
||||
{
|
||||
if (!isset($_POST['g-recaptcha-response']) || empty($_POST['g-recaptcha-response'])) {
|
||||
self::$errorType = self::ERROR_MISSING_RESPONSE;
|
||||
self::$errorMessage = "Please confirm that you're not a robot.";
|
||||
return false;
|
||||
}
|
||||
|
||||
$recaptchaApiUrl = 'https://www.google.com/recaptcha/api/siteverify';
|
||||
$secretKey = config('recaptcha_secret_key');
|
||||
|
||||
$recaptchaResponse = $_POST['g-recaptcha-response'];
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
$params = 'secret='.$secretKey.'&response='.$recaptchaResponse.'&remoteip='.$ip;
|
||||
|
||||
if (function_exists('curl_version')) {
|
||||
$curl_connection = curl_init($recaptchaApiUrl);
|
||||
|
||||
curl_setopt($curl_connection, CURLOPT_CONNECTTIMEOUT, 5);
|
||||
curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl_connection, CURLOPT_FOLLOWLOCATION, 0);
|
||||
curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $params);
|
||||
|
||||
$response = curl_exec($curl_connection);
|
||||
curl_close($curl_connection);
|
||||
} else {
|
||||
$response = file_get_contents($recaptchaApiUrl . '?' . $params);
|
||||
}
|
||||
|
||||
$json = json_decode($response);
|
||||
|
||||
$recaptchaType = config('recaptcha_type');
|
||||
if ($recaptchaType === 'v3') { // score based
|
||||
//log_append('recaptcha.log', 'recaptcha_score: ' . $json->score . ', action:' . $json->action);
|
||||
|
||||
if (!isset($json->action) || $json->action !== $action) {
|
||||
self::$errorType = self::ERROR_INVALID_ACTION;
|
||||
self::$errorMessage = 'Google ReCaptcha returned invalid action.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($json->score) || $json->score < config('recaptcha_v3_min_score')) {
|
||||
self::$errorType = self::ERROR_LOW_SCORE;
|
||||
self::$errorMessage = 'Your Google ReCaptcha score was too low.';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($json->success) || !$json->success) {
|
||||
self::$errorType = self::ERROR_NO_SUCCESS;
|
||||
self::$errorMessage = "Please confirm that you're not a robot.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getErrorMessage() {
|
||||
return self::$errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public static function getErrorType() {
|
||||
return self::$errorType;
|
||||
}
|
||||
}
|
||||
138
system/libs/Towns.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
global $db;
|
||||
|
||||
$query = $db->query('SELECT `id`, `name` FROM `towns`;')->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$towns = [];
|
||||
foreach($query as $town) {
|
||||
$towns[$town['id']] = $town['name'];
|
||||
}
|
||||
|
||||
return $towns;
|
||||
}
|
||||
}
|
||||
82
system/libs/TownsReader.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Autoloads Twig classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since 1.21 and will be removed in 2.0. Use Composer instead. 2.0.
|
||||
*/
|
||||
class Twig_Autoloader
|
||||
{
|
||||
/**
|
||||
* Registers Twig_Autoloader as an SPL autoloader.
|
||||
*
|
||||
* @param bool $prepend whether to prepend the autoloader or not
|
||||
*/
|
||||
public static function register($prepend = false)
|
||||
{
|
||||
if (PHP_VERSION_ID < 50300) {
|
||||
spl_autoload_register(array(__CLASS__, 'autoload'));
|
||||
} else {
|
||||
spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles autoloading of classes.
|
||||
*
|
||||
* @param string $class a class name
|
||||
*/
|
||||
public static function autoload($class)
|
||||
{
|
||||
if (0 !== strpos($class, 'Twig')) {// || !isset($class[0])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$file = __DIR__.'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php';
|
||||
|
||||
$dev_mode = (config('env') === 'dev');
|
||||
if($dev_mode && !is_file($file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
require $file;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Cache;
|
||||
|
||||
/**
|
||||
* Interface implemented by cache classes.
|
||||
*
|
||||
* It is highly recommended to always store templates on the filesystem to
|
||||
* benefit from the PHP opcode cache. This interface is mostly useful if you
|
||||
* need to implement a custom strategy for storing templates on the filesystem.
|
||||
*
|
||||
* @author Andrew Tch <andrew@noop.lv>
|
||||
*/
|
||||
interface CacheInterface
|
||||
{
|
||||
/**
|
||||
* Generates a cache key for the given template class name.
|
||||
*
|
||||
* @param string $name The template name
|
||||
* @param string $className The template class name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generateKey($name, $className);
|
||||
|
||||
/**
|
||||
* Writes the compiled template to cache.
|
||||
*
|
||||
* @param string $key The cache key
|
||||
* @param string $content The template representation as a PHP class
|
||||
*/
|
||||
public function write($key, $content);
|
||||
|
||||
/**
|
||||
* Loads a template from the cache.
|
||||
*
|
||||
* @param string $key The cache key
|
||||
*/
|
||||
public function load($key);
|
||||
|
||||
/**
|
||||
* Returns the modification timestamp of a key.
|
||||
*
|
||||
* @param string $key The cache key
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTimestamp($key);
|
||||
}
|
||||
|
||||
class_alias('Twig\Cache\CacheInterface', 'Twig_CacheInterface');
|
||||
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Cache;
|
||||
|
||||
/**
|
||||
* Implements a cache on the filesystem.
|
||||
*
|
||||
* @author Andrew Tch <andrew@noop.lv>
|
||||
*/
|
||||
class FilesystemCache implements CacheInterface
|
||||
{
|
||||
public const FORCE_BYTECODE_INVALIDATION = 1;
|
||||
|
||||
private $directory;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @param string $directory The root cache directory
|
||||
* @param int $options A set of options
|
||||
*/
|
||||
public function __construct($directory, $options = 0)
|
||||
{
|
||||
$this->directory = rtrim($directory, '\/').'/';
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
public function generateKey($name, $className)
|
||||
{
|
||||
$hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $className);
|
||||
|
||||
return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
|
||||
}
|
||||
|
||||
public function load($key)
|
||||
{
|
||||
if (file_exists($key)) {
|
||||
@include_once $key;
|
||||
}
|
||||
}
|
||||
|
||||
public function write($key, $content)
|
||||
{
|
||||
$dir = \dirname($key);
|
||||
if (!is_dir($dir)) {
|
||||
if (false === @mkdir($dir, 0777, true)) {
|
||||
clearstatcache(true, $dir);
|
||||
if (!is_dir($dir)) {
|
||||
throw new \RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
|
||||
}
|
||||
}
|
||||
} elseif (!is_writable($dir)) {
|
||||
throw new \RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
|
||||
}
|
||||
|
||||
$tmpFile = tempnam($dir, basename($key));
|
||||
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) {
|
||||
@chmod($key, 0666 & ~umask());
|
||||
|
||||
if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) {
|
||||
// Compile cached file into bytecode cache
|
||||
if (\function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN)) {
|
||||
@opcache_invalidate($key, true);
|
||||
} elseif (\function_exists('apc_compile_file')) {
|
||||
apc_compile_file($key);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $key));
|
||||
}
|
||||
|
||||
public function getTimestamp($key)
|
||||
{
|
||||
if (!file_exists($key)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) @filemtime($key);
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Cache\FilesystemCache', 'Twig_Cache_Filesystem');
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Cache;
|
||||
|
||||
/**
|
||||
* Implements a no-cache strategy.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
final class NullCache implements CacheInterface
|
||||
{
|
||||
public function generateKey($name, $className)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function write($key, $content)
|
||||
{
|
||||
}
|
||||
|
||||
public function load($key)
|
||||
{
|
||||
}
|
||||
|
||||
public function getTimestamp($key)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Cache\NullCache', 'Twig_Cache_Null');
|
||||
@@ -1,245 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
* (c) Armin Ronacher
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig;
|
||||
|
||||
use Twig\Node\Node;
|
||||
|
||||
/**
|
||||
* Compiles a node to PHP code.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Compiler
|
||||
{
|
||||
private $lastLine;
|
||||
private $source;
|
||||
private $indentation;
|
||||
private $env;
|
||||
private $debugInfo = [];
|
||||
private $sourceOffset;
|
||||
private $sourceLine;
|
||||
private $varNameSalt = 0;
|
||||
|
||||
public function __construct(Environment $env)
|
||||
{
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the environment instance related to this compiler.
|
||||
*
|
||||
* @return Environment
|
||||
*/
|
||||
public function getEnvironment()
|
||||
{
|
||||
return $this->env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current PHP code after compilation.
|
||||
*
|
||||
* @return string The PHP code
|
||||
*/
|
||||
public function getSource()
|
||||
{
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles a node.
|
||||
*
|
||||
* @param int $indentation The current indentation
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function compile(Node $node, $indentation = 0)
|
||||
{
|
||||
$this->lastLine = null;
|
||||
$this->source = '';
|
||||
$this->debugInfo = [];
|
||||
$this->sourceOffset = 0;
|
||||
// source code starts at 1 (as we then increment it when we encounter new lines)
|
||||
$this->sourceLine = 1;
|
||||
$this->indentation = $indentation;
|
||||
$this->varNameSalt = 0;
|
||||
|
||||
$node->compile($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function subcompile(Node $node, $raw = true)
|
||||
{
|
||||
if (false === $raw) {
|
||||
$this->source .= str_repeat(' ', $this->indentation * 4);
|
||||
}
|
||||
|
||||
$node->compile($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a raw string to the compiled code.
|
||||
*
|
||||
* @param string $string The string
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function raw($string)
|
||||
{
|
||||
$this->source .= $string;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a string to the compiled code by adding indentation.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function write(...$strings)
|
||||
{
|
||||
foreach ($strings as $string) {
|
||||
$this->source .= str_repeat(' ', $this->indentation * 4).$string;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a quoted string to the compiled code.
|
||||
*
|
||||
* @param string $value The string
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function string($value)
|
||||
{
|
||||
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PHP representation of a given value.
|
||||
*
|
||||
* @param mixed $value The value to convert
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function repr($value)
|
||||
{
|
||||
if (\is_int($value) || \is_float($value)) {
|
||||
if (false !== $locale = setlocale(\LC_NUMERIC, '0')) {
|
||||
setlocale(\LC_NUMERIC, 'C');
|
||||
}
|
||||
|
||||
$this->raw(var_export($value, true));
|
||||
|
||||
if (false !== $locale) {
|
||||
setlocale(\LC_NUMERIC, $locale);
|
||||
}
|
||||
} elseif (null === $value) {
|
||||
$this->raw('null');
|
||||
} elseif (\is_bool($value)) {
|
||||
$this->raw($value ? 'true' : 'false');
|
||||
} elseif (\is_array($value)) {
|
||||
$this->raw('array(');
|
||||
$first = true;
|
||||
foreach ($value as $key => $v) {
|
||||
if (!$first) {
|
||||
$this->raw(', ');
|
||||
}
|
||||
$first = false;
|
||||
$this->repr($key);
|
||||
$this->raw(' => ');
|
||||
$this->repr($v);
|
||||
}
|
||||
$this->raw(')');
|
||||
} else {
|
||||
$this->string($value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds debugging information.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addDebugInfo(Node $node)
|
||||
{
|
||||
if ($node->getTemplateLine() != $this->lastLine) {
|
||||
$this->write(sprintf("// line %d\n", $node->getTemplateLine()));
|
||||
|
||||
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
|
||||
$this->sourceOffset = \strlen($this->source);
|
||||
$this->debugInfo[$this->sourceLine] = $node->getTemplateLine();
|
||||
|
||||
$this->lastLine = $node->getTemplateLine();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDebugInfo()
|
||||
{
|
||||
ksort($this->debugInfo);
|
||||
|
||||
return $this->debugInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indents the generated code.
|
||||
*
|
||||
* @param int $step The number of indentation to add
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function indent($step = 1)
|
||||
{
|
||||
$this->indentation += $step;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outdents the generated code.
|
||||
*
|
||||
* @param int $step The number of indentation to remove
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws \LogicException When trying to outdent too much so the indentation would become negative
|
||||
*/
|
||||
public function outdent($step = 1)
|
||||
{
|
||||
// can't outdent by more steps than the current indentation level
|
||||
if ($this->indentation < $step) {
|
||||
throw new \LogicException('Unable to call outdent() as the indentation would become negative.');
|
||||
}
|
||||
|
||||
$this->indentation -= $step;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVarName()
|
||||
{
|
||||
return sprintf('__internal_compile_%d', $this->varNameSalt++);
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Compiler', 'Twig_Compiler');
|
||||
@@ -1,994 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig;
|
||||
|
||||
use Twig\Cache\CacheInterface;
|
||||
use Twig\Cache\FilesystemCache;
|
||||
use Twig\Cache\NullCache;
|
||||
use Twig\Error\Error;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Error\RuntimeError;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\Extension\CoreExtension;
|
||||
use Twig\Extension\EscaperExtension;
|
||||
use Twig\Extension\ExtensionInterface;
|
||||
use Twig\Extension\OptimizerExtension;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
use Twig\Loader\ChainLoader;
|
||||
use Twig\Loader\LoaderInterface;
|
||||
use Twig\Node\ModuleNode;
|
||||
use Twig\Node\Node;
|
||||
use Twig\NodeVisitor\NodeVisitorInterface;
|
||||
use Twig\RuntimeLoader\RuntimeLoaderInterface;
|
||||
use Twig\TokenParser\TokenParserInterface;
|
||||
|
||||
/**
|
||||
* Stores the Twig configuration and renders templates.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Environment
|
||||
{
|
||||
public const VERSION = '2.15.4';
|
||||
public const VERSION_ID = 21504;
|
||||
public const MAJOR_VERSION = 2;
|
||||
public const MINOR_VERSION = 15;
|
||||
public const RELEASE_VERSION = 4;
|
||||
public const EXTRA_VERSION = '';
|
||||
|
||||
private $charset;
|
||||
private $loader;
|
||||
private $debug;
|
||||
private $autoReload;
|
||||
private $cache;
|
||||
private $lexer;
|
||||
private $parser;
|
||||
private $compiler;
|
||||
private $baseTemplateClass;
|
||||
private $globals = [];
|
||||
private $resolvedGlobals;
|
||||
private $loadedTemplates;
|
||||
private $strictVariables;
|
||||
private $templateClassPrefix = '__TwigTemplate_';
|
||||
private $originalCache;
|
||||
private $extensionSet;
|
||||
private $runtimeLoaders = [];
|
||||
private $runtimes = [];
|
||||
private $optionsHash;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Available options:
|
||||
*
|
||||
* * debug: When set to true, it automatically set "auto_reload" to true as
|
||||
* well (default to false).
|
||||
*
|
||||
* * charset: The charset used by the templates (default to UTF-8).
|
||||
*
|
||||
* * base_template_class: The base template class to use for generated
|
||||
* templates (default to \Twig\Template).
|
||||
*
|
||||
* * cache: An absolute path where to store the compiled templates,
|
||||
* a \Twig\Cache\CacheInterface implementation,
|
||||
* or false to disable compilation cache (default).
|
||||
*
|
||||
* * auto_reload: Whether to reload the template if the original source changed.
|
||||
* If you don't provide the auto_reload option, it will be
|
||||
* determined automatically based on the debug value.
|
||||
*
|
||||
* * strict_variables: Whether to ignore invalid variables in templates
|
||||
* (default to false).
|
||||
*
|
||||
* * autoescape: Whether to enable auto-escaping (default to html):
|
||||
* * false: disable auto-escaping
|
||||
* * html, js: set the autoescaping to one of the supported strategies
|
||||
* * name: set the autoescaping strategy based on the template name extension
|
||||
* * PHP callback: a PHP callback that returns an escaping strategy based on the template "name"
|
||||
*
|
||||
* * optimizations: A flag that indicates which optimizations to apply
|
||||
* (default to -1 which means that all optimizations are enabled;
|
||||
* set it to 0 to disable).
|
||||
*/
|
||||
public function __construct(LoaderInterface $loader, $options = [])
|
||||
{
|
||||
$this->setLoader($loader);
|
||||
|
||||
$options = array_merge([
|
||||
'debug' => false,
|
||||
'charset' => 'UTF-8',
|
||||
'base_template_class' => Template::class,
|
||||
'strict_variables' => false,
|
||||
'autoescape' => 'html',
|
||||
'cache' => false,
|
||||
'auto_reload' => null,
|
||||
'optimizations' => -1,
|
||||
], $options);
|
||||
|
||||
$this->debug = (bool) $options['debug'];
|
||||
$this->setCharset($options['charset']);
|
||||
$this->baseTemplateClass = '\\'.ltrim($options['base_template_class'], '\\');
|
||||
if ('\\'.Template::class !== $this->baseTemplateClass && '\Twig_Template' !== $this->baseTemplateClass) {
|
||||
@trigger_error('The "base_template_class" option on '.__CLASS__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED);
|
||||
}
|
||||
$this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
|
||||
$this->strictVariables = (bool) $options['strict_variables'];
|
||||
$this->setCache($options['cache']);
|
||||
$this->extensionSet = new ExtensionSet();
|
||||
|
||||
$this->addExtension(new CoreExtension());
|
||||
$this->addExtension(new EscaperExtension($options['autoescape']));
|
||||
$this->addExtension(new OptimizerExtension($options['optimizations']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base template class for compiled templates.
|
||||
*
|
||||
* @return string The base template class name
|
||||
*/
|
||||
public function getBaseTemplateClass()
|
||||
{
|
||||
if (1 > \func_num_args() || \func_get_arg(0)) {
|
||||
@trigger_error('The '.__METHOD__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
return $this->baseTemplateClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base template class for compiled templates.
|
||||
*
|
||||
* @param string $class The base template class name
|
||||
*/
|
||||
public function setBaseTemplateClass($class)
|
||||
{
|
||||
@trigger_error('The '.__METHOD__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED);
|
||||
|
||||
$this->baseTemplateClass = $class;
|
||||
$this->updateOptionsHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables debugging mode.
|
||||
*/
|
||||
public function enableDebug()
|
||||
{
|
||||
$this->debug = true;
|
||||
$this->updateOptionsHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables debugging mode.
|
||||
*/
|
||||
public function disableDebug()
|
||||
{
|
||||
$this->debug = false;
|
||||
$this->updateOptionsHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if debug mode is enabled.
|
||||
*
|
||||
* @return bool true if debug mode is enabled, false otherwise
|
||||
*/
|
||||
public function isDebug()
|
||||
{
|
||||
return $this->debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the auto_reload option.
|
||||
*/
|
||||
public function enableAutoReload()
|
||||
{
|
||||
$this->autoReload = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the auto_reload option.
|
||||
*/
|
||||
public function disableAutoReload()
|
||||
{
|
||||
$this->autoReload = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the auto_reload option is enabled.
|
||||
*
|
||||
* @return bool true if auto_reload is enabled, false otherwise
|
||||
*/
|
||||
public function isAutoReload()
|
||||
{
|
||||
return $this->autoReload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the strict_variables option.
|
||||
*/
|
||||
public function enableStrictVariables()
|
||||
{
|
||||
$this->strictVariables = true;
|
||||
$this->updateOptionsHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the strict_variables option.
|
||||
*/
|
||||
public function disableStrictVariables()
|
||||
{
|
||||
$this->strictVariables = false;
|
||||
$this->updateOptionsHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the strict_variables option is enabled.
|
||||
*
|
||||
* @return bool true if strict_variables is enabled, false otherwise
|
||||
*/
|
||||
public function isStrictVariables()
|
||||
{
|
||||
return $this->strictVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current cache implementation.
|
||||
*
|
||||
* @param bool $original Whether to return the original cache option or the real cache instance
|
||||
*
|
||||
* @return CacheInterface|string|false A Twig\Cache\CacheInterface implementation,
|
||||
* an absolute path to the compiled templates,
|
||||
* or false to disable cache
|
||||
*/
|
||||
public function getCache($original = true)
|
||||
{
|
||||
return $original ? $this->originalCache : $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current cache implementation.
|
||||
*
|
||||
* @param CacheInterface|string|false $cache A Twig\Cache\CacheInterface implementation,
|
||||
* an absolute path to the compiled templates,
|
||||
* or false to disable cache
|
||||
*/
|
||||
public function setCache($cache)
|
||||
{
|
||||
if (\is_string($cache)) {
|
||||
$this->originalCache = $cache;
|
||||
$this->cache = new FilesystemCache($cache, $this->autoReload ? FilesystemCache::FORCE_BYTECODE_INVALIDATION : 0);
|
||||
} elseif (false === $cache) {
|
||||
$this->originalCache = $cache;
|
||||
$this->cache = new NullCache();
|
||||
} elseif ($cache instanceof CacheInterface) {
|
||||
$this->originalCache = $this->cache = $cache;
|
||||
} else {
|
||||
throw new \LogicException('Cache can only be a string, false, or a \Twig\Cache\CacheInterface implementation.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the template class associated with the given string.
|
||||
*
|
||||
* The generated template class is based on the following parameters:
|
||||
*
|
||||
* * The cache key for the given template;
|
||||
* * The currently enabled extensions;
|
||||
* * Whether the Twig C extension is available or not;
|
||||
* * PHP version;
|
||||
* * Twig version;
|
||||
* * Options with what environment was created.
|
||||
*
|
||||
* @param string $name The name for which to calculate the template class name
|
||||
* @param int|null $index The index if it is an embedded template
|
||||
*
|
||||
* @return string The template class name
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getTemplateClass($name, $index = null)
|
||||
{
|
||||
$key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
|
||||
|
||||
return $this->templateClassPrefix.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a template.
|
||||
*
|
||||
* @param string|TemplateWrapper $name The template name
|
||||
* @param array $context An array of parameters to pass to the template
|
||||
*
|
||||
* @return string The rendered template
|
||||
*
|
||||
* @throws LoaderError When the template cannot be found
|
||||
* @throws SyntaxError When an error occurred during compilation
|
||||
* @throws RuntimeError When an error occurred during rendering
|
||||
*/
|
||||
public function render($name, array $context = [])
|
||||
{
|
||||
return $this->load($name)->render($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a template.
|
||||
*
|
||||
* @param string|TemplateWrapper $name The template name
|
||||
* @param array $context An array of parameters to pass to the template
|
||||
*
|
||||
* @throws LoaderError When the template cannot be found
|
||||
* @throws SyntaxError When an error occurred during compilation
|
||||
* @throws RuntimeError When an error occurred during rendering
|
||||
*/
|
||||
public function display($name, array $context = [])
|
||||
{
|
||||
$this->load($name)->display($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a template.
|
||||
*
|
||||
* @param string|TemplateWrapper $name The template name
|
||||
*
|
||||
* @throws LoaderError When the template cannot be found
|
||||
* @throws RuntimeError When a previously generated cache is corrupted
|
||||
* @throws SyntaxError When an error occurred during compilation
|
||||
*
|
||||
* @return TemplateWrapper
|
||||
*/
|
||||
public function load($name)
|
||||
{
|
||||
if ($name instanceof TemplateWrapper) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
if ($name instanceof Template) {
|
||||
@trigger_error('Passing a \Twig\Template instance to '.__METHOD__.' is deprecated since Twig 2.7.0, use \Twig\TemplateWrapper instead.', \E_USER_DEPRECATED);
|
||||
|
||||
return new TemplateWrapper($this, $name);
|
||||
}
|
||||
|
||||
return new TemplateWrapper($this, $this->loadTemplate($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a template internal representation.
|
||||
*
|
||||
* This method is for internal use only and should never be called
|
||||
* directly.
|
||||
*
|
||||
* @param string $name The template name
|
||||
* @param int $index The index if it is an embedded template
|
||||
*
|
||||
* @return Template A template instance representing the given template name
|
||||
*
|
||||
* @throws LoaderError When the template cannot be found
|
||||
* @throws RuntimeError When a previously generated cache is corrupted
|
||||
* @throws SyntaxError When an error occurred during compilation
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function loadTemplate($name, $index = null)
|
||||
{
|
||||
return $this->loadClass($this->getTemplateClass($name), $name, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function loadClass($cls, $name, $index = null)
|
||||
{
|
||||
$mainCls = $cls;
|
||||
if (null !== $index) {
|
||||
$cls .= '___'.$index;
|
||||
}
|
||||
|
||||
if (isset($this->loadedTemplates[$cls])) {
|
||||
return $this->loadedTemplates[$cls];
|
||||
}
|
||||
|
||||
if (!class_exists($cls, false)) {
|
||||
$key = $this->cache->generateKey($name, $mainCls);
|
||||
|
||||
if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
|
||||
$this->cache->load($key);
|
||||
}
|
||||
|
||||
$source = null;
|
||||
if (!class_exists($cls, false)) {
|
||||
$source = $this->getLoader()->getSourceContext($name);
|
||||
$content = $this->compileSource($source);
|
||||
$this->cache->write($key, $content);
|
||||
$this->cache->load($key);
|
||||
|
||||
if (!class_exists($mainCls, false)) {
|
||||
/* Last line of defense if either $this->bcWriteCacheFile was used,
|
||||
* $this->cache is implemented as a no-op or we have a race condition
|
||||
* where the cache was cleared between the above calls to write to and load from
|
||||
* the cache.
|
||||
*/
|
||||
eval('?>'.$content);
|
||||
}
|
||||
|
||||
if (!class_exists($cls, false)) {
|
||||
throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// to be removed in 3.0
|
||||
$this->extensionSet->initRuntime($this);
|
||||
|
||||
return $this->loadedTemplates[$cls] = new $cls($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a template from source.
|
||||
*
|
||||
* This method should not be used as a generic way to load templates.
|
||||
*
|
||||
* @param string $template The template source
|
||||
* @param string $name An optional name of the template to be used in error messages
|
||||
*
|
||||
* @return TemplateWrapper A template instance representing the given template name
|
||||
*
|
||||
* @throws LoaderError When the template cannot be found
|
||||
* @throws SyntaxError When an error occurred during compilation
|
||||
*/
|
||||
public function createTemplate($template, string $name = null)
|
||||
{
|
||||
$hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $template, false);
|
||||
if (null !== $name) {
|
||||
$name = sprintf('%s (string template %s)', $name, $hash);
|
||||
} else {
|
||||
$name = sprintf('__string_template__%s', $hash);
|
||||
}
|
||||
|
||||
$loader = new ChainLoader([
|
||||
new ArrayLoader([$name => $template]),
|
||||
$current = $this->getLoader(),
|
||||
]);
|
||||
|
||||
$this->setLoader($loader);
|
||||
try {
|
||||
return new TemplateWrapper($this, $this->loadTemplate($name));
|
||||
} finally {
|
||||
$this->setLoader($current);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the template is still fresh.
|
||||
*
|
||||
* Besides checking the loader for freshness information,
|
||||
* this method also checks if the enabled extensions have
|
||||
* not changed.
|
||||
*
|
||||
* @param string $name The template name
|
||||
* @param int $time The last modification time of the cached template
|
||||
*
|
||||
* @return bool true if the template is fresh, false otherwise
|
||||
*/
|
||||
public function isTemplateFresh($name, $time)
|
||||
{
|
||||
return $this->extensionSet->getLastModified() <= $time && $this->getLoader()->isFresh($name, $time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to load a template consecutively from an array.
|
||||
*
|
||||
* Similar to load() but it also accepts instances of \Twig\Template and
|
||||
* \Twig\TemplateWrapper, and an array of templates where each is tried to be loaded.
|
||||
*
|
||||
* @param string|TemplateWrapper|array $names A template or an array of templates to try consecutively
|
||||
*
|
||||
* @return TemplateWrapper|Template
|
||||
*
|
||||
* @throws LoaderError When none of the templates can be found
|
||||
* @throws SyntaxError When an error occurred during compilation
|
||||
*/
|
||||
public function resolveTemplate($names)
|
||||
{
|
||||
if (!\is_array($names)) {
|
||||
$names = [$names];
|
||||
}
|
||||
|
||||
$count = \count($names);
|
||||
foreach ($names as $name) {
|
||||
if ($name instanceof Template) {
|
||||
return $name;
|
||||
}
|
||||
if ($name instanceof TemplateWrapper) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
if (1 !== $count && !$this->getLoader()->exists($name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $this->loadTemplate($name);
|
||||
}
|
||||
|
||||
throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
|
||||
}
|
||||
|
||||
public function setLexer(Lexer $lexer)
|
||||
{
|
||||
$this->lexer = $lexer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenizes a source code.
|
||||
*
|
||||
* @return TokenStream
|
||||
*
|
||||
* @throws SyntaxError When the code is syntactically wrong
|
||||
*/
|
||||
public function tokenize(Source $source)
|
||||
{
|
||||
if (null === $this->lexer) {
|
||||
$this->lexer = new Lexer($this);
|
||||
}
|
||||
|
||||
return $this->lexer->tokenize($source);
|
||||
}
|
||||
|
||||
public function setParser(Parser $parser)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a token stream to a node tree.
|
||||
*
|
||||
* @return ModuleNode
|
||||
*
|
||||
* @throws SyntaxError When the token stream is syntactically or semantically wrong
|
||||
*/
|
||||
public function parse(TokenStream $stream)
|
||||
{
|
||||
if (null === $this->parser) {
|
||||
$this->parser = new Parser($this);
|
||||
}
|
||||
|
||||
return $this->parser->parse($stream);
|
||||
}
|
||||
|
||||
public function setCompiler(Compiler $compiler)
|
||||
{
|
||||
$this->compiler = $compiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles a node and returns the PHP code.
|
||||
*
|
||||
* @return string The compiled PHP source code
|
||||
*/
|
||||
public function compile(Node $node)
|
||||
{
|
||||
if (null === $this->compiler) {
|
||||
$this->compiler = new Compiler($this);
|
||||
}
|
||||
|
||||
return $this->compiler->compile($node)->getSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles a template source code.
|
||||
*
|
||||
* @return string The compiled PHP source code
|
||||
*
|
||||
* @throws SyntaxError When there was an error during tokenizing, parsing or compiling
|
||||
*/
|
||||
public function compileSource(Source $source)
|
||||
{
|
||||
try {
|
||||
return $this->compile($this->parse($this->tokenize($source)));
|
||||
} catch (Error $e) {
|
||||
$e->setSourceContext($source);
|
||||
throw $e;
|
||||
} catch (\Exception $e) {
|
||||
throw new SyntaxError(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function setLoader(LoaderInterface $loader)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Loader instance.
|
||||
*
|
||||
* @return LoaderInterface
|
||||
*/
|
||||
public function getLoader()
|
||||
{
|
||||
return $this->loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default template charset.
|
||||
*
|
||||
* @param string $charset The default charset
|
||||
*/
|
||||
public function setCharset($charset)
|
||||
{
|
||||
if ('UTF8' === $charset = null === $charset ? null : strtoupper($charset)) {
|
||||
// iconv on Windows requires "UTF-8" instead of "UTF8"
|
||||
$charset = 'UTF-8';
|
||||
}
|
||||
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default template charset.
|
||||
*
|
||||
* @return string The default charset
|
||||
*/
|
||||
public function getCharset()
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given extension is registered.
|
||||
*
|
||||
* @param string $class The extension class name
|
||||
*
|
||||
* @return bool Whether the extension is registered or not
|
||||
*/
|
||||
public function hasExtension($class)
|
||||
{
|
||||
return $this->extensionSet->hasExtension($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a runtime loader.
|
||||
*/
|
||||
public function addRuntimeLoader(RuntimeLoaderInterface $loader)
|
||||
{
|
||||
$this->runtimeLoaders[] = $loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an extension by class name.
|
||||
*
|
||||
* @param string $class The extension class name
|
||||
*
|
||||
* @return ExtensionInterface
|
||||
*/
|
||||
public function getExtension($class)
|
||||
{
|
||||
return $this->extensionSet->getExtension($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the runtime implementation of a Twig element (filter/function/test).
|
||||
*
|
||||
* @param string $class A runtime class name
|
||||
*
|
||||
* @return object The runtime implementation
|
||||
*
|
||||
* @throws RuntimeError When the template cannot be found
|
||||
*/
|
||||
public function getRuntime($class)
|
||||
{
|
||||
if (isset($this->runtimes[$class])) {
|
||||
return $this->runtimes[$class];
|
||||
}
|
||||
|
||||
foreach ($this->runtimeLoaders as $loader) {
|
||||
if (null !== $runtime = $loader->load($class)) {
|
||||
return $this->runtimes[$class] = $runtime;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeError(sprintf('Unable to load the "%s" runtime.', $class));
|
||||
}
|
||||
|
||||
public function addExtension(ExtensionInterface $extension)
|
||||
{
|
||||
$this->extensionSet->addExtension($extension);
|
||||
$this->updateOptionsHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an array of extensions.
|
||||
*
|
||||
* @param array $extensions An array of extensions
|
||||
*/
|
||||
public function setExtensions(array $extensions)
|
||||
{
|
||||
$this->extensionSet->setExtensions($extensions);
|
||||
$this->updateOptionsHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all registered extensions.
|
||||
*
|
||||
* @return ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on)
|
||||
*/
|
||||
public function getExtensions()
|
||||
{
|
||||
return $this->extensionSet->getExtensions();
|
||||
}
|
||||
|
||||
public function addTokenParser(TokenParserInterface $parser)
|
||||
{
|
||||
$this->extensionSet->addTokenParser($parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered Token Parsers.
|
||||
*
|
||||
* @return TokenParserInterface[]
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getTokenParsers()
|
||||
{
|
||||
return $this->extensionSet->getTokenParsers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets registered tags.
|
||||
*
|
||||
* @return TokenParserInterface[]
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
$tags = [];
|
||||
foreach ($this->getTokenParsers() as $parser) {
|
||||
$tags[$parser->getTag()] = $parser;
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
public function addNodeVisitor(NodeVisitorInterface $visitor)
|
||||
{
|
||||
$this->extensionSet->addNodeVisitor($visitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered Node Visitors.
|
||||
*
|
||||
* @return NodeVisitorInterface[]
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getNodeVisitors()
|
||||
{
|
||||
return $this->extensionSet->getNodeVisitors();
|
||||
}
|
||||
|
||||
public function addFilter(TwigFilter $filter)
|
||||
{
|
||||
$this->extensionSet->addFilter($filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a filter by name.
|
||||
*
|
||||
* Subclasses may override this method and load filters differently;
|
||||
* so no list of filters is available.
|
||||
*
|
||||
* @param string $name The filter name
|
||||
*
|
||||
* @return TwigFilter|false
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getFilter($name)
|
||||
{
|
||||
return $this->extensionSet->getFilter($name);
|
||||
}
|
||||
|
||||
public function registerUndefinedFilterCallback(callable $callable)
|
||||
{
|
||||
$this->extensionSet->registerUndefinedFilterCallback($callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered Filters.
|
||||
*
|
||||
* Be warned that this method cannot return filters defined with registerUndefinedFilterCallback.
|
||||
*
|
||||
* @return TwigFilter[]
|
||||
*
|
||||
* @see registerUndefinedFilterCallback
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
return $this->extensionSet->getFilters();
|
||||
}
|
||||
|
||||
public function addTest(TwigTest $test)
|
||||
{
|
||||
$this->extensionSet->addTest($test);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered Tests.
|
||||
*
|
||||
* @return TwigTest[]
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getTests()
|
||||
{
|
||||
return $this->extensionSet->getTests();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a test by name.
|
||||
*
|
||||
* @param string $name The test name
|
||||
*
|
||||
* @return TwigTest|false
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getTest($name)
|
||||
{
|
||||
return $this->extensionSet->getTest($name);
|
||||
}
|
||||
|
||||
public function addFunction(TwigFunction $function)
|
||||
{
|
||||
$this->extensionSet->addFunction($function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a function by name.
|
||||
*
|
||||
* Subclasses may override this method and load functions differently;
|
||||
* so no list of functions is available.
|
||||
*
|
||||
* @param string $name function name
|
||||
*
|
||||
* @return TwigFunction|false
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getFunction($name)
|
||||
{
|
||||
return $this->extensionSet->getFunction($name);
|
||||
}
|
||||
|
||||
public function registerUndefinedFunctionCallback(callable $callable)
|
||||
{
|
||||
$this->extensionSet->registerUndefinedFunctionCallback($callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets registered functions.
|
||||
*
|
||||
* Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
|
||||
*
|
||||
* @return TwigFunction[]
|
||||
*
|
||||
* @see registerUndefinedFunctionCallback
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
return $this->extensionSet->getFunctions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a Global.
|
||||
*
|
||||
* New globals can be added before compiling or rendering a template;
|
||||
* but after, you can only update existing globals.
|
||||
*
|
||||
* @param string $name The global name
|
||||
* @param mixed $value The global value
|
||||
*/
|
||||
public function addGlobal($name, $value)
|
||||
{
|
||||
if ($this->extensionSet->isInitialized() && !\array_key_exists($name, $this->getGlobals())) {
|
||||
throw new \LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
|
||||
}
|
||||
|
||||
if (null !== $this->resolvedGlobals) {
|
||||
$this->resolvedGlobals[$name] = $value;
|
||||
} else {
|
||||
$this->globals[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered Globals.
|
||||
*
|
||||
* @return array An array of globals
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getGlobals()
|
||||
{
|
||||
if ($this->extensionSet->isInitialized()) {
|
||||
if (null === $this->resolvedGlobals) {
|
||||
$this->resolvedGlobals = array_merge($this->extensionSet->getGlobals(), $this->globals);
|
||||
}
|
||||
|
||||
return $this->resolvedGlobals;
|
||||
}
|
||||
|
||||
return array_merge($this->extensionSet->getGlobals(), $this->globals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges a context with the defined globals.
|
||||
*
|
||||
* @param array $context An array representing the context
|
||||
*
|
||||
* @return array The context merged with the globals
|
||||
*/
|
||||
public function mergeGlobals(array $context)
|
||||
{
|
||||
// we don't use array_merge as the context being generally
|
||||
// bigger than globals, this code is faster.
|
||||
foreach ($this->getGlobals() as $key => $value) {
|
||||
if (!\array_key_exists($key, $context)) {
|
||||
$context[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered unary Operators.
|
||||
*
|
||||
* @return array An array of unary operators
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getUnaryOperators()
|
||||
{
|
||||
return $this->extensionSet->getUnaryOperators();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registered binary Operators.
|
||||
*
|
||||
* @return array An array of binary operators
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getBinaryOperators()
|
||||
{
|
||||
return $this->extensionSet->getBinaryOperators();
|
||||
}
|
||||
|
||||
private function updateOptionsHash()
|
||||
{
|
||||
$this->optionsHash = implode(':', [
|
||||
$this->extensionSet->getSignature(),
|
||||
\PHP_MAJOR_VERSION,
|
||||
\PHP_MINOR_VERSION,
|
||||
self::VERSION,
|
||||
(int) $this->debug,
|
||||
$this->baseTemplateClass,
|
||||
(int) $this->strictVariables,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Environment', 'Twig_Environment');
|
||||
@@ -1,257 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Error;
|
||||
|
||||
use Twig\Source;
|
||||
use Twig\Template;
|
||||
|
||||
/**
|
||||
* Twig base exception.
|
||||
*
|
||||
* This exception class and its children must only be used when
|
||||
* an error occurs during the loading of a template, when a syntax error
|
||||
* is detected in a template, or when rendering a template. Other
|
||||
* errors must use regular PHP exception classes (like when the template
|
||||
* cache directory is not writable for instance).
|
||||
*
|
||||
* To help debugging template issues, this class tracks the original template
|
||||
* name and line where the error occurred.
|
||||
*
|
||||
* Whenever possible, you must set these information (original template name
|
||||
* and line number) yourself by passing them to the constructor. If some or all
|
||||
* these information are not available from where you throw the exception, then
|
||||
* this class will guess them automatically (when the line number is set to -1
|
||||
* and/or the name is set to null). As this is a costly operation, this
|
||||
* can be disabled by passing false for both the name and the line number
|
||||
* when creating a new instance of this class.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Error extends \Exception
|
||||
{
|
||||
private $lineno;
|
||||
private $name;
|
||||
private $rawMessage;
|
||||
private $sourcePath;
|
||||
private $sourceCode;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Set the line number to -1 to enable its automatic guessing.
|
||||
* Set the name to null to enable its automatic guessing.
|
||||
*
|
||||
* @param string $message The error message
|
||||
* @param int $lineno The template line where the error occurred
|
||||
* @param Source|string|null $source The source context where the error occurred
|
||||
* @param \Exception $previous The previous exception
|
||||
*/
|
||||
public function __construct(string $message, int $lineno = -1, $source = null, \Exception $previous = null)
|
||||
{
|
||||
parent::__construct('', 0, $previous);
|
||||
|
||||
if (null === $source) {
|
||||
$name = null;
|
||||
} elseif (!$source instanceof Source && !$source instanceof \Twig_Source) {
|
||||
@trigger_error(sprintf('Passing a string as a source to %s is deprecated since Twig 2.6.1; pass a Twig\Source instance instead.', __CLASS__), \E_USER_DEPRECATED);
|
||||
$name = $source;
|
||||
} else {
|
||||
$name = $source->getName();
|
||||
$this->sourceCode = $source->getCode();
|
||||
$this->sourcePath = $source->getPath();
|
||||
}
|
||||
|
||||
$this->lineno = $lineno;
|
||||
$this->name = $name;
|
||||
$this->rawMessage = $message;
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw message.
|
||||
*
|
||||
* @return string The raw message
|
||||
*/
|
||||
public function getRawMessage()
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the template line where the error occurred.
|
||||
*
|
||||
* @return int The template line
|
||||
*/
|
||||
public function getTemplateLine()
|
||||
{
|
||||
return $this->lineno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the template line where the error occurred.
|
||||
*
|
||||
* @param int $lineno The template line
|
||||
*/
|
||||
public function setTemplateLine($lineno)
|
||||
{
|
||||
$this->lineno = $lineno;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source context of the Twig template where the error occurred.
|
||||
*
|
||||
* @return Source|null
|
||||
*/
|
||||
public function getSourceContext()
|
||||
{
|
||||
return $this->name ? new Source($this->sourceCode, $this->name, $this->sourcePath) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source context of the Twig template where the error occurred.
|
||||
*/
|
||||
public function setSourceContext(Source $source = null)
|
||||
{
|
||||
if (null === $source) {
|
||||
$this->sourceCode = $this->name = $this->sourcePath = null;
|
||||
} else {
|
||||
$this->sourceCode = $source->getCode();
|
||||
$this->name = $source->getName();
|
||||
$this->sourcePath = $source->getPath();
|
||||
}
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
public function guess()
|
||||
{
|
||||
$this->guessTemplateInfo();
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
public function appendMessage($rawMessage)
|
||||
{
|
||||
$this->rawMessage .= $rawMessage;
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
private function updateRepr()
|
||||
{
|
||||
$this->message = $this->rawMessage;
|
||||
|
||||
if ($this->sourcePath && $this->lineno > 0) {
|
||||
$this->file = $this->sourcePath;
|
||||
$this->line = $this->lineno;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$dot = false;
|
||||
if ('.' === substr($this->message, -1)) {
|
||||
$this->message = substr($this->message, 0, -1);
|
||||
$dot = true;
|
||||
}
|
||||
|
||||
$questionMark = false;
|
||||
if ('?' === substr($this->message, -1)) {
|
||||
$this->message = substr($this->message, 0, -1);
|
||||
$questionMark = true;
|
||||
}
|
||||
|
||||
if ($this->name) {
|
||||
if (\is_string($this->name) || (\is_object($this->name) && method_exists($this->name, '__toString'))) {
|
||||
$name = sprintf('"%s"', $this->name);
|
||||
} else {
|
||||
$name = json_encode($this->name);
|
||||
}
|
||||
$this->message .= sprintf(' in %s', $name);
|
||||
}
|
||||
|
||||
if ($this->lineno && $this->lineno >= 0) {
|
||||
$this->message .= sprintf(' at line %d', $this->lineno);
|
||||
}
|
||||
|
||||
if ($dot) {
|
||||
$this->message .= '.';
|
||||
}
|
||||
|
||||
if ($questionMark) {
|
||||
$this->message .= '?';
|
||||
}
|
||||
}
|
||||
|
||||
private function guessTemplateInfo()
|
||||
{
|
||||
$template = null;
|
||||
$templateClass = null;
|
||||
|
||||
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT);
|
||||
foreach ($backtrace as $trace) {
|
||||
if (isset($trace['object']) && $trace['object'] instanceof Template && 'Twig\Template' !== \get_class($trace['object'])) {
|
||||
$currentClass = \get_class($trace['object']);
|
||||
$isEmbedContainer = null === $templateClass ? false : 0 === strpos($templateClass, $currentClass);
|
||||
if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
|
||||
$template = $trace['object'];
|
||||
$templateClass = \get_class($trace['object']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update template name
|
||||
if (null !== $template && null === $this->name) {
|
||||
$this->name = $template->getTemplateName();
|
||||
}
|
||||
|
||||
// update template path if any
|
||||
if (null !== $template && null === $this->sourcePath) {
|
||||
$src = $template->getSourceContext();
|
||||
$this->sourceCode = $src->getCode();
|
||||
$this->sourcePath = $src->getPath();
|
||||
}
|
||||
|
||||
if (null === $template || $this->lineno > -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = new \ReflectionObject($template);
|
||||
$file = $r->getFileName();
|
||||
|
||||
$exceptions = [$e = $this];
|
||||
while ($e = $e->getPrevious()) {
|
||||
$exceptions[] = $e;
|
||||
}
|
||||
|
||||
while ($e = array_pop($exceptions)) {
|
||||
$traces = $e->getTrace();
|
||||
array_unshift($traces, ['file' => $e->getFile(), 'line' => $e->getLine()]);
|
||||
|
||||
while ($trace = array_shift($traces)) {
|
||||
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
|
||||
if ($codeLine <= $trace['line']) {
|
||||
// update template line
|
||||
$this->lineno = $templateLine;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Error\Error', 'Twig_Error');
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Error;
|
||||
|
||||
/**
|
||||
* Exception thrown when an error occurs during template loading.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class LoaderError extends Error
|
||||
{
|
||||
}
|
||||
|
||||
class_alias('Twig\Error\LoaderError', 'Twig_Error_Loader');
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
* (c) Armin Ronacher
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Error;
|
||||
|
||||
/**
|
||||
* Exception thrown when an error occurs at runtime.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class RuntimeError extends Error
|
||||
{
|
||||
}
|
||||
|
||||
class_alias('Twig\Error\RuntimeError', 'Twig_Error_Runtime');
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
* (c) Armin Ronacher
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Error;
|
||||
|
||||
/**
|
||||
* \Exception thrown when a syntax error occurs during lexing or parsing of a template.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class SyntaxError extends Error
|
||||
{
|
||||
/**
|
||||
* Tweaks the error message to include suggestions.
|
||||
*
|
||||
* @param string $name The original name of the item that does not exist
|
||||
* @param array $items An array of possible items
|
||||
*/
|
||||
public function addSuggestions($name, array $items)
|
||||
{
|
||||
$alternatives = [];
|
||||
foreach ($items as $item) {
|
||||
$lev = levenshtein($name, $item);
|
||||
if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) {
|
||||
$alternatives[$item] = $lev;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$alternatives) {
|
||||
return;
|
||||
}
|
||||
|
||||
asort($alternatives);
|
||||
|
||||
$this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives))));
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Error\SyntaxError', 'Twig_Error_Syntax');
|
||||
@@ -1,830 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
* (c) Armin Ronacher
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig;
|
||||
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ArrayExpression;
|
||||
use Twig\Node\Expression\ArrowFunctionExpression;
|
||||
use Twig\Node\Expression\AssignNameExpression;
|
||||
use Twig\Node\Expression\Binary\ConcatBinary;
|
||||
use Twig\Node\Expression\BlockReferenceExpression;
|
||||
use Twig\Node\Expression\ConditionalExpression;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Expression\GetAttrExpression;
|
||||
use Twig\Node\Expression\MethodCallExpression;
|
||||
use Twig\Node\Expression\NameExpression;
|
||||
use Twig\Node\Expression\ParentExpression;
|
||||
use Twig\Node\Expression\TestExpression;
|
||||
use Twig\Node\Expression\Unary\NegUnary;
|
||||
use Twig\Node\Expression\Unary\NotUnary;
|
||||
use Twig\Node\Expression\Unary\PosUnary;
|
||||
use Twig\Node\Node;
|
||||
|
||||
/**
|
||||
* Parses expressions.
|
||||
*
|
||||
* This parser implements a "Precedence climbing" algorithm.
|
||||
*
|
||||
* @see https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
|
||||
* @see https://en.wikipedia.org/wiki/Operator-precedence_parser
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ExpressionParser
|
||||
{
|
||||
public const OPERATOR_LEFT = 1;
|
||||
public const OPERATOR_RIGHT = 2;
|
||||
|
||||
private $parser;
|
||||
private $env;
|
||||
private $unaryOperators;
|
||||
private $binaryOperators;
|
||||
|
||||
public function __construct(Parser $parser, Environment $env)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
$this->env = $env;
|
||||
$this->unaryOperators = $env->getUnaryOperators();
|
||||
$this->binaryOperators = $env->getBinaryOperators();
|
||||
}
|
||||
|
||||
public function parseExpression($precedence = 0, $allowArrow = false)
|
||||
{
|
||||
if ($allowArrow && $arrow = $this->parseArrow()) {
|
||||
return $arrow;
|
||||
}
|
||||
|
||||
$expr = $this->getPrimary();
|
||||
$token = $this->parser->getCurrentToken();
|
||||
while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
|
||||
$op = $this->binaryOperators[$token->getValue()];
|
||||
$this->parser->getStream()->next();
|
||||
|
||||
if ('is not' === $token->getValue()) {
|
||||
$expr = $this->parseNotTestExpression($expr);
|
||||
} elseif ('is' === $token->getValue()) {
|
||||
$expr = $this->parseTestExpression($expr);
|
||||
} elseif (isset($op['callable'])) {
|
||||
$expr = $op['callable']($this->parser, $expr);
|
||||
} else {
|
||||
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
|
||||
$class = $op['class'];
|
||||
$expr = new $class($expr, $expr1, $token->getLine());
|
||||
}
|
||||
|
||||
$token = $this->parser->getCurrentToken();
|
||||
}
|
||||
|
||||
if (0 === $precedence) {
|
||||
return $this->parseConditionalExpression($expr);
|
||||
}
|
||||
|
||||
return $expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrowFunctionExpression|null
|
||||
*/
|
||||
private function parseArrow()
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
|
||||
// short array syntax (one argument, no parentheses)?
|
||||
if ($stream->look(1)->test(/* Token::ARROW_TYPE */ 12)) {
|
||||
$line = $stream->getCurrent()->getLine();
|
||||
$token = $stream->expect(/* Token::NAME_TYPE */ 5);
|
||||
$names = [new AssignNameExpression($token->getValue(), $token->getLine())];
|
||||
$stream->expect(/* Token::ARROW_TYPE */ 12);
|
||||
|
||||
return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line);
|
||||
}
|
||||
|
||||
// first, determine if we are parsing an arrow function by finding => (long form)
|
||||
$i = 0;
|
||||
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
|
||||
return null;
|
||||
}
|
||||
++$i;
|
||||
while (true) {
|
||||
// variable name
|
||||
++$i;
|
||||
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
|
||||
break;
|
||||
}
|
||||
++$i;
|
||||
}
|
||||
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
|
||||
return null;
|
||||
}
|
||||
++$i;
|
||||
if (!$stream->look($i)->test(/* Token::ARROW_TYPE */ 12)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// yes, let's parse it properly
|
||||
$token = $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(');
|
||||
$line = $token->getLine();
|
||||
|
||||
$names = [];
|
||||
while (true) {
|
||||
$token = $stream->expect(/* Token::NAME_TYPE */ 5);
|
||||
$names[] = new AssignNameExpression($token->getValue(), $token->getLine());
|
||||
|
||||
if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')');
|
||||
$stream->expect(/* Token::ARROW_TYPE */ 12);
|
||||
|
||||
return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line);
|
||||
}
|
||||
|
||||
private function getPrimary(): AbstractExpression
|
||||
{
|
||||
$token = $this->parser->getCurrentToken();
|
||||
|
||||
if ($this->isUnary($token)) {
|
||||
$operator = $this->unaryOperators[$token->getValue()];
|
||||
$this->parser->getStream()->next();
|
||||
$expr = $this->parseExpression($operator['precedence']);
|
||||
$class = $operator['class'];
|
||||
|
||||
return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
|
||||
} elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
|
||||
$this->parser->getStream()->next();
|
||||
$expr = $this->parseExpression();
|
||||
$this->parser->getStream()->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'An opened parenthesis is not properly closed');
|
||||
|
||||
return $this->parsePostfixExpression($expr);
|
||||
}
|
||||
|
||||
return $this->parsePrimaryExpression();
|
||||
}
|
||||
|
||||
private function parseConditionalExpression($expr): AbstractExpression
|
||||
{
|
||||
while ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, '?')) {
|
||||
if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
|
||||
$expr2 = $this->parseExpression();
|
||||
if ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
|
||||
$expr3 = $this->parseExpression();
|
||||
} else {
|
||||
$expr3 = new ConstantExpression('', $this->parser->getCurrentToken()->getLine());
|
||||
}
|
||||
} else {
|
||||
$expr2 = $expr;
|
||||
$expr3 = $this->parseExpression();
|
||||
}
|
||||
|
||||
$expr = new ConditionalExpression($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
|
||||
}
|
||||
|
||||
return $expr;
|
||||
}
|
||||
|
||||
private function isUnary(Token $token): bool
|
||||
{
|
||||
return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->unaryOperators[$token->getValue()]);
|
||||
}
|
||||
|
||||
private function isBinary(Token $token): bool
|
||||
{
|
||||
return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->binaryOperators[$token->getValue()]);
|
||||
}
|
||||
|
||||
public function parsePrimaryExpression()
|
||||
{
|
||||
$token = $this->parser->getCurrentToken();
|
||||
switch ($token->getType()) {
|
||||
case /* Token::NAME_TYPE */ 5:
|
||||
$this->parser->getStream()->next();
|
||||
switch ($token->getValue()) {
|
||||
case 'true':
|
||||
case 'TRUE':
|
||||
$node = new ConstantExpression(true, $token->getLine());
|
||||
break;
|
||||
|
||||
case 'false':
|
||||
case 'FALSE':
|
||||
$node = new ConstantExpression(false, $token->getLine());
|
||||
break;
|
||||
|
||||
case 'none':
|
||||
case 'NONE':
|
||||
case 'null':
|
||||
case 'NULL':
|
||||
$node = new ConstantExpression(null, $token->getLine());
|
||||
break;
|
||||
|
||||
default:
|
||||
if ('(' === $this->parser->getCurrentToken()->getValue()) {
|
||||
$node = $this->getFunctionNode($token->getValue(), $token->getLine());
|
||||
} else {
|
||||
$node = new NameExpression($token->getValue(), $token->getLine());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case /* Token::NUMBER_TYPE */ 6:
|
||||
$this->parser->getStream()->next();
|
||||
$node = new ConstantExpression($token->getValue(), $token->getLine());
|
||||
break;
|
||||
|
||||
case /* Token::STRING_TYPE */ 7:
|
||||
case /* Token::INTERPOLATION_START_TYPE */ 10:
|
||||
$node = $this->parseStringExpression();
|
||||
break;
|
||||
|
||||
case /* Token::OPERATOR_TYPE */ 8:
|
||||
if (preg_match(Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
|
||||
// in this context, string operators are variable names
|
||||
$this->parser->getStream()->next();
|
||||
$node = new NameExpression($token->getValue(), $token->getLine());
|
||||
break;
|
||||
} elseif (isset($this->unaryOperators[$token->getValue()])) {
|
||||
$class = $this->unaryOperators[$token->getValue()]['class'];
|
||||
|
||||
$ref = new \ReflectionClass($class);
|
||||
if (!(\in_array($ref->getName(), [NegUnary::class, PosUnary::class, 'Twig_Node_Expression_Unary_Neg', 'Twig_Node_Expression_Unary_Pos'])
|
||||
|| $ref->isSubclassOf(NegUnary::class) || $ref->isSubclassOf(PosUnary::class)
|
||||
|| $ref->isSubclassOf('Twig_Node_Expression_Unary_Neg') || $ref->isSubclassOf('Twig_Node_Expression_Unary_Pos'))
|
||||
) {
|
||||
throw new SyntaxError(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
|
||||
}
|
||||
|
||||
$this->parser->getStream()->next();
|
||||
$expr = $this->parsePrimaryExpression();
|
||||
|
||||
$node = new $class($expr, $token->getLine());
|
||||
break;
|
||||
}
|
||||
|
||||
// no break
|
||||
default:
|
||||
if ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '[')) {
|
||||
$node = $this->parseArrayExpression();
|
||||
} elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) {
|
||||
$node = $this->parseHashExpression();
|
||||
} elseif ($token->test(/* Token::OPERATOR_TYPE */ 8, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
|
||||
throw new SyntaxError(sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
|
||||
} else {
|
||||
throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s".', Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->parsePostfixExpression($node);
|
||||
}
|
||||
|
||||
public function parseStringExpression()
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
|
||||
$nodes = [];
|
||||
// a string cannot be followed by another string in a single expression
|
||||
$nextCanBeString = true;
|
||||
while (true) {
|
||||
if ($nextCanBeString && $token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) {
|
||||
$nodes[] = new ConstantExpression($token->getValue(), $token->getLine());
|
||||
$nextCanBeString = false;
|
||||
} elseif ($stream->nextIf(/* Token::INTERPOLATION_START_TYPE */ 10)) {
|
||||
$nodes[] = $this->parseExpression();
|
||||
$stream->expect(/* Token::INTERPOLATION_END_TYPE */ 11);
|
||||
$nextCanBeString = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$expr = array_shift($nodes);
|
||||
foreach ($nodes as $node) {
|
||||
$expr = new ConcatBinary($expr, $node, $node->getTemplateLine());
|
||||
}
|
||||
|
||||
return $expr;
|
||||
}
|
||||
|
||||
public function parseArrayExpression()
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'An array element was expected');
|
||||
|
||||
$node = new ArrayExpression([], $stream->getCurrent()->getLine());
|
||||
$first = true;
|
||||
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
|
||||
if (!$first) {
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma');
|
||||
|
||||
// trailing ,?
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$first = false;
|
||||
|
||||
$node->addElement($this->parseExpression());
|
||||
}
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed');
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function parseHashExpression()
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '{', 'A hash element was expected');
|
||||
|
||||
$node = new ArrayExpression([], $stream->getCurrent()->getLine());
|
||||
$first = true;
|
||||
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
|
||||
if (!$first) {
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A hash value must be followed by a comma');
|
||||
|
||||
// trailing ,?
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$first = false;
|
||||
|
||||
// a hash key can be:
|
||||
//
|
||||
// * a number -- 12
|
||||
// * a string -- 'a'
|
||||
// * a name, which is equivalent to a string -- a
|
||||
// * an expression, which must be enclosed in parentheses -- (1 + 2)
|
||||
if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) {
|
||||
$key = new ConstantExpression($token->getValue(), $token->getLine());
|
||||
|
||||
// {a} is a shortcut for {a:a}
|
||||
if ($stream->test(Token::PUNCTUATION_TYPE, [',', '}'])) {
|
||||
$value = new NameExpression($key->getAttribute('value'), $key->getTemplateLine());
|
||||
$node->addElement($value, $key);
|
||||
continue;
|
||||
}
|
||||
} elseif (($token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) || $token = $stream->nextIf(/* Token::NUMBER_TYPE */ 6)) {
|
||||
$key = new ConstantExpression($token->getValue(), $token->getLine());
|
||||
} elseif ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
|
||||
$key = $this->parseExpression();
|
||||
} else {
|
||||
$current = $stream->getCurrent();
|
||||
|
||||
throw new SyntaxError(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
|
||||
}
|
||||
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ':', 'A hash key must be followed by a colon (:)');
|
||||
$value = $this->parseExpression();
|
||||
|
||||
$node->addElement($value, $key);
|
||||
}
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '}', 'An opened hash is not properly closed');
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function parsePostfixExpression($node)
|
||||
{
|
||||
while (true) {
|
||||
$token = $this->parser->getCurrentToken();
|
||||
if (/* Token::PUNCTUATION_TYPE */ 9 == $token->getType()) {
|
||||
if ('.' == $token->getValue() || '[' == $token->getValue()) {
|
||||
$node = $this->parseSubscriptExpression($node);
|
||||
} elseif ('|' == $token->getValue()) {
|
||||
$node = $this->parseFilterExpression($node);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function getFunctionNode($name, $line)
|
||||
{
|
||||
switch ($name) {
|
||||
case 'parent':
|
||||
$this->parseArguments();
|
||||
if (!\count($this->parser->getBlockStack())) {
|
||||
throw new SyntaxError('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
|
||||
}
|
||||
|
||||
if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
|
||||
throw new SyntaxError('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext());
|
||||
}
|
||||
|
||||
return new ParentExpression($this->parser->peekBlockStack(), $line);
|
||||
case 'block':
|
||||
$args = $this->parseArguments();
|
||||
if (\count($args) < 1) {
|
||||
throw new SyntaxError('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
|
||||
}
|
||||
|
||||
return new BlockReferenceExpression($args->getNode(0), \count($args) > 1 ? $args->getNode(1) : null, $line);
|
||||
case 'attribute':
|
||||
$args = $this->parseArguments();
|
||||
if (\count($args) < 2) {
|
||||
throw new SyntaxError('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
|
||||
}
|
||||
|
||||
return new GetAttrExpression($args->getNode(0), $args->getNode(1), \count($args) > 2 ? $args->getNode(2) : null, Template::ANY_CALL, $line);
|
||||
default:
|
||||
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
|
||||
$arguments = new ArrayExpression([], $line);
|
||||
foreach ($this->parseArguments() as $n) {
|
||||
$arguments->addElement($n);
|
||||
}
|
||||
|
||||
$node = new MethodCallExpression($alias['node'], $alias['name'], $arguments, $line);
|
||||
$node->setAttribute('safe', true);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
$args = $this->parseArguments(true);
|
||||
$class = $this->getFunctionNodeClass($name, $line);
|
||||
|
||||
return new $class($name, $args, $line);
|
||||
}
|
||||
}
|
||||
|
||||
public function parseSubscriptExpression($node)
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
$token = $stream->next();
|
||||
$lineno = $token->getLine();
|
||||
$arguments = new ArrayExpression([], $lineno);
|
||||
$type = Template::ANY_CALL;
|
||||
if ('.' == $token->getValue()) {
|
||||
$token = $stream->next();
|
||||
if (
|
||||
/* Token::NAME_TYPE */ 5 == $token->getType()
|
||||
||
|
||||
/* Token::NUMBER_TYPE */ 6 == $token->getType()
|
||||
||
|
||||
(/* Token::OPERATOR_TYPE */ 8 == $token->getType() && preg_match(Lexer::REGEX_NAME, $token->getValue()))
|
||||
) {
|
||||
$arg = new ConstantExpression($token->getValue(), $lineno);
|
||||
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
|
||||
$type = Template::METHOD_CALL;
|
||||
foreach ($this->parseArguments() as $n) {
|
||||
$arguments->addElement($n);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new SyntaxError(sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), Token::typeToEnglish($token->getType())), $lineno, $stream->getSourceContext());
|
||||
}
|
||||
|
||||
if ($node instanceof NameExpression && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
|
||||
if (!$arg instanceof ConstantExpression) {
|
||||
throw new SyntaxError(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
|
||||
}
|
||||
|
||||
$name = $arg->getAttribute('value');
|
||||
|
||||
$node = new MethodCallExpression($node, 'macro_'.$name, $arguments, $lineno);
|
||||
$node->setAttribute('safe', true);
|
||||
|
||||
return $node;
|
||||
}
|
||||
} else {
|
||||
$type = Template::ARRAY_CALL;
|
||||
|
||||
// slice?
|
||||
$slice = false;
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
|
||||
$slice = true;
|
||||
$arg = new ConstantExpression(0, $token->getLine());
|
||||
} else {
|
||||
$arg = $this->parseExpression();
|
||||
}
|
||||
|
||||
if ($stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
|
||||
$slice = true;
|
||||
}
|
||||
|
||||
if ($slice) {
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
|
||||
$length = new ConstantExpression(null, $token->getLine());
|
||||
} else {
|
||||
$length = $this->parseExpression();
|
||||
}
|
||||
|
||||
$class = $this->getFilterNodeClass('slice', $token->getLine());
|
||||
$arguments = new Node([$arg, $length]);
|
||||
$filter = new $class($node, new ConstantExpression('slice', $token->getLine()), $arguments, $token->getLine());
|
||||
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
|
||||
}
|
||||
|
||||
return new GetAttrExpression($node, $arg, $arguments, $type, $lineno);
|
||||
}
|
||||
|
||||
public function parseFilterExpression($node)
|
||||
{
|
||||
$this->parser->getStream()->next();
|
||||
|
||||
return $this->parseFilterExpressionRaw($node);
|
||||
}
|
||||
|
||||
public function parseFilterExpressionRaw($node, $tag = null)
|
||||
{
|
||||
while (true) {
|
||||
$token = $this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5);
|
||||
|
||||
$name = new ConstantExpression($token->getValue(), $token->getLine());
|
||||
if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
|
||||
$arguments = new Node();
|
||||
} else {
|
||||
$arguments = $this->parseArguments(true, false, true);
|
||||
}
|
||||
|
||||
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
|
||||
|
||||
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
|
||||
|
||||
if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '|')) {
|
||||
break;
|
||||
}
|
||||
|
||||
$this->parser->getStream()->next();
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses arguments.
|
||||
*
|
||||
* @param bool $namedArguments Whether to allow named arguments or not
|
||||
* @param bool $definition Whether we are parsing arguments for a function definition
|
||||
*
|
||||
* @return Node
|
||||
*
|
||||
* @throws SyntaxError
|
||||
*/
|
||||
public function parseArguments($namedArguments = false, $definition = false, $allowArrow = false)
|
||||
{
|
||||
$args = [];
|
||||
$stream = $this->parser->getStream();
|
||||
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(', 'A list of arguments must begin with an opening parenthesis');
|
||||
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
|
||||
if (!empty($args)) {
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'Arguments must be separated by a comma');
|
||||
|
||||
// if the comma above was a trailing comma, early exit the argument parse loop
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition) {
|
||||
$token = $stream->expect(/* Token::NAME_TYPE */ 5, null, 'An argument must be a name');
|
||||
$value = new NameExpression($token->getValue(), $this->parser->getCurrentToken()->getLine());
|
||||
} else {
|
||||
$value = $this->parseExpression(0, $allowArrow);
|
||||
}
|
||||
|
||||
$name = null;
|
||||
if ($namedArguments && $token = $stream->nextIf(/* Token::OPERATOR_TYPE */ 8, '=')) {
|
||||
if (!$value instanceof NameExpression) {
|
||||
throw new SyntaxError(sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext());
|
||||
}
|
||||
$name = $value->getAttribute('name');
|
||||
|
||||
if ($definition) {
|
||||
$value = $this->parsePrimaryExpression();
|
||||
|
||||
if (!$this->checkConstantExpression($value)) {
|
||||
throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, or an array).', $token->getLine(), $stream->getSourceContext());
|
||||
}
|
||||
} else {
|
||||
$value = $this->parseExpression(0, $allowArrow);
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition) {
|
||||
if (null === $name) {
|
||||
$name = $value->getAttribute('name');
|
||||
$value = new ConstantExpression(null, $this->parser->getCurrentToken()->getLine());
|
||||
}
|
||||
$args[$name] = $value;
|
||||
} else {
|
||||
if (null === $name) {
|
||||
$args[] = $value;
|
||||
} else {
|
||||
$args[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'A list of arguments must be closed by a parenthesis');
|
||||
|
||||
return new Node($args);
|
||||
}
|
||||
|
||||
public function parseAssignmentExpression()
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
$targets = [];
|
||||
while (true) {
|
||||
$token = $this->parser->getCurrentToken();
|
||||
if ($stream->test(/* Token::OPERATOR_TYPE */ 8) && preg_match(Lexer::REGEX_NAME, $token->getValue())) {
|
||||
// in this context, string operators are variable names
|
||||
$this->parser->getStream()->next();
|
||||
} else {
|
||||
$stream->expect(/* Token::NAME_TYPE */ 5, null, 'Only variables can be assigned to');
|
||||
}
|
||||
$value = $token->getValue();
|
||||
if (\in_array(strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), ['true', 'false', 'none', 'null'])) {
|
||||
throw new SyntaxError(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
|
||||
}
|
||||
$targets[] = new AssignNameExpression($value, $token->getLine());
|
||||
|
||||
if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Node($targets);
|
||||
}
|
||||
|
||||
public function parseMultitargetExpression()
|
||||
{
|
||||
$targets = [];
|
||||
while (true) {
|
||||
$targets[] = $this->parseExpression();
|
||||
if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Node($targets);
|
||||
}
|
||||
|
||||
private function parseNotTestExpression(Node $node): NotUnary
|
||||
{
|
||||
return new NotUnary($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
|
||||
}
|
||||
|
||||
private function parseTestExpression(Node $node): TestExpression
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
list($name, $test) = $this->getTest($node->getTemplateLine());
|
||||
|
||||
$class = $this->getTestNodeClass($test);
|
||||
$arguments = null;
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
|
||||
$arguments = $this->parseArguments(true);
|
||||
} elseif ($test->hasOneMandatoryArgument()) {
|
||||
$arguments = new Node([0 => $this->parsePrimaryExpression()]);
|
||||
}
|
||||
|
||||
if ('defined' === $name && $node instanceof NameExpression && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) {
|
||||
$node = new MethodCallExpression($alias['node'], $alias['name'], new ArrayExpression([], $node->getTemplateLine()), $node->getTemplateLine());
|
||||
$node->setAttribute('safe', true);
|
||||
}
|
||||
|
||||
return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine());
|
||||
}
|
||||
|
||||
private function getTest(int $line): array
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
$name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
|
||||
|
||||
if ($test = $this->env->getTest($name)) {
|
||||
return [$name, $test];
|
||||
}
|
||||
|
||||
if ($stream->test(/* Token::NAME_TYPE */ 5)) {
|
||||
// try 2-words tests
|
||||
$name = $name.' '.$this->parser->getCurrentToken()->getValue();
|
||||
|
||||
if ($test = $this->env->getTest($name)) {
|
||||
$stream->next();
|
||||
|
||||
return [$name, $test];
|
||||
}
|
||||
}
|
||||
|
||||
$e = new SyntaxError(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
|
||||
$e->addSuggestions($name, array_keys($this->env->getTests()));
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
private function getTestNodeClass(TwigTest $test): string
|
||||
{
|
||||
if ($test->isDeprecated()) {
|
||||
$stream = $this->parser->getStream();
|
||||
$message = sprintf('Twig Test "%s" is deprecated', $test->getName());
|
||||
|
||||
if (!\is_bool($test->getDeprecatedVersion())) {
|
||||
$message .= sprintf(' since version %s', $test->getDeprecatedVersion());
|
||||
}
|
||||
if ($test->getAlternative()) {
|
||||
$message .= sprintf('. Use "%s" instead', $test->getAlternative());
|
||||
}
|
||||
$src = $stream->getSourceContext();
|
||||
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine());
|
||||
|
||||
@trigger_error($message, \E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
return $test->getNodeClass();
|
||||
}
|
||||
|
||||
private function getFunctionNodeClass(string $name, int $line): string
|
||||
{
|
||||
if (false === $function = $this->env->getFunction($name)) {
|
||||
$e = new SyntaxError(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
|
||||
$e->addSuggestions($name, array_keys($this->env->getFunctions()));
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($function->isDeprecated()) {
|
||||
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
|
||||
if (!\is_bool($function->getDeprecatedVersion())) {
|
||||
$message .= sprintf(' since version %s', $function->getDeprecatedVersion());
|
||||
}
|
||||
if ($function->getAlternative()) {
|
||||
$message .= sprintf('. Use "%s" instead', $function->getAlternative());
|
||||
}
|
||||
$src = $this->parser->getStream()->getSourceContext();
|
||||
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
|
||||
|
||||
@trigger_error($message, \E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
return $function->getNodeClass();
|
||||
}
|
||||
|
||||
private function getFilterNodeClass(string $name, int $line): string
|
||||
{
|
||||
if (false === $filter = $this->env->getFilter($name)) {
|
||||
$e = new SyntaxError(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
|
||||
$e->addSuggestions($name, array_keys($this->env->getFilters()));
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($filter->isDeprecated()) {
|
||||
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
|
||||
if (!\is_bool($filter->getDeprecatedVersion())) {
|
||||
$message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
|
||||
}
|
||||
if ($filter->getAlternative()) {
|
||||
$message .= sprintf('. Use "%s" instead', $filter->getAlternative());
|
||||
}
|
||||
$src = $this->parser->getStream()->getSourceContext();
|
||||
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
|
||||
|
||||
@trigger_error($message, \E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
return $filter->getNodeClass();
|
||||
}
|
||||
|
||||
// checks that the node only contains "constant" elements
|
||||
private function checkConstantExpression(Node $node): bool
|
||||
{
|
||||
if (!($node instanceof ConstantExpression || $node instanceof ArrayExpression
|
||||
|| $node instanceof NegUnary || $node instanceof PosUnary
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($node as $n) {
|
||||
if (!$this->checkConstantExpression($n)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\ExpressionParser', 'Twig_ExpressionParser');
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Extension;
|
||||
|
||||
abstract class AbstractExtension implements ExtensionInterface
|
||||
{
|
||||
public function getTokenParsers()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getNodeVisitors()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getTests()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getFunctions()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getOperators()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\AbstractExtension', 'Twig_Extension');
|
||||