1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file has the hefty job of loading information for the forum. |
5
|
|
|
* |
6
|
|
|
* @name ElkArte Forum |
7
|
|
|
* @copyright ElkArte Forum contributors |
8
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause |
9
|
|
|
* |
10
|
|
|
* This file contains code covered by: |
11
|
|
|
* copyright: 2011 Simple Machines (http://www.simplemachines.org) |
12
|
|
|
* license: BSD, See included LICENSE.TXT for terms and conditions. |
13
|
|
|
* |
14
|
|
|
* @version 1.1.7 |
15
|
|
|
* |
16
|
|
|
*/ |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Load the $modSettings array and many necessary forum settings. |
20
|
|
|
* |
21
|
|
|
* What it does: |
22
|
|
|
* |
23
|
|
|
* - load the settings from cache if available, otherwise from the database. |
24
|
|
|
* - sets the timezone |
25
|
|
|
* - checks the load average settings if available. |
26
|
|
|
* - check whether post moderation is enabled. |
27
|
|
|
* - calls add_integration_function |
28
|
|
|
* - calls integrate_pre_include, integrate_pre_load, |
29
|
|
|
* |
30
|
|
|
* @event integrate_load_average is called if load average is enabled |
31
|
|
|
* @event integrate_pre_include to allow including files at startup |
32
|
|
|
* @event integrate_pre_load to call any pre load integration functions. |
33
|
|
|
* |
34
|
|
|
* @global array $modSettings is a giant array of all of the forum-wide settings and statistics. |
35
|
|
|
*/ |
36
|
|
|
function reloadSettings() |
37
|
|
|
{ |
38
|
|
|
global $modSettings; |
39
|
|
|
|
40
|
|
|
$db = database(); |
41
|
|
|
$cache = Cache::instance(); |
42
|
|
|
$hooks = Hooks::instance(); |
43
|
|
|
|
44
|
|
|
// Try to load it from the cache first; it'll never get cached if the setting is off. |
45
|
|
|
if (!$cache->getVar($modSettings, 'modSettings', 90)) |
46
|
|
|
{ |
47
|
|
|
$request = $db->query('', ' |
48
|
|
|
SELECT variable, value |
49
|
|
|
FROM {db_prefix}settings', |
50
|
|
|
array( |
51
|
|
|
) |
52
|
|
|
); |
53
|
|
|
$modSettings = array(); |
54
|
|
|
if (!$request) |
55
|
|
|
Errors::instance()->display_db_error(); |
56
|
|
|
while ($row = $db->fetch_row($request)) |
57
|
|
|
$modSettings[$row[0]] = $row[1]; |
58
|
|
|
$db->free_result($request); |
59
|
|
|
|
60
|
|
|
// Do a few things to protect against missing settings or settings with invalid values... |
61
|
|
|
if (empty($modSettings['defaultMaxTopics']) || $modSettings['defaultMaxTopics'] <= 0 || $modSettings['defaultMaxTopics'] > 999) |
62
|
|
|
$modSettings['defaultMaxTopics'] = 20; |
63
|
|
|
if (empty($modSettings['defaultMaxMessages']) || $modSettings['defaultMaxMessages'] <= 0 || $modSettings['defaultMaxMessages'] > 999) |
64
|
|
|
$modSettings['defaultMaxMessages'] = 15; |
65
|
|
|
if (empty($modSettings['defaultMaxMembers']) || $modSettings['defaultMaxMembers'] <= 0 || $modSettings['defaultMaxMembers'] > 999) |
66
|
|
|
$modSettings['defaultMaxMembers'] = 30; |
67
|
|
|
if (empty($modSettings['subject_length'])) |
68
|
|
|
$modSettings['subject_length'] = 24; |
69
|
|
|
|
70
|
|
|
$modSettings['warning_enable'] = $modSettings['warning_settings'][0]; |
71
|
|
|
|
72
|
|
|
// @deprecated since 1.1.0 - Just in case the upgrade script was run before B3 |
73
|
|
|
if (empty($modSettings['cal_limityear'])) |
74
|
|
|
{ |
75
|
|
|
$modSettings['cal_limityear'] = 10; |
76
|
|
|
updateSettings(array( |
77
|
|
|
'cal_limityear' => 10 |
78
|
|
|
)); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
$cache->put('modSettings', $modSettings, 90); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
$hooks->loadIntegrations(); |
85
|
|
|
|
86
|
|
|
// Setting the timezone is a requirement for some functions in PHP >= 5.1. |
87
|
|
|
if (isset($modSettings['default_timezone'])) |
88
|
|
|
date_default_timezone_set($modSettings['default_timezone']); |
89
|
|
|
|
90
|
|
|
// Check the load averages? |
91
|
|
|
if (!empty($modSettings['loadavg_enable'])) |
92
|
|
|
{ |
93
|
|
|
if (!$cache->getVar($modSettings['load_average'], 'loadavg', 90)) |
94
|
|
|
{ |
95
|
|
|
require_once(SUBSDIR . '/Server.subs.php'); |
96
|
|
|
$modSettings['load_average'] = detectServerLoad(); |
97
|
|
|
|
98
|
|
|
$cache->put('loadavg', $modSettings['load_average'], 90); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
if ($modSettings['load_average'] !== false) |
102
|
|
|
call_integration_hook('integrate_load_average', array($modSettings['load_average'])); |
103
|
|
|
|
104
|
|
|
// Let's have at least a zero |
105
|
|
|
if (empty($modSettings['loadavg_forum']) || $modSettings['load_average'] === false) |
106
|
|
|
$modSettings['current_load'] = 0; |
107
|
|
|
else |
108
|
|
|
$modSettings['current_load'] = $modSettings['load_average']; |
109
|
|
|
|
110
|
|
|
if (!empty($modSettings['loadavg_forum']) && $modSettings['current_load'] >= $modSettings['loadavg_forum']) |
111
|
|
|
Errors::instance()->display_loadavg_error(); |
112
|
|
|
} |
113
|
|
|
else |
114
|
|
|
$modSettings['current_load'] = 0; |
115
|
|
|
|
116
|
|
|
// Is post moderation alive and well? |
117
|
|
|
$modSettings['postmod_active'] = isset($modSettings['admin_features']) ? in_array('pm', explode(',', $modSettings['admin_features'])) : true; |
118
|
|
|
|
119
|
|
|
// @deprecated since 1.0.6 compatibility setting for migration |
120
|
|
|
if (!isset($modSettings['avatar_max_height'])) |
121
|
|
|
{ |
122
|
|
|
$modSettings['avatar_max_height'] = isset($modSettings['avatar_max_height_external']) ? $modSettings['avatar_max_height_external'] : 65; |
123
|
|
|
} |
124
|
|
|
if (!isset($modSettings['avatar_max_width'])) |
125
|
|
|
{ |
126
|
|
|
$modSettings['avatar_max_width'] = isset($modSettings['avatar_max_width_external']) ? $modSettings['avatar_max_width_external'] : 65; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
if (!isset($_SERVER['HTTPS']) || strtolower($_SERVER['HTTPS']) == 'off') |
130
|
|
|
{ |
131
|
|
|
$modSettings['secureCookies'] = 0; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
// Here to justify the name of this function. :P |
135
|
|
|
// It should be added to the install and upgrade scripts. |
136
|
|
|
// But since the converters need to be updated also. This is easier. |
137
|
|
|
if (empty($modSettings['currentAttachmentUploadDir'])) |
138
|
|
|
{ |
139
|
|
|
updateSettings(array( |
140
|
|
|
'attachmentUploadDir' => serialize(array(1 => $modSettings['attachmentUploadDir'])), |
141
|
|
|
'currentAttachmentUploadDir' => 1, |
142
|
|
|
)); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
// Integration is cool. |
146
|
|
|
if (defined('ELK_INTEGRATION_SETTINGS')) |
147
|
|
|
{ |
148
|
|
|
$integration_settings = Util::unserialize(ELK_INTEGRATION_SETTINGS); |
|
|
|
|
149
|
|
|
foreach ($integration_settings as $hook => $function) |
150
|
|
|
add_integration_function($hook, $function); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
// Any files to pre include? |
154
|
|
|
call_integration_include_hook('integrate_pre_include'); |
155
|
|
|
|
156
|
|
|
// Call pre load integration functions. |
157
|
|
|
call_integration_hook('integrate_pre_load'); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Load all the important user information. |
162
|
|
|
* |
163
|
|
|
* What it does: |
164
|
|
|
* |
165
|
|
|
* - sets up the $user_info array |
166
|
|
|
* - assigns $user_info['query_wanna_see_board'] for what boards the user can see. |
167
|
|
|
* - first checks for cookie or integration validation. |
168
|
|
|
* - uses the current session if no integration function or cookie is found. |
169
|
|
|
* - checks password length, if member is activated and the login span isn't over. |
170
|
|
|
* - if validation fails for the user, $id_member is set to 0. |
171
|
|
|
* - updates the last visit time when needed. |
172
|
|
|
* |
173
|
|
|
* @event integrate_verify_user allow for integration to verify a user |
174
|
|
|
* @event integrate_user_info to allow for adding to $user_info array |
175
|
|
|
*/ |
176
|
|
|
function loadUserSettings() |
177
|
|
|
{ |
178
|
|
|
global $context, $modSettings, $user_settings, $cookiename, $user_info, $language; |
179
|
|
|
|
180
|
|
|
$db = database(); |
181
|
|
|
$cache = Cache::instance(); |
182
|
|
|
|
183
|
|
|
// Check first the integration, then the cookie, and last the session. |
184
|
|
|
if (count($integration_ids = call_integration_hook('integrate_verify_user')) > 0) |
185
|
|
|
{ |
186
|
|
|
$id_member = 0; |
187
|
|
|
foreach ($integration_ids as $integration_id) |
188
|
|
|
{ |
189
|
|
|
$integration_id = (int) $integration_id; |
190
|
|
|
if ($integration_id > 0) |
191
|
|
|
{ |
192
|
|
|
$id_member = $integration_id; |
193
|
|
|
$already_verified = true; |
194
|
|
|
break; |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
} |
198
|
|
|
else |
199
|
|
|
$id_member = 0; |
200
|
|
|
|
201
|
|
|
// We'll need IPs and user agent and stuff, they came to visit us with! |
202
|
|
|
$req = request(); |
203
|
|
|
|
204
|
|
|
if (empty($id_member) && isset($_COOKIE[$cookiename])) |
205
|
|
|
{ |
206
|
|
|
list ($id_member, $password) = serializeToJson($_COOKIE[$cookiename], function ($array_from) use ($cookiename) { |
207
|
|
|
global $modSettings; |
208
|
|
|
|
209
|
|
|
require_once(SUBSDIR . '/Auth.subs.php'); |
210
|
|
|
$_COOKIE[$cookiename] = json_encode($array_from); |
211
|
|
|
setLoginCookie(60 * $modSettings['cookieTime'], $array_from[0], $array_from[1]); |
212
|
|
|
}); |
213
|
|
|
$id_member = !empty($id_member) && strlen($password) > 0 ? (int) $id_member : 0; |
214
|
|
|
} |
215
|
|
|
elseif (empty($id_member) && isset($_SESSION['login_' . $cookiename]) && (!empty($modSettings['disableCheckUA']) || $_SESSION['USER_AGENT'] == $req->user_agent())) |
216
|
|
|
{ |
217
|
|
|
// @todo Perhaps we can do some more checking on this, such as on the first octet of the IP? |
218
|
|
|
list ($id_member, $password, $login_span) = serializeToJson($_SESSION['login_' . $cookiename], function ($array_from) use ($cookiename) { |
219
|
|
|
$_SESSION['login_' . $cookiename] = json_encode($array_from); |
220
|
|
|
}); |
221
|
|
|
$id_member = !empty($id_member) && strlen($password) == 64 && $login_span > time() ? (int) $id_member : 0; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
// Only load this stuff if the user isn't a guest. |
225
|
|
|
if ($id_member != 0) |
226
|
|
|
{ |
227
|
|
|
// Is the member data cached? |
228
|
|
|
if ($cache->levelLowerThan(2) || $cache->getVar($user_settings, 'user_settings-' . $id_member, 60) === false) |
229
|
|
|
{ |
230
|
|
|
$this_user = $db->fetchQuery(' |
231
|
|
|
SELECT mem.*, COALESCE(a.id_attach, 0) AS id_attach, a.filename, a.attachment_type |
232
|
|
|
FROM {db_prefix}members AS mem |
233
|
|
|
LEFT JOIN {db_prefix}attachments AS a ON (a.id_member = {int:id_member}) |
234
|
|
|
WHERE mem.id_member = {int:id_member} |
235
|
|
|
LIMIT 1', |
236
|
|
|
array( |
237
|
|
|
'id_member' => $id_member, |
238
|
|
|
) |
239
|
|
|
); |
240
|
|
|
|
241
|
|
|
if (!empty($this_user)) |
242
|
|
|
{ |
243
|
|
|
list ($user_settings) = $this_user; |
244
|
|
|
|
245
|
|
|
// Make the ID specifically an integer |
246
|
|
|
$user_settings['id_member'] = (int) $user_settings['id_member']; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
if ($cache->levelHigherThan(1)) |
250
|
|
|
$cache->put('user_settings-' . $id_member, $user_settings, 60); |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
// Did we find 'im? If not, junk it. |
254
|
|
|
if (!empty($user_settings)) |
255
|
|
|
{ |
256
|
|
|
// As much as the password should be right, we can assume the integration set things up. |
257
|
|
|
if (!empty($already_verified) && $already_verified === true) |
258
|
|
|
$check = true; |
259
|
|
|
// SHA-256 passwords should be 64 characters long. |
260
|
|
|
elseif (strlen($password) == 64) |
|
|
|
|
261
|
|
|
$check = hash('sha256', ($user_settings['passwd'] . $user_settings['password_salt'])) == $password; |
262
|
|
|
else |
263
|
|
|
$check = false; |
264
|
|
|
|
265
|
|
|
// Wrong password or not activated - either way, you're going nowhere. |
266
|
|
|
$id_member = $check && ($user_settings['is_activated'] == 1 || $user_settings['is_activated'] == 11) ? (int) $user_settings['id_member'] : 0; |
267
|
|
|
} |
268
|
|
|
else |
269
|
|
|
$id_member = 0; |
270
|
|
|
|
271
|
|
|
// If we no longer have the member maybe they're being all hackey, stop brute force! |
272
|
|
|
if (!$id_member) |
273
|
|
|
validatePasswordFlood(!empty($user_settings['id_member']) ? $user_settings['id_member'] : $id_member, !empty($user_settings['passwd_flood']) ? $user_settings['passwd_flood'] : false, $id_member != 0); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
// Found 'im, let's set up the variables. |
277
|
|
|
if ($id_member != 0) |
278
|
|
|
{ |
279
|
|
|
// Let's not update the last visit time in these cases... |
280
|
|
|
// 1. SSI doesn't count as visiting the forum. |
281
|
|
|
// 2. RSS feeds and XMLHTTP requests don't count either. |
282
|
|
|
// 3. If it was set within this session, no need to set it again. |
283
|
|
|
// 4. New session, yet updated < five hours ago? Maybe cache can help. |
284
|
|
|
if (ELK != 'SSI' && !isset($_REQUEST['xml']) && (!isset($_REQUEST['action']) || $_REQUEST['action'] != '.xml') && empty($_SESSION['id_msg_last_visit']) && (!$cache->isEnabled() || !$cache->getVar($_SESSION['id_msg_last_visit'], 'user_last_visit-' . $id_member, 5 * 3600))) |
|
|
|
|
285
|
|
|
{ |
286
|
|
|
// @todo can this be cached? |
287
|
|
|
// Do a quick query to make sure this isn't a mistake. |
288
|
|
|
require_once(SUBSDIR . '/Messages.subs.php'); |
289
|
|
|
$visitOpt = basicMessageInfo($user_settings['id_msg_last_visit'], true); |
290
|
|
|
|
291
|
|
|
$_SESSION['id_msg_last_visit'] = $user_settings['id_msg_last_visit']; |
292
|
|
|
|
293
|
|
|
// If it was *at least* five hours ago... |
294
|
|
|
if ($visitOpt === false || $visitOpt['poster_time'] < time() - 5 * 3600) |
295
|
|
|
{ |
296
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
297
|
|
|
updateMemberData($id_member, array('id_msg_last_visit' => (int) $modSettings['maxMsgID'], 'last_login' => time(), 'member_ip' => $req->client_ip(), 'member_ip2' => $req->ban_ip())); |
298
|
|
|
$user_settings['last_login'] = time(); |
299
|
|
|
|
300
|
|
|
if ($cache->levelHigherThan(1)) |
301
|
|
|
$cache->put('user_settings-' . $id_member, $user_settings, 60); |
302
|
|
|
|
303
|
|
|
$cache->put('user_last_visit-' . $id_member, $_SESSION['id_msg_last_visit'], 5 * 3600); |
304
|
|
|
} |
305
|
|
|
} |
306
|
|
|
elseif (empty($_SESSION['id_msg_last_visit'])) |
307
|
|
|
$_SESSION['id_msg_last_visit'] = $user_settings['id_msg_last_visit']; |
308
|
|
|
|
309
|
|
|
$username = $user_settings['member_name']; |
310
|
|
|
|
311
|
|
|
if (empty($user_settings['additional_groups'])) |
312
|
|
|
$user_info = array( |
313
|
|
|
'groups' => array($user_settings['id_group'], $user_settings['id_post_group']) |
314
|
|
|
); |
315
|
|
|
else |
316
|
|
|
$user_info = array( |
317
|
|
|
'groups' => array_merge( |
318
|
|
|
array($user_settings['id_group'], $user_settings['id_post_group']), |
319
|
|
|
explode(',', $user_settings['additional_groups']) |
320
|
|
|
) |
321
|
|
|
); |
322
|
|
|
|
323
|
|
|
// Because history has proven that it is possible for groups to go bad - clean up in case. |
324
|
|
|
foreach ($user_info['groups'] as $k => $v) |
325
|
|
|
$user_info['groups'][$k] = (int) $v; |
326
|
|
|
|
327
|
|
|
// This is a logged in user, so definitely not a spider. |
328
|
|
|
$user_info['possibly_robot'] = false; |
329
|
|
|
|
330
|
|
|
// Lets upgrade the salt if needed. |
331
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
332
|
|
|
if (updateMemberSalt($id_member)) |
333
|
|
|
{ |
334
|
|
|
require_once(SUBSDIR . '/Auth.subs.php'); |
335
|
|
|
setLoginCookie(60 * $modSettings['cookieTime'], $user_settings['id_member'], hash('sha256', ($user_settings['passwd'] . $user_settings['password_salt']))); |
336
|
|
|
} |
337
|
|
|
} |
338
|
|
|
// If the user is a guest, initialize all the critical user settings. |
339
|
|
|
else |
340
|
|
|
{ |
341
|
|
|
// This is what a guest's variables should be. |
342
|
|
|
$username = ''; |
343
|
|
|
$user_info = array('groups' => array(-1)); |
344
|
|
|
$user_settings = array(); |
345
|
|
|
|
346
|
|
|
if (isset($_COOKIE[$cookiename])) |
347
|
|
|
$_COOKIE[$cookiename] = ''; |
348
|
|
|
|
349
|
|
|
// Create a login token if it doesn't exist yet. |
350
|
|
|
if (!isset($_SESSION['token']['post-login'])) |
351
|
|
|
createToken('login'); |
352
|
|
|
else |
353
|
|
|
list ($context['login_token_var'],,, $context['login_token']) = $_SESSION['token']['post-login']; |
354
|
|
|
|
355
|
|
|
// Do we perhaps think this is a search robot? Check every five minutes just in case... |
356
|
|
|
if ((!empty($modSettings['spider_mode']) || !empty($modSettings['spider_group'])) && (!isset($_SESSION['robot_check']) || $_SESSION['robot_check'] < time() - 300)) |
357
|
|
|
{ |
358
|
|
|
require_once(SUBSDIR . '/SearchEngines.subs.php'); |
359
|
|
|
$user_info['possibly_robot'] = spiderCheck(); |
360
|
|
|
} |
361
|
|
|
elseif (!empty($modSettings['spider_mode'])) |
362
|
|
|
$user_info['possibly_robot'] = isset($_SESSION['id_robot']) ? $_SESSION['id_robot'] : 0; |
363
|
|
|
// If we haven't turned on proper spider hunts then have a guess! |
364
|
|
|
else |
365
|
|
|
{ |
366
|
|
|
$ci_user_agent = strtolower($req->user_agent()); |
367
|
|
|
$user_info['possibly_robot'] = (strpos($ci_user_agent, 'mozilla') === false && strpos($ci_user_agent, 'opera') === false) || preg_match('~(googlebot|slurp|crawl|msnbot|yandex|bingbot|baidu)~u', $ci_user_agent) == 1; |
368
|
|
|
} |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
// Set up the $user_info array. |
372
|
|
|
$user_info += array( |
373
|
|
|
'id' => $id_member, |
374
|
|
|
'username' => $username, |
375
|
|
|
'name' => isset($user_settings['real_name']) ? $user_settings['real_name'] : '', |
376
|
|
|
'email' => isset($user_settings['email_address']) ? $user_settings['email_address'] : '', |
377
|
|
|
'passwd' => isset($user_settings['passwd']) ? $user_settings['passwd'] : '', |
378
|
|
|
'language' => empty($user_settings['lngfile']) || empty($modSettings['userLanguage']) ? $language : $user_settings['lngfile'], |
379
|
|
|
'is_guest' => $id_member == 0, |
380
|
|
|
'is_admin' => in_array(1, $user_info['groups']), |
381
|
|
|
'is_mod' => false, |
382
|
|
|
'theme' => empty($user_settings['id_theme']) ? 0 : $user_settings['id_theme'], |
383
|
|
|
'last_login' => empty($user_settings['last_login']) ? 0 : $user_settings['last_login'], |
384
|
|
|
'ip' => $req->client_ip(), |
385
|
|
|
'ip2' => $req->ban_ip(), |
386
|
|
|
'posts' => empty($user_settings['posts']) ? 0 : $user_settings['posts'], |
387
|
|
|
'time_format' => empty($user_settings['time_format']) ? $modSettings['time_format'] : $user_settings['time_format'], |
388
|
|
|
'time_offset' => empty($user_settings['time_offset']) ? 0 : $user_settings['time_offset'], |
389
|
|
|
'avatar' => array_merge(array( |
390
|
|
|
'url' => isset($user_settings['avatar']) ? $user_settings['avatar'] : '', |
391
|
|
|
'filename' => empty($user_settings['filename']) ? '' : $user_settings['filename'], |
392
|
|
|
'custom_dir' => !empty($user_settings['attachment_type']) && $user_settings['attachment_type'] == 1, |
393
|
|
|
'id_attach' => isset($user_settings['id_attach']) ? $user_settings['id_attach'] : 0 |
394
|
|
|
), determineAvatar($user_settings)), |
395
|
|
|
'smiley_set' => isset($user_settings['smiley_set']) ? $user_settings['smiley_set'] : '', |
396
|
|
|
'messages' => empty($user_settings['personal_messages']) ? 0 : $user_settings['personal_messages'], |
397
|
|
|
'mentions' => empty($user_settings['mentions']) ? 0 : max(0, $user_settings['mentions']), |
398
|
|
|
'unread_messages' => empty($user_settings['unread_messages']) ? 0 : $user_settings['unread_messages'], |
399
|
|
|
'total_time_logged_in' => empty($user_settings['total_time_logged_in']) ? 0 : $user_settings['total_time_logged_in'], |
400
|
|
|
'buddies' => !empty($modSettings['enable_buddylist']) && !empty($user_settings['buddy_list']) ? explode(',', $user_settings['buddy_list']) : array(), |
401
|
|
|
'ignoreboards' => !empty($user_settings['ignore_boards']) && !empty($modSettings['allow_ignore_boards']) ? explode(',', $user_settings['ignore_boards']) : array(), |
402
|
|
|
'ignoreusers' => !empty($user_settings['pm_ignore_list']) ? explode(',', $user_settings['pm_ignore_list']) : array(), |
403
|
|
|
'warning' => isset($user_settings['warning']) ? $user_settings['warning'] : 0, |
404
|
|
|
'permissions' => array(), |
405
|
|
|
); |
406
|
|
|
$user_info['groups'] = array_unique($user_info['groups']); |
407
|
|
|
|
408
|
|
|
// Make sure that the last item in the ignore boards array is valid. If the list was too long it could have an ending comma that could cause problems. |
409
|
|
|
if (!empty($user_info['ignoreboards']) && empty($user_info['ignoreboards'][$tmp = count($user_info['ignoreboards']) - 1])) |
410
|
|
|
unset($user_info['ignoreboards'][$tmp]); |
411
|
|
|
|
412
|
|
|
// Do we have any languages to validate this? |
413
|
|
|
if (!empty($modSettings['userLanguage']) && (!empty($_GET['language']) || !empty($_SESSION['language']))) |
414
|
|
|
$languages = getLanguages(); |
415
|
|
|
|
416
|
|
|
// Allow the user to change their language if its valid. |
417
|
|
|
if (!empty($modSettings['userLanguage']) && !empty($_GET['language']) && isset($languages[strtr($_GET['language'], './\\:', '____')])) |
418
|
|
|
{ |
419
|
|
|
$user_info['language'] = strtr($_GET['language'], './\\:', '____'); |
420
|
|
|
$_SESSION['language'] = $user_info['language']; |
421
|
|
|
} |
422
|
|
|
elseif (!empty($modSettings['userLanguage']) && !empty($_SESSION['language']) && isset($languages[strtr($_SESSION['language'], './\\:', '____')])) |
423
|
|
|
$user_info['language'] = strtr($_SESSION['language'], './\\:', '____'); |
424
|
|
|
|
425
|
|
|
// Just build this here, it makes it easier to change/use - administrators can see all boards. |
426
|
|
|
if ($user_info['is_admin']) |
427
|
|
|
$user_info['query_see_board'] = '1=1'; |
428
|
|
|
// Otherwise just the groups in $user_info['groups']. |
429
|
|
|
else |
430
|
|
|
$user_info['query_see_board'] = '((FIND_IN_SET(' . implode(', b.member_groups) != 0 OR FIND_IN_SET(', $user_info['groups']) . ', b.member_groups) != 0)' . (!empty($modSettings['deny_boards_access']) ? ' AND (FIND_IN_SET(' . implode(', b.deny_member_groups) = 0 AND FIND_IN_SET(', $user_info['groups']) . ', b.deny_member_groups) = 0)' : '') . (isset($user_info['mod_cache']) ? ' OR ' . $user_info['mod_cache']['mq'] : '') . ')'; |
431
|
|
|
// Build the list of boards they WANT to see. |
432
|
|
|
// This will take the place of query_see_boards in certain spots, so it better include the boards they can see also |
433
|
|
|
|
434
|
|
|
// If they aren't ignoring any boards then they want to see all the boards they can see |
435
|
|
|
if (empty($user_info['ignoreboards'])) |
436
|
|
|
$user_info['query_wanna_see_board'] = $user_info['query_see_board']; |
437
|
|
|
// Ok I guess they don't want to see all the boards |
438
|
|
|
else |
439
|
|
|
$user_info['query_wanna_see_board'] = '(' . $user_info['query_see_board'] . ' AND b.id_board NOT IN (' . implode(',', $user_info['ignoreboards']) . '))'; |
440
|
|
|
|
441
|
|
|
if ($user_info['is_guest'] === false) |
442
|
|
|
{ |
443
|
|
|
$http_request = HttpReq::instance(); |
444
|
|
|
if (!empty($modSettings['force_accept_agreement'])) |
445
|
|
|
{ |
446
|
|
|
if (!empty($modSettings['agreementRevision']) && !empty($modSettings['requireAgreement']) && in_array($http_request->action, array('reminder', 'register')) === false) |
|
|
|
|
447
|
|
|
{ |
448
|
|
|
if ($http_request->action !== 'profile' || $http_request->area !== 'deleteaccount') |
|
|
|
|
449
|
|
|
{ |
450
|
|
|
$agreement = new \Agreement($user_info['language']); |
451
|
|
|
if (false === $agreement->checkAccepted($id_member, $modSettings['agreementRevision'])) |
452
|
|
|
{ |
453
|
|
|
setOldUrl('agreement_url_redirect'); |
454
|
|
|
redirectexit('action=register;sa=agreement'); |
455
|
|
|
} |
456
|
|
|
} |
457
|
|
|
} |
458
|
|
|
} |
459
|
|
|
if (!empty($modSettings['force_accept_privacy_policy'])) |
460
|
|
|
{ |
461
|
|
|
if (!empty($modSettings['privacypolicyRevision']) && !empty($modSettings['requirePrivacypolicy']) && in_array($http_request->action, array('reminder', 'register')) === false) |
462
|
|
|
{ |
463
|
|
|
if ($http_request->action !== 'profile' || $http_request->area !== 'deleteaccount') |
464
|
|
|
{ |
465
|
|
|
$privacypol = new \PrivacyPolicy($user_info['language']); |
466
|
|
|
if (false === $privacypol->checkAccepted($id_member, $modSettings['privacypolicyRevision'])) |
467
|
|
|
{ |
468
|
|
|
setOldUrl('agreement_url_redirect'); |
469
|
|
|
redirectexit('action=register;sa=privacypol'); |
470
|
|
|
} |
471
|
|
|
} |
472
|
|
|
} |
473
|
|
|
} |
474
|
|
|
} |
475
|
|
|
call_integration_hook('integrate_user_info'); |
476
|
|
|
} |
477
|
|
|
|
478
|
|
|
/** |
479
|
|
|
* Check for moderators and see if they have access to the board. |
480
|
|
|
* |
481
|
|
|
* What it does: |
482
|
|
|
* |
483
|
|
|
* - sets up the $board_info array for current board information. |
484
|
|
|
* - if cache is enabled, the $board_info array is stored in cache. |
485
|
|
|
* - redirects to appropriate post if only message id is requested. |
486
|
|
|
* - is only used when inside a topic or board. |
487
|
|
|
* - determines the local moderators for the board. |
488
|
|
|
* - adds group id 3 if the user is a local moderator for the board they are in. |
489
|
|
|
* - prevents access if user is not in proper group nor a local moderator of the board. |
490
|
|
|
* |
491
|
1 |
|
* @event integrate_load_board_query allows to add tables and columns to the query, used |
492
|
1 |
|
* to add to the $board_info array |
493
|
|
|
* @event integrate_loaded_board called after board_info is populated, allows to add |
494
|
1 |
|
* directly to $board_info |
495
|
1 |
|
* |
496
|
|
|
*/ |
497
|
|
|
function loadBoard() |
498
|
1 |
|
{ |
499
|
|
|
global $txt, $scripturl, $context, $modSettings; |
500
|
|
|
global $board_info, $board, $topic, $user_info; |
501
|
1 |
|
|
502
|
|
|
$db = database(); |
503
|
|
|
$cache = Cache::instance(); |
504
|
1 |
|
|
505
|
|
|
// Assume they are not a moderator. |
506
|
|
|
$user_info['is_mod'] = false; |
507
|
1 |
|
// @since 1.0.5 - is_mod takes into account only local (board) moderators, |
508
|
1 |
|
// and not global moderators, is_moderator is meant to take into account both. |
509
|
|
|
$user_info['is_moderator'] = false; |
510
|
|
|
|
511
|
|
|
// Start the linktree off empty.. |
512
|
|
|
$context['linktree'] = array(); |
513
|
|
|
|
514
|
|
|
// Have they by chance specified a message id but nothing else? |
515
|
|
|
if (empty($_REQUEST['action']) && empty($topic) && empty($board) && !empty($_REQUEST['msg'])) |
516
|
|
|
{ |
517
|
|
|
// Make sure the message id is really an int. |
518
|
|
|
$_REQUEST['msg'] = (int) $_REQUEST['msg']; |
519
|
|
|
|
520
|
|
|
// Looking through the message table can be slow, so try using the cache first. |
521
|
|
|
if (!$cache->getVar($topic, 'msg_topic-' . $_REQUEST['msg'], 120)) |
522
|
|
|
{ |
523
|
|
|
require_once(SUBSDIR . '/Messages.subs.php'); |
524
|
|
|
$topic = associatedTopic($_REQUEST['msg']); |
525
|
|
|
|
526
|
|
|
// So did it find anything? |
527
|
|
|
if ($topic !== false) |
528
|
|
|
{ |
529
|
|
|
// Save save save. |
530
|
|
|
$cache->put('msg_topic-' . $_REQUEST['msg'], $topic, 120); |
531
|
|
|
} |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
// Remember redirection is the key to avoiding fallout from your bosses. |
535
|
|
|
if (!empty($topic)) |
536
|
|
|
redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg']); |
537
|
|
|
else |
538
|
1 |
|
{ |
539
|
1 |
|
loadPermissions(); |
540
|
|
|
loadTheme(); |
541
|
|
|
throw new Elk_Exception('topic_gone', false); |
542
|
|
|
} |
543
|
|
|
} |
544
|
1 |
|
|
545
|
1 |
|
// Load this board only if it is specified. |
546
|
|
|
if (empty($board) && empty($topic)) |
547
|
|
|
{ |
548
|
|
|
$board_info = array('moderators' => array()); |
549
|
|
|
return; |
550
|
|
|
} |
551
|
|
|
|
552
|
|
|
if ($cache->isEnabled() && (empty($topic) || $cache->levelHigherThan(2))) |
553
|
|
|
{ |
554
|
|
|
// @todo SLOW? |
555
|
|
|
if (!empty($topic)) |
556
|
|
|
$temp = $cache->get('topic_board-' . $topic, 120); |
557
|
|
|
else |
558
|
|
|
$temp = $cache->get('board-' . $board, 120); |
559
|
1 |
|
|
560
|
1 |
|
if (!empty($temp)) |
561
|
1 |
|
{ |
562
|
1 |
|
$board_info = $temp; |
563
|
|
|
$board = (int) $board_info['id']; |
564
|
1 |
|
} |
565
|
|
|
} |
566
|
1 |
|
|
567
|
|
|
if (empty($temp)) |
568
|
|
|
{ |
569
|
|
|
$select_columns = array(); |
570
|
1 |
|
$select_tables = array(); |
571
|
|
|
// Wanna grab something more from the boards table or another table at all? |
572
|
1 |
|
call_integration_hook('integrate_load_board_query', array(&$select_columns, &$select_tables)); |
573
|
1 |
|
|
574
|
1 |
|
$request = $db->query('', ' |
575
|
1 |
|
SELECT |
576
|
|
|
c.id_cat, b.name AS bname, b.description, b.num_topics, b.member_groups, b.deny_member_groups, |
577
|
|
|
b.id_parent, c.name AS cname, COALESCE(mem.id_member, 0) AS id_moderator, |
578
|
|
|
mem.real_name' . (!empty($topic) ? ', b.id_board' : '') . ', b.child_level, |
579
|
1 |
|
b.id_theme, b.override_theme, b.count_posts, b.id_profile, b.redirect, |
580
|
|
|
b.unapproved_topics, b.unapproved_posts' . (!empty($topic) ? ', t.approved, t.id_member_started' : '') . (!empty($select_columns) ? ', ' . implode(', ', $select_columns) : '') . ' |
581
|
1 |
|
FROM {db_prefix}boards AS b' . (!empty($topic) ? ' |
582
|
1 |
|
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})' : '') . (!empty($select_tables) ? ' |
583
|
|
|
' . implode("\n\t\t\t\t", $select_tables) : '') . ' |
584
|
1 |
|
LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) |
585
|
|
|
LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = {raw:board_link}) |
586
|
1 |
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member) |
587
|
1 |
|
WHERE b.id_board = {raw:board_link}', |
588
|
1 |
|
array( |
589
|
|
|
'current_topic' => $topic, |
590
|
|
|
'board_link' => empty($topic) ? $db->quote('{int:current_board}', array('current_board' => $board)) : 't.id_board', |
591
|
1 |
|
) |
592
|
1 |
|
); |
593
|
|
|
// If there aren't any, skip. |
594
|
|
|
if ($db->num_rows($request) > 0) |
595
|
|
|
{ |
596
|
1 |
|
$row = $db->fetch_assoc($request); |
597
|
1 |
|
|
598
|
|
|
// Set the current board. |
599
|
1 |
|
if (!empty($row['id_board'])) |
600
|
1 |
|
$board = (int) $row['id_board']; |
601
|
1 |
|
|
602
|
1 |
|
// Basic operating information. (globals... :/) |
603
|
1 |
|
$board_info = array( |
604
|
1 |
|
'id' => $board, |
605
|
1 |
|
'moderators' => array(), |
606
|
1 |
|
'cat' => array( |
607
|
1 |
|
'id' => $row['id_cat'], |
608
|
1 |
|
'name' => $row['cname'] |
609
|
1 |
|
), |
610
|
1 |
|
'name' => $row['bname'], |
611
|
1 |
|
'raw_description' => $row['description'], |
612
|
1 |
|
'description' => $row['description'], |
613
|
1 |
|
'num_topics' => $row['num_topics'], |
614
|
1 |
|
'unapproved_topics' => $row['unapproved_topics'], |
615
|
1 |
|
'unapproved_posts' => $row['unapproved_posts'], |
616
|
1 |
|
'unapproved_user_topics' => 0, |
617
|
1 |
|
'parent_boards' => getBoardParents($row['id_parent']), |
618
|
1 |
|
'parent' => $row['id_parent'], |
619
|
1 |
|
'child_level' => $row['child_level'], |
620
|
|
|
'theme' => $row['id_theme'], |
621
|
|
|
'override_theme' => !empty($row['override_theme']), |
622
|
1 |
|
'profile' => $row['id_profile'], |
623
|
1 |
|
'redirect' => $row['redirect'], |
624
|
|
|
'posts_count' => empty($row['count_posts']), |
625
|
1 |
|
'cur_topic_approved' => empty($topic) || $row['approved'], |
626
|
|
|
'cur_topic_starter' => empty($topic) ? 0 : $row['id_member_started'], |
627
|
|
|
); |
628
|
|
|
|
629
|
1 |
|
// Load the membergroups allowed, and check permissions. |
630
|
1 |
|
$board_info['groups'] = $row['member_groups'] == '' ? array() : explode(',', $row['member_groups']); |
631
|
|
|
$board_info['deny_groups'] = $row['deny_member_groups'] == '' ? array() : explode(',', $row['deny_member_groups']); |
632
|
|
|
|
633
|
|
|
call_integration_hook('integrate_loaded_board', array(&$board_info, &$row)); |
634
|
|
|
|
635
|
|
|
do |
636
|
|
|
{ |
637
|
1 |
|
if (!empty($row['id_moderator'])) |
638
|
|
|
$board_info['moderators'][$row['id_moderator']] = array( |
639
|
|
|
'id' => $row['id_moderator'], |
640
|
|
|
'name' => $row['real_name'], |
641
|
1 |
|
'href' => $scripturl . '?action=profile;u=' . $row['id_moderator'], |
642
|
1 |
|
'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_moderator'] . '">' . $row['real_name'] . '</a>' |
643
|
|
|
); |
644
|
|
|
} |
645
|
|
|
while ($row = $db->fetch_assoc($request)); |
646
|
|
|
|
647
|
|
|
// If the board only contains unapproved posts and the user can't approve then they can't see any topics. |
648
|
|
|
// If that is the case do an additional check to see if they have any topics waiting to be approved. |
649
|
|
|
if ($board_info['num_topics'] == 0 && $modSettings['postmod_active'] && !allowedTo('approve_posts')) |
650
|
|
|
{ |
651
|
|
|
// Free the previous result |
652
|
|
|
$db->free_result($request); |
653
|
|
|
|
654
|
|
|
// @todo why is this using id_topic? |
655
|
|
|
// @todo Can this get cached? |
656
|
|
|
$request = $db->query('', ' |
657
|
|
|
SELECT COUNT(id_topic) |
658
|
|
|
FROM {db_prefix}topics |
659
|
|
|
WHERE id_member_started={int:id_member} |
660
|
|
|
AND approved = {int:unapproved} |
661
|
|
|
AND id_board = {int:board}', |
662
|
|
|
array( |
663
|
|
|
'id_member' => $user_info['id'], |
664
|
1 |
|
'unapproved' => 0, |
665
|
1 |
|
'board' => $board, |
666
|
|
|
) |
667
|
|
|
); |
668
|
|
|
|
669
|
|
|
list ($board_info['unapproved_user_topics']) = $db->fetch_row($request); |
670
|
|
|
} |
671
|
1 |
|
|
672
|
|
|
if ($cache->isEnabled() && (empty($topic) || $cache->levelHigherThan(2))) |
673
|
|
|
{ |
674
|
|
|
// @todo SLOW? |
675
|
|
|
if (!empty($topic)) |
676
|
|
|
$cache->put('topic_board-' . $topic, $board_info, 120); |
677
|
|
|
$cache->put('board-' . $board, $board_info, 120); |
678
|
|
|
} |
679
|
|
|
} |
680
|
|
|
else |
681
|
|
|
{ |
682
|
1 |
|
// Otherwise the topic is invalid, there are no moderators, etc. |
683
|
1 |
|
$board_info = array( |
684
|
|
|
'moderators' => array(), |
685
|
1 |
|
'error' => 'exist' |
686
|
1 |
|
); |
687
|
|
|
$topic = null; |
688
|
1 |
|
$board = 0; |
689
|
1 |
|
} |
690
|
|
|
$db->free_result($request); |
691
|
1 |
|
} |
692
|
|
|
|
693
|
1 |
|
if (!empty($topic)) |
694
|
1 |
|
$_GET['board'] = (int) $board; |
695
|
1 |
|
|
696
|
1 |
|
if (!empty($board)) |
697
|
|
|
{ |
698
|
|
|
// Now check if the user is a moderator. |
699
|
1 |
|
$user_info['is_mod'] = isset($board_info['moderators'][$user_info['id']]); |
700
|
1 |
|
|
701
|
|
|
if (count(array_intersect($user_info['groups'], $board_info['groups'])) == 0 && !$user_info['is_admin']) |
702
|
1 |
|
$board_info['error'] = 'access'; |
703
|
1 |
|
if (!empty($modSettings['deny_boards_access']) && count(array_intersect($user_info['groups'], $board_info['deny_groups'])) != 0 && !$user_info['is_admin']) |
704
|
1 |
|
$board_info['error'] = 'access'; |
705
|
1 |
|
|
706
|
|
|
// Build up the linktree. |
707
|
1 |
|
$context['linktree'] = array_merge( |
708
|
1 |
|
$context['linktree'], |
709
|
1 |
|
array(array( |
710
|
1 |
|
'url' => $scripturl . $modSettings['default_forum_action'] . '#c' . $board_info['cat']['id'], |
711
|
1 |
|
'name' => $board_info['cat']['name'] |
712
|
|
|
)), |
713
|
|
|
array_reverse($board_info['parent_boards']), |
714
|
1 |
|
array(array( |
715
|
1 |
|
'url' => $scripturl . '?board=' . $board . '.0', |
716
|
1 |
|
'name' => $board_info['name'] |
717
|
1 |
|
)) |
718
|
|
|
); |
719
|
|
|
} |
720
|
1 |
|
|
721
|
1 |
|
// Set the template contextual information. |
722
|
|
|
$context['user']['is_mod'] = &$user_info['is_mod']; |
723
|
|
|
$context['user']['is_moderator'] = &$user_info['is_moderator']; |
724
|
|
|
$context['current_topic'] = $topic; |
725
|
|
|
$context['current_board'] = $board; |
726
|
|
|
|
727
|
|
|
// Hacker... you can't see this topic, I'll tell you that. (but moderators can!) |
728
|
|
|
if (!empty($board_info['error']) && (!empty($modSettings['deny_boards_access']) || $board_info['error'] != 'access' || !$user_info['is_moderator'])) |
729
|
|
|
{ |
730
|
|
|
// The permissions and theme need loading, just to make sure everything goes smoothly. |
731
|
|
|
loadPermissions(); |
732
|
|
|
loadTheme(); |
733
|
|
|
|
734
|
|
|
$_GET['board'] = ''; |
735
|
|
|
$_GET['topic'] = ''; |
736
|
|
|
|
737
|
|
|
// The linktree should not give the game away mate! |
738
|
|
|
$context['linktree'] = array( |
739
|
|
|
array( |
740
|
|
|
'url' => $scripturl, |
741
|
|
|
'name' => $context['forum_name_html_safe'] |
742
|
|
|
) |
743
|
|
|
); |
744
|
|
|
|
745
|
|
|
// If it's a prefetching agent, stop it |
746
|
|
|
stop_prefetching(); |
747
|
|
|
|
748
|
|
|
// If we're requesting an attachment. |
749
|
|
|
if (!empty($_REQUEST['action']) && $_REQUEST['action'] === 'dlattach') |
750
|
|
|
{ |
751
|
|
|
ob_end_clean(); |
752
|
|
|
header('HTTP/1.1 403 Forbidden'); |
753
|
|
|
exit; |
754
|
|
|
} |
755
|
|
|
elseif ($user_info['is_guest']) |
756
|
1 |
|
{ |
757
|
1 |
|
loadLanguage('Errors'); |
758
|
1 |
|
is_not_guest($txt['topic_gone']); |
759
|
|
|
} |
760
|
|
|
else |
761
|
|
|
throw new Elk_Exception('topic_gone', false); |
762
|
|
|
} |
763
|
|
|
|
764
|
|
|
if ($user_info['is_mod']) |
765
|
|
|
$user_info['groups'][] = 3; |
766
|
|
|
} |
767
|
|
|
|
768
|
|
|
/** |
769
|
|
|
* Load this user's permissions. |
770
|
|
|
* |
771
|
|
|
* What it does: |
772
|
|
|
* |
773
|
|
|
* - If the user is an admin, validate that they have not been banned. |
774
|
|
|
* - Attempt to load permissions from cache for cache level > 2 |
775
|
|
|
* - See if the user is possibly a robot and apply added permissions as needed |
776
|
|
|
* - Load permissions from the general permissions table. |
777
|
|
|
* - If inside a board load the necessary board permissions. |
778
|
|
|
* - If the user is not a guest, identify what other boards they have access to. |
779
|
|
|
*/ |
780
|
|
|
function loadPermissions() |
781
|
|
|
{ |
782
|
|
|
global $user_info, $board, $board_info, $modSettings; |
783
|
|
|
|
784
|
|
|
$db = database(); |
785
|
|
|
|
786
|
|
|
if ($user_info['is_admin']) |
787
|
|
|
{ |
788
|
|
|
banPermissions(); |
789
|
|
|
return; |
790
|
|
|
} |
791
|
|
|
|
792
|
|
|
$removals = array(); |
793
|
|
|
|
794
|
|
|
$cache = Cache::instance(); |
795
|
|
|
|
796
|
|
|
if ($cache->isEnabled()) |
797
|
|
|
{ |
798
|
|
|
$cache_groups = $user_info['groups']; |
799
|
|
|
asort($cache_groups); |
800
|
|
|
$cache_groups = implode(',', $cache_groups); |
801
|
|
|
|
802
|
|
|
// If it's a spider then cache it different. |
803
|
|
|
if ($user_info['possibly_robot']) |
804
|
|
|
$cache_groups .= '-spider'; |
805
|
|
|
|
806
|
|
|
$temp = array(); |
807
|
|
|
if ($cache->levelHigherThan(1) && !empty($board) && $cache->getVar($temp, 'permissions:' . $cache_groups . ':' . $board, 240) && time() - 240 > $modSettings['settings_updated']) |
808
|
|
|
{ |
809
|
|
|
list ($user_info['permissions']) = $temp; |
810
|
|
|
banPermissions(); |
811
|
|
|
|
812
|
|
|
return; |
813
|
|
|
} |
814
|
|
|
elseif ($cache->getVar($temp, 'permissions:' . $cache_groups, 240) && time() - 240 > $modSettings['settings_updated']) |
815
|
|
|
{ |
816
|
|
|
if (is_array($temp)) |
817
|
|
|
{ |
818
|
|
|
list ($user_info['permissions'], $removals) = $temp; |
819
|
|
|
} |
820
|
|
|
} |
821
|
|
|
} |
822
|
|
|
|
823
|
|
|
// If it is detected as a robot, and we are restricting permissions as a special group - then implement this. |
824
|
|
|
$spider_restrict = $user_info['possibly_robot'] && !empty($modSettings['spider_group']) ? ' OR (id_group = {int:spider_group} AND add_deny = 0)' : ''; |
825
|
|
|
|
826
|
|
|
if (empty($user_info['permissions'])) |
827
|
|
|
{ |
828
|
|
|
// Get the general permissions. |
829
|
|
|
$request = $db->query('', ' |
830
|
|
|
SELECT |
831
|
|
|
permission, add_deny |
832
|
|
|
FROM {db_prefix}permissions |
833
|
|
|
WHERE id_group IN ({array_int:member_groups}) |
834
|
|
|
' . $spider_restrict, |
835
|
|
|
array( |
836
|
|
|
'member_groups' => $user_info['groups'], |
837
|
|
|
'spider_group' => !empty($modSettings['spider_group']) && $modSettings['spider_group'] != 1 ? $modSettings['spider_group'] : 0, |
838
|
|
|
) |
839
|
|
|
); |
840
|
|
|
while ($row = $db->fetch_assoc($request)) |
841
|
|
|
{ |
842
|
|
|
if (empty($row['add_deny'])) |
843
|
|
|
$removals[] = $row['permission']; |
844
|
|
|
else |
845
|
|
|
$user_info['permissions'][] = $row['permission']; |
846
|
|
|
} |
847
|
|
|
$db->free_result($request); |
848
|
|
|
|
849
|
|
|
if (isset($cache_groups)) |
850
|
|
|
$cache->put('permissions:' . $cache_groups, array($user_info['permissions'], !empty($removals) ? $removals : array()), 2); |
851
|
|
|
} |
852
|
|
|
|
853
|
|
|
// Get the board permissions. |
854
|
|
|
if (!empty($board)) |
855
|
|
|
{ |
856
|
|
|
// Make sure the board (if any) has been loaded by loadBoard(). |
857
|
|
|
if (!isset($board_info['profile'])) |
858
|
|
|
throw new Elk_Exception('no_board'); |
859
|
|
|
|
860
|
|
|
$request = $db->query('', ' |
861
|
|
|
SELECT |
862
|
|
|
permission, add_deny |
863
|
|
|
FROM {db_prefix}board_permissions |
864
|
|
|
WHERE (id_group IN ({array_int:member_groups}) |
865
|
|
|
' . $spider_restrict . ') |
866
|
|
|
AND id_profile = {int:id_profile}', |
867
|
|
|
array( |
868
|
|
|
'member_groups' => $user_info['groups'], |
869
|
|
|
'id_profile' => $board_info['profile'], |
870
|
|
|
'spider_group' => !empty($modSettings['spider_group']) && $modSettings['spider_group'] != 1 ? $modSettings['spider_group'] : 0, |
871
|
|
|
) |
872
|
|
|
); |
873
|
|
|
while ($row = $db->fetch_assoc($request)) |
874
|
|
|
{ |
875
|
|
|
if (empty($row['add_deny'])) |
876
|
|
|
$removals[] = $row['permission']; |
877
|
|
|
else |
878
|
|
|
$user_info['permissions'][] = $row['permission']; |
879
|
|
|
} |
880
|
|
|
$db->free_result($request); |
881
|
|
|
} |
882
|
|
|
|
883
|
|
|
// Remove all the permissions they shouldn't have ;). |
884
|
|
|
if (!empty($modSettings['permission_enable_deny'])) |
885
|
|
|
$user_info['permissions'] = array_diff($user_info['permissions'], $removals); |
886
|
|
|
|
887
|
|
|
if (isset($cache_groups) && !empty($board) && $cache->levelHigherThan(1)) |
888
|
|
|
$cache->put('permissions:' . $cache_groups . ':' . $board, array($user_info['permissions'], null), 240); |
889
|
|
|
|
890
|
|
|
// Banned? Watch, don't touch.. |
891
|
|
|
banPermissions(); |
892
|
|
|
|
893
|
|
|
// Load the mod cache so we can know what additional boards they should see, but no sense in doing it for guests |
894
|
|
|
if (!$user_info['is_guest']) |
895
|
|
|
{ |
896
|
|
|
$user_info['is_moderator'] = $user_info['is_mod'] || allowedTo('moderate_board'); |
897
|
|
|
if (!isset($_SESSION['mc']) || $_SESSION['mc']['time'] <= $modSettings['settings_updated']) |
898
|
|
|
{ |
899
|
|
|
require_once(SUBSDIR . '/Auth.subs.php'); |
900
|
|
|
rebuildModCache(); |
901
|
|
|
} |
902
|
|
|
else |
903
|
|
|
$user_info['mod_cache'] = $_SESSION['mc']; |
904
|
|
|
} |
905
|
|
|
} |
906
|
|
|
|
907
|
|
|
/** |
908
|
|
|
* Loads an array of users' data by ID or member_name. |
909
|
|
|
* |
910
|
|
|
* @event integrate_load_member_data allows to add to the columns & tables for $user_profile |
911
|
|
|
* array population |
912
|
|
|
* @event integrate_add_member_data called after data is loaded, allows integration |
913
|
|
|
* to directly add to the user_profile array |
914
|
|
|
* |
915
|
1 |
|
* @param int[]|int|string[]|string $users An array of users by id or name |
916
|
|
|
* @param bool $is_name = false $users is by name or by id |
917
|
1 |
|
* @param string $set = 'normal' What kind of data to load (normal, profile, minimal) |
918
|
1 |
|
* |
919
|
|
|
* @return array|bool The ids of the members loaded or false |
920
|
|
|
*/ |
921
|
1 |
|
function loadMemberData($users, $is_name = false, $set = 'normal') |
922
|
1 |
|
{ |
923
|
|
|
global $user_profile, $modSettings, $board_info, $context, $user_info; |
924
|
|
|
|
925
|
1 |
|
$db = database(); |
926
|
|
|
$cache = Cache::instance(); |
927
|
|
|
|
928
|
1 |
|
// Can't just look for no users :P. |
929
|
1 |
|
if (empty($users)) |
930
|
|
|
return false; |
931
|
1 |
|
|
932
|
1 |
|
// Pass the set value |
933
|
|
|
$context['loadMemberContext_set'] = $set; |
934
|
|
|
|
935
|
|
|
// Make sure it's an array. |
936
|
|
|
$users = !is_array($users) ? array($users) : array_unique($users); |
937
|
|
|
$loaded_ids = array(); |
938
|
|
|
|
939
|
|
|
if (!$is_name && $cache->isEnabled() && $cache->levelHigherThan(2)) |
940
|
|
|
{ |
941
|
|
|
$users = array_values($users); |
942
|
|
|
for ($i = 0, $n = count($users); $i < $n; $i++) |
943
|
|
|
{ |
944
|
|
|
$data = $cache->get('member_data-' . $set . '-' . $users[$i], 240); |
945
|
|
|
if ($cache->isMiss()) |
946
|
|
|
continue; |
947
|
|
|
|
948
|
|
|
$loaded_ids[] = $data['id_member']; |
949
|
|
|
$user_profile[$data['id_member']] = $data; |
950
|
|
|
unset($users[$i]); |
951
|
|
|
} |
952
|
|
|
} |
953
|
|
|
|
954
|
|
|
// Used by default |
955
|
1 |
|
$select_columns = ' |
956
|
1 |
|
COALESCE(lo.log_time, 0) AS is_online, COALESCE(a.id_attach, 0) AS id_attach, a.filename, a.attachment_type, |
957
|
|
|
mem.signature, mem.avatar, mem.id_member, mem.member_name, |
958
|
|
|
mem.real_name, mem.email_address, mem.hide_email, mem.date_registered, mem.website_title, mem.website_url, |
959
|
|
|
mem.birthdate, mem.member_ip, mem.member_ip2, mem.posts, mem.last_login, mem.likes_given, mem.likes_received, |
960
|
|
|
mem.karma_good, mem.id_post_group, mem.karma_bad, mem.lngfile, mem.id_group, mem.time_offset, mem.show_online, |
961
|
1 |
|
mg.online_color AS member_group_color, COALESCE(mg.group_name, {string:blank_string}) AS member_group, |
962
|
|
|
pg.online_color AS post_group_color, COALESCE(pg.group_name, {string:blank_string}) AS post_group, |
963
|
|
|
mem.is_activated, mem.warning, ' . (!empty($modSettings['titlesEnable']) ? 'mem.usertitle, ' : '') . ' |
964
|
|
|
CASE WHEN mem.id_group = 0 OR mg.icons = {string:blank_string} THEN pg.icons ELSE mg.icons END AS icons'; |
965
|
|
|
$select_tables = ' |
966
|
1 |
|
LEFT JOIN {db_prefix}log_online AS lo ON (lo.id_member = mem.id_member) |
967
|
|
|
LEFT JOIN {db_prefix}attachments AS a ON (a.id_member = mem.id_member) |
968
|
|
|
LEFT JOIN {db_prefix}membergroups AS pg ON (pg.id_group = mem.id_post_group) |
969
|
1 |
|
LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = mem.id_group)'; |
970
|
|
|
|
971
|
|
|
// We add or replace according to the set |
972
|
|
|
switch ($set) |
973
|
1 |
|
{ |
974
|
1 |
|
case 'normal': |
975
|
|
|
$select_columns .= ', mem.buddy_list'; |
976
|
|
|
break; |
977
|
|
|
case 'profile': |
978
|
|
|
$select_columns .= ', mem.openid_uri, mem.id_theme, mem.pm_ignore_list, mem.pm_email_notify, mem.receive_from, |
979
|
|
|
mem.time_format, mem.secret_question, mem.additional_groups, mem.smiley_set, |
980
|
|
|
mem.total_time_logged_in, mem.notify_announcements, mem.notify_regularity, mem.notify_send_body, |
981
|
|
|
mem.notify_types, lo.url, mem.ignore_boards, mem.password_salt, mem.pm_prefs, mem.buddy_list, mem.otp_secret, mem.enable_otp'; |
982
|
|
|
break; |
983
|
|
|
case 'minimal': |
984
|
|
|
$select_columns = ' |
985
|
|
|
mem.id_member, mem.member_name, mem.real_name, mem.email_address, mem.hide_email, mem.date_registered, |
986
|
1 |
|
mem.posts, mem.last_login, mem.member_ip, mem.member_ip2, mem.lngfile, mem.id_group'; |
987
|
|
|
$select_tables = ''; |
988
|
1 |
|
break; |
989
|
1 |
|
default: |
990
|
|
|
trigger_error('loadMemberData(): Invalid member data set \'' . $set . '\'', E_USER_WARNING); |
991
|
1 |
|
} |
992
|
1 |
|
|
993
|
1 |
|
// Allow addons to easily add to the selected member data |
994
|
1 |
|
call_integration_hook('integrate_load_member_data', array(&$select_columns, &$select_tables, $set)); |
995
|
|
|
|
996
|
1 |
|
if (!empty($users)) |
997
|
1 |
|
{ |
998
|
|
|
// Load the member's data. |
999
|
1 |
|
$request = $db->query('', ' |
1000
|
1 |
|
SELECT' . $select_columns . ' |
1001
|
1 |
|
FROM {db_prefix}members AS mem' . $select_tables . ' |
1002
|
|
|
WHERE mem.' . ($is_name ? 'member_name' : 'id_member') . (count($users) == 1 ? ' = {' . ($is_name ? 'string' : 'int') . ':users}' : ' IN ({' . ($is_name ? 'array_string' : 'array_int') . ':users})'), |
1003
|
1 |
|
array( |
1004
|
1 |
|
'blank_string' => '', |
1005
|
1 |
|
'users' => count($users) == 1 ? current($users) : $users, |
1006
|
1 |
|
) |
1007
|
1 |
|
); |
1008
|
1 |
|
$new_loaded_ids = array(); |
1009
|
1 |
|
while ($row = $db->fetch_assoc($request)) |
1010
|
|
|
{ |
1011
|
|
|
$new_loaded_ids[] = $row['id_member']; |
1012
|
1 |
|
$loaded_ids[] = $row['id_member']; |
1013
|
1 |
|
$row['options'] = array(); |
1014
|
1 |
|
$user_profile[$row['id_member']] = $row; |
1015
|
|
|
} |
1016
|
|
|
$db->free_result($request); |
1017
|
|
|
} |
1018
|
1 |
|
|
1019
|
|
|
// Custom profile fields as well |
1020
|
1 |
|
if (!empty($new_loaded_ids) && !empty($user_info['id']) && $set !== 'minimal' && (in_array('cp', $context['admin_features']))) |
1021
|
|
|
{ |
1022
|
1 |
|
$request = $db->query('', ' |
1023
|
1 |
|
SELECT cfd.id_member, cfd.variable, cfd.value, cf.field_options, cf.field_type |
1024
|
|
|
FROM {db_prefix}custom_fields_data AS cfd |
1025
|
|
|
JOIN {db_prefix}custom_fields AS cf ON (cf.col_name = cfd.variable) |
1026
|
|
|
WHERE id_member' . (count($new_loaded_ids) == 1 ? ' = {int:loaded_ids}' : ' IN ({array_int:loaded_ids})'), |
1027
|
|
|
array( |
1028
|
|
|
'loaded_ids' => count($new_loaded_ids) == 1 ? $new_loaded_ids[0] : $new_loaded_ids, |
1029
|
|
|
) |
1030
|
|
|
); |
1031
|
|
|
while ($row = $db->fetch_assoc($request)) |
1032
|
|
|
{ |
1033
|
|
|
if (!empty($row['field_options'])) |
1034
|
|
|
{ |
1035
|
|
|
$field_options = explode(',', $row['field_options']); |
1036
|
|
|
$key = (int) array_search($row['value'], $field_options); |
1037
|
|
|
} |
1038
|
1 |
|
else |
1039
|
1 |
|
{ |
1040
|
|
|
$key = 0; |
1041
|
|
|
} |
1042
|
1 |
|
|
1043
|
1 |
|
$user_profile[$row['id_member']]['options'][$row['variable'] . '_key'] = $row['variable'] . '_' . $key; |
1044
|
|
|
$user_profile[$row['id_member']]['options'][$row['variable']] = $row['value']; |
1045
|
1 |
|
} |
1046
|
1 |
|
$db->free_result($request); |
1047
|
|
|
} |
1048
|
|
|
|
1049
|
|
|
// Anything else integration may want to add to the user_profile array |
1050
|
|
|
if (!empty($new_loaded_ids)) |
1051
|
|
|
call_integration_hook('integrate_add_member_data', array($new_loaded_ids, $set)); |
1052
|
1 |
|
|
1053
|
1 |
|
if (!empty($new_loaded_ids) && $cache->levelHigherThan(2)) |
1054
|
|
|
{ |
1055
|
|
|
for ($i = 0, $n = count($new_loaded_ids); $i < $n; $i++) |
1056
|
|
|
$cache->put('member_data-' . $set . '-' . $new_loaded_ids[$i], $user_profile[$new_loaded_ids[$i]], 240); |
1057
|
|
|
} |
1058
|
|
|
|
1059
|
|
|
// Are we loading any moderators? If so, fix their group data... |
1060
|
|
|
if (!empty($loaded_ids) && !empty($board_info['moderators']) && $set === 'normal' && count($temp_mods = array_intersect($loaded_ids, array_keys($board_info['moderators']))) !== 0) |
1061
|
|
|
{ |
1062
|
|
|
$group_info = array(); |
1063
|
|
|
if (!$cache->getVar($group_info, 'moderator_group_info', 480)) |
1064
|
|
|
{ |
1065
|
|
|
require_once(SUBSDIR . '/Membergroups.subs.php'); |
1066
|
|
|
$group_info = membergroupById(3, true); |
1067
|
|
|
|
1068
|
|
|
$cache->put('moderator_group_info', $group_info, 480); |
1069
|
|
|
} |
1070
|
|
|
|
1071
|
|
|
foreach ($temp_mods as $id) |
1072
|
|
|
{ |
1073
|
|
|
// By popular demand, don't show admins or global moderators as moderators. |
1074
|
|
|
if ($user_profile[$id]['id_group'] != 1 && $user_profile[$id]['id_group'] != 2) |
1075
|
|
|
$user_profile[$id]['member_group'] = $group_info['group_name']; |
1076
|
|
|
|
1077
|
1 |
|
// If the Moderator group has no color or icons, but their group does... don't overwrite. |
1078
|
|
|
if (!empty($group_info['icons'])) |
1079
|
|
|
$user_profile[$id]['icons'] = $group_info['icons']; |
1080
|
|
|
if (!empty($group_info['online_color'])) |
1081
|
|
|
$user_profile[$id]['member_group_color'] = $group_info['online_color']; |
1082
|
|
|
} |
1083
|
|
|
} |
1084
|
|
|
|
1085
|
|
|
return empty($loaded_ids) ? false : $loaded_ids; |
1086
|
|
|
} |
1087
|
|
|
|
1088
|
|
|
/** |
1089
|
|
|
* Loads the user's basic values... meant for template/theme usage. |
1090
|
|
|
* |
1091
|
|
|
* What it does: |
1092
|
|
|
* |
1093
|
|
|
* - Always loads the minimal values of username, name, id, href, link, email, show_email, registered, registered_timestamp |
1094
|
|
|
* - if $context['loadMemberContext_set'] is not minimal it will load in full a full set of user information |
1095
|
|
|
* - prepares signature for display (censoring if enabled) |
1096
|
|
|
* - loads in the members custom fields if any |
1097
|
|
|
* - prepares the users buddy list, including reverse buddy flags |
1098
|
|
|
* |
1099
|
1 |
|
* @event integrate_member_context allows to manipulate $memberContext[user] |
1100
|
1 |
|
* @param int $user |
1101
|
1 |
|
* @param bool $display_custom_fields = false |
1102
|
|
|
* |
1103
|
|
|
* @return boolean |
1104
|
1 |
|
*/ |
1105
|
1 |
|
function loadMemberContext($user, $display_custom_fields = false) |
1106
|
|
|
{ |
1107
|
|
|
global $memberContext, $user_profile, $txt, $scripturl, $user_info; |
1108
|
1 |
|
global $context, $modSettings, $settings; |
1109
|
1 |
|
static $dataLoaded = array(); |
1110
|
|
|
|
1111
|
1 |
|
// If this person's data is already loaded, skip it. |
1112
|
1 |
|
if (isset($dataLoaded[$user])) |
1113
|
|
|
return true; |
1114
|
|
|
|
1115
|
|
|
// We can't load guests or members not loaded by loadMemberData()! |
1116
|
|
|
if ($user == 0) |
1117
|
1 |
|
return false; |
1118
|
|
|
|
1119
|
|
|
if (!isset($user_profile[$user])) |
1120
|
1 |
|
{ |
1121
|
1 |
|
trigger_error('loadMemberContext(): member id ' . $user . ' not previously loaded by loadMemberData()', E_USER_WARNING); |
1122
|
|
|
return false; |
1123
|
|
|
} |
1124
|
1 |
|
|
1125
|
|
|
$parsers = \BBC\ParserWrapper::instance(); |
1126
|
|
|
|
1127
|
|
|
// Well, it's loaded now anyhow. |
1128
|
|
|
$dataLoaded[$user] = true; |
1129
|
1 |
|
$profile = $user_profile[$user]; |
1130
|
1 |
|
|
1131
|
1 |
|
// Censor everything. |
1132
|
1 |
|
$profile['signature'] = censor($profile['signature']); |
1133
|
|
|
|
1134
|
|
|
// TODO: We should look into a censoring toggle for custom fields |
1135
|
1 |
|
|
1136
|
1 |
|
// Set things up to be used before hand. |
1137
|
|
|
$profile['signature'] = str_replace(array("\n", "\r"), array('<br />', ''), $profile['signature']); |
1138
|
|
|
$profile['signature'] = $parsers->parseSignature($profile['signature'], true); |
1139
|
1 |
|
$profile['is_online'] = (!empty($profile['show_online']) || allowedTo('moderate_forum')) && $profile['is_online'] > 0; |
1140
|
1 |
|
$profile['icons'] = empty($profile['icons']) ? array('', '') : explode('#', $profile['icons']); |
1141
|
1 |
|
|
1142
|
1 |
|
// Setup the buddy status here (One whole in_array call saved :P) |
1143
|
1 |
|
$profile['buddy'] = in_array($profile['id_member'], $user_info['buddies']); |
1144
|
1 |
|
$buddy_list = !empty($profile['buddy_list']) ? explode(',', $profile['buddy_list']) : array(); |
1145
|
1 |
|
|
1146
|
1 |
|
// These minimal values are always loaded |
1147
|
1 |
|
$memberContext[$user] = array( |
1148
|
1 |
|
'username' => $profile['member_name'], |
1149
|
1 |
|
'name' => $profile['real_name'], |
1150
|
|
|
'id' => $profile['id_member'], |
1151
|
|
|
'href' => $scripturl . '?action=profile;u=' . $profile['id_member'], |
1152
|
|
|
'link' => '<a href="' . $scripturl . '?action=profile;u=' . $profile['id_member'] . '" title="' . $txt['profile_of'] . ' ' . trim($profile['real_name']) . '">' . $profile['real_name'] . '</a>', |
1153
|
1 |
|
'email' => $profile['email_address'], |
1154
|
1 |
|
'show_email' => showEmailAddress(!empty($profile['hide_email']), $profile['id_member']), |
1155
|
|
|
'registered_raw' => empty($profile['date_registered']) ? 0 : $profile['date_registered'], |
1156
|
1 |
|
'registered' => empty($profile['date_registered']) ? $txt['not_applicable'] : standardTime($profile['date_registered']), |
1157
|
1 |
|
'registered_timestamp' => empty($profile['date_registered']) ? 0 : forum_time(true, $profile['date_registered']), |
1158
|
1 |
|
); |
1159
|
1 |
|
|
1160
|
1 |
|
// If the set isn't minimal then load the monstrous array. |
1161
|
1 |
|
if ($context['loadMemberContext_set'] !== 'minimal') |
1162
|
1 |
|
{ |
1163
|
|
|
$memberContext[$user] += array( |
1164
|
1 |
|
'username_color' => '<span ' . (!empty($profile['member_group_color']) ? 'style="color:' . $profile['member_group_color'] . ';"' : '') . '>' . $profile['member_name'] . '</span>', |
1165
|
1 |
|
'name_color' => '<span ' . (!empty($profile['member_group_color']) ? 'style="color:' . $profile['member_group_color'] . ';"' : '') . '>' . $profile['real_name'] . '</span>', |
1166
|
1 |
|
'link_color' => '<a href="' . $scripturl . '?action=profile;u=' . $profile['id_member'] . '" title="' . $txt['profile_of'] . ' ' . $profile['real_name'] . '" ' . (!empty($profile['member_group_color']) ? 'style="color:' . $profile['member_group_color'] . ';"' : '') . '>' . $profile['real_name'] . '</a>', |
1167
|
1 |
|
'is_buddy' => $profile['buddy'], |
1168
|
1 |
|
'is_reverse_buddy' => in_array($user_info['id'], $buddy_list), |
1169
|
1 |
|
'buddies' => $buddy_list, |
1170
|
1 |
|
'title' => !empty($modSettings['titlesEnable']) ? $profile['usertitle'] : '', |
1171
|
1 |
|
'website' => array( |
1172
|
1 |
|
'title' => $profile['website_title'], |
1173
|
1 |
|
'url' => $profile['website_url'], |
1174
|
|
|
), |
1175
|
1 |
|
'birth_date' => empty($profile['birthdate']) || $profile['birthdate'] === '0001-01-01' ? '0000-00-00' : (substr($profile['birthdate'], 0, 4) === '0004' ? '0000' . substr($profile['birthdate'], 4) : $profile['birthdate']), |
1176
|
1 |
|
'signature' => $profile['signature'], |
1177
|
1 |
|
'real_posts' => $profile['posts'], |
1178
|
1 |
|
'posts' => comma_format($profile['posts']), |
1179
|
1 |
|
'avatar' => determineAvatar($profile), |
1180
|
|
|
'last_login' => empty($profile['last_login']) ? $txt['never'] : standardTime($profile['last_login']), |
1181
|
1 |
|
'last_login_timestamp' => empty($profile['last_login']) ? 0 : forum_time(false, $profile['last_login']), |
1182
|
1 |
|
'karma' => array( |
1183
|
1 |
|
'good' => $profile['karma_good'], |
1184
|
1 |
|
'bad' => $profile['karma_bad'], |
1185
|
1 |
|
'allow' => !$user_info['is_guest'] && !empty($modSettings['karmaMode']) && $user_info['id'] != $user && allowedTo('karma_edit') && |
1186
|
|
|
($user_info['posts'] >= $modSettings['karmaMinPosts'] || $user_info['is_admin']), |
1187
|
1 |
|
), |
1188
|
1 |
|
'likes' => array( |
1189
|
1 |
|
'given' => $profile['likes_given'], |
1190
|
1 |
|
'received' => $profile['likes_received'] |
1191
|
1 |
|
), |
1192
|
1 |
|
'ip' => htmlspecialchars($profile['member_ip'], ENT_COMPAT, 'UTF-8'), |
1193
|
1 |
|
'ip2' => htmlspecialchars($profile['member_ip2'], ENT_COMPAT, 'UTF-8'), |
1194
|
1 |
|
'online' => array( |
1195
|
1 |
|
'is_online' => $profile['is_online'], |
1196
|
1 |
|
'text' => Util::htmlspecialchars($txt[$profile['is_online'] ? 'online' : 'offline']), |
1197
|
1 |
|
'member_online_text' => sprintf($txt[$profile['is_online'] ? 'member_is_online' : 'member_is_offline'], Util::htmlspecialchars($profile['real_name'])), |
1198
|
1 |
|
'href' => $scripturl . '?action=pm;sa=send;u=' . $profile['id_member'], |
1199
|
1 |
|
'link' => '<a href="' . $scripturl . '?action=pm;sa=send;u=' . $profile['id_member'] . '">' . $txt[$profile['is_online'] ? 'online' : 'offline'] . '</a>', |
1200
|
1 |
|
'label' => $txt[$profile['is_online'] ? 'online' : 'offline'] |
1201
|
1 |
|
), |
1202
|
1 |
|
'language' => Util::ucwords(strtr($profile['lngfile'], array('_' => ' '))), |
1203
|
1 |
|
'is_activated' => isset($profile['is_activated']) ? $profile['is_activated'] : 1, |
1204
|
1 |
|
'is_banned' => isset($profile['is_activated']) ? $profile['is_activated'] >= 10 : 0, |
1205
|
1 |
|
'options' => $profile['options'], |
1206
|
1 |
|
'is_guest' => false, |
1207
|
1 |
|
'group' => $profile['member_group'], |
1208
|
1 |
|
'group_color' => $profile['member_group_color'], |
1209
|
|
|
'group_id' => $profile['id_group'], |
1210
|
1 |
|
'post_group' => $profile['post_group'], |
1211
|
|
|
'post_group_color' => $profile['post_group_color'], |
1212
|
|
|
'group_icons' => str_repeat('<img src="' . str_replace('$language', $context['user']['language'], isset($profile['icons'][1]) ? $settings['images_url'] . '/group_icons/' . $profile['icons'][1] : '') . '" alt="[*]" />', empty($profile['icons'][0]) || empty($profile['icons'][1]) ? 0 : $profile['icons'][0]), |
1213
|
1 |
|
'warning' => $profile['warning'], |
1214
|
1 |
|
'warning_status' => !empty($modSettings['warning_mute']) && $modSettings['warning_mute'] <= $profile['warning'] ? 'mute' : (!empty($modSettings['warning_moderate']) && $modSettings['warning_moderate'] <= $profile['warning'] ? 'moderate' : (!empty($modSettings['warning_watch']) && $modSettings['warning_watch'] <= $profile['warning'] ? 'watch' : (''))), |
1215
|
|
|
'local_time' => standardTime(time() + ($profile['time_offset'] - $user_info['time_offset']) * 3600, false), |
1216
|
|
|
'custom_fields' => array(), |
1217
|
|
|
); |
1218
|
|
|
} |
1219
|
|
|
|
1220
|
|
|
// Are we also loading the members custom fields into context? |
1221
|
|
|
if ($display_custom_fields && !empty($modSettings['displayFields'])) |
1222
|
|
|
{ |
1223
|
|
|
if (!isset($context['display_fields'])) |
1224
|
|
|
$context['display_fields'] = Util::unserialize($modSettings['displayFields']); |
1225
|
|
|
|
1226
|
|
|
foreach ($context['display_fields'] as $custom) |
1227
|
|
|
{ |
1228
|
|
|
if (!isset($custom['title']) || trim($custom['title']) == '' || empty($profile['options'][$custom['colname']])) |
1229
|
|
|
continue; |
1230
|
|
|
|
1231
|
|
|
$value = $profile['options'][$custom['colname']]; |
1232
|
|
|
|
1233
|
|
|
// BBC? |
1234
|
|
|
if ($custom['bbc']) |
1235
|
|
|
$value = $parsers->parseCustomFields($value); |
1236
|
|
|
// ... or checkbox? |
1237
|
|
|
elseif (isset($custom['type']) && $custom['type'] == 'check') |
1238
|
|
|
$value = $value ? $txt['yes'] : $txt['no']; |
1239
|
|
|
|
1240
|
|
|
// Enclosing the user input within some other text? |
1241
|
|
|
if (!empty($custom['enclose'])) |
1242
|
|
|
{ |
1243
|
|
|
$replacements = array( |
1244
|
|
|
'{SCRIPTURL}' => $scripturl, |
1245
|
|
|
'{IMAGES_URL}' => $settings['images_url'], |
1246
|
|
|
'{DEFAULT_IMAGES_URL}' => $settings['default_images_url'], |
1247
|
|
|
'{INPUT}' => $value, |
1248
|
|
|
); |
1249
|
|
|
|
1250
|
|
|
if (in_array($custom['type'], array('radio', 'select'))) |
1251
|
|
|
{ |
1252
|
|
|
$replacements['{KEY}'] = $profile['options'][$custom['colname'] . '_key']; |
1253
|
|
|
} |
1254
|
|
|
$value = strtr($custom['enclose'], $replacements); |
1255
|
|
|
} |
1256
|
|
|
|
1257
|
|
|
$memberContext[$user]['custom_fields'][] = array( |
1258
|
1 |
|
'title' => $custom['title'], |
1259
|
1 |
|
'colname' => $custom['colname'], |
1260
|
|
|
'value' => $value, |
1261
|
|
|
'placement' => !empty($custom['placement']) ? $custom['placement'] : 0, |
1262
|
|
|
); |
1263
|
|
|
} |
1264
|
|
|
} |
1265
|
|
|
|
1266
|
|
|
call_integration_hook('integrate_member_context', array($user, $display_custom_fields)); |
1267
|
|
|
return true; |
1268
|
|
|
} |
1269
|
|
|
|
1270
|
7 |
|
/** |
1271
|
7 |
|
* Loads information about what browser the user is viewing with and places it in $context |
1272
|
7 |
|
* |
1273
|
|
|
* @uses Browser_Detector class from BrowserDetect.class.php |
1274
|
|
|
*/ |
1275
|
|
|
function detectBrowser() |
1276
|
|
|
{ |
1277
|
|
|
// Load the current user's browser of choice |
1278
|
|
|
$detector = new Browser_Detector; |
1279
|
|
|
$detector->detectBrowser(); |
1280
|
|
|
} |
1281
|
|
|
|
1282
|
7 |
|
/** |
1283
|
|
|
* Get the id of a theme |
1284
|
|
|
* |
1285
|
7 |
|
* @param int $id_theme |
1286
|
7 |
|
* @return int |
1287
|
|
|
*/ |
1288
|
7 |
|
function getThemeId($id_theme = 0) |
1289
|
|
|
{ |
1290
|
|
|
global $modSettings, $user_info, $board_info, $ssi_theme; |
1291
|
|
|
|
1292
|
|
|
// The theme was specified by parameter. |
1293
|
|
|
if (!empty($id_theme)) |
1294
|
7 |
|
$id_theme = (int) $id_theme; |
1295
|
|
|
// The theme was specified by REQUEST. |
1296
|
|
|
elseif (!empty($_REQUEST['theme']) && (!empty($modSettings['theme_allow']) || allowedTo('admin_forum'))) |
1297
|
7 |
|
{ |
1298
|
|
|
$id_theme = (int) $_REQUEST['theme']; |
1299
|
|
|
$_SESSION['id_theme'] = $id_theme; |
1300
|
7 |
|
} |
1301
|
|
|
// The theme was specified by REQUEST... previously. |
1302
|
|
|
elseif (!empty($_SESSION['id_theme']) && (!empty($modSettings['theme_allow']) || allowedTo('admin_forum'))) |
1303
|
|
|
$id_theme = (int) $_SESSION['id_theme']; |
1304
|
7 |
|
// The theme is just the user's choice. (might use ?board=1;theme=0 to force board theme.) |
1305
|
|
|
elseif (!empty($user_info['theme']) && !isset($_REQUEST['theme']) && (!empty($modSettings['theme_allow']) || allowedTo('admin_forum'))) |
1306
|
7 |
|
$id_theme = $user_info['theme']; |
1307
|
|
|
// The theme was specified by the board. |
1308
|
|
|
elseif (!empty($board_info['theme'])) |
1309
|
|
|
$id_theme = $board_info['theme']; |
1310
|
7 |
|
// The theme is the forum's default. |
1311
|
7 |
|
else |
1312
|
|
|
$id_theme = $modSettings['theme_guests']; |
1313
|
7 |
|
|
1314
|
|
|
call_integration_hook('integrate_customize_theme_id', array(&$id_theme)); |
1315
|
7 |
|
|
1316
|
|
|
// Verify the id_theme... no foul play. |
1317
|
4 |
|
// Always allow the board specific theme, if they are overriding. |
1318
|
4 |
|
if (!empty($board_info['theme']) && $board_info['override_theme']) |
1319
|
4 |
|
$id_theme = $board_info['theme']; |
1320
|
|
|
// If they have specified a particular theme to use with SSI allow it to be used. |
1321
|
4 |
|
elseif (!empty($ssi_theme) && $id_theme == $ssi_theme) |
1322
|
4 |
|
$id_theme = (int) $id_theme; |
1323
|
|
|
elseif (!empty($modSettings['knownThemes']) && !allowedTo('admin_forum')) |
1324
|
3 |
|
{ |
1325
|
|
|
$themes = explode(',', $modSettings['knownThemes']); |
1326
|
7 |
|
if (!in_array($id_theme, $themes)) |
1327
|
|
|
$id_theme = $modSettings['theme_guests']; |
1328
|
|
|
else |
1329
|
|
|
$id_theme = (int) $id_theme; |
1330
|
|
|
} |
1331
|
|
|
else |
1332
|
|
|
$id_theme = (int) $id_theme; |
1333
|
|
|
|
1334
|
|
|
return $id_theme; |
1335
|
|
|
} |
1336
|
|
|
|
1337
|
|
|
/** |
1338
|
|
|
* Load in the theme variables for a given theme / member combination |
1339
|
7 |
|
* |
1340
|
|
|
* @param int $id_theme |
1341
|
7 |
|
* @param int $member |
1342
|
|
|
* |
1343
|
|
|
* @return array |
1344
|
7 |
|
*/ |
1345
|
7 |
|
function getThemeData($id_theme, $member) |
1346
|
7 |
|
{ |
1347
|
|
|
global $modSettings, $boardurl; |
1348
|
|
|
|
1349
|
|
|
$cache = Cache::instance(); |
1350
|
|
|
|
1351
|
7 |
|
// Do we already have this members theme data and specific options loaded (for aggressive cache settings) |
1352
|
|
|
$temp = array(); |
1353
|
|
|
if ($cache->levelHigherThan(1) && $cache->getVar($temp, 'theme_settings-' . $id_theme . ':' . $member, 60) && time() - 60 > $modSettings['settings_updated']) |
1354
|
|
|
{ |
1355
|
7 |
|
$themeData = $temp; |
1356
|
|
|
$flag = true; |
1357
|
7 |
|
} |
1358
|
7 |
|
// Or do we just have the system wide theme settings cached |
1359
|
7 |
|
elseif ($cache->getVar($temp, 'theme_settings-' . $id_theme, 90) && time() - 60 > $modSettings['settings_updated']) |
1360
|
|
|
$themeData = $temp + array($member => array()); |
1361
|
|
|
// Nothing at all then |
1362
|
7 |
|
else |
1363
|
|
|
$themeData = array(-1 => array(), 0 => array(), $member => array()); |
1364
|
|
|
|
1365
|
7 |
|
if (empty($flag)) |
1366
|
7 |
|
{ |
1367
|
|
|
$db = database(); |
1368
|
7 |
|
|
1369
|
7 |
|
// Load variables from the current or default theme, global or this user's. |
1370
|
|
|
$result = $db->query('', ' |
1371
|
7 |
|
SELECT variable, value, id_member, id_theme |
1372
|
|
|
FROM {db_prefix}themes |
1373
|
7 |
|
WHERE id_member' . (empty($themeData[0]) ? ' IN (-1, 0, {int:id_member})' : ' = {int:id_member}') . ' |
1374
|
|
|
AND id_theme' . ($id_theme == 1 ? ' = {int:id_theme}' : ' IN ({int:id_theme}, 1)'), |
1375
|
|
|
array( |
1376
|
7 |
|
'id_theme' => $id_theme, |
1377
|
|
|
'id_member' => $member, |
1378
|
|
|
) |
1379
|
7 |
|
); |
1380
|
7 |
|
|
1381
|
|
|
$immutable_theme_data = array('actual_theme_url', 'actual_images_url', 'base_theme_dir', 'base_theme_url', 'default_images_url', 'default_theme_dir', 'default_theme_url', 'default_template', 'images_url', 'number_recent_posts', 'smiley_sets_default', 'theme_dir', 'theme_id', 'theme_layers', 'theme_templates', 'theme_url'); |
1382
|
|
|
|
1383
|
7 |
|
// Pick between $settings and $options depending on whose data it is. |
1384
|
7 |
|
while ($row = $db->fetch_assoc($result)) |
1385
|
|
|
{ |
1386
|
|
|
// There are just things we shouldn't be able to change as members. |
1387
|
7 |
|
if ($row['id_member'] != 0 && in_array($row['variable'], $immutable_theme_data)) |
1388
|
7 |
|
continue; |
1389
|
7 |
|
|
1390
|
7 |
|
// If this is the theme_dir of the default theme, store it. |
1391
|
|
|
if (in_array($row['variable'], array('theme_dir', 'theme_url', 'images_url')) && $row['id_theme'] == '1' && empty($row['id_member'])) |
1392
|
7 |
|
$themeData[0]['default_' . $row['variable']] = $row['value']; |
1393
|
7 |
|
|
1394
|
7 |
|
// If this isn't set yet, is a theme option, or is not the default theme.. |
1395
|
7 |
|
if (!isset($themeData[$row['id_member']][$row['variable']]) || $row['id_theme'] != '1') |
1396
|
7 |
|
$themeData[$row['id_member']][$row['variable']] = substr($row['variable'], 0, 5) == 'show_' ? $row['value'] == '1' : $row['value']; |
1397
|
|
|
} |
1398
|
|
|
$db->free_result($result); |
1399
|
|
|
|
1400
|
|
|
if (file_exists($themeData[0]['default_theme_dir'] . '/cache') && is_writable($themeData[0]['default_theme_dir'] . '/cache')) |
1401
|
|
|
{ |
1402
|
|
|
$themeData[0]['default_theme_cache_dir'] = $themeData[0]['default_theme_dir'] . '/cache'; |
1403
|
|
|
$themeData[0]['default_theme_cache_url'] = $themeData[0]['default_theme_url'] . '/cache'; |
1404
|
7 |
|
} |
1405
|
7 |
|
else |
1406
|
7 |
|
{ |
1407
|
|
|
$themeData[0]['default_theme_cache_dir'] = CACHEDIR; |
1408
|
7 |
|
$themeData[0]['default_theme_cache_url'] = $boardurl . '/cache'; |
1409
|
7 |
|
} |
1410
|
7 |
|
|
1411
|
7 |
|
// Set the defaults if the user has not chosen on their own |
1412
|
|
|
if (!empty($themeData[-1])) |
1413
|
|
|
{ |
1414
|
7 |
|
foreach ($themeData[-1] as $k => $v) |
1415
|
7 |
|
{ |
1416
|
|
|
if (!isset($themeData[$member][$k])) |
1417
|
7 |
|
$themeData[$member][$k] = $v; |
1418
|
7 |
|
} |
1419
|
7 |
|
} |
1420
|
|
|
|
1421
|
7 |
|
// If being aggressive we save the site wide and member theme settings |
1422
|
|
|
if ($cache->levelHigherThan(1)) |
1423
|
|
|
$cache->put('theme_settings-' . $id_theme . ':' . $member, $themeData, 60); |
1424
|
|
|
// Only if we didn't already load that part of the cache... |
1425
|
|
|
elseif (!isset($temp)) |
1426
|
|
|
$cache->put('theme_settings-' . $id_theme, array(-1 => $themeData[-1], 0 => $themeData[0]), 90); |
1427
|
|
|
} |
1428
|
|
|
|
1429
|
|
|
return $themeData; |
1430
|
|
|
} |
1431
|
7 |
|
|
1432
|
|
|
/** |
1433
|
|
|
* Initialize a theme for use |
1434
|
7 |
|
* |
1435
|
|
|
* @param int $id_theme |
1436
|
|
|
*/ |
1437
|
7 |
|
function initTheme($id_theme = 0) |
1438
|
|
|
{ |
1439
|
|
|
global $user_info, $settings, $options, $context; |
1440
|
7 |
|
|
1441
|
7 |
|
// Validate / fetch the themes id |
1442
|
7 |
|
$id_theme = getThemeId($id_theme); |
1443
|
|
|
|
1444
|
7 |
|
// Need to know who we are loading the theme for |
1445
|
7 |
|
$member = empty($user_info['id']) ? -1 : $user_info['id']; |
1446
|
7 |
|
|
1447
|
7 |
|
// Load in the theme variables for them |
1448
|
|
|
$themeData = getThemeData($id_theme, $member); |
1449
|
|
|
$settings = $themeData[0]; |
1450
|
7 |
|
$options = $themeData[$member]; |
1451
|
|
|
|
1452
|
|
|
$settings['theme_id'] = $id_theme; |
1453
|
7 |
|
$settings['actual_theme_url'] = $settings['theme_url']; |
1454
|
7 |
|
$settings['actual_images_url'] = $settings['images_url']; |
1455
|
|
|
$settings['actual_theme_dir'] = $settings['theme_dir']; |
1456
|
|
|
|
1457
|
7 |
|
// Reload the templates |
1458
|
7 |
|
Templates::instance()->reloadDirectories($settings); |
1459
|
|
|
|
1460
|
|
|
// Setup the default theme file. In the future, this won't exist and themes will just have to extend it if they want |
1461
|
|
|
require_once($settings['default_theme_dir'] . '/Theme.php'); |
1462
|
|
|
$default_theme_instance = new \Themes\DefaultTheme\Theme(1); |
1463
|
|
|
|
1464
|
|
|
// Check if there is a Theme file |
1465
|
|
|
if ($id_theme != 1 && !empty($settings['theme_dir']) && file_exists($settings['theme_dir'] . '/Theme.php')) |
1466
|
|
|
{ |
1467
|
|
|
require_once($settings['theme_dir'] . '/Theme.php'); |
1468
|
|
|
|
1469
|
7 |
|
$class = '\\Themes\\' . basename(ucfirst($settings['theme_dir'])) . 'Theme\\Theme'; |
1470
|
|
|
|
1471
|
7 |
|
$theme = new $class($id_theme); |
1472
|
|
|
|
1473
|
|
|
$context['theme_instance'] = $theme; |
1474
|
|
|
} |
1475
|
|
|
else |
1476
|
|
|
{ |
1477
|
|
|
$context['theme_instance'] = $default_theme_instance; |
1478
|
|
|
} |
1479
|
|
|
} |
1480
|
|
|
|
1481
|
|
|
/** |
1482
|
|
|
* Load a theme, by ID. |
1483
|
|
|
* |
1484
|
|
|
* What it does: |
1485
|
|
|
* |
1486
|
|
|
* - identify the theme to be loaded. |
1487
|
|
|
* - validate that the theme is valid and that the user has permission to use it |
1488
|
|
|
* - load the users theme settings and site settings into $options. |
1489
|
|
|
* - prepares the list of folders to search for template loading. |
1490
|
|
|
* - identify what smiley set to use. |
1491
|
|
|
* - sets up $context['user'] |
1492
|
|
|
* - detects the users browser and sets a mobile friendly environment if needed |
1493
|
|
|
* - loads default JS variables for use in every theme |
1494
|
|
|
* - loads default JS scripts for use in every theme |
1495
|
|
|
* |
1496
|
|
|
* @event integrate_init_theme used to call initialization theme integration functions and |
1497
|
7 |
|
* change / update $settings |
1498
|
7 |
|
* @event integrate_theme_include allows to include files at this point |
1499
|
7 |
|
* @event integrate_load_theme calls functions after theme is loaded |
1500
|
|
|
* @param int $id_theme = 0 |
1501
|
7 |
|
* @param bool $initialize = true |
1502
|
|
|
*/ |
1503
|
7 |
|
function loadTheme($id_theme = 0, $initialize = true) |
1504
|
7 |
|
{ |
1505
|
|
|
global $user_info, $user_settings; |
1506
|
7 |
|
global $txt, $scripturl, $mbname, $modSettings; |
1507
|
|
|
global $context, $settings, $options; |
1508
|
7 |
|
|
1509
|
|
|
initTheme($id_theme); |
1510
|
|
|
|
1511
|
7 |
|
if (!$initialize) |
1512
|
7 |
|
return; |
1513
|
|
|
|
1514
|
|
|
loadThemeUrls(); |
1515
|
|
|
|
1516
|
|
|
loadUserContext(); |
1517
|
|
|
|
1518
|
|
|
// Set up some additional interface preference context |
1519
|
|
|
if (!empty($options['admin_preferences'])) |
1520
|
|
|
{ |
1521
|
|
|
$context['admin_preferences'] = serializeToJson($options['admin_preferences'], function ($array_form) { |
1522
|
|
|
global $context; |
1523
|
7 |
|
|
1524
|
|
|
$context['admin_preferences'] = $array_form; |
1525
|
|
|
require_once(SUBSDIR . '/Admin.subs.php'); |
1526
|
7 |
|
updateAdminPreferences(); |
1527
|
7 |
|
}); |
1528
|
3 |
|
} |
1529
|
3 |
|
else |
1530
|
|
|
{ |
1531
|
|
|
$context['admin_preferences'] = array(); |
1532
|
|
|
} |
1533
|
|
|
|
1534
|
|
|
if (!$user_info['is_guest']) |
1535
|
|
|
{ |
1536
|
|
|
if (!empty($options['minmax_preferences'])) |
1537
|
|
|
{ |
1538
|
|
|
$context['minmax_preferences'] = serializeToJson($options['minmax_preferences'], function ($array_form) { |
1539
|
|
|
global $settings, $user_info; |
1540
|
3 |
|
|
1541
|
|
|
// Update the option. |
1542
|
3 |
|
require_once(SUBSDIR . '/Themes.subs.php'); |
1543
|
|
|
updateThemeOptions(array($settings['theme_id'], $user_info['id'], 'minmax_preferences', json_encode($array_form))); |
1544
|
4 |
|
}); |
1545
|
|
|
} |
1546
|
|
|
else |
1547
|
|
|
{ |
1548
|
7 |
|
$context['minmax_preferences'] = array(); |
1549
|
|
|
} |
1550
|
|
|
} |
1551
|
7 |
|
// Guest may have collapsed the header, check the cookie to prevent collapse jumping |
1552
|
|
|
elseif ($user_info['is_guest'] && isset($_COOKIE['upshrink'])) |
1553
|
|
|
$context['minmax_preferences'] = array('upshrink' => $_COOKIE['upshrink']); |
1554
|
7 |
|
|
1555
|
7 |
|
// Load the basic layers |
1556
|
7 |
|
theme()->loadDefaultLayers(); |
1557
|
7 |
|
|
1558
|
7 |
|
// @todo when are these set before loadTheme(0, true)? |
1559
|
7 |
|
loadThemeContext(); |
1560
|
|
|
|
1561
|
|
|
// @todo These really don't belong in loadTheme() since they are more general than the theme. |
1562
|
7 |
|
$context['session_var'] = $_SESSION['session_var']; |
1563
|
7 |
|
$context['session_id'] = $_SESSION['session_value']; |
1564
|
4 |
|
$context['forum_name'] = $mbname; |
1565
|
4 |
|
$context['forum_name_html_safe'] = $context['forum_name']; |
1566
|
4 |
|
$context['current_action'] = isset($_REQUEST['action']) ? $_REQUEST['action'] : null; |
1567
|
4 |
|
$context['current_subaction'] = isset($_REQUEST['sa']) ? $_REQUEST['sa'] : null; |
1568
|
|
|
|
1569
|
|
|
// Set some permission related settings. |
1570
|
7 |
|
if ($user_info['is_guest'] && !empty($modSettings['enableVBStyleLogin'])) |
1571
|
|
|
{ |
1572
|
|
|
$context['show_login_bar'] = true; |
1573
|
7 |
|
$context['theme_header_callbacks'][] = 'login_bar'; |
1574
|
|
|
loadJavascriptFile('sha256.js', array('defer' => true)); |
1575
|
|
|
} |
1576
|
7 |
|
|
1577
|
7 |
|
// This determines the server... not used in many places, except for login fixing. |
1578
|
7 |
|
detectServer(); |
1579
|
7 |
|
|
1580
|
|
|
// Detect the browser. This is separated out because it's also used in attachment downloads |
1581
|
|
|
detectBrowser(); |
1582
|
7 |
|
|
1583
|
7 |
|
// Set the top level linktree up. |
1584
|
|
|
array_unshift($context['linktree'], array( |
1585
|
|
|
'url' => $scripturl, |
1586
|
|
|
'name' => $context['forum_name'] |
1587
|
|
|
)); |
1588
|
|
|
|
1589
|
|
|
// Just some mobile-friendly settings |
1590
|
|
|
if ($context['browser_body_id'] == 'mobile') |
1591
|
|
|
{ |
1592
|
|
|
// Disable the preview text. |
1593
|
|
|
$modSettings['message_index_preview'] = 0; |
1594
|
7 |
|
// Force the usage of click menu instead of a hover menu. |
1595
|
7 |
|
$options['use_click_menu'] = 1; |
1596
|
|
|
// No space left for a sidebar |
1597
|
|
|
$options['use_sidebar_menu'] = false; |
1598
|
7 |
|
// Disable the search dropdown. |
1599
|
|
|
$modSettings['search_dropdown'] = false; |
1600
|
|
|
} |
1601
|
7 |
|
|
1602
|
7 |
|
if (!isset($txt)) |
1603
|
|
|
$txt = array(); |
1604
|
|
|
|
1605
|
7 |
|
// Defaults in case of odd things |
1606
|
|
|
$settings['avatars_on_indexes'] = 0; |
1607
|
|
|
|
1608
|
7 |
|
// Initialize the theme. |
1609
|
7 |
|
if (function_exists('template_init')) |
1610
|
|
|
$settings = array_merge($settings, template_init()); |
1611
|
|
|
|
1612
|
7 |
|
// Call initialization theme integration functions. |
1613
|
7 |
|
call_integration_hook('integrate_init_theme', array($id_theme, &$settings)); |
1614
|
|
|
|
1615
|
7 |
|
// Guests may still need a name. |
1616
|
|
|
if ($context['user']['is_guest'] && empty($context['user']['name'])) |
1617
|
|
|
$context['user']['name'] = $txt['guest_title']; |
1618
|
7 |
|
|
1619
|
7 |
|
// Any theme-related strings that need to be loaded? |
1620
|
7 |
|
if (!empty($settings['require_theme_strings'])) |
1621
|
7 |
|
loadLanguage('ThemeStrings', '', false); |
1622
|
|
|
|
1623
|
|
|
theme()->loadSupportCSS(); |
1624
|
7 |
|
|
1625
|
7 |
|
// We allow theme variants, because we're cool. |
1626
|
|
|
if (!empty($settings['theme_variants'])) |
1627
|
|
|
{ |
1628
|
7 |
|
theme()->loadThemeVariant(); |
1629
|
7 |
|
} |
1630
|
|
|
|
1631
|
7 |
|
// A bit lonely maybe, though I think it should be set up *after* the theme variants detection |
1632
|
7 |
|
$context['header_logo_url_html_safe'] = empty($settings['header_logo_url']) ? $settings['images_url'] . '/' . $context['theme_variant_url'] . 'logo_elk.png' : Util::htmlspecialchars($settings['header_logo_url']); |
1633
|
|
|
$context['right_to_left'] = !empty($txt['lang_rtl']); |
1634
|
|
|
|
1635
|
|
|
// Allow overriding the board wide time/number formats. |
1636
|
|
|
if (empty($user_settings['time_format']) && !empty($txt['time_format'])) |
1637
|
|
|
$user_info['time_format'] = $txt['time_format']; |
1638
|
|
|
|
1639
|
7 |
|
if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'always') |
1640
|
|
|
{ |
1641
|
|
|
$settings['theme_url'] = $settings['default_theme_url']; |
1642
|
7 |
|
$settings['images_url'] = $settings['default_images_url']; |
1643
|
7 |
|
$settings['theme_dir'] = $settings['default_theme_dir']; |
1644
|
|
|
} |
1645
|
7 |
|
|
1646
|
7 |
|
// Make a special URL for the language. |
1647
|
|
|
$settings['lang_images_url'] = $settings['images_url'] . '/' . (!empty($txt['image_lang']) ? $txt['image_lang'] : $user_info['language']); |
1648
|
|
|
|
1649
|
7 |
|
// RTL languages require an additional stylesheet. |
1650
|
|
|
if ($context['right_to_left']) |
1651
|
7 |
|
loadCSSFile('rtl.css'); |
1652
|
7 |
|
|
1653
|
7 |
|
if (!empty($context['theme_variant']) && $context['right_to_left']) |
1654
|
7 |
|
loadCSSFile($context['theme_variant'] . '/rtl' . $context['theme_variant'] . '.css'); |
1655
|
7 |
|
|
1656
|
|
|
// This allows us to change the way things look for the admin. |
1657
|
7 |
|
$context['admin_features'] = explode(',', isset($modSettings['admin_features']) ? $modSettings['admin_features'] : 'cd,cp,k,w,rg,ml,pm'); |
1658
|
7 |
|
|
1659
|
|
|
if (!empty($modSettings['xmlnews_enable']) && (!empty($modSettings['allow_guestAccess']) || $context['user']['is_logged'])) |
1660
|
|
|
$context['newsfeed_urls'] = array( |
1661
|
|
|
'rss' => $scripturl . '?action=.xml;type=rss2;limit=' . (!empty($modSettings['xmlnews_limit']) ? $modSettings['xmlnews_limit'] : 5), |
1662
|
|
|
'atom' => $scripturl . '?action=.xml;type=atom;limit=' . (!empty($modSettings['xmlnews_limit']) ? $modSettings['xmlnews_limit'] : 5) |
1663
|
|
|
); |
1664
|
|
|
|
1665
|
|
|
if (!empty($_SESSION['agreement_accepted'])) |
1666
|
|
|
{ |
1667
|
7 |
|
$_SESSION['agreement_accepted'] = null; |
1668
|
7 |
|
$context['accepted_agreement'] = array( |
1669
|
|
|
'errors' => array( |
1670
|
|
|
'accepted_agreement' => $txt['agreement_accepted'] |
1671
|
|
|
) |
1672
|
|
|
); |
1673
|
|
|
} |
1674
|
|
|
|
1675
|
|
|
if (!empty($_SESSION['privacypolicy_accepted'])) |
1676
|
|
|
{ |
1677
|
7 |
|
$_SESSION['privacypolicy_accepted'] = null; |
1678
|
|
|
$context['accepted_agreement'] = array( |
1679
|
7 |
|
'errors' => array( |
1680
|
|
|
'accepted_privacy_policy' => $txt['privacypolicy_accepted'] |
1681
|
|
|
) |
1682
|
7 |
|
); |
1683
|
|
|
} |
1684
|
|
|
|
1685
|
7 |
|
theme()->loadThemeJavascript(); |
1686
|
|
|
|
1687
|
|
|
Hooks::instance()->newPath(array('$themedir' => $settings['theme_dir'])); |
1688
|
7 |
|
|
1689
|
7 |
|
// Any files to include at this point? |
1690
|
|
|
call_integration_include_hook('integrate_theme_include'); |
1691
|
|
|
|
1692
|
|
|
// Call load theme integration functions. |
1693
|
|
|
call_integration_hook('integrate_load_theme'); |
1694
|
|
|
|
1695
|
|
|
// We are ready to go. |
1696
|
|
|
$context['theme_loaded'] = true; |
1697
|
|
|
} |
1698
|
7 |
|
|
1699
|
|
|
/** |
1700
|
|
|
* Detects url and checks against expected boardurl |
1701
|
7 |
|
* |
1702
|
7 |
|
* Attempts to correct improper URL's |
1703
|
|
|
*/ |
1704
|
|
|
function loadThemeUrls() |
1705
|
|
|
{ |
1706
|
|
|
global $scripturl, $boardurl, $modSettings; |
1707
|
|
|
|
1708
|
|
|
// Check to see if they're accessing it from the wrong place. |
1709
|
|
|
if (isset($_SERVER['HTTP_HOST']) || isset($_SERVER['SERVER_NAME'])) |
1710
|
7 |
|
{ |
1711
|
7 |
|
$detected_url = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 'https://' : 'http://'; |
1712
|
|
|
$detected_url .= empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST']; |
1713
|
|
|
$temp = preg_replace('~/' . basename($scripturl) . '(/.+)?$~', '', strtr(dirname($_SERVER['PHP_SELF']), '\\', '/')); |
1714
|
|
|
if ($temp != '/') |
1715
|
|
|
$detected_url .= $temp; |
1716
|
|
|
} |
1717
|
|
|
|
1718
|
|
|
if (isset($detected_url) && $detected_url != $boardurl) |
1719
|
|
|
{ |
1720
|
|
|
// Try #1 - check if it's in a list of alias addresses. |
1721
|
|
|
if (!empty($modSettings['forum_alias_urls'])) |
1722
|
|
|
{ |
1723
|
|
|
$aliases = explode(',', $modSettings['forum_alias_urls']); |
1724
|
|
|
foreach ($aliases as $alias) |
1725
|
|
|
{ |
1726
|
|
|
// Rip off all the boring parts, spaces, etc. |
1727
|
|
|
if ($detected_url == trim($alias) || strtr($detected_url, array('http://' => '', 'https://' => '')) == trim($alias)) |
1728
|
|
|
$do_fix = true; |
1729
|
|
|
} |
1730
|
|
|
} |
1731
|
|
|
|
1732
|
|
|
// Hmm... check #2 - is it just different by a www? Send them to the correct place!! |
1733
|
|
|
if (empty($do_fix) && strtr($detected_url, array('://' => '://www.')) == $boardurl && (empty($_GET) || count($_GET) == 1) && ELK != 'SSI') |
|
|
|
|
1734
|
|
|
{ |
1735
|
|
|
// Okay, this seems weird, but we don't want an endless loop - this will make $_GET not empty ;). |
1736
|
|
|
if (empty($_GET)) |
1737
|
|
|
redirectexit('wwwRedirect'); |
1738
|
|
|
else |
1739
|
|
|
{ |
1740
|
|
|
if (key($_GET) !== 'wwwRedirect') |
1741
|
|
|
redirectexit('wwwRedirect;' . key($_GET) . '=' . current($_GET)); |
1742
|
|
|
} |
1743
|
|
|
} |
1744
|
|
|
|
1745
|
|
|
// #3 is just a check for SSL... |
1746
|
|
|
if (strtr($detected_url, array('https://' => 'http://')) == $boardurl) |
1747
|
7 |
|
$do_fix = true; |
1748
|
|
|
|
1749
|
|
|
// Okay, #4 - perhaps it's an IP address? We're gonna want to use that one, then. (assuming it's the IP or something...) |
1750
|
|
|
if (!empty($do_fix) || preg_match('~^http[s]?://(?:[\d\.:]+|\[[\d:]+\](?::\d+)?)(?:$|/)~', $detected_url) == 1) |
|
|
|
|
1751
|
|
|
{ |
1752
|
|
|
fixThemeUrls($detected_url); |
1753
|
|
|
} |
1754
|
7 |
|
} |
1755
|
|
|
} |
1756
|
|
|
|
1757
|
|
|
/** |
1758
|
7 |
|
* Loads various theme related settings into context and sets system wide theme defaults |
1759
|
7 |
|
*/ |
1760
|
7 |
|
function loadThemeContext() |
1761
|
7 |
|
{ |
1762
|
7 |
|
global $context, $settings, $modSettings, $txt; |
1763
|
7 |
|
|
1764
|
7 |
|
// Some basic information... |
1765
|
7 |
|
$init = array( |
1766
|
7 |
|
'html_headers' => '', |
1767
|
|
|
'links' => array(), |
1768
|
7 |
|
'css_files' => array(), |
1769
|
7 |
|
'javascript_files' => array(), |
1770
|
|
|
'css_rules' => array(), |
1771
|
|
|
'javascript_inline' => array('standard' => array(), 'defer' => array()), |
1772
|
7 |
|
'javascript_vars' => array(), |
1773
|
7 |
|
); |
1774
|
|
|
foreach ($init as $area => $value) |
1775
|
7 |
|
{ |
1776
|
7 |
|
$context[$area] = isset($context[$area]) ? $context[$area] : $value; |
1777
|
|
|
} |
1778
|
7 |
|
|
1779
|
7 |
|
// Set a couple of bits for the template. |
1780
|
|
|
$context['right_to_left'] = !empty($txt['lang_rtl']); |
1781
|
7 |
|
$context['tabindex'] = 1; |
1782
|
|
|
|
1783
|
7 |
|
$context['theme_variant'] = ''; |
1784
|
7 |
|
$context['theme_variant_url'] = ''; |
1785
|
|
|
|
1786
|
|
|
$context['menu_separator'] = !empty($settings['use_image_buttons']) ? ' ' : ' | '; |
1787
|
7 |
|
$context['can_register'] = empty($modSettings['registration_method']) || $modSettings['registration_method'] != 3; |
1788
|
|
|
|
1789
|
|
|
foreach (array('theme_header', 'upper_content') as $call) |
1790
|
7 |
|
{ |
1791
|
7 |
|
if (!isset($context[$call . '_callbacks'])) |
1792
|
|
|
{ |
1793
|
|
|
$context[$call . '_callbacks'] = array(); |
1794
|
|
|
} |
1795
|
|
|
} |
1796
|
|
|
|
1797
|
|
|
// This allows sticking some HTML on the page output - useful for controls. |
1798
|
7 |
|
$context['insert_after_template'] = ''; |
1799
|
|
|
} |
1800
|
|
|
|
1801
|
7 |
|
/** |
1802
|
7 |
|
* Loads basic user information in to $context['user'] |
1803
|
7 |
|
*/ |
1804
|
7 |
|
function loadUserContext() |
1805
|
7 |
|
{ |
1806
|
7 |
|
global $context, $user_info, $txt, $modSettings; |
1807
|
7 |
|
|
1808
|
|
|
// Set up the contextual user array. |
1809
|
7 |
|
$context['user'] = array( |
1810
|
7 |
|
'id' => $user_info['id'], |
1811
|
7 |
|
'is_logged' => !$user_info['is_guest'], |
1812
|
7 |
|
'is_guest' => &$user_info['is_guest'], |
1813
|
7 |
|
'is_admin' => &$user_info['is_admin'], |
1814
|
|
|
'is_mod' => &$user_info['is_mod'], |
1815
|
|
|
'is_moderator' => &$user_info['is_moderator'], |
1816
|
|
|
// A user can mod if they have permission to see the mod center, or they are a board/group/approval moderator. |
1817
|
7 |
|
'can_mod' => allowedTo('access_mod_center') || (!$user_info['is_guest'] && ($user_info['mod_cache']['gq'] != '0=1' || $user_info['mod_cache']['bq'] != '0=1' || ($modSettings['postmod_active'] && !empty($user_info['mod_cache']['ap'])))), |
1818
|
7 |
|
'username' => $user_info['username'], |
1819
|
3 |
|
'language' => $user_info['language'], |
1820
|
3 |
|
'email' => $user_info['email'], |
1821
|
4 |
|
'ignoreusers' => $user_info['ignoreusers'], |
1822
|
|
|
); |
1823
|
4 |
|
|
1824
|
4 |
|
// Something for the guests |
1825
|
|
|
if (!$context['user']['is_guest']) |
1826
|
7 |
|
{ |
1827
|
7 |
|
$context['user']['name'] = $user_info['name']; |
1828
|
7 |
|
} |
1829
|
7 |
|
elseif ($context['user']['is_guest'] && !empty($txt['guest_title'])) |
1830
|
|
|
{ |
1831
|
|
|
$context['user']['name'] = $txt['guest_title']; |
1832
|
|
|
} |
1833
|
|
|
|
1834
|
|
|
$context['user']['smiley_set'] = determineSmileySet($user_info['smiley_set'], $modSettings['smiley_sets_known']); |
1835
|
|
|
$context['smiley_enabled'] = $user_info['smiley_set'] !== 'none'; |
1836
|
|
|
$context['user']['smiley_path'] = $modSettings['smileys_url'] . '/' . $context['user']['smiley_set'] . '/'; |
1837
|
|
|
} |
1838
|
|
|
|
1839
|
|
|
/** |
1840
|
|
|
* Called if the detected URL is not the same as boardurl but is a common |
1841
|
|
|
* variation in which case it updates key system variables so it works. |
1842
|
|
|
* |
1843
|
|
|
* @param string $detected_url |
1844
|
|
|
*/ |
1845
|
|
|
function fixThemeUrls($detected_url) |
1846
|
|
|
{ |
1847
|
|
|
global $boardurl, $scripturl, $settings, $modSettings, $context, $board_info; |
1848
|
|
|
|
1849
|
|
|
// Caching is good ;). |
1850
|
|
|
$oldurl = $boardurl; |
1851
|
|
|
|
1852
|
|
|
// Fix $boardurl and $scripturl. |
1853
|
|
|
$boardurl = $detected_url; |
1854
|
|
|
$scripturl = strtr($scripturl, array($oldurl => $boardurl)); |
1855
|
|
|
$_SERVER['REQUEST_URL'] = strtr($_SERVER['REQUEST_URL'], array($oldurl => $boardurl)); |
1856
|
|
|
|
1857
|
|
|
// Fix the theme urls... |
1858
|
|
|
$settings['theme_url'] = strtr($settings['theme_url'], array($oldurl => $boardurl)); |
1859
|
|
|
$settings['default_theme_url'] = strtr($settings['default_theme_url'], array($oldurl => $boardurl)); |
1860
|
|
|
$settings['actual_theme_url'] = strtr($settings['actual_theme_url'], array($oldurl => $boardurl)); |
1861
|
|
|
$settings['images_url'] = strtr($settings['images_url'], array($oldurl => $boardurl)); |
1862
|
|
|
$settings['default_images_url'] = strtr($settings['default_images_url'], array($oldurl => $boardurl)); |
1863
|
|
|
$settings['actual_images_url'] = strtr($settings['actual_images_url'], array($oldurl => $boardurl)); |
1864
|
|
|
|
1865
|
|
|
// And just a few mod settings :). |
1866
|
|
|
$modSettings['smileys_url'] = strtr($modSettings['smileys_url'], array($oldurl => $boardurl)); |
1867
|
|
|
$modSettings['avatar_url'] = strtr($modSettings['avatar_url'], array($oldurl => $boardurl)); |
1868
|
|
|
|
1869
|
|
|
// Clean up after loadBoard(). |
1870
|
|
|
if (isset($board_info['moderators'])) |
1871
|
|
|
{ |
1872
|
|
|
foreach ($board_info['moderators'] as $k => $dummy) |
1873
|
|
|
{ |
1874
|
|
|
$board_info['moderators'][$k]['href'] = strtr($dummy['href'], array($oldurl => $boardurl)); |
1875
|
|
|
$board_info['moderators'][$k]['link'] = strtr($dummy['link'], array('"' . $oldurl => '"' . $boardurl)); |
1876
|
|
|
} |
1877
|
|
|
} |
1878
|
|
|
|
1879
|
|
|
foreach ($context['linktree'] as $k => $dummy) |
1880
|
|
|
$context['linktree'][$k]['url'] = strtr($dummy['url'], array($oldurl => $boardurl)); |
1881
|
|
|
} |
1882
|
|
|
|
1883
|
|
|
/** |
1884
|
|
|
* Determine the current user's smiley set |
1885
|
7 |
|
* |
1886
|
|
|
* @param mixed[] $user_smiley_set |
1887
|
7 |
|
* @param mixed[] $known_smiley_sets |
1888
|
7 |
|
* |
1889
|
7 |
|
* @return mixed |
1890
|
7 |
|
*/ |
1891
|
|
|
function determineSmileySet($user_smiley_set, $known_smiley_sets) |
1892
|
|
|
{ |
1893
|
|
|
global $modSettings, $settings; |
1894
|
|
|
|
1895
|
|
|
if ((!in_array($user_smiley_set, explode(',', $known_smiley_sets)) && $user_smiley_set !== 'none') || empty($modSettings['smiley_sets_enable'])) |
|
|
|
|
1896
|
7 |
|
{ |
1897
|
|
|
$set = !empty($settings['smiley_sets_default']) ? $settings['smiley_sets_default'] : $modSettings['smiley_sets_default']; |
1898
|
|
|
} |
1899
|
|
|
else |
1900
|
|
|
{ |
1901
|
|
|
$set = $user_smiley_set; |
1902
|
|
|
} |
1903
|
|
|
|
1904
|
|
|
return $set; |
1905
|
|
|
} |
1906
|
|
|
|
1907
|
2 |
|
/** |
1908
|
|
|
* This loads the bare minimum data. |
1909
|
2 |
|
* |
1910
|
2 |
|
* - Needed by scheduled tasks, |
1911
|
|
|
* - Needed by any other code that needs language files before the forum (the theme) is loaded. |
1912
|
|
|
*/ |
1913
|
|
|
function loadEssentialThemeData() |
1914
|
2 |
|
{ |
1915
|
|
|
global $settings, $modSettings, $mbname, $context; |
1916
|
|
|
|
1917
|
2 |
|
if (function_exists('database') === false) |
1918
|
|
|
{ |
1919
|
|
|
throw new \Exception(''); |
1920
|
|
|
} |
1921
|
2 |
|
|
1922
|
|
|
$db = database(); |
1923
|
2 |
|
|
1924
|
2 |
|
// Get all the default theme variables. |
1925
|
2 |
|
$db->fetchQueryCallback(' |
1926
|
|
|
SELECT id_theme, variable, value |
1927
|
|
|
FROM {db_prefix}themes |
1928
|
2 |
|
WHERE id_member = {int:no_member} |
1929
|
|
|
AND id_theme IN (1, {int:theme_guests})', |
1930
|
2 |
|
array( |
1931
|
|
|
'no_member' => 0, |
1932
|
|
|
'theme_guests' => $modSettings['theme_guests'], |
1933
|
2 |
|
), |
1934
|
2 |
|
function ($row) |
|
|
|
|
1935
|
2 |
|
{ |
1936
|
2 |
|
global $settings; |
1937
|
|
|
|
1938
|
|
|
$settings[$row['variable']] = $row['value']; |
1939
|
2 |
|
|
1940
|
2 |
|
// Is this the default theme? |
1941
|
|
|
if (in_array($row['variable'], array('theme_dir', 'theme_url', 'images_url')) && $row['id_theme'] == '1') |
1942
|
|
|
$settings['default_' . $row['variable']] = $row['value']; |
1943
|
|
|
} |
1944
|
|
|
); |
1945
|
2 |
|
|
1946
|
2 |
|
// Check we have some directories setup. |
1947
|
|
|
if (!Templates::instance()->hasDirectories()) |
1948
|
2 |
|
{ |
1949
|
2 |
|
Templates::instance()->reloadDirectories($settings); |
1950
|
|
|
} |
1951
|
|
|
|
1952
|
|
|
// Assume we want this. |
1953
|
|
|
$context['forum_name'] = $mbname; |
1954
|
|
|
$context['forum_name_html_safe'] = $context['forum_name']; |
1955
|
|
|
|
1956
|
|
|
loadLanguage('index+Addons'); |
1957
|
|
|
} |
1958
|
|
|
|
1959
|
|
|
/** |
1960
|
|
|
* Load a template - if the theme doesn't include it, use the default. |
1961
|
|
|
* |
1962
|
|
|
* What it does: |
1963
|
|
|
* |
1964
|
|
|
* - loads a template file with the name template_name from the current, default, or base theme. |
1965
|
|
|
* - detects a wrong default theme directory and tries to work around it. |
1966
|
|
|
* - can be used to only load style sheets by using false as the template name |
1967
|
|
|
* loading of style sheets with this function is deprecated, use loadCSSFile instead |
1968
|
|
|
* - if $settings['template_dirs'] is empty, it delays the loading of the template |
1969
|
|
|
* |
1970
|
|
|
* @uses the requireTemplate() function to actually load the file. |
1971
|
|
|
* @param string|false $template_name |
1972
|
13 |
|
* @param string[]|string $style_sheets any style sheets to load with the template |
1973
|
|
|
* @param bool $fatal = true if fatal is true, dies with an error message if the template cannot be found |
1974
|
|
|
* |
1975
|
|
|
* @return boolean|null |
1976
|
|
|
* @throws Elk_Exception |
1977
|
|
|
*/ |
1978
|
|
|
function loadTemplate($template_name, $style_sheets = array(), $fatal = true) |
1979
|
|
|
{ |
1980
|
|
|
return Templates::instance()->load($template_name, $style_sheets, $fatal); |
|
|
|
|
1981
|
|
|
} |
1982
|
|
|
|
1983
|
|
|
/** |
1984
|
|
|
* Load a sub-template. |
1985
|
|
|
* |
1986
|
|
|
* What it does: |
1987
|
|
|
* |
1988
|
|
|
* - loads the sub template specified by sub_template_name, which must be in an already-loaded template. |
1989
|
|
|
* - if ?debug is in the query string, shows administrators a marker after every sub template |
1990
|
|
|
* for debugging purposes. |
1991
|
|
|
* |
1992
|
|
|
* @param string $sub_template_name |
1993
|
|
|
* @param bool|string $fatal = false |
1994
|
|
|
* - $fatal = true is for templates that shouldn't get a 'pretty' error screen |
1995
|
|
|
* - $fatal = 'ignore' to skip |
1996
|
|
|
* @throws Elk_Exception |
1997
|
|
|
*/ |
1998
|
|
|
function loadSubTemplate($sub_template_name, $fatal = false) |
1999
|
|
|
{ |
2000
|
|
|
Templates::instance()->loadSubTemplate($sub_template_name, $fatal); |
2001
|
|
|
|
2002
|
|
|
return true; |
2003
|
|
|
} |
2004
|
|
|
|
2005
|
|
|
/** |
2006
|
|
|
* Add a CSS file for output later |
2007
|
|
|
* |
2008
|
|
|
* @param string[]|string $filenames string or array of filenames to work on |
2009
|
|
|
* @param mixed[] $params = array() |
2010
|
|
|
* Keys are the following: |
2011
|
|
|
* - ['local'] (true/false): define if the file is local |
2012
|
7 |
|
* - ['fallback'] (true/false): if false will attempt to load the file |
2013
|
|
|
* from the default theme if not found in the current theme |
2014
|
7 |
|
* - ['stale'] (true/false/string): if true or null, use cache stale, |
2015
|
7 |
|
* false do not, or used a supplied string |
2016
|
|
|
* @param string $id optional id to use in html id="" |
2017
|
7 |
|
*/ |
2018
|
7 |
|
function loadCSSFile($filenames, $params = array(), $id = '') |
2019
|
|
|
{ |
2020
|
7 |
|
global $context; |
2021
|
7 |
|
|
2022
|
|
|
if (empty($filenames)) |
2023
|
7 |
|
return; |
2024
|
7 |
|
|
2025
|
7 |
|
if (!is_array($filenames)) |
2026
|
7 |
|
$filenames = array($filenames); |
2027
|
|
|
|
2028
|
7 |
|
if (in_array('admin.css', $filenames)) |
2029
|
7 |
|
$filenames[] = $context['theme_variant'] . '/admin' . $context['theme_variant'] . '.css'; |
2030
|
|
|
|
2031
|
|
|
$params['subdir'] = isset($params['subdir']) ? $params['subdir'] : 'css'; |
2032
|
|
|
$params['extension'] = 'css'; |
2033
|
|
|
$params['index_name'] = 'css_files'; |
2034
|
|
|
$params['debug_index'] = 'sheets'; |
2035
|
|
|
|
2036
|
|
|
loadAssetFile($filenames, $params, $id); |
2037
|
|
|
} |
2038
|
|
|
|
2039
|
|
|
/** |
2040
|
|
|
* Add a Javascript file for output later |
2041
|
|
|
* |
2042
|
|
|
* What it does: |
2043
|
|
|
* |
2044
|
|
|
* - Can be passed an array of filenames, all which will have the same |
2045
|
|
|
* parameters applied, |
2046
|
|
|
* - if you need specific parameters on a per file basis, call it multiple times |
2047
|
|
|
* |
2048
|
|
|
* @param string[]|string $filenames string or array of filenames to work on |
2049
|
|
|
* @param mixed[] $params = array() |
2050
|
|
|
* Keys are the following: |
2051
|
|
|
* - ['local'] (true/false): define if the file is local, if file does not |
2052
|
|
|
* start with http its assumed local |
2053
|
|
|
* - ['defer'] (true/false): define if the file should load in <head> or before |
2054
|
|
|
* the closing <html> tag |
2055
|
|
|
* - ['fallback'] (true/false): if true will attempt to load the file from the |
2056
|
|
|
* default theme if not found in the current this is the default behavior |
2057
|
7 |
|
* if this is not supplied |
2058
|
7 |
|
* - ['async'] (true/false): if the script should be loaded asynchronously (HTML5) |
2059
|
|
|
* - ['stale'] (true/false/string): if true or null, use cache stale, false do |
2060
|
7 |
|
* not, or used a supplied string |
2061
|
7 |
|
* @param string $id = '' optional id to use in html id="" |
2062
|
7 |
|
*/ |
2063
|
7 |
|
function loadJavascriptFile($filenames, $params = array(), $id = '') |
2064
|
|
|
{ |
2065
|
7 |
|
if (empty($filenames)) |
2066
|
7 |
|
return; |
2067
|
|
|
|
2068
|
|
|
$params['subdir'] = isset($params['subdir']) ? $params['subdir'] : 'scripts'; |
2069
|
|
|
$params['extension'] = 'js'; |
2070
|
|
|
$params['index_name'] = 'js_files'; |
2071
|
|
|
$params['debug_index'] = 'javascript'; |
2072
|
|
|
|
2073
|
|
|
loadAssetFile($filenames, $params, $id); |
2074
|
|
|
} |
2075
|
|
|
|
2076
|
|
|
/** |
2077
|
|
|
* Add an asset (css, js or other) file for output later |
2078
|
|
|
* |
2079
|
|
|
* What it does: |
2080
|
|
|
* |
2081
|
|
|
* - Can be passed an array of filenames, all which will have the same |
2082
|
|
|
* parameters applied, |
2083
|
|
|
* - If you need specific parameters on a per file basis, call it multiple times |
2084
|
|
|
* |
2085
|
|
|
* @param string[]|string $filenames string or array of filenames to work on |
2086
|
|
|
* @param mixed[] $params = array() |
2087
|
|
|
* Keys are the following: |
2088
|
|
|
* - ['subdir'] (string): the subdirectory of the theme dir the file is in |
2089
|
|
|
* - ['extension'] (string): the extension of the file (e.g. css) |
2090
|
|
|
* - ['index_name'] (string): the $context index that holds the array of loaded |
2091
|
|
|
* files |
2092
|
|
|
* - ['debug_index'] (string): the index that holds the array of loaded |
2093
|
|
|
* files for debugging debug |
2094
|
|
|
* - ['local'] (true/false): define if the file is local, if file does not |
2095
|
|
|
* start with http or // (schema-less URLs) its assumed local. |
2096
|
|
|
* The parameter is in fact useful only for files whose name starts with |
2097
|
|
|
* http, in any other case (e.g. passing a local URL) the parameter would |
2098
|
|
|
* fail in properly adding the file to the list. |
2099
|
|
|
* - ['defer'] (true/false): define if the file should load in <head> or before |
2100
|
|
|
* the closing <html> tag |
2101
|
|
|
* - ['fallback'] (true/false): if true will attempt to load the file from the |
2102
|
|
|
* default theme if not found in the current this is the default behavior |
2103
|
7 |
|
* if this is not supplied |
2104
|
|
|
* - ['async'] (true/false): if the script should be loaded asynchronously (HTML5) |
2105
|
7 |
|
* - ['stale'] (true/false/string): if true or null, use cache stale, false do |
2106
|
7 |
|
* not, or used a supplied string |
2107
|
|
|
* @param string $id = '' optional id to use in html id="" |
2108
|
7 |
|
*/ |
2109
|
|
|
function loadAssetFile($filenames, $params = array(), $id = '') |
2110
|
7 |
|
{ |
2111
|
7 |
|
global $settings, $context, $db_show_debug; |
2112
|
|
|
|
2113
|
|
|
if (empty($filenames)) |
2114
|
7 |
|
return; |
2115
|
7 |
|
|
2116
|
|
|
$cache = Cache::instance(); |
2117
|
|
|
|
2118
|
|
|
if (!is_array($filenames)) |
2119
|
|
|
$filenames = array($filenames); |
2120
|
|
|
|
2121
|
7 |
|
// Static values for all these settings |
2122
|
7 |
|
if (!isset($params['stale']) || $params['stale'] === true) |
2123
|
|
|
$staler_string = CACHE_STALE; |
2124
|
|
|
elseif (is_string($params['stale'])) |
2125
|
7 |
|
$staler_string = ($params['stale'][0] === '?' ? $params['stale'] : '?' . $params['stale']); |
2126
|
7 |
|
else |
2127
|
7 |
|
$staler_string = ''; |
2128
|
7 |
|
|
2129
|
|
|
$fallback = (!empty($params['fallback']) && ($params['fallback'] === false)) ? false : true; |
2130
|
|
|
$dir = '/' . $params['subdir'] . '/'; |
2131
|
|
|
|
2132
|
|
|
// Whoa ... we've done this before yes? |
2133
|
|
|
$cache_name = 'load_' . $params['extension'] . '_' . hash('md5', $settings['theme_dir'] . implode('_', $filenames)); |
2134
|
|
|
$temp = array(); |
2135
|
|
|
if ($cache->getVar($temp, $cache_name, 600)) |
2136
|
|
|
{ |
2137
|
|
|
if (empty($context[$params['index_name']])) |
2138
|
|
|
$context[$params['index_name']] = array(); |
2139
|
|
|
|
2140
|
|
|
$context[$params['index_name']] += $temp; |
2141
|
|
|
|
2142
|
|
|
if ($db_show_debug === true) |
2143
|
|
|
{ |
2144
|
7 |
|
foreach ($temp as $temp_params) |
2145
|
|
|
{ |
2146
|
|
|
Debug::instance()->add($params['debug_index'], $temp_params['options']['basename'] . '(' . (!empty($temp_params['options']['local']) ? (!empty($temp_params['options']['url']) ? basename($temp_params['options']['url']) : basename($temp_params['options']['dir'])) : '') . ')'); |
2147
|
7 |
|
} |
2148
|
|
|
} |
2149
|
|
|
} |
2150
|
7 |
|
else |
2151
|
|
|
{ |
2152
|
7 |
|
$this_build = array(); |
2153
|
|
|
|
2154
|
|
|
// All the files in this group use the above parameters |
2155
|
|
|
foreach ($filenames as $filename) |
2156
|
|
|
{ |
2157
|
|
|
// Account for shorthand like admin.ext?xyz11 filenames |
2158
|
7 |
|
$has_cache_staler = strpos($filename, '.' . $params['extension'] . '?'); |
2159
|
7 |
|
if ($has_cache_staler) |
2160
|
|
|
{ |
2161
|
7 |
|
$cache_staler = $staler_string; |
2162
|
|
|
$params['basename'] = substr($filename, 0, $has_cache_staler + strlen($params['extension']) + 1); |
2163
|
|
|
} |
2164
|
7 |
|
else |
2165
|
7 |
|
{ |
2166
|
7 |
|
$cache_staler = $staler_string; |
2167
|
7 |
|
$params['basename'] = $filename; |
2168
|
7 |
|
} |
2169
|
|
|
$this_id = empty($id) ? strtr(basename($filename), '?', '_') : $id; |
2170
|
|
|
|
2171
|
7 |
|
// Is this a local file? |
2172
|
7 |
|
if (!empty($params['local']) || (substr($filename, 0, 4) !== 'http' && substr($filename, 0, 2) !== '//')) |
2173
|
|
|
{ |
2174
|
|
|
$params['local'] = true; |
2175
|
|
|
$params['dir'] = $settings['theme_dir'] . $dir; |
2176
|
|
|
$params['url'] = $settings['theme_url']; |
2177
|
|
|
|
2178
|
|
|
// Fallback if we are not already in the default theme |
2179
|
|
|
if ($fallback && ($settings['theme_dir'] !== $settings['default_theme_dir']) && !file_exists($settings['theme_dir'] . $dir . $params['basename'])) |
2180
|
|
|
{ |
2181
|
|
|
// Can't find it in this theme, how about the default? |
2182
|
|
|
if (file_exists($settings['default_theme_dir'] . $dir . $params['basename'])) |
2183
|
|
|
{ |
2184
|
7 |
|
$filename = $settings['default_theme_url'] . $dir . $params['basename'] . $cache_staler; |
2185
|
7 |
|
$params['dir'] = $settings['default_theme_dir'] . $dir; |
2186
|
|
|
$params['url'] = $settings['default_theme_url']; |
2187
|
|
|
} |
2188
|
7 |
|
else |
2189
|
7 |
|
$filename = false; |
2190
|
7 |
|
} |
2191
|
|
|
else |
2192
|
7 |
|
$filename = $settings['theme_url'] . $dir . $params['basename'] . $cache_staler; |
2193
|
7 |
|
} |
2194
|
|
|
|
2195
|
|
|
// Add it to the array for use in the template |
2196
|
7 |
|
if (!empty($filename)) |
2197
|
|
|
{ |
2198
|
|
|
$this_build[$this_id] = $context[$params['index_name']][$this_id] = array('filename' => $filename, 'options' => $params); |
2199
|
7 |
|
|
2200
|
7 |
|
if ($db_show_debug === true) |
2201
|
|
|
{ |
2202
|
7 |
|
Debug::instance()->add($params['debug_index'], $params['basename'] . '(' . (!empty($params['local']) ? (!empty($params['url']) ? basename($params['url']) : basename($params['dir'])) : '') . ')'); |
2203
|
|
|
} |
2204
|
|
|
} |
2205
|
|
|
|
2206
|
|
|
// Save it so we don't have to build this so often |
2207
|
|
|
$cache->put($cache_name, $this_build, 600); |
2208
|
|
|
} |
2209
|
|
|
} |
2210
|
|
|
} |
2211
|
|
|
|
2212
|
2 |
|
/** |
2213
|
2 |
|
* Add a Javascript variable for output later (for feeding text strings and similar to JS) |
2214
|
|
|
* |
2215
|
|
|
* @param mixed[] $vars array of vars to include in the output done as 'varname' => 'var value' |
2216
|
|
|
* @param bool $escape = false, whether or not to escape the value |
2217
|
|
|
*/ |
2218
|
|
|
function addJavascriptVar($vars, $escape = false) |
2219
|
|
|
{ |
2220
|
|
|
theme()->addJavascriptVar($vars, $escape); |
2221
|
|
|
} |
2222
|
|
|
|
2223
|
|
|
/** |
2224
|
|
|
* Add a block of inline Javascript code to be executed later |
2225
|
|
|
* |
2226
|
|
|
* What it does: |
2227
|
|
|
* |
2228
|
|
|
* - only use this if you have to, generally external JS files are better, but for very small scripts |
2229
|
4 |
|
* or for scripts that require help from PHP/whatever, this can be useful. |
2230
|
4 |
|
* - all code added with this function is added to the same <script> tag so do make sure your JS is clean! |
2231
|
|
|
* |
2232
|
|
|
* @param string $javascript |
2233
|
|
|
* @param bool $defer = false, define if the script should load in <head> or before the closing <html> tag |
2234
|
|
|
*/ |
2235
|
|
|
function addInlineJavascript($javascript, $defer = false) |
2236
|
|
|
{ |
2237
|
|
|
theme()->addInlineJavascript($javascript, $defer); |
2238
|
|
|
} |
2239
|
|
|
|
2240
|
|
|
/** |
2241
|
|
|
* Load a language file. |
2242
|
|
|
* |
2243
|
|
|
* - Tries the current and default themes as well as the user and global languages. |
2244
|
|
|
* |
2245
|
37 |
|
* @param string $template_name |
2246
|
37 |
|
* @param string $lang = '' |
2247
|
37 |
|
* @param bool $fatal = true |
2248
|
|
|
* @param bool $force_reload = false |
2249
|
|
|
* @return string The language actually loaded. |
2250
|
37 |
|
*/ |
2251
|
37 |
|
function loadLanguage($template_name, $lang = '', $fatal = true, $force_reload = false) |
2252
|
|
|
{ |
2253
|
37 |
|
global $user_info, $language, $settings, $modSettings; |
2254
|
37 |
|
global $db_show_debug, $txt; |
2255
|
|
|
static $already_loaded = array(); |
2256
|
|
|
|
2257
|
17 |
|
// Default to the user's language. |
2258
|
17 |
|
if ($lang == '') |
2259
|
|
|
$lang = isset($user_info['language']) ? $user_info['language'] : $language; |
2260
|
|
|
|
2261
|
17 |
|
if (!$force_reload && isset($already_loaded[$template_name]) && $already_loaded[$template_name] == $lang) |
2262
|
17 |
|
return $lang; |
2263
|
|
|
|
2264
|
|
|
// Do we want the English version of language file as fallback? |
2265
|
17 |
|
if (empty($modSettings['disable_language_fallback']) && $lang != 'english') |
2266
|
17 |
|
loadLanguage($template_name, 'english', false); |
2267
|
17 |
|
|
2268
|
|
|
// Make sure we have $settings - if not we're in trouble and need to find it! |
2269
|
17 |
|
if (empty($settings['default_theme_dir'])) |
2270
|
|
|
loadEssentialThemeData(); |
2271
|
17 |
|
|
2272
|
|
|
// What theme are we in? |
2273
|
17 |
|
$theme_name = basename($settings['theme_url']); |
2274
|
17 |
|
if (empty($theme_name)) |
2275
|
|
|
$theme_name = 'unknown'; |
2276
|
|
|
|
2277
|
|
|
$fix_arrays = false; |
2278
|
17 |
|
// For each file open it up and write it out! |
2279
|
17 |
|
foreach (explode('+', $template_name) as $template) |
2280
|
17 |
|
{ |
2281
|
|
|
if ($template === 'index') |
2282
|
|
|
$fix_arrays = true; |
2283
|
17 |
|
|
2284
|
17 |
|
// Obviously, the current theme is most important to check. |
2285
|
|
|
$attempts = array( |
2286
|
|
|
array($settings['theme_dir'], $template, $lang, $settings['theme_url']), |
2287
|
|
|
array($settings['theme_dir'], $template, $language, $settings['theme_url']), |
2288
|
|
|
); |
2289
|
|
|
|
2290
|
17 |
|
// Do we have a base theme to worry about? |
2291
|
17 |
|
if (isset($settings['base_theme_dir'])) |
2292
|
|
|
{ |
2293
|
|
|
$attempts[] = array($settings['base_theme_dir'], $template, $lang, $settings['base_theme_url']); |
2294
|
17 |
|
$attempts[] = array($settings['base_theme_dir'], $template, $language, $settings['base_theme_url']); |
2295
|
17 |
|
} |
2296
|
|
|
|
2297
|
|
|
// Fall back on the default theme if necessary. |
2298
|
|
|
$attempts[] = array($settings['default_theme_dir'], $template, $lang, $settings['default_theme_url']); |
2299
|
|
|
$attempts[] = array($settings['default_theme_dir'], $template, $language, $settings['default_theme_url']); |
2300
|
17 |
|
|
2301
|
|
|
// Fall back on the English language if none of the preferred languages can be found. |
2302
|
|
|
if (!in_array('english', array($lang, $language))) |
2303
|
17 |
|
{ |
2304
|
17 |
|
$attempts[] = array($settings['theme_dir'], $template, 'english', $settings['theme_url']); |
2305
|
|
|
$attempts[] = array($settings['default_theme_dir'], $template, 'english', $settings['default_theme_url']); |
2306
|
17 |
|
} |
2307
|
17 |
|
|
2308
|
|
|
$templates = Templates::instance(); |
2309
|
17 |
|
|
2310
|
|
|
// Try to find the language file. |
2311
|
|
|
$found = false; |
2312
|
17 |
|
foreach ($attempts as $k => $file) |
2313
|
|
|
{ |
2314
|
17 |
|
if (file_exists($file[0] . '/languages/' . $file[2] . '/' . $file[1] . '.' . $file[2] . '.php')) |
2315
|
|
|
{ |
2316
|
|
|
// Include it! |
2317
|
|
|
$templates->templateInclude($file[0] . '/languages/' . $file[2] . '/' . $file[1] . '.' . $file[2] . '.php'); |
2318
|
|
|
|
2319
|
|
|
// Note that we found it. |
2320
|
|
|
$found = true; |
2321
|
|
|
|
2322
|
|
|
break; |
2323
|
|
|
} |
2324
|
|
|
// @deprecated since 1.0 - old way of archiving language files, all in one directory |
2325
|
|
|
elseif (file_exists($file[0] . '/languages/' . $file[1] . '.' . $file[2] . '.php')) |
2326
|
|
|
{ |
2327
|
17 |
|
// Include it! |
2328
|
|
|
$templates->templateInclude($file[0] . '/languages/' . $file[1] . '.' . $file[2] . '.php'); |
2329
|
|
|
|
2330
|
17 |
|
// Note that we found it. |
2331
|
17 |
|
$found = true; |
2332
|
|
|
|
2333
|
|
|
break; |
2334
|
|
|
} |
2335
|
17 |
|
} |
2336
|
|
|
|
2337
|
|
|
// That couldn't be found! Log the error, but *try* to continue normally. |
2338
|
17 |
|
if (!$found && $fatal) |
2339
|
|
|
{ |
2340
|
|
|
Errors::instance()->log_error(sprintf($txt['theme_language_error'], $template_name . '.' . $lang, 'template')); |
2341
|
17 |
|
break; |
2342
|
17 |
|
} |
2343
|
|
|
} |
2344
|
|
|
|
2345
|
|
|
if ($fix_arrays) |
2346
|
|
|
fix_calendar_text(); |
2347
|
17 |
|
|
2348
|
|
|
// Keep track of what we're up to soldier. |
2349
|
|
|
if ($db_show_debug === true) |
2350
|
17 |
|
{ |
2351
|
|
|
Debug::instance()->add('language_files', $template_name . '.' . $lang . ' (' . $theme_name . ')'); |
2352
|
|
|
} |
2353
|
|
|
|
2354
|
|
|
// Remember what we have loaded, and in which language. |
2355
|
|
|
$already_loaded[$template_name] = $lang; |
2356
|
|
|
|
2357
|
|
|
// Return the language actually loaded. |
2358
|
|
|
return $lang; |
2359
|
|
|
} |
2360
|
|
|
|
2361
|
|
|
/** |
2362
|
|
|
* Loads / Sets arrays for use in date display |
2363
|
|
|
*/ |
2364
|
|
|
function fix_calendar_text() |
2365
|
|
|
{ |
2366
|
|
|
global $txt; |
2367
|
|
|
|
2368
|
|
|
$txt['days'] = array( |
2369
|
|
|
$txt['sunday'], |
2370
|
|
|
$txt['monday'], |
2371
|
|
|
$txt['tuesday'], |
2372
|
|
|
$txt['wednesday'], |
2373
|
|
|
$txt['thursday'], |
2374
|
|
|
$txt['friday'], |
2375
|
|
|
$txt['saturday'], |
2376
|
|
|
); |
2377
|
|
|
$txt['days_short'] = array( |
2378
|
|
|
$txt['sunday_short'], |
2379
|
|
|
$txt['monday_short'], |
2380
|
|
|
$txt['tuesday_short'], |
2381
|
|
|
$txt['wednesday_short'], |
2382
|
|
|
$txt['thursday_short'], |
2383
|
|
|
$txt['friday_short'], |
2384
|
|
|
$txt['saturday_short'], |
2385
|
|
|
); |
2386
|
|
|
$txt['months'] = array( |
2387
|
|
|
1 => $txt['january'], |
2388
|
|
|
$txt['february'], |
2389
|
|
|
$txt['march'], |
2390
|
|
|
$txt['april'], |
2391
|
|
|
$txt['may'], |
2392
|
|
|
$txt['june'], |
2393
|
|
|
$txt['july'], |
2394
|
|
|
$txt['august'], |
2395
|
|
|
$txt['september'], |
2396
|
|
|
$txt['october'], |
2397
|
|
|
$txt['november'], |
2398
|
|
|
$txt['december'], |
2399
|
|
|
); |
2400
|
|
|
$txt['months_titles'] = array( |
2401
|
|
|
1 => $txt['january_titles'], |
2402
|
|
|
$txt['february_titles'], |
2403
|
|
|
$txt['march_titles'], |
2404
|
|
|
$txt['april_titles'], |
2405
|
|
|
$txt['may_titles'], |
2406
|
|
|
$txt['june_titles'], |
2407
|
|
|
$txt['july_titles'], |
2408
|
|
|
$txt['august_titles'], |
2409
|
|
|
$txt['september_titles'], |
2410
|
|
|
$txt['october_titles'], |
2411
|
|
|
$txt['november_titles'], |
2412
|
|
|
$txt['december_titles'], |
2413
|
|
|
); |
2414
|
|
|
$txt['months_short'] = array( |
2415
|
|
|
1 => $txt['january_short'], |
2416
|
|
|
$txt['february_short'], |
2417
|
|
|
$txt['march_short'], |
2418
|
|
|
$txt['april_short'], |
2419
|
|
|
$txt['may_short'], |
2420
|
|
|
$txt['june_short'], |
2421
|
|
|
$txt['july_short'], |
2422
|
|
|
$txt['august_short'], |
2423
|
|
|
$txt['september_short'], |
2424
|
|
|
$txt['october_short'], |
2425
|
|
|
$txt['november_short'], |
2426
|
|
|
$txt['december_short'], |
2427
|
|
|
); |
2428
|
|
|
} |
2429
|
|
|
|
2430
|
|
|
/** |
2431
|
|
|
* Get all parent boards (requires first parent as parameter) |
2432
|
|
|
* |
2433
|
|
|
* What it does: |
2434
|
|
|
* |
2435
|
|
|
* - It finds all the parents of id_parent, and that board itself. |
2436
|
|
|
* - Additionally, it detects the moderators of said boards. |
2437
|
|
|
* - Returns an array of information about the boards found. |
2438
|
11 |
|
* |
2439
|
|
|
* @param int $id_parent |
2440
|
11 |
|
* |
2441
|
11 |
|
* @return array |
2442
|
11 |
|
* @throws Elk_Exception parent_not_found |
2443
|
|
|
*/ |
2444
|
|
|
function getBoardParents($id_parent) |
2445
|
11 |
|
{ |
2446
|
11 |
|
global $scripturl; |
2447
|
11 |
|
|
2448
|
11 |
|
$db = database(); |
2449
|
|
|
$cache = Cache::instance(); |
2450
|
|
|
$boards = array(); |
2451
|
11 |
|
|
2452
|
|
|
// First check if we have this cached already. |
2453
|
10 |
|
if (!$cache->getVar($boards, 'board_parents-' . $id_parent, 480)) |
2454
|
|
|
{ |
2455
|
|
|
$boards = array(); |
2456
|
|
|
$original_parent = $id_parent; |
2457
|
|
|
|
2458
|
|
|
// Loop while the parent is non-zero. |
2459
|
|
|
while ($id_parent != 0) |
2460
|
10 |
|
{ |
2461
|
|
|
$result = $db->query('', ' |
2462
|
10 |
|
SELECT |
2463
|
|
|
b.id_parent, b.name, {int:board_parent} AS id_board, COALESCE(mem.id_member, 0) AS id_moderator, |
2464
|
10 |
|
mem.real_name, b.child_level |
2465
|
|
|
FROM {db_prefix}boards AS b |
2466
|
10 |
|
LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = b.id_board) |
2467
|
10 |
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member) |
2468
|
|
|
WHERE b.id_board = {int:board_parent}', |
2469
|
|
|
array( |
2470
|
10 |
|
'board_parent' => $id_parent, |
2471
|
|
|
) |
2472
|
10 |
|
); |
2473
|
10 |
|
// In the EXTREMELY unlikely event this happens, give an error message. |
2474
|
10 |
|
if ($db->num_rows($result) == 0) |
2475
|
10 |
|
{ |
2476
|
10 |
|
throw new Elk_Exception('parent_not_found', 'critical'); |
2477
|
10 |
|
} |
2478
|
10 |
|
while ($row = $db->fetch_assoc($result)) |
2479
|
10 |
|
{ |
2480
|
10 |
|
if (!isset($boards[$row['id_board']])) |
2481
|
10 |
|
{ |
2482
|
|
|
$id_parent = $row['id_parent']; |
2483
|
|
|
$boards[$row['id_board']] = array( |
2484
|
10 |
|
'url' => $scripturl . '?board=' . $row['id_board'] . '.0', |
2485
|
10 |
|
'name' => $row['name'], |
2486
|
|
|
'level' => $row['child_level'], |
2487
|
|
|
'moderators' => array() |
2488
|
|
|
); |
2489
|
|
|
} |
2490
|
|
|
|
2491
|
|
|
// If a moderator exists for this board, add that moderator for all children too. |
2492
|
|
|
if (!empty($row['id_moderator'])) |
2493
|
|
|
foreach ($boards as $id => $dummy) |
2494
|
10 |
|
{ |
2495
|
10 |
|
$boards[$id]['moderators'][$row['id_moderator']] = array( |
2496
|
10 |
|
'id' => $row['id_moderator'], |
2497
|
|
|
'name' => $row['real_name'], |
2498
|
11 |
|
'href' => $scripturl . '?action=profile;u=' . $row['id_moderator'], |
2499
|
11 |
|
'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_moderator'] . '">' . $row['real_name'] . '</a>' |
2500
|
|
|
); |
2501
|
11 |
|
} |
2502
|
|
|
} |
2503
|
|
|
$db->free_result($result); |
2504
|
|
|
} |
2505
|
|
|
|
2506
|
|
|
$cache->put('board_parents-' . $original_parent, $boards, 480); |
2507
|
|
|
} |
2508
|
|
|
|
2509
|
|
|
return $boards; |
2510
|
|
|
} |
2511
|
1 |
|
|
2512
|
|
|
/** |
2513
|
1 |
|
* Attempt to reload our known languages. |
2514
|
|
|
* |
2515
|
|
|
* @param bool $use_cache = true |
2516
|
1 |
|
*/ |
2517
|
|
|
function getLanguages($use_cache = true) |
2518
|
1 |
|
{ |
2519
|
1 |
|
global $settings; |
2520
|
|
|
|
2521
|
1 |
|
$cache = Cache::instance(); |
2522
|
1 |
|
|
2523
|
|
|
// Either we don't use the cache, or its expired. |
2524
|
|
|
$languages = array(); |
2525
|
|
|
|
2526
|
1 |
|
if (!$use_cache || !$cache->getVar($languages, 'known_languages', $cache->levelLowerThan(2) ? 86400 : 3600)) |
2527
|
1 |
|
{ |
2528
|
1 |
|
// If we don't have our theme information yet, lets get it. |
2529
|
|
|
if (empty($settings['default_theme_dir'])) |
2530
|
|
|
loadTheme(0, false); |
2531
|
1 |
|
|
2532
|
1 |
|
// Default language directories to try. |
2533
|
|
|
$language_directories = array( |
2534
|
|
|
$settings['default_theme_dir'] . '/languages', |
2535
|
1 |
|
$settings['actual_theme_dir'] . '/languages', |
2536
|
|
|
); |
2537
|
1 |
|
|
2538
|
|
|
// We possibly have a base theme directory. |
2539
|
|
|
if (!empty($settings['base_theme_dir'])) |
2540
|
1 |
|
$language_directories[] = $settings['base_theme_dir'] . '/languages'; |
2541
|
1 |
|
|
2542
|
|
|
// Remove any duplicates. |
2543
|
1 |
|
$language_directories = array_unique($language_directories); |
2544
|
1 |
|
|
2545
|
|
|
foreach ($language_directories as $language_dir) |
2546
|
|
|
{ |
2547
|
1 |
|
// Can't look in here... doesn't exist! |
2548
|
1 |
|
if (!file_exists($language_dir)) |
2549
|
|
|
continue; |
2550
|
|
|
|
2551
|
1 |
|
$dir = dir($language_dir); |
2552
|
1 |
|
while ($entry = $dir->read()) |
2553
|
|
|
{ |
2554
|
|
|
// Only directories are interesting |
2555
|
1 |
|
if ($entry == '..' || !is_dir($dir->path . '/' . $entry)) |
2556
|
1 |
|
continue; |
2557
|
|
|
|
2558
|
1 |
|
// @todo at some point we may want to simplify that stuff (I mean scanning all the files just for index) |
2559
|
1 |
|
$file_dir = dir($dir->path . '/' . $entry); |
2560
|
1 |
|
while ($file_entry = $file_dir->read()) |
2561
|
1 |
|
{ |
2562
|
1 |
|
// Look for the index language file.... |
2563
|
|
|
if (!preg_match('~^index\.(.+)\.php$~', $file_entry, $matches)) |
2564
|
1 |
|
continue; |
2565
|
1 |
|
|
2566
|
1 |
|
$languages[$matches[1]] = array( |
2567
|
1 |
|
'name' => Util::ucwords(strtr($matches[1], array('_' => ' '))), |
2568
|
1 |
|
'selected' => false, |
2569
|
|
|
'filename' => $matches[1], |
2570
|
|
|
'location' => $language_dir . '/' . $entry . '/index.' . $matches[1] . '.php', |
2571
|
1 |
|
); |
2572
|
1 |
|
} |
2573
|
|
|
$file_dir->close(); |
2574
|
1 |
|
} |
2575
|
|
|
$dir->close(); |
2576
|
|
|
} |
2577
|
|
|
|
2578
|
|
|
// Lets cash in on this deal. |
2579
|
|
|
$cache->put('known_languages', $languages, $cache->isEnabled() && $cache->levelLowerThan(1) ? 86400 : 3600); |
2580
|
|
|
} |
2581
|
|
|
|
2582
|
|
|
return $languages; |
2583
|
|
|
} |
2584
|
|
|
|
2585
|
|
|
/** |
2586
|
|
|
* Initialize a database connection. |
2587
|
|
|
*/ |
2588
|
|
|
function loadDatabase() |
2589
|
|
|
{ |
2590
|
|
|
global $db_persist, $db_server, $db_user, $db_passwd, $db_port; |
2591
|
|
|
global $db_type, $db_name, $ssi_db_user, $ssi_db_passwd, $db_prefix; |
2592
|
|
|
|
2593
|
|
|
// Database stuffs |
2594
|
|
|
require_once(SOURCEDIR . '/database/Database.subs.php'); |
2595
|
|
|
|
2596
|
|
|
// Figure out what type of database we are using. |
2597
|
|
|
if (empty($db_type) || !file_exists(SOURCEDIR . '/database/Db-' . $db_type . '.class.php')) |
2598
|
|
|
$db_type = 'mysql'; |
2599
|
|
|
|
2600
|
|
|
// If we are in SSI try them first, but don't worry if it doesn't work, we have the normal username and password we can use. |
2601
|
|
|
if (ELK === 'SSI' && !empty($ssi_db_user) && !empty($ssi_db_passwd)) |
2602
|
|
|
$connection = elk_db_initiate($db_server, $db_name, $ssi_db_user, $ssi_db_passwd, $db_prefix, array('persist' => $db_persist, 'non_fatal' => true, 'dont_select_db' => true, 'port' => $db_port), $db_type); |
2603
|
|
|
|
2604
|
|
|
// Either we aren't in SSI mode, or it failed. |
2605
|
|
|
if (empty($connection)) |
2606
|
|
|
$connection = elk_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('persist' => $db_persist, 'dont_select_db' => ELK === 'SSI', 'port' => $db_port), $db_type); |
2607
|
|
|
|
2608
|
|
|
// Safe guard here, if there isn't a valid connection lets put a stop to it. |
2609
|
|
|
if (!$connection) |
2610
|
|
|
Errors::instance()->display_db_error(); |
2611
|
|
|
|
2612
|
|
|
// If in SSI mode fix up the prefix. |
2613
|
|
|
$db = database(); |
2614
|
|
|
if (ELK === 'SSI') |
|
|
|
|
2615
|
|
|
$db_prefix = $db->fix_prefix($db_prefix, $db_name); |
2616
|
|
|
|
2617
|
|
|
// Case sensitive database? Let's define a constant. |
2618
|
|
|
if ($db->db_case_sensitive() && !defined('DB_CASE_SENSITIVE')) |
2619
|
|
|
DEFINE('DB_CASE_SENSITIVE', '1'); |
2620
|
|
|
} |
2621
|
|
|
|
2622
|
|
|
/** |
2623
|
|
|
* Determine the user's avatar type and return the information as an array |
2624
|
|
|
* |
2625
|
|
|
* @todo this function seems more useful than expected, it should be improved. :P |
2626
|
2 |
|
* |
2627
|
|
|
* @event integrate_avatar allows access to $avatar array before it is returned |
2628
|
2 |
|
* @param mixed[] $profile array containing the users profile data |
2629
|
2 |
|
* |
2630
|
|
|
* @return mixed[] $avatar |
2631
|
2 |
|
*/ |
2632
|
|
|
function determineAvatar($profile) |
2633
|
|
|
{ |
2634
|
2 |
|
global $modSettings, $scripturl, $settings; |
2635
|
2 |
|
|
2636
|
|
|
if (empty($profile)) |
2637
|
|
|
return array(); |
2638
|
|
|
|
2639
|
|
|
$avatar_protocol = substr(strtolower($profile['avatar']), 0, 7); |
2640
|
|
|
|
2641
|
|
|
// uploaded avatar? |
2642
|
|
|
if ($profile['id_attach'] > 0 && empty($profile['avatar'])) |
2643
|
|
|
{ |
2644
|
|
|
// where are those pesky avatars? |
2645
|
|
|
$avatar_url = empty($profile['attachment_type']) ? $scripturl . '?action=dlattach;attach=' . $profile['id_attach'] . ';type=avatar' : $modSettings['custom_avatar_url'] . '/' . $profile['filename']; |
2646
|
|
|
|
2647
|
2 |
|
$avatar = array( |
2648
|
|
|
'name' => $profile['avatar'], |
2649
|
|
|
'image' => '<img class="avatar avatarresize" src="' . $avatar_url . '" alt="" />', |
2650
|
|
|
'href' => $avatar_url, |
2651
|
|
|
'url' => '', |
2652
|
|
|
); |
2653
|
|
|
} |
2654
|
|
|
// remote avatar? |
2655
|
|
|
elseif ($avatar_protocol === 'http://' || $avatar_protocol === 'https:/') |
2656
|
|
|
{ |
2657
|
2 |
|
$avatar = array( |
2658
|
|
|
'name' => $profile['avatar'], |
2659
|
|
|
'image' => '<img class="avatar avatarresize" src="' . $profile['avatar'] . '" alt="" />', |
2660
|
|
|
'href' => $profile['avatar'], |
2661
|
|
|
'url' => $profile['avatar'], |
2662
|
|
|
); |
2663
|
|
|
} |
2664
|
|
|
// Gravatar instead? |
2665
|
|
|
elseif (!empty($profile['avatar']) && $profile['avatar'] === 'gravatar') |
2666
|
|
|
{ |
2667
|
|
|
// Gravatars URL. |
2668
|
|
|
$gravatar_url = '//www.gravatar.com/avatar/' . hash('md5', strtolower($profile['email_address'])) . '?s=' . $modSettings['avatar_max_height'] . (!empty($modSettings['gravatar_rating']) ? ('&r=' . $modSettings['gravatar_rating']) : ''); |
2669
|
|
|
|
2670
|
2 |
|
$avatar = array( |
2671
|
|
|
'name' => $profile['avatar'], |
2672
|
|
|
'image' => '<img class="avatar avatarresize" src="' . $gravatar_url . '" alt="" />', |
2673
|
|
|
'href' => $gravatar_url, |
2674
|
|
|
'url' => $gravatar_url, |
2675
|
|
|
); |
2676
|
|
|
} |
2677
|
|
|
// an avatar from the gallery? |
2678
|
|
|
elseif (!empty($profile['avatar']) && !($avatar_protocol === 'http://' || $avatar_protocol === 'https:/')) |
2679
|
|
|
{ |
2680
|
2 |
|
$avatar = array( |
2681
|
|
|
'name' => $profile['avatar'], |
2682
|
|
|
'image' => '<img class="avatar avatarresize" src="' . $modSettings['avatar_url'] . '/' . $profile['avatar'] . '" alt="" />', |
2683
|
|
|
'href' => $modSettings['avatar_url'] . '/' . $profile['avatar'], |
2684
|
|
|
'url' => $modSettings['avatar_url'] . '/' . $profile['avatar'], |
2685
|
|
|
); |
2686
|
|
|
} |
2687
|
|
|
// no custom avatar found yet, maybe a default avatar? |
2688
|
|
|
elseif (!empty($modSettings['avatar_default']) && empty($profile['avatar']) && empty($profile['filename'])) |
2689
|
|
|
{ |
2690
|
|
|
// $settings not initialized? We can't do anything further.. |
2691
|
|
|
if (!empty($settings)) |
2692
|
|
|
{ |
2693
|
|
|
// Let's proceed with the default avatar. |
2694
|
|
|
// TODO: This should be incorporated into the theme. |
2695
|
|
|
$avatar = array( |
2696
|
|
|
'name' => '', |
2697
|
|
|
'image' => '<img class="avatar avatarresize" src="' . $settings['images_url'] . '/default_avatar.png" alt="" />', |
2698
|
|
|
'href' => $settings['images_url'] . '/default_avatar.png', |
2699
|
|
|
'url' => 'http://', |
2700
|
|
|
); |
2701
|
|
|
} |
2702
|
2 |
|
else |
2703
|
2 |
|
{ |
2704
|
2 |
|
$avatar = array(); |
2705
|
|
|
} |
2706
|
2 |
|
} |
2707
|
|
|
// finally ... |
2708
|
|
|
else |
2709
|
2 |
|
$avatar = array( |
2710
|
|
|
'name' => '', |
2711
|
2 |
|
'image' => '', |
2712
|
|
|
'href' => '', |
2713
|
2 |
|
'url' => '' |
2714
|
|
|
); |
2715
|
|
|
|
2716
|
|
|
// Make sure there's a preview for gravatars available. |
2717
|
|
|
$avatar['gravatar_preview'] = '//www.gravatar.com/avatar/' . hash('md5', strtolower($profile['email_address'])) . '?s=' . $modSettings['avatar_max_height'] . (!empty($modSettings['gravatar_rating']) ? ('&r=' . $modSettings['gravatar_rating']) : ''); |
2718
|
|
|
|
2719
|
|
|
call_integration_hook('integrate_avatar', array(&$avatar, $profile)); |
2720
|
|
|
|
2721
|
15 |
|
return $avatar; |
2722
|
15 |
|
} |
2723
|
|
|
|
2724
|
15 |
|
/** |
2725
|
15 |
|
* Get information about the server |
2726
|
|
|
*/ |
2727
|
|
|
function detectServer() |
2728
|
|
|
{ |
2729
|
|
|
global $context; |
2730
|
|
|
static $server = null; |
2731
|
|
|
|
2732
|
|
|
if ($server === null) |
2733
|
|
|
{ |
2734
|
|
|
$server = new Server($_SERVER); |
2735
|
|
|
$servers = array('iis', 'apache', 'litespeed', 'lighttpd', 'nginx', 'cgi', 'windows'); |
2736
|
|
|
$context['server'] = array(); |
2737
|
|
|
foreach ($servers as $name) |
2738
|
|
|
{ |
2739
|
15 |
|
$context['server']['is_' . $name] = $server->is($name); |
2740
|
|
|
} |
2741
|
|
|
|
2742
|
|
|
$context['server']['iso_case_folding'] = $server->is('iso_case_folding'); |
2743
|
|
|
// A bug in some versions of IIS under CGI (older ones) makes cookie setting not work with Location: headers. |
2744
|
|
|
$context['server']['needs_login_fix'] = $server->is('needs_login_fix'); |
2745
|
|
|
} |
2746
|
|
|
|
2747
|
|
|
return $server; |
2748
|
|
|
} |
2749
|
|
|
|
2750
|
|
|
/** |
2751
|
|
|
* Returns if a webserver is of type server (apache, nginx, etc) |
2752
|
|
|
* |
2753
|
|
|
* @param $server |
2754
|
|
|
* |
2755
|
|
|
* @return bool |
2756
|
|
|
*/ |
2757
|
|
|
function serverIs($server) |
2758
|
|
|
{ |
2759
|
|
|
return detectServer()->is($server); |
2760
|
|
|
} |
2761
|
|
|
|
2762
|
|
|
/** |
2763
|
|
|
* Do some important security checks: |
2764
|
|
|
* |
2765
|
|
|
* What it does: |
2766
|
|
|
* |
2767
|
|
|
* - Checks the existence of critical files e.g. install.php |
2768
|
|
|
* - Checks for an active admin session. |
2769
|
|
|
* - Checks cache directory is writable. |
2770
|
|
|
* - Calls secureDirectory to protect attachments & cache. |
2771
|
|
|
* - Checks if the forum is in maintenance mode. |
2772
|
|
|
*/ |
2773
|
|
|
function doSecurityChecks() |
2774
|
|
|
{ |
2775
|
|
|
global $modSettings, $context, $maintenance, $user_info, $txt, $scripturl, $user_settings, $options; |
2776
|
|
|
|
2777
|
|
|
$show_warnings = false; |
2778
|
|
|
|
2779
|
|
|
$cache = Cache::instance(); |
2780
|
|
|
|
2781
|
|
|
if (allowedTo('admin_forum') && !$user_info['is_guest']) |
2782
|
|
|
{ |
2783
|
|
|
// If agreement is enabled, at least the english version shall exists |
2784
|
|
|
if ($modSettings['requireAgreement'] && !file_exists(BOARDDIR . '/agreement.txt')) |
2785
|
|
|
{ |
2786
|
|
|
$context['security_controls_files']['title'] = $txt['generic_warning']; |
2787
|
|
|
$context['security_controls_files']['errors']['agreement'] = $txt['agreement_missing']; |
2788
|
|
|
$show_warnings = true; |
2789
|
|
|
} |
2790
|
|
|
|
2791
|
|
|
// Cache directory writable? |
2792
|
|
|
if ($cache->isEnabled() && !is_writable(CACHEDIR)) |
2793
|
|
|
{ |
2794
|
|
|
$context['security_controls_files']['title'] = $txt['generic_warning']; |
2795
|
|
|
$context['security_controls_files']['errors']['cache'] = $txt['cache_writable']; |
2796
|
|
|
$show_warnings = true; |
2797
|
|
|
} |
2798
|
|
|
|
2799
|
|
|
if (checkSecurityFiles()) |
2800
|
|
|
$show_warnings = true; |
2801
|
|
|
|
2802
|
|
|
// We are already checking so many files...just few more doesn't make any difference! :P |
2803
|
|
|
require_once(SUBSDIR . '/Attachments.subs.php'); |
2804
|
|
|
$path = getAttachmentPath(); |
2805
|
|
|
secureDirectory($path, true); |
2806
|
|
|
secureDirectory(CACHEDIR, false, '"\.(js|css)$"'); |
2807
|
|
|
|
2808
|
|
|
// Active admin session? |
2809
|
|
|
if (isAdminSessionActive()) |
2810
|
|
|
$context['warning_controls']['admin_session'] = sprintf($txt['admin_session_active'], ($scripturl . '?action=admin;area=adminlogoff;redir;' . $context['session_var'] . '=' . $context['session_id'])); |
2811
|
|
|
|
2812
|
|
|
// Maintenance mode enabled? |
2813
|
|
|
if (!empty($maintenance)) |
2814
|
|
|
$context['warning_controls']['maintenance'] = sprintf($txt['admin_maintenance_active'], ($scripturl . '?action=admin;area=serversettings;' . $context['session_var'] . '=' . $context['session_id'])); |
2815
|
|
|
|
2816
|
|
|
// New updates |
2817
|
|
|
if (defined('FORUM_VERSION')) |
2818
|
|
|
{ |
2819
|
|
|
$index = 'new_in_' . str_replace(array('ElkArte ', '.'), array('', '_'), FORUM_VERSION); |
2820
|
|
|
if (!empty($modSettings[$index]) && empty($options['dismissed_' . $index])) |
2821
|
|
|
{ |
2822
|
|
|
$show_warnings = true; |
2823
|
|
|
$context['new_version_updates'] = array( |
2824
|
|
|
'title' => $txt['new_version_updates'], |
2825
|
|
|
'errors' => array(replaceBasicActionUrl($txt['new_version_updates_text'])), |
2826
|
|
|
); |
2827
|
|
|
} |
2828
|
|
|
} |
2829
|
|
|
} |
2830
|
|
|
|
2831
|
|
|
// Check for database errors. |
2832
|
|
|
if (!empty($_SESSION['query_command_denied'])) |
2833
|
|
|
{ |
2834
|
|
|
if ($user_info['is_admin']) |
2835
|
|
|
{ |
2836
|
|
|
$context['security_controls_query']['title'] = $txt['query_command_denied']; |
2837
|
|
|
$show_warnings = true; |
2838
|
|
|
foreach ($_SESSION['query_command_denied'] as $command => $error) |
2839
|
|
|
$context['security_controls_query']['errors'][$command] = '<pre>' . Util::htmlspecialchars($error) . '</pre>'; |
2840
|
|
|
} |
2841
|
|
|
else |
2842
|
|
|
{ |
2843
|
|
|
$context['security_controls_query']['title'] = $txt['query_command_denied_guests']; |
2844
|
|
|
foreach ($_SESSION['query_command_denied'] as $command => $error) |
2845
|
|
|
$context['security_controls_query']['errors'][$command] = '<pre>' . sprintf($txt['query_command_denied_guests_msg'], Util::htmlspecialchars($command)) . '</pre>'; |
2846
|
|
|
} |
2847
|
|
|
} |
2848
|
|
|
|
2849
|
|
|
// Are there any members waiting for approval? |
2850
|
|
|
if (allowedTo('moderate_forum') && ((!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 2) || !empty($modSettings['approveAccountDeletion'])) && !empty($modSettings['unapprovedMembers'])) |
2851
|
|
|
$context['warning_controls']['unapproved_members'] = sprintf($txt[$modSettings['unapprovedMembers'] == 1 ? 'approve_one_member_waiting' : 'approve_many_members_waiting'], $scripturl . '?action=admin;area=viewmembers;sa=browse;type=approve', $modSettings['unapprovedMembers']); |
2852
|
|
|
|
2853
|
|
|
if (!empty($context['open_mod_reports']) && (empty($user_settings['mod_prefs']) || $user_settings['mod_prefs'][0] == 1)) |
2854
|
|
|
{ |
2855
|
|
|
$context['warning_controls']['open_mod_reports'] = '<a href="' . $scripturl . '?action=moderate;area=reports">' . sprintf($txt['mod_reports_waiting'], $context['open_mod_reports']) . '</a>'; |
2856
|
|
|
} |
2857
|
|
|
|
2858
|
|
|
if (!empty($context['open_pm_reports']) && allowedTo('admin_forum')) |
2859
|
|
|
{ |
2860
|
|
|
$context['warning_controls']['open_pm_reports'] = '<a href="' . $scripturl . '?action=moderate;area=pm_reports">' . sprintf($txt['pm_reports_waiting'], $context['open_pm_reports']) . '</a>'; |
2861
|
|
|
} |
2862
|
|
|
|
2863
|
|
|
if (isset($_SESSION['ban']['cannot_post'])) |
2864
|
|
|
{ |
2865
|
|
|
// An admin cannot be banned (technically he could), and if it is better he knows. |
2866
|
|
|
$context['security_controls_ban']['title'] = sprintf($txt['you_are_post_banned'], $user_info['is_guest'] ? $txt['guest_title'] : $user_info['name']); |
2867
|
|
|
$show_warnings = true; |
2868
|
|
|
|
2869
|
|
|
$context['security_controls_ban']['errors']['reason'] = ''; |
2870
|
|
|
|
2871
|
|
|
if (!empty($_SESSION['ban']['cannot_post']['reason'])) |
2872
|
|
|
$context['security_controls_ban']['errors']['reason'] = $_SESSION['ban']['cannot_post']['reason']; |
2873
|
|
|
|
2874
|
|
|
if (!empty($_SESSION['ban']['expire_time'])) |
2875
|
|
|
$context['security_controls_ban']['errors']['reason'] .= '<span class="smalltext">' . sprintf($txt['your_ban_expires'], standardTime($_SESSION['ban']['expire_time'], false)) . '</span>'; |
2876
|
|
|
else |
2877
|
|
|
$context['security_controls_ban']['errors']['reason'] .= '<span class="smalltext">' . $txt['your_ban_expires_never'] . '</span>'; |
2878
|
|
|
} |
2879
|
|
|
|
2880
|
|
|
// Finally, let's show the layer. |
2881
|
|
|
if ($show_warnings || !empty($context['warning_controls'])) |
2882
|
|
|
\Template_Layers::instance()->addAfter('admin_warning', 'body'); |
2883
|
|
|
} |
2884
|
|
|
|
2885
|
|
|
/** |
2886
|
|
|
* Load everything necessary for the BBC parsers |
2887
|
|
|
*/ |
2888
|
|
|
function loadBBCParsers() |
2889
|
|
|
{ |
2890
|
|
|
global $modSettings; |
2891
|
|
|
|
2892
|
|
|
// Set the default disabled BBC |
2893
|
|
|
if (!empty($modSettings['disabledBBC'])) |
2894
|
|
|
{ |
2895
|
|
|
if (!is_array($modSettings['disabledBBC'])) |
2896
|
|
|
$disabledBBC = explode(',', $modSettings['disabledBBC']); |
2897
|
|
|
else |
2898
|
|
|
$disabledBBC = $modSettings['disabledBBC']; |
2899
|
|
|
\BBC\ParserWrapper::instance()->setDisabled(empty($disabledBBC) ? array() : (array) $disabledBBC); |
2900
|
|
|
} |
2901
|
|
|
|
2902
|
|
|
return 1; |
2903
|
|
|
} |
2904
|
|
|
|
2905
|
|
|
/** |
2906
|
|
|
* This is necessary to support data stored in the pre-1.0.8 way (i.e. serialized) |
2907
|
|
|
* |
2908
|
|
|
* @param string $variable The string to convert |
2909
|
|
|
* @param null|callable $save_callback The function that will save the data to the db |
2910
|
|
|
* @return mixed[] the array |
2911
|
|
|
*/ |
2912
|
|
|
function serializeToJson($variable, $save_callback = null) |
2913
|
|
|
{ |
2914
|
|
|
$array_form = json_decode($variable, true); |
2915
|
|
|
|
2916
|
|
|
// decoding failed, let's try with unserialize |
2917
|
|
|
if (!is_array($array_form)) |
2918
|
|
|
{ |
2919
|
|
|
try |
2920
|
|
|
{ |
2921
|
|
|
$array_form = Util::unserialize($variable); |
2922
|
|
|
} |
2923
|
|
|
catch (\Exception $e) |
2924
|
|
|
{ |
2925
|
|
|
$array_form = false; |
2926
|
|
|
} |
2927
|
|
|
|
2928
|
|
|
// If unserialize fails as well, let's just store an empty array |
2929
|
|
|
if ($array_form === false) |
2930
|
|
|
{ |
2931
|
|
|
$array_form = array(0, '', 0); |
2932
|
|
|
} |
2933
|
|
|
|
2934
|
|
|
// Time to update the value if necessary |
2935
|
|
|
if ($save_callback !== null) |
2936
|
|
|
{ |
2937
|
|
|
$save_callback($array_form); |
2938
|
|
|
} |
2939
|
|
|
} |
2940
|
|
|
|
2941
|
|
|
return $array_form; |
2942
|
|
|
} |
2943
|
|
|
|
2944
|
|
|
/* |
2945
|
|
|
* Provide a PHP 8.1 version of strftime |
2946
|
|
|
* |
2947
|
|
|
* @param string $format of the date/time to return |
2948
|
|
|
* @param int|null $timestamp to convert |
2949
|
|
|
* @return string|false |
2950
|
|
|
*/ |
2951
|
|
|
function elk_strftime(string $format, int $timestamp = null) |
2952
|
|
|
{ |
2953
|
|
|
if (function_exists('strftime') && (PHP_VERSION_ID < 80100)) |
2954
|
|
|
return strftime($format, $timestamp); |
2955
|
|
|
|
2956
|
|
|
if (is_null($timestamp)) |
2957
|
|
|
$timestamp = time(); |
2958
|
|
|
|
2959
|
|
|
$date_equivalents = array ( |
2960
|
|
|
'%a' => 'D', |
2961
|
|
|
'%A' => 'l', |
2962
|
|
|
'%d' => 'd', |
2963
|
|
|
'%e' => 'j', |
2964
|
|
|
'%j' => 'z', |
2965
|
|
|
'%u' => 'N', |
2966
|
|
|
'%w' => 'w', |
2967
|
|
|
// Week |
2968
|
|
|
'%U' => '', // Week Number of the given year |
2969
|
|
|
'%V' => 'W', |
2970
|
|
|
'%W' => '', |
2971
|
|
|
// Month |
2972
|
|
|
'%b' => 'M', |
2973
|
|
|
'%B' => 'F', |
2974
|
|
|
'%h' => 'M', |
2975
|
|
|
'%m' => 'm', |
2976
|
|
|
// Year |
2977
|
|
|
'%C' => '', // Two digit representation of the century |
2978
|
|
|
'%g' => 'y', |
2979
|
|
|
'%G' => 'o', |
2980
|
|
|
'%y' => 'y', |
2981
|
|
|
'%Y' => 'Y', |
2982
|
|
|
// Time |
2983
|
|
|
'%H' => 'H', |
2984
|
|
|
'%k' => 'G', |
2985
|
|
|
'%I' => 'h', |
2986
|
|
|
'%l' => 'g', |
2987
|
|
|
'%M' => 'i', |
2988
|
|
|
'%p' => 'A', |
2989
|
|
|
'%P' => 'a', |
2990
|
|
|
'%r' => 'H:i:s a', |
2991
|
|
|
'%R' => 'H:i', |
2992
|
|
|
'%S' => 's', |
2993
|
|
|
'%T' => 'h:m:s', |
2994
|
|
|
'%X' => '', // Preferred time representation based upon locale |
2995
|
|
|
'%z' => 'O', |
2996
|
|
|
'%Z' => 'T', |
2997
|
|
|
// Time and Date Stamps |
2998
|
|
|
'%c' => 'c', |
2999
|
|
|
'%D' => 'm/d/y', |
3000
|
|
|
'%F' => 'y/m/d', |
3001
|
|
|
'%s' => 'U', |
3002
|
|
|
'%x' => '', // Locale based date representation |
3003
|
|
|
// Misc |
3004
|
|
|
'%n' => "\n", |
3005
|
|
|
'%t' => "\t", |
3006
|
|
|
'%%' => '%', |
3007
|
|
|
); |
3008
|
|
|
|
3009
|
|
|
$format = preg_replace_callback( |
3010
|
|
|
'/%[A-Za-z]{1}/', |
3011
|
|
|
function($matches) use ($timestamp, $date_equivalents) |
3012
|
|
|
{ |
3013
|
|
|
$new_format = str_replace(array_keys($date_equivalents), array_values($date_equivalents), $matches[0]); |
3014
|
|
|
return date($new_format, $timestamp); |
3015
|
|
|
}, |
3016
|
|
|
$format |
3017
|
|
|
); |
3018
|
|
|
|
3019
|
|
|
return $format; |
3020
|
|
|
} |
3021
|
|
|
|
3022
|
|
|
/* |
3023
|
|
|
* Provide a PHP 8.1 version of gmstrftime |
3024
|
|
|
* |
3025
|
|
|
* @param string $format of the date/time to return |
3026
|
|
|
* @param int|null $timestamp to convert |
3027
|
|
|
* @return string|false |
3028
|
|
|
*/ |
3029
|
|
|
function elk_gmstrftime(string $format, int $timestamp = null) |
3030
|
|
|
{ |
3031
|
|
|
if (function_exists('gmstrftime') && (PHP_VERSION_ID < 80100)) |
3032
|
|
|
return gmstrftime($format, $timestamp); |
3033
|
|
|
|
3034
|
|
|
return elk_strftime($format, $timestamp); |
3035
|
|
|
} |
3036
|
|
|
|