Compare commits

..

77 Commits

Author SHA1 Message Date
slawkens
a8c65a7ab9 Update show_thread.php 2023-02-07 10:54:58 +01:00
slawkens
b60f345ae5 fix forum show_thread 2023-02-07 10:54:55 +01:00
slawkens
b82c021ff7 $config_account_salt -> USE_ACCOUNT_SALT 2023-02-07 10:48:29 +01:00
slawkens
d0c479d11d feature: plugin require more options with comma 2023-02-07 10:43:08 +01:00
slawkens
577f9b7373 Configurable admin panel folder 2023-02-07 10:13:51 +01:00
slawkens
3700875c47 fix warning in reload cache in dev mode 2023-02-07 10:13:04 +01:00
slawkens
5747fb5723 Fix execute in CLI 2023-02-07 09:45:36 +01:00
Gabriel Pedro
a846d8a7e7 fix: mass teleport position validation (#214)
* fix: mass teleport position validation

* fix: max position
2023-02-06 21:55:29 +01:00
slawkens
3fb30f6391 fix signature on custom basedir 2023-02-06 21:31:47 +01:00
slawkens
91c6ef1ddf remove wrong char 2023-02-06 21:21:04 +01:00
slawkens
098beb9d46 shorten some code + const convert 2023-02-06 20:51:00 +01:00
slawkens
fb17d2e060 feature: router aliases 2023-02-06 20:50:50 +01:00
slawkens
513ca3830b Update example.json 2023-02-06 20:35:59 +01:00
slawkens
17eb5426e3 Move account_types to config, account.web_flags to common.php 2023-02-06 20:27:12 +01:00
slawkens
b918f88776 shorten code + fix conversion (int) 2023-02-06 20:25:22 +01:00
slawkens
4eb9bbbbcf shorten some expressions with ?? 2023-02-06 20:05:01 +01:00
slawkens
56bd2c86b7 add required input to admin pages 2023-02-06 19:40:06 +01:00
slawkens
94719b45b2 fix "Please fill all input" 2023-02-06 19:39:12 +01:00
slawkens
958681bdc9 Add verify to pages, add messages, limits, fix add 2023-02-06 19:36:16 +01:00
slawkens
c1eb7d4f52 fix news adding, rename const to NEWS_* 2023-02-06 19:35:00 +01:00
slawkens
ea09b6a91b fix changelog add 2023-02-06 19:34:26 +01:00
slawkens
58bc0a7c28 new function> escapeHtml + fix css in admin menus 2023-02-06 17:32:48 +01:00
slawkens
35a660be7d fix double ACTION define + undefined URI in template 2023-02-06 16:58:51 +01:00
slawkens
07a03c38b3 fix base dir detection 2023-02-06 16:40:29 +01:00
slawkens
6b54ac65ca Show First, Second instead of numbers 2023-02-05 06:27:10 +01:00
slawkens
070b04afa9 Fix signature 2023-02-05 06:24:28 +01:00
slawkens
039ddc7967 Add list of Open Source Software MyAAC is using 2023-02-04 16:17:28 +01:00
slawkens
9fa65ce7a4 Add password confirm, and change text type to password 2023-02-04 07:50:05 +01:00
slawkens
6aa28a3002 Adjustments & fixed to mass actions 2023-02-03 23:42:52 +01:00
slawkens
938d01eb00 fix duplicated word 2023-02-03 17:16:30 +01:00
slawkens
e0347f252c adjust required version according to composer.json 2023-02-03 16:51:44 +01:00
slawkens
bf3362dc1b remove misleading comment 2023-02-03 16:42:23 +01:00
slawkens
ec38a79235 feature: mail confirmed reward
Suggested by @EPuncker

# Conflicts:
#	system/hooks.php
2023-02-03 16:41:36 +01:00
slawkens
eaec00122b Fix #178 2023-02-03 16:38:00 +01:00
slawkens
7e62bd74a3 Fix admin logout 2023-02-03 13:00:49 +01:00
slawkens
6c5215a8ed block access to some files 2023-02-03 12:52:41 +01:00
slawkens
eb4ea48641 Allow admin pages included into plugins dir 2023-02-03 12:19:35 +01:00
slawkens
a0ccbbe8c2 Remove comments
Not allowed in normal json
2023-02-03 12:19:17 +01:00
slawkens
63d2c5c6b5 Add redirect_from && redirect_to to router options
+ Also add * for all methods shortcut
2023-02-03 12:18:35 +01:00
slawkens
7d38945e8d Add missing var 2023-02-03 12:16:25 +01:00
slawkens
53732005aa This code wasn't used 2023-02-03 12:16:02 +01:00
slawkens
c4a5cae988 Delete accountmanagement.php 2023-02-03 12:15:43 +01:00
slawkens
69a92fb859 fix logout hook 2 2023-02-03 12:15:33 +01:00
slawkens
9fadba7d07 Move mass_* pages to correct folder 2023-02-03 12:14:36 +01:00
slawkens
a080b21408 fix & add admin icons 2023-02-03 12:12:57 +01:00
slawkens
11768424a3 Merge branch 'develop' into feature/new-router
# Conflicts:
#	composer.json
#	system/login.php
2023-02-03 07:31:39 +01:00
slawkens
07887423c6 Merge branch 'develop' into feature/new-router 2022-11-28 21:42:47 +01:00
slawkens
35928fe576 small fixes 2022-11-28 21:37:38 +01:00
slawkens
60f64e21d8 Rewriting the router v2
To be more flexible
2022-11-28 21:37:25 +01:00
slawkens
7bfa21a239 fix parse error 2022-11-28 16:42:23 +01:00
slawkens
8af786902d Add some error box to error 2022-11-28 16:42:01 +01:00
slawkens
ba04536169 $db->select: make $where parameter optional, allows to get all records 2022-11-28 15:53:14 +01:00
slawkens
c646dc124b Move pages tbc 2022-11-28 15:51:41 +01:00
slawkens
2eb9f4d284 Move pages 2022-11-28 13:17:49 +01:00
slawkens
cdc06056c8 Merge branch 'develop' into feature/new-router 2022-11-28 13:14:09 +01:00
slawkens
1be1bc9178 fix premium_ends_at for tfs 1.3+ 2022-11-07 09:11:57 +01:00
slawkens
48d561ac6f Merge branch 'develop' into feature/new-router 2022-10-28 17:33:22 +02:00
slawkens
731755f05a Merge branch 'develop' into feature/new-router 2022-09-27 13:02:47 +02:00
slawkens
de3eaacf60 Merge branch 'develop' into feature/new-router 2022-03-16 17:24:22 +01:00
slawkens
bb699ffef2 nothing important, just early exit & fixes
Fix creature display
2022-03-16 17:19:17 +01:00
slawkens
34fa672c0f Merge branch 'develop' into feature/new-router 2022-03-16 13:48:12 +01:00
slawkens
f74c1ac247 Merge branch 'feature/new-router' of https://github.com/otsoft/myaac into feature/new-router 2021-12-25 13:29:41 +01:00
slawkens
0af595a5a6 Update package-lock.json 2021-12-11 06:23:05 +01:00
slawkens
10eb9e7ff0 Don't hide "Install Plugin" Box by default 2021-12-11 06:22:03 +01:00
slawkens
1d163279ce Add PLUGINS to Twig path 2021-12-11 06:20:55 +01:00
slawkens
8cac9af966 Fix path - should not be absolute 2021-12-07 10:51:41 +01:00
slawkens
7008c9f4d8 Optimisations & fixes. 2021-12-05 10:33:31 +01:00
slawkens
468f59fbec Merge branch 'develop' into feature/new-router 2021-12-05 06:11:00 +01:00
slawkens
bebe6892d0 Merge branch 'develop' into feature/new-router 2021-08-30 16:17:56 +02:00
slawkens
a8e65b72a4 Merge branch 'develop' into feature/new-router 2021-06-08 23:41:29 +02:00
slawkens
e52a301d9e [WIP] nikic/fast-route implementation
I will describe it more in Pull Request
2021-06-08 19:17:38 +02:00
slawkens
cf04c1df02 Small improvement to plugins.enabled check 2021-06-08 18:37:00 +02:00
slawkens
98f6b03747 Fix forum table style (boards & thread view) 2021-06-08 18:14:02 +02:00
slawkens
9d5665a476 Fix create character when admin (any case is allowed now) 2021-06-08 12:49:31 +02:00
slawkens
3eb5810526 small adjustment in news.php 2021-06-08 11:49:17 +02:00
slawkens
26d0c2a359 Fix guild back buttons (change logo & motd) 2021-06-08 11:26:06 +02:00
slawkens
073cf80812 Remove unneeded escape 2021-06-08 11:25:11 +02:00
258 changed files with 3086 additions and 7653 deletions

6
.gitattributes vendored
View File

@@ -3,12 +3,8 @@
.gitignore export-ignore
.github export-ignore
.editorconfig export-ignore
.travis.yml export-ignore
_config.yml export-ignore
release.sh export-ignore
# cypress
cypress export-ignore
cypress.config.js export-ignore
cypress.env.json
*.sh text eol=lf

View File

@@ -1,120 +0,0 @@
name: Cypress
on:
pull_request:
branches: [develop]
push:
branches: [develop]
jobs:
cypress:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: myaac
MYSQL_USER: myaac
MYSQL_PASSWORD: myaac
ports:
- 3306/tcp
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
fail-fast: false
matrix:
php-versions: [ '7.4', '8.0', '8.1' ]
name: MyAAC on PHP ${{ matrix.php-versions }}
steps:
- name: 📌 MySQL Start & init & show db
run: |
sudo /etc/init.d/mysql start
mysql -e 'CREATE DATABASE myaac;' -uroot -proot
mysql -e "SHOW DATABASES" -uroot -proot
- name: Checkout MyAAC
uses: actions/checkout@v3
with:
ref: 0.9
- name: Checkout TFS
uses: actions/checkout@v3
with:
repository: otland/forgottenserver
ref: 1.4
path: tfs
- name: Import TFS Schema
run: |
mysql -uroot -proot myaac < tfs/schema.sql
- name: Rename config.lua
run: mv tfs/config.lua.dist tfs/config.lua
- name: Replace mysqlUser
uses: jacobtomlinson/gha-find-replace@v2
with:
find: 'mysqlUser = "forgottenserver"'
replace: 'mysqlUser = "root"'
regex: false
include: 'tfs/config.lua'
- name: Replace mysqlPass
uses: jacobtomlinson/gha-find-replace@v2
with:
find: 'mysqlPass = ""'
replace: 'mysqlPass = "root"'
regex: false
include: 'tfs/config.lua'
- name: Replace mysqlDatabase
uses: jacobtomlinson/gha-find-replace@v2
with:
find: 'mysqlDatabase = "forgottenserver"'
replace: 'mysqlDatabase = "myaac"'
regex: false
include: 'tfs/config.lua'
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, dom, fileinfo, mysql, json, xml, pdo, pdo_mysql
- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache composer dependencies
uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
# Use composer.json for key, if composer.lock is not committed.
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: Run PHP server
run: nohup php -S localhost:8080 > php.log 2>&1 &
- name: Cypress Run
uses: cypress-io/github-action@v5
env:
CYPRESS_URL: http://localhost:8080
CYPRESS_SERVER_PATH: /home/runner/work/myaac/myaac/tfs
- name: Save screenshots
uses: actions/upload-artifact@v3
if: always()
with:
name: cypress-screenshots
path: cypress/screenshots
- name: Upload Cypress Videos
uses: actions/upload-artifact@v3
if: always()
with:
name: cypress-videos
path: cypress/videos

View File

@@ -1,16 +1,13 @@
name: PHP Linting
on:
pull_request:
branches: [develop]
branches: [master, develop]
push:
branches: [develop]
branches: [master]
jobs:
phplint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: overtrue/phplint@8.2
with:
path: .
options: --exclude=*.log
- uses: actions/checkout@v1
- uses: michaelw90/PHP-Lint@master

7
.gitignore vendored
View File

@@ -2,9 +2,6 @@ Thumbs.db
.DS_Store
.idea
#
/.htaccess
# composer
composer.lock
vendor
@@ -12,10 +9,6 @@ vendor
# npm
node_modules
# cypress
cypress.env.json
cypress/e2e/2-advanced-examples
# created by release.sh
releases
tmp

View File

@@ -6,14 +6,10 @@
Options -MultiViews
</IfModule>
<FilesMatch "^(CHANGELOG\.md|README\.md|composer\.json|composer\.lock|package\.json|package-lock\.json|cypress\.env\.json)$">
Require all denied
</FilesMatch>
<IfModule mod_rewrite.c>
RewriteEngine On
#RewriteBase /myaac/
#RewriteBase /myaac/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

18
.travis.yml Normal file
View File

@@ -0,0 +1,18 @@
language: php
php:
- 7.1
- 7.2
- 7.3
- 7.4
- 8.0
cache:
directories:
- $HOME/.composer/cache
before_script:
- composer require php-parallel-lint/php-parallel-lint --no-suggest --no-progress --no-interaction --no-ansi --quiet --optimize-autoloader
script:
- php vendor/bin/parallel-lint --no-progress --no-colors --exclude vendor --exclude "system/libs/pot/OTS_DB_PDOQuery.php" .

View File

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

View File

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

View File

@@ -36,7 +36,7 @@ Official website: https://my-aac.org
chmod 660 images/guilds
chmod 660 images/houses
chmod 660 images/gallery
chmod -R 760 system/cache
chmod -R 770 system/cache
Visit http://your_domain/install (http://localhost/install) and follow instructions in the browser.

View File

@@ -1,2 +1 @@
<?php
// nothing yet here
<?php

View File

@@ -1,35 +0,0 @@
<?php
$order = 10;
$settingsMenu = [];
$settingsMenu[] = [
'name' => 'MyAAC',
'link' => 'settings&plugin=core',
'icon' => 'list',
'order' => $order,
];
foreach (Plugins::getAllPluginsSettings() as $setting) {
$file = BASE . $setting['settingsFilename'];
if (!file_exists($file)) {
warning('Plugin setting: ' . $file . ' - cannot be loaded.');
continue;
}
$order += 10;
$settings = require $file;
$settingsMenu[] = [
'name' => $settings['name'],
'link' => 'settings&plugin=' . $setting['pluginFilename'],
'icon' => 'list',
'order' => $order,
];
}
unset($settings, $file, $order);
return $settingsMenu;

View File

@@ -6,6 +6,10 @@ require '../common.php';
const ADMIN_PANEL = true;
const MYAAC_ADMIN = true;
if(file_exists(BASE . 'config.local.php')) {
require_once BASE . 'config.local.php';
}
if(file_exists(BASE . 'install') && (!isset($config['installed']) || !$config['installed']))
{
header('Location: ' . BASE_URL . 'install/');
@@ -25,9 +29,10 @@ define('PAGE', $page);
require SYSTEM . 'functions.php';
require SYSTEM . 'init.php';
// verify myaac tables exists in database
if(!$db->hasTable('myaac_account_actions')) {
throw new RuntimeException('Seems that the table <strong>myaac_account_actions</strong> of MyAAC doesn\'t exist in the database. This is a fatal error. You can try to reinstall MyAAC by visiting <a href="' . BASE_URL . 'install">this</a> url.');
if(config('env') === 'dev') {
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
}
// event system
@@ -37,6 +42,7 @@ $hooks->load();
require SYSTEM . 'status.php';
require SYSTEM . 'login.php';
require SYSTEM . 'migrate.php';
require __DIR__ . '/includes/functions.php';
$twig->addGlobal('config', $config);
@@ -64,9 +70,7 @@ if(!@file_exists($file)) {
}
ob_start();
if($hooks->trigger(HOOK_ADMIN_BEFORE_PAGE)) {
require $file;
}
include($file);
$content .= ob_get_contents();
ob_end_clean();

View File

@@ -10,17 +10,12 @@
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Account editor';
$admin_base = ADMIN_URL . '?p=accounts';
$admin_base = BASE_URL . 'admin/?p=accounts';
$use_datatable = true;
if ($config['account_country'])
require SYSTEM . 'countries.conf.php';
$nameOrNumberColumn = 'name';
if (USE_ACCOUNT_NUMBER) {
$nameOrNumberColumn = 'number';
}
$hasSecretColumn = $db->hasColumn('accounts', 'secret');
$hasCoinsColumn = $db->hasColumn('accounts', 'coins');
$hasPointsColumn = $db->hasColumn('accounts', 'premium_points');
@@ -37,7 +32,7 @@ if ($config['account_country']) {
$countries[$code] = $c;
}
$web_acc = ACCOUNT_WEB_FLAGS;
$acc_type = setting('core.account_types');
$acc_type = config('account_types');
?>
<link rel="stylesheet" type="text/css" href="<?php echo BASE_URL; ?>tools/css/jquery.datetimepicker.css"/ >
@@ -53,16 +48,16 @@ else if (isset($_REQUEST['search'])) {
if (strlen($search_account) < 3 && !Validator::number($search_account)) {
echo_error('Player name is too short.');
} else {
$query = $db->query('SELECT `id` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` = ' . $db->quote($search_account));
$query = $db->query('SELECT `id` FROM `accounts` WHERE `name` = ' . $db->quote($search_account));
if ($query->rowCount() == 1) {
$query = $query->fetch();
$id = (int)$query['id'];
} else {
$query = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` LIKE ' . $db->quote('%' . $search_account . '%'));
$query = $db->query('SELECT `id`, `name` FROM `accounts` WHERE `name` LIKE ' . $db->quote('%' . $search_account . '%'));
if ($query->rowCount() > 0 && $query->rowCount() <= 10) {
$str_construct = 'Do you mean?<ul class="mb-0">';
foreach ($query as $row)
$str_construct .= '<li><a href="' . $admin_base . '&id=' . $row['id'] . '">' . $row[$nameOrNumberColumn] . '</a></li>';
$str_construct .= '<li><a href="' . $admin_base . '&id=' . $row['id'] . '">' . $row['name'] . '</a></li>';
$str_construct .= '</ul>';
echo_error($str_construct);
} else if ($query->rowCount() > 10)
@@ -150,7 +145,7 @@ else if (isset($_REQUEST['search'])) {
$web_lastlogin = strtotime($_POST['web_lastlogin']);
verify_number($web_lastlogin, 'Web Last login', 11);
if (!$error && $hooks->trigger(HOOK_ADMIN_ACCOUNTS_SAVE_POST, ['account_id' => $account->getId(), 'account_email' => $account->getEMail()])) {
if (!$error) {
if (USE_ACCOUNT_NAME) {
$account->setName($name);
}
@@ -208,7 +203,7 @@ else if (isset($_REQUEST['search'])) {
}
}
} else if ($id == 0) {
$accounts_db = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '`' . ($hasTypeColumn ? ',type' : ($hasGroupColumn ? ',group_id' : '')) . ' FROM `accounts` ORDER BY `id` ASC');
$accounts_db = $db->query('SELECT `id`, `name`' . ($hasTypeColumn ? ',type' : ($hasGroupColumn ? ',group_id' : '')) . ' FROM `accounts` ORDER BY `id` ASC');
?>
<div class="col-12 col-sm-12 col-lg-10">
<div class="card card-info card-outline">
@@ -220,7 +215,7 @@ else if (isset($_REQUEST['search'])) {
<thead>
<tr>
<th>ID</th>
<th><?= ($nameOrNumberColumn == 'number' ? 'Number' : 'Name'); ?></th>
<th>Name</th>
<?php if($hasTypeColumn || $hasGroupColumn): ?>
<th>Position</th>
<?php endif; ?>
@@ -231,7 +226,7 @@ else if (isset($_REQUEST['search'])) {
<?php foreach ($accounts_db as $account_lst): ?>
<tr>
<th><?php echo $account_lst['id']; ?></th>
<td><?php echo $account_lst[$nameOrNumberColumn]; ?></a></td>
<td><?php echo $account_lst['name']; ?></a></td>
<?php if($hasTypeColumn || $hasGroupColumn): ?>
<td>
<?php if ($hasTypeColumn) {
@@ -289,11 +284,6 @@ else if (isset($_REQUEST['search'])) {
<label for="name">Account Name:</label>
<input type="text" class="form-control" id="name" name="name" autocomplete="off" value="<?php echo $account->getName(); ?>"/>
</div>
<?php elseif (USE_ACCOUNT_NUMBER): ?>
<div class="col-12 col-sm-12 col-lg-4">
<label for="name">Account Number:</label>
<input type="text" class="form-control" id="name" name="name" autocomplete="off" value="<?php echo $account->getNumber(); ?>"/>
</div>
<?php endif; ?>
<div class="col-12 col-sm-12 col-lg-5">
<div class="form-check">
@@ -361,7 +351,7 @@ else if (isset($_REQUEST['search'])) {
</div>
<div class="form-group row">
<div class="col-12 col-sm-12 col-lg-6">
<label for="email">Email:</label><?php echo (setting('core.mail_enabled') ? ' (<a href="' . ADMIN_URL . '?p=mailer&mail_to=' . $account->getEMail() . '">Send Mail</a>)' : ''); ?>
<label for="email">Email:</label><?php echo (config('mail_enabled') ? ' (<a href="' . ADMIN_URL . '?p=mailer&mail_to=' . $account->getEMail() . '">Send Mail</a>)' : ''); ?>
<input type="text" class="form-control" id="email" name="email" autocomplete="off" value="<?php echo $account->getEMail(); ?>"/>
</div>
<?php if ($hasCoinsColumn): ?>

View File

@@ -47,11 +47,12 @@ $tmp = '';
if (fetchDatabaseConfig('site_closed_message', $tmp))
$closed_message = $tmp;
$settingAdminPanelModules = setting('core.admin_panel_modules');
if (count($settingAdminPanelModules) > 0) {
$configAdminPanelModules = config('admin_panel_modules');
if (isset($configAdminPanelModules)) {
echo '<div class="row">';
$configAdminPanelModules = explode(',', $configAdminPanelModules);
$twig_loader->prependPath(__DIR__ . '/modules/templates');
foreach ($settingAdminPanelModules as $box) {
foreach ($configAdminPanelModules as $box) {
$file = __DIR__ . '/modules/' . $box . '.php';
if (file_exists($file)) {
include($file);

View File

@@ -10,12 +10,6 @@
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Login';
require PAGES . 'account/login.php';
if ($logged) {
header('Location: ' . (admin() ? ADMIN_URL : BASE_URL));
return;
}
$twig->display('admin.login.html.twig', [
'logout' => (ACTION == 'logout' ? 'You have been logged out!' : ''),
'account' => USE_ACCOUNT_NAME ? 'Name' : 'Number',

View File

@@ -15,8 +15,8 @@ if (!hasFlag(FLAG_CONTENT_MAILER) && !superAdmin()) {
return;
}
if (!setting('core.mail_enabled')) {
echo 'Mail support disabled in config.';
if (!config('mail_enabled')) {
echo 'Mail support disabled.';
return;
}

View File

@@ -46,7 +46,6 @@ if (isset($_REQUEST['template'])) {
if ($cache->enabled()) {
$cache->delete('template_menus');
}
success('Saved at ' . date('H:i'));
}
@@ -57,7 +56,6 @@ if (isset($_REQUEST['template'])) {
echo 'Cannot find template config.php file.';
return;
}
if (!isset($config['menu_categories'])) {
echo "No menu categories set in template config.php.<br/>This template doesn't support dynamic menus.";
return;
@@ -93,16 +91,15 @@ if (isset($_REQUEST['template'])) {
<ul class="sortable" id="sortable-<?php echo $id ?>">
<?php
if (isset($menus[$id])) {
$i = 0;
foreach ($menus[$id] as $menu):
foreach ($menus[$id] as $i => $menu):
?>
<li class="ui-state-default" id="list-<?php echo $id ?>-<?php echo $i ?>"><label>Name:</label> <input type="text" name="menu[<?php echo $id ?>][]" value="<?php echo escapeHtml($menu['name']); ?>"/>
<label>Link:</label> <input type="text" name="menu_link[<?php echo $id ?>][]" value="<?php echo $menu['link'] ?>"/>
<input type="hidden" name="menu_blank[<?php echo $id ?>][]" value="0"/>
<label><input class="blank-checkbox" type="checkbox" <?php echo($menu['blank'] == 1 ? 'checked' : '') ?>/><span title="Open in New Window">New Window</span></label>
<input class="color-picker" type="text" name="menu_color[<?php echo $id ?>][]" value="<?php echo (empty($menu['color']) ? ($config['menu_default_color'] ?? '#ffffff') : $menu['color']); ?>"/>
<input class="color-picker" type="text" name="menu_color[<?php echo $id ?>][]" value="#<?php echo $menu['color'] ?>"/>
<a class="remove-button" id="remove-button-<?php echo $id ?>-<?php echo $i ?>"><i class="fas fa-trash"></a></i></li>
<?php $i++; $last_id[$id] = $i;
<?php $last_id[$id] = $i;
endforeach;
} ?>
</ul>
@@ -123,8 +120,7 @@ if (isset($_REQUEST['template'])) {
<?php
$twig->display('admin.menus.js.html.twig', array(
'menus' => $menus,
'last_id' => $last_id,
'menu_default_color' => $config['menu_default_color'] ?? '#ffffff'
'last_id' => $last_id
));
?>
<?php

View File

@@ -1,6 +1,4 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
$balance = ($db->hasColumn('players', 'balance') ? $db->query('SELECT `balance`, `id`, `name`,`level` FROM `players` ORDER BY `balance` DESC LIMIT 10;') : 0);
$twig->display('balance.html.twig', array(

View File

@@ -1,6 +1,4 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
$coins = ($db->hasColumn('accounts', 'coins') ? $db->query('SELECT `coins`, `' . (USE_ACCOUNT_NAME ? 'name' : 'id') . '` as `name` FROM `accounts` ORDER BY `coins` DESC LIMIT 10;') : 0);
$twig->display('coins.html.twig', array(

View File

@@ -1,6 +1,4 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
$players = ($db->hasColumn('accounts', 'created') ? $db->query('SELECT `created`, `' . (USE_ACCOUNT_NAME ? 'name' : 'id') . '` as `name` FROM `accounts` ORDER BY `created` DESC LIMIT 10;') : 0);
$twig->display('created.html.twig', array(

View File

@@ -1,6 +1,4 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
$players = ($db->hasColumn('players', 'lastlogin') ? $db->query('SELECT name, level, lastlogin FROM players ORDER BY lastlogin DESC LIMIT 10;') : 0);
$twig->display('lastlogin.html.twig', array(
'players' => $players,

View File

@@ -1,6 +1,4 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
$points = ($db->hasColumn('accounts', 'premium_points') ? $db->query('SELECT `premium_points`, `' . (USE_ACCOUNT_NAME ? 'name' : 'id') . '` as `name` FROM `accounts` ORDER BY `premium_points` DESC LIMIT 10;') : 0);
$twig->display('points.html.twig', array(

View File

@@ -76,18 +76,18 @@ if (!empty($action)) {
$enable_tinymce = $_page['enable_tinymce'] == '1';
$access = $_page['access'];
} else {
if(Pages::update($id, $name, $p_title, $body, $player_id, $php, $enable_tinymce, $access, $errors)) {
if(Pages::update($id, $name, $p_title, $body, $player_id, $php, $enable_tinymce, $access)) {
$action = $name = $p_title = $body = '';
$player_id = 1;
$access = 0;
$php = false;
$enable_tinymce = true;
success('Updated successful.');
success("Updated successful.");
}
}
} else if ($action == 'hide') {
Pages::toggleHidden($id, $errors, $status);
success(($status == 1 ? 'Show' : 'Hide') . ' successful.');
success(($status == 1 ? 'Show' : 'Hide') . " successful.");
}
if (!empty($errors))
@@ -152,10 +152,6 @@ class Pages
$errors[] = 'Enable PHP is wrong.';
return false;
}
if ($php == 1 && !getBoolean(setting('core.admin_pages_php_enable'))) {
$errors[] = 'PHP pages disabled on this server. To enable go to Settings in Admin Panel and enable <strong>Enable PHP Pages</strong>.';
return false;
}
if(!isset($enable_tinymce) || ($enable_tinymce != 0 && $enable_tinymce != 1)) {
$errors[] = 'Enable TinyMCE is wrong.';
return false;
@@ -204,7 +200,7 @@ class Pages
return !count($errors);
}
static public function update($id, $name, $title, $body, $player_id, $php, $enable_tinymce, $access, &$errors)
static public function update($id, $name, $title, $body, $player_id, $php, $enable_tinymce, $access)
{
if(!self::verify($name, $title, $body, $player_id, $php, $enable_tinymce, $access, $errors)) {
return false;
@@ -258,3 +254,5 @@ class Pages
return !count($errors);
}
}
?>

View File

@@ -16,4 +16,4 @@ if (!function_exists('phpinfo')) { ?>
<?php return;
}
?>
<iframe src="<?php echo ADMIN_URL; ?>tools/phpinfo.php" width="1024" height="550"></iframe>
<iframe src="<?php echo BASE_URL; ?>admin/tools/phpinfo.php" width="1024" height="550"></iframe>

View File

@@ -10,7 +10,7 @@
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Player editor';
$player_base = ADMIN_URL . '?p=players';
$player_base = BASE_URL . 'admin/?p=players';
$use_datatable = true;
require_once LIBS . 'forum.php';
@@ -663,14 +663,7 @@ else if (isset($_REQUEST['search'])) {
</div>
<div class="col-12 col-sm-12 col-lg-6">
<label for="lastip" class="control-label">Last IP:</label>
<input type="text" class="form-control" id="lastip" name="lastip" autocomplete="off" maxlength="10" value="<?php
if (strlen($player->getLastIP()) > 11) {
echo inet_ntop($player->getLastIP());
}
else {
echo longToIp($player->getLastIP());
}
?>" readonly/>
<input type="text" class="form-control" id="lastip" name="lastip" autocomplete="off" maxlength="10" value="<?php echo longToIp($player->getLastIP()); ?>" readonly/>
</div>
</div>
<?php if ($db->hasColumn('players', 'loss_experience')): ?>

View File

@@ -13,119 +13,98 @@ $use_datatable = true;
require_once LIBS . 'plugins.php';
if (!getBoolean(setting('core.admin_plugins_manage_enable'))) {
warning('Plugin installation and management is disabled in Settings.<br/>If you wish to enable, go to Settings and enable <strong>Enable Plugins Manage</strong>.');
}
else {
$twig->display('admin.plugins.form.html.twig');
$twig->display('admin.plugins.form.html.twig');
if (isset($_REQUEST['uninstall'])) {
$uninstall = $_REQUEST['uninstall'];
if (isset($_REQUEST['uninstall'])) {
$uninstall = $_REQUEST['uninstall'];
if (Plugins::uninstall($uninstall)) {
success('Successfully uninstalled plugin ' . $uninstall);
} else {
error('Error while uninstalling plugin ' . $uninstall . ': ' . Plugins::getError());
if (Plugins::uninstall($uninstall)) {
success('Successfully uninstalled plugin ' . $uninstall);
} else {
error('Error while uninstalling plugin ' . $uninstall . ': ' . Plugins::getError());
}
} else if (isset($_FILES["plugin"]["name"])) {
$file = $_FILES["plugin"];
$filename = $file["name"];
$tmp_name = $file["tmp_name"];
$type = $file["type"];
$name = explode(".", $filename);
$accepted_types = array('application/zip', 'application/x-zip-compressed', 'multipart/x-zip', 'application/x-compressed', 'application/octet-stream', 'application/zip-compressed');
if (isset($file['error'])) {
$error = 'Error uploading file';
switch ($file['error']) {
case UPLOAD_ERR_OK:
$error = false;
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
$error .= ' - file too large (limit of ' . ini_get('upload_max_filesize') . ' bytes). You can enlarge the limits by changing "upload_max_filesize" in php.ini';
break;
case UPLOAD_ERR_PARTIAL:
$error .= ' - file upload was not completed.';
break;
case UPLOAD_ERR_NO_FILE:
$error .= ' - zero-length file uploaded.';
break;
default:
$error .= ' - internal error #' . $file['error'];
break;
}
} else if (isset($_REQUEST['enable'])) {
$enable = $_REQUEST['enable'];
if (Plugins::enable($enable)) {
success('Successfully enabled plugin ' . $enable);
} else {
error('Error while enabling plugin ' . $enable . ': ' . Plugins::getError());
}
} else if (isset($_REQUEST['disable'])) {
$disable = $_REQUEST['disable'];
if (Plugins::disable($disable)) {
success('Successfully disabled plugin ' . $disable);
} else {
error('Error while disabling plugin ' . $disable . ': ' . Plugins::getError());
}
} else if (isset($_FILES['plugin']['name'])) {
$file = $_FILES['plugin'];
$filename = $file['name'];
$tmp_name = $file['tmp_name'];
$type = $file['type'];
}
$name = explode('.', $filename);
$accepted_types = array('application/zip', 'application/x-zip-compressed', 'multipart/x-zip', 'application/x-compressed', 'application/octet-stream', 'application/zip-compressed');
if (isset($error) && $error != false) {
error($error);
} else {
if (is_uploaded_file($file['tmp_name'])) {
$filetype = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if ($filetype == 'zip') // check if it is zipped/compressed file
{
$tmp_filename = pathinfo($filename, PATHINFO_FILENAME);
$targetzip = BASE . 'plugins/' . $tmp_filename . '.zip';
if (isset($file['error'])) {
$error = 'Error uploading file';
switch ($file['error']) {
case UPLOAD_ERR_OK:
$error = false;
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
$error .= ' - file too large (limit of ' . ini_get('upload_max_filesize') . ' bytes). You can enlarge the limits by changing "upload_max_filesize" in php.ini';
break;
case UPLOAD_ERR_PARTIAL:
$error .= ' - file upload was not completed.';
break;
case UPLOAD_ERR_NO_FILE:
$error .= ' - zero-length file uploaded.';
break;
default:
$error .= ' - internal error #' . $file['error'];
break;
}
}
if (isset($error) && $error != false) {
error($error);
} else {
if (is_uploaded_file($file['tmp_name'])) {
$filetype = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if ($filetype == 'zip') // check if it is zipped/compressed file
{
$tmp_filename = pathinfo($filename, PATHINFO_FILENAME);
$targetzip = BASE . 'plugins/' . $tmp_filename . '.zip';
if (move_uploaded_file($tmp_name, $targetzip)) { // move uploaded file
if (Plugins::install($targetzip)) {
foreach (Plugins::getWarnings() as $warning) {
warning($warning);
}
$info = Plugins::getPluginJson();
success((isset($info['name']) ? '<strong>' . $info['name'] . '</strong> p' : 'P') . 'lugin has been successfully installed.');
} else {
$error = Plugins::getError();
error(!empty($error) ? $error : 'Unexpected error happened while installing plugin. Please try again later.');
if (move_uploaded_file($tmp_name, $targetzip)) { // move uploaded file
if (Plugins::install($targetzip)) {
foreach (Plugins::getWarnings() as $warning) {
warning($warning);
}
unlink($targetzip); // delete the Zipped file
} else
error('There was a problem with the upload. Please try again.');
} else {
error('The file you are trying to upload is not a .zip file. Please try again.');
}
$info = Plugins::getPluginJson();
success((isset($info['name']) ? '<strong>' . $info['name'] . '</strong> p' : 'P') . 'lugin has been successfully installed.');
} else {
$error = Plugins::getError();
error(!empty($error) ? $error : 'Unexpected error happened while installing plugin. Please try again later.');
}
unlink($targetzip); // delete the Zipped file
} else
error('There was a problem with the upload. Please try again.');
} else {
error('Error uploading file - unknown error.');
error('The file you are trying to upload is not a .zip file. Please try again.');
}
} else {
error('Error uploading file - unknown error.');
}
}
}
$plugins = array();
foreach (get_plugins(true) as $plugin) {
foreach (get_plugins() as $plugin) {
$string = file_get_contents(BASE . 'plugins/' . $plugin . '.json');
$string = Plugins::removeComments($string);
$plugin_info = json_decode($string, true);
if (!$plugin_info) {
if ($plugin_info == false) {
warning('Cannot load plugin info ' . $plugin . '.json');
} else {
$disabled = (strpos($plugin, 'disabled.') !== false);
$pluginOriginal = ($disabled ? str_replace('disabled.', '', $plugin) : $plugin);
$plugins[] = array(
'name' => $plugin_info['name'] ?? '',
'description' => $plugin_info['description'] ?? '',
'version' => $plugin_info['version'] ?? '',
'author' => $plugin_info['author'] ?? '',
'contact' => $plugin_info['contact'] ?? '',
'file' => $pluginOriginal,
'enabled' => !$disabled,
'name' => isset($plugin_info['name']) ? $plugin_info['name'] : '',
'description' => isset($plugin_info['description']) ? $plugin_info['description'] : '',
'version' => isset($plugin_info['version']) ? $plugin_info['version'] : '',
'author' => isset($plugin_info['author']) ? $plugin_info['author'] : '',
'contact' => isset($plugin_info['contact']) ? $plugin_info['contact'] : '',
'file' => $plugin,
'uninstall' => isset($plugin_info['uninstall'])
);
}

View File

@@ -1,56 +0,0 @@
<?php
/**
* Menus
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Settings';
require_once SYSTEM . 'clients.conf.php';
if (empty($_GET['plugin'])) {
error('Please select plugin from left Panel.');
return;
}
$plugin = $_GET['plugin'];
if($plugin != 'core') {
$pluginSettings = Plugins::getPluginSettings($plugin);
if (!$pluginSettings) {
error('This plugin does not exist or does not have settings defined.');
return;
}
$settingsFilePath = BASE . $pluginSettings;
}
else {
$settingsFilePath = SYSTEM . 'settings.php';
}
if (!file_exists($settingsFilePath)) {
error("Plugin $plugin does not exist or does not have settings defined.");
return;
}
$settingsFile = require $settingsFilePath;
if (!is_array($settingsFile)) {
error("Cannot load settings file for plugin $plugin");
return;
}
$settingsKeyName = ($plugin == 'core' ? $plugin : $settingsFile['key']);
$title = ($plugin == 'core' ? 'Settings' : 'Plugin Settings - ' . $plugin);
$settingsParsed = Settings::display($settingsKeyName, $settingsFile['settings']);
$twig->display('admin.settings.html.twig', [
'settingsParsed' => $settingsParsed['content'],
'settings' => $settingsFile['settings'],
'script' => $settingsParsed['script'],
'settingsKeyName' => $settingsKeyName,
]);

View File

@@ -36,3 +36,4 @@ $twig->display('admin.statistics.html.twig', array(
'account_type' => (USE_ACCOUNT_NAME ? 'name' : 'number'),
'points' => $points
));
?>

View File

@@ -47,3 +47,4 @@ function version_revert($version)
$release = $version;
return $major . '.' . $minor . '.' . $release;
}*/
?>

View File

@@ -8,15 +8,10 @@
* @link https://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
use DeviceDetector\DeviceDetector;
use DeviceDetector\Parser\Client\Browser;
use DeviceDetector\Parser\OperatingSystem;
$title = 'Visitors';
$use_datatable = true;
if (!setting('core.visitors_counter')): ?>
if (!$config['visitors_counter']): ?>
Visitors counter is disabled.<br/>
You can enable it by editing this configurable in <b>config.local.php</b> file:<br/>
<p style="margin-left: 3em;"><b>$config['visitors_counter'] = true;</b></p>
@@ -25,42 +20,18 @@ if (!setting('core.visitors_counter')): ?>
endif;
require SYSTEM . 'libs/visitors.php';
$visitors = new Visitors(setting('core.visitors_counter_ttl'));
$visitors = new Visitors($config['visitors_counter_ttl']);
function compare($a, $b): int {
function compare($a, $b)
{
return $a['lastvisit'] > $b['lastvisit'] ? -1 : 1;
}
$tmp = $visitors->getVisitors();
usort($tmp, 'compare');
foreach ($tmp as &$visitor) {
$userAgent = $visitor['user_agent'] ?? '';
if (!strlen($userAgent) || $userAgent == 'unknown') {
$browser = 'Unknown';
}
else {
$dd = new DeviceDetector($userAgent);
$dd->parse();
if ($dd->isBot()) {
$bot = $dd->getBot();
$message = '(Bot) %s, <a href="%s" target="_blank">%s</a>';
$browser = sprintf($message, $bot['category'], $bot['url'], $bot['name']);
}
else {
$osFamily = OperatingSystem::getOsFamily($dd->getOs('name'));
$browserFamily = Browser::getBrowserFamily($dd->getClient('name'));
$browser = $osFamily . ', ' . $browserFamily;
}
}
$visitor['browser'] = $browser;
}
$twig->display('admin.visitors.html.twig', array(
'config_visitors_counter_ttl' => setting('core.visitors_counter_ttl'),
'config_visitors_counter_ttl' => $config['visitors_counter_ttl'],
'visitors' => $tmp
));
?>

View File

@@ -1,11 +1,8 @@
<?php
return [
$menus = [
['name' => 'Dashboard', 'icon' => 'tachometer-alt', 'order' => 10, 'link' => 'dashboard'],
['name' => 'Settings', 'icon' => 'edit', 'order' => 19, 'link' =>
require ADMIN . 'includes/settings_menus.php'
],
['name' => 'News', 'icon' => 'newspaper', 'order' => 20, 'link' =>
['name' => 'News', 'icon' => 'newspaper', 'order' => 20, 'link' =>
[
['name' => 'View', 'link' => 'news', 'icon' => 'list', 'order' => 10],
['name' => 'Add news', 'link' => 'news&action=new&type=1', 'icon' => 'plus', 'order' => 20],
@@ -19,7 +16,7 @@ return [
['name' => 'Add', 'link' => 'changelog&action=new', 'icon' => 'plus', 'order' => 20],
],
],
['name' => 'Mailer', 'icon' => 'envelope', 'order' => 40, 'link' => 'mailer', 'disabled' => !setting('core.mail_enabled')],
['name' => 'Mailer', 'icon' => 'envelope', 'order' => 40, 'link' => 'mailer', 'disabled' => !config('mail_enabled')],
['name' => 'Pages', 'icon' => 'book', 'order' => 50, 'link' =>
[
['name' => 'View', 'link' => 'pages', 'icon' => 'list', 'order' => 10],

View File

@@ -2,7 +2,6 @@
<!doctype html>
<html lang="en">
<head>
<?php $hooks->trigger(HOOK_ADMIN_HEAD_START); ?>
<?php echo template_header(true); ?>
<title><?php echo (isset($title) ? $title . ' - ' : '') . $config['lua']['serverName'];?></title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
@@ -17,10 +16,8 @@
<script src="<?php echo BASE_URL; ?>tools/js/respond.min.js"></script>
<![endif]-->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
<?php $hooks->trigger(HOOK_ADMIN_HEAD_END); ?>
</head>
<body class="sidebar-mini ">
<?php $hooks->trigger(HOOK_ADMIN_BODY_START); ?>
<?php if ($logged && admin()) { ?>
<div class="wrapper">
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
@@ -68,7 +65,7 @@
if (!$has_child) { ?>
<li class="nav-item">
<a class="nav-link<?php echo(strpos($menu['link'], $page) !== false ? ' active' : '') ?>" href="?p=<?php echo $menu['link'] ?>">
<i class="nav-icon fas fa-<?php echo($menu['icon'] ?? 'link') ?>"></i>
<i class="nav-icon fas fa-<?php echo(isset($menu['icon']) ? $menu['icon'] : 'link') ?>"></i>
<p><?php echo $menu['name'] ?></p>
</a>
</li>
@@ -76,9 +73,9 @@
} else if ($has_child) {
$used_menu = null;
$nav_construct = '';
foreach ($menu['link'] as $sub_category => $sub_menu) {
foreach ($menu['link'] as $category => $sub_menu) {
$nav_construct .= '<li class="nav-item"><a href="?p=' . $sub_menu['link'] . '" class="nav-link';
if ($_SERVER['QUERY_STRING'] == 'p=' . $sub_menu['link']) {
if ($page == $sub_menu['link']) {
$nav_construct .= ' active';
$used_menu = true;
}
@@ -198,6 +195,5 @@ if ($logged && admin()) {
<script src="<?php echo BASE_URL; ?>tools/js/datatables.bs.min.js"></script>
<?php } ?>
<script src="<?php echo BASE_URL; ?>tools/js/adminlte.min.js"></script>
<?php $hooks->trigger(HOOK_ADMIN_BODY_END); ?>
</body>
</html>

View File

@@ -13,3 +13,4 @@ if(!function_exists('phpinfo'))
die('phpinfo() disabled on this web server.');
phpinfo();
?>

View File

@@ -1,34 +0,0 @@
<?php
const MYAAC_ADMIN = true;
require '../../common.php';
require SYSTEM . 'functions.php';
require SYSTEM . 'init.php';
require SYSTEM . 'login.php';
if(!admin()) {
http_response_code(500);
die('Access denied.');
}
if (!isset($_REQUEST['plugin'])) {
http_response_code(500);
die('Please enter plugin name.');
}
if (!isset($_POST['settings'])) {
http_response_code(500);
die('Please enter settings.');
}
$settings = Settings::getInstance();
$settings->save($_REQUEST['plugin'], $_POST['settings']);
$errors = $settings->getErrors();
if (count($errors) > 0) {
http_response_code(500);
die(implode('<br/>', $errors));
}
echo 'Saved at ' . date('H:i');

View File

@@ -26,8 +26,8 @@
if (version_compare(phpversion(), '7.2.5', '<')) die('PHP version 7.2.5 or higher is required.');
const MYAAC = true;
const MYAAC_VERSION = '0.10.0-dev';
const DATABASE_VERSION = 36;
const MYAAC_VERSION = '0.9.0-dev';
const DATABASE_VERSION = 33;
const TABLE_PREFIX = 'myaac_';
define('START_TIME', microtime(true));
define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX'));
@@ -138,25 +138,11 @@ if(!IS_CLI) {
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_PANEL_FOLDER . '/');
define('ADMIN_URL', SERVER_URL . BASE_DIR . '/admin/');
//define('CURRENT_URL', BASE_URL . $_SERVER['REQUEST_URI']);
}
if (file_exists(BASE . 'config.local.php')) {
require 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);
require SYSTEM . 'exception.php';
}
$autoloadFile = VENDOR . 'autoload.php';

View File

@@ -10,10 +10,6 @@
"composer/semver": "^3.2",
"twig/twig": "^2.0",
"erusev/parsedown": "^1.7",
"nikic/fast-route": "^1.3",
"matomo/device-detector": "^6.0"
},
"require-dev": {
"filp/whoops": "^2.15"
"nikic/fast-route": "^1.3"
}
}

326
config.php Normal file
View File

@@ -0,0 +1,326 @@
<?php
/**
* This is MyAAC's Main Configuration file
*
* All the default values are kept here, you should not modify it but use
* a config.local.php file instead to override the settings from here.
*
* This is a piece of PHP code so PHP syntax applies!
* For boolean values please use true/false.
*
* Minimally 'server_path' directive have to be filled, other options are optional.
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
$config = array(
// directories & files
'server_path' => '', // path to the server directory (same directory where config file is located)
/**
* Environment Setting
*
* if you use this script on your live server - set to 'prod' (production)
* if you want to test and debug the script locally, or develop plugins, set to 'dev' (development)
* WARNING: on 'dev' cache is disabled, so site will be significantly slower !!!
* WARNING2: on 'dev' all PHP errors/warnings are displayed
* Recommended: 'prod' cause of speed (page load time is better)
*/
'env' => 'prod', // 'prod' for production and 'dev' for development
'template' => 'kathrine', // template used by website (kathrine, tibiacom)
'template_allow_change' => true, // allow users to choose their own template while browsing website?
'vocations_amount' => 4, // how much basic vocations your server got (without promotion)
// what client version are you using on this OT?
// used for the Downloads page and some templates aswell
'client' => 1098, // 954 = client 9.54
'session_prefix' => 'myaac_', // must be unique for every site on your server
'friendly_urls' => false, // mod_rewrite is required for this, it makes links looks more elegant to eye, and also are SEO friendly (example: https://my-aac.org/guilds/Testing instead of https://my-aac.org/?subtopic=guilds&name=Testing). Remember to rename .htaccess.dist to .htaccess
'gzip_output' => false, // gzip page content before sending it to the browser, uses less bandwidth but more cpu cycles
// gesior backward support (templates & pages)
// allows using gesior templates and pages with myaac
// might bring some performance when disabled
'backward_support' => true,
// head options (html)
'meta_description' => 'Tibia is a free massive multiplayer online role playing game (MMORPG).', // description of the site
'meta_keywords' => 'free online game, free multiplayer game, ots, open tibia server', // keywords list separated by commas
// footer
'footer' => ''/*'<br/>Your Server &copy; 2016. All rights reserved.'*/,
'language' => 'en', // default language (currently only 'en' available)
'language_allow_change' => false,
'visitors_counter' => true,
'visitors_counter_ttl' => 10, // how long visitor will be marked as online (in minutes)
'views_counter' => true,
// cache system. by default file cache is used
'cache_engine' => 'auto', // apc, apcu, eaccelerator, xcache, file, auto, or blank to disable.
'cache_prefix' => 'myaac_', // have to be unique if running more MyAAC instances on the same server (except file system cache)
// database details (leave blank for auto detect from config.lua)
'database_host' => '',
'database_port' => '', // leave blank to default 3306
'database_user' => '',
'database_password' => '',
'database_name' => '',
'database_log' => false, // should database queries be logged 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
// multiworld system (only TFS 0.3)
'multiworld' => false, // use multiworld system?
'worlds' => array( // list of worlds
//'1' => 'Your World Name',
//'2' => 'Your Second World Name'
),
// images
'outfit_images_url' => 'https://outfit-images.ots.me/outfit.php', // set to animoutfit.php for animated outfit
'outfit_images_wrong_looktypes' => [75, 126, 127, 266, 302], // this looktypes needs to have different margin-top and margin-left because they are wrong positioned
'item_images_url' => 'https://item-images.ots.me/1092/', // set to images/items if you host your own items in images folder
'item_images_extension' => '.gif',
// creatures
'creatures_images_url' => 'images/monsters/', // set to images/monsters if you host your own creatures in images folder
'creatures_images_extension' => '.gif',
'creatures_images_preview' => false, // set to true to allow picture previews for creatures
'creatures_items_url' => 'https://tibia.fandom.com/wiki/', // set to website which shows details about items.
'creatures_loot_percentage' => true, // set to true to show the loot tooltip percent
// account
'account_management' => true, // disable if you're using other method to manage users (fe. tfs account manager)
'account_login_by_email' => false, // use email instead of Account Name like in latest Tibia
'account_login_by_email_fallback' => false, // allow also additionally login by Account Name/Number (for users that might forget their email)
'account_create_auto_login' => false, // auto login after creating account?
'account_create_character_create' => true, // allow directly to create character on create account page?
'account_mail_verify' => false, // force users to confirm their email addresses when registering
'account_mail_confirmed_reward' => [ // reward users for confirming their E-Mails
// account_mail_verify needs to be enabled too
'premium_days' => 0,
'premium_points' => 0,
'coins' => 0,
'message' => 'You received %d %s for confirming your E-Mail address.' // example: You received 20 premium points for confirming your E-Mail address.
],
'account_mail_unique' => true, // email addresses cannot be duplicated? (one account = one email)
'account_mail_block_plus_sign' => true, // block email with '+' signs like test+box@gmail.com (help protect against spamming accounts)
'account_premium_days' => 0, // default premium days on new account
'account_premium_points' => 0, // default premium points on new account
'account_welcome_mail' => true, // send welcome email when user registers
'account_mail_change' => 2, // how many days user need to change email to account - block hackers
'account_country' => true, // user will be able to set country of origin when registering account, this information will be viewable in others places aswell
'account_country_recognize' => true, // should country of user be automatically recognized by his IP? This makes an external API call to http://ipinfo.io
'account_change_character_name' => false, // can user change their character name for premium points?
'account_change_character_name_points' => 30, // cost of name change
'account_change_character_sex' => false, // can user change their character sex for premium points?
'account_change_character_sex_points' => 30, // cost of sex change
'characters_per_account' => 10, // max. number of characters per account
// mail
'mail_enabled' => false, // is aac maker configured to send e-mails?
'mail_address' => 'no-reply@your-server.org', // server e-mail address (from:)
'mail_admin' => 'your-address@your-server.org', // admin email address, where mails from contact form will be sent
'mail_signature' => array( // signature that will be included at the end of every message sent using _mail function
'plain' => ""/*"--\nMy Server,\nhttp://www.myserver.com"*/,
'html' => ''/*'<br/>My Server,\n<a href="http://www.myserver.com">myserver.com</a>'*/
),
'smtp_enabled' => false, // send by smtp or mail function (set false if use mail function, set to true if you use GMail or Microsoft Outlook)
'smtp_host' => '', // mail host. smtp.gmail.com for GMail / smtp-mail.outlook.com for Microsoft Outlook
'smtp_port' => 25, // 25 (default) / 465 (ssl, GMail) / 587 (tls, Microsoft Outlook)
'smtp_auth' => true, // need authorization?
'smtp_user' => 'admin@example.org', // here your email username
'smtp_pass' => '',
'smtp_secure' => '', // What kind of encryption to use on the SMTP connection. Options: '', 'ssl' (GMail) or 'tls' (Microsoft Outlook)
'smtp_debug' => false, // set true to debug (you will see more info in error.log)
// Google reCAPTCHA (prevent spam bots)
'recaptcha_enabled' => false, // enable recaptcha verification code
'recaptcha_type' => 'v3', // 'v2-checkbox', 'v2-invisible', 'v3'
'recaptcha_site_key' => '', // get your own site and secret keys at https://www.google.com/recaptcha
'recaptcha_secret_key' => '',
// following option apply only for ReCaptcha v2-checkbox
'recaptcha_v2_theme' => 'light', // light, dark
// following option apply only for ReCaptcha v3
// min score for validation, between 0 - 1.0
// https://developers.google.com/recaptcha/docs/v3#interpreting_the_score
'recaptcha_v3_min_score' => 0.5,
//
'generate_new_reckey' => true, // let player generate new recovery key, he will receive e-mail with new rec key (not display on page, hacker can't generate rec key)
'generate_new_reckey_price' => 20, // price for new recovery key
'send_mail_when_change_password' => true, // send e-mail with new password when change password to account
'send_mail_when_generate_reckey' => true, // send e-mail with rec key (key is displayed on page anyway when generate)
// you may need to adjust this for older tfs versions
// by removing Community Manager
'account_types' => [
'None',
'Normal',
'Tutor',
'Senior Tutor',
'Gamemaster',
'Community Manager',
'God',
],
// genders (aka sex)
'genders' => array(
0 => 'Female',
1 => 'Male'
),
// new character config
'character_samples' => array( // vocations, format: ID_of_vocation => 'Name of Character to copy'
//0 => 'Rook Sample',
1 => 'Sorcerer Sample',
2 => 'Druid Sample',
3 => 'Paladin Sample',
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 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,
'character_name_npc_check' => true,
// list of towns
// if you use TFS 1.3 with support for 'towns' table in database, then you can ignore this - it will be configured automatically (from MySQL database - Table - towns)
// otherwise it will try to load from your .OTBM map file
// if you don't see towns on website, then you need to fill this out
'towns' => array(
0 => 'No town',
1 => 'Sample town'
),
// guilds
'guild_management' => true, // enable guild management system on the site?
'guild_need_level' => 1, // min. level to form a guild
'guild_need_premium' => true, // require premium account to form a guild?
'guild_image_size_kb' => 80, // maximum size of the guild logo image in KB (kilobytes)
'guild_description_default' => 'New guild. Leader must edit this text :)',
'guild_description_chars_limit' => 1000, // limit of guild description
'guild_description_lines_limit' => 6, // limit of lines, if description has more lines it will be showed as long text, without 'enters'
'guild_motd_chars_limit' => 150, // limit of MOTD (message of the day) that is shown later in the game on the guild channel
// online page
'online_record' => true, // display players record?
'online_vocations' => false, // display vocation statistics?
'online_vocations_images' => false, // display vocation images?
'online_skulls' => false, // display skull images
'online_outfit' => true,
'online_afk' => false,
// support list page
'team_style' => 2, // 1/2 (1 - normal table, 2 - in boxes, grouped by group id)
'team_display_status' => true,
'team_display_lastlogin' => true,
'team_display_world' => false,
'team_display_outfit' => true,
// bans page
'bans_per_page' => 20,
// highscores page
'highscores_vocation_box' => true, // show 'Choose a vocation' box on the highscores (allowing peoples to sort highscores by vocation)?
'highscores_vocation' => true, // show player vocation under his nickname?
'highscores_frags' => false, // show 'Frags' tab (best fraggers on the server)?
'highscores_balance' => false, // show 'Balance' tab (richest players on the server)
'highscores_outfit' => true, // show player outfit?
'highscores_country_box' => false, // doesnt work yet! (not implemented)
'highscores_groups_hidden' => 3, // this group id and higher won't be shown on the highscores
'highscores_ids_hidden' => array(0), // this ids of players will be hidden on the highscores (should be ids of samples)
'highscores_per_page' => 100, // how many records per page on highscores
'highscores_cache_ttl' => 15, // how often to update highscores from database in minutes (default 15 minutes)
// characters page
'characters' => array( // what things to display on character view page (true/false in each option)
'level' => true,
'experience' => false,
'magic_level' => false,
'balance' => false,
'marriage_info' => true, // only 0.3
'outfit' => true,
'creation_date' => true,
'quests' => true,
'skills' => true,
'equipment' => true,
'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(
//'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
'signature_browser_cache' => 60, // how long to cache by browser (in minutes), default 1 hour
// news page
'news_limit' => 5, // limit of news on the latest news page
'news_ticker_limit' => 5, // limit of news in tickers (mini news) (0 to disable)
'news_date_format' => 'j.n.Y', // check php manual date() function for more info about this
'news_author' => true, // show author of the news
// gifts/shop system
'gifts_system' => false,
// support/system
'bug_report' => true, // this configurable has no effect, its always enabled
// forum
'forum' => 'site', // link to the server forum, set to "site" if you want to use build in forum system, otherwise leave empty if you aren't going to use any forum
'forum_level_required' => 0, // level required to post, 0 to disable
'forum_post_interval' => 30, // in seconds
'forum_posts_per_page' => 20,
'forum_threads_per_page' => 20,
// uncomment to force use table for forum
//'forum_table_prefix' => 'z_', // what forum mysql table to use, z_ (for gesior old forum) or myaac_ (for myaac)
// last kills
'last_kills_limit' => 50, // max. number of deaths shown on the last kills page
// status, took automatically from config file if empty
'status_enabled' => true, // you can disable status checking by settings this to "false"
'status_ip' => '',
'status_port' => '',
'status_timeout' => 2.0, // how long to wait for the initial response from the server (default: 2 seconds)
// how often to connect to server and update status (default: every minute)
// if your status timeout in config.lua is bigger, that it will be used instead
// when server is offline, it will be checked every time web refreshes, ignoring this variable
'status_interval' => 60,
// admin panel
'admin_panel_modules' => 'statistics,web_status,server_status,lastlogin,created,points,coins,balance', // default - statistics,web_status,server_status,lastlogin,created,points,coins,balance
// other
'anonymous_usage_statistics' => true,
'email_lai_sec_interval' => 60, // time in seconds between e-mails to one account from lost account interface, block spam
'google_analytics_id' => '', // e.g.: UA-XXXXXXX-X
'experiencetable_columns' => 3, // how many columns to display in experience table page. * experiencetable_rows, 5 = 500 (will show up to 500 level)
'experiencetable_rows' => 200, // till how many levels in one column
'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()
);

View File

@@ -1,9 +0,0 @@
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});

View File

@@ -1,75 +0,0 @@
describe('Install MyAAC', () => {
beforeEach(() => {
// Cypress starts out with a blank slate for each test
// so we must tell it to visit our website with the `cy.visit()` command.
// Since we want to visit the same URL at the start of all our tests,
// we include it in our beforeEach function so that it runs before each test
cy.visit(Cypress.env('URL'))
})
it('Go through installer', () => {
cy.visit(Cypress.env('URL') + '/install/?step=welcome')
cy.wait(1000)
cy.screenshot('install-welcome')
// step 1 - Welcome
cy.get('select[name="lang"]').select('en')
//cy.get('input[type=button]').contains('Next »').click()
cy.get('form').submit()
// step 2 - License
// just skip
cy.contains('GNU/GPL License');
cy.get('form').submit()
// step 3 - Requirements
cy.contains('Requirements check');
cy.get('#step').then(elem => {
elem.val('config');
});
cy.get('form').submit()
// step 4 - Configuration
cy.contains('Basic configuration');
cy.get('#vars_server_path').click().clear().type(Cypress.env('SERVER_PATH'))
cy.get('#vars_mail_admin').click().clear().type('noone@example.net')
cy.get('[type="checkbox"]').uncheck() // usage statistics uncheck
cy.wait(1000)
cy.get('form').submit()
// check if there is any error
// step 5 - Import Schema
cy.contains('Import MySQL schema');
// AAC is not installed yet, this message should not come
cy.contains('Seems AAC is already installed. Skipping importing MySQL schema..').should('not.exist')
cy.contains('[class="alert alert-success"]', 'Local configuration has been saved into file: config.local.php').should('be.visible')
cy.get('form').submit()
// step 6 - Admin Account
cy.get('#vars_email').click().clear().type('admin@my-aac.org')
cy.get('#vars_account').click().clear().type('admin')
cy.get('#vars_password').click().clear().type('test1234')
cy.get('#vars_password_confirm').click().clear().type('test1234')
cy.get('#vars_player_name').click().clear().type('Admin')
cy.get('form').submit()
cy.contains('[class="alert alert-success"]', 'Congratulations', { timeout: 30000 }).should('be.visible')
cy.screenshot('install-finish')
})
})

View File

@@ -1,33 +0,0 @@
describe('Create Account Page', () => {
beforeEach(() => {
// Cypress starts out with a blank slate for each test
// so we must tell it to visit our website with the `cy.visit()` command.
// Since we want to visit the same URL at the start of all our tests,
// we include it in our beforeEach function so that it runs before each test
cy.visit(Cypress.env('URL') + '/index.php/account/create')
})
it('Create Test Account', () => {
cy.screenshot('create-account-page')
cy.get('#account_input').type('tester')
cy.get('#email').type('tester@example.com')
cy.get('#password').type('test1234')
cy.get('#password2').type('test1234')
cy.get('#character_name').type('Slaw')
cy.get('#sex1').check()
cy.get('#vocation1').check()
cy.get('#accept_rules').check()
cy.get('#createaccount').submit()
// no errors please
cy.contains('The Following Errors Have Occurred:').should('not.exist')
// ss of post page
cy.screenshot('create-account-page-post')
})
})

View File

@@ -1,5 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@@ -1,25 +0,0 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })

View File

@@ -1,20 +0,0 @@
// ***********************************************************
// This example support/e2e.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

View File

@@ -56,6 +56,22 @@ if(preg_match("/^(.*)\.(gif|jpg|png|jpeg|tiff|bmp|css|js|less|map|html|zip|rar|g
exit;
}
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'))
{
header('Location: ' . BASE_URL . 'install/');
@@ -84,11 +100,13 @@ $twig->addGlobal('status', $status);
require_once SYSTEM . 'router.php';
require SYSTEM . 'migrate.php';
$hooks->trigger(HOOK_STARTUP);
// anonymous usage statistics
// sent only when user agrees
if(setting('core.anonymous_usage_statistics')) {
if(isset($config['anonymous_usage_statistics']) && $config['anonymous_usage_statistics']) {
$report_time = 30 * 24 * 60 * 60; // report one time per 30 days
$should_report = true;
@@ -121,16 +139,17 @@ if(setting('core.anonymous_usage_statistics')) {
}
}
if(setting('core.views_counter'))
if($config['views_counter'])
require_once SYSTEM . 'counter.php';
if(setting('core.visitors_counter')) {
if($config['visitors_counter'])
{
require_once SYSTEM . 'libs/visitors.php';
$visitors = new Visitors(setting('core.visitors_counter_ttl'));
$visitors = new Visitors($config['visitors_counter_ttl']);
}
// backward support for gesior
if(setting('core.backward_support')) {
if($config['backward_support']) {
define('INITIALIZED', true);
$SQL = $db;
$layout_header = template_header();
@@ -146,8 +165,7 @@ if(setting('core.backward_support')) {
$config['site'] = &$config;
$config['server'] = &$config['lua'];
$config['site']['shop_system'] = setting('core.gifts_system');
$config['site']['gallery_page'] = true;
$config['site']['shop_system'] = $config['gifts_system'];
if(!isset($config['vdarkborder']))
$config['vdarkborder'] = '#505050';
@@ -160,9 +178,8 @@ if(setting('core.backward_support')) {
$config['site']['serverinfo_page'] = true;
$config['site']['screenshot_page'] = true;
$forumSetting = setting('core.forum');
if($forumSetting != '')
$config['forum_link'] = (strtolower($forumSetting) === 'site' ? getLink('forum') : $forumSetting);
if($config['forum'] != '')
$config['forum_link'] = (strtolower($config['forum']) === 'site' ? getLink('forum') : $config['forum']);
foreach($status as $key => $value)
$config['status']['serverStatus_' . $key] = $value;

View File

@@ -38,3 +38,4 @@ if(!isset($error) || !$error) {
$error = true;
}
}
?>

View File

@@ -1,4 +1,4 @@
SET @myaac_database_version = 36;
SET @myaac_database_version = 33;
CREATE TABLE `myaac_account_actions`
(
@@ -203,7 +203,6 @@ CREATE TABLE `myaac_monsters` (
`mana` int(11) NOT NULL DEFAULT 0,
`exp` int(11) NOT NULL,
`health` int(11) NOT NULL,
`look` VARCHAR(255) NOT NULL DEFAULT '',
`speed_lvl` int(11) NOT NULL default 1,
`use_haste` tinyint(1) NOT NULL,
`voices` text NOT NULL,
@@ -303,16 +302,6 @@ CREATE TABLE `myaac_gallery`
INSERT INTO `myaac_gallery` (`id`, `ordering`, `comment`, `image`, `thumb`, `author`) VALUES (NULL, 1, 'Demon', 'images/gallery/demon.jpg', 'images/gallery/demon_thumb.gif', 'MyAAC');
CREATE TABLE `myaac_settings`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL DEFAULT '',
`key` VARCHAR(255) NOT NULL DEFAULT '',
`value` TEXT NOT NULL,
PRIMARY KEY (`id`),
KEY `key` (`key`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE `myaac_spells`
(
`id` INT(11) NOT NULL AUTO_INCREMENT,
@@ -341,7 +330,6 @@ CREATE TABLE `myaac_visitors`
`ip` VARCHAR(45) NOT NULL,
`lastvisit` INT(11) NOT NULL DEFAULT 0,
`page` VARCHAR(2048) NOT NULL,
`user_agent` VARCHAR(255) NOT NULL DEFAULT '',
UNIQUE (`ip`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;

View File

@@ -1,4 +1,4 @@
We have detected that you don't have access to write to the system/cache directory. Under linux you can fix it by using this two command, where first one should be enough (for apache):<br/><br/><span class="console">chown -R www-data.www-data /var/www/*</span><br/><span class="console">chmod -R 760 system/cache</span>
We have detected that you don't have access to write to the system/cache directory. Under linux you can fix it by using this two command, where first one should be enough (for apache):<br/><br/><span class="console">chown -R www-data.www-data /var/www/*</span><br/><span class="console">chmod -R 660 system/cache</span>
<style type="text/css">
.console {

View File

@@ -12,7 +12,9 @@ require SYSTEM . 'functions.php';
require BASE . 'install/includes/functions.php';
require BASE . 'install/includes/locale.php';
require SYSTEM . 'clients.conf.php';
require LIBS . 'settings.php';
if(file_exists(BASE . 'config.local.php'))
require BASE . 'config.local.php';
// ignore undefined index from Twig autoloader
$config['env'] = 'prod';
@@ -24,13 +26,13 @@ $twig = new Twig_Environment($twig_loader, array(
));
// load installation status
$step = $_REQUEST['step'] ?? 'welcome';
$step = isset($_POST['step']) ? $_POST['step'] : 'welcome';
$install_status = array();
if(file_exists(CACHE . 'install.txt')) {
$install_status = unserialize(file_get_contents(CACHE . 'install.txt'));
if(!isset($_REQUEST['step'])) {
if(!isset($_POST['step'])) {
$step = isset($install_status['step']) ? $install_status['step'] : '';
}
}
@@ -68,7 +70,7 @@ if($step == 'database') {
$key = str_replace('var_', '', $key);
if(in_array($key, array('account', 'account_id', 'password', 'password_confirm', 'email', 'player_name'))) {
if(in_array($key, array('account', 'password', 'password_confirm', 'email', 'player_name'))) {
continue;
}
@@ -89,6 +91,10 @@ if($step == 'database') {
break;
}
}
else if($key == 'mail_admin' && !Validator::email($value)) {
$errors[] = $locale['step_config_mail_admin_error'];
break;
}
else if($key == 'timezone' && !in_array($value, DateTimeZone::listIdentifiers())) {
$errors[] = $locale['step_config_timezone_error'];
break;
@@ -104,11 +110,13 @@ if($step == 'database') {
}
}
else if($step == 'admin') {
if(!file_exists(BASE . 'config.local.php') || !isset($config['installed']) || !$config['installed']) {
$step = 'database';
$config_failed = true;
if(file_exists(BASE . 'config.local.php') && isset($config['installed']) && $config['installed'] && isset($_SESSION['saved'])) {
$config_failed = false;
}
else {
$_SESSION['saved'] = true;
if($config_failed) {
$step = 'database';
}
}
else if($step == 'finish') {

View File

@@ -5,3 +5,4 @@ $twig->display('install.license.html.twig', array(
'license' => file_get_contents(BASE . 'LICENSE'),
'buttons' => next_buttons()
));
?>

View File

@@ -18,3 +18,4 @@ $twig->display('install.config.html.twig', array(
'errors' => isset($errors) ? $errors : null,
'buttons' => next_buttons()
));
?>

View File

@@ -11,12 +11,16 @@ if(!isset($_SESSION['var_server_path'])) {
}
if(!$error) {
$configToSave = [
// by default, set env to prod
// user can disable when he wants
'env' => 'prod',
];
$content = "<?php";
$content .= PHP_EOL;
$content .= '// place for your configuration directives, so you can later easily update myaac';
$content .= PHP_EOL;
$content .= '$config[\'installed\'] = true;';
$content .= PHP_EOL;
// by default, set env to prod
// user can disable when he wants
$content .= '$config[\'env\'] = \'prod\'; // dev or prod';
$content .= PHP_EOL;
foreach($_SESSION as $key => $value)
{
if(strpos($key, 'var_') !== false)
@@ -28,14 +32,17 @@ if(!$error) {
$value .= '/';
}
if(!in_array($key, ['var_usage', 'var_date_timezone', 'var_client', 'var_account', 'var_account_id', 'var_password', 'var_password_confirm', 'var_step', 'var_email', 'var_player_name'], true)) {
$configToSave[str_replace('var_', '', $key)] = $value;
if($key === 'var_usage') {
$content .= '$config[\'anonymous_usage_statistics\'] = ' . ((int)$value == 1 ? 'true' : 'false') . ';';
$content .= PHP_EOL;
}
else if(!in_array($key, array('var_account', 'var_account_id', 'var_password', 'var_step', 'var_email', 'var_player_name'), true)) {
$content .= '$config[\'' . str_replace('var_', '', $key) . '\'] = \'' . $value . '\';';
$content .= PHP_EOL;
}
}
}
$configToSave['cache_prefix'] = 'myaac_' . generateRandomString(8, true, false, true);
require BASE . 'install/includes/config.php';
if(!$error) {
@@ -48,42 +55,38 @@ if(!$error) {
error($database_error);
}
else {
if(!$db->hasTable('accounts')) {
$tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
if(!$db->hasTable('players')) {
$tmp = str_replace('$TABLE$', 'players', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
if(!$db->hasTable('guilds')) {
$tmp = str_replace('$TABLE$', 'guilds', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
$twig->display('install.installer.html.twig', array(
'url' => 'tools/5-database.php',
'message' => $locale['loading_spinner']
));
if(!$error) {
$twig->display('install.installer.html.twig', array(
'url' => 'tools/5-database.php',
'message' => $locale['loading_spinner']
));
if(!Validator::email($_SESSION['var_mail_admin'])) {
error($locale['step_config_mail_admin_error']);
$error = true;
}
$content .= '$config[\'session_prefix\'] = \'myaac_' . generateRandomString(8, true, false, true, false) . '_\';';
$content .= PHP_EOL;
$content .= '$config[\'cache_prefix\'] = \'myaac_' . generateRandomString(8, true, false, true, false) . '_\';';
$saved = true;
if(!$error) {
$saved = file_put_contents(BASE . 'config.local.php', $content);
}
$content = '';
$saved = Settings::saveConfig($configToSave, BASE . 'config.local.php', $content);
if($saved) {
success($locale['step_database_config_saved']);
$_SESSION['saved'] = true;
if(!$error) {
$_SESSION['saved'] = true;
}
}
else {
$_SESSION['config_content'] = $content;
unset($_SESSION['saved']);
$locale['step_database_error_file'] = str_replace('$FILE$', '<b>' . BASE . 'config.php</b>', $locale['step_database_error_file']);
error($locale['step_database_error_file'] . '<br/>
$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/>
<textarea cols="70" rows="10">' . $content . '</textarea>');
}
}
@@ -95,7 +98,7 @@ if(!$error) {
<div class="text-center m-3">
<form action="<?php echo BASE_URL; ?>install/" method="post">
<input type="hidden" name="step" id="step" value="admin" />
<?php echo next_buttons(true, !$error);
<?php echo next_buttons(true, $error ? false : true);
?>
</form>
</div>

View File

@@ -8,7 +8,7 @@ if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['save
else {
require SYSTEM . 'init.php';
if(!$error) {
if(USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER)
if(USE_ACCOUNT_NAME)
$account = isset($_SESSION['var_account']) ? $_SESSION['var_account'] : null;
else
$account_id = isset($_SESSION['var_account_id']) ? $_SESSION['var_account_id'] : null;
@@ -65,6 +65,7 @@ else {
$new_account->setPassword(encrypt($password));
$new_account->setEMail($email);
$new_account->unblock();
$new_account->save();
$new_account->setCustomField('created', time());
@@ -116,44 +117,24 @@ else {
}
}
$settings = Settings::getInstance();
foreach($_SESSION as $key => $value) {
if (in_array($key, ['var_usage', 'var_date_timezone', 'var_client'])) {
if ($key == 'var_usage') {
$key = 'anonymous_usage_statistics';
$value = ((int)$value == 1 ? 'true' : 'false');
} elseif ($key == 'var_date_timezone') {
$key = 'date_timezone';
} elseif ($key == 'var_client') {
$key = 'client';
}
$settings->updateInDatabase('core', $key, $value);
}
}
success('Settings saved.');
$twig->display('install.installer.html.twig', array(
'url' => 'tools/7-finish.php',
'message' => $locale['importing_spinner']
));
if(!isset($_SESSION['installed'])) {
if (!array_key_exists('CI', getenv())) {
$report_url = 'https://my-aac.org/report_install.php?v=' . MYAAC_VERSION . '&b=' . urlencode(BASE_URL);
if (function_exists('curl_version'))
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $report_url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_exec($curl);
curl_close($curl);
}
else if (ini_get('allow_url_fopen') ) {
file_get_contents($report_url);
}
$report_url = 'https://my-aac.org/report_install.php?v=' . MYAAC_VERSION . '&b=' . urlencode(BASE_URL);
if (function_exists('curl_version'))
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $report_url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_exec($curl);
curl_close($curl);
}
else if (ini_get('allow_url_fopen') ) {
file_get_contents($report_url);
}
$_SESSION['installed'] = true;
}

View File

@@ -4,7 +4,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $locale['encoding']; ?>" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>MyAAC - <?php echo $locale['installation']; ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="template/style.css" />
<script type="text/javascript" src="<?php echo BASE_URL; ?>tools/js/jquery.min.js"></script>
</head>
@@ -29,7 +29,7 @@
$progress = ($i == 6) ? 100 : $i * 16;
}
echo '<li class="list-group-item' . ($step == $value ? ' active' : '') . '">' . ++$i . '. ' . $locale['step_' . $value] . '</li>';
echo '<li' . ($step == $value ? ' class="list-group-item active"' : ' class="list-group-item"') . '>' . ++$i . '. ' . $locale['step_' . $value] . '</li>';
}
?>

View File

@@ -23,6 +23,24 @@ if(!$error) {
}
}
if(!$db->hasTable('accounts')) {
$locale['step_database_error_table'] = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']);
error($locale['step_database_error_table']);
return;
}
if(!$db->hasTable('players')) {
$locale['step_database_error_table'] = str_replace('$TABLE$', 'players', $locale['step_database_error_table']);
error($locale['step_database_error_table']);
return;
}
if(!$db->hasTable('guilds')) {
$locale['step_database_error_table'] = str_replace('$TABLE$', 'guilds', $locale['step_database_error_table']);
error($locale['step_database_error_table']);
return;
}
if($db->hasTable(TABLE_PREFIX . 'account_actions')) {
$locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']);
warning($locale['step_database_error_table_exist']);
@@ -55,8 +73,13 @@ else {
success($locale['step_database_adding_field'] . ' accounts.key...');
}
if(!$db->hasColumn('accounts', 'blocked')) {
if(query("ALTER TABLE `accounts` ADD `blocked` TINYINT(1) NOT NULL DEFAULT FALSE COMMENT 'internal usage' AFTER `key`;"))
success($locale['step_database_adding_field'] . ' accounts.blocked...');
}
if(!$db->hasColumn('accounts', 'created')) {
if(query("ALTER TABLE `accounts` ADD `created` INT(11) NOT NULL DEFAULT 0 AFTER `" . ($db->hasColumn('accounts', 'group_id') ? 'group_id' : 'key') . "`;"))
if(query("ALTER TABLE `accounts` ADD `created` INT(11) NOT NULL DEFAULT 0 AFTER `" . ($db->hasColumn('accounts', 'group_id') ? 'group_id' : 'blocked') . "`;"))
success($locale['step_database_adding_field'] . ' accounts.created...');
}

View File

@@ -11,11 +11,11 @@ ini_set('max_execution_time', 300);
ob_implicit_flush();
ob_end_flush();
header('X-Accel-Buffering: no');
/*
if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) {
warning($locale['already_installed']);
return;
}*/
}
require SYSTEM . 'init.php';
@@ -51,6 +51,13 @@ DataLoader::load();
// update config.highscores_ids_hidden
require_once SYSTEM . 'migrations/20.php';
$database_migration_20 = true;
$content = '';
if(!databaseMigration20($content)) {
$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/>
<textarea cols="70" rows="10">' . $content . '</textarea>');
}
// add z_polls tables
require_once SYSTEM . 'migrations/22.php';

View File

@@ -1,5 +1,7 @@
<?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';

View File

@@ -7,23 +7,6 @@ server {
# increase max file upload
client_max_body_size 10M;
# this is very important, be sure its in your nginx conf - it prevents access to logs etc.
location ~ /system {
deny all;
return 404;
}
# block .htaccess
location ~ /\.ht {
deny all;
}
# block git files and folders
location ~ /\.git {
return 404;
deny all;
}
location / {
try_files $uri $uri/ /index.php;
}
@@ -32,6 +15,15 @@ server {
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
# for ubuntu 22.04+ it will be php8.1-sock
}
location ~ /\.ht {
deny all;
}
location /system {
deny all;
return 404;
}
}

1927
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +0,0 @@
{
"devDependencies": {
"cypress": "^12.12.0"
}
}

View File

@@ -1,3 +1,11 @@
<IfModule mod_autoindex.c>
Options -Indexes
</IfModule>
<IfVersion < 2.4>
order allow,deny
deny from all
</IfVersion>
<IfVersion >= 2.4>
Require all denied
</IfVersion>

View File

@@ -1,3 +1,3 @@
To play on {{ config.lua.serverName }} you need an account.
All you have to do to create your new account is to enter an account {% if constant('USE_ACCOUNT_NAME') %}name{% else %}number{% endif %}, password{% if config.account_country %}, country{% endif %} and your email address.
All you have to do to create your new account is to enter an account {% if constant('USE_ACCOUNT_NAME') %}name{% else %}number{% endif %}, password{% if config.recaptcha_enabled %}, confirm reCAPTCHA{% endif %}{% if config.account_country %}, country{% endif %} and your email address.
Also you have to agree to the terms presented below. If you have done so, your account {% if constant('USE_ACCOUNT_NAME') %}name{% else %}number{% endif %} will be shown on the following page and your account password will be sent to your email address along with further instructions. If you do not receive the email with your password, please check your spam filter.<br/><br/>

View File

@@ -39,6 +39,5 @@
"redirect_from": "/redirectExample",
"redirect_to": "account/manage"
}
},
"settings": "plugins/your-plugin-folder/settings.php"
}
}

View File

@@ -22,7 +22,7 @@ if [ $1 = "prepare" ]; then
mkdir -p tmp
# get myaac from git archive
git archive --format zip --output tmp/myaac.zip develop
git archive --format zip --output tmp/myaac.zip master
cd tmp/ || exit
@@ -35,11 +35,6 @@ if [ $1 = "prepare" ]; then
unzip -q myaac.zip -d $dir
rm myaac.zip
cd $dir || exit
# dependencies
composer install --no-dev
echo "Now you can make changes to $dir. When you are ready, type 'release.sh pack'"
exit
fi

206
system/autoload.php Normal file
View File

@@ -0,0 +1,206 @@
<?php
namespace MyAAC;
$loader = new \MyAAC\Psr4AutoloaderClass;
// register the autoloader
$loader->register();
// register the base directories for the namespace prefix
$loader->addNamespace('Composer\Semver', LIBS . 'semver');
$loader->addNamespace('Twig', LIBS . 'Twig');
/**
* An example of a general-purpose implementation that includes the optional
* functionality of allowing multiple base directories for a single namespace
* prefix.
*
* Given a foo-bar package of classes in the file system at the following
* paths ...
*
* /path/to/packages/foo-bar/
* src/
* Baz.php # Foo\Bar\Baz
* Qux/
* Quux.php # Foo\Bar\Qux\Quux
* tests/
* BazTest.php # Foo\Bar\BazTest
* Qux/
* QuuxTest.php # Foo\Bar\Qux\QuuxTest
*
* ... add the path to the class files for the \Foo\Bar\ namespace prefix
* as follows:
*
* <?php
* // instantiate the loader
* $loader = new \Example\Psr4AutoloaderClass;
*
* // register the autoloader
* $loader->register();
*
* // register the base directories for the namespace prefix
* $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src');
* $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/tests');
*
* The following line would cause the autoloader to attempt to load the
* \Foo\Bar\Qux\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php:
*
* <?php
* new \Foo\Bar\Qux\Quux;
*
* The following line would cause the autoloader to attempt to load the
* \Foo\Bar\Qux\QuuxTest class from /path/to/packages/foo-bar/tests/Qux/QuuxTest.php:
*
* <?php
* new \Foo\Bar\Qux\QuuxTest;
*/
class Psr4AutoloaderClass
{
/**
* An associative array where the key is a namespace prefix and the value
* is an array of base directories for classes in that namespace.
*
* @var array
*/
protected $prefixes = array();
/**
* Register loader with SPL autoloader stack.
*
* @return void
*/
public function register()
{
spl_autoload_register(array($this, 'loadClass'));
}
/**
* Adds a base directory for a namespace prefix.
*
* @param string $prefix The namespace prefix.
* @param string $base_dir A base directory for class files in the
* namespace.
* @param bool $prepend If true, prepend the base directory to the stack
* instead of appending it; this causes it to be searched first rather
* than last.
* @return void
*/
public function addNamespace($prefix, $base_dir, $prepend = false)
{
// normalize namespace prefix
$prefix = trim($prefix, '\\') . '\\';
// normalize the base directory with a trailing separator
$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';
// initialize the namespace prefix array
if (isset($this->prefixes[$prefix]) === false) {
$this->prefixes[$prefix] = array();
}
// retain the base directory for the namespace prefix
if ($prepend) {
array_unshift($this->prefixes[$prefix], $base_dir);
} else {
array_push($this->prefixes[$prefix], $base_dir);
}
}
/**
* Loads the class file for a given class name.
*
* @param string $class The fully-qualified class name.
* @return mixed The mapped file name on success, or boolean false on
* failure.
*/
public function loadClass($class)
{
if (0 === strpos($class, 'Twig_')) {
$file = LIBS . 'Twig/' . str_replace(array('_', "\0"), array('/', ''), $class).'.php';
if((config('env') === 'dev') && !is_file($file)) {
return false;
}
require $file;
return false;
}
// the current namespace prefix
$prefix = $class;
// work backwards through the namespace names of the fully-qualified
// class name to find a mapped file name
while (false !== $pos = strrpos($prefix, '\\')) {
// retain the trailing namespace separator in the prefix
$prefix = substr($class, 0, $pos + 1);
// the rest is the relative class name
$relative_class = substr($class, $pos + 1);
// try to load a mapped file for the prefix and relative class
$mapped_file = $this->loadMappedFile($prefix, $relative_class);
if ($mapped_file) {
return $mapped_file;
}
// remove the trailing namespace separator for the next iteration
// of strrpos()
$prefix = rtrim($prefix, '\\');
}
// never found a mapped file
return false;
}
/**
* Load the mapped file for a namespace prefix and relative class.
*
* @param string $prefix The namespace prefix.
* @param string $relative_class The relative class name.
* @return mixed Boolean false if no mapped file can be loaded, or the
* name of the mapped file that was loaded.
*/
protected function loadMappedFile($prefix, $relative_class)
{
// are there any base directories for this namespace prefix?
if (isset($this->prefixes[$prefix]) === false) {
return false;
}
// look through base directories for this namespace prefix
foreach ($this->prefixes[$prefix] as $base_dir) {
// replace the namespace prefix with the base directory,
// replace namespace separators with directory separators
// in the relative class name, append with .php
$file = $base_dir
. str_replace('\\', '/', $relative_class)
. '.php';
// if the mapped file exists, require it
if ($this->requireFile($file)) {
// yes, we're done
return $file;
}
}
// never found it
return false;
}
/**
* If a file exists, require it from the file system.
*
* @param string $file The file to require.
* @return bool True if the file exists, false if not.
*/
protected function requireFile($file)
{
if (config('env') !== 'dev' || file_exists($file)) {
require $file;
return true;
}
return false;
}
}

View File

@@ -9,30 +9,7 @@
*/
defined('MYAAC') or die('Direct access not allowed!');
class Account extends OTS_Account {
public function loadById($id) {
$this->load($id);
}
public function loadByName($name) {
$this->find($name);
}
}
class Player extends OTS_Player {
public function loadById($id) {
$this->load($id);
}
public function loadByName($name) {
$this->find($name);
}
}
class Guild extends OTS_Guild {
public function loadById($id) {
$this->load($id);
}
public function loadByName($name) {
$this->find($name);
}
}
class Player extends OTS_Player {}
class Guild extends OTS_Guild {}
class GuildRank extends OTS_GuildRank {}
class House extends OTS_House {}

View File

@@ -1,103 +0,0 @@
<?php
$deprecatedConfig = [
'date_timezone',
'genders',
'template',
'template_allow_change',
'vocations_amount',
'vocations',
'client',
'session_prefix',
'friendly_urls',
'backward_support',
'charset',
'meta_description',
'meta_keywords',
'footer',
'database_encryption' => 'database_hash',
//'language',
'visitors_counter',
'visitors_counter_ttl',
'views_counter',
'outfit_images_url',
'outfit_images_wrong_looktypes',
'item_images_url',
'account_country',
'towns',
'quests',
'character_samples',
'character_towns',
'characters_per_account',
'characters_search_limit',
'news_author',
'news_limit',
'news_ticker_limit',
'news_date_format',
'highscores_groups_hidden',
'highscores_ids_hidden',
'online_record',
'online_vocations',
'online_vocations_images',
'online_skulls',
'online_outfit',
'online_afk',
'team_display_outfit' => 'team_outfit',
'team_display_status' => 'team_status',
'team_display_world' => 'team_world',
'team_display_lastlogin' => 'team_lastlogin',
'last_kills_limit',
'multiworld',
'forum',
'signature_enabled',
'signature_type',
'signature_cache_time',
'signature_browser_cache',
'gifts_system',
'status_enabled',
'status_ip',
'status_port',
'mail_enabled',
'account_login_by_email',
'account_login_by_email_fallback',
'account_mail_verify',
'account_create_character_create',
'account_change_character_name',
'account_change_character_name_points' => 'account_change_character_name_price',
'account_change_character_sex',
'account_change_character_sex_points' => 'account_change_character_name_price',
];
foreach ($deprecatedConfig as $key => $value) {
config(
[
(is_string($key) ? $key : $value),
setting('core.'.$value)
]
);
//var_dump($settings['core.'.$value]['value']);
}
$deprecatedConfigCharacters = [
'level',
'experience',
'magic_level',
'balance',
'marriage_info' => 'marriage',
'outfit',
'creation_date',
'quests',
'skills',
'equipment',
'frags',
'deleted',
];
$tmp = [];
foreach ($deprecatedConfigCharacters as $key => $value) {
$tmp[(is_string($key) ? $key : $value)] = setting('core.characters_'.$value);
}
config(['characters', $tmp]);
unset($tmp);

View File

@@ -10,10 +10,6 @@
defined('MYAAC') or die('Direct access not allowed!');
switch($page)
{
case 'adminpanel':
header('Location: ' . ADMIN_URL);
die;
case 'createaccount':
$page = 'account/create';
break;
@@ -34,7 +30,6 @@ switch($page)
$page = 'news';
break;
case 'archive':
case 'newsarchive':
$page = 'news/archive';
break;

View File

@@ -51,3 +51,4 @@ else
updateDatabaseConfig('views_counter', $views_counter); // update counter
}
}
?>

View File

@@ -9,11 +9,7 @@
*/
defined('MYAAC') or die('Direct access not allowed!');
if (!isset($config['database_overwrite'])) {
$config['database_overwrite'] = false;
}
if(!$config['database_overwrite'] && !isset($config['database_user'][0], $config['database_password'][0], $config['database_name'][0]))
if(!isset($config['database_user'][0], $config['database_password'][0], $config['database_name'][0]))
{
if(isset($config['lua']['sqlType'])) {// tfs 0.3
if(isset($config['lua']['mysqlHost'])) {// tfs 0.2

View File

@@ -1,25 +1,4 @@
<?php
/**
* Exception handler
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2023 MyAAC
* @link https://my-aac.org
*/
if (class_exists(\Whoops\Run::class)) {
$whoops = new \Whoops\Run;
if(IS_CLI) {
$whoops->pushHandler(new \Whoops\Handler\PlainTextHandler);
}
else {
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
}
$whoops->register();
return;
}
require LIBS . 'SensitiveException.php';
@@ -44,8 +23,6 @@ function exception_handler($exception) {
$backtrace_formatted = nl2br($exception->getTraceAsString());
$message = $message . "<br/><br/>File: {$exception->getFile()}<br/>Line: {$exception->getLine()}";
// display basic error message without template
// template is missing, why? probably someone deleted templates dir, or it wasn't downloaded right
$template_file = SYSTEM . 'templates/exception.html.twig';

View File

@@ -7,11 +7,12 @@
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
defined('MYAAC') or die('Direct access not allowed!');
use PHPMailer\PHPMailer\PHPMailer;
use Twig\Loader\ArrayLoader as Twig_ArrayLoader;
defined('MYAAC') or die('Direct access not allowed!');
function message($message, $type, $return)
{
if(IS_CLI) {
@@ -32,49 +33,55 @@ function message($message, $type, $return)
return true;
}
function success($message, $return = false) {
return message($message, 'success', $return);
return message($message, 'success', $return);
}
function warning($message, $return = false) {
return message($message, 'warning', $return);
return message($message, 'warning', $return);
}
function note($message, $return = false) {
return message($message, 'note', $return);
return message($message, 'note', $return);
}
function error($message, $return = false) {
return message($message, ((defined('MYAAC_INSTALL') || defined('MYAAC_ADMIN')) ? 'danger' : 'error'), $return);
return message($message, ((defined('MYAAC_INSTALL') || defined('MYAAC_ADMIN')) ? 'danger' : 'error'), $return);
}
function longToIp($ip): string
function longToIp($ip)
{
$exp = explode(".", long2ip($ip));
return $exp[3].".".$exp[2].".".$exp[1].".".$exp[0];
}
function generateLink($url, $name, $blank = false): string {
function generateLink($url, $name, $blank = false) {
return '<a href="' . $url . '"' . ($blank ? ' target="_blank"' : '') . '>' . $name . '</a>';
}
function getFullLink($page, $name, $blank = false): string {
function getFullLink($page, $name, $blank = false) {
return generateLink(getLink($page), $name, $blank);
}
function getLink($page, $action = null): string {
return BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . $page . ($action ? '/' . $action : '');
}
function internalLayoutLink($page, $action = null): string {
return getLink($page, $action);
}
function getForumThreadLink($thread_id, $page = NULL): string {
return BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'forum/thread/' . (int)$thread_id . (isset($page) ? '/' . $page : '');
}
function getForumBoardLink($board_id, $page = NULL): string {
return BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'forum/board/' . (int)$board_id . (isset($page) ? '/' . $page : '');
}
function getPlayerLink($name, $generate = true): string
function getLink($page, $action = null)
{
global $config;
return BASE_URL . ($config['friendly_urls'] ? '' : 'index.php/') . $page . ($action ? '/' . $action : '');
}
function internalLayoutLink($page, $action = null) {return getLink($page, $action);}
function getForumThreadLink($thread_id, $page = NULL)
{
global $config;
return BASE_URL . ($config['friendly_urls'] ? '' : 'index.php/') . 'forum/thread/' . (int)$thread_id . (isset($page) ? '/' . $page : '');
}
function getForumBoardLink($board_id, $page = NULL)
{
global $config;
return BASE_URL . ($config['friendly_urls'] ? '' : 'index.php/') . 'forum/board/' . (int)$board_id . (isset($page) ? '/' . $page : '');
}
function getPlayerLink($name, $generate = true)
{
global $config;
if(is_numeric($name))
{
$player = new OTS_Player();
@@ -83,23 +90,25 @@ function getPlayerLink($name, $generate = true): string
$name = $player->getName();
}
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'characters/' . urlencode($name);
$url = BASE_URL . ($config['friendly_urls'] ? '' : 'index.php/') . 'characters/' . urlencode($name);
if(!$generate) return $url;
return generateLink($url, $name);
}
function getMonsterLink($name, $generate = true): string
function getMonsterLink($name, $generate = true)
{
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'creatures/' . urlencode($name);
global $config;
$url = BASE_URL . ($config['friendly_urls'] ? '' : 'index.php/') . 'creatures/' . urlencode($name);
if(!$generate) return $url;
return generateLink($url, $name);
}
function getHouseLink($name, $generate = true): string
function getHouseLink($name, $generate = true)
{
global $db;
global $db, $config;
if(is_numeric($name))
{
@@ -109,22 +118,25 @@ function getHouseLink($name, $generate = true): string
$name = $house->fetchColumn();
}
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'houses/' . urlencode($name);
$url = BASE_URL . ($config['friendly_urls'] ? '' : 'index.php/') . 'houses/' . urlencode($name);
if(!$generate) return $url;
return generateLink($url, $name);
}
function getGuildLink($name, $generate = true): string
function getGuildLink($name, $generate = true)
{
if(is_numeric($name)) {
$name = getGuildNameById($name);
if ($name === false) {
$name = 'Unknown';
}
global $db, $config;
if(is_numeric($name))
{
$guild = $db->query(
'SELECT `name` FROM `guilds` WHERE `id` = ' . (int)$name);
if($guild->rowCount() > 0)
$name = $guild->fetchColumn();
}
$url = BASE_URL . (setting('core.friendly_urls') ? '' : 'index.php/') . 'guilds/' . urlencode($name);
$url = BASE_URL . ($config['friendly_urls'] ? '' : 'index.php/') . 'guilds/' . urlencode($name);
if(!$generate) return $url;
return generateLink($url, $name);
@@ -170,7 +182,7 @@ function getItemRarity($chance) {
return '';
}
function getFlagImage($country): string
function getFlagImage($country)
{
if(!isset($country[0]))
return '';
@@ -192,7 +204,7 @@ function getFlagImage($country): string
* @param mixed $v Variable to check.
* @return bool Value boolean status.
*/
function getBoolean($v): bool
function getBoolean($v)
{
if(is_bool($v)) {
return $v;
@@ -215,7 +227,7 @@ function getBoolean($v): bool
* @param bool $special Should special characters by used?
* @return string Generated string.
*/
function generateRandomString($length, $lowCase = true, $upCase = false, $numeric = false, $special = false): string
function generateRandomString($length, $lowCase = true, $upCase = false, $numeric = false, $special = false)
{
$characters = '';
if($lowCase)
@@ -455,7 +467,7 @@ function tickers()
* Types: head_start, head_end, body_start, body_end, center_top
*
*/
function template_place_holder($type): string
function template_place_holder($type)
{
global $twig, $template_place_holders;
$ret = '';
@@ -479,7 +491,7 @@ function template_place_holder($type): string
/**
* Returns <head> content to be used by templates.
*/
function template_header($is_admin = false): string
function template_header($is_admin = false)
{
global $title_full, $config, $twig;
$charset = isset($config['charset']) ? $config['charset'] : 'utf-8';
@@ -496,32 +508,29 @@ function template_header($is_admin = false): string
/**
* Returns footer content to be used by templates.
*/
function template_footer(): string
function template_footer()
{
global $views_counter;
global $config, $views_counter;
$ret = '';
if(admin()) {
if(admin())
$ret .= generateLink(ADMIN_URL, 'Admin Panel', true);
}
if(setting('core.visitors_counter')) {
if($config['visitors_counter'])
{
global $visitors;
$amount = $visitors->getAmountVisitors();
$ret .= '<br/>Currently there ' . ($amount > 1 ? 'are' : 'is') . ' ' . $amount . ' visitor' . ($amount > 1 ? 's' : '') . '.';
}
if(setting('core.views_counter')) {
if($config['views_counter'])
$ret .= '<br/>Page has been viewed ' . $views_counter . ' times.';
}
if(setting('core.footer_load_time')) {
if(config('footer_show_load_time')) {
$ret .= '<br/>Load time: ' . round(microtime(true) - START_TIME, 4) . ' seconds.';
}
$settingFooter = setting('core.footer');
if(isset($settingFooter[0])) {
$ret .= '<br/>' . $settingFooter;
}
if(isset($config['footer'][0]))
$ret .= '<br/>' . $config['footer'];
// please respect my work and help spreading the word, thanks!
return $ret . '<br/>' . base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4=');
@@ -529,8 +538,8 @@ function template_footer(): string
function template_ga_code()
{
global $twig;
if(!isset(setting('core.google_analytics_id')[0]))
global $config, $twig;
if(!isset($config['google_analytics_id'][0]))
return '';
return $twig->render('google_analytics.html.twig');
@@ -747,10 +756,10 @@ function get_browser_languages()
{
$ret = array();
if(empty($_SERVER['HTTP_ACCEPT_LANGUAGE']))
$acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
if(!isset($acceptLang[0]))
return $ret;
$acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$languages = strtolower($acceptLang);
// $languages = 'pl,en-us;q=0.7,en;q=0.3 ';
// need to remove spaces from strings to avoid error
@@ -783,21 +792,16 @@ function get_templates()
* Generates list of installed plugins
* @return array $plugins
*/
function get_plugins($disabled = false): array
function get_plugins()
{
$ret = [];
$ret = array();
$path = PLUGINS;
foreach(scandir($path, SCANDIR_SORT_ASCENDING) as $file) {
foreach(scandir($path, 0) as $file) {
$file_ext = pathinfo($file, PATHINFO_EXTENSION);
$file_name = pathinfo($file, PATHINFO_FILENAME);
if ($file === '.' || $file === '..' || $file === 'example.json' || $file_ext !== 'json' || is_dir($path . $file)) {
if ($file === '.' || $file === '..' || $file === 'disabled' || $file === 'example.json' || $file_ext !== 'json' || is_dir($path . $file))
continue;
}
if (!$disabled && strpos($file, 'disabled.') !== false) {
continue;
}
$ret[] = str_replace('.json', '', $file_name);
}
@@ -815,7 +819,7 @@ function getWorldName($id)
/**
* Mailing users.
* Mailing has to be enabled in settings (in Admin Panel).
* $config['mail_enabled'] have to be enabled.
*
* @param string $to Recipient email address.
* @param string $subject Subject of the message.
@@ -827,9 +831,8 @@ function _mail($to, $subject, $body, $altBody = '', $add_html_tags = true)
{
global $mailer, $config;
if (!setting('core.mail_enabled')) {
log_append('mailer-error.log', '_mail() function has been used, but Mail Support is disabled.');
return false;
if (!config('mail_enabled')) {
log_append('mailer-error.log', '_mail() function has been used, but config.mail_enabled is disabled.');
}
if(!$mailer)
@@ -841,60 +844,47 @@ function _mail($to, $subject, $body, $altBody = '', $add_html_tags = true)
$mailer->clearAllRecipients();
}
$signature_html = setting('core.mail_signature_html');
$signature_html = '';
if(isset($config['mail_signature']['html']))
$signature_html = $config['mail_signature']['html'];
if($add_html_tags && isset($body[0]))
$tmp_body = '<html><head></head><body>' . $body . '<br/><br/>' . $signature_html . '</body></html>';
else
$tmp_body = $body . '<br/><br/>' . $signature_html;
define('MAIL_MAIL', 0);
define('MAIL_SMTP', 1);
$mailOption = setting('core.mail_option');
if($mailOption == MAIL_SMTP)
if($config['smtp_enabled'])
{
$mailer->isSMTP();
$mailer->Host = setting('core.smtp_host');
$mailer->Port = setting('core.smtp_port');
$mailer->SMTPAuth = setting('core.smtp_auth');
$mailer->Username = setting('core.smtp_user');
$mailer->Password = setting('core.smtp_pass');
define('SMTP_SECURITY_NONE', 0);
define('SMTP_SECURITY_SSL', 1);
define('SMTP_SECURITY_TLS', 2);
$security = setting('core.smtp_security');
$tmp = '';
if ($security === SMTP_SECURITY_SSL) {
$tmp = 'ssl';
}
else if ($security == SMTP_SECURITY_TLS) {
$tmp = 'tls';
}
$mailer->SMTPSecure = $tmp;
$mailer->Host = $config['smtp_host'];
$mailer->Port = (int)$config['smtp_port'];
$mailer->SMTPAuth = $config['smtp_auth'];
$mailer->Username = $config['smtp_user'];
$mailer->Password = $config['smtp_pass'];
$mailer->SMTPSecure = isset($config['smtp_secure']) ? $config['smtp_secure'] : '';
}
else {
$mailer->isMail();
}
$mailer->isHTML(isset($body[0]) > 0);
$mailer->From = setting('core.mail_address');
$mailer->Sender = setting('core.mail_address');
$mailer->From = $config['mail_address'];
$mailer->Sender = $config['mail_address'];
$mailer->CharSet = 'utf-8';
$mailer->FromName = $config['lua']['serverName'];
$mailer->Subject = $subject;
$mailer->addAddress($to);
$mailer->Body = $tmp_body;
if(setting('core.smtp_debug')) {
if(config('smtp_debug')) {
$mailer->SMTPDebug = 2;
$mailer->Debugoutput = 'echo';
}
$signature_plain = setting('core.mail_signature_plain');
$signature_plain = '';
if(isset($config['mail_signature']['plain']))
$signature_plain = $config['mail_signature']['plain'];
if(isset($altBody[0])) {
$mailer->AltBody = $altBody . $signature_plain;
}
@@ -936,8 +926,8 @@ function load_config_lua($filename)
$config_file = $filename;
if(!@file_exists($config_file))
{
log_append('error.log', '[load_config_file] Fatal error: Cannot load config.lua (' . $filename . ').');
throw new RuntimeException('ERROR: Cannot find ' . $filename . ' file.');
log_append('error.log', '[load_config_file] Fatal error: Cannot load config.lua (' . $filename . '). Error: ' . print_r(error_get_last(), true));
throw new RuntimeException('ERROR: Cannot find ' . $filename . ' file. More info in system/logs/error.log');
}
$result = array();
@@ -1054,7 +1044,7 @@ function getTopPlayers($limit = 5) {
$deleted = 'deletion';
$is_tfs10 = $db->hasTable('players_online');
$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` < ' . setting('core.highscores_groups_hidden') . ' AND `id` NOT IN (' . implode(', ', setting('core.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) {
@@ -1107,9 +1097,6 @@ function deleteDirectory($dir, $ignore = array(), $contentOnly = false) {
function config($key) {
global $config;
if (is_array($key)) {
if (is_null($key[1])) {
unset($config[$key[0]]);
}
return $config[$key[0]] = $key[1];
}
@@ -1125,21 +1112,6 @@ function configLua($key) {
return @$config['lua'][$key];
}
function setting($key)
{
$settings = Settings::getInstance();
if (is_array($key)) {
if (is_null($key[1])) {
unset($settings[$key[0]]);
}
return $settings[$key[0]] = $key[1];
}
return $settings[$key]['value'];
}
function clearCache()
{
require_once LIBS . 'news.php';
@@ -1217,7 +1189,7 @@ function getCustomPageInfo($page)
return null;
}
function getCustomPage($page, &$success): string
function getCustomPage($page, &$success)
{
global $db, $twig, $title, $ignore, $logged_access;
@@ -1508,8 +1480,8 @@ function right($str, $length) {
}
function getCreatureImgPath($creature){
$creature_path = config('monsters_images_url');
$creature_gfx_name = trim(strtolower($creature)) . config('monsters_images_extension');
$creature_path = config('creatures_images_url');
$creature_gfx_name = trim(strtolower($creature)) . config('creatures_images_extension');
if (!file_exists($creature_path . $creature_gfx_name)) {
$creature_gfx_name = str_replace(" ", "", $creature_gfx_name);
if (file_exists($creature_path . $creature_gfx_name)) {
@@ -1572,47 +1544,6 @@ function escapeHtml($html) {
return htmlentities($html, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
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(GUILD_IMAGES_DIR . $guildLogo)) {
$logo = $guildLogo;
}
}
return BASE_URL . GUILD_IMAGES_DIR . $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('')
]);
}
// validator functions
require_once LIBS . 'validator.php';
require_once SYSTEM . 'compat/base.php';

View File

@@ -30,7 +30,6 @@ define('HOOK_CHARACTERS_AFTER_CHARACTERS', ++$i);
define('HOOK_LOGIN', ++$i);
define('HOOK_LOGIN_ATTEMPT', ++$i);
define('HOOK_LOGOUT', ++$i);
define('HOOK_ACCOUNT_CHANGE_PASSWORD_POST', ++$i);
define('HOOK_ACCOUNT_CREATE_BEFORE_FORM', ++$i);
define('HOOK_ACCOUNT_CREATE_BEFORE_BOXES', ++$i);
define('HOOK_ACCOUNT_CREATE_BETWEEN_BOXES_1', ++$i);
@@ -40,8 +39,8 @@ 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_PASSWORD', ++$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);
@@ -49,34 +48,11 @@ 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_LOGIN_BEFORE_PAGE', ++$i);
define('HOOK_ACCOUNT_LOGIN_BEFORE_ACCOUNT', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT', ++$i);
define('HOOK_ACCOUNT_LOGIN_BEFORE_PASSWORD', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_PASSWORD', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_REMEMBER_ME', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_PAGE', ++$i);
define('HOOK_ACCOUNT_LOGIN_POST', ++$i);
define('HOOK_ADMIN_HEAD_END', ++$i);
define('HOOK_ADMIN_HEAD_START', ++$i);
define('HOOK_ADMIN_BODY_START', ++$i);
define('HOOK_ADMIN_BODY_END', ++$i);
define('HOOK_ADMIN_BEFORE_PAGE', ++$i);
define('HOOK_ACCOUNT_CREATE_AFTER_SUBMIT', ++$i);
define('HOOK_ADMIN_MENU', ++$i);
define('HOOK_ADMIN_LOGIN_AFTER_ACCOUNT', ++$i);
define('HOOK_ADMIN_LOGIN_AFTER_PASSWORD', ++$i);
define('HOOK_ADMIN_LOGIN_AFTER_SIGN_IN', ++$i);
define('HOOK_ADMIN_ACCOUNTS_SAVE_POST', ++$i);
define('HOOK_EMAIL_CONFIRMED', ++$i);
define('HOOK_GUILDS_BEFORE_GUILD_HEADER', ++$i);
define('HOOK_GUILDS_AFTER_GUILD_HEADER', ++$i);
define('HOOK_GUILDS_AFTER_GUILD_INFORMATION', ++$i);
define('HOOK_GUILDS_AFTER_GUILD_MEMBERS', ++$i);
define('HOOK_GUILDS_AFTER_INVITED_CHARACTERS', ++$i);
const HOOK_FIRST = HOOK_STARTUP;
define('HOOK_LAST', $i);
define('HOOK_FIRST', HOOK_STARTUP);
define('HOOK_LAST', HOOK_EMAIL_CONFIRMED);
require_once LIBS . 'plugins.php';
class Hook

View File

@@ -9,24 +9,22 @@
*/
defined('MYAAC') or die('Direct access not allowed!');
// load configuration
require_once BASE . 'config.php';
if(file_exists(BASE . 'config.local.php')) // user customizations
require BASE . 'config.local.php';
if(!isset($config['installed']) || !$config['installed']) {
throw new RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.');
}
if(config('env') === 'dev') {
require SYSTEM . 'exception.php';
}
if(empty($config['server_path'])) {
throw new RuntimeException('Server Path has been not set. Go to config.php and set it.');
}
date_default_timezone_set($config['date_timezone']);
// take care of trailing slash at the end
if($config['server_path'][strlen($config['server_path']) - 1] !== '/')
$config['server_path'] .= '/';
// enable gzip compression if supported by the browser
if(isset($config['gzip_output']) && $config['gzip_output'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false && function_exists('ob_gzhandler'))
if($config['gzip_output'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false && function_exists('ob_gzhandler'))
ob_start('ob_gzhandler');
// cache
@@ -94,6 +92,9 @@ if(isset($config['lua']['servername']))
if(isset($config['lua']['houserentperiod']))
$config['lua']['houseRentPeriod'] = $config['lua']['houserentperiod'];
if($config['item_images_url'][strlen($config['item_images_url']) - 1] !== '/')
$config['item_images_url'] .= '/';
// localize data/ directory based on data directory set in config.lua
foreach(array('dataDirectory', 'data_directory', 'datadir') as $key) {
if(!isset($config['lua'][$key][0])) {
@@ -117,34 +118,51 @@ if(!isset($foundValue)) {
$config['data_path'] = $foundValue;
unset($foundValue);
// new config values for compability
if(!isset($config['highscores_ids_hidden']) || count($config['highscores_ids_hidden']) == 0) {
$config['highscores_ids_hidden'] = array(0);
}
$config['account_create_character_create'] = config('account_create_character_create') && (!config('mail_enabled') || !config('account_mail_verify'));
// POT
require_once SYSTEM . 'libs/pot/OTS.php';
$ots = POT::getInstance();
require_once SYSTEM . 'database.php';
// execute migrations
require SYSTEM . 'migrate.php';
// settings
require_once LIBS . 'Settings.php';
$settings = Settings::getInstance();
$settings->load();
// deprecated config values
require_once SYSTEM . 'compat/config.php';
date_default_timezone_set(setting('core.date_timezone'));
$config['account_create_character_create'] = config('account_create_character_create') && (!setting('core.mail_enabled') || !config('account_mail_verify'));
$settingsItemImagesURL = setting('core.item_images_url');
if($settingsItemImagesURL[strlen($settingsItemImagesURL) - 1] !== '/') {
setting(['core.item_images_url', $settingsItemImagesURL . '/']);
}
define('USE_ACCOUNT_NAME', $db->hasColumn('accounts', 'name'));
define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number'));
define('USE_ACCOUNT_SALT', $db->hasColumn('accounts', 'salt'));
// load vocation names
$tmp = '';
if($cache->enabled() && $cache->fetch('vocations', $tmp)) {
$config['vocations'] = unserialize($tmp);
}
else {
if(!class_exists('DOMDocument')) {
throw new RuntimeException('Please install PHP xml extension. MyAAC will not work without it.');
}
$vocations = new DOMDocument();
$file = $config['data_path'] . 'XML/vocations.xml';
if(!@file_exists($file))
$file = $config['data_path'] . 'vocations.xml';
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) {
$id = $vocation->getAttribute('id');
$config['vocations'][$id] = $vocation->getAttribute('name');
}
if($cache->enabled()) {
$cache->set('vocations', serialize($config['vocations']), 120);
}
}
unset($tmp, $id, $vocation);
require LIBS . 'Towns.php';
Towns::load();

View File

@@ -58,3 +58,4 @@ function outputItem($id = 100, $count = 1)
$file_name = Items_Images::$outputDir . $file_name . '.gif';
readfile($file_name);
}
?>

View File

@@ -18,8 +18,8 @@ class CreateCharacter
*/
public function checkName($name, &$errors)
{
$minLength = setting('core.create_character_name_min_length');
$maxLength = setting('core.create_character_name_max_length');
$minLength = config('character_name_min_length');
$maxLength = config('character_name_max_length');
if(empty($name)) {
$errors['name'] = 'Please enter a name for your character!';
@@ -138,7 +138,7 @@ class CreateCharacter
if(empty($errors))
{
$number_of_players_on_account = $account->getPlayersList(true)->count();
$number_of_players_on_account = $account->getPlayersList(false)->count();
if($number_of_players_on_account >= config('characters_per_account'))
$errors[] = 'You have too many characters on your account <b>('.$number_of_players_on_account.'/'.config('characters_per_account').')</b>!';
}
@@ -149,7 +149,7 @@ class CreateCharacter
$char_to_copy = new OTS_Player();
$char_to_copy->find($char_to_copy_name);
if(!$char_to_copy->isLoaded())
$errors[] = 'Wrong characters configuration. Try again or contact with admin. ADMIN: Go to Admin Panel -> Settings -> Create Character and set valid characters to copy names. Character to copy: <b>'.$char_to_copy_name.'</b> doesn\'t exist.';
$errors[] = 'Wrong characters configuration. Try again or contact with admin. ADMIN: Edit file config.php and set valid characters to copy names. Character to copy: <b>'.$char_to_copy_name.'</b> doesn\'t exist.';
}
if(!empty($errors)) {
@@ -195,7 +195,7 @@ class CreateCharacter
for($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++) {
$value = 10;
if (setting('core.use_character_sample_skills')) {
if (config('use_character_sample_skills')) {
$value = $char_to_copy->getSkill($skill);
}
@@ -239,24 +239,22 @@ class CreateCharacter
}
if($db->hasTable('player_skills')) {
for($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++) {
for($i=0; $i<7; $i++) {
$value = 10;
if (setting('core.use_character_sample_skills')) {
$value = $char_to_copy->getSkill($skill);
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` = ' . $skill);
$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().', '.$skill.', ' . $value . ', 0)');
$db->query('INSERT INTO `player_skills` (`player_id`, `skillid`, `value`, `count`) VALUES ('.$player->getId().', '.$i.', ' . $value . ', 0)');
}
}
}
if ($db->hasTable('player_items') && $db->hasColumn('player_items', 'pid') && $db->hasColumn('player_items', 'sid') && $db->hasColumn('player_items', 'itemtype')) {
$loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$char_to_copy->getId()."");
foreach($loaded_items_to_copy as $save_item) {
$blob = $db->quote($save_item['attributes']);
$db->query("INSERT INTO `player_items` (`player_id` ,`pid` ,`sid` ,`itemtype`, `count`, `attributes`) VALUES ('".$player->getId()."', '".$save_item['pid']."', '".$save_item['sid']."', '".$save_item['itemtype']."', '".$save_item['count']."', $blob);");
}
$loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$char_to_copy->getId()."");
foreach($loaded_items_to_copy as $save_item) {
$blob = $db->quote($save_item['attributes']);
$db->query("INSERT INTO `player_items` (`player_id` ,`pid` ,`sid` ,`itemtype`, `count`, `attributes`) VALUES ('".$player->getId()."', '".$save_item['pid']."', '".$save_item['sid']."', '".$save_item['itemtype']."', '".$save_item['count']."', $blob);");
}
global $twig;

View File

@@ -0,0 +1,84 @@
<?php
class GoogleReCAPTCHA
{
private static $errorMessage = '';
private static $errorType;
const ERROR_MISSING_RESPONSE = 1;
const ERROR_INVALID_ACTION = 2;
const ERROR_LOW_SCORE = 3;
const ERROR_NO_SUCCESS = 4;
public static function verify($action = '')
{
if (!isset($_POST['g-recaptcha-response']) || empty($_POST['g-recaptcha-response'])) {
self::$errorType = self::ERROR_MISSING_RESPONSE;
self::$errorMessage = "Please confirm that you're not a robot.";
return false;
}
$recaptchaApiUrl = 'https://www.google.com/recaptcha/api/siteverify';
$secretKey = config('recaptcha_secret_key');
$recaptchaResponse = $_POST['g-recaptcha-response'];
$ip = $_SERVER['REMOTE_ADDR'];
$params = 'secret='.$secretKey.'&response='.$recaptchaResponse.'&remoteip='.$ip;
if (function_exists('curl_version')) {
$curl_connection = curl_init($recaptchaApiUrl);
curl_setopt($curl_connection, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl_connection, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $params);
$response = curl_exec($curl_connection);
curl_close($curl_connection);
} else {
$response = file_get_contents($recaptchaApiUrl . '?' . $params);
}
$json = json_decode($response);
$recaptchaType = config('recaptcha_type');
if ($recaptchaType === 'v3') { // score based
//log_append('recaptcha.log', 'recaptcha_score: ' . $json->score . ', action:' . $json->action);
if (!isset($json->action) || $json->action !== $action) {
self::$errorType = self::ERROR_INVALID_ACTION;
self::$errorMessage = 'Google ReCaptcha returned invalid action.';
return false;
}
if (!isset($json->score) || $json->score < config('recaptcha_v3_min_score')) {
self::$errorType = self::ERROR_LOW_SCORE;
self::$errorMessage = 'Your Google ReCaptcha score was too low.';
return false;
}
}
if (!isset($json->success) || !$json->success) {
self::$errorType = self::ERROR_NO_SUCCESS;
self::$errorMessage = "Please confirm that you're not a robot.";
return false;
}
return true;
}
/**
* @return string
*/
public static function getErrorMessage() {
return self::$errorMessage;
}
/**
* @return int
*/
public static function getErrorType() {
return self::$errorType;
}
}

View File

@@ -1,598 +0,0 @@
<?php
/**
* CreateCharacter
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2020 MyAAC
* @link https://my-aac.org
*/
class Settings implements ArrayAccess
{
static private $instance;
private $settingsFile = [];
private $settingsDatabase = [];
private $cache = [];
private $valuesAsked = [];
private $errors = [];
/**
* @return Settings
*/
public static function getInstance(): Settings
{
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function load()
{
$cache = Cache::getInstance();
if ($cache->enabled()) {
$tmp = '';
if ($cache->fetch('settings', $tmp)) {
$this->settingsDatabase = unserialize($tmp);
return;
}
}
global $db;
$settings = $db->query('SELECT * FROM `' . TABLE_PREFIX . 'settings`');
if($settings->rowCount() > 0) {
foreach ($settings->fetchAll(PDO::FETCH_ASSOC) as $setting) {
$this->settingsDatabase[$setting['name']][$setting['key']] = $setting['value'];
}
}
if ($cache->enabled()) {
$cache->set('settings', serialize($this->settingsDatabase), 600);
}
}
public function save($pluginName, $values) {
global $db;
if (!isset($this->settingsFile[$pluginName])) {
throw new RuntimeException('Error on save settings: plugin does not exist');
}
$settings = $this->settingsFile[$pluginName];
if (isset($settings['callbacks']['beforeSave'])) {
if (!$settings['callbacks']['beforeSave']($settings, $values)) {
return false;
}
}
$this->errors = [];
$db->query('DELETE FROM `' . TABLE_PREFIX . 'settings` WHERE `name` = ' . $db->quote($pluginName) . ';');
foreach ($values as $key => $value) {
$errorMessage = '';
if (isset($settings['settings'][$key]['callbacks']['beforeSave']) && !$settings['settings'][$key]['callbacks']['beforeSave']($key, $value, $errorMessage)) {
$this->errors[] = $errorMessage;
continue;
}
try {
$db->insert(TABLE_PREFIX . 'settings', ['name' => $pluginName, 'key' => $key, 'value' => $value]);
} catch (PDOException $error) {
$this->errors[] = 'Error while saving setting (' . $pluginName . ' - ' . $key . '): ' . $error->getMessage();
}
}
$cache = Cache::getInstance();
if ($cache->enabled()) {
$cache->delete('settings');
}
return true;
}
public function updateInDatabase($pluginName, $key, $value)
{
global $db;
$db->update(TABLE_PREFIX . 'settings', ['value' => $value], ['name' => $pluginName, 'key' => $key]);
}
public function deleteFromDatabase($pluginName, $key = null)
{
global $db;
if (!isset($key)) {
$db->delete(TABLE_PREFIX . 'settings', ['name' => $pluginName], -1);
}
else {
$db->delete(TABLE_PREFIX . 'settings', ['name' => $pluginName, 'key' => $key]);
}
}
public static function display($plugin, $settings): array
{
global $db;
$query = 'SELECT `key`, `value` FROM `' . TABLE_PREFIX . 'settings` WHERE `name` = ' . $db->quote($plugin) . ';';
$query = $db->query($query);
$settingsDb = [];
if($query->rowCount() > 0) {
foreach($query->fetchAll(PDO::FETCH_ASSOC) as $value) {
$settingsDb[$value['key']] = $value['value'];
}
}
$config = [];
require BASE . 'config.local.php';
foreach ($config as $key => $value) {
if (is_bool($value)) {
$settingsDb[$key] = $value ? 'true' : 'false';
}
else {
$settingsDb[$key] = (string)$value;
}
}
$javascript = '';
ob_start();
?>
<ul class="nav nav-tabs" id="myTab">
<?php
$i = 0;
foreach($settings as $setting) {
if (isset($setting['script'])) {
$javascript .= $setting['script'] . PHP_EOL;
}
if ($setting['type'] === 'category') {
?>
<li class="nav-item">
<a class="nav-link<?= ($i === 0 ? ' active' : ''); ?>" id="home-tab-<?= $i++; ?>" data-toggle="tab" href="#tab-<?= str_replace(' ', '', $setting['title']); ?>" type="button"><?= $setting['title']; ?></a>
</li>
<?php
}
}
?>
</ul>
<div class="tab-content" id="tab-content">
<?php
$checkbox = function ($key, $type, $value) {
echo '<label><input type="radio" id="' . $key . '_' . ($type ? 'yes' : 'no') . '" name="settings[' . $key . ']" value="' . ($type ? 'true' : 'false') . '" ' . ($value === $type ? 'checked' : '') . '/>' . ($type ? 'Yes' : 'No') . '</label> ';
};
$i = 0;
$j = 0;
foreach($settings as $key => $setting) {
if ($setting['type'] === 'category') {
if ($j++ !== 0) { // close previous category
echo '</tbody></table></div>';
}
?>
<div class="tab-pane fade show<?= ($j === 1 ? ' active' : ''); ?>" id="tab-<?= str_replace(' ', '', $setting['title']); ?>">
<?php
continue;
}
if ($setting['type'] === 'section') {
if ($i++ !== 0) { // close previous section
echo '</tbody></table>';
}
?>
<h3 id="row_<?= $key ?>" style="text-align: center"><strong><?= $setting['title']; ?></strong></h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th style="width: 13%">Name</th>
<th style="width: 30%">Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<?php
continue;
}
if (!isset($setting['hidden']) || !$setting['hidden']) {
?>
<tr id="row_<?= $key ?>">
<td><label for="<?= $key ?>" class="control-label"><?= $setting['name'] ?></label></td>
<td>
<?php
}
if (isset($setting['hidden']) && $setting['hidden']) {
$value = '';
if ($setting['type'] === 'boolean') {
$value = ($setting['default'] ? 'true' : 'false');
}
else if (in_array($setting['type'], ['text', 'number', 'email', 'password', 'textarea'])) {
$value = $setting['default'];
}
else if ($setting['type'] === 'options') {
$value = $setting['options'][$setting['default']];
}
echo '<input type="hidden" name="settings[' . $key . ']" value="' . $value . '" id="' . $key . '"';
}
else if ($setting['type'] === 'boolean') {
if(isset($settingsDb[$key])) {
if($settingsDb[$key] === 'true') {
$value = true;
}
else {
$value = false;
}
}
else {
$value = ($setting['default'] ?? false);
}
$checkbox($key, true, $value);
$checkbox($key, false, $value);
}
else if (in_array($setting['type'], ['text', 'number', 'email', 'password'])) {
if ($setting['type'] === 'number') {
$min = (isset($setting['min']) ? ' min="' . $setting['min'] . '"' : '');
$max = (isset($setting['max']) ? ' max="' . $setting['max'] . '"' : '');
$step = (isset($setting['step']) ? ' step="' . $setting['step'] . '"' : '');
}
else {
$min = $max = $step = '';
}
echo '<input class="form-control" type="' . $setting['type'] . '" name="settings[' . $key . ']" value="' . ($settingsDb[$key] ?? ($setting['default'] ?? '')) . '" id="' . $key . '"' . $min . $max . $step . '/>';
}
else if($setting['type'] === 'textarea') {
$value = ($settingsDb[$key] ?? ($setting['default'] ?? ''));
$valueWithSpaces = array_map('trim', preg_split('/\r\n|\r|\n/', trim($value)));
$rows = count($valueWithSpaces);
if ($rows < 2) {
$rows = 2; // always min 2 rows for textarea
}
echo '<textarea class="form-control" rows="' . $rows . '" name="settings[' . $key . ']" id="' . $key . '">' . $value . '</textarea>';
}
else if ($setting['type'] === 'options') {
if ($setting['options'] === '$templates') {
$templates = [];
foreach (get_templates() as $value) {
$templates[$value] = $value;
}
$setting['options'] = $templates;
}
else if($setting['options'] === '$clients') {
$clients = [];
foreach((array)config('clients') as $client) {
$client_version = (string)($client / 100);
if(strpos($client_version, '.') === false)
$client_version .= '.0';
$clients[$client] = $client_version;
}
$setting['options'] = $clients;
}
else if ($setting['options'] == '$timezones') {
$timezones = [];
foreach (DateTimeZone::listIdentifiers() as $value) {
$timezones[$value] = $value;
}
$setting['options'] = $timezones;
}
else {
if (is_string($setting['options'])) {
$setting['options'] = explode(',', $setting['options']);
foreach ($setting['options'] as &$option) {
$option = trim($option);
}
}
}
echo '<select class="form-control" name="settings[' . $key . ']" id="' . $key . '">';
foreach ($setting['options'] as $value => $option) {
$compareTo = ($settingsDb[$key] ?? ($setting['default'] ?? ''));
if($value === 'true') {
$selected = $compareTo === true;
}
else if($value === 'false') {
$selected = $compareTo === false;
}
else {
$selected = $compareTo == $value;
}
echo '<option value="' . $value . '" ' . ($selected ? 'selected' : '') . '>' . $option . '</option>';
}
echo '</select>';
}
if (!isset($setting['hidden']) || !$setting['hidden']) {
?>
</td>
<td>
<div class="well setting-default"><?php
echo ($setting['desc'] ?? '');
echo '<br/>';
echo '<strong>Default:</strong> ';
if ($setting['type'] === 'boolean') {
echo ($setting['default'] ? 'Yes' : 'No');
}
else if (in_array($setting['type'], ['text', 'number', 'email', 'password', 'textarea'])) {
echo $setting['default'];
}
else if ($setting['type'] === 'options') {
if (!empty($setting['default'])) {
echo $setting['options'][$setting['default']];
}
}
?></div>
</td>
</tr>
<?php
}
}
?>
</tbody>
</table>
</div>
</div>
<div class="box-footer">
<button name="save" type="submit" class="btn btn-primary">Save</button>
</div>
<?php
return ['content' => ob_get_clean(), 'script' => $javascript];
}
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
throw new \RuntimeException("Settings: You cannot set empty offset with value: $value!");
}
$this->loadPlugin($offset);
$pluginKeyName = $this->valuesAsked['pluginKeyName'];
$key = $this->valuesAsked['key'];
// remove whole plugin settings
if (!isset($value)) {
$this->offsetUnset($offset);
$this->deleteFromDatabase($pluginKeyName, $key);
return;
}
$this->settingsDatabase[$pluginKeyName][$key] = $value;
$this->updateInDatabase($pluginKeyName, $key, $value);
}
#[\ReturnTypeWillChange]
public function offsetExists($offset): bool
{
$this->loadPlugin($offset);
$pluginKeyName = $this->valuesAsked['pluginKeyName'];
$key = $this->valuesAsked['key'];
// remove specified plugin settings (all)
if(is_null($key)) {
return isset($this->settingsDatabase[$offset]);
}
return isset($this->settingsDatabase[$pluginKeyName][$key]);
}
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
$this->loadPlugin($offset);
$pluginKeyName = $this->valuesAsked['pluginKeyName'];
$key = $this->valuesAsked['key'];
if (isset($this->cache[$offset])) {
unset($this->cache[$offset]);
}
// remove specified plugin settings (all)
if(!isset($key)) {
unset($this->settingsFile[$pluginKeyName]);
unset($this->settingsDatabase[$pluginKeyName]);
$this->deleteFromDatabase($pluginKeyName);
return;
}
unset($this->settingsFile[$pluginKeyName]['settings'][$key]);
unset($this->settingsDatabase[$pluginKeyName][$key]);
$this->deleteFromDatabase($pluginKeyName, $key);
}
/**
* Get settings
* Usage: $setting['plugin_name.key']
* Example: $settings['shop_system.paypal_email']
*
* @param mixed $offset
* @return array|mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
// try cache hit
if(isset($this->cache[$offset])) {
return $this->cache[$offset];
}
$this->loadPlugin($offset);
$pluginKeyName = $this->valuesAsked['pluginKeyName'];
$key = $this->valuesAsked['key'];
// return specified plugin settings (all)
if(!isset($key)) {
if (!isset($this->settingsFile[$pluginKeyName]['settings'])) {
throw new RuntimeException('Unknown plugin settings: ' . $pluginKeyName);
}
return $this->settingsFile[$pluginKeyName]['settings'];
}
$ret = [];
if(isset($this->settingsFile[$pluginKeyName]['settings'][$key])) {
$ret = $this->settingsFile[$pluginKeyName]['settings'][$key];
}
if(isset($this->settingsDatabase[$pluginKeyName][$key])) {
$value = $this->settingsDatabase[$pluginKeyName][$key];
$ret['value'] = $value;
}
else {
$ret['value'] = $this->settingsFile[$pluginKeyName]['settings'][$key]['default'];
}
if(isset($ret['type'])) {
switch($ret['type']) {
case 'boolean':
$ret['value'] = getBoolean($ret['value']);
break;
case 'number':
if (!isset($ret['step']) || (int)$ret['step'] == 1) {
$ret['value'] = (int)$ret['value'];
}
break;
default:
break;
}
}
if (isset($ret['callbacks']['get'])) {
$ret['value'] = $ret['callbacks']['get']($ret['value']);
}
$this->cache[$offset] = $ret;
return $ret;
}
private function updateValuesAsked($offset)
{
$pluginKeyName = $offset;
if (strpos($offset, '.')) {
$explode = explode('.', $offset, 2);
$pluginKeyName = $explode[0];
$key = $explode[1];
$this->valuesAsked = ['pluginKeyName' => $pluginKeyName, 'key' => $key];
}
else {
$this->valuesAsked = ['pluginKeyName' => $pluginKeyName, 'key' => null];
}
}
private function loadPlugin($offset)
{
$this->updateValuesAsked($offset);
$pluginKeyName = $this->valuesAsked['pluginKeyName'];
$key = $this->valuesAsked['key'];
if (!isset($this->settingsFile[$pluginKeyName])) {
if ($pluginKeyName === 'core') {
$settingsFilePath = SYSTEM . 'settings.php';
} else {
//$pluginSettings = Plugins::getPluginSettings($pluginKeyName);
$settings = Plugins::getAllPluginsSettings();
if (!isset($settings[$pluginKeyName])) {
warning("Setting $pluginKeyName does not exist or does not have settings defined.");
return;
}
$settingsFilePath = BASE . $settings[$pluginKeyName]['settingsFilename'];
}
if (!file_exists($settingsFilePath)) {
throw new \RuntimeException('Failed to load settings file for plugin: ' . $pluginKeyName);
}
$this->settingsFile[$pluginKeyName] = require $settingsFilePath;
}
}
public static function saveConfig($config, $filename, &$content = '')
{
$content = "<?php" . PHP_EOL .
"\$config['installed'] = true;" . PHP_EOL;
foreach ($config as $key => $value) {
$content .= "\$config['$key'] = ";
$content .= var_export($value, true);
$content .= ';' . PHP_EOL;
}
$success = file_put_contents($filename, $content);
// we saved new config.php, need to revalidate cache (only if opcache is enabled)
if (function_exists('opcache_invalidate')) {
opcache_invalidate($filename);
}
return $success;
}
public static function testDatabaseConnection($config): bool
{
$user = null;
$password = null;
$dns = [];
if( isset($config['database_name']) ) {
$dns[] = 'dbname=' . $config['database_name'];
}
if( isset($config['database_user']) ) {
$user = $config['database_user'];
}
if( isset($config['database_password']) ) {
$password = $config['database_password'];
}
if( isset($config['database_host']) ) {
$dns[] = 'host=' . $config['database_host'];
}
if( isset($config['database_port']) ) {
$dns[] = 'port=' . $config['database_port'];
}
try {
$connectionTest = new PDO('mysql:' . implode(';', $dns), $user, $password);
$connectionTest->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $error) {
error('MySQL connection failed. Settings has been reverted.');
error($error->getMessage());
return false;
}
return true;
}
public function getErrors() {
return $this->errors;
}
}

View File

@@ -110,21 +110,4 @@ class Cache
* @return bool
*/
public function enabled() {return false;}
public static function remember($key, $ttl, $callback)
{
$cache = self::getInstance();
if(!$cache->enabled()) {
return $callback();
}
$value = null;
if ($cache->fetch($key, $value)) {
return unserialize($value);
}
$value = $callback();
$cache->set($key, serialize($value),$ttl);
return $value;
}
}

View File

@@ -82,9 +82,6 @@ class Creatures {
$armor = $monster->getArmor();
$defensev = $monster->getDefense();
//load look
$look = $monster->getLook();
//load monster flags
$flags = $monster->getFlags();
if(!isset($flags['summonable']))
@@ -150,7 +147,6 @@ class Creatures {
'armor' => $armor,
'race' => $race,
'loot' => json_encode($loot),
'look' => json_encode($look),
'summons' => json_encode($summons)
));

View File

@@ -41,3 +41,4 @@ class Data
return $db->update($this->table, $data, $where);
}
}
?>

View File

@@ -10,7 +10,7 @@
*/
defined('MYAAC') or die('Direct access not allowed!');
$configForumTablePrefix = setting('core.forum_table_prefix');
$configForumTablePrefix = config('forum_table_prefix');
if(null !== $configForumTablePrefix && !empty(trim($configForumTablePrefix))) {
if(!in_array($configForumTablePrefix, array('myaac_', 'z_'))) {
throw new RuntimeException('Invalid value for forum_table_prefix in config.php. Can be only: "myaac_" or "z_".');
@@ -47,7 +47,7 @@ class Forum
return
$db->query(
'SELECT `id` FROM `players` WHERE `account_id` = ' . $db->quote($account->getId()) .
' AND `level` >= ' . $db->quote(setting('core.forum_level_required')) .
' AND `level` >= ' . $db->quote($config['forum_level_required']) .
' LIMIT 1')->rowCount() > 0;
}

View File

@@ -10,7 +10,7 @@
*/
defined('MYAAC') or die('Direct access not allowed!');
function is_sub_dir($path = NULL, $parent_folder = BASE) {
function is_sub_dir($path = NULL, $parent_folder = SITE_PATH) {
//Get directory path minus last folder
$dir = dirname($path);
@@ -41,9 +41,9 @@ function is_sub_dir($path = NULL, $parent_folder = BASE) {
use Composer\Semver\Semver;
class Plugins {
private static $warnings = [];
private static $warnings = array();
private static $error = null;
private static $plugin_json = [];
private static $plugin_json = array();
public static function getRoutes()
{
@@ -56,8 +56,22 @@ class Plugins {
}
$routes = [];
foreach(self::getAllPluginsJson() as $plugin) {
$warningPreTitle = 'Plugin: ' . $plugin['name'] . ' - ';
foreach(get_plugins() as $filename) {
$string = file_get_contents(PLUGINS . $filename . '.json');
$string = self::removeComments($string);
$plugin = json_decode($string, true);
self::$plugin_json = $plugin;
if ($plugin == null) {
self::$warnings[] = 'Cannot load ' . $filename . '.json. File might be not a valid json code.';
continue;
}
if(isset($plugin['enabled']) && !getBoolean($plugin['enabled'])) {
self::$warnings[] = 'Skipping ' . $filename . '... The plugin is disabled.';
continue;
}
$warningPreTitle = 'Plugin: ' . $filename . ' - ';
if (isset($plugin['routes'])) {
foreach ($plugin['routes'] as $_name => $info) {
@@ -66,8 +80,7 @@ class Plugins {
if ($method !== '*') {
$methods = is_string($method) ? explode(',', $info['method']) : $method;
foreach ($methods as $method) {
$method = strtolower($method);
if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'head'])) {
if (!in_array($method, ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'])) {
self::$warnings[] = $warningPreTitle . 'Not allowed method ' . $method . '... Disabling this route...';
}
}
@@ -148,14 +161,28 @@ class Plugins {
}
$hooks = [];
foreach(self::getAllPluginsJson() as $plugin) {
foreach(get_plugins() as $filename) {
$string = file_get_contents(PLUGINS . $filename . '.json');
$string = self::removeComments($string);
$plugin = json_decode($string, true);
self::$plugin_json = $plugin;
if ($plugin == null) {
self::$warnings[] = 'Cannot load ' . $filename . '.json. File might be not a valid json code.';
continue;
}
if(isset($plugin['enabled']) && !getBoolean($plugin['enabled'])) {
self::$warnings[] = 'Skipping ' . $filename . '... The plugin is disabled.';
continue;
}
if (isset($plugin['hooks'])) {
foreach ($plugin['hooks'] as $_name => $info) {
if (defined('HOOK_'. $info['type'])) {
$hook = constant('HOOK_'. $info['type']);
$hooks[] = ['name' => $_name, 'type' => $hook, 'file' => $info['file']];
} else {
self::$warnings[] = 'Plugin: ' . $plugin['name'] . '. Unknown event type: ' . $info['type'];
self::$warnings[] = 'Plugin: ' . $filename . '. Unknown event type: ' . $info['type'];
}
}
}
@@ -168,108 +195,7 @@ class Plugins {
return $hooks;
}
public static function getAllPluginsSettings()
{
$cache = Cache::getInstance();
if ($cache->enabled()) {
$tmp = '';
if ($cache->fetch('plugins_settings', $tmp)) {
return unserialize($tmp);
}
}
$settings = [];
foreach (self::getAllPluginsJson() as $plugin) {
if (isset($plugin['settings'])) {
$settingsFile = require BASE . $plugin['settings'];
if (!isset($settingsFile['key'])) {
warning("Settings file for plugin - {$plugin['name']} does not contain 'key' field");
continue;
}
$settings[$settingsFile['key']] = ['pluginFilename' => $plugin['filename'], 'settingsFilename' => $plugin['settings']];
}
}
if ($cache->enabled()) {
$cache->set('plugins_settings', serialize($settings), 600); // cache for 10 minutes
}
return $settings;
}
public static function getAllPluginsJson($disabled = false)
{
$cache = Cache::getInstance();
if ($cache->enabled()) {
$tmp = '';
if ($cache->fetch('plugins', $tmp)) {
return unserialize($tmp);
}
}
$plugins = [];
foreach (get_plugins($disabled) as $filename) {
$plugin = self::getPluginJson($filename);
if (!$plugin) {
continue;
}
$plugin['filename'] = $filename;
$plugins[] = $plugin;
}
if ($cache->enabled()) {
$cache->set('plugins', serialize($plugins), 600); // cache for 10 minutes
}
return $plugins;
}
public static function getPluginSettings($filename)
{
$plugin_json = self::getPluginJson($filename);
if (!$plugin_json) {
return false;
}
if (!isset($plugin_json['settings']) || !file_exists(BASE . $plugin_json['settings'])) {
return false;
}
return $plugin_json['settings'];
}
public static function getPluginJson($filename = null)
{
if(!isset($filename)) {
return self::$plugin_json;
}
$pathToPlugin = PLUGINS . $filename . '.json';
if (!file_exists($pathToPlugin)) {
self::$warnings[] = "Cannot load $filename.json. File doesn't exist.";
return false;
}
$string = file_get_contents($pathToPlugin);
$plugin_json = json_decode($string, true);
if ($plugin_json == null) {
self::$warnings[] = "Cannot load $filename.json. File might be not a valid json code.";
return false;
}
if (isset($plugin_json['enabled']) && !getBoolean($plugin_json['enabled'])) {
self::$warnings[] = 'Skipping ' . $filename . '... The plugin is disabled.';
return false;
}
return $plugin_json;
}
public static function install($file): bool
{
public static function install($file) {
global $db;
if(!\class_exists('ZipArchive')) {
@@ -308,13 +234,8 @@ class Plugins {
return false;
}
$pluginFilename = str_replace('.json', '', basename($json_file));
if (self::existDisabled($pluginFilename)) {
success('The plugin already existed, but was disabled. It has been enabled again and will be now reinstalled.');
self::enable($pluginFilename);
}
$string = file_get_contents($file_name);
$string = self::removeComments($string);
$plugin_json = json_decode($string, true);
self::$plugin_json = $plugin_json;
if ($plugin_json == null) {
@@ -514,45 +435,7 @@ class Plugins {
return false;
}
public static function isEnabled($pluginFileName): bool
{
$filenameJson = $pluginFileName . '.json';
return !is_file(PLUGINS . 'disabled.' . $filenameJson) && is_file(PLUGINS . $filenameJson);
}
public static function existDisabled($pluginFileName): bool
{
$filenameJson = $pluginFileName . '.json';
return is_file(PLUGINS . 'disabled.' . $filenameJson);
}
public static function enable($pluginFileName): bool {
return self::enableDisable($pluginFileName, true);
}
public static function disable($pluginFileName): bool {
return self::enableDisable($pluginFileName, false);
}
private static function enableDisable($pluginFileName, $enable): bool
{
$filenameJson = $pluginFileName . '.json';
$fileExist = is_file(PLUGINS . ($enable ? 'disabled.' : '') . $filenameJson);
if (!$fileExist) {
self::$error = 'Cannot ' . ($enable ? 'enable' : 'disable') . ' plugin: ' . $pluginFileName . '. File does not exist.';
return false;
}
$result = rename(PLUGINS . ($enable ? 'disabled.' : '') . $filenameJson, PLUGINS . ($enable ? '' : 'disabled.') . $filenameJson);
if (!$result) {
self::$error = 'Cannot ' . ($enable ? 'enable' : 'disable') . ' plugin: ' . $pluginFileName . '. Permission problem.';
return false;
}
return true;
}
public static function uninstall($plugin_name): bool
public static function uninstall($plugin_name)
{
$filename = BASE . 'plugins/' . $plugin_name . '.json';
if(!file_exists($filename)) {
@@ -560,8 +443,9 @@ class Plugins {
return false;
}
$string = file_get_contents($filename);
$string = self::removeComments($string);
$plugin_info = json_decode($string, true);
if(!$plugin_info) {
if($plugin_info == false) {
self::$error = 'Cannot load plugin info ' . $plugin_name . '.json';
return false;
}
@@ -608,8 +492,7 @@ class Plugins {
return false;
}
public static function is_installed($plugin_name, $version): bool
{
public static function is_installed($plugin_name, $version) {
$filename = BASE . 'plugins/' . $plugin_name . '.json';
if(!file_exists($filename)) {
return false;
@@ -617,7 +500,7 @@ class Plugins {
$string = file_get_contents($filename);
$plugin_info = json_decode($string, true);
if(!$plugin_info) {
if($plugin_info == false) {
return false;
}
@@ -640,6 +523,26 @@ class Plugins {
return self::$error;
}
public static function getPluginJson() {
return self::$plugin_json;
}
public static function removeComments($string) {
$string = preg_replace('!/\*.*?\*/!s', '', $string);
$string = preg_replace('/\n\s*\n/', "\n", $string);
// Removes multi-line comments and does not create
// a blank line, also treats white spaces/tabs
$string = preg_replace('!^[ \t]*/\*.*?\*/[ \t]*[\r\n]!s', '', $string);
// Removes single line '//' comments, treats blank characters
$string = preg_replace('![ \t]*//.*[ \t]*[\r\n]!', '', $string);
// Strip blank lines
$string = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $string);
return $string;
}
/**
* Install menus
* Helper function for plugins

View File

@@ -32,3 +32,5 @@ class E_OTS_ErrorCode extends Exception
}
/**#@-*/
?>

View File

@@ -36,3 +36,5 @@ class E_OTS_Generic extends E_OTS_ErrorCode
}
/**#@-*/
?>

View File

@@ -22,3 +22,5 @@ class E_OTS_NotAContainer extends Exception
}
/**#@-*/
?>

View File

@@ -32,3 +32,5 @@ class E_OTS_OTBMError extends E_OTS_ErrorCode
}
/**#@-*/
?>

View File

@@ -22,3 +22,5 @@ class E_OTS_ReadOnly extends Exception
}
/**#@-*/
?>

View File

@@ -37,3 +37,5 @@ interface IOTS_Cipher
}
/**#@-*/
?>

View File

@@ -89,3 +89,5 @@ interface IOTS_DataDisplay
}
/**#@-*/
?>

View File

@@ -96,3 +96,5 @@ interface IOTS_Display
}
/**#@-*/
?>

View File

@@ -67,3 +67,5 @@ interface IOTS_GuildAction
}
/**#@-*/
?>

View File

@@ -21,6 +21,7 @@
* @property string $password Password.
* @property string $eMail Email address.
* @property int $premiumEnd Timestamp of PACC end.
* @property bool $blocked Blocked flag state.
* @property bool $deleted Deleted flag state.
* @property bool $warned Warned flag state.
* @property bool $banned Ban state.
@@ -38,7 +39,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
* @var array
* @version 0.1.5
*/
private $data = array('email' => '', 'rlname' => '','location' => '', 'country' => '','web_flags' => 0, 'lastday' => 0, 'premdays' => 0, 'created' => 0);
private $data = array('email' => '', 'blocked' => false, 'rlname' => '','location' => '', 'country' => '','web_flags' => 0, 'lastday' => 0, 'premdays' => 0, 'created' => 0);
public static $cache = array();
@@ -230,22 +231,26 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
* @param int $id Account number.
* @throws PDOException On PDO operation error.
*/
public function load($id, $fresh = false)
public function load($id, $fresh = false, $searchOnlyById = false)
{
if(!$fresh && isset(self::$cache[$id])) {
$this->data = self::$cache[$id];
return;
}
$numberColumn = 'id';
$nameOrNumber = '';
if (USE_ACCOUNT_NAME) {
$nameOrNumber = '`name`,';
} else if (USE_ACCOUNT_NUMBER) {
$nameOrNumber = '`number`,';
if (!$searchOnlyById) {
if (USE_ACCOUNT_NAME) {
$nameOrNumber = '`name`,';
} else if (USE_ACCOUNT_NUMBER) {
$nameOrNumber = '`number`,';
$numberColumn = 'number';
}
}
// SELECT query on database
$this->data = $this->db->query('SELECT `id`, ' . $nameOrNumber . '`password`, `email`, `rlname`, `location`, `country`, `web_flags`, ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays`, ' : '') . ($this->db->hasColumn('accounts', 'lastday') ? '`lastday`, ' : ($this->db->hasColumn('accounts', 'premend') ? '`premend`,' : ($this->db->hasColumn('accounts', 'premium_ends_at') ? '`premium_ends_at`,' : ''))) . '`created` FROM `accounts` WHERE `id` = ' . (int) $id)->fetch();
$this->data = $this->db->query('SELECT `id`, ' . $nameOrNumber . '`password`, `email`, `blocked`, `rlname`, `location`, `country`, `web_flags`, ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays`, ' : '') . ($this->db->hasColumn('accounts', 'lastday') ? '`lastday`, ' : ($this->db->hasColumn('accounts', 'premend') ? '`premend`,' : ($this->db->hasColumn('accounts', 'premium_ends_at') ? '`premium_ends_at`,' : ''))) . '`created` FROM `accounts` WHERE `' . $numberColumn . '` = ' . (int) $id)->fetch();
self::$cache[$id] = $this->data;
}
@@ -263,13 +268,8 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
*/
public function find($name)
{
$nameOrNumberColumn = 'name';
if (USE_ACCOUNT_NUMBER) {
$nameOrNumberColumn = 'number';
}
// finds player's ID
$id = $this->db->query('SELECT `id` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` = ' . $this->db->quote($name) )->fetch();
$id = $this->db->query('SELECT `id` FROM `accounts` WHERE `name` = ' . $this->db->quote($name) )->fetch();
// if anything was found
if( isset($id['id']) )
@@ -345,7 +345,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
}
// UPDATE query on database
$this->db->exec('UPDATE `accounts` SET ' . ($this->db->hasColumn('accounts', 'name') ? '`name` = ' . $this->db->quote($this->data['name']) . ',' : '') . '`password` = ' . $this->db->quote($this->data['password']) . ', `email` = ' . $this->db->quote($this->data['email']) . ', `rlname` = ' . $this->db->quote($this->data['rlname']) . ', `location` = ' . $this->db->quote($this->data['location']) . ', `country` = ' . $this->db->quote($this->data['country']) . ', `web_flags` = ' . (int) $this->data['web_flags'] . ', ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays` = ' . (int) $this->data['premdays'] . ',' : '') . '`' . $field . '` = ' . (int) $this->data[$field] . ' WHERE `id` = ' . $this->data['id']);
$this->db->exec('UPDATE `accounts` SET ' . ($this->db->hasColumn('accounts', 'name') ? '`name` = ' . $this->db->quote($this->data['name']) . ',' : '') . '`password` = ' . $this->db->quote($this->data['password']) . ', `email` = ' . $this->db->quote($this->data['email']) . ', `blocked` = ' . (int) $this->data['blocked'] . ', `rlname` = ' . $this->db->quote($this->data['rlname']) . ', `location` = ' . $this->db->quote($this->data['location']) . ', `country` = ' . $this->db->quote($this->data['country']) . ', `web_flags` = ' . (int) $this->data['web_flags'] . ', ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays` = ' . (int) $this->data['premdays'] . ',' : '') . '`' . $field . '` = ' . (int) $this->data[$field] . ' WHERE `id` = ' . $this->data['id']);
}
/**
@@ -650,6 +650,53 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
$this->data['email'] = (string) $email;
}
/**
* Checks if account is blocked.
*
* <p>
* Note: Since 0.0.3 version this method throws {@link E_OTS_NotLoaded E_OTS_NotLoaded} exception instead of triggering E_USER_WARNING.
* </p>
*
* @version 0.0.3
* @return bool Blocked state.
* @throws E_OTS_NotLoaded If account is not loaded.
*/
public function isBlocked()
{
if( !isset($this->data['blocked']) )
{
throw new E_OTS_NotLoaded();
}
return $this->data['blocked'];
}
/**
* Unblocks account.
*
* <p>
* This method only updates object state. To save changes in database you need to use {@link OTS_Account::save() save() method} to flush changed to database.
* </p>
*/
public function unblock()
{
$this->data['blocked'] = false;
}
/**
* Blocks account.
*
* <p>
* This method only updates object state. To save changes in databaseed to use {@link OTS_Account::save() save() method} to flush changed to database.
* </p>
*/
public function block()
{
$this->data['blocked'] = true;
}
/**
* Reads custom field.
*
@@ -994,7 +1041,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
$access = 0;
// finds ranks of all characters
foreach($this->getPlayersList(false) as $player)
foreach($this->getPlayersList() as $player)
{
$rank = $player->getRank();
@@ -1100,6 +1147,9 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
case 'playersList':
return $this->getPlayersList();
case 'blocked':
return $this->isBlocked();
case 'deleted':
return $this->isDeleted();
@@ -1145,6 +1195,17 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
$this->setPremiumEnd($value);
break;
case 'blocked':
if($value)
{
$this->block();
}
else
{
$this->unblock();
}
break;
case 'deleted':
if($value)
{
@@ -1198,3 +1259,5 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
}
/**#@-*/
?>

View File

@@ -34,3 +34,5 @@ class OTS_AccountBans_List extends OTS_Bans_List
$this->setFilter($filter);
}
}
?>

View File

@@ -735,3 +735,5 @@ class OTS_Admin
}
/**#@-*/
?>

View File

@@ -100,3 +100,5 @@ class OTS_Bans_List extends OTS_Base_List
}
}
}
?>

View File

@@ -265,3 +265,5 @@ abstract class OTS_Base_DB extends PDO implements IOTS_DB
}
/**#@-*/
?>

View File

@@ -146,3 +146,5 @@ class OTS_BinaryTools
}
/**#@-*/
?>

View File

@@ -149,3 +149,5 @@ class OTS_Container extends OTS_Item implements IteratorAggregate
}
/**#@-*/
?>

View File

@@ -357,3 +357,5 @@ class OTS_FileLoader
}
/**#@-*/
?>

View File

@@ -671,3 +671,5 @@ class OTS_Group extends OTS_Row_DAO implements IteratorAggregate, Countable
}
/**#@-*/
?>

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