mirror of
https://github.com/slawkens/myaac.git
synced 2025-04-26 17:29:21 +02:00
Compare commits
405 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e13bd879db | ||
![]() |
f696f74a06 | ||
![]() |
3b18e400c0 | ||
![]() |
d1c72b3240 | ||
![]() |
7abc3c7833 | ||
![]() |
c0c4fe33e9 | ||
![]() |
05827b7861 | ||
![]() |
c304a9ab43 | ||
![]() |
d390ea325e | ||
![]() |
37ba9c7366 | ||
![]() |
7c3ebf70fa | ||
![]() |
eda773cb55 | ||
![]() |
c5c266b023 | ||
![]() |
9483cfaad8 | ||
![]() |
b4ed68dfd7 | ||
![]() |
39b19ed4c8 | ||
![]() |
580b888b1d | ||
![]() |
19d3e15c11 | ||
![]() |
5a68d204bb | ||
![]() |
e09fe51774 | ||
![]() |
b2c9eb4745 | ||
![]() |
d96787ec21 | ||
![]() |
5df5c64e4f | ||
![]() |
3c4b19743f | ||
![]() |
0e25ce553c | ||
![]() |
2e4bbeb7f7 | ||
![]() |
cb6640343b | ||
![]() |
4658d1cb29 | ||
![]() |
b25feaadf6 | ||
![]() |
2693db5f6f | ||
![]() |
8195b44061 | ||
![]() |
035d0c1012 | ||
![]() |
5a953ce901 | ||
![]() |
01660bd2b4 | ||
![]() |
5b858c521a | ||
![]() |
d1c5a189c3 | ||
![]() |
de1bb37bcb | ||
![]() |
e0036a3e32 | ||
![]() |
7f4737631d | ||
![]() |
317505bf19 | ||
![]() |
55b8645d3f | ||
![]() |
ffb8f0879b | ||
![]() |
79f5614dce | ||
![]() |
2c347d0eac | ||
![]() |
d40178104b | ||
![]() |
55543ee881 | ||
![]() |
d39386cfab | ||
![]() |
b5bbae62b0 | ||
![]() |
71ef30d35e | ||
![]() |
263c7bed07 | ||
![]() |
1458b7a412 | ||
![]() |
3e00c52128 | ||
![]() |
d73aceb272 | ||
![]() |
1c55d4a220 | ||
![]() |
1edf8833c8 | ||
![]() |
0ffc5f68b4 | ||
![]() |
81b6652738 | ||
![]() |
e5b4d2c6b3 | ||
![]() |
da1830371f | ||
![]() |
6ba04967ed | ||
![]() |
f503e140f3 | ||
![]() |
f875f3cd20 | ||
![]() |
72632c7b45 | ||
![]() |
1f2e7bd72d | ||
![]() |
016138ab55 | ||
![]() |
77efb80a12 | ||
![]() |
02eea950e4 | ||
![]() |
2793c41655 | ||
![]() |
62d3c198d5 | ||
![]() |
ef62b53cec | ||
![]() |
7181b988e9 | ||
![]() |
8b0b123f42 | ||
![]() |
f98332c698 | ||
![]() |
b1660bf27a | ||
![]() |
191ad25eb2 | ||
![]() |
7469be6efb | ||
![]() |
47a3bfd265 | ||
![]() |
5ae0be2323 | ||
![]() |
42154d55a0 | ||
![]() |
9dcc08ee6e | ||
![]() |
ba537b42bb | ||
![]() |
9c318f9012 | ||
![]() |
a88103a956 | ||
![]() |
e26e6f3a1c | ||
![]() |
08d67a07e0 | ||
![]() |
6e9a89cb2e | ||
![]() |
e3aa3d4031 | ||
![]() |
156a68f8bd | ||
![]() |
6a28da5d33 | ||
![]() |
ee32384dca | ||
![]() |
19afd73e8a | ||
![]() |
eead6a2975 | ||
![]() |
11b11dd3ee | ||
![]() |
483155cf4c | ||
![]() |
55dbade8d5 | ||
![]() |
d1bc63d07a | ||
![]() |
83a91ec540 | ||
![]() |
7b43c972dd | ||
![]() |
3fdf1d3f44 | ||
![]() |
764db0c203 | ||
![]() |
538076bc45 | ||
![]() |
4327b66f91 | ||
![]() |
3f27724569 | ||
![]() |
9c0c2bbece | ||
![]() |
946144016b | ||
![]() |
5c3b01aca4 | ||
![]() |
50983a2b85 | ||
![]() |
765886f0c7 | ||
![]() |
8ea78a5852 | ||
![]() |
063cbab93e | ||
![]() |
f1670f4012 | ||
![]() |
6fcf0f7117 | ||
![]() |
7a07763625 | ||
![]() |
8d2172a649 | ||
![]() |
b8f65207b6 | ||
![]() |
ea675afe86 | ||
![]() |
cc1cebf359 | ||
![]() |
1e874c7027 | ||
![]() |
a338fd967c | ||
![]() |
8796ff7e72 | ||
![]() |
a8172a518f | ||
![]() |
559c2c7bd2 | ||
![]() |
7a546e5a41 | ||
![]() |
5f7a9154b7 | ||
![]() |
0d52978d9f | ||
![]() |
df48363ea4 | ||
![]() |
34725e0257 | ||
![]() |
df321154f6 | ||
![]() |
f2a3ec1185 | ||
![]() |
ce4aed0f17 | ||
![]() |
d0c82f6fb0 | ||
![]() |
89b76e721d | ||
![]() |
6091290efe | ||
![]() |
e4c4990e7f | ||
![]() |
4f1235bfe9 | ||
![]() |
bf9d440a95 | ||
![]() |
59a149c253 | ||
![]() |
563099f290 | ||
![]() |
3732bf988d | ||
![]() |
ab964fa1de | ||
![]() |
b5c694224e | ||
![]() |
23810345f6 | ||
![]() |
b574a29331 | ||
![]() |
6593e32d83 | ||
![]() |
b09adc836d | ||
![]() |
dcf9a45974 | ||
![]() |
21258313ef | ||
![]() |
f851fa3845 | ||
![]() |
2fdd507902 | ||
![]() |
b850e56ff1 | ||
![]() |
8d10082179 | ||
![]() |
996ae625c9 | ||
![]() |
467f7ef927 | ||
![]() |
fa015b8d39 | ||
![]() |
4b4864561c | ||
![]() |
475cea8549 | ||
![]() |
760214fdbd | ||
![]() |
9c5dcd7b19 | ||
![]() |
720e400f7c | ||
![]() |
c261c6ba48 | ||
![]() |
933d4e1d6f | ||
![]() |
1d08833726 | ||
![]() |
7cfca55e3c | ||
![]() |
7e13b62b8f | ||
![]() |
5ccfcd541e | ||
![]() |
ba4d2a9c48 | ||
![]() |
7a61f613ec | ||
![]() |
073d9da0bc | ||
![]() |
e081a67589 | ||
![]() |
37a27b8065 | ||
![]() |
d34f7eb2fc | ||
![]() |
f6c080cb5c | ||
![]() |
a983fd03b1 | ||
![]() |
5b651886a5 | ||
![]() |
6484ab75d9 | ||
![]() |
becad18465 | ||
![]() |
ec7e5a8838 | ||
![]() |
300c1b4ebc | ||
![]() |
4f0dd89eb9 | ||
![]() |
79f7c3dbd4 | ||
![]() |
f24fc75b12 | ||
![]() |
4fcc71e127 | ||
![]() |
403b4aa89b | ||
![]() |
613bcf379b | ||
![]() |
8f2cc2ca38 | ||
![]() |
cdae11226d | ||
![]() |
79fd97ad78 | ||
![]() |
b477d4c821 | ||
![]() |
289f82ad23 | ||
![]() |
92569b7965 | ||
![]() |
c03b041f40 | ||
![]() |
2ac8ed7411 | ||
![]() |
3280b3b9df | ||
![]() |
05c37b94bb | ||
![]() |
a91e7226dc | ||
![]() |
a39600efe2 | ||
![]() |
4fd5922784 | ||
![]() |
b3d1274ffe | ||
![]() |
9de49b4b6a | ||
![]() |
e6a368c3ac | ||
![]() |
3dca1b519a | ||
![]() |
ae8af396f4 | ||
![]() |
38294420d5 | ||
![]() |
c0dee61add | ||
![]() |
a84c92e007 | ||
![]() |
60a854e5fd | ||
![]() |
fa9f7aab7c | ||
![]() |
d697a556c2 | ||
![]() |
802fd831cb | ||
![]() |
52ca8a844a | ||
![]() |
573fc819d3 | ||
![]() |
ead9d79cb1 | ||
![]() |
43c197316a | ||
![]() |
c318d3a9de | ||
![]() |
80d3f5ffe8 | ||
![]() |
f9d85b10b7 | ||
![]() |
4028a58adc | ||
![]() |
0a3a079b86 | ||
![]() |
d691148c84 | ||
![]() |
48f74b9c7a | ||
![]() |
99338afacb | ||
![]() |
301c3b86e2 | ||
![]() |
130f7ba405 | ||
![]() |
e552bcfe82 | ||
![]() |
ad75499a91 | ||
![]() |
7ddcb441c8 | ||
![]() |
99da8dbec1 | ||
![]() |
743d5164b3 | ||
![]() |
1f7dfdca50 | ||
![]() |
2164d59331 | ||
![]() |
0d845b764b | ||
![]() |
0a2cd69a4b | ||
![]() |
ddb60fa1e0 | ||
![]() |
b7e33c5e6d | ||
![]() |
095ff7963d | ||
![]() |
dfb8be07f0 | ||
![]() |
74b4d98bba | ||
![]() |
8a7e4f0132 | ||
![]() |
6ebdb0ba89 | ||
![]() |
33817e5ab1 | ||
![]() |
cd1b481de5 | ||
![]() |
ab99db62bd | ||
![]() |
dd3d6b3f47 | ||
![]() |
d99f507244 | ||
![]() |
b6c8a0923f | ||
![]() |
0663b3bbf4 | ||
![]() |
d683fce2b9 | ||
![]() |
3d56214c07 | ||
![]() |
e2575c3612 | ||
![]() |
084256ce01 | ||
![]() |
240be18367 | ||
![]() |
ac271839a6 | ||
![]() |
734a63f6c3 | ||
![]() |
e73daedd42 | ||
![]() |
802e6c228c | ||
![]() |
edf2004539 | ||
![]() |
9e949eb32a | ||
![]() |
e255c35002 | ||
![]() |
dfd3c2c4a5 | ||
![]() |
876543f064 | ||
![]() |
e10f82e0e9 | ||
![]() |
f496a48a4d | ||
![]() |
1fbb7c373e | ||
![]() |
d58d7f79e7 | ||
![]() |
0643c56bc5 | ||
![]() |
c51acf9dbd | ||
![]() |
2f2a326eac | ||
![]() |
10dad0fb4e | ||
![]() |
fe01070bd1 | ||
![]() |
b558109844 | ||
![]() |
ac37802b7a | ||
![]() |
f9c8027c3f | ||
![]() |
28dd1969b3 | ||
![]() |
50270f6d6f | ||
![]() |
fad80307d8 | ||
![]() |
323d1b0504 | ||
![]() |
d6c1232d2d | ||
![]() |
678d719036 | ||
![]() |
723e81e90e | ||
![]() |
60d2cfea99 | ||
![]() |
84c39676ee | ||
![]() |
a11d038c1d | ||
![]() |
2f627bf4b0 | ||
![]() |
67c603ef94 | ||
![]() |
dec63f353f | ||
![]() |
7ab6b026fb | ||
![]() |
a2a773d714 | ||
![]() |
aa26a71949 | ||
![]() |
e3c695175b | ||
![]() |
ccdcdd01d8 | ||
![]() |
ef2a408298 | ||
![]() |
6a4dbcef62 | ||
![]() |
c8a87a2a8a | ||
![]() |
d0bfe93d38 | ||
![]() |
75df8c5a6a | ||
![]() |
b55813e362 | ||
![]() |
575f0c62b4 | ||
![]() |
3e9544f1dc | ||
![]() |
152e5ac70e | ||
![]() |
3544643a07 | ||
![]() |
f7ae76d10f | ||
![]() |
add9370696 | ||
![]() |
cadc17cc52 | ||
![]() |
878dfc5a01 | ||
![]() |
2400f7c20a | ||
![]() |
9d7854dda6 | ||
![]() |
7303aabc2b | ||
![]() |
ab478f488a | ||
![]() |
c7a2b090d7 | ||
![]() |
f2c3b6362d | ||
![]() |
c664be7b74 | ||
![]() |
aa17ddbf24 | ||
![]() |
62faacbed6 | ||
![]() |
d03d6e2ec1 | ||
![]() |
93a1760263 | ||
![]() |
0de8894e4d | ||
![]() |
e95ea22dbd | ||
![]() |
5dbfde62a6 | ||
![]() |
0ba886bc6b | ||
![]() |
2684205b5a | ||
![]() |
856507fb66 | ||
![]() |
d019fbc050 | ||
![]() |
129d5653e6 | ||
![]() |
9560ad0c20 | ||
![]() |
a4fa7567aa | ||
![]() |
9ff032740c | ||
![]() |
dbc76abcdd | ||
![]() |
746a5dc816 | ||
![]() |
194d110079 | ||
![]() |
eed490507c | ||
![]() |
2800ab1e88 | ||
![]() |
faf40f8bed | ||
![]() |
3f12ee40ac | ||
![]() |
b4532bd473 | ||
![]() |
b389874a7e | ||
![]() |
ea2dc69f7c | ||
![]() |
b0593b0ae1 | ||
![]() |
664348e475 | ||
![]() |
e3e00f0109 | ||
![]() |
d3850280f4 | ||
![]() |
d8b3b41358 | ||
![]() |
e7706cad74 | ||
![]() |
727d6788fe | ||
![]() |
e3ecf8ec96 | ||
![]() |
1999b19a1c | ||
![]() |
c55e2910ac | ||
![]() |
ad3694ef96 | ||
![]() |
7fd784b2f6 | ||
![]() |
d8f0ac5880 | ||
![]() |
b4ee4de110 | ||
![]() |
b9713fea76 | ||
![]() |
c6dd937922 | ||
![]() |
81d4158c03 | ||
![]() |
bf0e6ff862 | ||
![]() |
8518afe70d | ||
![]() |
091ab688e7 | ||
![]() |
2e5b066d88 | ||
![]() |
cd3a15feab | ||
![]() |
836499a48c | ||
![]() |
4983816ff6 | ||
![]() |
0326657d60 | ||
![]() |
fcff820858 | ||
![]() |
dc536f0fc0 | ||
![]() |
f958b8dd4f | ||
![]() |
352d3b1bde | ||
![]() |
f3061a0e74 | ||
![]() |
d4222e98e6 | ||
![]() |
8dd07d4873 | ||
![]() |
5f891fb9d6 | ||
![]() |
b3b6d0ff5d | ||
![]() |
0ac01b3f0d | ||
![]() |
c6e55edb09 | ||
![]() |
dfc70c098f | ||
![]() |
c1d1e9596a | ||
![]() |
53078e046e | ||
![]() |
2af968031c | ||
![]() |
bdd3c394a3 | ||
![]() |
f719b3c112 | ||
![]() |
8e0001a635 | ||
![]() |
5b3581b88e | ||
![]() |
ca1436ea3f | ||
![]() |
5cd6b79ee0 | ||
![]() |
0ec5942ee4 | ||
![]() |
90af164a8a | ||
![]() |
fd83ee37ae | ||
![]() |
8e935e62be | ||
![]() |
a0d38b1f36 | ||
![]() |
6b49ecc99a | ||
![]() |
ae24a464dc | ||
![]() |
f519784cae | ||
![]() |
601cbd5ab7 | ||
![]() |
fd4a507645 | ||
![]() |
bf8d07226e | ||
![]() |
fcddfb6adf | ||
![]() |
5fcd97129e | ||
![]() |
af3a1c2f55 | ||
![]() |
13584a4d96 | ||
![]() |
6de4953d50 | ||
![]() |
b15c213890 | ||
![]() |
2f52e5d9f3 | ||
![]() |
1d6afea9c4 | ||
![]() |
8d79efd6ad | ||
![]() |
99bcd54afe | ||
![]() |
6ce6eee529 | ||
![]() |
054b40e358 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -8,3 +8,4 @@ _config.yml export-ignore
|
||||
release.sh export-ignore
|
||||
|
||||
*.sh text eol=lf
|
||||
VERSION text eol=lf
|
||||
|
16
.github/workflows/phplint.yml
vendored
Normal file
16
.github/workflows/phplint.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
name: PHP Linting
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
phplint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: overtrue/phplint@3.4.0
|
||||
with:
|
||||
path: .
|
||||
options: --exclude="system/libs/polyfill-mbstring/bootstrap80.php"
|
41
.gitignore
vendored
41
.gitignore
vendored
@ -1,11 +1,28 @@
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
.idea
|
||||
|
||||
#
|
||||
/.htaccess
|
||||
|
||||
# composer
|
||||
composer.lock
|
||||
vendor
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
tools/ext
|
||||
|
||||
# cypress
|
||||
cypress.env.json
|
||||
cypress/e2e/2-advanced-examples
|
||||
cypress/screenshots
|
||||
|
||||
# created by release.sh
|
||||
releases
|
||||
tmp
|
||||
|
||||
releases
|
||||
config.local.php
|
||||
PERSONAL_NOTES
|
||||
|
||||
# all custom templates
|
||||
templates/*
|
||||
@ -16,6 +33,16 @@ templates/*
|
||||
images/guilds/*
|
||||
!images/guilds/default.gif
|
||||
|
||||
# editor images
|
||||
images/editor/*
|
||||
!images/editor/index.html
|
||||
|
||||
# gallery images
|
||||
images/gallery/*
|
||||
!images/gallery/index.html
|
||||
!images/gallery/demon.jpg
|
||||
!images/gallery/demon_thumb.gif
|
||||
|
||||
# cache
|
||||
system/cache/*
|
||||
!system/cache/index.html
|
||||
@ -23,16 +50,26 @@ 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
|
||||
|
||||
# data
|
||||
system/data/*
|
||||
!system/data/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
|
||||
|
||||
# others/rest
|
||||
|
@ -7,13 +7,14 @@ php:
|
||||
- 7.2
|
||||
- 7.3
|
||||
- 7.4
|
||||
- 8.0
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
before_script:
|
||||
- composer require jakub-onderka/php-parallel-lint --no-suggest --no-progress --no-interaction --no-ansi --quiet --optimize-autoloader
|
||||
- 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 .
|
||||
- php vendor/bin/parallel-lint --no-progress --no-colors --exclude vendor --exclude "system/libs/pot/OTS_DB_PDOQuery_PHP71.php" .
|
||||
|
346
CHANGELOG.md
346
CHANGELOG.md
@ -1,19 +1,357 @@
|
||||
# Changelog
|
||||
|
||||
## [0.8.2 - x.x.2020]
|
||||
## [0.8.22 - 27.01.2025]
|
||||
|
||||
### Changed
|
||||
* Better exception handler, which clears the whole html output, so the message is better visible + better style (https://github.com/slawkens/myaac/commit/c304a9ab43bf0bda41907db3e6f65293350640a2 + https://github.com/slawkens/myaac/commit/7abc3c78334d44fb64684b26d8a305d0fe676caa)
|
||||
* Optimize $player->isOnline() function, thanks @gesior (https://github.com/slawkens/myaac/commit/7c3ebf70fa4751af986be7b46ee3530d4875271e)
|
||||
* All $cache->set calls should have $ttl (https://github.com/slawkens/myaac/commit/37ba9c7366139778d09d1316d7cb49a255165778)
|
||||
|
||||
### Fixed
|
||||
* exception in lostaccount.php - $account->getName() (https://github.com/slawkens/myaac/commit/d390ea325e2dbfd87a830cfe40991f58e07a87a1)
|
||||
|
||||
## [0.8.21 - 09.01.2025]
|
||||
|
||||
### Added
|
||||
* support for button_color (red, green, blue) (https://github.com/slawkens/myaac/commit/b2c9eb474513650a014352d820602b8007eb3bf3)
|
||||
|
||||
### Changed
|
||||
* Set default_socket_timeout for ipinfo.io checkup (https://github.com/slawkens/myaac/commit/e09fe517747e4f462c72395ede39759bf308d171)
|
||||
|
||||
### Fixed
|
||||
* XSS in forum (https://github.com/slawkens/myaac/commit/580b888b1dd1317d7ccf5f888536159c3bfe4324)
|
||||
* move_thread by unauthorized user (https://github.com/slawkens/myaac/commit/19d3e15c114de65ef6c379e4da66d32138a0e7c4)
|
||||
* change sex wrong price deducted (https://github.com/slawkens/myaac/commit/39b19ed4c8724385ee80f7d02219e84f6b3f5d95)
|
||||
* fix for TFS 1.4.2 exception on creating character, where conditions column is NULL (https://github.com/slawkens/myaac/commit/5a68d204bb24392d424efde4133b0a3222e788bb)
|
||||
|
||||
## [0.8.20 - 26.11.2024]
|
||||
|
||||
Small fix regarding the latest release and the linux system.
|
||||
|
||||
Download this one, instead of the 0.8.19 if you are using linux.
|
||||
|
||||
If you are using 0.8.19, make this update:
|
||||
|
||||
The fix is to make this change in the system/libs/hooks.php
|
||||
|
||||
Change
|
||||
```
|
||||
require_once LIBS . 'src/plugins.php';
|
||||
```
|
||||
|
||||
Into:
|
||||
```
|
||||
require_once LIBS . 'src/Plugins.php';
|
||||
```
|
||||
|
||||
Yeah, we just changed 'p' to 'P' - that's just case-sensitive nature of linux.
|
||||
|
||||
## [0.8.19 - 19.11.2024]
|
||||
|
||||
### Added
|
||||
* syntactic sugar for db structure changes (https://github.com/slawkens/myaac/commit/e0036a3e32e8c37c28665dd7ae18ac9b8fc167d9)
|
||||
* add "None" vocation to highscores (https://github.com/slawkens/myaac/commit/7f4737631dfcb6ec255c6d9301304d3bf222a033)
|
||||
* new hooks in account manage + create (https://github.com/slawkens/myaac/commit/d40178104b0f411b9672102c49a4b87ac16e1779)
|
||||
* new functions: getGuildNameById($id) + getGuildLogoById($id) + Plugins::installMenus($templateName, $menus, $clearOld = false) (https://github.com/slawkens/myaac/commit/de1bb37bcb6d111fbdf185ef9c2fec7e7f05053e + https://github.com/slawkens/myaac/commit/d1c5a189c3b182a36933ed507c6ae36b61fe1d45 + https://github.com/slawkens/myaac/commit/5a953ce901522d080aa16fcfcd268e9544bf6e1a)
|
||||
|
||||
### Changed
|
||||
* set default encryption to sha1 (https://github.com/slawkens/myaac/commit/55b8645d3f38c47f4aafc1906625b676c429cdd5)
|
||||
* prefer get_browser_real_ip() over REMOTE_ADDR (cause of Cloudflare and similar services) (https://github.com/slawkens/myaac/commit/b5bbae62b09db50a73bfa3e288245ea718005aa9)
|
||||
* allow account_create_character_create even if account_mail_verify is activated (https://github.com/slawkens/myaac/commit/1edf8833c844b25372017e4affaf12aa02cdce7a)
|
||||
* better https detection (patched from develop) (https://github.com/slawkens/myaac/commit/d73aceb272d0615244fcfd0998d75e6c6c15d3fe)
|
||||
* require login before create new thread (#261, @anyeor)
|
||||
* better tables.headline.html.twig (patched from 1.0) (https://github.com/slawkens/myaac/commit/71ef30d35ecb2f876e9b861f211f737302bf408e)
|
||||
|
||||
### Fixed
|
||||
* bans page fixed functions getPlayerNameByAccount + getPlayerNameById (https://github.com/slawkens/myaac/commit/d39386cfabfa13e5c916ead69e2f8f90fdc47f4f)
|
||||
* account verify - do not allow login without verified email (https://github.com/slawkens/myaac/commit/1edf8833c844b25372017e4affaf12aa02cdce7a, Thanks @anyeor)
|
||||
* if <flags> is not present in monster.xml (https://github.com/slawkens/myaac/commit/81b6652738a7b04be3980cbf55443a6fbe437b34)
|
||||
* $db->update when there is null value (https://github.com/slawkens/myaac/commit/1458b7a412ff6875cebba1b88d380f7f959ee6be)
|
||||
* error on $db __destruct saving current script name in CLI (https://github.com/slawkens/myaac/commit/01660bd2b4967315c0e16d2f83c6c39f0b78683d)
|
||||
|
||||
## [0.8.18 - 29.05.2024]
|
||||
|
||||
### Added
|
||||
* hook in guilds page to support guild wars (https://github.com/slawkens/myaac/commit/f875f3cd2059fac5c23a08ce73dd8621a66613e0)
|
||||
|
||||
## [0.8.17 - 18.05.2024]
|
||||
|
||||
### Added
|
||||
* TwigTypeCastingExtension (https://github.com/slawkens/myaac/commit/7181b988e9518320d57486670ca4e2d3b2fe1cfa)
|
||||
|
||||
### Fixed
|
||||
* fix XSS in creatures.php (https://github.com/slawkens/myaac/commit/02eea950e4fd756e8d5c32e56181986d51f5ac70, @gesior)
|
||||
* don't allow redirect to external website (https://github.com/slawkens/myaac/commit/ef62b53cec5a479cc85aa15940ad9ebbcefde876)
|
||||
* change_info if account_country is disabled (https://github.com/slawkens/myaac/commit/62d3c198d567541a90900fe2d7ede070e7b1ff68)
|
||||
|
||||
### Changed
|
||||
* use word-break: break-all in guilds description + character comment (https://github.com/slawkens/myaac/commit/191ad25eb2d4c1cec6f6668da7a345fec0ad2a7f)
|
||||
* set default status_ip to 127.0.0.1, most server are hosted locally anyway (https://github.com/slawkens/myaac/commit/2793c41655b47f7db295143a298ccda70f11462b)
|
||||
|
||||
## [0.8.16 - 12.02.2024]
|
||||
|
||||
### Fixed
|
||||
* broken installation
|
||||
* database and finish step warnings/errors (https://github.com/slawkens/myaac/pull/245, @danilopucci)
|
||||
* silently ignore if the hook does not exist
|
||||
|
||||
## [0.8.15 - 09.12.2023]
|
||||
|
||||
More security fixes, especially in bugtracker.
|
||||
|
||||
## [0-8.14 - 27.11.2023]
|
||||
Security fixes.
|
||||
|
||||
### Fixed
|
||||
* XSS vulnerability in bugtracker (https://github.com/slawkens/myaac/commit/83a91ec540072d319dd338abff45f8d5ebf48190)
|
||||
* XSS vulnerability in forum (https://github.com/slawkens/myaac/commit/d1bc63d07ad88a143358cacd2c417891eea74dcc + https://github.com/slawkens/myaac/commit/55dbade8d5280c5baed45e5f7ebc3613b8e9b9e8)
|
||||
* Session Fixation (https://github.com/slawkens/myaac/commit/483155cf4c1e3068aaee0d44541dfa61f6223379)
|
||||
* displaying ban info on account page (https://github.com/slawkens/myaac/commit/764db0c203d1826ffce3a5a78f83a97e56bd0685)
|
||||
|
||||
### Changed
|
||||
* Clear some additional cache keys - like database cache (https://github.com/slawkens/myaac/commit/4327b66f915d06dce504211692173606b9ef3b4e)
|
||||
|
||||
## [0.8.13 - 16.09.2023]
|
||||
|
||||
### Added
|
||||
* latest client versions to config (https://github.com/slawkens/myaac/commit/765886f0c782807400c429577cde5e45bd7c308f)
|
||||
* patching from develop - twig context for hooks (https://github.com/slawkens/myaac/commit/f1670f4012cc7595433fe0b1937c1f9b15a60b07)
|
||||
|
||||
### Fixed
|
||||
* fixed XSS vulnerability in some pages (https://github.com/slawkens/myaac/commit/5c3b01aca4f3cfe8abc86b8ce48194b2da87b808)
|
||||
|
||||
Nothing more or less!
|
||||
|
||||
## [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 :)
|
||||
|
||||
### 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
|
||||
* Updating template menus on template change
|
||||
* 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
|
||||
* Fix OTS_House houseid parameter
|
||||
* 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]
|
||||
|
||||
|
14
CONTRIBUTORS.txt
Normal file
14
CONTRIBUTORS.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# automatically exported using this script:
|
||||
# git log --all --format='%cN <%cE>' | sort -u > contributors
|
||||
# in no particular order
|
||||
# cleaned for readability
|
||||
|
||||
Evil Puncker <EPuncker@users.noreply.github.com>
|
||||
Fernando Matos <fernando@pixele.com.br>
|
||||
Lee <42119604+Leesneaks@users.noreply.github.com>
|
||||
caio <caio.zucoli@gmail.com>
|
||||
slawkens <slawkens@gmail.com>
|
||||
tobi132 <52947952+tobi132@users.noreply.github.com>
|
||||
vankk <nwtr.otland@hotmail.com>
|
||||
whiteblXK <krzys16001@gmail.com>
|
||||
xitobuh <jonas.hockert92@gmail.com>
|
3
CREDITS
3
CREDITS
@ -1,2 +1,3 @@
|
||||
* Gesior.pl (2007 - 2008)
|
||||
* Slawkens (2009 - 2020)
|
||||
* Slawkens (2009 - 2023)
|
||||
* Contributors listed in CONTRIBUTORS.txt
|
||||
|
77
README.md
77
README.md
@ -1,18 +1,31 @@
|
||||
# myaac
|
||||
# [MyAAC](https://my-aac.org)
|
||||
|
||||
MyAAC is a free and open-source Automatic Account Creator (AAC) written in PHP. It is a fork of the [Gesior](https://github.com/gesior/Gesior2012) project. It supports only MySQL databases.
|
||||
|
||||
Official website: https://my-aac.org
|
||||
|
||||
### REQUIREMENTS
|
||||
[](https://github.com/slawkens/myaac/actions)
|
||||
[](https://opensource.org/licenses/gpl-license)
|
||||
[](https://github.com/slawkens/myaac/releases)
|
||||
[](https://discord.gg/2J39Wus)
|
||||
[](https://github.com/slawkens/myaac/issues?q=is%3Aissue+is%3Aclosed)
|
||||
|
||||
| Version | Status | Branch | Requirements |
|
||||
|:--------|:-----------------------|:--------|:---------------|
|
||||
| **1.x** | **Active development** | develop | **PHP >= 8.1** |
|
||||
| 0.9.x | Not developed anymore | 0.9 | PHP >= 7.2.5 |
|
||||
| 0.8.x | Active support | master | PHP >= 7.2.5 |
|
||||
| 0.7.x | End Of Life | 0.7 | PHP >= 5.3.3 |
|
||||
|
||||
### Requirements
|
||||
|
||||
- PHP 5.5 or later
|
||||
- MySQL database
|
||||
- PDO PHP Extension
|
||||
- XML PHP Extension
|
||||
- ZIP PHP Extension
|
||||
- (optional) mod_rewrite to use friendly_urls
|
||||
- PHP Extensions: pdo, xml, json
|
||||
- (optional) apache2 mod_rewrite (to use friendly_urls)
|
||||
- (optional) zip PHP Extension (to install plugins)
|
||||
- (optional) gd PHP Extension (for generating signature images)
|
||||
|
||||
### INSTALLATION AND CONFIGURATION
|
||||
### Installation
|
||||
|
||||
Just decompress and untar the source (which you should have done by now,
|
||||
if you're reading this), into your webserver's document root.
|
||||
@ -28,19 +41,51 @@ Official website: https://my-aac.org
|
||||
chmod 660 images/guilds
|
||||
chmod 660 images/houses
|
||||
chmod 660 images/gallery
|
||||
chmod -R 770 system/cache
|
||||
chmod -R 760 system/cache
|
||||
|
||||
Visit http://your_domain/install (http://localhost/install) and follow instructions in the browser.
|
||||
|
||||
### KNOWN PROBLEMS
|
||||
### Configuration
|
||||
|
||||
- none -
|
||||
Check *config.php* to get more informations. (Notice: MyAAC 1.0+ doesn't use config.php anymore, it has been moved to Admin Panel - Settings page).
|
||||
|
||||
### OTHER NOTES
|
||||
Use *config.local.php* for your local configuration changes.
|
||||
|
||||
If you have a great idea or want contribute to the project - visit our website at https://www.my-aac.org
|
||||
### Branches
|
||||
|
||||
### LICENSING
|
||||
This repository follows the Git Flow Workflow.
|
||||
Cheatsheet: [Git-Flow-Cheetsheet](https://danielkummer.github.io/git-flow-cheatsheet)
|
||||
|
||||
This program and all associated files are released under the GNU Public
|
||||
License, see LICENSE for details.
|
||||
That means, we use:
|
||||
* master branch, for current stable release
|
||||
* develop branch, for development version (next release)
|
||||
* feature branches, for features etc.
|
||||
|
||||
### Known Problems
|
||||
|
||||
- Some compatibility issues with some exotical distibutions.
|
||||
|
||||
### Contributing
|
||||
|
||||
Contributions are more than welcome.
|
||||
|
||||
Pull requests should be made to the *develop* branch as that is the working branch, master is for release code.
|
||||
|
||||
Bug fixes to current release should be done to master branch.
|
||||
|
||||
Look: [Contributing](https://github.com/otsoft/myaac/wiki/Contributing) in our wiki.
|
||||
|
||||
### Other Notes
|
||||
|
||||
If you have a great idea or want contribute to the project - visit our website at https://www.my-aac.org
|
||||
|
||||
## Project supported by JetBrains
|
||||
|
||||
Many thanks to Jetbrains for kindly providing a license for me to work on this and other open-source projects.
|
||||
|
||||
[](https://www.jetbrains.com/?from=https://github.com/slawkens)
|
||||
|
||||
### License
|
||||
|
||||
This program and all associated files are released under the GNU Public License.
|
||||
See [LICENSE](https://github.com/slawkens/myaac/blob/master/LICENSE) for details.
|
||||
|
16
SECURITY.md
Normal file
16
SECURITY.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 1.x.y | :white_check_mark: |
|
||||
| 0.9.x | :x: |
|
||||
| 0.8.x | :white_check_mark: |
|
||||
| < 0.7 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you found a security vulnerability, please write an email to security@my-aac.org
|
||||
|
||||
All reports will be taken very seriously, and a fix will be posted as soon as possible.
|
@ -1 +1,2 @@
|
||||
<?php
// nothing yet here
?>
|
||||
<?php
|
||||
// nothing yet here
|
@ -2,6 +2,9 @@
|
||||
// few things we'll need
|
||||
require '../common.php';
|
||||
|
||||
define('ADMIN_PANEL', true);
|
||||
define('MYAAC_ADMIN', true);
|
||||
|
||||
if(file_exists(BASE . 'config.local.php')) {
|
||||
require_once BASE . 'config.local.php';
|
||||
}
|
||||
@ -12,8 +15,6 @@ if(file_exists(BASE . 'install') && (!isset($config['installed']) || !$config['i
|
||||
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!');
|
||||
}
|
||||
|
||||
define('ADMIN_PANEL', true);
|
||||
|
||||
$content = '';
|
||||
|
||||
// validate page
|
||||
@ -27,6 +28,12 @@ define('PAGE', $page);
|
||||
require SYSTEM . 'functions.php';
|
||||
require SYSTEM . 'init.php';
|
||||
|
||||
if(config('env') === 'dev') {
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
}
|
||||
|
||||
// event system
|
||||
require_once SYSTEM . 'hooks.php';
|
||||
$hooks = new Hooks();
|
||||
@ -34,6 +41,7 @@ $hooks->load();
|
||||
|
||||
require SYSTEM . 'status.php';
|
||||
require SYSTEM . 'login.php';
|
||||
require SYSTEM . 'migrate.php';
|
||||
require ADMIN . 'includes/functions.php';
|
||||
|
||||
$twig->addGlobal('config', $config);
|
||||
@ -45,7 +53,7 @@ if(!$logged || !admin()) {
|
||||
}
|
||||
|
||||
// include our page
|
||||
$file = SYSTEM . 'pages/admin/' . $page . '.php';
|
||||
$file = ADMIN . 'pages/' . $page . '.php';
|
||||
if(!@file_exists($file)) {
|
||||
$page = '404';
|
||||
$file = SYSTEM . 'pages/404.php';
|
||||
@ -60,4 +68,4 @@ ob_end_clean();
|
||||
// template
|
||||
$template_path = 'template/';
|
||||
require ADMIN . $template_path . 'template.php';
|
||||
?>
|
||||
|
||||
|
@ -182,7 +182,7 @@ if ($id > 0) {
|
||||
}
|
||||
|
||||
$lastDay = 0;
|
||||
if($p_days != 0 && $p_days != PHP_INT_MAX ) {
|
||||
if($p_days != 0 && $p_days != OTS_Account::GRATIS_PREMIUM_DAYS) {
|
||||
$lastDay = time();
|
||||
} else if ($lastDay != 0) {
|
||||
$lastDay = 0;
|
||||
@ -279,7 +279,13 @@ else if ($id > 0 && isset($account) && $account->isLoaded()) {
|
||||
<?php
|
||||
$acc_group = $account->getAccGroupId();
|
||||
if ($hasTypeColumn) {
|
||||
$acc_type = array("Normal", "Tutor", "Senior Tutor", "Gamemaster", "God"); ?>
|
||||
$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">
|
||||
@ -420,7 +426,7 @@ else if ($id > 0 && isset($account) && $account->isLoaded()) {
|
||||
<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; ?>"
|
||||
<input type="text" class="form-control" name="search_name" value="<?php echo escapeHtml($search_account); ?>"
|
||||
maxlength="32" size="32">
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" type="button" class="btn btn-info btn-flat">Search</button>
|
@ -10,8 +10,8 @@
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
$title = 'Load items.xml';
|
||||
|
||||
require LIBS . 'items.php';
|
||||
require LIBS . 'weapons.php';
|
||||
require_once LIBS . 'items.php';
|
||||
require_once LIBS . 'weapons.php';
|
||||
|
||||
$twig->display('admin.items.html.twig');
|
||||
|
@ -89,7 +89,7 @@ if (isset($_REQUEST['template'])) {
|
||||
if (isset($menus[$id])) {
|
||||
$i = 0;
|
||||
foreach ($menus[$id] as $menu) {
|
||||
echo '<li class="ui-state-default" id="list-' . $id . '-' . $i . '"><label>Name:</label><input type="text" name="menu[' . $id . '][]" value="' . $menu['name'] . '"/>
|
||||
echo '<li class="ui-state-default" id="list-' . $id . '-' . $i . '"><label>Name:</label><input type="text" name="menu[' . $id . '][]" value="' . escapeHtml($menu['name']) . '"/>
|
||||
<label>Link:</label><input type="text" name="menu_link[' . $id . '][]" value="' . $menu['link'] . '"/>
|
||||
<input type="hidden" name="menu_blank[' . $id . '][]" value="0" />
|
||||
<label><input class="blank-checkbox" type="checkbox" ' . ($menu['blank'] == 1 ? 'checked' : '') . '/><span title="Open in New Window">Open in New Window</span></label>
|
||||
@ -134,4 +134,4 @@ if (isset($_REQUEST['template'])) {
|
||||
$twig->display('admin.menus.form.html.twig', array(
|
||||
'templates' => $templates
|
||||
));
|
||||
}
|
||||
}
|
@ -117,7 +117,7 @@ if($action == 'edit' || $action == 'new') {
|
||||
'news_link_form' => '?p=news&action=' . ($action == 'edit' ? 'edit' : 'add'),
|
||||
'news_id' => isset($id) ? $id : null,
|
||||
'title' => isset($p_title) ? $p_title : '',
|
||||
'body' => isset($body) ? htmlentities($body, ENT_COMPAT, 'UTF-8') : '',
|
||||
'body' => isset($body) ? escapeHtml($body) : '',
|
||||
'type' => isset($type) ? $type : null,
|
||||
'player' => isset($player) && $player->isLoaded() ? $player : null,
|
||||
'player_id' => isset($player_id) ? $player_id : null,
|
@ -105,7 +105,7 @@ $twig->display('admin.pages.form.html.twig', array(
|
||||
'title' => $p_title,
|
||||
'php' => $php,
|
||||
'enable_tinymce' => $enable_tinymce,
|
||||
'body' => isset($body) ? htmlentities($body, ENT_COMPAT, 'UTF-8') : '',
|
||||
'body' => isset($body) ? escapeHtml($body) : '',
|
||||
'groups' => $groups->getGroups(),
|
||||
'access' => $access
|
||||
));
|
||||
@ -196,5 +196,3 @@ class Pages
|
||||
return !count($errors);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -210,7 +210,7 @@ if ($id > 0) {
|
||||
|
||||
if ($hasBlessingsColumn) {
|
||||
$blessings = $_POST['blessings'];
|
||||
verify_number($blessings, 'Blessings', 2);
|
||||
verify_number($blessings, 'Blessings', 3);
|
||||
}
|
||||
|
||||
$balance = $_POST['balance'];
|
||||
@ -650,7 +650,7 @@ else if ($id > 0 && isset($player) && $player->isLoaded())
|
||||
<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->getLookBody(); ?>"
|
||||
value="<?php echo $player->getLookFeet(); ?>"
|
||||
class="slider form-control" id="look_feet" name="look_feet">
|
||||
</div>
|
||||
</div>
|
||||
@ -697,7 +697,14 @@ else if ($id > 0 && isset($player) && $player->isLoaded())
|
||||
<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 echo longToIp($player->getLastIP()); ?>"
|
||||
maxlength="10" value="<?php
|
||||
if (strlen($player->getLastIP()) > 11) {
|
||||
echo inet_ntop($player->getLastIP());
|
||||
}
|
||||
else {
|
||||
echo longToIp($player->getLastIP());
|
||||
}
|
||||
?>"
|
||||
readonly/>
|
||||
</div>
|
||||
</div>
|
||||
@ -777,7 +784,7 @@ else if ($id > 0 && isset($player) && $player->isLoaded())
|
||||
<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; ?>"
|
||||
<input type="text" class="form-control" name="search_name" value="<?php echo escapeHtml($search_name); ?>"
|
||||
maxlength="32" size="32">
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" type="button" class="btn btn-info btn-flat">Search</button>
|
||||
@ -885,15 +892,13 @@ else if ($id > 0 && isset($player) && $player->isLoaded())
|
||||
var look_feet = $('#look_feet').val();
|
||||
var look_type = $('#look_type').val();
|
||||
|
||||
var look_addons = '';
|
||||
<?php if($hasLookAddons): ?>
|
||||
var look_addons = '&addons=' + $('#look_addons').val();
|
||||
<?php
|
||||
else: ?>
|
||||
var look_addons = '';
|
||||
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>
|
||||
</script>
|
@ -10,8 +10,6 @@
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
$title = 'Plugin manager';
|
||||
|
||||
require_once LIBS . 'plugins.php';
|
||||
|
||||
$twig->display('admin.plugins.form.html.twig');
|
||||
|
||||
if (isset($_REQUEST['uninstall'])) {
|
@ -36,4 +36,3 @@ $twig->display('admin.statistics.html.twig', array(
|
||||
'account_type' => (USE_ACCOUNT_NAME ? 'name' : 'number'),
|
||||
'points' => $points
|
||||
));
|
||||
?>
|
@ -26,7 +26,7 @@ if ($version_compare == 0) {
|
||||
success('MyAAC latest version is ' . $myaac_version . '. You\'re using the latest version.
|
||||
<br/>View CHANGELOG ' . generateLink(ADMIN_URL . '?p=changelog', 'here'));
|
||||
} else if ($version_compare < 0) {
|
||||
echo success('Woah, seems you\'re using newer version as latest released one! MyAAC latest released version is ' . $myaac_version . ', and you\'re using version ' . MYAAC_VERSION . '.
|
||||
success('Woah, seems you\'re using newer version as latest released one! MyAAC latest released version is ' . $myaac_version . ', and you\'re using version ' . MYAAC_VERSION . '.
|
||||
<br/>View CHANGELOG ' . generateLink(ADMIN_URL . '?p=changelog', 'here'));
|
||||
} else {
|
||||
warning('You\'re using outdated version.<br/>
|
||||
@ -47,4 +47,3 @@ function version_revert($version)
|
||||
$release = $version;
|
||||
return $major . '.' . $minor . '.' . $release;
|
||||
}*/
|
||||
?>
|
@ -1,4 +1,6 @@
|
||||
<?php
|
||||
define('MYAAC_ADMIN', true);
|
||||
|
||||
require '../../common.php';
|
||||
require SYSTEM . 'functions.php';
|
||||
require SYSTEM . 'init.php';
|
||||
@ -11,4 +13,3 @@ if(!function_exists('phpinfo'))
|
||||
die('phpinfo() disabled on this web server.');
|
||||
|
||||
phpinfo();
|
||||
?>
|
||||
|
@ -1,4 +1,6 @@
|
||||
<?php
|
||||
define('MYAAC_ADMIN', true);
|
||||
|
||||
require '../../common.php';
|
||||
require SYSTEM . 'init.php';
|
||||
require SYSTEM . 'functions.php';
|
||||
|
58
common.php
58
common.php
@ -23,15 +23,15 @@
|
||||
* @copyright 2019 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
if (version_compare(phpversion(), '5.5', '<')) die('PHP version 5.5 or higher is required.');
|
||||
session_start();
|
||||
if (version_compare(phpversion(), '7.2.5', '<')) die('PHP version 7.2.5 or higher is required.');
|
||||
|
||||
define('MYAAC', true);
|
||||
define('MYAAC_VERSION', '0.8.2-dev');
|
||||
define('DATABASE_VERSION', 30);
|
||||
define('MYAAC_VERSION', '0.8.22');
|
||||
define('DATABASE_VERSION', 33);
|
||||
define('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);
|
||||
@ -85,6 +85,11 @@ define('TFS_03', 4);
|
||||
define('TFS_FIRST', TFS_02);
|
||||
define('TFS_LAST', TFS_03);
|
||||
|
||||
if (!IS_CLI) {
|
||||
session_save_path(SYSTEM . 'php_sessions');
|
||||
session_start();
|
||||
}
|
||||
|
||||
// basedir
|
||||
$basedir = '';
|
||||
$tmp = explode('/', $_SERVER['SCRIPT_NAME']);
|
||||
@ -92,26 +97,39 @@ $size = count($tmp) - 1;
|
||||
for($i = 1; $i < $size; $i++)
|
||||
$basedir .= '/' . $tmp[$i];
|
||||
|
||||
$basedir = str_replace(array('/admin', '/install'), '', $basedir);
|
||||
$basedir = str_replace(array('/admin', '/install', '/tools'), '', $basedir);
|
||||
define('BASE_DIR', $basedir);
|
||||
|
||||
if(isset($_SERVER['HTTP_HOST'][0])) {
|
||||
$baseHost = $_SERVER['HTTP_HOST'];
|
||||
}
|
||||
else {
|
||||
if(isset($_SERVER['SERVER_NAME'][0])) {
|
||||
$baseHost = $_SERVER['SERVER_NAME'];
|
||||
}
|
||||
else {
|
||||
$baseHost = $_SERVER['SERVER_ADDR'];
|
||||
}
|
||||
if (file_exists(BASE . 'config.local.php') && !defined('MYAAC_INSTALL')) {
|
||||
require BASE . 'config.local.php';
|
||||
}
|
||||
|
||||
define('SERVER_URL', 'http' . (isset($_SERVER['HTTPS'][0]) && strtolower($_SERVER['HTTPS']) === 'on' ? 's' : '') . '://' . $baseHost);
|
||||
define('BASE_URL', SERVER_URL . BASE_DIR . '/');
|
||||
define('ADMIN_URL', SERVER_URL . BASE_DIR . '/admin/');
|
||||
if(!IS_CLI) {
|
||||
if (isset($_SERVER['HTTP_HOST'][0])) {
|
||||
$baseHost = $_SERVER['HTTP_HOST'];
|
||||
} else {
|
||||
if (isset($_SERVER['SERVER_NAME'][0])) {
|
||||
$baseHost = $_SERVER['SERVER_NAME'];
|
||||
} else {
|
||||
$baseHost = $_SERVER['SERVER_ADDR'];
|
||||
}
|
||||
}
|
||||
|
||||
//define('CURRENT_URL', BASE_URL . $_SERVER['REQUEST_URI']);
|
||||
define('SERVER_URL', 'http' . (isHttps() ? 's' : '') . '://' . $baseHost);
|
||||
define('BASE_URL', SERVER_URL . BASE_DIR . '/');
|
||||
define('ADMIN_URL', SERVER_URL . BASE_DIR . '/admin/');
|
||||
|
||||
require SYSTEM . 'exception.php';
|
||||
//define('CURRENT_URL', BASE_URL . $_SERVER['REQUEST_URI']);
|
||||
if(@$config['env'] === 'dev') {
|
||||
require SYSTEM . 'exception.php';
|
||||
}
|
||||
}
|
||||
require SYSTEM . 'autoload.php';
|
||||
|
||||
function isHttps(): bool
|
||||
{
|
||||
return
|
||||
(!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https')
|
||||
|| (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|
||||
|| (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] === 443);
|
||||
}
|
||||
|
43
config.php
43
config.php
@ -77,6 +77,7 @@ $config = array(
|
||||
'database_log' => false, // should database queries be logged and and saved into system/logs/database.log?
|
||||
'database_socket' => '', // set if you want to connect to database through socket (example: /var/run/mysqld/mysqld.sock)
|
||||
'database_persistent' => false, // use database permanent connection (like server), may speed up your site
|
||||
'database_encryption' => 'sha1',
|
||||
|
||||
// multiworld system (only TFS 0.3)
|
||||
'multiworld' => false, // use multiworld system?
|
||||
@ -86,14 +87,21 @@ $config = array(
|
||||
),
|
||||
|
||||
// images
|
||||
'outfit_images_url' => 'http://outfit-images.ots.me/outfit.php', // set to animoutfit.php for animated outfit
|
||||
'item_images_url' => 'http://item-images.ots.me/1092/', // set to images/items if you host your own items in images folder
|
||||
'outfit_images_url' => 'https://outfit-images.ots.me/outfit.php', // set to animoutfit.php for animated outfit
|
||||
'item_images_url' => 'https://item-images.ots.me/1092/', // set to images/items if you host your own items in images folder
|
||||
|
||||
// account
|
||||
'account_management' => true, // disable if you're using other method to manage users (fe. tfs account manager)
|
||||
'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
|
||||
'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_unique' => true, // email addresses cannot be duplicated? (one account = one email)
|
||||
'account_premium_days' => 0, // default premium days on new account
|
||||
'account_premium_points' => 0, // default premium points on new account
|
||||
@ -151,12 +159,17 @@ $config = array(
|
||||
4 => 'Knight Sample'
|
||||
),
|
||||
|
||||
'use_character_sample_skills' => false,
|
||||
|
||||
// it must show limited number of players after using search in character page
|
||||
'characters_search_limit' => 15,
|
||||
|
||||
// town list used when creating character
|
||||
// won't be displayed if there is only one item (rookgaard for example)
|
||||
'character_towns' => array(1),
|
||||
|
||||
// characters lenght
|
||||
// This is the minimum and the maximum length that a player can create a character. It is highly recommend the maximum lenght be 21.
|
||||
// characters length
|
||||
// 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,
|
||||
|
||||
@ -221,7 +234,10 @@ $config = array(
|
||||
'frags' => false,
|
||||
'deleted' => false, // should deleted characters from same account be still listed on the list of characters? When enabled it will show that character is "[DELETED]"
|
||||
),
|
||||
'quests' => array(), // quests list (displayed in character view), name => storage
|
||||
'quests' => array(
|
||||
//'Some Quest' => 123,
|
||||
//'Some Quest Two' => 456,
|
||||
), // quests list (displayed in character view), name => storage
|
||||
'signature_enabled' => true,
|
||||
'signature_type' => 'tibian', // signature engine to use: tibian, mango, gesior
|
||||
'signature_cache_time' => 5, // how long to store cached file (in minutes), default 5 minutes
|
||||
@ -252,9 +268,10 @@ $config = array(
|
||||
'last_kills_limit' => 50, // max. number of deaths shown on the last kills page
|
||||
|
||||
// status, took automatically from config file if empty
|
||||
'status_ip' => '',
|
||||
'status_enabled' => true, // you can disable status checking by settings this to "false"
|
||||
'status_ip' => '127.0.0.1',
|
||||
'status_port' => '',
|
||||
'status_timeout' => 2, // how long to wait for the initial response from the server (default: 2 seconds)
|
||||
'status_timeout' => 1.0, // how long to wait for the initial response from the server (default: 1 second)
|
||||
|
||||
// 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
|
||||
@ -273,5 +290,13 @@ $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()
|
||||
'npc' => array(),
|
||||
|
||||
// character name blocked
|
||||
'character_name_blocked' => array(
|
||||
'prefix' => array(),
|
||||
'names' => array(),
|
||||
'words' => array(),
|
||||
),
|
||||
|
||||
);
|
||||
|
0
images/gallery/index.html
Normal file
0
images/gallery/index.html
Normal file
89
index.php
89
index.php
@ -24,6 +24,7 @@
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
|
||||
ob_start();
|
||||
require_once 'common.php';
|
||||
require_once SYSTEM . 'functions.php';
|
||||
|
||||
@ -38,7 +39,7 @@ else
|
||||
$uri = str_replace(array('index.php/', '?'), '', $uri);
|
||||
define('URI', $uri);
|
||||
|
||||
if(preg_match("/^[A-Za-z0-9-_%\'+]+\.png$/i", $uri)) {
|
||||
if(preg_match("/^[A-Za-z0-9-_%'+]+\.png$/i", $uri)) {
|
||||
$tmp = explode('.', $uri);
|
||||
$_REQUEST['name'] = urldecode($tmp[0]);
|
||||
|
||||
@ -48,7 +49,7 @@ if(preg_match("/^[A-Za-z0-9-_%\'+]+\.png$/i", $uri)) {
|
||||
}
|
||||
|
||||
if(preg_match("/^(.*)\.(gif|jpg|png|jpeg|tiff|bmp|css|js|less|map|html|php|zip|rar|gz|ttf|woff|ico)$/i", $_SERVER['REQUEST_URI'])) {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
http_response_code(404);
|
||||
exit;
|
||||
}
|
||||
|
||||
@ -56,11 +57,17 @@ if(file_exists(BASE . 'config.local.php')) {
|
||||
require_once BASE . 'config.local.php';
|
||||
}
|
||||
|
||||
ini_set('log_errors', 1);
|
||||
if(config('env') === 'dev') {
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
}
|
||||
else {
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('display_startup_errors', 0);
|
||||
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
|
||||
}
|
||||
|
||||
if((!isset($config['installed']) || !$config['installed']) && file_exists(BASE . 'install'))
|
||||
{
|
||||
@ -68,6 +75,14 @@ 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';
|
||||
@ -75,7 +90,11 @@ if(empty($uri) || isset($_REQUEST['template'])) {
|
||||
}
|
||||
else {
|
||||
$tmp = strtolower($uri);
|
||||
if(!preg_match('/[^A-z0-9_\-]/', $uri) && file_exists(SYSTEM . 'pages/' . $tmp . '.php')) {
|
||||
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')) {
|
||||
$_REQUEST['p'] = $uri;
|
||||
$found = true;
|
||||
}
|
||||
@ -127,13 +146,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);
|
||||
}
|
||||
|
||||
@ -148,6 +167,12 @@ 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)) {
|
||||
@ -168,44 +193,17 @@ define('PAGE', $page);
|
||||
|
||||
$template_place_holders = array();
|
||||
|
||||
require_once SYSTEM . 'init.php';
|
||||
|
||||
// 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';
|
||||
|
||||
$twig->addGlobal('config', $config);
|
||||
$twig->addGlobal('status', $status);
|
||||
|
||||
// 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.');
|
||||
}
|
||||
|
||||
// database migrations
|
||||
$tmp = '';
|
||||
if(fetchDatabaseConfig('database_version', $tmp)) { // we got version
|
||||
$tmp = (int)$tmp;
|
||||
if($tmp < DATABASE_VERSION) { // import if older
|
||||
$db->revalidateCache();
|
||||
for($i = $tmp + 1; $i <= DATABASE_VERSION; $i++) {
|
||||
require SYSTEM . 'migrations/' . $i . '.php';
|
||||
updateDatabaseConfig('database_version', $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // register first version
|
||||
registerDatabaseConfig('database_version', 0);
|
||||
$db->revalidateCache();
|
||||
for($i = 1; $i <= DATABASE_VERSION; $i++) {
|
||||
require SYSTEM . 'migrations/' . $i . '.php';
|
||||
updateDatabaseConfig('database_version', $i);
|
||||
}
|
||||
}
|
||||
require SYSTEM . 'migrate.php';
|
||||
|
||||
$hooks->trigger(HOOK_STARTUP);
|
||||
|
||||
@ -224,7 +222,7 @@ if(isset($config['anonymous_usage_statistics']) && $config['anonymous_usage_stat
|
||||
if(fetchDatabaseConfig('last_usage_report', $value)) {
|
||||
$should_report = time() > (int)$value + $report_time;
|
||||
if($cache->enabled()) {
|
||||
$cache->set('last_usage_report', $value);
|
||||
$cache->set('last_usage_report', $value, 60 * 60);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -239,7 +237,7 @@ if(isset($config['anonymous_usage_statistics']) && $config['anonymous_usage_stat
|
||||
|
||||
updateDatabaseConfig('last_usage_report', time());
|
||||
if($cache->enabled()) {
|
||||
$cache->set('last_usage_report', time());
|
||||
$cache->set('last_usage_report', time(), 60 * 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -301,6 +299,7 @@ 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';
|
||||
@ -325,8 +324,10 @@ if($load_it)
|
||||
if(SITE_CLOSED && admin())
|
||||
$content .= '<p class="note">Site is under maintenance (closed mode). Only privileged users can see it.</p>';
|
||||
|
||||
if($config['backward_support'])
|
||||
require SYSTEM . 'compat_pages.php';
|
||||
if($config['backward_support']) {
|
||||
require SYSTEM . 'compat/pages.php';
|
||||
require SYSTEM . 'compat/classes.php';
|
||||
}
|
||||
|
||||
$ignore = false;
|
||||
|
||||
@ -346,11 +347,13 @@ if($load_it)
|
||||
)) . $content;
|
||||
}
|
||||
} else {
|
||||
$file = SYSTEM . 'pages/' . $page . '.php';
|
||||
if(!@file_exists($file))
|
||||
{
|
||||
$page = '404';
|
||||
$file = SYSTEM . 'pages/404.php';
|
||||
$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)) {
|
||||
$page = '404';
|
||||
$file = SYSTEM . 'pages/404.php';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,4 +38,3 @@ if(!isset($error) || !$error) {
|
||||
$error = true;
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,3 +1,5 @@
|
||||
SET @myaac_database_version = 33;
|
||||
|
||||
CREATE TABLE `myaac_account_actions`
|
||||
(
|
||||
`account_id` INT(11) NOT NULL,
|
||||
@ -57,6 +59,8 @@ CREATE TABLE `myaac_config`
|
||||
UNIQUE (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
|
||||
|
||||
INSERT INTO `myaac_config` (`name`, `value`) VALUES ('database_version', @myaac_database_version);
|
||||
|
||||
CREATE TABLE `myaac_faq`
|
||||
(
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
@ -320,9 +324,9 @@ CREATE TABLE `myaac_spells`
|
||||
|
||||
CREATE TABLE `myaac_visitors`
|
||||
(
|
||||
`ip` VARCHAR(16) NOT NULL,
|
||||
`ip` VARCHAR(45) NOT NULL,
|
||||
`lastvisit` INT(11) NOT NULL DEFAULT 0,
|
||||
`page` VARCHAR(100) NOT NULL,
|
||||
`page` VARCHAR(2048) NOT NULL,
|
||||
UNIQUE (`ip`)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
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>
|
||||
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>
|
||||
|
||||
<style type="text/css">
|
||||
.console {
|
||||
font-family:Courier;
|
||||
font-family: Courier,serif;
|
||||
color: #CCCCCC;
|
||||
background: #000000;
|
||||
border: 3px double #CCCCCC;
|
||||
padding: 0px;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
@ -70,7 +70,7 @@ if($step == 'database') {
|
||||
|
||||
$key = str_replace('var_', '', $key);
|
||||
|
||||
if(in_array($key, array('account', 'password', 'email', 'player_name'))) {
|
||||
if(in_array($key, array('account', 'account_id', 'password', 'email', 'player_name'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -114,14 +114,12 @@ if($step == 'database') {
|
||||
}
|
||||
}
|
||||
else if($step == 'admin') {
|
||||
$config_failed = true;
|
||||
if(file_exists(BASE . 'config.local.php') && isset($config['installed']) && $config['installed'] && isset($_SESSION['saved'])) {
|
||||
$config_failed = false;
|
||||
}
|
||||
|
||||
if($config_failed) {
|
||||
if(!file_exists(BASE . 'config.local.php') || !isset($config['installed']) || !$config['installed']) {
|
||||
$step = 'database';
|
||||
}
|
||||
else {
|
||||
$_SESSION['saved'] = true;
|
||||
}
|
||||
}
|
||||
else if($step == 'finish') {
|
||||
$email = $_SESSION['var_email'];
|
||||
@ -191,14 +189,14 @@ clearstatcache();
|
||||
if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) {
|
||||
if(!file_exists(BASE . 'install/ip.txt')) {
|
||||
$content = warning('AAC installation is disabled. To enable it make file <b>ip.txt</b> in install/ directory and put there your IP.<br/>
|
||||
Your IP is:<br /><b>' . $_SERVER['REMOTE_ADDR'] . '</b>', true);
|
||||
Your IP is:<br /><b>' . get_browser_real_ip() . '</b>', true);
|
||||
}
|
||||
else {
|
||||
$file_content = trim(file_get_contents(BASE . 'install/ip.txt'));
|
||||
$allow = false;
|
||||
$listIP = preg_split('/\s+/', $file_content);
|
||||
foreach($listIP as $ip) {
|
||||
if($_SERVER['REMOTE_ADDR'] == $ip) {
|
||||
if(get_browser_real_ip() == $ip) {
|
||||
$allow = true;
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,3 @@ $twig->display('install.license.html.twig', array(
|
||||
'license' => file_get_contents(BASE . 'LICENSE'),
|
||||
'buttons' => next_buttons()
|
||||
));
|
||||
?>
|
||||
|
@ -1,6 +1,10 @@
|
||||
<?php
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
// configuration
|
||||
$extensions_required = [
|
||||
'pdo', 'pdo_mysql', 'xml', 'zip'
|
||||
];
|
||||
/*
|
||||
*
|
||||
* @param string $name
|
||||
@ -35,9 +39,11 @@ version_check('register_long_arrays', !$ini_register_globals, $ini_register_glob
|
||||
$ini_safe_mode = ini_get_bool('safe_mode');
|
||||
version_check('safe_mode', !$ini_safe_mode, $ini_safe_mode ? $locale['on'] : $locale['off'], true);
|
||||
|
||||
version_check(str_replace('$EXTENSION$', 'PDO', $locale['step_requirements_extension']) , extension_loaded('pdo'), extension_loaded('pdo') ? $locale['loaded'] : $locale['not_loaded']);
|
||||
version_check(str_replace('$EXTENSION$', 'XML', $locale['step_requirements_extension']), extension_loaded('xml'), extension_loaded('xml') ? $locale['loaded'] : $locale['not_loaded']);
|
||||
version_check(str_replace('$EXTENSION$', 'ZIP', $locale['step_requirements_extension']), extension_loaded('zip'), extension_loaded('zip') ? $locale['loaded'] : $locale['not_loaded']);
|
||||
foreach ($extensions_required as $ext) {
|
||||
$loaded = extension_loaded($ext);
|
||||
version_check(str_replace('$EXTENSION$', strtoupper($ext), $locale['step_requirements_extension']) , $loaded, $loaded ? $locale['loaded'] : $locale['not_loaded']);
|
||||
}
|
||||
|
||||
|
||||
if($failed)
|
||||
{
|
||||
|
@ -18,4 +18,3 @@ $twig->display('install.config.html.twig', array(
|
||||
'errors' => isset($errors) ? $errors : null,
|
||||
'buttons' => next_buttons()
|
||||
));
|
||||
?>
|
@ -57,16 +57,35 @@ if(!$error) {
|
||||
error($database_error);
|
||||
}
|
||||
else {
|
||||
$twig->display('install.installer.html.twig', array(
|
||||
'url' => 'tools/5-database.php',
|
||||
'message' => $locale['loading_spinner']
|
||||
));
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -82,6 +101,7 @@ if(!$error) {
|
||||
}
|
||||
|
||||
if($saved) {
|
||||
success($locale['step_database_config_saved']);
|
||||
if(!$error) {
|
||||
$_SESSION['saved'] = true;
|
||||
}
|
||||
@ -91,7 +111,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']);
|
||||
warning($locale['step_database_error_file'] . '<br/>
|
||||
error($locale['step_database_error_file'] . '<br/>
|
||||
<textarea cols="70" rows="10">' . $content . '</textarea>');
|
||||
}
|
||||
}
|
||||
@ -102,6 +122,6 @@ 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 ? false : true);
|
||||
<?php echo next_buttons(true, !$error);
|
||||
?>
|
||||
</form>
|
||||
</form>
|
||||
|
@ -66,7 +66,6 @@ else {
|
||||
$new_account->setPassword(encrypt($password));
|
||||
$new_account->setEMail($email);
|
||||
|
||||
$new_account->unblock();
|
||||
$new_account->save();
|
||||
|
||||
$new_account->setCustomField('created', time());
|
||||
@ -80,10 +79,12 @@ else {
|
||||
|
||||
$account_used->setCustomField('web_flags', FLAG_ADMIN + FLAG_SUPER_ADMIN);
|
||||
$account_used->setCustomField('country', 'us');
|
||||
$account_used->setCustomField('email_verified', 1);
|
||||
|
||||
if($db->hasColumn('accounts', 'group_id'))
|
||||
$account_used->setCustomField('group_id', $groups->getHighestId());
|
||||
if($db->hasColumn('accounts', 'type'))
|
||||
$account_used->setCustomField('type', 5);
|
||||
$account_used->setCustomField('type', 6);
|
||||
|
||||
if(!$player_db->isLoaded())
|
||||
$player->setAccountId($account_used->getId());
|
||||
|
@ -1,3 +1,4 @@
|
||||
<?php defined('MYAAC') or die('Direct access not allowed!'); ?>
|
||||
<!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']; ?>">
|
||||
<head>
|
||||
@ -45,4 +46,4 @@
|
||||
<p style="text-align: center;"><?php echo base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4='); ?></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -1,4 +1,6 @@
|
||||
<?php
|
||||
define('MYAAC_INSTALL', true);
|
||||
|
||||
require_once '../../common.php';
|
||||
|
||||
require SYSTEM . 'functions.php';
|
||||
@ -9,8 +11,10 @@ $error = false;
|
||||
require BASE . 'install/includes/config.php';
|
||||
|
||||
ini_set('max_execution_time', 300);
|
||||
|
||||
@ob_end_flush();
|
||||
ob_implicit_flush();
|
||||
ob_end_flush();
|
||||
|
||||
header('X-Accel-Buffering: no');
|
||||
|
||||
if(!$error) {
|
||||
@ -21,24 +25,6 @@ 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']);
|
||||
@ -48,7 +34,6 @@ else {
|
||||
try {
|
||||
$db->query(file_get_contents(BASE . 'install/includes/schema.sql'));
|
||||
|
||||
registerDatabaseConfig('database_version', DATABASE_VERSION);
|
||||
$locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']);
|
||||
success($locale['step_database_success_schema']);
|
||||
}
|
||||
@ -72,13 +57,8 @@ 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' : 'blocked') . "`;"))
|
||||
if(query("ALTER TABLE `accounts` ADD `created` INT(11) NOT NULL DEFAULT 0 AFTER `" . ($db->hasColumn('accounts', 'group_id') ? 'group_id' : 'email') . "`;"))
|
||||
success($locale['step_database_adding_field'] . ' accounts.created...');
|
||||
}
|
||||
|
||||
@ -247,4 +227,4 @@ if($db->hasTable('z_forum')) {
|
||||
success($locale['step_database_adding_field'] . ' z_forum.closed...');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
<?php
|
||||
define('MYAAC_INSTALL', true);
|
||||
|
||||
require_once '../../common.php';
|
||||
|
||||
require SYSTEM . 'functions.php';
|
||||
@ -6,8 +8,10 @@ require BASE . 'install/includes/functions.php';
|
||||
require BASE . 'install/includes/locale.php';
|
||||
|
||||
ini_set('max_execution_time', 300);
|
||||
|
||||
@ob_end_flush();
|
||||
ob_implicit_flush();
|
||||
ob_end_flush();
|
||||
|
||||
header('X-Accel-Buffering: no');
|
||||
|
||||
if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) {
|
||||
@ -34,10 +38,10 @@ function insert_sample_if_not_exist($p) {
|
||||
|
||||
$success = true;
|
||||
insert_sample_if_not_exist(array('name' => 'Rook Sample', 'level' => 1, 'vocation_id' => 0, 'health' => 150, 'healthmax' => 150, 'experience' => 0, 'looktype' => 130, 'mana' => 0, 'manamax' => 0, 'soul' => 100, 'cap' => 400));
|
||||
insert_sample_if_not_exist(array('name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 35, 'manamax' => 35, 'soul' => 100, 'cap' => 470));
|
||||
insert_sample_if_not_exist(array('name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 35, 'manamax' => 35, 'soul' => 100, 'cap' => 470));
|
||||
insert_sample_if_not_exist(array('name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 35, 'manamax' => 35, 'soul' => 100, 'cap' => 470));
|
||||
insert_sample_if_not_exist(array('name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 35, 'manamax' => 35, 'soul' => 100, 'cap' => 470));
|
||||
insert_sample_if_not_exist(array('name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
|
||||
insert_sample_if_not_exist(array('name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
|
||||
insert_sample_if_not_exist(array('name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
|
||||
insert_sample_if_not_exist(array('name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
|
||||
|
||||
if($success) {
|
||||
success($locale['step_database_imported_players']);
|
||||
@ -91,6 +95,7 @@ require_once SYSTEM . 'migrations/22.php';
|
||||
|
||||
// add myaac_pages pages
|
||||
require_once SYSTEM . 'migrations/27.php';
|
||||
require_once SYSTEM . 'migrations/30.php';
|
||||
|
||||
$locale['step_finish_desc'] = str_replace('$ADMIN_PANEL$', generateLink(str_replace('tools/', '',ADMIN_URL), $locale['step_finish_admin_panel'], true), $locale['step_finish_desc']);
|
||||
$locale['step_finish_desc'] = str_replace('$HOMEPAGE$', generateLink(str_replace('tools/', '', BASE_URL), $locale['step_finish_homepage'], true), $locale['step_finish_desc']);
|
||||
|
285
login.php
Normal file
285
login.php
Normal file
@ -0,0 +1,285 @@
|
||||
<?php
|
||||
require_once 'common.php';
|
||||
require_once 'config.php';
|
||||
require_once 'config.local.php';
|
||||
require_once SYSTEM . 'functions.php';
|
||||
require_once SYSTEM . 'init.php';
|
||||
require_once SYSTEM . 'status.php';
|
||||
|
||||
# error function
|
||||
function sendError($message, $code = 3){
|
||||
$ret = [];
|
||||
$ret['errorCode'] = $code;
|
||||
$ret['errorMessage'] = $message;
|
||||
die(json_encode($ret));
|
||||
}
|
||||
|
||||
# event schedule function
|
||||
function parseEvent($table1, $date, $table2)
|
||||
{
|
||||
if ($table1) {
|
||||
if ($date) {
|
||||
if ($table2) {
|
||||
$date = $table1->getAttribute('startdate');
|
||||
return date_create("{$date}")->format('U');
|
||||
} else {
|
||||
$date = $table1->getAttribute('enddate');
|
||||
return date_create("{$date}")->format('U');
|
||||
}
|
||||
} else {
|
||||
foreach($table1 as $attr) {
|
||||
if ($attr) {
|
||||
return $attr->getAttribute($table2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'error';
|
||||
}
|
||||
|
||||
$request = json_decode(file_get_contents('php://input'));
|
||||
$action = $request->type ?? '';
|
||||
|
||||
/** @var OTS_Base_DB $db */
|
||||
/** @var array $config */
|
||||
|
||||
switch ($action) {
|
||||
case 'cacheinfo':
|
||||
$playersonline = $db->query("select count(*) from `players_online`")->fetchAll();
|
||||
die(json_encode([
|
||||
'playersonline' => (intval($playersonline[0][0])),
|
||||
'twitchstreams' => 0,
|
||||
'twitchviewer' => 0,
|
||||
'gamingyoutubestreams' => 0,
|
||||
'gamingyoutubeviewer' => 0
|
||||
]));
|
||||
|
||||
case 'eventschedule':
|
||||
$eventlist = [];
|
||||
$file_path = config('server_path') . 'data/XML/events.xml';
|
||||
if (!file_exists($file_path)) {
|
||||
die(json_encode([]));
|
||||
}
|
||||
$xml = new DOMDocument;
|
||||
$xml->load($file_path);
|
||||
$tmplist = [];
|
||||
$tableevent = $xml->getElementsByTagName('event');
|
||||
|
||||
foreach ($tableevent as $event) {
|
||||
if ($event) { $tmplist = [
|
||||
'colorlight' => parseEvent($event->getElementsByTagName('colors'), false, 'colorlight'),
|
||||
'colordark' => parseEvent($event->getElementsByTagName('colors'), false, 'colordark'),
|
||||
'description' => parseEvent($event->getElementsByTagName('description'), false, 'description'),
|
||||
'displaypriority' => intval(parseEvent($event->getElementsByTagName('details'), false, 'displaypriority')),
|
||||
'enddate' => intval(parseEvent($event, true, false)),
|
||||
'isseasonal' => getBoolean(intval(parseEvent($event->getElementsByTagName('details'), false, 'isseasonal'))),
|
||||
'name' => $event->getAttribute('name'),
|
||||
'startdate' => intval(parseEvent($event, true, true)),
|
||||
'specialevent' => intval(parseEvent($event->getElementsByTagName('details'), false, 'specialevent'))
|
||||
];
|
||||
$eventlist[] = $tmplist; } }
|
||||
die(json_encode(['eventlist' => $eventlist, 'lastupdatetimestamp' => time()]));
|
||||
|
||||
case 'boostedcreature':
|
||||
$boostDB = $db->query("select * from " . $db->tableName('boosted_creature'))->fetchAll();
|
||||
foreach ($boostDB as $Tableboost) {
|
||||
die(json_encode([
|
||||
'boostedcreature' => true,
|
||||
'raceid' => intval($Tableboost['raceid'])
|
||||
]));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'login':
|
||||
|
||||
$port = $config['lua']['gameProtocolPort'];
|
||||
|
||||
// default world info
|
||||
$world = [
|
||||
'id' => 0,
|
||||
'name' => $config['lua']['serverName'],
|
||||
'externaladdress' => $config['lua']['ip'],
|
||||
'externalport' => $port,
|
||||
'externaladdressprotected' => $config['lua']['ip'],
|
||||
'externalportprotected' => $port,
|
||||
'externaladdressunprotected' => $config['lua']['ip'],
|
||||
'externalportunprotected' => $port,
|
||||
'previewstate' => 0,
|
||||
'location' => 'BRA', // BRA, EUR, USA
|
||||
'anticheatprotection' => false,
|
||||
'pvptype' => array_search($config['lua']['worldType'], ['pvp', 'no-pvp', 'pvp-enforced']),
|
||||
'istournamentworld' => false,
|
||||
'restrictedstore' => false,
|
||||
'currenttournamentphase' => 2
|
||||
];
|
||||
|
||||
$characters = [];
|
||||
$account = new OTS_Account();
|
||||
|
||||
$inputEmail = $request->email ?? false;
|
||||
$inputAccountName = $request->accountname ?? false;
|
||||
$inputToken = $request->token ?? false;
|
||||
|
||||
if ($inputEmail != false) { // login by email
|
||||
$account->findByEmail($request->email);
|
||||
}
|
||||
else if($inputAccountName != false) { // login by account name
|
||||
$account->find($inputAccountName);
|
||||
}
|
||||
|
||||
$config_salt_enabled = fieldExist('salt', 'accounts');
|
||||
$current_password = encrypt(($config_salt_enabled ? $account->getCustomField('salt') : '') . $request->password);
|
||||
|
||||
if (!$account->isLoaded() || $account->getPassword() != $current_password) {
|
||||
sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.');
|
||||
}
|
||||
|
||||
//log_append('test.log', var_export($account->getCustomField('secret'), true));
|
||||
$accountHasSecret = false;
|
||||
if (fieldExist('secret', 'accounts')) {
|
||||
$accountSecret = $account->getCustomField('secret');
|
||||
if ($accountSecret != null && $accountSecret != '') {
|
||||
$accountHasSecret = true;
|
||||
if ($inputToken === false) {
|
||||
sendError('Submit a valid two-factor authentication token.', 6);
|
||||
} else {
|
||||
require_once LIBS . 'rfc6238.php';
|
||||
if (TokenAuth6238::verify($accountSecret, $inputToken) !== true) {
|
||||
sendError('Two-factor authentication failed, token is wrong.', 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// common columns
|
||||
$columns = 'id, name, level, sex, vocation, looktype, lookhead, lookbody, looklegs, lookfeet, lookaddons';
|
||||
|
||||
if (fieldExist('isreward', 'accounts')) {
|
||||
$columns .= ', isreward';
|
||||
}
|
||||
|
||||
if (fieldExist('istutorial', 'accounts')) {
|
||||
$columns .= ', istutorial';
|
||||
}
|
||||
|
||||
$players = $db->query("select {$columns} from players where account_id = " . $account->getId() . " AND deletion = 0");
|
||||
if($players && $players->rowCount() > 0) {
|
||||
$players = $players->fetchAll();
|
||||
|
||||
$highestLevelId = 0;
|
||||
$highestLevel = 0;
|
||||
foreach ($players as $player) {
|
||||
if ($player['level'] >= $highestLevel) {
|
||||
$highestLevel = $player['level'];
|
||||
$highestLevelId = $player['id'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($players as $player) {
|
||||
$characters[] = create_char($player, $highestLevelId);
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldExist('premdays', 'accounts') && fieldExist('lastday', 'accounts')) {
|
||||
$save = false;
|
||||
$timeNow = time();
|
||||
$query = $db->query("select `premdays`, `lastday` from `accounts` where `id` = " . $account->getId());
|
||||
if ($query->rowCount() > 0) {
|
||||
$query = $query->fetch();
|
||||
$premDays = (int)$query['premdays'];
|
||||
$lastDay = (int)$query['lastday'];
|
||||
$lastLogin = $lastDay;
|
||||
} else {
|
||||
sendError("Error while fetching your account data. Please contact admin.");
|
||||
}
|
||||
if ($premDays != 0 && $premDays != PHP_INT_MAX) {
|
||||
if ($lastDay == 0) {
|
||||
$lastDay = $timeNow;
|
||||
$save = true;
|
||||
} else {
|
||||
$days = (int)(($timeNow - $lastDay) / 86400);
|
||||
if ($days > 0) {
|
||||
if ($days >= $premDays) {
|
||||
$premDays = 0;
|
||||
$lastDay = 0;
|
||||
} else {
|
||||
$premDays -= $days;
|
||||
$reminder = ($timeNow - $lastDay) % 86400;
|
||||
$lastDay = $timeNow - $reminder;
|
||||
}
|
||||
|
||||
$save = true;
|
||||
}
|
||||
}
|
||||
} else if ($lastDay != 0) {
|
||||
$lastDay = 0;
|
||||
$save = true;
|
||||
}
|
||||
if ($save) {
|
||||
$db->query("update `accounts` set `premdays` = " . $premDays . ", `lastday` = " . $lastDay . " where `id` = " . $account->getId());
|
||||
}
|
||||
}
|
||||
|
||||
$worlds = [$world];
|
||||
$playdata = compact('worlds', 'characters');
|
||||
|
||||
$sessionKey = ($inputEmail !== false) ? $inputEmail : $inputAccountName; // email or account name
|
||||
$sessionKey .= "\n" . $request->password; // password
|
||||
if (!fieldExist('istutorial', 'players')) {
|
||||
$sessionKey .= "\n";
|
||||
}
|
||||
$sessionKey .= ($accountHasSecret && strlen($accountSecret) > 5) ? $inputToken : '';
|
||||
|
||||
// this is workaround to distinguish between TFS 1.x and otservbr
|
||||
// TFS 1.x requires the number in session key
|
||||
// otservbr requires just login and password
|
||||
// so we check for istutorial field which is present in otservbr, and not in TFS
|
||||
if (!fieldExist('istutorial', 'players')) {
|
||||
$sessionKey .= "\n".floor(time() / 30);
|
||||
}
|
||||
|
||||
//log_append('slaw.log', $sessionKey);
|
||||
|
||||
$session = [
|
||||
'sessionkey' => $sessionKey,
|
||||
'lastlogintime' => 0,
|
||||
'ispremium' => $config['lua']['freePremium'] || $account->isPremium(),
|
||||
'premiumuntil' => ($account->getPremDays()) > 0 ? (time() + ($account->getPremDays() * 86400)) : 0,
|
||||
'status' => 'active', // active, frozen or suspended
|
||||
'returnernotification' => false,
|
||||
'showrewardnews' => true,
|
||||
'isreturner' => true,
|
||||
'fpstracking' => false,
|
||||
'optiontracking' => false,
|
||||
'tournamentticketpurchasestate' => 0,
|
||||
'emailcoderequest' => false
|
||||
];
|
||||
die(json_encode(compact('session', 'playdata')));
|
||||
|
||||
default:
|
||||
sendError("Unrecognized event {$action}.");
|
||||
break;
|
||||
}
|
||||
|
||||
function create_char($player, $highestLevelId) {
|
||||
global $config;
|
||||
return [
|
||||
'worldid' => 0,
|
||||
'name' => $player['name'],
|
||||
'ismale' => intval($player['sex']) === 1,
|
||||
'tutorial' => isset($player['istutorial']) && $player['istutorial'],
|
||||
'level' => intval($player['level']),
|
||||
'vocation' => $config['vocations'][$player['vocation']],
|
||||
'outfitid' => intval($player['looktype']),
|
||||
'headcolor' => intval($player['lookhead']),
|
||||
'torsocolor' => intval($player['lookbody']),
|
||||
'legscolor' => intval($player['looklegs']),
|
||||
'detailcolor' => intval($player['lookfeet']),
|
||||
'addonsflags' => intval($player['lookaddons']),
|
||||
'ishidden' => isset($player['deletion']) && (int)$player['deletion'] === 1,
|
||||
'istournamentparticipant' => false,
|
||||
'ismaincharacter' => $highestLevelId == $player['id'],
|
||||
'dailyrewardstate' => isset($player['isreward']) ? intval($player['isreward']) : 0,
|
||||
'remainingdailytournamentplaytime' => 0
|
||||
];
|
||||
}
|
@ -1,25 +1,36 @@
|
||||
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;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php;
|
||||
}
|
||||
# increase max file upload
|
||||
client_max_body_size 10M;
|
||||
|
||||
location ~ \.php$ {
|
||||
include snippets/fastcgi-php.conf;
|
||||
fastcgi_read_timeout 240;
|
||||
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
|
||||
}
|
||||
# this is very important, be sure its in your nginx conf - it prevents access to logs etc.
|
||||
location ~ /system {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
# block .htaccess, CHANGELOG.md, composer.json etc.
|
||||
# this is to prevent finding software versions
|
||||
location ~\.(ht|md|json|dist)$ {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location /system {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
# block git files and folders
|
||||
location ~ /\.git {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,3 @@
|
||||
<IfModule mod_autoindex.c>
|
||||
Options -Indexes
|
||||
</IfModule>
|
||||
|
||||
<IfVersion < 2.4>
|
||||
order allow,deny
|
||||
deny from all
|
||||
</IfVersion>
|
||||
<IfVersion >= 2.4>
|
||||
Require all denied
|
||||
</IfVersion>
|
||||
|
17
plugins/email-confirmed-reward.json
Normal file
17
plugins/email-confirmed-reward.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
33
plugins/email-confirmed-reward/reward.php
Normal file
33
plugins/email-confirmed-reward/reward.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?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'));
|
||||
}
|
18
release.sh
18
release.sh
@ -13,16 +13,18 @@ fi
|
||||
|
||||
if [ $1 = "prepare" ]; then
|
||||
# define release version
|
||||
version=`cat VERSION`
|
||||
version=`php system/get_version_for_release.php`
|
||||
|
||||
echo "Preparing to release version $version of the MyAAC Project!"
|
||||
|
||||
# get myaac from git archive
|
||||
git archive --format zip --output tmp/myaac.zip master
|
||||
|
||||
# make required directories
|
||||
mkdir -p releases
|
||||
mkdir -p tmp && cd tmp
|
||||
mkdir -p tmp
|
||||
|
||||
# get myaac from git archive
|
||||
git archive --format zip --output tmp/myaac.zip 0.8
|
||||
|
||||
cd tmp/ || exit
|
||||
|
||||
dir="myaac-$version"
|
||||
if [ -d "$dir" ] ; then
|
||||
@ -39,9 +41,9 @@ fi
|
||||
|
||||
if [ $1 = "pack" ]; then
|
||||
# define release version
|
||||
version=`cat VERSION`
|
||||
version=`php system/get_version_for_release.php`
|
||||
|
||||
cd tmp
|
||||
cd tmp || exit
|
||||
|
||||
# tar.gz
|
||||
echo "Creating .tar.gz package.."
|
||||
@ -60,4 +62,4 @@ if [ $1 = "pack" ]; then
|
||||
echo "Done. Released files can be found in 'releases' directory."
|
||||
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
@ -9,6 +9,11 @@ $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
|
||||
@ -203,4 +208,4 @@ class Psr4AutoloaderClass
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ require_once __DIR__ . '/../../common.php';
|
||||
require_once SYSTEM . 'functions.php';
|
||||
require_once SYSTEM . 'init.php';
|
||||
require_once SYSTEM . 'hooks.php';
|
||||
require_once LIBS . 'plugins.php';
|
||||
|
||||
if($argc !== 2) {
|
||||
echo 'This command expects one parameter: zip file name (plugin)' . PHP_EOL;
|
||||
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
$config['clients'] = array(
|
||||
$config['clients'] = [
|
||||
710,
|
||||
740,
|
||||
750,
|
||||
@ -54,7 +54,9 @@ $config['clients'] = array(
|
||||
|
||||
1000,
|
||||
1010,
|
||||
1020,
|
||||
1021,
|
||||
1030,
|
||||
1031,
|
||||
1034,
|
||||
1041,
|
||||
@ -62,6 +64,7 @@ $config['clients'] = array(
|
||||
1053,
|
||||
1054,
|
||||
1058,
|
||||
1070,
|
||||
1075,
|
||||
1077,
|
||||
1079,
|
||||
@ -73,6 +76,37 @@ $config['clients'] = array(
|
||||
1096,
|
||||
1097,
|
||||
1098,
|
||||
|
||||
1100,
|
||||
);
|
||||
?>
|
||||
1102,
|
||||
1140,
|
||||
1150,
|
||||
1180,
|
||||
|
||||
1200,
|
||||
1202,
|
||||
1215,
|
||||
1220,
|
||||
1230,
|
||||
1240,
|
||||
1251,
|
||||
1260,
|
||||
1270,
|
||||
1280,
|
||||
1285,
|
||||
1286,
|
||||
1290,
|
||||
1291,
|
||||
|
||||
1300,
|
||||
1310,
|
||||
1311,
|
||||
1312,
|
||||
1316,
|
||||
1320,
|
||||
1321,
|
||||
1322,
|
||||
1330,
|
||||
1332,
|
||||
1340,
|
||||
];
|
||||
|
38
system/compat/classes.php
Normal file
38
system/compat/classes.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* Compat classes (backward support for Gesior AAC)
|
||||
*
|
||||
* @package MyAAC
|
||||
* @author Slawkens <slawkens@gmail.com>
|
||||
* @copyright 2022 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
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 GuildRank extends OTS_GuildRank {}
|
||||
class House extends OTS_House {}
|
@ -10,6 +10,14 @@
|
||||
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;
|
||||
@ -37,4 +45,3 @@ switch($page)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
?>
|
@ -51,4 +51,3 @@ else
|
||||
updateDatabaseConfig('views_counter', $views_counter); // update counter
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -116,5 +116,4 @@ defined('MYAAC') or die('Direct access not allowed!');
|
||||
'<li>MySQL is not configured propertly in <i>config.lua</i>.</li>' .
|
||||
'<li>MySQL server is not running.</li>' .
|
||||
'</ul>' . $error->getMessage());
|
||||
|
||||
}
|
@ -23,6 +23,8 @@ 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';
|
||||
@ -35,11 +37,13 @@ function exception_handler($exception) {
|
||||
}
|
||||
|
||||
// display beautiful error message
|
||||
// the file is .twig.html, but its not really parsed by Twig
|
||||
// the file is .twig.html, but it's not really parsed by Twig
|
||||
// we just replace some values manually
|
||||
// cause in case Twig throws exception, we can show it too
|
||||
$content = file_get_contents($template_file);
|
||||
$content = str_replace(array('{{ BASE_URL }}', '{{ message }}', '{{ backtrace }}', '{{ powered_by }}'), array(BASE_URL, $message, $backtrace_formatted, base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4=')), $content);
|
||||
$content = str_replace(array('{{ BASE_URL }}', '{{ exceptionClass }}', '{{ message }}', '{{ backtrace }}', '{{ powered_by }}'), array(BASE_URL, get_class($exception), $message, $backtrace_formatted, base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4=')), $content);
|
||||
|
||||
@ob_clean();
|
||||
|
||||
echo $content;
|
||||
}
|
||||
|
@ -7,18 +7,26 @@
|
||||
* @copyright 2019 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
use Twig\Loader\ArrayLoader as Twig_ArrayLoader;
|
||||
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
function message($message, $type, $return)
|
||||
{
|
||||
if($return)
|
||||
return '<div class="' . $type . '" style="margin-bottom:10px;">' . $message . '</div>';
|
||||
if(IS_CLI) {
|
||||
if($return) {
|
||||
return $message;
|
||||
}
|
||||
|
||||
echo '<div class="' . $type . '" style="margin-bottom:10px;">' . $message . '</div>';
|
||||
return true;
|
||||
echo $message;
|
||||
return true;
|
||||
}
|
||||
|
||||
if($return)
|
||||
return '<div class="' . $type . '" style="margin-bottom:10px;">' . $message . '</div>';
|
||||
|
||||
echo '<div class="' . $type . '" style="margin-bottom:10px;">' . $message . '</div>';
|
||||
return true;
|
||||
}
|
||||
function success($message, $return = false) {
|
||||
return message($message, 'success', $return);
|
||||
@ -442,7 +450,7 @@ function tickers()
|
||||
*/
|
||||
function template_place_holder($type)
|
||||
{
|
||||
global $template_place_holders;
|
||||
global $twig, $template_place_holders;
|
||||
$ret = '';
|
||||
|
||||
if(array_key_exists($type, $template_place_holders) && is_array($template_place_holders[$type]))
|
||||
@ -451,6 +459,9 @@ function template_place_holder($type)
|
||||
if($type === 'head_start') {
|
||||
$ret .= template_header();
|
||||
}
|
||||
elseif ($type === 'body_start') {
|
||||
$ret .= $twig->render('browsehappy.html.twig');
|
||||
}
|
||||
elseif($type === 'body_end') {
|
||||
$ret .= template_ga_code();
|
||||
}
|
||||
@ -745,10 +756,10 @@ function get_browser_languages()
|
||||
{
|
||||
$ret = array();
|
||||
|
||||
$acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
|
||||
if(!isset($acceptLang[0]))
|
||||
if(empty($_SERVER['HTTP_ACCEPT_LANGUAGE']))
|
||||
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
|
||||
@ -786,7 +797,7 @@ function get_plugins()
|
||||
$ret = array();
|
||||
|
||||
$path = PLUGINS;
|
||||
foreach(scandir($path, 0) as $file) {
|
||||
foreach(scandir($path, SCANDIR_SORT_ASCENDING) 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))
|
||||
@ -912,8 +923,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 . '). Error: ' . print_r(error_get_last(), true));
|
||||
throw new RuntimeException('ERROR: Cannot find ' . $filename . ' file. More info in system/logs/error.log');
|
||||
log_append('error.log', '[load_config_file] Fatal error: Cannot load config.lua (' . $filename . ').');
|
||||
throw new RuntimeException('ERROR: Cannot find ' . $filename . ' file.');
|
||||
}
|
||||
|
||||
$result = array();
|
||||
@ -922,6 +933,12 @@ function load_config_lua($filename)
|
||||
if(count($lines) > 0) {
|
||||
foreach($lines as $ln => $line)
|
||||
{
|
||||
$line = trim($line);
|
||||
if(@$line[0] === '{' || @$line[0] === '}') {
|
||||
// arrays are not supported yet
|
||||
// just ignore the error
|
||||
continue;
|
||||
}
|
||||
$tmp_exp = explode('=', $line, 2);
|
||||
if(strpos($line, 'dofile') !== false)
|
||||
{
|
||||
@ -948,16 +965,17 @@ function load_config_lua($filename)
|
||||
$result[$key] = (string) substr(substr($value, 1), 0, -1);
|
||||
elseif(in_array($value, array('true', 'false')))
|
||||
$result[$key] = ($value === 'true') ? true : false;
|
||||
elseif(@$value[0] === '{' && @$value[strlen($value) - 1] === '}') {
|
||||
elseif(@$value[0] === '{') {
|
||||
// arrays are not supported yet
|
||||
// just ignore the error
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($result as $tmp_key => $tmp_value) // load values definied by other keys, like: dailyFragsToBlackSkull = dailyFragsToRedSkull
|
||||
$value = str_replace($tmp_key, $tmp_value, $value);
|
||||
$ret = @eval("return $value;");
|
||||
if((string) $ret == '') // = parser error
|
||||
if((string) $ret == '' && trim($value) !== '""') // = parser error
|
||||
{
|
||||
throw new RuntimeException('ERROR: Loading config.lua file. Line <b>' . ($ln + 1) . '</b> of LUA config file is not valid [key: <b>' . $key . '</b>]');
|
||||
}
|
||||
@ -982,6 +1000,10 @@ function str_replace_first($search, $replace, $subject) {
|
||||
}
|
||||
|
||||
function get_browser_real_ip() {
|
||||
if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
|
||||
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
|
||||
}
|
||||
|
||||
if(isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR']))
|
||||
return $_SERVER['REMOTE_ADDR'];
|
||||
else if(isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP']))
|
||||
@ -1019,7 +1041,7 @@ function getTopPlayers($limit = 5) {
|
||||
$deleted = 'deletion';
|
||||
|
||||
$is_tfs10 = $db->hasTable('players_online');
|
||||
$players = $db->query('SELECT `id`, `name`, `level`, `experience`, `looktype`' . ($db->hasColumn('players', 'lookaddons') ? ', `lookaddons`' : '') . ', `lookhead`, `lookbody`, `looklegs`, `lookfeet`' . ($is_tfs10 ? '' : ', `online`') . ' FROM `players` WHERE `group_id` < ' . config('highscores_groups_hidden') . ' AND `id` NOT IN (' . implode(', ', config('highscores_ids_hidden')) . ') AND `' . $deleted . '` = 0 AND `account_id` != 1 ORDER BY `experience` DESC LIMIT ' . (int)$limit)->fetchAll();
|
||||
$players = $db->query('SELECT `id`, `name`, `level`, `vocation`, `experience`, `looktype`' . ($db->hasColumn('players', 'lookaddons') ? ', `lookaddons`' : '') . ', `lookhead`, `lookbody`, `looklegs`, `lookfeet`' . ($is_tfs10 ? '' : ', `online`') . ' FROM `players` WHERE `group_id` < ' . config('highscores_groups_hidden') . ' AND `id` NOT IN (' . implode(', ', config('highscores_ids_hidden')) . ') AND `' . $deleted . '` = 0 AND `account_id` != 1 ORDER BY `experience` DESC LIMIT ' . (int)$limit)->fetchAll();
|
||||
|
||||
if($is_tfs10) {
|
||||
foreach($players as &$player) {
|
||||
@ -1124,9 +1146,30 @@ function clearCache()
|
||||
if ($cache->fetch('failed_logins', $tmp))
|
||||
$cache->delete('failed_logins');
|
||||
|
||||
global $template_name;
|
||||
if ($cache->fetch('template_ini' . $template_name, $tmp))
|
||||
$cache->delete('template_ini' . $template_name);
|
||||
foreach (get_templates() as $template) {
|
||||
if ($cache->fetch('template_ini_' . $template, $tmp)) {
|
||||
$cache->delete('template_ini_' . $template);
|
||||
}
|
||||
}
|
||||
|
||||
if ($cache->fetch('template_menus', $tmp)) {
|
||||
$cache->delete('template_menus');
|
||||
}
|
||||
if ($cache->fetch('database_tables', $tmp)) {
|
||||
$cache->delete('database_tables');
|
||||
}
|
||||
if ($cache->fetch('database_columns', $tmp)) {
|
||||
$cache->delete('database_columns');
|
||||
}
|
||||
if ($cache->fetch('database_checksum', $tmp)) {
|
||||
$cache->delete('database_checksum');
|
||||
}
|
||||
if ($cache->fetch('hooks', $tmp)) {
|
||||
$cache->delete('hooks');
|
||||
}
|
||||
if ($cache->fetch('last_kills', $tmp)) {
|
||||
$cache->delete('last_kills');
|
||||
}
|
||||
}
|
||||
|
||||
deleteDirectory(CACHE . 'signatures', ['index.html'], true);
|
||||
@ -1221,6 +1264,73 @@ function getCustomPage($page, &$success)
|
||||
return $content;
|
||||
}
|
||||
|
||||
function escapeHtml($html) {
|
||||
return htmlspecialchars($html);
|
||||
}
|
||||
|
||||
function getGuildNameById($id)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$guild = $db->query('SELECT `name` FROM `guilds` WHERE `id` = ' . (int)$id);
|
||||
|
||||
if ($guild->rowCount() > 0) {
|
||||
return $guild->fetchColumn();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getGuildLogoById($id)
|
||||
{
|
||||
global $db;
|
||||
|
||||
$logo = 'default.gif';
|
||||
|
||||
$query = $db->query('SELECT `logo_name` FROM `guilds` WHERE `id` = ' . (int)$id);
|
||||
if ($query->rowCount() == 1) {
|
||||
|
||||
$query = $query->fetch(PDO::FETCH_ASSOC);
|
||||
$guildLogo = $query['logo_name'];
|
||||
|
||||
if (!empty($guildLogo) && file_exists('images/guilds/' . $guildLogo)) {
|
||||
$logo = $guildLogo;
|
||||
}
|
||||
}
|
||||
|
||||
return BASE_URL . 'images/guilds/' . $logo;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
global $db, $logged_access;
|
||||
|
||||
if (!isset($logged_access)) {
|
||||
$logged_access = 1;
|
||||
}
|
||||
|
||||
$pages = $db->query('SELECT `name` FROM ' . TABLE_PREFIX . 'pages WHERE ' . ($withHidden ? '' : '`hidden` != 1 AND ') . '`access` <= ' . $db->quote($logged_access));
|
||||
$ret = [];
|
||||
|
||||
if ($pages->rowCount() < 1) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
foreach($pages->fetchAll() as $page) {
|
||||
$ret[] = $page['name'];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// validator functions
|
||||
require_once LIBS . 'validator.php';
|
||||
require_once SYSTEM . 'compat.php';
|
||||
require_once SYSTEM . 'compat/base.php';
|
||||
|
6
system/get_version_for_release.php
Normal file
6
system/get_version_for_release.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/../common.php';
|
||||
if (IS_CLI) {
|
||||
echo MYAAC_VERSION;
|
||||
}
|
@ -9,44 +9,60 @@
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
define('HOOK_STARTUP', 1);
|
||||
define('HOOK_BEFORE_PAGE', 2);
|
||||
define('HOOK_AFTER_PAGE', 3);
|
||||
define('HOOK_FINISH', 4);
|
||||
define('HOOK_TIBIACOM_ARTICLE', 5);
|
||||
define('HOOK_TIBIACOM_BORDER_3', 6);
|
||||
define('HOOK_CHARACTERS_BEFORE_INFORMATIONS', 7);
|
||||
define('HOOK_CHARACTERS_AFTER_INFORMATIONS', 8);
|
||||
define('HOOK_CHARACTERS_BEFORE_SIGNATURE', 9);
|
||||
define('HOOK_CHARACTERS_AFTER_SIGNATURE', 10);
|
||||
define('HOOK_CHARACTERS_AFTER_ACCOUNT', 11);
|
||||
define('HOOK_CHARACTERS_AFTER_CHARACTERS', 12);
|
||||
define('HOOK_LOGIN', 13);
|
||||
define('HOOK_LOGIN_ATTEMPT', 14);
|
||||
define('HOOK_LOGOUT', 15);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_FORM', 16);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_BOXES', 17);
|
||||
define('HOOK_ACCOUNT_CREATE_BETWEEN_BOXES_1', 18);
|
||||
define('HOOK_ACCOUNT_CREATE_BETWEEN_BOXES_2', 19);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_BOXES', 20);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_ACCOUNT', 21);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_ACCOUNT', 22);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_EMAIL', 23);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_COUNTRY', 24);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_PASSWORDS', 25);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_RECAPTCHA', 26);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_CHARACTER_NAME', 27);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_CHARACTER_NAME', 28);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_SEX', 29);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_VOCATION', 30);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_TOWNS', 31);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_SUBMIT_BUTTON', 32);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_FORM', 33);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_SUBMIT', 34);
|
||||
$i = 0;
|
||||
define('HOOK_STARTUP', ++$i);
|
||||
define('HOOK_BEFORE_PAGE', ++$i);
|
||||
define('HOOK_AFTER_PAGE', ++$i);
|
||||
define('HOOK_FINISH', ++$i);
|
||||
define('HOOK_TIBIACOM_ARTICLE', ++$i);
|
||||
define('HOOK_TIBIACOM_BORDER_3', ++$i);
|
||||
define('HOOK_CHARACTERS_BEFORE_INFORMATIONS', ++$i);
|
||||
define('HOOK_CHARACTERS_AFTER_INFORMATIONS', ++$i);
|
||||
define('HOOK_CHARACTERS_BEFORE_SKILLS', ++$i);
|
||||
define('HOOK_CHARACTERS_AFTER_SKILLS', ++$i);
|
||||
define('HOOK_CHARACTERS_AFTER_QUESTS', ++$i);
|
||||
define('HOOK_CHARACTERS_AFTER_EQUIPMENT', ++$i);
|
||||
define('HOOK_CHARACTERS_BEFORE_DEATHS', ++$i);
|
||||
define('HOOK_CHARACTERS_BEFORE_SIGNATURE', ++$i);
|
||||
define('HOOK_CHARACTERS_AFTER_SIGNATURE', ++$i);
|
||||
define('HOOK_CHARACTERS_AFTER_ACCOUNT', ++$i);
|
||||
define('HOOK_CHARACTERS_AFTER_CHARACTERS', ++$i);
|
||||
define('HOOK_LOGIN', ++$i);
|
||||
define('HOOK_LOGIN_ATTEMPT', ++$i);
|
||||
define('HOOK_LOGOUT', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_FORM', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_BOXES', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_BETWEEN_BOXES_1', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_BETWEEN_BOXES_2', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_BOXES', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_ACCOUNT', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_ACCOUNT', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_EMAIL', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_COUNTRY', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_PASSWORDS', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_RECAPTCHA', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_CHARACTER_NAME', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_CHARACTER_NAME', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_SEX', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_VOCATION', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_TOWNS', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_BEFORE_SUBMIT_BUTTON', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_FORM', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_POST', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_SUBMIT', ++$i);
|
||||
define('HOOK_ACCOUNT_CREATE_AFTER_SAVED', ++$i);
|
||||
define('HOOK_ACCOUNT_MANAGE_BEFORE_GENERAL_INFORMATION', ++$i);
|
||||
define('HOOK_ACCOUNT_MANAGE_BEFORE_PUBLIC_INFORMATION', ++$i);
|
||||
define('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS', ++$i);
|
||||
define('HOOK_ACCOUNT_MANAGE_BEFORE_CHARACTERS', ++$i);
|
||||
define('HOOK_EMAIL_CONFIRMED', ++$i);
|
||||
define('HOOK_GUILDS_AFTER_INVITED_CHARACTERS', ++$i);
|
||||
define('HOOK_FIRST', HOOK_STARTUP);
|
||||
define('HOOK_LAST', HOOK_ACCOUNT_CREATE_AFTER_SUBMIT);
|
||||
define('HOOK_LAST', HOOK_EMAIL_CONFIRMED);
|
||||
|
||||
require_once LIBS . 'plugins.php';
|
||||
require_once LIBS . 'src/Plugins.php';
|
||||
|
||||
class Hook
|
||||
{
|
||||
private $_name, $_type, $_file;
|
||||
@ -67,9 +83,7 @@ class Hook
|
||||
}*/
|
||||
|
||||
global $db, $config, $template_path, $ots, $content, $twig;
|
||||
if(file_exists(BASE . $this->_file)) {
|
||||
$ret = require BASE . $this->_file;
|
||||
}
|
||||
$ret = include BASE . $this->_file;
|
||||
|
||||
return !isset($ret) || $ret == 1 || $ret;
|
||||
}
|
||||
|
@ -28,12 +28,10 @@ if($config['gzip_output'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($
|
||||
ob_start('ob_gzhandler');
|
||||
|
||||
// cache
|
||||
require_once SYSTEM . 'libs/cache.php';
|
||||
require_once LIBS . 'cache.php';
|
||||
require_once LIBS . 'src/Cache.php';
|
||||
$cache = Cache::getInstance();
|
||||
|
||||
// twig
|
||||
require_once SYSTEM . 'twig.php';
|
||||
|
||||
// trim values we receive
|
||||
if(isset($_POST))
|
||||
{
|
||||
@ -76,8 +74,8 @@ if($config_lua_reload) {
|
||||
|
||||
// cache config
|
||||
if($cache->enabled()) {
|
||||
$cache->set('config_lua', serialize($config['lua']), 120);
|
||||
$cache->set('server_path', $config['server_path']);
|
||||
$cache->set('config_lua', serialize($config['lua']), 2 * 60);
|
||||
$cache->set('server_path', $config['server_path'], 10 * 60);
|
||||
}
|
||||
}
|
||||
unset($tmp);
|
||||
@ -114,16 +112,21 @@ if(!isset($foundValue)) {
|
||||
$config['data_path'] = $foundValue;
|
||||
unset($foundValue);
|
||||
|
||||
// new config values for compability
|
||||
// new config values for compatibility
|
||||
if(!isset($config['highscores_ids_hidden']) || count($config['highscores_ids_hidden']) == 0) {
|
||||
$config['highscores_ids_hidden'] = array(0);
|
||||
}
|
||||
|
||||
$config['account_mail_verify'] = config('account_mail_verify') && config('mail_enabled');
|
||||
|
||||
// POT
|
||||
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'));
|
||||
// load vocation names
|
||||
$tmp = '';
|
||||
@ -140,10 +143,8 @@ else {
|
||||
if(!@file_exists($file))
|
||||
$file = $config['data_path'] . 'vocations.xml';
|
||||
|
||||
$vocations->load($file);
|
||||
|
||||
if(!$vocations)
|
||||
throw new RuntimeException('ERROR: Cannot load <i>vocations.xml</i> file.');
|
||||
if(!$vocations->load($file))
|
||||
throw new RuntimeException('ERROR: Cannot load <i>vocations.xml</i> - the file is malformed. Check the file with xml syntax validator.');
|
||||
|
||||
$config['vocations'] = array();
|
||||
foreach($vocations->getElementsByTagName('vocation') as $vocation) {
|
||||
@ -180,7 +181,8 @@ else {
|
||||
// load towns from database (TFS 1.3) //
|
||||
////////////////////////////////////////
|
||||
|
||||
$towns = array();
|
||||
$tmp = '';
|
||||
$towns = [];
|
||||
if($cache->enabled() && $cache->fetch('towns', $tmp)) {
|
||||
$towns = unserialize($tmp);
|
||||
}
|
||||
@ -193,20 +195,14 @@ else {
|
||||
}
|
||||
|
||||
unset($query);
|
||||
if($cache->enabled()) {
|
||||
$cache->set('towns', serialize($towns), 600);
|
||||
}
|
||||
}
|
||||
else if($cache->enabled()) {
|
||||
$cache->set('towns', serialize(array()), 600);
|
||||
else {
|
||||
$towns = config('towns');
|
||||
}
|
||||
}
|
||||
|
||||
$configTowns = config('towns');
|
||||
if($configTowns !== null && (!isset($configTowns[1]) || $configTowns[1] !== 'Sample town')) {
|
||||
$towns = array_replace(
|
||||
$towns, $configTowns
|
||||
);
|
||||
if($cache->enabled()) {
|
||||
$cache->set('towns', serialize($towns), 600);
|
||||
}
|
||||
}
|
||||
|
||||
config(['towns', $towns]);
|
||||
|
@ -58,4 +58,3 @@ function outputItem($id = 100, $count = 1)
|
||||
$file_name = Items_Images::$outputDir . $file_name . '.gif';
|
||||
readfile($file_name);
|
||||
}
|
||||
?>
|
||||
|
@ -11,6 +11,57 @@
|
||||
|
||||
class CreateCharacter
|
||||
{
|
||||
/**
|
||||
* @param $name
|
||||
* @param $errors
|
||||
* @return bool
|
||||
*/
|
||||
public function checkName($name, &$errors)
|
||||
{
|
||||
$minLength = config('character_name_min_length');
|
||||
$maxLength = config('character_name_max_length');
|
||||
|
||||
if(empty($name)) {
|
||||
$errors['name'] = 'Please enter a name for your character!';
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strlen($name) > $maxLength) {
|
||||
$errors['name'] = 'Name is too long. Max. length <b>' . $maxLength . '</b> letters.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strlen($name) < $minLength) {
|
||||
$errors['name'] = 'Name is too short. Min. length <b>' . $minLength . '</b> letters.';
|
||||
return false;
|
||||
}
|
||||
|
||||
$name_length = strlen($name);
|
||||
if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- '") != $name_length) {
|
||||
$errors['name'] = 'This name contains invalid letters, words or format. Please use only a-Z, - , \' and space.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!preg_match("/[A-z ']/", $name)) {
|
||||
$errors['name'] = 'Your name contains illegal characters.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!admin() && !Validator::newCharacterName($name)) {
|
||||
$errors['name'] = Validator::getLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
$player = new OTS_Player();
|
||||
$player->find($name);
|
||||
if($player->isLoaded()) {
|
||||
$errors['name'] = 'Character with this name already exist.';
|
||||
return false;
|
||||
}
|
||||
|
||||
return empty($errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param int $sex
|
||||
@ -19,42 +70,27 @@ class CreateCharacter
|
||||
* @param array $errors
|
||||
* @return bool
|
||||
*/
|
||||
public function check($name, $sex, &$vocation, &$town, &$errors) {
|
||||
$minLength = config('character_name_min_length');
|
||||
$maxLength = config('character_name_max_length');
|
||||
public function check($name, $sex, &$vocation, &$town, &$errors)
|
||||
{
|
||||
$this->checkName($name, $errors);
|
||||
|
||||
if(empty($name))
|
||||
$errors['name'] = 'Please enter a name for your character!';
|
||||
else if(strlen($name) > $maxLength)
|
||||
$errors['name'] = 'Name is too long. Max. lenght <b>'.$maxLength.'</b> letters.';
|
||||
else if(strlen($name) < $minLength)
|
||||
$errors['name'] = 'Name is too short. Min. lenght <b>'.$minLength.'</b> letters.';
|
||||
else {
|
||||
if(!admin() && !Validator::newCharacterName($name)) {
|
||||
$errors['name'] = Validator::getLastError();
|
||||
}
|
||||
|
||||
$exist = new OTS_Player();
|
||||
$exist->find($name);
|
||||
if($exist->isLoaded()) {
|
||||
$errors['name'] = 'Character with this name already exist.';
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($sex) && $sex != "0")
|
||||
if(empty($sex) && $sex != "0") {
|
||||
$errors['sex'] = 'Please select the sex for your character!';
|
||||
}
|
||||
|
||||
if(count(config('character_samples')) > 1)
|
||||
{
|
||||
if(!isset($vocation))
|
||||
$errors['vocation'] = 'Please select a vocation for your character.';
|
||||
}
|
||||
else
|
||||
else {
|
||||
$vocation = config('character_samples')[0];
|
||||
}
|
||||
|
||||
if(count(config('character_towns')) > 1) {
|
||||
if(!isset($town))
|
||||
if(!isset($town)) {
|
||||
$errors['town'] = 'Please select a town for your character.';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$town = config('character_towns')[0];
|
||||
@ -102,7 +138,7 @@ class CreateCharacter
|
||||
|
||||
if(empty($errors))
|
||||
{
|
||||
$number_of_players_on_account = $account->getPlayersList()->count();
|
||||
$number_of_players_on_account = $account->getPlayersList(true)->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>!';
|
||||
}
|
||||
@ -120,7 +156,7 @@ class CreateCharacter
|
||||
return false;
|
||||
}
|
||||
|
||||
global $db, $twig;
|
||||
global $db;
|
||||
|
||||
if($sex == "0")
|
||||
$char_to_copy->setLookType(136);
|
||||
@ -157,8 +193,14 @@ class CreateCharacter
|
||||
$player->setManaSpent($char_to_copy->getManaSpent());
|
||||
$player->setSoul($char_to_copy->getSoul());
|
||||
|
||||
for($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++)
|
||||
$player->setSkill($skill, 10);
|
||||
for($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++) {
|
||||
$value = 10;
|
||||
if (config('use_character_sample_skills')) {
|
||||
$value = $char_to_copy->getSkill($skill);
|
||||
}
|
||||
|
||||
$player->setSkill($skill, $value);
|
||||
}
|
||||
|
||||
$player->setLookBody($char_to_copy->getLookBody());
|
||||
$player->setLookFeet($char_to_copy->getLookFeet());
|
||||
@ -186,7 +228,7 @@ class CreateCharacter
|
||||
}
|
||||
|
||||
$player->save();
|
||||
$player->setCustomField("created", time());
|
||||
$player->setCustomField('created', time());
|
||||
|
||||
$player = new OTS_Player();
|
||||
$player->find($name);
|
||||
@ -197,18 +239,28 @@ class CreateCharacter
|
||||
}
|
||||
|
||||
if($db->hasTable('player_skills')) {
|
||||
|
||||
for($i=0; $i<7; $i++) {
|
||||
$value = 10;
|
||||
if (config('use_character_sample_skills')) {
|
||||
$value = $char_to_copy->getSkill($i);
|
||||
}
|
||||
$skillExists = $db->query('SELECT `skillid` FROM `player_skills` WHERE `player_id` = ' . $player->getId() . ' AND `skillid` = ' . $i);
|
||||
if($skillExists->rowCount() <= 0) {
|
||||
$db->query('INSERT INTO `player_skills` (`player_id`, `skillid`, `value`, `count`) VALUES ('.$player->getId().', '.$i.', 10, 0)');
|
||||
$db->query('INSERT INTO `player_skills` (`player_id`, `skillid`, `value`, `count`) VALUES ('.$player->getId().', '.$i.', ' . $value . ', 0)');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$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)
|
||||
$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']."', '".$save_item['attributes']."');");
|
||||
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);");
|
||||
}
|
||||
}
|
||||
|
||||
global $twig;
|
||||
$twig->display('success.html.twig', array(
|
||||
'title' => 'Character Created',
|
||||
'description' => 'The character <b>' . $name . '</b> has been created.<br/>
|
||||
@ -219,4 +271,4 @@ class CreateCharacter
|
||||
$account->logAction('Created character <b>' . $name . '</b>.');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ namespace Twig\Cache;
|
||||
*/
|
||||
class FilesystemCache implements CacheInterface
|
||||
{
|
||||
const FORCE_BYTECODE_INVALIDATION = 1;
|
||||
public const FORCE_BYTECODE_INVALIDATION = 1;
|
||||
|
||||
private $directory;
|
||||
private $options;
|
||||
@ -35,7 +35,7 @@ class FilesystemCache implements CacheInterface
|
||||
|
||||
public function generateKey($name, $className)
|
||||
{
|
||||
$hash = hash('sha256', $className);
|
||||
$hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $className);
|
||||
|
||||
return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
|
||||
}
|
||||
@ -67,7 +67,7 @@ class FilesystemCache implements CacheInterface
|
||||
|
||||
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)) {
|
||||
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);
|
||||
|
@ -14,11 +14,9 @@ namespace Twig\Cache;
|
||||
/**
|
||||
* Implements a no-cache strategy.
|
||||
*
|
||||
* @final
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class NullCache implements CacheInterface
|
||||
final class NullCache implements CacheInterface
|
||||
{
|
||||
public function generateKey($name, $className)
|
||||
{
|
||||
|
@ -12,23 +12,22 @@
|
||||
|
||||
namespace Twig;
|
||||
|
||||
use Twig\Node\ModuleNode;
|
||||
use Twig\Node\Node;
|
||||
|
||||
/**
|
||||
* Compiles a node to PHP code.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Compiler implements \Twig_CompilerInterface
|
||||
class Compiler
|
||||
{
|
||||
protected $lastLine;
|
||||
protected $source;
|
||||
protected $indentation;
|
||||
protected $env;
|
||||
protected $debugInfo = [];
|
||||
protected $sourceOffset;
|
||||
protected $sourceLine;
|
||||
protected $filename;
|
||||
private $lastLine;
|
||||
private $source;
|
||||
private $indentation;
|
||||
private $env;
|
||||
private $debugInfo = [];
|
||||
private $sourceOffset;
|
||||
private $sourceLine;
|
||||
private $varNameSalt = 0;
|
||||
|
||||
public function __construct(Environment $env)
|
||||
@ -36,16 +35,6 @@ class Compiler implements \Twig_CompilerInterface
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 1.25 (to be removed in 2.0)
|
||||
*/
|
||||
public function getFilename()
|
||||
{
|
||||
@trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED);
|
||||
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the environment instance related to this compiler.
|
||||
*
|
||||
@ -73,7 +62,7 @@ class Compiler implements \Twig_CompilerInterface
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function compile(\Twig_NodeInterface $node, $indentation = 0)
|
||||
public function compile(Node $node, $indentation = 0)
|
||||
{
|
||||
$this->lastLine = null;
|
||||
$this->source = '';
|
||||
@ -84,17 +73,12 @@ class Compiler implements \Twig_CompilerInterface
|
||||
$this->indentation = $indentation;
|
||||
$this->varNameSalt = 0;
|
||||
|
||||
if ($node instanceof ModuleNode) {
|
||||
// to be removed in 2.0
|
||||
$this->filename = $node->getTemplateName();
|
||||
}
|
||||
|
||||
$node->compile($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function subcompile(\Twig_NodeInterface $node, $raw = true)
|
||||
public function subcompile(Node $node, $raw = true)
|
||||
{
|
||||
if (false === $raw) {
|
||||
$this->source .= str_repeat(' ', $this->indentation * 4);
|
||||
@ -124,9 +108,8 @@ class Compiler implements \Twig_CompilerInterface
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function write()
|
||||
public function write(...$strings)
|
||||
{
|
||||
$strings = \func_get_args();
|
||||
foreach ($strings as $string) {
|
||||
$this->source .= str_repeat(' ', $this->indentation * 4).$string;
|
||||
}
|
||||
@ -134,22 +117,6 @@ class Compiler implements \Twig_CompilerInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an indentation to the current PHP code after compilation.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated since 1.27 (to be removed in 2.0).
|
||||
*/
|
||||
public function addIndentation()
|
||||
{
|
||||
@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use write(\'\') instead.', E_USER_DEPRECATED);
|
||||
|
||||
$this->source .= str_repeat(' ', $this->indentation * 4);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a quoted string to the compiled code.
|
||||
*
|
||||
@ -174,21 +141,21 @@ class Compiler implements \Twig_CompilerInterface
|
||||
public function repr($value)
|
||||
{
|
||||
if (\is_int($value) || \is_float($value)) {
|
||||
if (false !== $locale = setlocale(LC_NUMERIC, '0')) {
|
||||
setlocale(LC_NUMERIC, 'C');
|
||||
if (false !== $locale = setlocale(\LC_NUMERIC, '0')) {
|
||||
setlocale(\LC_NUMERIC, 'C');
|
||||
}
|
||||
|
||||
$this->raw(var_export($value, true));
|
||||
|
||||
if (false !== $locale) {
|
||||
setlocale(LC_NUMERIC, $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('[');
|
||||
$this->raw('array(');
|
||||
$first = true;
|
||||
foreach ($value as $key => $v) {
|
||||
if (!$first) {
|
||||
@ -199,7 +166,7 @@ class Compiler implements \Twig_CompilerInterface
|
||||
$this->raw(' => ');
|
||||
$this->repr($v);
|
||||
}
|
||||
$this->raw(']');
|
||||
$this->raw(')');
|
||||
} else {
|
||||
$this->string($value);
|
||||
}
|
||||
@ -212,22 +179,12 @@ class Compiler implements \Twig_CompilerInterface
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addDebugInfo(\Twig_NodeInterface $node)
|
||||
public function addDebugInfo(Node $node)
|
||||
{
|
||||
if ($node->getTemplateLine() != $this->lastLine) {
|
||||
$this->write(sprintf("// line %d\n", $node->getTemplateLine()));
|
||||
|
||||
// when mbstring.func_overload is set to 2
|
||||
// mb_substr_count() replaces substr_count()
|
||||
// but they have different signatures!
|
||||
if (((int) ini_get('mbstring.func_overload')) & 2) {
|
||||
@trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED);
|
||||
|
||||
// this is much slower than the "right" version
|
||||
$this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
|
||||
} else {
|
||||
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
|
||||
}
|
||||
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
|
||||
$this->sourceOffset = \strlen($this->source);
|
||||
$this->debugInfo[$this->sourceLine] = $node->getTemplateLine();
|
||||
|
||||
@ -281,7 +238,7 @@ class Compiler implements \Twig_CompilerInterface
|
||||
|
||||
public function getVarName()
|
||||
{
|
||||
return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->varNameSalt++));
|
||||
return sprintf('__internal_compile_%d', $this->varNameSalt++);
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -38,11 +38,9 @@ use Twig\Template;
|
||||
*/
|
||||
class Error extends \Exception
|
||||
{
|
||||
protected $lineno;
|
||||
// to be renamed to name in 2.0
|
||||
protected $filename;
|
||||
protected $rawMessage;
|
||||
|
||||
private $lineno;
|
||||
private $name;
|
||||
private $rawMessage;
|
||||
private $sourcePath;
|
||||
private $sourceCode;
|
||||
|
||||
@ -57,22 +55,23 @@ class Error extends \Exception
|
||||
* @param Source|string|null $source The source context where the error occurred
|
||||
* @param \Exception $previous The previous exception
|
||||
*/
|
||||
public function __construct($message, $lineno = -1, $source = null, \Exception $previous = null)
|
||||
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) {
|
||||
// for compat with the Twig C ext., passing the template name as string is accepted
|
||||
} 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();
|
||||
}
|
||||
parent::__construct('', 0, $previous);
|
||||
|
||||
$this->lineno = $lineno;
|
||||
$this->filename = $name;
|
||||
$this->name = $name;
|
||||
$this->rawMessage = $message;
|
||||
$this->updateRepr();
|
||||
}
|
||||
@ -87,67 +86,6 @@ class Error extends \Exception
|
||||
return $this->rawMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the logical name where the error occurred.
|
||||
*
|
||||
* @return string The name
|
||||
*
|
||||
* @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead.
|
||||
*/
|
||||
public function getTemplateFile()
|
||||
{
|
||||
@trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logical name where the error occurred.
|
||||
*
|
||||
* @param string $name The name
|
||||
*
|
||||
* @deprecated since 1.27 (to be removed in 2.0). Use setSourceContext() instead.
|
||||
*/
|
||||
public function setTemplateFile($name)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
$this->filename = $name;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the logical name where the error occurred.
|
||||
*
|
||||
* @return string The name
|
||||
*
|
||||
* @deprecated since 1.29 (to be removed in 2.0). Use getSourceContext() instead.
|
||||
*/
|
||||
public function getTemplateName()
|
||||
{
|
||||
@trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logical name where the error occurred.
|
||||
*
|
||||
* @param string $name The name
|
||||
*
|
||||
* @deprecated since 1.29 (to be removed in 2.0). Use setSourceContext() instead.
|
||||
*/
|
||||
public function setTemplateName($name)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
$this->filename = $name;
|
||||
$this->sourceCode = $this->sourcePath = null;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the template line where the error occurred.
|
||||
*
|
||||
@ -177,7 +115,7 @@ class Error extends \Exception
|
||||
*/
|
||||
public function getSourceContext()
|
||||
{
|
||||
return $this->filename ? new Source($this->sourceCode, $this->filename, $this->sourcePath) : null;
|
||||
return $this->name ? new Source($this->sourceCode, $this->name, $this->sourcePath) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,10 +124,10 @@ class Error extends \Exception
|
||||
public function setSourceContext(Source $source = null)
|
||||
{
|
||||
if (null === $source) {
|
||||
$this->sourceCode = $this->filename = $this->sourcePath = null;
|
||||
$this->sourceCode = $this->name = $this->sourcePath = null;
|
||||
} else {
|
||||
$this->sourceCode = $source->getCode();
|
||||
$this->filename = $source->getName();
|
||||
$this->name = $source->getName();
|
||||
$this->sourcePath = $source->getPath();
|
||||
}
|
||||
|
||||
@ -208,10 +146,7 @@ class Error extends \Exception
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected function updateRepr()
|
||||
private function updateRepr()
|
||||
{
|
||||
$this->message = $this->rawMessage;
|
||||
|
||||
@ -234,11 +169,11 @@ class Error extends \Exception
|
||||
$questionMark = true;
|
||||
}
|
||||
|
||||
if ($this->filename) {
|
||||
if (\is_string($this->filename) || (\is_object($this->filename) && method_exists($this->filename, '__toString'))) {
|
||||
$name = sprintf('"%s"', $this->filename);
|
||||
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->filename);
|
||||
$name = json_encode($this->name);
|
||||
}
|
||||
$this->message .= sprintf(' in %s', $name);
|
||||
}
|
||||
@ -256,20 +191,17 @@ class Error extends \Exception
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected function guessTemplateInfo()
|
||||
private function guessTemplateInfo()
|
||||
{
|
||||
$template = null;
|
||||
$templateClass = null;
|
||||
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
|
||||
$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'])) {
|
||||
if (isset($trace['object']) && $trace['object'] instanceof Template && 'Twig\Template' !== \get_class($trace['object'])) {
|
||||
$currentClass = \get_class($trace['object']);
|
||||
$isEmbedContainer = 0 === strpos($templateClass, $currentClass);
|
||||
if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
|
||||
$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']);
|
||||
}
|
||||
@ -277,8 +209,8 @@ class Error extends \Exception
|
||||
}
|
||||
|
||||
// update template name
|
||||
if (null !== $template && null === $this->filename) {
|
||||
$this->filename = $template->getTemplateName();
|
||||
if (null !== $template && null === $this->name) {
|
||||
$this->name = $template->getTemplateName();
|
||||
}
|
||||
|
||||
// update template path if any
|
||||
@ -296,7 +228,7 @@ class Error extends \Exception
|
||||
$file = $r->getFileName();
|
||||
|
||||
$exceptions = [$e = $this];
|
||||
while ($e instanceof self && $e = $e->getPrevious()) {
|
||||
while ($e = $e->getPrevious()) {
|
||||
$exceptions[] = $e;
|
||||
}
|
||||
|
||||
|
@ -26,20 +26,6 @@ class SyntaxError extends Error
|
||||
* @param array $items An array of possible items
|
||||
*/
|
||||
public function addSuggestions($name, array $items)
|
||||
{
|
||||
if (!$alternatives = self::computeAlternatives($name, $items)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', $alternatives)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* To be merged with the addSuggestions() method in 2.0.
|
||||
*/
|
||||
public static function computeAlternatives($name, $items)
|
||||
{
|
||||
$alternatives = [];
|
||||
foreach ($items as $item) {
|
||||
@ -48,9 +34,14 @@ class SyntaxError extends Error
|
||||
$alternatives[$item] = $lev;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$alternatives) {
|
||||
return;
|
||||
}
|
||||
|
||||
asort($alternatives);
|
||||
|
||||
return array_keys($alternatives);
|
||||
$this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives))));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
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;
|
||||
@ -24,6 +25,7 @@ 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;
|
||||
@ -43,30 +45,20 @@ use Twig\Node\Node;
|
||||
*/
|
||||
class ExpressionParser
|
||||
{
|
||||
const OPERATOR_LEFT = 1;
|
||||
const OPERATOR_RIGHT = 2;
|
||||
|
||||
protected $parser;
|
||||
protected $unaryOperators;
|
||||
protected $binaryOperators;
|
||||
public const OPERATOR_LEFT = 1;
|
||||
public const OPERATOR_RIGHT = 2;
|
||||
|
||||
private $parser;
|
||||
private $env;
|
||||
private $unaryOperators;
|
||||
private $binaryOperators;
|
||||
|
||||
public function __construct(Parser $parser, $env = null)
|
||||
public function __construct(Parser $parser, Environment $env)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
|
||||
if ($env instanceof Environment) {
|
||||
$this->env = $env;
|
||||
$this->unaryOperators = $env->getUnaryOperators();
|
||||
$this->binaryOperators = $env->getBinaryOperators();
|
||||
} else {
|
||||
@trigger_error('Passing the operators as constructor arguments to '.__METHOD__.' is deprecated since version 1.27. Pass the environment instead.', E_USER_DEPRECATED);
|
||||
|
||||
$this->env = $parser->getEnvironment();
|
||||
$this->unaryOperators = func_get_arg(1);
|
||||
$this->binaryOperators = func_get_arg(2);
|
||||
}
|
||||
$this->env = $env;
|
||||
$this->unaryOperators = $env->getUnaryOperators();
|
||||
$this->binaryOperators = $env->getBinaryOperators();
|
||||
}
|
||||
|
||||
public function parseExpression($precedence = 0, $allowArrow = false)
|
||||
@ -86,7 +78,7 @@ class ExpressionParser
|
||||
} elseif ('is' === $token->getValue()) {
|
||||
$expr = $this->parseTestExpression($expr);
|
||||
} elseif (isset($op['callable'])) {
|
||||
$expr = \call_user_func($op['callable'], $this->parser, $expr);
|
||||
$expr = $op['callable']($this->parser, $expr);
|
||||
} else {
|
||||
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
|
||||
$class = $op['class'];
|
||||
@ -111,57 +103,57 @@ class ExpressionParser
|
||||
$stream = $this->parser->getStream();
|
||||
|
||||
// short array syntax (one argument, no parentheses)?
|
||||
if ($stream->look(1)->test(Token::ARROW_TYPE)) {
|
||||
if ($stream->look(1)->test(/* Token::ARROW_TYPE */ 12)) {
|
||||
$line = $stream->getCurrent()->getLine();
|
||||
$token = $stream->expect(Token::NAME_TYPE);
|
||||
$token = $stream->expect(/* Token::NAME_TYPE */ 5);
|
||||
$names = [new AssignNameExpression($token->getValue(), $token->getLine())];
|
||||
$stream->expect(Token::ARROW_TYPE);
|
||||
$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, '(')) {
|
||||
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, ',')) {
|
||||
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
|
||||
break;
|
||||
}
|
||||
++$i;
|
||||
}
|
||||
if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, ')')) {
|
||||
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
|
||||
return null;
|
||||
}
|
||||
++$i;
|
||||
if (!$stream->look($i)->test(Token::ARROW_TYPE)) {
|
||||
if (!$stream->look($i)->test(/* Token::ARROW_TYPE */ 12)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// yes, let's parse it properly
|
||||
$token = $stream->expect(Token::PUNCTUATION_TYPE, '(');
|
||||
$token = $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(');
|
||||
$line = $token->getLine();
|
||||
|
||||
$names = [];
|
||||
while (true) {
|
||||
$token = $stream->expect(Token::NAME_TYPE);
|
||||
$token = $stream->expect(/* Token::NAME_TYPE */ 5);
|
||||
$names[] = new AssignNameExpression($token->getValue(), $token->getLine());
|
||||
|
||||
if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) {
|
||||
if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ')');
|
||||
$stream->expect(Token::ARROW_TYPE);
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')');
|
||||
$stream->expect(/* Token::ARROW_TYPE */ 12);
|
||||
|
||||
return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line);
|
||||
}
|
||||
|
||||
protected function getPrimary()
|
||||
private function getPrimary(): AbstractExpression
|
||||
{
|
||||
$token = $this->parser->getCurrentToken();
|
||||
|
||||
@ -172,10 +164,10 @@ class ExpressionParser
|
||||
$class = $operator['class'];
|
||||
|
||||
return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
|
||||
} elseif ($token->test(Token::PUNCTUATION_TYPE, '(')) {
|
||||
} elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
|
||||
$this->parser->getStream()->next();
|
||||
$expr = $this->parseExpression();
|
||||
$this->parser->getStream()->expect(Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
|
||||
$this->parser->getStream()->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'An opened parenthesis is not properly closed');
|
||||
|
||||
return $this->parsePostfixExpression($expr);
|
||||
}
|
||||
@ -183,12 +175,12 @@ class ExpressionParser
|
||||
return $this->parsePrimaryExpression();
|
||||
}
|
||||
|
||||
protected function parseConditionalExpression($expr)
|
||||
private function parseConditionalExpression($expr): AbstractExpression
|
||||
{
|
||||
while ($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, '?')) {
|
||||
if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ':')) {
|
||||
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, ':')) {
|
||||
if ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
|
||||
$expr3 = $this->parseExpression();
|
||||
} else {
|
||||
$expr3 = new ConstantExpression('', $this->parser->getCurrentToken()->getLine());
|
||||
@ -204,21 +196,21 @@ class ExpressionParser
|
||||
return $expr;
|
||||
}
|
||||
|
||||
protected function isUnary(Token $token)
|
||||
private function isUnary(Token $token): bool
|
||||
{
|
||||
return $token->test(Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
|
||||
return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->unaryOperators[$token->getValue()]);
|
||||
}
|
||||
|
||||
protected function isBinary(Token $token)
|
||||
private function isBinary(Token $token): bool
|
||||
{
|
||||
return $token->test(Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
|
||||
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:
|
||||
case /* Token::NAME_TYPE */ 5:
|
||||
$this->parser->getStream()->next();
|
||||
switch ($token->getValue()) {
|
||||
case 'true':
|
||||
@ -247,17 +239,17 @@ class ExpressionParser
|
||||
}
|
||||
break;
|
||||
|
||||
case Token::NUMBER_TYPE:
|
||||
case /* Token::NUMBER_TYPE */ 6:
|
||||
$this->parser->getStream()->next();
|
||||
$node = new ConstantExpression($token->getValue(), $token->getLine());
|
||||
break;
|
||||
|
||||
case Token::STRING_TYPE:
|
||||
case Token::INTERPOLATION_START_TYPE:
|
||||
case /* Token::STRING_TYPE */ 7:
|
||||
case /* Token::INTERPOLATION_START_TYPE */ 10:
|
||||
$node = $this->parseStringExpression();
|
||||
break;
|
||||
|
||||
case Token::OPERATOR_TYPE:
|
||||
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();
|
||||
@ -267,10 +259,8 @@ class ExpressionParser
|
||||
$class = $this->unaryOperators[$token->getValue()]['class'];
|
||||
|
||||
$ref = new \ReflectionClass($class);
|
||||
$negClass = 'Twig\Node\Expression\Unary\NegUnary';
|
||||
$posClass = 'Twig\Node\Expression\Unary\PosUnary';
|
||||
if (!(\in_array($ref->getName(), [$negClass, $posClass, 'Twig_Node_Expression_Unary_Neg', 'Twig_Node_Expression_Unary_Pos'])
|
||||
|| $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass)
|
||||
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());
|
||||
@ -285,11 +275,11 @@ class ExpressionParser
|
||||
|
||||
// no break
|
||||
default:
|
||||
if ($token->test(Token::PUNCTUATION_TYPE, '[')) {
|
||||
if ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '[')) {
|
||||
$node = $this->parseArrayExpression();
|
||||
} elseif ($token->test(Token::PUNCTUATION_TYPE, '{')) {
|
||||
} elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) {
|
||||
$node = $this->parseHashExpression();
|
||||
} elseif ($token->test(Token::OPERATOR_TYPE, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
|
||||
} 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());
|
||||
@ -307,12 +297,12 @@ class ExpressionParser
|
||||
// a string cannot be followed by another string in a single expression
|
||||
$nextCanBeString = true;
|
||||
while (true) {
|
||||
if ($nextCanBeString && $token = $stream->nextIf(Token::STRING_TYPE)) {
|
||||
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)) {
|
||||
} elseif ($stream->nextIf(/* Token::INTERPOLATION_START_TYPE */ 10)) {
|
||||
$nodes[] = $this->parseExpression();
|
||||
$stream->expect(Token::INTERPOLATION_END_TYPE);
|
||||
$stream->expect(/* Token::INTERPOLATION_END_TYPE */ 11);
|
||||
$nextCanBeString = true;
|
||||
} else {
|
||||
break;
|
||||
@ -330,16 +320,16 @@ class ExpressionParser
|
||||
public function parseArrayExpression()
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
|
||||
$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, ']')) {
|
||||
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
|
||||
if (!$first) {
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma');
|
||||
|
||||
// trailing ,?
|
||||
if ($stream->test(Token::PUNCTUATION_TYPE, ']')) {
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -347,7 +337,7 @@ class ExpressionParser
|
||||
|
||||
$node->addElement($this->parseExpression());
|
||||
}
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed');
|
||||
|
||||
return $node;
|
||||
}
|
||||
@ -355,16 +345,16 @@ class ExpressionParser
|
||||
public function parseHashExpression()
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
|
||||
$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, '}')) {
|
||||
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
|
||||
if (!$first) {
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A hash value must be followed by a comma');
|
||||
|
||||
// trailing ,?
|
||||
if ($stream->test(Token::PUNCTUATION_TYPE, '}')) {
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -376,9 +366,18 @@ class ExpressionParser
|
||||
// * 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::STRING_TYPE)) || ($token = $stream->nextIf(Token::NAME_TYPE)) || $token = $stream->nextIf(Token::NUMBER_TYPE)) {
|
||||
if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) {
|
||||
$key = new ConstantExpression($token->getValue(), $token->getLine());
|
||||
} elseif ($stream->test(Token::PUNCTUATION_TYPE, '(')) {
|
||||
|
||||
// {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();
|
||||
@ -386,12 +385,12 @@ class ExpressionParser
|
||||
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, ':', 'A hash key must be followed by a colon (:)');
|
||||
$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, '}', 'An opened hash is not properly closed');
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '}', 'An opened hash is not properly closed');
|
||||
|
||||
return $node;
|
||||
}
|
||||
@ -400,7 +399,7 @@ class ExpressionParser
|
||||
{
|
||||
while (true) {
|
||||
$token = $this->parser->getCurrentToken();
|
||||
if (Token::PUNCTUATION_TYPE == $token->getType()) {
|
||||
if (/* Token::PUNCTUATION_TYPE */ 9 == $token->getType()) {
|
||||
if ('.' == $token->getValue() || '[' == $token->getValue()) {
|
||||
$node = $this->parseSubscriptExpression($node);
|
||||
} elseif ('|' == $token->getValue()) {
|
||||
@ -474,22 +473,22 @@ class ExpressionParser
|
||||
if ('.' == $token->getValue()) {
|
||||
$token = $stream->next();
|
||||
if (
|
||||
Token::NAME_TYPE == $token->getType()
|
||||
/* Token::NAME_TYPE */ 5 == $token->getType()
|
||||
||
|
||||
Token::NUMBER_TYPE == $token->getType()
|
||||
/* Token::NUMBER_TYPE */ 6 == $token->getType()
|
||||
||
|
||||
(Token::OPERATOR_TYPE == $token->getType() && preg_match(Lexer::REGEX_NAME, $token->getValue()))
|
||||
(/* 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, '(')) {
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
|
||||
$type = Template::METHOD_CALL;
|
||||
foreach ($this->parseArguments() as $n) {
|
||||
$arguments->addElement($n);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new SyntaxError('Expected name or number.', $lineno, $stream->getSourceContext());
|
||||
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'))) {
|
||||
@ -499,11 +498,7 @@ class ExpressionParser
|
||||
|
||||
$name = $arg->getAttribute('value');
|
||||
|
||||
if ($this->parser->isReservedMacroName($name)) {
|
||||
throw new SyntaxError(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext());
|
||||
}
|
||||
|
||||
$node = new MethodCallExpression($node, 'get'.$name, $arguments, $lineno);
|
||||
$node = new MethodCallExpression($node, 'macro_'.$name, $arguments, $lineno);
|
||||
$node->setAttribute('safe', true);
|
||||
|
||||
return $node;
|
||||
@ -513,19 +508,19 @@ class ExpressionParser
|
||||
|
||||
// slice?
|
||||
$slice = false;
|
||||
if ($stream->test(Token::PUNCTUATION_TYPE, ':')) {
|
||||
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, ':')) {
|
||||
if ($stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
|
||||
$slice = true;
|
||||
}
|
||||
|
||||
if ($slice) {
|
||||
if ($stream->test(Token::PUNCTUATION_TYPE, ']')) {
|
||||
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
|
||||
$length = new ConstantExpression(null, $token->getLine());
|
||||
} else {
|
||||
$length = $this->parseExpression();
|
||||
@ -535,12 +530,12 @@ class ExpressionParser
|
||||
$arguments = new Node([$arg, $length]);
|
||||
$filter = new $class($node, new ConstantExpression('slice', $token->getLine()), $arguments, $token->getLine());
|
||||
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ']');
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ']');
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
|
||||
}
|
||||
|
||||
return new GetAttrExpression($node, $arg, $arguments, $type, $lineno);
|
||||
@ -556,10 +551,10 @@ class ExpressionParser
|
||||
public function parseFilterExpressionRaw($node, $tag = null)
|
||||
{
|
||||
while (true) {
|
||||
$token = $this->parser->getStream()->expect(Token::NAME_TYPE);
|
||||
$token = $this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5);
|
||||
|
||||
$name = new ConstantExpression($token->getValue(), $token->getLine());
|
||||
if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '(')) {
|
||||
if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
|
||||
$arguments = new Node();
|
||||
} else {
|
||||
$arguments = $this->parseArguments(true, false, true);
|
||||
@ -569,7 +564,7 @@ class ExpressionParser
|
||||
|
||||
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
|
||||
|
||||
if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '|')) {
|
||||
if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '|')) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -594,21 +589,26 @@ class ExpressionParser
|
||||
$args = [];
|
||||
$stream = $this->parser->getStream();
|
||||
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
|
||||
while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) {
|
||||
$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, ',', 'Arguments must be separated by a comma');
|
||||
$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, null, 'An argument must be a name');
|
||||
$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, '=')) {
|
||||
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());
|
||||
}
|
||||
@ -618,7 +618,7 @@ class ExpressionParser
|
||||
$value = $this->parsePrimaryExpression();
|
||||
|
||||
if (!$this->checkConstantExpression($value)) {
|
||||
throw new SyntaxError(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $stream->getSourceContext());
|
||||
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);
|
||||
@ -639,7 +639,7 @@ class ExpressionParser
|
||||
}
|
||||
}
|
||||
}
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
|
||||
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'A list of arguments must be closed by a parenthesis');
|
||||
|
||||
return new Node($args);
|
||||
}
|
||||
@ -650,19 +650,19 @@ class ExpressionParser
|
||||
$targets = [];
|
||||
while (true) {
|
||||
$token = $this->parser->getCurrentToken();
|
||||
if ($stream->test(Token::OPERATOR_TYPE) && preg_match(Lexer::REGEX_NAME, $token->getValue())) {
|
||||
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, null, 'Only variables can be assigned to');
|
||||
$stream->expect(/* Token::NAME_TYPE */ 5, null, 'Only variables can be assigned to');
|
||||
}
|
||||
$value = $token->getValue();
|
||||
if (\in_array(strtolower($value), ['true', 'false', 'none', 'null'])) {
|
||||
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, ',')) {
|
||||
if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -675,7 +675,7 @@ class ExpressionParser
|
||||
$targets = [];
|
||||
while (true) {
|
||||
$targets[] = $this->parseExpression();
|
||||
if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ',')) {
|
||||
if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -683,35 +683,42 @@ class ExpressionParser
|
||||
return new Node($targets);
|
||||
}
|
||||
|
||||
private function parseNotTestExpression(\Twig_NodeInterface $node)
|
||||
private function parseNotTestExpression(Node $node): NotUnary
|
||||
{
|
||||
return new NotUnary($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
|
||||
}
|
||||
|
||||
private function parseTestExpression(\Twig_NodeInterface $node)
|
||||
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, '(')) {
|
||||
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($line)
|
||||
private function getTest(int $line): array
|
||||
{
|
||||
$stream = $this->parser->getStream();
|
||||
$name = $stream->expect(Token::NAME_TYPE)->getValue();
|
||||
$name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
|
||||
|
||||
if ($test = $this->env->getTest($name)) {
|
||||
return [$name, $test];
|
||||
}
|
||||
|
||||
if ($stream->test(Token::NAME_TYPE)) {
|
||||
if ($stream->test(/* Token::NAME_TYPE */ 5)) {
|
||||
// try 2-words tests
|
||||
$name = $name.' '.$this->parser->getCurrentToken()->getValue();
|
||||
|
||||
@ -728,11 +735,12 @@ class ExpressionParser
|
||||
throw $e;
|
||||
}
|
||||
|
||||
private function getTestNodeClass($test)
|
||||
private function getTestNodeClass(TwigTest $test): string
|
||||
{
|
||||
if ($test instanceof TwigTest && $test->isDeprecated()) {
|
||||
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());
|
||||
}
|
||||
@ -740,19 +748,15 @@ class ExpressionParser
|
||||
$message .= sprintf('. Use "%s" instead', $test->getAlternative());
|
||||
}
|
||||
$src = $stream->getSourceContext();
|
||||
$message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $stream->getCurrent()->getLine());
|
||||
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine());
|
||||
|
||||
@trigger_error($message, E_USER_DEPRECATED);
|
||||
@trigger_error($message, \E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
if ($test instanceof TwigTest) {
|
||||
return $test->getNodeClass();
|
||||
}
|
||||
|
||||
return $test instanceof \Twig_Test_Node ? $test->getClass() : 'Twig\Node\Expression\TestExpression';
|
||||
return $test->getNodeClass();
|
||||
}
|
||||
|
||||
protected function getFunctionNodeClass($name, $line)
|
||||
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());
|
||||
@ -761,7 +765,7 @@ class ExpressionParser
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($function instanceof TwigFunction && $function->isDeprecated()) {
|
||||
if ($function->isDeprecated()) {
|
||||
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
|
||||
if (!\is_bool($function->getDeprecatedVersion())) {
|
||||
$message .= sprintf(' since version %s', $function->getDeprecatedVersion());
|
||||
@ -770,19 +774,15 @@ class ExpressionParser
|
||||
$message .= sprintf('. Use "%s" instead', $function->getAlternative());
|
||||
}
|
||||
$src = $this->parser->getStream()->getSourceContext();
|
||||
$message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
|
||||
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
|
||||
|
||||
@trigger_error($message, E_USER_DEPRECATED);
|
||||
@trigger_error($message, \E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
if ($function instanceof TwigFunction) {
|
||||
return $function->getNodeClass();
|
||||
}
|
||||
|
||||
return $function instanceof \Twig_Function_Node ? $function->getClass() : 'Twig\Node\Expression\FunctionExpression';
|
||||
return $function->getNodeClass();
|
||||
}
|
||||
|
||||
protected function getFilterNodeClass($name, $line)
|
||||
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());
|
||||
@ -791,7 +791,7 @@ class ExpressionParser
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($filter instanceof TwigFilter && $filter->isDeprecated()) {
|
||||
if ($filter->isDeprecated()) {
|
||||
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
|
||||
if (!\is_bool($filter->getDeprecatedVersion())) {
|
||||
$message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
|
||||
@ -800,20 +800,16 @@ class ExpressionParser
|
||||
$message .= sprintf('. Use "%s" instead', $filter->getAlternative());
|
||||
}
|
||||
$src = $this->parser->getStream()->getSourceContext();
|
||||
$message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
|
||||
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
|
||||
|
||||
@trigger_error($message, E_USER_DEPRECATED);
|
||||
@trigger_error($message, \E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
if ($filter instanceof TwigFilter) {
|
||||
return $filter->getNodeClass();
|
||||
}
|
||||
|
||||
return $filter instanceof \Twig_Filter_Node ? $filter->getClass() : 'Twig\Node\Expression\FilterExpression';
|
||||
return $filter->getNodeClass();
|
||||
}
|
||||
|
||||
// checks that the node only contains "constant" elements
|
||||
protected function checkConstantExpression(\Twig_NodeInterface $node)
|
||||
private function checkConstantExpression(Node $node): bool
|
||||
{
|
||||
if (!($node instanceof ConstantExpression || $node instanceof ArrayExpression
|
||||
|| $node instanceof NegUnary || $node instanceof PosUnary
|
||||
|
@ -11,17 +11,8 @@
|
||||
|
||||
namespace Twig\Extension;
|
||||
|
||||
use Twig\Environment;
|
||||
|
||||
abstract class AbstractExtension implements ExtensionInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_InitRuntimeInterface instead
|
||||
*/
|
||||
public function initRuntime(Environment $environment)
|
||||
{
|
||||
}
|
||||
|
||||
public function getTokenParsers()
|
||||
{
|
||||
return [];
|
||||
@ -51,22 +42,6 @@ abstract class AbstractExtension implements ExtensionInterface
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_GlobalsInterface instead
|
||||
*/
|
||||
public function getGlobals()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return \get_class($this);
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\AbstractExtension', 'Twig_Extension');
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,10 +12,7 @@
|
||||
namespace Twig\Extension {
|
||||
use Twig\TwigFunction;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class DebugExtension extends AbstractExtension
|
||||
final class DebugExtension extends AbstractExtension
|
||||
{
|
||||
public function getFunctions()
|
||||
{
|
||||
@ -33,11 +30,6 @@ class DebugExtension extends AbstractExtension
|
||||
new TwigFunction('dump', 'twig_var_dump', ['is_safe' => $isDumpOutputHtmlSafe ? ['html'] : [], 'needs_context' => true, 'needs_environment' => true, 'is_variadic' => true]),
|
||||
];
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'debug';
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\DebugExtension', 'Twig_Extension_Debug');
|
||||
@ -48,7 +40,7 @@ use Twig\Environment;
|
||||
use Twig\Template;
|
||||
use Twig\TemplateWrapper;
|
||||
|
||||
function twig_var_dump(Environment $env, $context, array $vars = [])
|
||||
function twig_var_dump(Environment $env, $context, ...$vars)
|
||||
{
|
||||
if (!$env->isDebug()) {
|
||||
return;
|
||||
@ -66,9 +58,7 @@ function twig_var_dump(Environment $env, $context, array $vars = [])
|
||||
|
||||
var_dump($vars);
|
||||
} else {
|
||||
foreach ($vars as $var) {
|
||||
var_dump($var);
|
||||
}
|
||||
var_dump(...$vars);
|
||||
}
|
||||
|
||||
return ob_get_clean();
|
||||
|
@ -10,16 +10,21 @@
|
||||
*/
|
||||
|
||||
namespace Twig\Extension {
|
||||
use Twig\FileExtensionEscapingStrategy;
|
||||
use Twig\NodeVisitor\EscaperNodeVisitor;
|
||||
use Twig\TokenParser\AutoEscapeTokenParser;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class EscaperExtension extends AbstractExtension
|
||||
final class EscaperExtension extends AbstractExtension
|
||||
{
|
||||
protected $defaultStrategy;
|
||||
private $defaultStrategy;
|
||||
private $escapers = [];
|
||||
|
||||
/** @internal */
|
||||
public $safeClasses = [];
|
||||
|
||||
/** @internal */
|
||||
public $safeLookup = [];
|
||||
|
||||
/**
|
||||
* @param string|false|callable $defaultStrategy An escaping strategy
|
||||
@ -44,6 +49,8 @@ class EscaperExtension extends AbstractExtension
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('escape', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
|
||||
new TwigFilter('e', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
|
||||
new TwigFilter('raw', 'twig_raw_filter', ['is_safe' => ['all']]),
|
||||
];
|
||||
}
|
||||
@ -58,21 +65,8 @@ class EscaperExtension extends AbstractExtension
|
||||
*/
|
||||
public function setDefaultStrategy($defaultStrategy)
|
||||
{
|
||||
// for BC
|
||||
if (true === $defaultStrategy) {
|
||||
@trigger_error('Using "true" as the default strategy is deprecated since version 1.21. Use "html" instead.', E_USER_DEPRECATED);
|
||||
|
||||
$defaultStrategy = 'html';
|
||||
}
|
||||
|
||||
if ('filename' === $defaultStrategy) {
|
||||
@trigger_error('Using "filename" as the default strategy is deprecated since version 1.27. Use "name" instead.', E_USER_DEPRECATED);
|
||||
|
||||
$defaultStrategy = 'name';
|
||||
}
|
||||
|
||||
if ('name' === $defaultStrategy) {
|
||||
$defaultStrategy = ['\Twig\FileExtensionEscapingStrategy', 'guess'];
|
||||
$defaultStrategy = [FileExtensionEscapingStrategy::class, 'guess'];
|
||||
}
|
||||
|
||||
$this->defaultStrategy = $defaultStrategy;
|
||||
@ -96,9 +90,47 @@ class EscaperExtension extends AbstractExtension
|
||||
return $this->defaultStrategy;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
/**
|
||||
* Defines a new escaper to be used via the escape filter.
|
||||
*
|
||||
* @param string $strategy The strategy name that should be used as a strategy in the escape call
|
||||
* @param callable $callable A valid PHP callable
|
||||
*/
|
||||
public function setEscaper($strategy, callable $callable)
|
||||
{
|
||||
return 'escaper';
|
||||
$this->escapers[$strategy] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all defined escapers.
|
||||
*
|
||||
* @return callable[] An array of escapers
|
||||
*/
|
||||
public function getEscapers()
|
||||
{
|
||||
return $this->escapers;
|
||||
}
|
||||
|
||||
public function setSafeClasses(array $safeClasses = [])
|
||||
{
|
||||
$this->safeClasses = [];
|
||||
$this->safeLookup = [];
|
||||
foreach ($safeClasses as $class => $strategies) {
|
||||
$this->addSafeClass($class, $strategies);
|
||||
}
|
||||
}
|
||||
|
||||
public function addSafeClass(string $class, array $strategies)
|
||||
{
|
||||
$class = ltrim($class, '\\');
|
||||
if (!isset($this->safeClasses[$class])) {
|
||||
$this->safeClasses[$class] = [];
|
||||
}
|
||||
$this->safeClasses[$class] = array_merge($this->safeClasses[$class], $strategies);
|
||||
|
||||
foreach ($strategies as $strategy) {
|
||||
$this->safeLookup[$strategy][$class] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,6 +138,14 @@ class_alias('Twig\Extension\EscaperExtension', 'Twig_Extension_Escaper');
|
||||
}
|
||||
|
||||
namespace {
|
||||
use Twig\Environment;
|
||||
use Twig\Error\RuntimeError;
|
||||
use Twig\Extension\CoreExtension;
|
||||
use Twig\Extension\EscaperExtension;
|
||||
use Twig\Markup;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Node;
|
||||
|
||||
/**
|
||||
* Marks a variable as being safe.
|
||||
*
|
||||
@ -117,4 +157,272 @@ function twig_raw_filter($string)
|
||||
{
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes a string.
|
||||
*
|
||||
* @param mixed $string The value to be escaped
|
||||
* @param string $strategy The escaping strategy
|
||||
* @param string $charset The charset
|
||||
* @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function twig_escape_filter(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
|
||||
{
|
||||
if ($autoescape && $string instanceof Markup) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
if (!\is_string($string)) {
|
||||
if (\is_object($string) && method_exists($string, '__toString')) {
|
||||
if ($autoescape) {
|
||||
$c = \get_class($string);
|
||||
$ext = $env->getExtension(EscaperExtension::class);
|
||||
if (!isset($ext->safeClasses[$c])) {
|
||||
$ext->safeClasses[$c] = [];
|
||||
foreach (class_parents($string) + class_implements($string) as $class) {
|
||||
if (isset($ext->safeClasses[$class])) {
|
||||
$ext->safeClasses[$c] = array_unique(array_merge($ext->safeClasses[$c], $ext->safeClasses[$class]));
|
||||
foreach ($ext->safeClasses[$class] as $s) {
|
||||
$ext->safeLookup[$s][$c] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($ext->safeLookup[$strategy][$c]) || isset($ext->safeLookup['all'][$c])) {
|
||||
return (string) $string;
|
||||
}
|
||||
}
|
||||
|
||||
$string = (string) $string;
|
||||
} elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'])) {
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
if ('' === $string) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (null === $charset) {
|
||||
$charset = $env->getCharset();
|
||||
}
|
||||
|
||||
switch ($strategy) {
|
||||
case 'html':
|
||||
// see https://www.php.net/htmlspecialchars
|
||||
|
||||
// Using a static variable to avoid initializing the array
|
||||
// each time the function is called. Moving the declaration on the
|
||||
// top of the function slow downs other escaping strategies.
|
||||
static $htmlspecialcharsCharsets = [
|
||||
'ISO-8859-1' => true, 'ISO8859-1' => true,
|
||||
'ISO-8859-15' => true, 'ISO8859-15' => true,
|
||||
'utf-8' => true, 'UTF-8' => true,
|
||||
'CP866' => true, 'IBM866' => true, '866' => true,
|
||||
'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
|
||||
'1251' => true,
|
||||
'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
|
||||
'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
|
||||
'BIG5' => true, '950' => true,
|
||||
'GB2312' => true, '936' => true,
|
||||
'BIG5-HKSCS' => true,
|
||||
'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
|
||||
'EUC-JP' => true, 'EUCJP' => true,
|
||||
'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
|
||||
];
|
||||
|
||||
if (isset($htmlspecialcharsCharsets[$charset])) {
|
||||
return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
|
||||
}
|
||||
|
||||
if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
|
||||
// cache the lowercase variant for future iterations
|
||||
$htmlspecialcharsCharsets[$charset] = true;
|
||||
|
||||
return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
|
||||
}
|
||||
|
||||
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
||||
$string = htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8');
|
||||
|
||||
return iconv('UTF-8', $charset, $string);
|
||||
|
||||
case 'js':
|
||||
// escape all non-alphanumeric characters
|
||||
// into their \x or \uHHHH representations
|
||||
if ('UTF-8' !== $charset) {
|
||||
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
||||
}
|
||||
|
||||
if (!preg_match('//u', $string)) {
|
||||
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
|
||||
}
|
||||
|
||||
$string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', function ($matches) {
|
||||
$char = $matches[0];
|
||||
|
||||
/*
|
||||
* A few characters have short escape sequences in JSON and JavaScript.
|
||||
* Escape sequences supported only by JavaScript, not JSON, are omitted.
|
||||
* \" is also supported but omitted, because the resulting string is not HTML safe.
|
||||
*/
|
||||
static $shortMap = [
|
||||
'\\' => '\\\\',
|
||||
'/' => '\\/',
|
||||
"\x08" => '\b',
|
||||
"\x0C" => '\f',
|
||||
"\x0A" => '\n',
|
||||
"\x0D" => '\r',
|
||||
"\x09" => '\t',
|
||||
];
|
||||
|
||||
if (isset($shortMap[$char])) {
|
||||
return $shortMap[$char];
|
||||
}
|
||||
|
||||
$codepoint = mb_ord($char, 'UTF-8');
|
||||
if (0x10000 > $codepoint) {
|
||||
return sprintf('\u%04X', $codepoint);
|
||||
}
|
||||
|
||||
// Split characters outside the BMP into surrogate pairs
|
||||
// https://tools.ietf.org/html/rfc2781.html#section-2.1
|
||||
$u = $codepoint - 0x10000;
|
||||
$high = 0xD800 | ($u >> 10);
|
||||
$low = 0xDC00 | ($u & 0x3FF);
|
||||
|
||||
return sprintf('\u%04X\u%04X', $high, $low);
|
||||
}, $string);
|
||||
|
||||
if ('UTF-8' !== $charset) {
|
||||
$string = iconv('UTF-8', $charset, $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
|
||||
case 'css':
|
||||
if ('UTF-8' !== $charset) {
|
||||
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
||||
}
|
||||
|
||||
if (!preg_match('//u', $string)) {
|
||||
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
|
||||
}
|
||||
|
||||
$string = preg_replace_callback('#[^a-zA-Z0-9]#Su', function ($matches) {
|
||||
$char = $matches[0];
|
||||
|
||||
return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : mb_ord($char, 'UTF-8'));
|
||||
}, $string);
|
||||
|
||||
if ('UTF-8' !== $charset) {
|
||||
$string = iconv('UTF-8', $charset, $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
|
||||
case 'html_attr':
|
||||
if ('UTF-8' !== $charset) {
|
||||
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
||||
}
|
||||
|
||||
if (!preg_match('//u', $string)) {
|
||||
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
|
||||
}
|
||||
|
||||
$string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', function ($matches) {
|
||||
/**
|
||||
* This function is adapted from code coming from Zend Framework.
|
||||
*
|
||||
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com)
|
||||
* @license https://framework.zend.com/license/new-bsd New BSD License
|
||||
*/
|
||||
$chr = $matches[0];
|
||||
$ord = \ord($chr);
|
||||
|
||||
/*
|
||||
* The following replaces characters undefined in HTML with the
|
||||
* hex entity for the Unicode replacement character.
|
||||
*/
|
||||
if (($ord <= 0x1f && "\t" != $chr && "\n" != $chr && "\r" != $chr) || ($ord >= 0x7f && $ord <= 0x9f)) {
|
||||
return '�';
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the current character to escape has a name entity we should
|
||||
* replace it with while grabbing the hex value of the character.
|
||||
*/
|
||||
if (1 === \strlen($chr)) {
|
||||
/*
|
||||
* While HTML supports far more named entities, the lowest common denominator
|
||||
* has become HTML5's XML Serialisation which is restricted to the those named
|
||||
* entities that XML supports. Using HTML entities would result in this error:
|
||||
* XML Parsing Error: undefined entity
|
||||
*/
|
||||
static $entityMap = [
|
||||
34 => '"', /* quotation mark */
|
||||
38 => '&', /* ampersand */
|
||||
60 => '<', /* less-than sign */
|
||||
62 => '>', /* greater-than sign */
|
||||
];
|
||||
|
||||
if (isset($entityMap[$ord])) {
|
||||
return $entityMap[$ord];
|
||||
}
|
||||
|
||||
return sprintf('&#x%02X;', $ord);
|
||||
}
|
||||
|
||||
/*
|
||||
* Per OWASP recommendations, we'll use hex entities for any other
|
||||
* characters where a named entity does not exist.
|
||||
*/
|
||||
return sprintf('&#x%04X;', mb_ord($chr, 'UTF-8'));
|
||||
}, $string);
|
||||
|
||||
if ('UTF-8' !== $charset) {
|
||||
$string = iconv('UTF-8', $charset, $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
|
||||
case 'url':
|
||||
return rawurlencode($string);
|
||||
|
||||
default:
|
||||
// check the ones set on CoreExtension for BC (to be removed in 3.0)
|
||||
$legacyEscapers = $env->getExtension(CoreExtension::class)->getEscapers(false);
|
||||
if (array_key_exists($strategy, $legacyEscapers)) {
|
||||
return $legacyEscapers[$strategy]($env, $string, $charset);
|
||||
}
|
||||
|
||||
$escapers = $env->getExtension(EscaperExtension::class)->getEscapers();
|
||||
if (array_key_exists($strategy, $escapers)) {
|
||||
return $escapers[$strategy]($env, $string, $charset);
|
||||
}
|
||||
|
||||
$escapers = array_merge($legacyEscapers, $escapers);
|
||||
$validStrategies = implode(', ', array_merge(['html', 'js', 'url', 'css', 'html_attr'], array_keys($escapers)));
|
||||
|
||||
throw new RuntimeError(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
function twig_escape_filter_is_safe(Node $filterArgs)
|
||||
{
|
||||
foreach ($filterArgs as $arg) {
|
||||
if ($arg instanceof ConstantExpression) {
|
||||
return [$arg->getAttribute('value')];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
return ['html'];
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace Twig\Extension;
|
||||
|
||||
use Twig\Environment;
|
||||
use Twig\NodeVisitor\NodeVisitorInterface;
|
||||
use Twig\TokenParser\TokenParserInterface;
|
||||
use Twig\TwigFilter;
|
||||
@ -25,15 +24,6 @@ use Twig\TwigTest;
|
||||
*/
|
||||
interface ExtensionInterface
|
||||
{
|
||||
/**
|
||||
* Initializes the runtime environment.
|
||||
*
|
||||
* This is where you can load some file that contains filter functions for instance.
|
||||
*
|
||||
* @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_InitRuntimeInterface instead
|
||||
*/
|
||||
public function initRuntime(Environment $environment);
|
||||
|
||||
/**
|
||||
* Returns the token parser instances to add to the existing list.
|
||||
*
|
||||
@ -75,24 +65,6 @@ interface ExtensionInterface
|
||||
* @return array<array> First array of unary operators, second array of binary operators
|
||||
*/
|
||||
public function getOperators();
|
||||
|
||||
/**
|
||||
* Returns a list of global variables to add to the existing list.
|
||||
*
|
||||
* @return array An array of global variables
|
||||
*
|
||||
* @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_GlobalsInterface instead
|
||||
*/
|
||||
public function getGlobals();
|
||||
|
||||
/**
|
||||
* Returns the name of the extension.
|
||||
*
|
||||
* @return string The extension name
|
||||
*
|
||||
* @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
|
||||
*/
|
||||
public function getName();
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\ExtensionInterface', 'Twig_ExtensionInterface');
|
||||
|
@ -21,6 +21,12 @@ namespace Twig\Extension;
|
||||
*/
|
||||
interface GlobalsInterface
|
||||
{
|
||||
/**
|
||||
* Returns a list of global variables to add to the existing list.
|
||||
*
|
||||
* @return array An array of global variables
|
||||
*/
|
||||
public function getGlobals();
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\GlobalsInterface', 'Twig_Extension_GlobalsInterface');
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
namespace Twig\Extension;
|
||||
|
||||
use Twig\Environment;
|
||||
|
||||
/**
|
||||
* Enables usage of the deprecated Twig\Extension\AbstractExtension::initRuntime() method.
|
||||
*
|
||||
@ -18,9 +20,17 @@ namespace Twig\Extension;
|
||||
* deprecated initRuntime() method in your extensions.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since Twig 2.7, to be removed in 3.0
|
||||
*/
|
||||
interface InitRuntimeInterface
|
||||
{
|
||||
/**
|
||||
* Initializes the runtime environment.
|
||||
*
|
||||
* This is where you can load some file that contains filter functions for instance.
|
||||
*/
|
||||
public function initRuntime(Environment $environment);
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\InitRuntimeInterface', 'Twig_Extension_InitRuntimeInterface');
|
||||
|
@ -13,12 +13,9 @@ namespace Twig\Extension;
|
||||
|
||||
use Twig\NodeVisitor\OptimizerNodeVisitor;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class OptimizerExtension extends AbstractExtension
|
||||
final class OptimizerExtension extends AbstractExtension
|
||||
{
|
||||
protected $optimizers;
|
||||
private $optimizers;
|
||||
|
||||
public function __construct($optimizers = -1)
|
||||
{
|
||||
@ -29,11 +26,6 @@ class OptimizerExtension extends AbstractExtension
|
||||
{
|
||||
return [new OptimizerNodeVisitor($this->optimizers)];
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'optimizer';
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\OptimizerExtension', 'Twig_Extension_Optimizer');
|
||||
|
@ -41,12 +41,7 @@ class ProfilerExtension extends AbstractExtension
|
||||
|
||||
public function getNodeVisitors()
|
||||
{
|
||||
return [new ProfilerNodeVisitor(\get_class($this))];
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'profiler';
|
||||
return [new ProfilerNodeVisitor(static::class)];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,17 +12,17 @@
|
||||
namespace Twig\Extension;
|
||||
|
||||
use Twig\NodeVisitor\SandboxNodeVisitor;
|
||||
use Twig\Sandbox\SecurityNotAllowedMethodError;
|
||||
use Twig\Sandbox\SecurityNotAllowedPropertyError;
|
||||
use Twig\Sandbox\SecurityPolicyInterface;
|
||||
use Twig\Source;
|
||||
use Twig\TokenParser\SandboxTokenParser;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class SandboxExtension extends AbstractExtension
|
||||
final class SandboxExtension extends AbstractExtension
|
||||
{
|
||||
protected $sandboxedGlobally;
|
||||
protected $sandboxed;
|
||||
protected $policy;
|
||||
private $sandboxedGlobally;
|
||||
private $sandboxed;
|
||||
private $policy;
|
||||
|
||||
public function __construct(SecurityPolicyInterface $policy, $sandboxed = false)
|
||||
{
|
||||
@ -77,33 +77,49 @@ class SandboxExtension extends AbstractExtension
|
||||
}
|
||||
}
|
||||
|
||||
public function checkMethodAllowed($obj, $method)
|
||||
public function checkMethodAllowed($obj, $method, int $lineno = -1, Source $source = null)
|
||||
{
|
||||
if ($this->isSandboxed()) {
|
||||
$this->policy->checkMethodAllowed($obj, $method);
|
||||
try {
|
||||
$this->policy->checkMethodAllowed($obj, $method);
|
||||
} catch (SecurityNotAllowedMethodError $e) {
|
||||
$e->setSourceContext($source);
|
||||
$e->setTemplateLine($lineno);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function checkPropertyAllowed($obj, $method)
|
||||
public function checkPropertyAllowed($obj, $property, int $lineno = -1, Source $source = null)
|
||||
{
|
||||
if ($this->isSandboxed()) {
|
||||
$this->policy->checkPropertyAllowed($obj, $method);
|
||||
try {
|
||||
$this->policy->checkPropertyAllowed($obj, $property);
|
||||
} catch (SecurityNotAllowedPropertyError $e) {
|
||||
$e->setSourceContext($source);
|
||||
$e->setTemplateLine($lineno);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function ensureToStringAllowed($obj)
|
||||
public function ensureToStringAllowed($obj, int $lineno = -1, Source $source = null)
|
||||
{
|
||||
if ($this->isSandboxed() && \is_object($obj) && method_exists($obj, '__toString')) {
|
||||
$this->policy->checkMethodAllowed($obj, '__toString');
|
||||
try {
|
||||
$this->policy->checkMethodAllowed($obj, '__toString');
|
||||
} catch (SecurityNotAllowedMethodError $e) {
|
||||
$e->setSourceContext($source);
|
||||
$e->setTemplateLine($lineno);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'sandbox';
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\SandboxExtension', 'Twig_Extension_Sandbox');
|
||||
|
@ -13,32 +13,32 @@ namespace Twig\Extension;
|
||||
|
||||
use Twig\NodeVisitor\NodeVisitorInterface;
|
||||
use Twig\TokenParser\TokenParserInterface;
|
||||
use Twig\TwigFilter;
|
||||
use Twig\TwigFunction;
|
||||
use Twig\TwigTest;
|
||||
|
||||
/**
|
||||
* Internal class.
|
||||
*
|
||||
* This class is used by \Twig\Environment as a staging area and must not be used directly.
|
||||
* Used by \Twig\Environment as a staging area.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class StagingExtension extends AbstractExtension
|
||||
final class StagingExtension extends AbstractExtension
|
||||
{
|
||||
protected $functions = [];
|
||||
protected $filters = [];
|
||||
protected $visitors = [];
|
||||
protected $tokenParsers = [];
|
||||
protected $globals = [];
|
||||
protected $tests = [];
|
||||
private $functions = [];
|
||||
private $filters = [];
|
||||
private $visitors = [];
|
||||
private $tokenParsers = [];
|
||||
private $tests = [];
|
||||
|
||||
public function addFunction($name, $function)
|
||||
public function addFunction(TwigFunction $function)
|
||||
{
|
||||
if (isset($this->functions[$name])) {
|
||||
@trigger_error(sprintf('Overriding function "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
|
||||
if (isset($this->functions[$function->getName()])) {
|
||||
throw new \LogicException(sprintf('Function "%s" is already registered.', $function->getName()));
|
||||
}
|
||||
|
||||
$this->functions[$name] = $function;
|
||||
$this->functions[$function->getName()] = $function;
|
||||
}
|
||||
|
||||
public function getFunctions()
|
||||
@ -46,13 +46,13 @@ class StagingExtension extends AbstractExtension
|
||||
return $this->functions;
|
||||
}
|
||||
|
||||
public function addFilter($name, $filter)
|
||||
public function addFilter(TwigFilter $filter)
|
||||
{
|
||||
if (isset($this->filters[$name])) {
|
||||
@trigger_error(sprintf('Overriding filter "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
|
||||
if (isset($this->filters[$filter->getName()])) {
|
||||
throw new \LogicException(sprintf('Filter "%s" is already registered.', $filter->getName()));
|
||||
}
|
||||
|
||||
$this->filters[$name] = $filter;
|
||||
$this->filters[$filter->getName()] = $filter;
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
@ -73,7 +73,7 @@ class StagingExtension extends AbstractExtension
|
||||
public function addTokenParser(TokenParserInterface $parser)
|
||||
{
|
||||
if (isset($this->tokenParsers[$parser->getTag()])) {
|
||||
@trigger_error(sprintf('Overriding tag "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $parser->getTag()), E_USER_DEPRECATED);
|
||||
throw new \LogicException(sprintf('Tag "%s" is already registered.', $parser->getTag()));
|
||||
}
|
||||
|
||||
$this->tokenParsers[$parser->getTag()] = $parser;
|
||||
@ -84,34 +84,19 @@ class StagingExtension extends AbstractExtension
|
||||
return $this->tokenParsers;
|
||||
}
|
||||
|
||||
public function addGlobal($name, $value)
|
||||
public function addTest(TwigTest $test)
|
||||
{
|
||||
$this->globals[$name] = $value;
|
||||
}
|
||||
|
||||
public function getGlobals()
|
||||
{
|
||||
return $this->globals;
|
||||
}
|
||||
|
||||
public function addTest($name, $test)
|
||||
{
|
||||
if (isset($this->tests[$name])) {
|
||||
@trigger_error(sprintf('Overriding test "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
|
||||
if (isset($this->tests[$test->getName()])) {
|
||||
throw new \LogicException(sprintf('Test "%s" is already registered.', $test->getName()));
|
||||
}
|
||||
|
||||
$this->tests[$name] = $test;
|
||||
$this->tests[$test->getName()] = $test;
|
||||
}
|
||||
|
||||
public function getTests()
|
||||
{
|
||||
return $this->tests;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'staging';
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\StagingExtension', 'Twig_Extension_Staging');
|
||||
|
@ -12,10 +12,7 @@
|
||||
namespace Twig\Extension {
|
||||
use Twig\TwigFunction;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class StringLoaderExtension extends AbstractExtension
|
||||
final class StringLoaderExtension extends AbstractExtension
|
||||
{
|
||||
public function getFunctions()
|
||||
{
|
||||
@ -23,11 +20,6 @@ class StringLoaderExtension extends AbstractExtension
|
||||
new TwigFunction('template_from_string', 'twig_template_from_string', ['needs_environment' => true]),
|
||||
];
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'string_loader';
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\Extension\StringLoaderExtension', 'Twig_Extension_StringLoader');
|
||||
@ -47,7 +39,7 @@ use Twig\TemplateWrapper;
|
||||
*
|
||||
* @return TemplateWrapper
|
||||
*/
|
||||
function twig_template_from_string(Environment $env, $template, $name = null)
|
||||
function twig_template_from_string(Environment $env, $template, string $name = null)
|
||||
{
|
||||
return $env->createTemplate((string) $template, $name);
|
||||
}
|
||||
|
475
system/libs/Twig/ExtensionSet.php
Normal file
475
system/libs/Twig/ExtensionSet.php
Normal file
@ -0,0 +1,475 @@
|
||||
<?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\Error\RuntimeError;
|
||||
use Twig\Extension\ExtensionInterface;
|
||||
use Twig\Extension\GlobalsInterface;
|
||||
use Twig\Extension\InitRuntimeInterface;
|
||||
use Twig\Extension\StagingExtension;
|
||||
use Twig\NodeVisitor\NodeVisitorInterface;
|
||||
use Twig\TokenParser\TokenParserInterface;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class ExtensionSet
|
||||
{
|
||||
private $extensions;
|
||||
private $initialized = false;
|
||||
private $runtimeInitialized = false;
|
||||
private $staging;
|
||||
private $parsers;
|
||||
private $visitors;
|
||||
private $filters;
|
||||
private $tests;
|
||||
private $functions;
|
||||
private $unaryOperators;
|
||||
private $binaryOperators;
|
||||
private $globals;
|
||||
private $functionCallbacks = [];
|
||||
private $filterCallbacks = [];
|
||||
private $lastModified = 0;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->staging = new StagingExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the runtime environment.
|
||||
*
|
||||
* @deprecated since Twig 2.7
|
||||
*/
|
||||
public function initRuntime(Environment $env)
|
||||
{
|
||||
if ($this->runtimeInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->runtimeInitialized = true;
|
||||
|
||||
foreach ($this->extensions as $extension) {
|
||||
if ($extension instanceof InitRuntimeInterface) {
|
||||
$extension->initRuntime($env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function hasExtension(string $class): bool
|
||||
{
|
||||
$class = ltrim($class, '\\');
|
||||
if (!isset($this->extensions[$class]) && class_exists($class, false)) {
|
||||
// For BC/FC with namespaced aliases
|
||||
$class = (new \ReflectionClass($class))->name;
|
||||
}
|
||||
|
||||
return isset($this->extensions[$class]);
|
||||
}
|
||||
|
||||
public function getExtension(string $class): ExtensionInterface
|
||||
{
|
||||
$class = ltrim($class, '\\');
|
||||
if (!isset($this->extensions[$class]) && class_exists($class, false)) {
|
||||
// For BC/FC with namespaced aliases
|
||||
$class = (new \ReflectionClass($class))->name;
|
||||
}
|
||||
|
||||
if (!isset($this->extensions[$class])) {
|
||||
throw new RuntimeError(sprintf('The "%s" extension is not enabled.', $class));
|
||||
}
|
||||
|
||||
return $this->extensions[$class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ExtensionInterface[] $extensions
|
||||
*/
|
||||
public function setExtensions(array $extensions)
|
||||
{
|
||||
foreach ($extensions as $extension) {
|
||||
$this->addExtension($extension);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ExtensionInterface[]
|
||||
*/
|
||||
public function getExtensions(): array
|
||||
{
|
||||
return $this->extensions;
|
||||
}
|
||||
|
||||
public function getSignature(): string
|
||||
{
|
||||
return json_encode(array_keys($this->extensions));
|
||||
}
|
||||
|
||||
public function isInitialized(): bool
|
||||
{
|
||||
return $this->initialized || $this->runtimeInitialized;
|
||||
}
|
||||
|
||||
public function getLastModified(): int
|
||||
{
|
||||
if (0 !== $this->lastModified) {
|
||||
return $this->lastModified;
|
||||
}
|
||||
|
||||
foreach ($this->extensions as $extension) {
|
||||
$r = new \ReflectionObject($extension);
|
||||
if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModified) {
|
||||
$this->lastModified = $extensionTime;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->lastModified;
|
||||
}
|
||||
|
||||
public function addExtension(ExtensionInterface $extension)
|
||||
{
|
||||
$class = \get_class($extension);
|
||||
|
||||
if ($this->initialized) {
|
||||
throw new \LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
|
||||
}
|
||||
|
||||
if (isset($this->extensions[$class])) {
|
||||
throw new \LogicException(sprintf('Unable to register extension "%s" as it is already registered.', $class));
|
||||
}
|
||||
|
||||
$this->extensions[$class] = $extension;
|
||||
}
|
||||
|
||||
public function addFunction(TwigFunction $function)
|
||||
{
|
||||
if ($this->initialized) {
|
||||
throw new \LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName()));
|
||||
}
|
||||
|
||||
$this->staging->addFunction($function);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TwigFunction[]
|
||||
*/
|
||||
public function getFunctions(): array
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
return $this->functions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TwigFunction|false
|
||||
*/
|
||||
public function getFunction(string $name)
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
if (isset($this->functions[$name])) {
|
||||
return $this->functions[$name];
|
||||
}
|
||||
|
||||
foreach ($this->functions as $pattern => $function) {
|
||||
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
|
||||
|
||||
if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
|
||||
array_shift($matches);
|
||||
$function->setArguments($matches);
|
||||
|
||||
return $function;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->functionCallbacks as $callback) {
|
||||
if (false !== $function = $callback($name)) {
|
||||
return $function;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function registerUndefinedFunctionCallback(callable $callable)
|
||||
{
|
||||
$this->functionCallbacks[] = $callable;
|
||||
}
|
||||
|
||||
public function addFilter(TwigFilter $filter)
|
||||
{
|
||||
if ($this->initialized) {
|
||||
throw new \LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
|
||||
}
|
||||
|
||||
$this->staging->addFilter($filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TwigFilter[]
|
||||
*/
|
||||
public function getFilters(): array
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
return $this->filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TwigFilter|false
|
||||
*/
|
||||
public function getFilter(string $name)
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
if (isset($this->filters[$name])) {
|
||||
return $this->filters[$name];
|
||||
}
|
||||
|
||||
foreach ($this->filters as $pattern => $filter) {
|
||||
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
|
||||
|
||||
if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
|
||||
array_shift($matches);
|
||||
$filter->setArguments($matches);
|
||||
|
||||
return $filter;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->filterCallbacks as $callback) {
|
||||
if (false !== $filter = $callback($name)) {
|
||||
return $filter;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function registerUndefinedFilterCallback(callable $callable)
|
||||
{
|
||||
$this->filterCallbacks[] = $callable;
|
||||
}
|
||||
|
||||
public function addNodeVisitor(NodeVisitorInterface $visitor)
|
||||
{
|
||||
if ($this->initialized) {
|
||||
throw new \LogicException('Unable to add a node visitor as extensions have already been initialized.');
|
||||
}
|
||||
|
||||
$this->staging->addNodeVisitor($visitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NodeVisitorInterface[]
|
||||
*/
|
||||
public function getNodeVisitors(): array
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
return $this->visitors;
|
||||
}
|
||||
|
||||
public function addTokenParser(TokenParserInterface $parser)
|
||||
{
|
||||
if ($this->initialized) {
|
||||
throw new \LogicException('Unable to add a token parser as extensions have already been initialized.');
|
||||
}
|
||||
|
||||
$this->staging->addTokenParser($parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TokenParserInterface[]
|
||||
*/
|
||||
public function getTokenParsers(): array
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
return $this->parsers;
|
||||
}
|
||||
|
||||
public function getGlobals(): array
|
||||
{
|
||||
if (null !== $this->globals) {
|
||||
return $this->globals;
|
||||
}
|
||||
|
||||
$globals = [];
|
||||
foreach ($this->extensions as $extension) {
|
||||
if (!$extension instanceof GlobalsInterface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$extGlobals = $extension->getGlobals();
|
||||
if (!\is_array($extGlobals)) {
|
||||
throw new \UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension)));
|
||||
}
|
||||
|
||||
$globals = array_merge($globals, $extGlobals);
|
||||
}
|
||||
|
||||
if ($this->initialized) {
|
||||
$this->globals = $globals;
|
||||
}
|
||||
|
||||
return $globals;
|
||||
}
|
||||
|
||||
public function addTest(TwigTest $test)
|
||||
{
|
||||
if ($this->initialized) {
|
||||
throw new \LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
|
||||
}
|
||||
|
||||
$this->staging->addTest($test);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TwigTest[]
|
||||
*/
|
||||
public function getTests(): array
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
return $this->tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TwigTest|false
|
||||
*/
|
||||
public function getTest(string $name)
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
if (isset($this->tests[$name])) {
|
||||
return $this->tests[$name];
|
||||
}
|
||||
|
||||
foreach ($this->tests as $pattern => $test) {
|
||||
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
|
||||
|
||||
if ($count) {
|
||||
if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
|
||||
array_shift($matches);
|
||||
$test->setArguments($matches);
|
||||
|
||||
return $test;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUnaryOperators(): array
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
return $this->unaryOperators;
|
||||
}
|
||||
|
||||
public function getBinaryOperators(): array
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initExtensions();
|
||||
}
|
||||
|
||||
return $this->binaryOperators;
|
||||
}
|
||||
|
||||
private function initExtensions()
|
||||
{
|
||||
$this->parsers = [];
|
||||
$this->filters = [];
|
||||
$this->functions = [];
|
||||
$this->tests = [];
|
||||
$this->visitors = [];
|
||||
$this->unaryOperators = [];
|
||||
$this->binaryOperators = [];
|
||||
|
||||
foreach ($this->extensions as $extension) {
|
||||
$this->initExtension($extension);
|
||||
}
|
||||
$this->initExtension($this->staging);
|
||||
// Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception
|
||||
$this->initialized = true;
|
||||
}
|
||||
|
||||
private function initExtension(ExtensionInterface $extension)
|
||||
{
|
||||
// filters
|
||||
foreach ($extension->getFilters() as $filter) {
|
||||
$this->filters[$filter->getName()] = $filter;
|
||||
}
|
||||
|
||||
// functions
|
||||
foreach ($extension->getFunctions() as $function) {
|
||||
$this->functions[$function->getName()] = $function;
|
||||
}
|
||||
|
||||
// tests
|
||||
foreach ($extension->getTests() as $test) {
|
||||
$this->tests[$test->getName()] = $test;
|
||||
}
|
||||
|
||||
// token parsers
|
||||
foreach ($extension->getTokenParsers() as $parser) {
|
||||
if (!$parser instanceof TokenParserInterface) {
|
||||
throw new \LogicException('getTokenParsers() must return an array of \Twig\TokenParser\TokenParserInterface.');
|
||||
}
|
||||
|
||||
$this->parsers[] = $parser;
|
||||
}
|
||||
|
||||
// node visitors
|
||||
foreach ($extension->getNodeVisitors() as $visitor) {
|
||||
$this->visitors[] = $visitor;
|
||||
}
|
||||
|
||||
// operators
|
||||
if ($operators = $extension->getOperators()) {
|
||||
if (!\is_array($operators)) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators).(\is_resource($operators) ? '' : '#'.$operators)));
|
||||
}
|
||||
|
||||
if (2 !== \count($operators)) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators)));
|
||||
}
|
||||
|
||||
$this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
|
||||
$this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class_alias('Twig\ExtensionSet', 'Twig_ExtensionSet');
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user