init.php

main 336 lines · 13.3 KB Raw
Alex Alex Commit Initial commit 01/10/2026 09:20
1<?php
2if (PHP_VERSION_ID < 80100) {
3 die('PHP 8.1 or higher is required.');
4}
5
6if (!isset($GLOBALS['__znote_start_time'])) {
7 $GLOBALS['__znote_start_time'] = microtime(true);
8}
9$l_start = $GLOBALS['__znote_start_time'];
10$start = $GLOBALS['__znote_start_time'];
11
12$time = time();
13$version = (string)require __DIR__ . '/version.php';
14
15$aacQueries = 0;
16$accQueriesData = array();
17
18if (is_file(__DIR__ . '/../vendor/autoload.php')) {
19 require_once __DIR__ . '/../vendor/autoload.php';
20}
21
22ob_start();
23require_once 'config.php';
24require_once __DIR__ . '/session.php';
25require_once __DIR__ . '/security.php';
26znote_session_start((array)($config['session'] ?? array()));
27znote_security_boot((array)($config['security'] ?? array()));
28
29$sessionPrefix = $config['session_prefix'];
30
31if ($config['paypal']['enabled'] || $config['use_captcha']) {
32 $curlcheck = extension_loaded('curl');
33 if (!$curlcheck) die("php cURL is not enabled. It is required to for paypal or captcha services.<br>1. Find your php.ini file.<br>2. Uncomment extension=php_curl<br>Restart web server.<br><br><b>If you don't want this then disable paypal & use_captcha in config.php.</b>");
34}
35if ($config['use_captcha'] && !extension_loaded('openssl')) {
36 die("php openSSL is not enabled. It is required to for captcha services.<br>1. Find your php.ini file.<br>2. Uncomment extension=php_openssl<br>Restart web server.<br><br><b>If you don't want this then disable use_captcha in config.php.</b>");
37}
38
39// References ( & ) works as an alias for a variable,
40// they point to the same memmory, instead of duplicating it.
41if (!isset($config['TFSVersion'])) $config['TFSVersion'] = &$config['ServerEngine'];
42if (!isset($config['ServerEngine'])) $config['ServerEngine'] = &$config['TFSVersion'];
43
44$config['ServerEngineReal'] = $config['ServerEngine'];
45if (in_array($config['ServerEngineReal'], array('TFS_16', 'CANARY', 'BLACKTEK'), true)) {
46 $config['ServerEngine'] = 'TFS_10';
47 $config['TFSVersion'] = 'TFS_10';
48}
49if ($config['ServerEngineReal'] === 'CANARY') {
50 $config['twoFactorAuthenticator'] = false;
51}
52
53if (PHP_SAPI !== 'cli'
54 && !is_file(__DIR__ . '/../config.local.php')
55 && !is_file(__DIR__ . '/../install/installed.lock')
56 && is_file(__DIR__ . '/../install/index.php')
57) {
58 $znoteRoot = str_replace('\\', '/', (string)realpath(__DIR__ . '/..'));
59 $scriptDir = str_replace('\\', '/', (string)realpath(dirname((string)($_SERVER['SCRIPT_FILENAME'] ?? ''))));
60
61 $depth = 0;
62 if ($znoteRoot !== '' && $scriptDir !== '' && strpos($scriptDir . '/', $znoteRoot . '/') === 0) {
63 $below = trim(substr($scriptDir, strlen($znoteRoot)), '/');
64 $depth = ($below === '') ? 0 : count(explode('/', $below));
65 }
66
67 $segments = array_values(array_filter(explode('/', str_replace('\\', '/', dirname((string)($_SERVER['SCRIPT_NAME'] ?? '')))), 'strlen'));
68 if ($depth > 0) {
69 $segments = array_slice($segments, 0, max(0, count($segments) - $depth));
70 }
71
72 header('Location: ' . ($segments ? '/' . implode('/', $segments) : '') . '/install/');
73 exit;
74}
75
76require_once 'database/connect.php';
77require_once 'function/general.php';
78require_once 'function/translate.php';
79require_once 'function/bbcode.php';
80require_once 'function/users.php';
81require_once 'function/cache.php';
82require_once 'function/downloads.php';
83require_once 'function/mail.php';
84require_once 'function/token.php';
85require_once 'function/rfc6238.php';
86require_once 'function/twofa2.php';
87require_once __DIR__ . '/adapter/ServerAdapterInterface.php';
88require_once __DIR__ . '/adapter/TFSAdapter.php';
89require_once __DIR__ . '/adapter/CanaryAdapter.php';
90require_once __DIR__ . '/adapter/OtHireAdapter.php';
91require_once __DIR__ . '/adapter/BlackTekAdapter.php';
92require_once __DIR__ . '/adapter/factory.php';
93require_once 'function/itemparser/itemlistparser.php';
94require_once 'function/settings.php';
95require_once 'function/migrations.php';
96require_once 'function/backups.php';
97require_once 'function/health.php';
98require_once 'function/login_guard.php';
99require_once 'function/adminlog.php';
100require_once 'function/updater.php';
101require_once 'function/theme.php';
102require_once 'function/menus.php';
103require_once 'function/landing.php';
104require_once 'function/minimap.php';
105require_once 'function/serverdata.php';
106require_once 'function/serverdata_overrides.php';
107require_once 'function/plugins.php';
108require_once 'function/scheduler.php';
109require_once 'function/plugin_settings.php';
110require_once 'function/loginwebservice.php';
111require_once 'function/payments.php';
112
113// Settings saved from the admin panel override the values in config.php.
114znote_apply_settings();
115znote_security_boot((array)($config['security'] ?? array()));
116
117// Local item-image passthrough: when $config['shop']['imageServer'] points at a
118// disk folder, serve <folder>/<id>.<png|gif|jpg|...> straight from PHP. Placed
119// after znote_apply_settings() so the admin-panel value wins over config.php.
120if (isset($_GET['znote_item_img'])) {
121 while (ob_get_level() > 0) ob_end_clean();
122 $zii_id = (int) $_GET['znote_item_img'];
123 $zii_dir = function_exists('znote_item_image_dir') ? znote_item_image_dir() : '';
124 if ($zii_dir === '' || $zii_id <= 0) { http_response_code(404); exit; }
125 $zii_cfg = strtolower(preg_replace('/[^a-z0-9]/i', '', (string) ($config['shop']['imageType'] ?? '')));
126 $zii_exts = array_values(array_unique(array_filter(array_merge(array($zii_cfg), array('png', 'gif', 'jpg', 'jpeg', 'webp')))));
127 $zii_file = '';
128 foreach ($zii_exts as $zii_e) {
129 $zii_p = $zii_dir . DIRECTORY_SEPARATOR . $zii_id . '.' . $zii_e;
130 if (is_file($zii_p)) { $zii_file = $zii_p; break; }
131 }
132 $zii_real = $zii_file !== '' ? realpath($zii_file) : false;
133 if ($zii_real === false || strncmp($zii_real, $zii_dir, strlen($zii_dir)) !== 0) { http_response_code(404); exit; }
134 $zii_mime = array('png' => 'image/png', 'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'webp' => 'image/webp');
135 $zii_x = strtolower(pathinfo($zii_real, PATHINFO_EXTENSION));
136 header('Content-Type: ' . ($zii_mime[$zii_x] ?? 'application/octet-stream'));
137 header('Content-Length: ' . (string) filesize($zii_real));
138 header('Cache-Control: public, max-age=86400');
139 header('X-Content-Type-Options: nosniff');
140 readfile($zii_real);
141 exit;
142}
143
144// Enabled plugins register their hooks here, once the database and settings
145// are available and before any page has done anything.
146znote_plugins_load();
147
148// The active theme's own config file (defines $follow, the countdown, ...).
149// Loaded here, at global scope, so shells, menus, widgets and views all see
150// those variables through $GLOBALS.
151$themeConfigFile = theme_file('layout_config.php');
152if ($themeConfigFile !== null) {
153 require_once $themeConfigFile;
154}
155
156
157if (!isset($_SESSION['token'])) {
158 Token::generate();
159}
160
161if (user_logged_in() === true && znote2fa_v2_enabled()) {
162 $currentTwoFactorSessionVersion = znote2fa_session_version((int)getSession('user_id'));
163 $sessionTwoFactorVersion = (int)($_SESSION['tfa2_sv'] ?? 1);
164
165 if ($sessionTwoFactorVersion !== $currentTwoFactorSessionVersion) {
166 // "Log out all devices" bumped the version stored for this account: this
167 // session was minted before that and no longer counts as logged in.
168 znote_session_destroy();
169 } else {
170 // Adopt sessions created before 2FA v2 existed. Treating their version as
171 // one means a later logout-all still invalidates them correctly.
172 $_SESSION['tfa2_sv'] = $currentTwoFactorSessionVersion;
173 }
174}
175
176if (user_logged_in() === true) {
177 $session_user_id = (int)getSession('user_id');
178 $user_data = user_data($session_user_id, 'id', 'name', 'password', 'email', 'premium_ends_at');
179 if (!is_array($user_data)) $user_data = array();
180 $user_data += array('id' => 0, 'name' => '', 'password' => '', 'email' => '', 'premium_ends_at' => 0);
181
182 $premiumLeft = (int)$user_data['premium_ends_at'] - time();
183 $user_data['premdays'] = ($premiumLeft > 0) ? floor($premiumLeft / 86400) : 0;
184
185 $user_znote_data = user_znote_account_data($session_user_id, 'ip', 'created', 'points', 'cooldown', 'flag' ,'active_email');
186 if (!is_array($user_znote_data)) $user_znote_data = array();
187 $user_znote_data += array('ip' => 0, 'created' => 0, 'points' => 0, 'cooldown' => 0, 'flag' => '', 'active_email' => 0);
188}
189// ---------------------------------------------------------------------------
190// Maintenance mode
191//
192// Checked here, after the session is up, so is_admin() is available: an admin
193// browsing a closed site sees it normally and can keep working. Everyone else
194// gets the message and nothing else - no queries, no layout, no theme.
195// ---------------------------------------------------------------------------
196$updateMaintenance = is_file(__DIR__ . '/update/maintenance.lock');
197if (!empty($config['maintenance']) || $updateMaintenance) {
198 $maintenanceAdmin = (user_logged_in() === true) && isset($user_data) && is_admin($user_data);
199
200 // The admin panel is always reachable, otherwise you could lock yourself
201 // out of the switch that turns this off.
202 $maintenanceScript = basename($_SERVER['SCRIPT_NAME'] ?? '');
203 $maintenanceExempt = in_array($maintenanceScript, array('login.php', 'logout.php'), true)
204 || strpos((string)($_SERVER['SCRIPT_NAME'] ?? ''), '/admin/') !== false;
205
206 if (!$maintenanceAdmin && !$maintenanceExempt) {
207 http_response_code(503);
208 header('Retry-After: 3600');
209 ?><!DOCTYPE html>
210 <html lang="en"><head><meta charset="utf-8">
211 <meta name="viewport" content="width=device-width, initial-scale=1">
212 <title><?= htmlspecialchars($config['site_title'], ENT_QUOTES, 'UTF-8') ?></title>
213 <style>
214 body{margin:0;min-height:100vh;display:grid;place-items:center;background:#14181f;color:#dfe4ec;
215 font:16px/1.6 system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;padding:24px}
216 .box{max-width:520px;text-align:center}
217 h1{font-size:22px;margin:0 0 14px}
218 p{color:#93a0b2;margin:0 0 18px}
219 a{color:#d1a233}
220 </style></head><body>
221 <div class="box">
222 <h1><?= htmlspecialchars($config['site_title'], ENT_QUOTES, 'UTF-8') ?></h1>
223 <p><?= nl2br(htmlspecialchars($updateMaintenance ? 'ZnoteX is being updated. Please come back shortly.' : (string)$config['maintenance_message'], ENT_QUOTES, 'UTF-8')) ?></p>
224 <p><a href="login.php">Staff login</a></p>
225 </div></body></html><?php
226 exit;
227 }
228}
229
230$errors = array();
231// Log IP
232if ($config['log_ip']) {
233 $visitor_config = $config['ip_security'];
234
235 $flush = $config['flush_ip_logs'];
236 if ($flush != false) {
237 $timef = $time - $flush;
238 if (getCache() < $timef) {
239 $timef = $time - $visitor_config['time_period'];
240 db()->execute("DELETE FROM znote_visitors_details WHERE time <= ?", [$timef]);
241 setCache($time);
242 }
243 }
244
245 $visitor_data = znote_visitors_get_data();
246
247 znote_visitor_set_data($visitor_data); // update or insert data
248 znote_visitor_insert_detailed_data(0); // detailed data
249
250 $visitor_detailed = znote_visitors_get_detailed_data($visitor_config['time_period']);
251
252 // max activity
253 $v_activity = 0;
254 $v_register = 0;
255 $v_highscore = 0;
256 $v_c_char = 0;
257 $v_s_char = 0;
258 $v_form = 0;
259 foreach ((array)$visitor_detailed as $v_d) {
260 // Activity
261 if ($v_d['ip'] == getIPLong()) {
262 // count each type of visit
263 switch ($v_d['type']) {
264 case 0: // max activity
265 $v_activity++;
266 break;
267
268 case 1: // account registered
269 $v_register++;
270 $v_form++;
271 break;
272
273 case 2: // character creations
274 $v_c_char++;
275 $v_form++;
276 break;
277
278 case 3: // Highscore fetched
279 $v_highscore++;
280 $v_form++;
281 break;
282
283 case 4: // character searched
284 $v_s_char++;
285 $v_form++;
286 break;
287
288 case 5: // Other forms (login.?)
289 $v_form++;
290 break;
291 }
292
293 }
294 }
295
296 // Deny access if activity is too high
297 if ($v_activity > $visitor_config['max_activity']) die("Chill down. Your web activity is too big. max_activity");
298 if ($v_register > $visitor_config['max_account']) die("Chill down. You can't create multiple accounts that fast. max_account");
299 if ($v_c_char > $visitor_config['max_character']) die("Chill down. Your web activity is too big. max_character");
300 if ($v_form > $visitor_config['max_post']) die("Chill down. Your web activity is too big. max_post");
301
302 //var_dump($v_activity, $v_register, $v_highscore, $v_c_char, $v_s_char, $v_form);
303 //echo ' <--- IP logging activity past 10 seconds.';
304}
305
306// Sub page override system
307$filename = explode('/', $_SERVER['SCRIPT_NAME']);
308$filename = $filename[count($filename) - 1];
309$page_filename = str_replace('.php', '', $filename);
310if ($config['allowSubPages']) {
311 $subFile = theme_file('sub.php');
312 if ($subFile !== null) require_once $subFile;
313 if (isset($subpages) && !empty($subpages)) {
314 foreach ($subpages as $page) {
315 if ($page['override'] && $page['file'] === $filename) {
316 theme_open();
317 $subPage = theme_file('sub/'.$page['file']);
318 if ($subPage !== null) require_once $subPage;
319 theme_close();
320 exit;
321 }
322 }
323 } else {
324 ?>
325 <div style="background-color: white; padding: 20px; width: 100%; float:left;">
326 <h2 style="color: black;">Old layout!</h2>
327 <p style="color: black;">The layout is running an outdated sub system which is not compatible with this version of Znote AAC.</p>
328 <p style="color: black;">The file layouts/&lt;theme&gt;/sub.php is outdated.
329 <br>Please update it to look like <a style="color: orange;" target="_BLANK" href="https://github.com/Znote/ZnoteAAC/blob/master/layout/sub.php" >THIS.</a> (ZnoteX: layouts/https://github.com/Znote/ZnoteAAC/blob/master/layout/sub.phplt;themehttps://github.com/Znote/ZnoteAAC/blob/master/layout/sub.phpgt;/sub.php)<a href="">THIS.</a>
330 </p>
331 </div>
332 <?php
333 }
334}
335?>
336
Top