Chris@76
|
1 <?php
|
Chris@76
|
2
|
Chris@76
|
3 /**
|
Chris@76
|
4 * Simple Machines Forum (SMF)
|
Chris@76
|
5 *
|
Chris@76
|
6 * @package SMF
|
Chris@76
|
7 * @author Simple Machines http://www.simplemachines.org
|
Chris@76
|
8 * @copyright 2011 Simple Machines
|
Chris@76
|
9 * @license http://www.simplemachines.org/about/smf/license.php BSD
|
Chris@76
|
10 *
|
Chris@76
|
11 * @version 2.0
|
Chris@76
|
12 */
|
Chris@76
|
13
|
Chris@76
|
14 if (!defined('SMF'))
|
Chris@76
|
15 die('Hacking attempt...');
|
Chris@76
|
16
|
Chris@76
|
17 /* This file has all the main functions in it that relate to, well,
|
Chris@76
|
18 everything. It provides all of the following functions:
|
Chris@76
|
19
|
Chris@76
|
20 void updateStats(string statistic, string condition = '1')
|
Chris@76
|
21 - statistic can be 'member', 'message', 'topic', or 'postgroups'.
|
Chris@76
|
22 - parameter1 and parameter2 are optional, and are used to update only
|
Chris@76
|
23 those stats that need updating.
|
Chris@76
|
24 - the 'member' statistic updates the latest member, the total member
|
Chris@76
|
25 count, and the number of unapproved members.
|
Chris@76
|
26 - 'member' also only counts approved members when approval is on, but
|
Chris@76
|
27 is much more efficient with it off.
|
Chris@76
|
28 - updating 'message' changes the total number of messages, and the
|
Chris@76
|
29 highest message id by id_msg - which can be parameters 1 and 2,
|
Chris@76
|
30 respectively.
|
Chris@76
|
31 - 'topic' updates the total number of topics, or if parameter1 is true
|
Chris@76
|
32 simply increments them.
|
Chris@76
|
33 - the 'postgroups' case updates those members who match condition's
|
Chris@76
|
34 post-based membergroups in the database (restricted by parameter1).
|
Chris@76
|
35
|
Chris@76
|
36 void updateMemberData(int id_member, array data)
|
Chris@76
|
37 - updates the columns in the members table.
|
Chris@76
|
38 - id_member is either an int or an array of ints to be updated.
|
Chris@76
|
39 - data is an associative array of the columns to be updated and their
|
Chris@76
|
40 respective values.
|
Chris@76
|
41 - any string values updated should be quoted and slashed.
|
Chris@76
|
42 - the value of any column can be '+' or '-', which mean 'increment'
|
Chris@76
|
43 and decrement, respectively.
|
Chris@76
|
44 - if the member's post number is updated, updates their post groups.
|
Chris@76
|
45 - this function should be used whenever member data needs to be
|
Chris@76
|
46 updated in place of an UPDATE query.
|
Chris@76
|
47
|
Chris@76
|
48 void updateSettings(array changeArray, use_update = false)
|
Chris@76
|
49 - updates both the settings table and $modSettings array.
|
Chris@76
|
50 - all of changeArray's indexes and values are assumed to have escaped
|
Chris@76
|
51 apostrophes (')!
|
Chris@76
|
52 - if a variable is already set to what you want to change it to, that
|
Chris@76
|
53 variable will be skipped over; it would be unnecessary to reset.
|
Chris@76
|
54 - if use_update is true, UPDATEs will be used instead of REPLACE.
|
Chris@76
|
55 - when use_update is true, the value can be true or false to increment
|
Chris@76
|
56 or decrement it, respectively.
|
Chris@76
|
57
|
Chris@76
|
58 string constructPageIndex(string base_url, int &start, int max_value,
|
Chris@76
|
59 int num_per_page, bool compact_start = false)
|
Chris@76
|
60 - builds the page list, e.g. 1 ... 6 7 [8] 9 10 ... 15.
|
Chris@76
|
61 - compact_start caused it to use "url.page" instead of
|
Chris@76
|
62 "url;start=page".
|
Chris@76
|
63 - handles any wireless settings (adding special things to URLs.)
|
Chris@76
|
64 - very importantly, cleans up the start value passed, and forces it to
|
Chris@76
|
65 be a multiple of num_per_page.
|
Chris@76
|
66 - also checks that start is not more than max_value.
|
Chris@76
|
67 - base_url should be the URL without any start parameter on it.
|
Chris@76
|
68 - uses the compactTopicPagesEnable and compactTopicPagesContiguous
|
Chris@76
|
69 settings to decide how to display the menu.
|
Chris@76
|
70 - an example is available near the function definition.
|
Chris@76
|
71
|
Chris@76
|
72 string comma_format(float number)
|
Chris@76
|
73 - formats a number to display in the style of the admins' choosing.
|
Chris@76
|
74 - uses the format of number_format to decide how to format the number.
|
Chris@76
|
75 - for example, it might display "1 234,50".
|
Chris@76
|
76 - caches the formatting data from the setting for optimization.
|
Chris@76
|
77
|
Chris@76
|
78 string timeformat(int time, bool show_today = true, string offset_type = false)
|
Chris@76
|
79 - returns a pretty formated version of time based on the user's format
|
Chris@76
|
80 in $user_info['time_format'].
|
Chris@76
|
81 - applies all necessary time offsets to the timestamp, unless offset_type
|
Chris@76
|
82 is set.
|
Chris@76
|
83 - if todayMod is set and show_today was not not specified or true, an
|
Chris@76
|
84 alternate format string is used to show the date with something to
|
Chris@76
|
85 show it is "today" or "yesterday".
|
Chris@76
|
86 - performs localization (more than just strftime would do alone.)
|
Chris@76
|
87
|
Chris@76
|
88 string un_htmlspecialchars(string text)
|
Chris@76
|
89 - removes the base entities (<, ", etc.) from text.
|
Chris@76
|
90 - should be used instead of html_entity_decode for PHP version
|
Chris@76
|
91 compatibility reasons.
|
Chris@76
|
92 - additionally converts and '.
|
Chris@76
|
93 - returns the string without entities.
|
Chris@76
|
94
|
Chris@76
|
95 string shorten_subject(string regular_subject, int length)
|
Chris@76
|
96 - shortens a subject so that it is either shorter than length, or that
|
Chris@76
|
97 length plus an ellipsis.
|
Chris@76
|
98 - respects internationalization characters and entities as one character.
|
Chris@76
|
99 - avoids trailing entities.
|
Chris@76
|
100 - returns the shortened string.
|
Chris@76
|
101
|
Chris@76
|
102 int forum_time(bool use_user_offset = true)
|
Chris@76
|
103 - returns the current time with offsets.
|
Chris@76
|
104 - always applies the offset in the time_offset setting.
|
Chris@76
|
105 - if use_user_offset is true, applies the user's offset as well.
|
Chris@76
|
106 - returns seconds since the unix epoch.
|
Chris@76
|
107
|
Chris@76
|
108 array permute(array input)
|
Chris@76
|
109 - calculates all the possible permutations (orders) of array.
|
Chris@76
|
110 - should not be called on huge arrays (bigger than like 10 elements.)
|
Chris@76
|
111 - returns an array containing each permutation.
|
Chris@76
|
112
|
Chris@76
|
113 string parse_bbc(string message, bool smileys = true, string cache_id = '', array parse_tags = null)
|
Chris@76
|
114 - this very hefty function parses bbc in message.
|
Chris@76
|
115 - only parses bbc tags which are not disabled in disabledBBC.
|
Chris@76
|
116 - also handles basic HTML, if enablePostHTML is on.
|
Chris@76
|
117 - caches the from/to replace regular expressions so as not to reload
|
Chris@76
|
118 them every time a string is parsed.
|
Chris@76
|
119 - only parses smileys if smileys is true.
|
Chris@76
|
120 - does nothing if the enableBBC setting is off.
|
Chris@76
|
121 - applies the fixLongWords magic if the setting is set to on.
|
Chris@76
|
122 - uses the cache_id as a unique identifier to facilitate any caching
|
Chris@76
|
123 it may do.
|
Chris@76
|
124 - returns the modified message.
|
Chris@76
|
125
|
Chris@76
|
126 void parsesmileys(string &message)
|
Chris@76
|
127 - the smiley parsing function which makes pretty faces appear :).
|
Chris@76
|
128 - if custom smiley sets are turned off by smiley_enable, the default
|
Chris@76
|
129 set of smileys will be used.
|
Chris@76
|
130 - these are specifically not parsed in code tags [url=mailto:Dad@blah.com]
|
Chris@76
|
131 - caches the smileys from the database or array in memory.
|
Chris@76
|
132 - doesn't return anything, but rather modifies message directly.
|
Chris@76
|
133
|
Chris@76
|
134 string highlight_php_code(string code)
|
Chris@76
|
135 - Uses PHP's highlight_string() to highlight PHP syntax
|
Chris@76
|
136 - does special handling to keep the tabs in the code available.
|
Chris@76
|
137 - used to parse PHP code from inside [code] and [php] tags.
|
Chris@76
|
138 - returns the code with highlighted HTML.
|
Chris@76
|
139
|
Chris@76
|
140 void writeLog(bool force = false)
|
Chris@76
|
141 // !!!
|
Chris@76
|
142
|
Chris@76
|
143 void redirectexit(string setLocation = '', bool use_refresh = false)
|
Chris@76
|
144 // !!!
|
Chris@76
|
145
|
Chris@76
|
146 void obExit(bool do_header = true, bool do_footer = do_header)
|
Chris@76
|
147 // !!!
|
Chris@76
|
148
|
Chris@76
|
149 int logAction($action, $extra = array())
|
Chris@76
|
150 // !!!
|
Chris@76
|
151
|
Chris@76
|
152 void trackStats($stats = array())
|
Chris@76
|
153 - caches statistics changes, and flushes them if you pass nothing.
|
Chris@76
|
154 - if '+' is used as a value, it will be incremented.
|
Chris@76
|
155 - does not actually commit the changes until the end of the page view.
|
Chris@76
|
156 - depends on the trackStats setting.
|
Chris@76
|
157
|
Chris@76
|
158 void spamProtection(string error_type)
|
Chris@76
|
159 - attempts to protect from spammed messages and the like.
|
Chris@76
|
160 - takes a $txt index. (not an actual string.)
|
Chris@76
|
161 - time taken depends on error_type - generally uses the modSetting.
|
Chris@76
|
162
|
Chris@76
|
163 array url_image_size(string url)
|
Chris@76
|
164 - uses getimagesize() to determine the size of a file.
|
Chris@76
|
165 - attempts to connect to the server first so it won't time out.
|
Chris@76
|
166 - returns false on failure, otherwise the output of getimagesize().
|
Chris@76
|
167
|
Chris@76
|
168 void determineTopicClass(array &topic_context)
|
Chris@76
|
169 // !!!
|
Chris@76
|
170
|
Chris@76
|
171 void setupThemeContext(bool force_reload = false)
|
Chris@76
|
172 // !!!
|
Chris@76
|
173
|
Chris@76
|
174 void template_rawdata()
|
Chris@76
|
175 // !!!
|
Chris@76
|
176
|
Chris@76
|
177 void template_header()
|
Chris@76
|
178 // !!!
|
Chris@76
|
179
|
Chris@76
|
180 void theme_copyright(bool get_it = false)
|
Chris@76
|
181 // !!!
|
Chris@76
|
182
|
Chris@76
|
183 void template_footer()
|
Chris@76
|
184 // !!!
|
Chris@76
|
185
|
Chris@76
|
186 void db_debug_junk()
|
Chris@76
|
187 // !!!
|
Chris@76
|
188
|
Chris@76
|
189 void getAttachmentFilename(string filename, int id_attach, bool new = true)
|
Chris@76
|
190 // !!!
|
Chris@76
|
191
|
Chris@76
|
192 array ip2range(string $fullip)
|
Chris@76
|
193 - converts a given IP string to an array.
|
Chris@76
|
194 - internal function used to convert a user-readable format to
|
Chris@76
|
195 a format suitable for the database.
|
Chris@76
|
196 - returns 'unknown' if the ip in the input was '255.255.255.255'.
|
Chris@76
|
197
|
Chris@76
|
198 string host_from_ip(string ip_address)
|
Chris@76
|
199 // !!!
|
Chris@76
|
200
|
Chris@76
|
201 string create_button(string filename, string alt, string label, bool custom = '')
|
Chris@76
|
202 // !!!
|
Chris@76
|
203
|
Chris@76
|
204 void clean_cache(type = '')
|
Chris@76
|
205 - clean the cache directory ($cachedir, if any and in use)
|
Chris@76
|
206 - it may only remove the files of a certain type
|
Chris@76
|
207 (if the $type parameter is given)
|
Chris@76
|
208
|
Chris@76
|
209 array call_integration_hook(string hook, array parameters = array())
|
Chris@76
|
210 - calls all functions of the given hook.
|
Chris@76
|
211 - supports static class method calls.
|
Chris@76
|
212 - returns the results of the functions as an array.
|
Chris@76
|
213
|
Chris@76
|
214 void add_integration_function(string hook, string function, bool permanent = true)
|
Chris@76
|
215 - adds the given function to the given hook.
|
Chris@76
|
216 - does nothing if the functions is already added.
|
Chris@76
|
217 - if permanent parameter is true, updates the value in settings table.
|
Chris@76
|
218
|
Chris@76
|
219 void remove_integration_function(string hook, string function)
|
Chris@76
|
220 - removes the given function from the given hook.
|
Chris@76
|
221 - does nothing if the functions is not available.
|
Chris@76
|
222 */
|
Chris@76
|
223
|
Chris@76
|
224 // Update some basic statistics...
|
Chris@76
|
225 function updateStats($type, $parameter1 = null, $parameter2 = null)
|
Chris@76
|
226 {
|
Chris@76
|
227 global $sourcedir, $modSettings, $smcFunc;
|
Chris@76
|
228
|
Chris@76
|
229 switch ($type)
|
Chris@76
|
230 {
|
Chris@76
|
231 case 'member':
|
Chris@76
|
232 $changes = array(
|
Chris@76
|
233 'memberlist_updated' => time(),
|
Chris@76
|
234 );
|
Chris@76
|
235
|
Chris@76
|
236 // #1 latest member ID, #2 the real name for a new registration.
|
Chris@76
|
237 if (is_numeric($parameter1))
|
Chris@76
|
238 {
|
Chris@76
|
239 $changes['latestMember'] = $parameter1;
|
Chris@76
|
240 $changes['latestRealName'] = $parameter2;
|
Chris@76
|
241
|
Chris@76
|
242 updateSettings(array('totalMembers' => true), true);
|
Chris@76
|
243 }
|
Chris@76
|
244
|
Chris@76
|
245 // We need to calculate the totals.
|
Chris@76
|
246 else
|
Chris@76
|
247 {
|
Chris@76
|
248 // Update the latest activated member (highest id_member) and count.
|
Chris@76
|
249 $result = $smcFunc['db_query']('', '
|
Chris@76
|
250 SELECT COUNT(*), MAX(id_member)
|
Chris@76
|
251 FROM {db_prefix}members
|
Chris@76
|
252 WHERE is_activated = {int:is_activated}',
|
Chris@76
|
253 array(
|
Chris@76
|
254 'is_activated' => 1,
|
Chris@76
|
255 )
|
Chris@76
|
256 );
|
Chris@76
|
257 list ($changes['totalMembers'], $changes['latestMember']) = $smcFunc['db_fetch_row']($result);
|
Chris@76
|
258 $smcFunc['db_free_result']($result);
|
Chris@76
|
259
|
Chris@76
|
260 // Get the latest activated member's display name.
|
Chris@76
|
261 $result = $smcFunc['db_query']('', '
|
Chris@76
|
262 SELECT real_name
|
Chris@76
|
263 FROM {db_prefix}members
|
Chris@76
|
264 WHERE id_member = {int:id_member}
|
Chris@76
|
265 LIMIT 1',
|
Chris@76
|
266 array(
|
Chris@76
|
267 'id_member' => (int) $changes['latestMember'],
|
Chris@76
|
268 )
|
Chris@76
|
269 );
|
Chris@76
|
270 list ($changes['latestRealName']) = $smcFunc['db_fetch_row']($result);
|
Chris@76
|
271 $smcFunc['db_free_result']($result);
|
Chris@76
|
272
|
Chris@76
|
273 // Are we using registration approval?
|
Chris@76
|
274 if ((!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 2) || !empty($modSettings['approveAccountDeletion']))
|
Chris@76
|
275 {
|
Chris@76
|
276 // Update the amount of members awaiting approval - ignoring COPPA accounts, as you can't approve them until you get permission.
|
Chris@76
|
277 $result = $smcFunc['db_query']('', '
|
Chris@76
|
278 SELECT COUNT(*)
|
Chris@76
|
279 FROM {db_prefix}members
|
Chris@76
|
280 WHERE is_activated IN ({array_int:activation_status})',
|
Chris@76
|
281 array(
|
Chris@76
|
282 'activation_status' => array(3, 4),
|
Chris@76
|
283 )
|
Chris@76
|
284 );
|
Chris@76
|
285 list ($changes['unapprovedMembers']) = $smcFunc['db_fetch_row']($result);
|
Chris@76
|
286 $smcFunc['db_free_result']($result);
|
Chris@76
|
287 }
|
Chris@76
|
288 }
|
Chris@76
|
289
|
Chris@76
|
290 updateSettings($changes);
|
Chris@76
|
291 break;
|
Chris@76
|
292
|
Chris@76
|
293 case 'message':
|
Chris@76
|
294 if ($parameter1 === true && $parameter2 !== null)
|
Chris@76
|
295 updateSettings(array('totalMessages' => true, 'maxMsgID' => $parameter2), true);
|
Chris@76
|
296 else
|
Chris@76
|
297 {
|
Chris@76
|
298 // SUM and MAX on a smaller table is better for InnoDB tables.
|
Chris@76
|
299 $result = $smcFunc['db_query']('', '
|
Chris@76
|
300 SELECT SUM(num_posts + unapproved_posts) AS total_messages, MAX(id_last_msg) AS max_msg_id
|
Chris@76
|
301 FROM {db_prefix}boards
|
Chris@76
|
302 WHERE redirect = {string:blank_redirect}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
|
Chris@76
|
303 AND id_board != {int:recycle_board}' : ''),
|
Chris@76
|
304 array(
|
Chris@76
|
305 'recycle_board' => isset($modSettings['recycle_board']) ? $modSettings['recycle_board'] : 0,
|
Chris@76
|
306 'blank_redirect' => '',
|
Chris@76
|
307 )
|
Chris@76
|
308 );
|
Chris@76
|
309 $row = $smcFunc['db_fetch_assoc']($result);
|
Chris@76
|
310 $smcFunc['db_free_result']($result);
|
Chris@76
|
311
|
Chris@76
|
312 updateSettings(array(
|
Chris@76
|
313 'totalMessages' => $row['total_messages'] === null ? 0 : $row['total_messages'],
|
Chris@76
|
314 'maxMsgID' => $row['max_msg_id'] === null ? 0 : $row['max_msg_id']
|
Chris@76
|
315 ));
|
Chris@76
|
316 }
|
Chris@76
|
317 break;
|
Chris@76
|
318
|
Chris@76
|
319 case 'subject':
|
Chris@76
|
320 // Remove the previous subject (if any).
|
Chris@76
|
321 $smcFunc['db_query']('', '
|
Chris@76
|
322 DELETE FROM {db_prefix}log_search_subjects
|
Chris@76
|
323 WHERE id_topic = {int:id_topic}',
|
Chris@76
|
324 array(
|
Chris@76
|
325 'id_topic' => (int) $parameter1,
|
Chris@76
|
326 )
|
Chris@76
|
327 );
|
Chris@76
|
328
|
Chris@76
|
329 // Insert the new subject.
|
Chris@76
|
330 if ($parameter2 !== null)
|
Chris@76
|
331 {
|
Chris@76
|
332 $parameter1 = (int) $parameter1;
|
Chris@76
|
333 $parameter2 = text2words($parameter2);
|
Chris@76
|
334
|
Chris@76
|
335 $inserts = array();
|
Chris@76
|
336 foreach ($parameter2 as $word)
|
Chris@76
|
337 $inserts[] = array($word, $parameter1);
|
Chris@76
|
338
|
Chris@76
|
339 if (!empty($inserts))
|
Chris@76
|
340 $smcFunc['db_insert']('ignore',
|
Chris@76
|
341 '{db_prefix}log_search_subjects',
|
Chris@76
|
342 array('word' => 'string', 'id_topic' => 'int'),
|
Chris@76
|
343 $inserts,
|
Chris@76
|
344 array('word', 'id_topic')
|
Chris@76
|
345 );
|
Chris@76
|
346 }
|
Chris@76
|
347 break;
|
Chris@76
|
348
|
Chris@76
|
349 case 'topic':
|
Chris@76
|
350 if ($parameter1 === true)
|
Chris@76
|
351 updateSettings(array('totalTopics' => true), true);
|
Chris@76
|
352 else
|
Chris@76
|
353 {
|
Chris@76
|
354 // Get the number of topics - a SUM is better for InnoDB tables.
|
Chris@76
|
355 // We also ignore the recycle bin here because there will probably be a bunch of one-post topics there.
|
Chris@76
|
356 $result = $smcFunc['db_query']('', '
|
Chris@76
|
357 SELECT SUM(num_topics + unapproved_topics) AS total_topics
|
Chris@76
|
358 FROM {db_prefix}boards' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
|
Chris@76
|
359 WHERE id_board != {int:recycle_board}' : ''),
|
Chris@76
|
360 array(
|
Chris@76
|
361 'recycle_board' => !empty($modSettings['recycle_board']) ? $modSettings['recycle_board'] : 0,
|
Chris@76
|
362 )
|
Chris@76
|
363 );
|
Chris@76
|
364 $row = $smcFunc['db_fetch_assoc']($result);
|
Chris@76
|
365 $smcFunc['db_free_result']($result);
|
Chris@76
|
366
|
Chris@76
|
367 updateSettings(array('totalTopics' => $row['total_topics'] === null ? 0 : $row['total_topics']));
|
Chris@76
|
368 }
|
Chris@76
|
369 break;
|
Chris@76
|
370
|
Chris@76
|
371 case 'postgroups':
|
Chris@76
|
372 // Parameter two is the updated columns: we should check to see if we base groups off any of these.
|
Chris@76
|
373 if ($parameter2 !== null && !in_array('posts', $parameter2))
|
Chris@76
|
374 return;
|
Chris@76
|
375
|
Chris@76
|
376 if (($postgroups = cache_get_data('updateStats:postgroups', 360)) == null)
|
Chris@76
|
377 {
|
Chris@76
|
378 // Fetch the postgroups!
|
Chris@76
|
379 $request = $smcFunc['db_query']('', '
|
Chris@76
|
380 SELECT id_group, min_posts
|
Chris@76
|
381 FROM {db_prefix}membergroups
|
Chris@76
|
382 WHERE min_posts != {int:min_posts}',
|
Chris@76
|
383 array(
|
Chris@76
|
384 'min_posts' => -1,
|
Chris@76
|
385 )
|
Chris@76
|
386 );
|
Chris@76
|
387 $postgroups = array();
|
Chris@76
|
388 while ($row = $smcFunc['db_fetch_assoc']($request))
|
Chris@76
|
389 $postgroups[$row['id_group']] = $row['min_posts'];
|
Chris@76
|
390 $smcFunc['db_free_result']($request);
|
Chris@76
|
391
|
Chris@76
|
392 // Sort them this way because if it's done with MySQL it causes a filesort :(.
|
Chris@76
|
393 arsort($postgroups);
|
Chris@76
|
394
|
Chris@76
|
395 cache_put_data('updateStats:postgroups', $postgroups, 360);
|
Chris@76
|
396 }
|
Chris@76
|
397
|
Chris@76
|
398 // Oh great, they've screwed their post groups.
|
Chris@76
|
399 if (empty($postgroups))
|
Chris@76
|
400 return;
|
Chris@76
|
401
|
Chris@76
|
402 // Set all membergroups from most posts to least posts.
|
Chris@76
|
403 $conditions = '';
|
Chris@76
|
404 foreach ($postgroups as $id => $min_posts)
|
Chris@76
|
405 {
|
Chris@76
|
406 $conditions .= '
|
Chris@76
|
407 WHEN posts >= ' . $min_posts . (!empty($lastMin) ? ' AND posts <= ' . $lastMin : '') . ' THEN ' . $id;
|
Chris@76
|
408 $lastMin = $min_posts;
|
Chris@76
|
409 }
|
Chris@76
|
410
|
Chris@76
|
411 // A big fat CASE WHEN... END is faster than a zillion UPDATE's ;).
|
Chris@76
|
412 $smcFunc['db_query']('', '
|
Chris@76
|
413 UPDATE {db_prefix}members
|
Chris@76
|
414 SET id_post_group = CASE ' . $conditions . '
|
Chris@76
|
415 ELSE 0
|
Chris@76
|
416 END' . ($parameter1 != null ? '
|
Chris@76
|
417 WHERE ' . (is_array($parameter1) ? 'id_member IN ({array_int:members})' : 'id_member = {int:members}') : ''),
|
Chris@76
|
418 array(
|
Chris@76
|
419 'members' => $parameter1,
|
Chris@76
|
420 )
|
Chris@76
|
421 );
|
Chris@76
|
422 break;
|
Chris@76
|
423
|
Chris@76
|
424 default:
|
Chris@76
|
425 trigger_error('updateStats(): Invalid statistic type \'' . $type . '\'', E_USER_NOTICE);
|
Chris@76
|
426 }
|
Chris@76
|
427 }
|
Chris@76
|
428
|
Chris@76
|
429 // Assumes the data has been htmlspecialchar'd.
|
Chris@76
|
430 function updateMemberData($members, $data)
|
Chris@76
|
431 {
|
Chris@76
|
432 global $modSettings, $user_info, $smcFunc;
|
Chris@76
|
433
|
Chris@76
|
434 $parameters = array();
|
Chris@76
|
435 if (is_array($members))
|
Chris@76
|
436 {
|
Chris@76
|
437 $condition = 'id_member IN ({array_int:members})';
|
Chris@76
|
438 $parameters['members'] = $members;
|
Chris@76
|
439 }
|
Chris@76
|
440 elseif ($members === null)
|
Chris@76
|
441 $condition = '1=1';
|
Chris@76
|
442 else
|
Chris@76
|
443 {
|
Chris@76
|
444 $condition = 'id_member = {int:member}';
|
Chris@76
|
445 $parameters['member'] = $members;
|
Chris@76
|
446 }
|
Chris@76
|
447
|
Chris@76
|
448 if (!empty($modSettings['integrate_change_member_data']))
|
Chris@76
|
449 {
|
Chris@76
|
450 // Only a few member variables are really interesting for integration.
|
Chris@76
|
451 $integration_vars = array(
|
Chris@76
|
452 'member_name',
|
Chris@76
|
453 'real_name',
|
Chris@76
|
454 'email_address',
|
Chris@76
|
455 'id_group',
|
Chris@76
|
456 'gender',
|
Chris@76
|
457 'birthdate',
|
Chris@76
|
458 'website_title',
|
Chris@76
|
459 'website_url',
|
Chris@76
|
460 'location',
|
Chris@76
|
461 'hide_email',
|
Chris@76
|
462 'time_format',
|
Chris@76
|
463 'time_offset',
|
Chris@76
|
464 'avatar',
|
Chris@76
|
465 'lngfile',
|
Chris@76
|
466 );
|
Chris@76
|
467 $vars_to_integrate = array_intersect($integration_vars, array_keys($data));
|
Chris@76
|
468
|
Chris@76
|
469 // Only proceed if there are any variables left to call the integration function.
|
Chris@76
|
470 if (count($vars_to_integrate) != 0)
|
Chris@76
|
471 {
|
Chris@76
|
472 // Fetch a list of member_names if necessary
|
Chris@76
|
473 if ((!is_array($members) && $members === $user_info['id']) || (is_array($members) && count($members) == 1 && in_array($user_info['id'], $members)))
|
Chris@76
|
474 $member_names = array($user_info['username']);
|
Chris@76
|
475 else
|
Chris@76
|
476 {
|
Chris@76
|
477 $member_names = array();
|
Chris@76
|
478 $request = $smcFunc['db_query']('', '
|
Chris@76
|
479 SELECT member_name
|
Chris@76
|
480 FROM {db_prefix}members
|
Chris@76
|
481 WHERE ' . $condition,
|
Chris@76
|
482 $parameters
|
Chris@76
|
483 );
|
Chris@76
|
484 while ($row = $smcFunc['db_fetch_assoc']($request))
|
Chris@76
|
485 $member_names[] = $row['member_name'];
|
Chris@76
|
486 $smcFunc['db_free_result']($request);
|
Chris@76
|
487 }
|
Chris@76
|
488
|
Chris@76
|
489 if (!empty($member_names))
|
Chris@76
|
490 foreach ($vars_to_integrate as $var)
|
Chris@76
|
491 call_integration_hook('integrate_change_member_data', array($member_names, $var, $data[$var]));
|
Chris@76
|
492 }
|
Chris@76
|
493 }
|
Chris@76
|
494
|
Chris@76
|
495 // Everything is assumed to be a string unless it's in the below.
|
Chris@76
|
496 $knownInts = array(
|
Chris@76
|
497 'date_registered', 'posts', 'id_group', 'last_login', 'instant_messages', 'unread_messages',
|
Chris@76
|
498 'new_pm', 'pm_prefs', 'gender', 'hide_email', 'show_online', 'pm_email_notify', 'pm_receive_from', 'karma_good', 'karma_bad',
|
Chris@76
|
499 'notify_announcements', 'notify_send_body', 'notify_regularity', 'notify_types',
|
Chris@76
|
500 'id_theme', 'is_activated', 'id_msg_last_visit', 'id_post_group', 'total_time_logged_in', 'warning',
|
Chris@76
|
501 );
|
Chris@76
|
502 $knownFloats = array(
|
Chris@76
|
503 'time_offset',
|
Chris@76
|
504 );
|
Chris@76
|
505
|
Chris@76
|
506 $setString = '';
|
Chris@76
|
507 foreach ($data as $var => $val)
|
Chris@76
|
508 {
|
Chris@76
|
509 $type = 'string';
|
Chris@76
|
510 if (in_array($var, $knownInts))
|
Chris@76
|
511 $type = 'int';
|
Chris@76
|
512 elseif (in_array($var, $knownFloats))
|
Chris@76
|
513 $type = 'float';
|
Chris@76
|
514 elseif ($var == 'birthdate')
|
Chris@76
|
515 $type = 'date';
|
Chris@76
|
516
|
Chris@76
|
517 // Doing an increment?
|
Chris@76
|
518 if ($type == 'int' && ($val === '+' || $val === '-'))
|
Chris@76
|
519 {
|
Chris@76
|
520 $val = $var . ' ' . $val . ' 1';
|
Chris@76
|
521 $type = 'raw';
|
Chris@76
|
522 }
|
Chris@76
|
523
|
Chris@76
|
524 // Ensure posts, instant_messages, and unread_messages don't overflow or underflow.
|
Chris@76
|
525 if (in_array($var, array('posts', 'instant_messages', 'unread_messages')))
|
Chris@76
|
526 {
|
Chris@76
|
527 if (preg_match('~^' . $var . ' (\+ |- |\+ -)([\d]+)~', $val, $match))
|
Chris@76
|
528 {
|
Chris@76
|
529 if ($match[1] != '+ ')
|
Chris@76
|
530 $val = 'CASE WHEN ' . $var . ' <= ' . abs($match[2]) . ' THEN 0 ELSE ' . $val . ' END';
|
Chris@76
|
531 $type = 'raw';
|
Chris@76
|
532 }
|
Chris@76
|
533 }
|
Chris@76
|
534
|
Chris@76
|
535 $setString .= ' ' . $var . ' = {' . $type . ':p_' . $var . '},';
|
Chris@76
|
536 $parameters['p_' . $var] = $val;
|
Chris@76
|
537 }
|
Chris@76
|
538
|
Chris@76
|
539 $smcFunc['db_query']('', '
|
Chris@76
|
540 UPDATE {db_prefix}members
|
Chris@76
|
541 SET' . substr($setString, 0, -1) . '
|
Chris@76
|
542 WHERE ' . $condition,
|
Chris@76
|
543 $parameters
|
Chris@76
|
544 );
|
Chris@76
|
545
|
Chris@76
|
546 updateStats('postgroups', $members, array_keys($data));
|
Chris@76
|
547
|
Chris@76
|
548 // Clear any caching?
|
Chris@76
|
549 if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2 && !empty($members))
|
Chris@76
|
550 {
|
Chris@76
|
551 if (!is_array($members))
|
Chris@76
|
552 $members = array($members);
|
Chris@76
|
553
|
Chris@76
|
554 foreach ($members as $member)
|
Chris@76
|
555 {
|
Chris@76
|
556 if ($modSettings['cache_enable'] >= 3)
|
Chris@76
|
557 {
|
Chris@76
|
558 cache_put_data('member_data-profile-' . $member, null, 120);
|
Chris@76
|
559 cache_put_data('member_data-normal-' . $member, null, 120);
|
Chris@76
|
560 cache_put_data('member_data-minimal-' . $member, null, 120);
|
Chris@76
|
561 }
|
Chris@76
|
562 cache_put_data('user_settings-' . $member, null, 60);
|
Chris@76
|
563 }
|
Chris@76
|
564 }
|
Chris@76
|
565 }
|
Chris@76
|
566
|
Chris@76
|
567 // Updates the settings table as well as $modSettings... only does one at a time if $update is true.
|
Chris@76
|
568 function updateSettings($changeArray, $update = false, $debug = false)
|
Chris@76
|
569 {
|
Chris@76
|
570 global $modSettings, $smcFunc;
|
Chris@76
|
571
|
Chris@76
|
572 if (empty($changeArray) || !is_array($changeArray))
|
Chris@76
|
573 return;
|
Chris@76
|
574
|
Chris@76
|
575 // In some cases, this may be better and faster, but for large sets we don't want so many UPDATEs.
|
Chris@76
|
576 if ($update)
|
Chris@76
|
577 {
|
Chris@76
|
578 foreach ($changeArray as $variable => $value)
|
Chris@76
|
579 {
|
Chris@76
|
580 $smcFunc['db_query']('', '
|
Chris@76
|
581 UPDATE {db_prefix}settings
|
Chris@76
|
582 SET value = {' . ($value === false || $value === true ? 'raw' : 'string') . ':value}
|
Chris@76
|
583 WHERE variable = {string:variable}',
|
Chris@76
|
584 array(
|
Chris@76
|
585 'value' => $value === true ? 'value + 1' : ($value === false ? 'value - 1' : $value),
|
Chris@76
|
586 'variable' => $variable,
|
Chris@76
|
587 )
|
Chris@76
|
588 );
|
Chris@76
|
589 $modSettings[$variable] = $value === true ? $modSettings[$variable] + 1 : ($value === false ? $modSettings[$variable] - 1 : $value);
|
Chris@76
|
590 }
|
Chris@76
|
591
|
Chris@76
|
592 // Clean out the cache and make sure the cobwebs are gone too.
|
Chris@76
|
593 cache_put_data('modSettings', null, 90);
|
Chris@76
|
594
|
Chris@76
|
595 return;
|
Chris@76
|
596 }
|
Chris@76
|
597
|
Chris@76
|
598 $replaceArray = array();
|
Chris@76
|
599 foreach ($changeArray as $variable => $value)
|
Chris@76
|
600 {
|
Chris@76
|
601 // Don't bother if it's already like that ;).
|
Chris@76
|
602 if (isset($modSettings[$variable]) && $modSettings[$variable] == $value)
|
Chris@76
|
603 continue;
|
Chris@76
|
604 // If the variable isn't set, but would only be set to nothing'ness, then don't bother setting it.
|
Chris@76
|
605 elseif (!isset($modSettings[$variable]) && empty($value))
|
Chris@76
|
606 continue;
|
Chris@76
|
607
|
Chris@76
|
608 $replaceArray[] = array($variable, $value);
|
Chris@76
|
609
|
Chris@76
|
610 $modSettings[$variable] = $value;
|
Chris@76
|
611 }
|
Chris@76
|
612
|
Chris@76
|
613 if (empty($replaceArray))
|
Chris@76
|
614 return;
|
Chris@76
|
615
|
Chris@76
|
616 $smcFunc['db_insert']('replace',
|
Chris@76
|
617 '{db_prefix}settings',
|
Chris@76
|
618 array('variable' => 'string-255', 'value' => 'string-65534'),
|
Chris@76
|
619 $replaceArray,
|
Chris@76
|
620 array('variable')
|
Chris@76
|
621 );
|
Chris@76
|
622
|
Chris@76
|
623 // Kill the cache - it needs redoing now, but we won't bother ourselves with that here.
|
Chris@76
|
624 cache_put_data('modSettings', null, 90);
|
Chris@76
|
625 }
|
Chris@76
|
626
|
Chris@76
|
627 // Constructs a page list.
|
Chris@76
|
628 // $pageindex = constructPageIndex($scripturl . '?board=' . $board, $_REQUEST['start'], $num_messages, $maxindex, true);
|
Chris@76
|
629 function constructPageIndex($base_url, &$start, $max_value, $num_per_page, $flexible_start = false)
|
Chris@76
|
630 {
|
Chris@76
|
631 global $modSettings;
|
Chris@76
|
632
|
Chris@76
|
633 // Save whether $start was less than 0 or not.
|
Chris@76
|
634 $start = (int) $start;
|
Chris@76
|
635 $start_invalid = $start < 0;
|
Chris@76
|
636
|
Chris@76
|
637 // Make sure $start is a proper variable - not less than 0.
|
Chris@76
|
638 if ($start_invalid)
|
Chris@76
|
639 $start = 0;
|
Chris@76
|
640 // Not greater than the upper bound.
|
Chris@76
|
641 elseif ($start >= $max_value)
|
Chris@76
|
642 $start = max(0, (int) $max_value - (((int) $max_value % (int) $num_per_page) == 0 ? $num_per_page : ((int) $max_value % (int) $num_per_page)));
|
Chris@76
|
643 // And it has to be a multiple of $num_per_page!
|
Chris@76
|
644 else
|
Chris@76
|
645 $start = max(0, (int) $start - ((int) $start % (int) $num_per_page));
|
Chris@76
|
646
|
Chris@76
|
647 // Wireless will need the protocol on the URL somewhere.
|
Chris@76
|
648 if (WIRELESS)
|
Chris@76
|
649 $base_url .= ';' . WIRELESS_PROTOCOL;
|
Chris@76
|
650
|
Chris@76
|
651 $base_link = '<a class="navPages" href="' . ($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%1$d') . '">%2$s</a> ';
|
Chris@76
|
652
|
Chris@76
|
653 // Compact pages is off or on?
|
Chris@76
|
654 if (empty($modSettings['compactTopicPagesEnable']))
|
Chris@76
|
655 {
|
Chris@76
|
656 // Show the left arrow.
|
Chris@76
|
657 $pageindex = $start == 0 ? ' ' : sprintf($base_link, $start - $num_per_page, '«');
|
Chris@76
|
658
|
Chris@76
|
659 // Show all the pages.
|
Chris@76
|
660 $display_page = 1;
|
Chris@76
|
661 for ($counter = 0; $counter < $max_value; $counter += $num_per_page)
|
Chris@76
|
662 $pageindex .= $start == $counter && !$start_invalid ? '<strong>' . $display_page++ . '</strong> ' : sprintf($base_link, $counter, $display_page++);
|
Chris@76
|
663
|
Chris@76
|
664 // Show the right arrow.
|
Chris@76
|
665 $display_page = ($start + $num_per_page) > $max_value ? $max_value : ($start + $num_per_page);
|
Chris@76
|
666 if ($start != $counter - $max_value && !$start_invalid)
|
Chris@76
|
667 $pageindex .= $display_page > $counter - $num_per_page ? ' ' : sprintf($base_link, $display_page, '»');
|
Chris@76
|
668 }
|
Chris@76
|
669 else
|
Chris@76
|
670 {
|
Chris@76
|
671 // If they didn't enter an odd value, pretend they did.
|
Chris@76
|
672 $PageContiguous = (int) ($modSettings['compactTopicPagesContiguous'] - ($modSettings['compactTopicPagesContiguous'] % 2)) / 2;
|
Chris@76
|
673
|
Chris@76
|
674 // Show the first page. (>1< ... 6 7 [8] 9 10 ... 15)
|
Chris@76
|
675 if ($start > $num_per_page * $PageContiguous)
|
Chris@76
|
676 $pageindex = sprintf($base_link, 0, '1');
|
Chris@76
|
677 else
|
Chris@76
|
678 $pageindex = '';
|
Chris@76
|
679
|
Chris@76
|
680 // Show the ... after the first page. (1 >...< 6 7 [8] 9 10 ... 15)
|
Chris@76
|
681 if ($start > $num_per_page * ($PageContiguous + 1))
|
Chris@76
|
682 $pageindex .= '<span style="font-weight: bold;" onclick="' . htmlspecialchars('expandPages(this, ' . JavaScriptEscape(($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%1$d')) . ', ' . $num_per_page . ', ' . ($start - $num_per_page * $PageContiguous) . ', ' . $num_per_page . ');') . '" onmouseover="this.style.cursor = \'pointer\';"> ... </span>';
|
Chris@76
|
683
|
Chris@76
|
684 // Show the pages before the current one. (1 ... >6 7< [8] 9 10 ... 15)
|
Chris@76
|
685 for ($nCont = $PageContiguous; $nCont >= 1; $nCont--)
|
Chris@76
|
686 if ($start >= $num_per_page * $nCont)
|
Chris@76
|
687 {
|
Chris@76
|
688 $tmpStart = $start - $num_per_page * $nCont;
|
Chris@76
|
689 $pageindex.= sprintf($base_link, $tmpStart, $tmpStart / $num_per_page + 1);
|
Chris@76
|
690 }
|
Chris@76
|
691
|
Chris@76
|
692 // Show the current page. (1 ... 6 7 >[8]< 9 10 ... 15)
|
Chris@76
|
693 if (!$start_invalid)
|
Chris@76
|
694 $pageindex .= '[<strong>' . ($start / $num_per_page + 1) . '</strong>] ';
|
Chris@76
|
695 else
|
Chris@76
|
696 $pageindex .= sprintf($base_link, $start, $start / $num_per_page + 1);
|
Chris@76
|
697
|
Chris@76
|
698 // Show the pages after the current one... (1 ... 6 7 [8] >9 10< ... 15)
|
Chris@76
|
699 $tmpMaxPages = (int) (($max_value - 1) / $num_per_page) * $num_per_page;
|
Chris@76
|
700 for ($nCont = 1; $nCont <= $PageContiguous; $nCont++)
|
Chris@76
|
701 if ($start + $num_per_page * $nCont <= $tmpMaxPages)
|
Chris@76
|
702 {
|
Chris@76
|
703 $tmpStart = $start + $num_per_page * $nCont;
|
Chris@76
|
704 $pageindex .= sprintf($base_link, $tmpStart, $tmpStart / $num_per_page + 1);
|
Chris@76
|
705 }
|
Chris@76
|
706
|
Chris@76
|
707 // Show the '...' part near the end. (1 ... 6 7 [8] 9 10 >...< 15)
|
Chris@76
|
708 if ($start + $num_per_page * ($PageContiguous + 1) < $tmpMaxPages)
|
Chris@76
|
709 $pageindex .= '<span style="font-weight: bold;" onclick="expandPages(this, \'' . ($flexible_start ? strtr($base_url, array('\'' => '\\\'')) : strtr($base_url, array('%' => '%%', '\'' => '\\\'')) . ';start=%1$d') . '\', ' . ($start + $num_per_page * ($PageContiguous + 1)) . ', ' . $tmpMaxPages . ', ' . $num_per_page . ');" onmouseover="this.style.cursor=\'pointer\';"> ... </span>';
|
Chris@76
|
710
|
Chris@76
|
711 // Show the last number in the list. (1 ... 6 7 [8] 9 10 ... >15<)
|
Chris@76
|
712 if ($start + $num_per_page * $PageContiguous < $tmpMaxPages)
|
Chris@76
|
713 $pageindex .= sprintf($base_link, $tmpMaxPages, $tmpMaxPages / $num_per_page + 1);
|
Chris@76
|
714 }
|
Chris@76
|
715
|
Chris@76
|
716 return $pageindex;
|
Chris@76
|
717 }
|
Chris@76
|
718
|
Chris@76
|
719 // Formats a number to display in the style of the admin's choosing.
|
Chris@76
|
720 function comma_format($number, $override_decimal_count = false)
|
Chris@76
|
721 {
|
Chris@76
|
722 global $txt;
|
Chris@76
|
723 static $thousands_separator = null, $decimal_separator = null, $decimal_count = null;
|
Chris@76
|
724
|
Chris@76
|
725 // !!! Should, perhaps, this just be handled in the language files, and not a mod setting?
|
Chris@76
|
726 // (French uses 1 234,00 for example... what about a multilingual forum?)
|
Chris@76
|
727
|
Chris@76
|
728 // Cache these values...
|
Chris@76
|
729 if ($decimal_separator === null)
|
Chris@76
|
730 {
|
Chris@76
|
731 // Not set for whatever reason?
|
Chris@76
|
732 if (empty($txt['number_format']) || preg_match('~^1([^\d]*)?234([^\d]*)(0*?)$~', $txt['number_format'], $matches) != 1)
|
Chris@76
|
733 return $number;
|
Chris@76
|
734
|
Chris@76
|
735 // Cache these each load...
|
Chris@76
|
736 $thousands_separator = $matches[1];
|
Chris@76
|
737 $decimal_separator = $matches[2];
|
Chris@76
|
738 $decimal_count = strlen($matches[3]);
|
Chris@76
|
739 }
|
Chris@76
|
740
|
Chris@76
|
741 // Format the string with our friend, number_format.
|
Chris@76
|
742 return number_format($number, is_float($number) ? ($override_decimal_count === false ? $decimal_count : $override_decimal_count) : 0, $decimal_separator, $thousands_separator);
|
Chris@76
|
743 }
|
Chris@76
|
744
|
Chris@76
|
745 // Format a time to make it look purdy.
|
Chris@76
|
746 function timeformat($log_time, $show_today = true, $offset_type = false)
|
Chris@76
|
747 {
|
Chris@76
|
748 global $context, $user_info, $txt, $modSettings, $smcFunc;
|
Chris@76
|
749 static $non_twelve_hour;
|
Chris@76
|
750
|
Chris@76
|
751 // Offset the time.
|
Chris@76
|
752 if (!$offset_type)
|
Chris@76
|
753 $time = $log_time + ($user_info['time_offset'] + $modSettings['time_offset']) * 3600;
|
Chris@76
|
754 // Just the forum offset?
|
Chris@76
|
755 elseif ($offset_type == 'forum')
|
Chris@76
|
756 $time = $log_time + $modSettings['time_offset'] * 3600;
|
Chris@76
|
757 else
|
Chris@76
|
758 $time = $log_time;
|
Chris@76
|
759
|
Chris@76
|
760 // We can't have a negative date (on Windows, at least.)
|
Chris@76
|
761 if ($log_time < 0)
|
Chris@76
|
762 $log_time = 0;
|
Chris@76
|
763
|
Chris@76
|
764 // Today and Yesterday?
|
Chris@76
|
765 if ($modSettings['todayMod'] >= 1 && $show_today === true)
|
Chris@76
|
766 {
|
Chris@76
|
767 // Get the current time.
|
Chris@76
|
768 $nowtime = forum_time();
|
Chris@76
|
769
|
Chris@76
|
770 $then = @getdate($time);
|
Chris@76
|
771 $now = @getdate($nowtime);
|
Chris@76
|
772
|
Chris@76
|
773 // Try to make something of a time format string...
|
Chris@76
|
774 $s = strpos($user_info['time_format'], '%S') === false ? '' : ':%S';
|
Chris@76
|
775 if (strpos($user_info['time_format'], '%H') === false && strpos($user_info['time_format'], '%T') === false)
|
Chris@76
|
776 {
|
Chris@76
|
777 $h = strpos($user_info['time_format'], '%l') === false ? '%I' : '%l';
|
Chris@76
|
778 $today_fmt = $h . ':%M' . $s . ' %p';
|
Chris@76
|
779 }
|
Chris@76
|
780 else
|
Chris@76
|
781 $today_fmt = '%H:%M' . $s;
|
Chris@76
|
782
|
Chris@76
|
783 // Same day of the year, same year.... Today!
|
Chris@76
|
784 if ($then['yday'] == $now['yday'] && $then['year'] == $now['year'])
|
Chris@76
|
785 return $txt['today'] . timeformat($log_time, $today_fmt, $offset_type);
|
Chris@76
|
786
|
Chris@76
|
787 // Day-of-year is one less and same year, or it's the first of the year and that's the last of the year...
|
Chris@76
|
788 if ($modSettings['todayMod'] == '2' && (($then['yday'] == $now['yday'] - 1 && $then['year'] == $now['year']) || ($now['yday'] == 0 && $then['year'] == $now['year'] - 1) && $then['mon'] == 12 && $then['mday'] == 31))
|
Chris@76
|
789 return $txt['yesterday'] . timeformat($log_time, $today_fmt, $offset_type);
|
Chris@76
|
790 }
|
Chris@76
|
791
|
Chris@76
|
792 $str = !is_bool($show_today) ? $show_today : $user_info['time_format'];
|
Chris@76
|
793
|
Chris@76
|
794 if (setlocale(LC_TIME, $txt['lang_locale']))
|
Chris@76
|
795 {
|
Chris@76
|
796 if (!isset($non_twelve_hour))
|
Chris@76
|
797 $non_twelve_hour = trim(strftime('%p')) === '';
|
Chris@76
|
798 if ($non_twelve_hour && strpos($str, '%p') !== false)
|
Chris@76
|
799 $str = str_replace('%p', (strftime('%H', $time) < 12 ? $txt['time_am'] : $txt['time_pm']), $str);
|
Chris@76
|
800
|
Chris@76
|
801 foreach (array('%a', '%A', '%b', '%B') as $token)
|
Chris@76
|
802 if (strpos($str, $token) !== false)
|
Chris@76
|
803 $str = str_replace($token, !empty($txt['lang_capitalize_dates']) ? $smcFunc['ucwords'](strftime($token, $time)) : strftime($token, $time), $str);
|
Chris@76
|
804 }
|
Chris@76
|
805 else
|
Chris@76
|
806 {
|
Chris@76
|
807 // Do-it-yourself time localization. Fun.
|
Chris@76
|
808 foreach (array('%a' => 'days_short', '%A' => 'days', '%b' => 'months_short', '%B' => 'months') as $token => $text_label)
|
Chris@76
|
809 if (strpos($str, $token) !== false)
|
Chris@76
|
810 $str = str_replace($token, $txt[$text_label][(int) strftime($token === '%a' || $token === '%A' ? '%w' : '%m', $time)], $str);
|
Chris@76
|
811
|
Chris@76
|
812 if (strpos($str, '%p') !== false)
|
Chris@76
|
813 $str = str_replace('%p', (strftime('%H', $time) < 12 ? $txt['time_am'] : $txt['time_pm']), $str);
|
Chris@76
|
814 }
|
Chris@76
|
815
|
Chris@76
|
816 // Windows doesn't support %e; on some versions, strftime fails altogether if used, so let's prevent that.
|
Chris@76
|
817 if ($context['server']['is_windows'] && strpos($str, '%e') !== false)
|
Chris@76
|
818 $str = str_replace('%e', ltrim(strftime('%d', $time), '0'), $str);
|
Chris@76
|
819
|
Chris@76
|
820 // Format any other characters..
|
Chris@76
|
821 return strftime($str, $time);
|
Chris@76
|
822 }
|
Chris@76
|
823
|
Chris@76
|
824 // Removes special entities from strings. Compatibility...
|
Chris@76
|
825 function un_htmlspecialchars($string)
|
Chris@76
|
826 {
|
Chris@76
|
827 static $translation;
|
Chris@76
|
828
|
Chris@76
|
829 if (!isset($translation))
|
Chris@76
|
830 $translation = array_flip(get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES)) + array(''' => '\'', ' ' => ' ');
|
Chris@76
|
831
|
Chris@76
|
832 return strtr($string, $translation);
|
Chris@76
|
833 }
|
Chris@76
|
834
|
Chris@76
|
835 // Shorten a subject + internationalization concerns.
|
Chris@76
|
836 function shorten_subject($subject, $len)
|
Chris@76
|
837 {
|
Chris@76
|
838 global $smcFunc;
|
Chris@76
|
839
|
Chris@76
|
840 // It was already short enough!
|
Chris@76
|
841 if ($smcFunc['strlen']($subject) <= $len)
|
Chris@76
|
842 return $subject;
|
Chris@76
|
843
|
Chris@76
|
844 // Shorten it by the length it was too long, and strip off junk from the end.
|
Chris@76
|
845 return $smcFunc['substr']($subject, 0, $len) . '...';
|
Chris@76
|
846 }
|
Chris@76
|
847
|
Chris@76
|
848 // The current time with offset.
|
Chris@76
|
849 function forum_time($use_user_offset = true, $timestamp = null)
|
Chris@76
|
850 {
|
Chris@76
|
851 global $user_info, $modSettings;
|
Chris@76
|
852
|
Chris@76
|
853 if ($timestamp === null)
|
Chris@76
|
854 $timestamp = time();
|
Chris@76
|
855 elseif ($timestamp == 0)
|
Chris@76
|
856 return 0;
|
Chris@76
|
857
|
Chris@76
|
858 return $timestamp + ($modSettings['time_offset'] + ($use_user_offset ? $user_info['time_offset'] : 0)) * 3600;
|
Chris@76
|
859 }
|
Chris@76
|
860
|
Chris@76
|
861 // This gets all possible permutations of an array.
|
Chris@76
|
862 function permute($array)
|
Chris@76
|
863 {
|
Chris@76
|
864 $orders = array($array);
|
Chris@76
|
865
|
Chris@76
|
866 $n = count($array);
|
Chris@76
|
867 $p = range(0, $n);
|
Chris@76
|
868 for ($i = 1; $i < $n; null)
|
Chris@76
|
869 {
|
Chris@76
|
870 $p[$i]--;
|
Chris@76
|
871 $j = $i % 2 != 0 ? $p[$i] : 0;
|
Chris@76
|
872
|
Chris@76
|
873 $temp = $array[$i];
|
Chris@76
|
874 $array[$i] = $array[$j];
|
Chris@76
|
875 $array[$j] = $temp;
|
Chris@76
|
876
|
Chris@76
|
877 for ($i = 1; $p[$i] == 0; $i++)
|
Chris@76
|
878 $p[$i] = 1;
|
Chris@76
|
879
|
Chris@76
|
880 $orders[] = $array;
|
Chris@76
|
881 }
|
Chris@76
|
882
|
Chris@76
|
883 return $orders;
|
Chris@76
|
884 }
|
Chris@76
|
885
|
Chris@76
|
886 // Parse bulletin board code in a string, as well as smileys optionally.
|
Chris@76
|
887 function parse_bbc($message, $smileys = true, $cache_id = '', $parse_tags = array())
|
Chris@76
|
888 {
|
Chris@76
|
889 global $txt, $scripturl, $context, $modSettings, $user_info, $smcFunc;
|
Chris@76
|
890 static $bbc_codes = array(), $itemcodes = array(), $no_autolink_tags = array();
|
Chris@76
|
891 static $disabled;
|
Chris@76
|
892
|
Chris@76
|
893 // Don't waste cycles
|
Chris@76
|
894 if ($message === '')
|
Chris@76
|
895 return '';
|
Chris@76
|
896
|
Chris@76
|
897 // Never show smileys for wireless clients. More bytes, can't see it anyway :P.
|
Chris@76
|
898 if (WIRELESS)
|
Chris@76
|
899 $smileys = false;
|
Chris@76
|
900 elseif ($smileys !== null && ($smileys == '1' || $smileys == '0'))
|
Chris@76
|
901 $smileys = (bool) $smileys;
|
Chris@76
|
902
|
Chris@76
|
903 if (empty($modSettings['enableBBC']) && $message !== false)
|
Chris@76
|
904 {
|
Chris@76
|
905 if ($smileys === true)
|
Chris@76
|
906 parsesmileys($message);
|
Chris@76
|
907
|
Chris@76
|
908 return $message;
|
Chris@76
|
909 }
|
Chris@76
|
910
|
Chris@76
|
911 // Just in case it wasn't determined yet whether UTF-8 is enabled.
|
Chris@76
|
912 if (!isset($context['utf8']))
|
Chris@76
|
913 $context['utf8'] = (empty($modSettings['global_character_set']) ? $txt['lang_character_set'] : $modSettings['global_character_set']) === 'UTF-8';
|
Chris@76
|
914
|
Chris@76
|
915 // If we are not doing every tag then we don't cache this run.
|
Chris@76
|
916 if (!empty($parse_tags) && !empty($bbc_codes))
|
Chris@76
|
917 {
|
Chris@76
|
918 $temp_bbc = $bbc_codes;
|
Chris@76
|
919 $bbc_codes = array();
|
Chris@76
|
920 }
|
Chris@76
|
921
|
Chris@76
|
922 // Sift out the bbc for a performance improvement.
|
Chris@76
|
923 if (empty($bbc_codes) || $message === false || !empty($parse_tags))
|
Chris@76
|
924 {
|
Chris@76
|
925 if (!empty($modSettings['disabledBBC']))
|
Chris@76
|
926 {
|
Chris@76
|
927 $temp = explode(',', strtolower($modSettings['disabledBBC']));
|
Chris@76
|
928
|
Chris@76
|
929 foreach ($temp as $tag)
|
Chris@76
|
930 $disabled[trim($tag)] = true;
|
Chris@76
|
931 }
|
Chris@76
|
932
|
Chris@76
|
933 if (empty($modSettings['enableEmbeddedFlash']))
|
Chris@76
|
934 $disabled['flash'] = true;
|
Chris@76
|
935
|
Chris@76
|
936 /* The following bbc are formatted as an array, with keys as follows:
|
Chris@76
|
937
|
Chris@76
|
938 tag: the tag's name - should be lowercase!
|
Chris@76
|
939
|
Chris@76
|
940 type: one of...
|
Chris@76
|
941 - (missing): [tag]parsed content[/tag]
|
Chris@76
|
942 - unparsed_equals: [tag=xyz]parsed content[/tag]
|
Chris@76
|
943 - parsed_equals: [tag=parsed data]parsed content[/tag]
|
Chris@76
|
944 - unparsed_content: [tag]unparsed content[/tag]
|
Chris@76
|
945 - closed: [tag], [tag/], [tag /]
|
Chris@76
|
946 - unparsed_commas: [tag=1,2,3]parsed content[/tag]
|
Chris@76
|
947 - unparsed_commas_content: [tag=1,2,3]unparsed content[/tag]
|
Chris@76
|
948 - unparsed_equals_content: [tag=...]unparsed content[/tag]
|
Chris@76
|
949
|
Chris@76
|
950 parameters: an optional array of parameters, for the form
|
Chris@76
|
951 [tag abc=123]content[/tag]. The array is an associative array
|
Chris@76
|
952 where the keys are the parameter names, and the values are an
|
Chris@76
|
953 array which may contain the following:
|
Chris@76
|
954 - match: a regular expression to validate and match the value.
|
Chris@76
|
955 - quoted: true if the value should be quoted.
|
Chris@76
|
956 - validate: callback to evaluate on the data, which is $data.
|
Chris@76
|
957 - value: a string in which to replace $1 with the data.
|
Chris@76
|
958 either it or validate may be used, not both.
|
Chris@76
|
959 - optional: true if the parameter is optional.
|
Chris@76
|
960
|
Chris@76
|
961 test: a regular expression to test immediately after the tag's
|
Chris@76
|
962 '=', ' ' or ']'. Typically, should have a \] at the end.
|
Chris@76
|
963 Optional.
|
Chris@76
|
964
|
Chris@76
|
965 content: only available for unparsed_content, closed,
|
Chris@76
|
966 unparsed_commas_content, and unparsed_equals_content.
|
Chris@76
|
967 $1 is replaced with the content of the tag. Parameters
|
Chris@76
|
968 are replaced in the form {param}. For unparsed_commas_content,
|
Chris@76
|
969 $2, $3, ..., $n are replaced.
|
Chris@76
|
970
|
Chris@76
|
971 before: only when content is not used, to go before any
|
Chris@76
|
972 content. For unparsed_equals, $1 is replaced with the value.
|
Chris@76
|
973 For unparsed_commas, $1, $2, ..., $n are replaced.
|
Chris@76
|
974
|
Chris@76
|
975 after: similar to before in every way, except that it is used
|
Chris@76
|
976 when the tag is closed.
|
Chris@76
|
977
|
Chris@76
|
978 disabled_content: used in place of content when the tag is
|
Chris@76
|
979 disabled. For closed, default is '', otherwise it is '$1' if
|
Chris@76
|
980 block_level is false, '<div>$1</div>' elsewise.
|
Chris@76
|
981
|
Chris@76
|
982 disabled_before: used in place of before when disabled. Defaults
|
Chris@76
|
983 to '<div>' if block_level, '' if not.
|
Chris@76
|
984
|
Chris@76
|
985 disabled_after: used in place of after when disabled. Defaults
|
Chris@76
|
986 to '</div>' if block_level, '' if not.
|
Chris@76
|
987
|
Chris@76
|
988 block_level: set to true the tag is a "block level" tag, similar
|
Chris@76
|
989 to HTML. Block level tags cannot be nested inside tags that are
|
Chris@76
|
990 not block level, and will not be implicitly closed as easily.
|
Chris@76
|
991 One break following a block level tag may also be removed.
|
Chris@76
|
992
|
Chris@76
|
993 trim: if set, and 'inside' whitespace after the begin tag will be
|
Chris@76
|
994 removed. If set to 'outside', whitespace after the end tag will
|
Chris@76
|
995 meet the same fate.
|
Chris@76
|
996
|
Chris@76
|
997 validate: except when type is missing or 'closed', a callback to
|
Chris@76
|
998 validate the data as $data. Depending on the tag's type, $data
|
Chris@76
|
999 may be a string or an array of strings (corresponding to the
|
Chris@76
|
1000 replacement.)
|
Chris@76
|
1001
|
Chris@76
|
1002 quoted: when type is 'unparsed_equals' or 'parsed_equals' only,
|
Chris@76
|
1003 may be not set, 'optional', or 'required' corresponding to if
|
Chris@76
|
1004 the content may be quoted. This allows the parser to read
|
Chris@76
|
1005 [tag="abc]def[esdf]"] properly.
|
Chris@76
|
1006
|
Chris@76
|
1007 require_parents: an array of tag names, or not set. If set, the
|
Chris@76
|
1008 enclosing tag *must* be one of the listed tags, or parsing won't
|
Chris@76
|
1009 occur.
|
Chris@76
|
1010
|
Chris@76
|
1011 require_children: similar to require_parents, if set children
|
Chris@76
|
1012 won't be parsed if they are not in the list.
|
Chris@76
|
1013
|
Chris@76
|
1014 disallow_children: similar to, but very different from,
|
Chris@76
|
1015 require_children, if it is set the listed tags will not be
|
Chris@76
|
1016 parsed inside the tag.
|
Chris@76
|
1017
|
Chris@76
|
1018 parsed_tags_allowed: an array restricting what BBC can be in the
|
Chris@76
|
1019 parsed_equals parameter, if desired.
|
Chris@76
|
1020 */
|
Chris@76
|
1021
|
Chris@76
|
1022 $codes = array(
|
Chris@76
|
1023 array(
|
Chris@76
|
1024 'tag' => 'abbr',
|
Chris@76
|
1025 'type' => 'unparsed_equals',
|
Chris@76
|
1026 'before' => '<abbr title="$1">',
|
Chris@76
|
1027 'after' => '</abbr>',
|
Chris@76
|
1028 'quoted' => 'optional',
|
Chris@76
|
1029 'disabled_after' => ' ($1)',
|
Chris@76
|
1030 ),
|
Chris@76
|
1031 array(
|
Chris@76
|
1032 'tag' => 'acronym',
|
Chris@76
|
1033 'type' => 'unparsed_equals',
|
Chris@76
|
1034 'before' => '<acronym title="$1">',
|
Chris@76
|
1035 'after' => '</acronym>',
|
Chris@76
|
1036 'quoted' => 'optional',
|
Chris@76
|
1037 'disabled_after' => ' ($1)',
|
Chris@76
|
1038 ),
|
Chris@76
|
1039 array(
|
Chris@76
|
1040 'tag' => 'anchor',
|
Chris@76
|
1041 'type' => 'unparsed_equals',
|
Chris@76
|
1042 'test' => '[#]?([A-Za-z][A-Za-z0-9_\-]*)\]',
|
Chris@76
|
1043 'before' => '<span id="post_$1">',
|
Chris@76
|
1044 'after' => '</span>',
|
Chris@76
|
1045 ),
|
Chris@76
|
1046 array(
|
Chris@76
|
1047 'tag' => 'b',
|
Chris@76
|
1048 'before' => '<strong>',
|
Chris@76
|
1049 'after' => '</strong>',
|
Chris@76
|
1050 ),
|
Chris@76
|
1051 array(
|
Chris@76
|
1052 'tag' => 'bdo',
|
Chris@76
|
1053 'type' => 'unparsed_equals',
|
Chris@76
|
1054 'before' => '<bdo dir="$1">',
|
Chris@76
|
1055 'after' => '</bdo>',
|
Chris@76
|
1056 'test' => '(rtl|ltr)\]',
|
Chris@76
|
1057 'block_level' => true,
|
Chris@76
|
1058 ),
|
Chris@76
|
1059 array(
|
Chris@76
|
1060 'tag' => 'black',
|
Chris@76
|
1061 'before' => '<span style="color: black;" class="bbc_color">',
|
Chris@76
|
1062 'after' => '</span>',
|
Chris@76
|
1063 ),
|
Chris@76
|
1064 array(
|
Chris@76
|
1065 'tag' => 'blue',
|
Chris@76
|
1066 'before' => '<span style="color: blue;" class="bbc_color">',
|
Chris@76
|
1067 'after' => '</span>',
|
Chris@76
|
1068 ),
|
Chris@76
|
1069 array(
|
Chris@76
|
1070 'tag' => 'br',
|
Chris@76
|
1071 'type' => 'closed',
|
Chris@76
|
1072 'content' => '<br />',
|
Chris@76
|
1073 ),
|
Chris@76
|
1074 array(
|
Chris@76
|
1075 'tag' => 'center',
|
Chris@76
|
1076 'before' => '<div align="center">',
|
Chris@76
|
1077 'after' => '</div>',
|
Chris@76
|
1078 'block_level' => true,
|
Chris@76
|
1079 ),
|
Chris@76
|
1080 array(
|
Chris@76
|
1081 'tag' => 'code',
|
Chris@76
|
1082 'type' => 'unparsed_content',
|
Chris@76
|
1083 'content' => '<div class="codeheader">' . $txt['code'] . ': <a href="javascript:void(0);" onclick="return smfSelectText(this);" class="codeoperation">' . $txt['code_select'] . '</a></div>' . ($context['browser']['is_gecko'] || $context['browser']['is_opera'] ? '<pre style="margin: 0; padding: 0;">' : '') . '<code class="bbc_code">$1</code>' . ($context['browser']['is_gecko'] || $context['browser']['is_opera'] ? '</pre>' : ''),
|
Chris@76
|
1084 // !!! Maybe this can be simplified?
|
Chris@76
|
1085 'validate' => isset($disabled['code']) ? null : create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1086 global $context;
|
Chris@76
|
1087
|
Chris@76
|
1088 if (!isset($disabled[\'code\']))
|
Chris@76
|
1089 {
|
Chris@76
|
1090 $php_parts = preg_split(\'~(<\?php|\?>)~\', $data, -1, PREG_SPLIT_DELIM_CAPTURE);
|
Chris@76
|
1091
|
Chris@76
|
1092 for ($php_i = 0, $php_n = count($php_parts); $php_i < $php_n; $php_i++)
|
Chris@76
|
1093 {
|
Chris@76
|
1094 // Do PHP code coloring?
|
Chris@76
|
1095 if ($php_parts[$php_i] != \'<?php\')
|
Chris@76
|
1096 continue;
|
Chris@76
|
1097
|
Chris@76
|
1098 $php_string = \'\';
|
Chris@76
|
1099 while ($php_i + 1 < count($php_parts) && $php_parts[$php_i] != \'?>\')
|
Chris@76
|
1100 {
|
Chris@76
|
1101 $php_string .= $php_parts[$php_i];
|
Chris@76
|
1102 $php_parts[$php_i++] = \'\';
|
Chris@76
|
1103 }
|
Chris@76
|
1104 $php_parts[$php_i] = highlight_php_code($php_string . $php_parts[$php_i]);
|
Chris@76
|
1105 }
|
Chris@76
|
1106
|
Chris@76
|
1107 // Fix the PHP code stuff...
|
Chris@76
|
1108 $data = str_replace("<pre style=\"display: inline;\">\t</pre>", "\t", implode(\'\', $php_parts));
|
Chris@76
|
1109
|
Chris@76
|
1110 // Older browsers are annoying, aren\'t they?
|
Chris@76
|
1111 if ($context[\'browser\'][\'is_ie4\'] || $context[\'browser\'][\'is_ie5\'] || $context[\'browser\'][\'is_ie5.5\'])
|
Chris@76
|
1112 $data = str_replace("\t", "<pre style=\"display: inline;\">\t</pre>", $data);
|
Chris@76
|
1113 else
|
Chris@76
|
1114 $data = str_replace("\t", "<span style=\"white-space: pre;\">\t</span>", $data);
|
Chris@76
|
1115
|
Chris@76
|
1116 // Recent Opera bug requiring temporary fix. &nsbp; is needed before </code> to avoid broken selection.
|
Chris@76
|
1117 if ($context[\'browser\'][\'is_opera\'])
|
Chris@76
|
1118 $data .= \' \';
|
Chris@76
|
1119 }'),
|
Chris@76
|
1120 'block_level' => true,
|
Chris@76
|
1121 ),
|
Chris@76
|
1122 array(
|
Chris@76
|
1123 'tag' => 'code',
|
Chris@76
|
1124 'type' => 'unparsed_equals_content',
|
Chris@76
|
1125 'content' => '<div class="codeheader">' . $txt['code'] . ': ($2) <a href="#" onclick="return smfSelectText(this);" class="codeoperation">' . $txt['code_select'] . '</a></div>' . ($context['browser']['is_gecko'] || $context['browser']['is_opera'] ? '<pre style="margin: 0; padding: 0;">' : '') . '<code class="bbc_code">$1</code>' . ($context['browser']['is_gecko'] || $context['browser']['is_opera'] ? '</pre>' : ''),
|
Chris@76
|
1126 // !!! Maybe this can be simplified?
|
Chris@76
|
1127 'validate' => isset($disabled['code']) ? null : create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1128 global $context;
|
Chris@76
|
1129
|
Chris@76
|
1130 if (!isset($disabled[\'code\']))
|
Chris@76
|
1131 {
|
Chris@76
|
1132 $php_parts = preg_split(\'~(<\?php|\?>)~\', $data[0], -1, PREG_SPLIT_DELIM_CAPTURE);
|
Chris@76
|
1133
|
Chris@76
|
1134 for ($php_i = 0, $php_n = count($php_parts); $php_i < $php_n; $php_i++)
|
Chris@76
|
1135 {
|
Chris@76
|
1136 // Do PHP code coloring?
|
Chris@76
|
1137 if ($php_parts[$php_i] != \'<?php\')
|
Chris@76
|
1138 continue;
|
Chris@76
|
1139
|
Chris@76
|
1140 $php_string = \'\';
|
Chris@76
|
1141 while ($php_i + 1 < count($php_parts) && $php_parts[$php_i] != \'?>\')
|
Chris@76
|
1142 {
|
Chris@76
|
1143 $php_string .= $php_parts[$php_i];
|
Chris@76
|
1144 $php_parts[$php_i++] = \'\';
|
Chris@76
|
1145 }
|
Chris@76
|
1146 $php_parts[$php_i] = highlight_php_code($php_string . $php_parts[$php_i]);
|
Chris@76
|
1147 }
|
Chris@76
|
1148
|
Chris@76
|
1149 // Fix the PHP code stuff...
|
Chris@76
|
1150 $data[0] = str_replace("<pre style=\"display: inline;\">\t</pre>", "\t", implode(\'\', $php_parts));
|
Chris@76
|
1151
|
Chris@76
|
1152 // Older browsers are annoying, aren\'t they?
|
Chris@76
|
1153 if ($context[\'browser\'][\'is_ie4\'] || $context[\'browser\'][\'is_ie5\'] || $context[\'browser\'][\'is_ie5.5\'])
|
Chris@76
|
1154 $data[0] = str_replace("\t", "<pre style=\"display: inline;\">\t</pre>", $data[0]);
|
Chris@76
|
1155 else
|
Chris@76
|
1156 $data[0] = str_replace("\t", "<span style=\"white-space: pre;\">\t</span>", $data[0]);
|
Chris@76
|
1157
|
Chris@76
|
1158 // Recent Opera bug requiring temporary fix. &nsbp; is needed before </code> to avoid broken selection.
|
Chris@76
|
1159 if ($context[\'browser\'][\'is_opera\'])
|
Chris@76
|
1160 $data[0] .= \' \';
|
Chris@76
|
1161 }'),
|
Chris@76
|
1162 'block_level' => true,
|
Chris@76
|
1163 ),
|
Chris@76
|
1164 array(
|
Chris@76
|
1165 'tag' => 'color',
|
Chris@76
|
1166 'type' => 'unparsed_equals',
|
Chris@76
|
1167 'test' => '(#[\da-fA-F]{3}|#[\da-fA-F]{6}|[A-Za-z]{1,20}|rgb\(\d{1,3}, ?\d{1,3}, ?\d{1,3}\))\]',
|
Chris@76
|
1168 'before' => '<span style="color: $1;" class="bbc_color">',
|
Chris@76
|
1169 'after' => '</span>',
|
Chris@76
|
1170 ),
|
Chris@76
|
1171 array(
|
Chris@76
|
1172 'tag' => 'email',
|
Chris@76
|
1173 'type' => 'unparsed_content',
|
Chris@76
|
1174 'content' => '<a href="mailto:$1" class="bbc_email">$1</a>',
|
Chris@76
|
1175 // !!! Should this respect guest_hideContacts?
|
Chris@76
|
1176 'validate' => create_function('&$tag, &$data, $disabled', '$data = strtr($data, array(\'<br />\' => \'\'));'),
|
Chris@76
|
1177 ),
|
Chris@76
|
1178 array(
|
Chris@76
|
1179 'tag' => 'email',
|
Chris@76
|
1180 'type' => 'unparsed_equals',
|
Chris@76
|
1181 'before' => '<a href="mailto:$1" class="bbc_email">',
|
Chris@76
|
1182 'after' => '</a>',
|
Chris@76
|
1183 // !!! Should this respect guest_hideContacts?
|
Chris@76
|
1184 'disallow_children' => array('email', 'ftp', 'url', 'iurl'),
|
Chris@76
|
1185 'disabled_after' => ' ($1)',
|
Chris@76
|
1186 ),
|
Chris@76
|
1187 array(
|
Chris@76
|
1188 'tag' => 'flash',
|
Chris@76
|
1189 'type' => 'unparsed_commas_content',
|
Chris@76
|
1190 'test' => '\d+,\d+\]',
|
Chris@76
|
1191 'content' => ($context['browser']['is_ie'] && !$context['browser']['is_mac_ie'] ? '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="$2" height="$3"><param name="movie" value="$1" /><param name="play" value="true" /><param name="loop" value="true" /><param name="quality" value="high" /><param name="AllowScriptAccess" value="never" /><embed src="$1" width="$2" height="$3" play="true" loop="true" quality="high" AllowScriptAccess="never" /><noembed><a href="$1" target="_blank" class="new_win">$1</a></noembed></object>' : '<embed type="application/x-shockwave-flash" src="$1" width="$2" height="$3" play="true" loop="true" quality="high" AllowScriptAccess="never" /><noembed><a href="$1" target="_blank" class="new_win">$1</a></noembed>'),
|
Chris@76
|
1192 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1193 if (isset($disabled[\'url\']))
|
Chris@76
|
1194 $tag[\'content\'] = \'$1\';
|
Chris@76
|
1195 elseif (strpos($data[0], \'http://\') !== 0 && strpos($data[0], \'https://\') !== 0)
|
Chris@76
|
1196 $data[0] = \'http://\' . $data[0];
|
Chris@76
|
1197 '),
|
Chris@76
|
1198 'disabled_content' => '<a href="$1" target="_blank" class="new_win">$1</a>',
|
Chris@76
|
1199 ),
|
Chris@76
|
1200 array(
|
Chris@76
|
1201 'tag' => 'font',
|
Chris@76
|
1202 'type' => 'unparsed_equals',
|
Chris@76
|
1203 'test' => '[A-Za-z0-9_,\-\s]+?\]',
|
Chris@76
|
1204 'before' => '<span style="font-family: $1;" class="bbc_font">',
|
Chris@76
|
1205 'after' => '</span>',
|
Chris@76
|
1206 ),
|
Chris@76
|
1207 array(
|
Chris@76
|
1208 'tag' => 'ftp',
|
Chris@76
|
1209 'type' => 'unparsed_content',
|
Chris@76
|
1210 'content' => '<a href="$1" class="bbc_ftp new_win" target="_blank">$1</a>',
|
Chris@76
|
1211 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1212 $data = strtr($data, array(\'<br />\' => \'\'));
|
Chris@76
|
1213 if (strpos($data, \'ftp://\') !== 0 && strpos($data, \'ftps://\') !== 0)
|
Chris@76
|
1214 $data = \'ftp://\' . $data;
|
Chris@76
|
1215 '),
|
Chris@76
|
1216 ),
|
Chris@76
|
1217 array(
|
Chris@76
|
1218 'tag' => 'ftp',
|
Chris@76
|
1219 'type' => 'unparsed_equals',
|
Chris@76
|
1220 'before' => '<a href="$1" class="bbc_ftp new_win" target="_blank">',
|
Chris@76
|
1221 'after' => '</a>',
|
Chris@76
|
1222 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1223 if (strpos($data, \'ftp://\') !== 0 && strpos($data, \'ftps://\') !== 0)
|
Chris@76
|
1224 $data = \'ftp://\' . $data;
|
Chris@76
|
1225 '),
|
Chris@76
|
1226 'disallow_children' => array('email', 'ftp', 'url', 'iurl'),
|
Chris@76
|
1227 'disabled_after' => ' ($1)',
|
Chris@76
|
1228 ),
|
Chris@76
|
1229 array(
|
Chris@76
|
1230 'tag' => 'glow',
|
Chris@76
|
1231 'type' => 'unparsed_commas',
|
Chris@76
|
1232 'test' => '[#0-9a-zA-Z\-]{3,12},([012]\d{1,2}|\d{1,2})(,[^]]+)?\]',
|
Chris@76
|
1233 'before' => $context['browser']['is_ie'] ? '<table border="0" cellpadding="0" cellspacing="0" style="display: inline; vertical-align: middle; font: inherit;"><tr><td style="filter: Glow(color=$1, strength=$2); font: inherit;">' : '<span style="text-shadow: $1 1px 1px 1px">',
|
Chris@76
|
1234 'after' => $context['browser']['is_ie'] ? '</td></tr></table> ' : '</span>',
|
Chris@76
|
1235 ),
|
Chris@76
|
1236 array(
|
Chris@76
|
1237 'tag' => 'green',
|
Chris@76
|
1238 'before' => '<span style="color: green;" class="bbc_color">',
|
Chris@76
|
1239 'after' => '</span>',
|
Chris@76
|
1240 ),
|
Chris@76
|
1241 array(
|
Chris@76
|
1242 'tag' => 'html',
|
Chris@76
|
1243 'type' => 'unparsed_content',
|
Chris@76
|
1244 'content' => '$1',
|
Chris@76
|
1245 'block_level' => true,
|
Chris@76
|
1246 'disabled_content' => '$1',
|
Chris@76
|
1247 ),
|
Chris@76
|
1248 array(
|
Chris@76
|
1249 'tag' => 'hr',
|
Chris@76
|
1250 'type' => 'closed',
|
Chris@76
|
1251 'content' => '<hr />',
|
Chris@76
|
1252 'block_level' => true,
|
Chris@76
|
1253 ),
|
Chris@76
|
1254 array(
|
Chris@76
|
1255 'tag' => 'i',
|
Chris@76
|
1256 'before' => '<em>',
|
Chris@76
|
1257 'after' => '</em>',
|
Chris@76
|
1258 ),
|
Chris@76
|
1259 array(
|
Chris@76
|
1260 'tag' => 'img',
|
Chris@76
|
1261 'type' => 'unparsed_content',
|
Chris@76
|
1262 'parameters' => array(
|
Chris@76
|
1263 'alt' => array('optional' => true),
|
Chris@76
|
1264 'width' => array('optional' => true, 'value' => ' width="$1"', 'match' => '(\d+)'),
|
Chris@76
|
1265 'height' => array('optional' => true, 'value' => ' height="$1"', 'match' => '(\d+)'),
|
Chris@76
|
1266 ),
|
Chris@76
|
1267 'content' => '<img src="$1" alt="{alt}"{width}{height} class="bbc_img resized" />',
|
Chris@76
|
1268 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1269 $data = strtr($data, array(\'<br />\' => \'\'));
|
Chris@76
|
1270 if (strpos($data, \'http://\') !== 0 && strpos($data, \'https://\') !== 0)
|
Chris@76
|
1271 $data = \'http://\' . $data;
|
Chris@76
|
1272 '),
|
Chris@76
|
1273 'disabled_content' => '($1)',
|
Chris@76
|
1274 ),
|
Chris@76
|
1275 array(
|
Chris@76
|
1276 'tag' => 'img',
|
Chris@76
|
1277 'type' => 'unparsed_content',
|
Chris@76
|
1278 'content' => '<img src="$1" alt="" class="bbc_img" />',
|
Chris@76
|
1279 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1280 $data = strtr($data, array(\'<br />\' => \'\'));
|
Chris@76
|
1281 if (strpos($data, \'http://\') !== 0 && strpos($data, \'https://\') !== 0)
|
Chris@76
|
1282 $data = \'http://\' . $data;
|
Chris@76
|
1283 '),
|
Chris@76
|
1284 'disabled_content' => '($1)',
|
Chris@76
|
1285 ),
|
Chris@76
|
1286 array(
|
Chris@76
|
1287 'tag' => 'iurl',
|
Chris@76
|
1288 'type' => 'unparsed_content',
|
Chris@76
|
1289 'content' => '<a href="$1" class="bbc_link">$1</a>',
|
Chris@76
|
1290 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1291 $data = strtr($data, array(\'<br />\' => \'\'));
|
Chris@76
|
1292 if (strpos($data, \'http://\') !== 0 && strpos($data, \'https://\') !== 0)
|
Chris@76
|
1293 $data = \'http://\' . $data;
|
Chris@76
|
1294 '),
|
Chris@76
|
1295 ),
|
Chris@76
|
1296 array(
|
Chris@76
|
1297 'tag' => 'iurl',
|
Chris@76
|
1298 'type' => 'unparsed_equals',
|
Chris@76
|
1299 'before' => '<a href="$1" class="bbc_link">',
|
Chris@76
|
1300 'after' => '</a>',
|
Chris@76
|
1301 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1302 if (substr($data, 0, 1) == \'#\')
|
Chris@76
|
1303 $data = \'#post_\' . substr($data, 1);
|
Chris@76
|
1304 elseif (strpos($data, \'http://\') !== 0 && strpos($data, \'https://\') !== 0)
|
Chris@76
|
1305 $data = \'http://\' . $data;
|
Chris@76
|
1306 '),
|
Chris@76
|
1307 'disallow_children' => array('email', 'ftp', 'url', 'iurl'),
|
Chris@76
|
1308 'disabled_after' => ' ($1)',
|
Chris@76
|
1309 ),
|
Chris@76
|
1310 array(
|
Chris@76
|
1311 'tag' => 'left',
|
Chris@76
|
1312 'before' => '<div style="text-align: left;">',
|
Chris@76
|
1313 'after' => '</div>',
|
Chris@76
|
1314 'block_level' => true,
|
Chris@76
|
1315 ),
|
Chris@76
|
1316 array(
|
Chris@76
|
1317 'tag' => 'li',
|
Chris@76
|
1318 'before' => '<li>',
|
Chris@76
|
1319 'after' => '</li>',
|
Chris@76
|
1320 'trim' => 'outside',
|
Chris@76
|
1321 'require_parents' => array('list'),
|
Chris@76
|
1322 'block_level' => true,
|
Chris@76
|
1323 'disabled_before' => '',
|
Chris@76
|
1324 'disabled_after' => '<br />',
|
Chris@76
|
1325 ),
|
Chris@76
|
1326 array(
|
Chris@76
|
1327 'tag' => 'list',
|
Chris@76
|
1328 'before' => '<ul class="bbc_list">',
|
Chris@76
|
1329 'after' => '</ul>',
|
Chris@76
|
1330 'trim' => 'inside',
|
Chris@76
|
1331 'require_children' => array('li', 'list'),
|
Chris@76
|
1332 'block_level' => true,
|
Chris@76
|
1333 ),
|
Chris@76
|
1334 array(
|
Chris@76
|
1335 'tag' => 'list',
|
Chris@76
|
1336 'parameters' => array(
|
Chris@76
|
1337 'type' => array('match' => '(none|disc|circle|square|decimal|decimal-leading-zero|lower-roman|upper-roman|lower-alpha|upper-alpha|lower-greek|lower-latin|upper-latin|hebrew|armenian|georgian|cjk-ideographic|hiragana|katakana|hiragana-iroha|katakana-iroha)'),
|
Chris@76
|
1338 ),
|
Chris@76
|
1339 'before' => '<ul class="bbc_list" style="list-style-type: {type};">',
|
Chris@76
|
1340 'after' => '</ul>',
|
Chris@76
|
1341 'trim' => 'inside',
|
Chris@76
|
1342 'require_children' => array('li'),
|
Chris@76
|
1343 'block_level' => true,
|
Chris@76
|
1344 ),
|
Chris@76
|
1345 array(
|
Chris@76
|
1346 'tag' => 'ltr',
|
Chris@76
|
1347 'before' => '<div dir="ltr">',
|
Chris@76
|
1348 'after' => '</div>',
|
Chris@76
|
1349 'block_level' => true,
|
Chris@76
|
1350 ),
|
Chris@76
|
1351 array(
|
Chris@76
|
1352 'tag' => 'me',
|
Chris@76
|
1353 'type' => 'unparsed_equals',
|
Chris@76
|
1354 'before' => '<div class="meaction">* $1 ',
|
Chris@76
|
1355 'after' => '</div>',
|
Chris@76
|
1356 'quoted' => 'optional',
|
Chris@76
|
1357 'block_level' => true,
|
Chris@76
|
1358 'disabled_before' => '/me ',
|
Chris@76
|
1359 'disabled_after' => '<br />',
|
Chris@76
|
1360 ),
|
Chris@76
|
1361 array(
|
Chris@76
|
1362 'tag' => 'move',
|
Chris@76
|
1363 'before' => '<marquee>',
|
Chris@76
|
1364 'after' => '</marquee>',
|
Chris@76
|
1365 'block_level' => true,
|
Chris@76
|
1366 'disallow_children' => array('move'),
|
Chris@76
|
1367 ),
|
Chris@76
|
1368 array(
|
Chris@76
|
1369 'tag' => 'nobbc',
|
Chris@76
|
1370 'type' => 'unparsed_content',
|
Chris@76
|
1371 'content' => '$1',
|
Chris@76
|
1372 ),
|
Chris@76
|
1373 array(
|
Chris@76
|
1374 'tag' => 'php',
|
Chris@76
|
1375 'type' => 'unparsed_content',
|
Chris@76
|
1376 'content' => '<span class="phpcode">$1</span>',
|
Chris@76
|
1377 'validate' => isset($disabled['php']) ? null : create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1378 if (!isset($disabled[\'php\']))
|
Chris@76
|
1379 {
|
Chris@76
|
1380 $add_begin = substr(trim($data), 0, 5) != \'<?\';
|
Chris@76
|
1381 $data = highlight_php_code($add_begin ? \'<?php \' . $data . \'?>\' : $data);
|
Chris@76
|
1382 if ($add_begin)
|
Chris@76
|
1383 $data = preg_replace(array(\'~^(.+?)<\?.{0,40}?php(?: |\s)~\', \'~\?>((?:</(font|span)>)*)$~\'), \'$1\', $data, 2);
|
Chris@76
|
1384 }'),
|
Chris@76
|
1385 'block_level' => false,
|
Chris@76
|
1386 'disabled_content' => '$1',
|
Chris@76
|
1387 ),
|
Chris@76
|
1388 array(
|
Chris@76
|
1389 'tag' => 'pre',
|
Chris@76
|
1390 'before' => '<pre>',
|
Chris@76
|
1391 'after' => '</pre>',
|
Chris@76
|
1392 ),
|
Chris@76
|
1393 array(
|
Chris@76
|
1394 'tag' => 'quote',
|
Chris@76
|
1395 'before' => '<div class="quoteheader"><div class="topslice_quote">' . $txt['quote'] . '</div></div><blockquote>',
|
Chris@76
|
1396 'after' => '</blockquote><div class="quotefooter"><div class="botslice_quote"></div></div>',
|
Chris@76
|
1397 'block_level' => true,
|
Chris@76
|
1398 ),
|
Chris@76
|
1399 array(
|
Chris@76
|
1400 'tag' => 'quote',
|
Chris@76
|
1401 'parameters' => array(
|
Chris@76
|
1402 'author' => array('match' => '(.{1,192}?)', 'quoted' => true),
|
Chris@76
|
1403 ),
|
Chris@76
|
1404 'before' => '<div class="quoteheader"><div class="topslice_quote">' . $txt['quote_from'] . ': {author}</div></div><blockquote>',
|
Chris@76
|
1405 'after' => '</blockquote><div class="quotefooter"><div class="botslice_quote"></div></div>',
|
Chris@76
|
1406 'block_level' => true,
|
Chris@76
|
1407 ),
|
Chris@76
|
1408 array(
|
Chris@76
|
1409 'tag' => 'quote',
|
Chris@76
|
1410 'type' => 'parsed_equals',
|
Chris@76
|
1411 'before' => '<div class="quoteheader"><div class="topslice_quote">' . $txt['quote_from'] . ': $1</div></div><blockquote>',
|
Chris@76
|
1412 'after' => '</blockquote><div class="quotefooter"><div class="botslice_quote"></div></div>',
|
Chris@76
|
1413 'quoted' => 'optional',
|
Chris@76
|
1414 // Don't allow everything to be embedded with the author name.
|
Chris@76
|
1415 'parsed_tags_allowed' => array('url', 'iurl', 'ftp'),
|
Chris@76
|
1416 'block_level' => true,
|
Chris@76
|
1417 ),
|
Chris@76
|
1418 array(
|
Chris@76
|
1419 'tag' => 'quote',
|
Chris@76
|
1420 'parameters' => array(
|
Chris@76
|
1421 'author' => array('match' => '([^<>]{1,192}?)'),
|
Chris@76
|
1422 'link' => array('match' => '(?:board=\d+;)?((?:topic|threadid)=[\dmsg#\./]{1,40}(?:;start=[\dmsg#\./]{1,40})?|action=profile;u=\d+)'),
|
Chris@76
|
1423 'date' => array('match' => '(\d+)', 'validate' => 'timeformat'),
|
Chris@76
|
1424 ),
|
Chris@76
|
1425 'before' => '<div class="quoteheader"><div class="topslice_quote"><a href="' . $scripturl . '?{link}">' . $txt['quote_from'] . ': {author} ' . $txt['search_on'] . ' {date}</a></div></div><blockquote>',
|
Chris@76
|
1426 'after' => '</blockquote><div class="quotefooter"><div class="botslice_quote"></div></div>',
|
Chris@76
|
1427 'block_level' => true,
|
Chris@76
|
1428 ),
|
Chris@76
|
1429 array(
|
Chris@76
|
1430 'tag' => 'quote',
|
Chris@76
|
1431 'parameters' => array(
|
Chris@76
|
1432 'author' => array('match' => '(.{1,192}?)'),
|
Chris@76
|
1433 ),
|
Chris@76
|
1434 'before' => '<div class="quoteheader"><div class="topslice_quote">' . $txt['quote_from'] . ': {author}</div></div><blockquote>',
|
Chris@76
|
1435 'after' => '</blockquote><div class="quotefooter"><div class="botslice_quote"></div></div>',
|
Chris@76
|
1436 'block_level' => true,
|
Chris@76
|
1437 ),
|
Chris@76
|
1438 array(
|
Chris@76
|
1439 'tag' => 'red',
|
Chris@76
|
1440 'before' => '<span style="color: red;" class="bbc_color">',
|
Chris@76
|
1441 'after' => '</span>',
|
Chris@76
|
1442 ),
|
Chris@76
|
1443 array(
|
Chris@76
|
1444 'tag' => 'right',
|
Chris@76
|
1445 'before' => '<div style="text-align: right;">',
|
Chris@76
|
1446 'after' => '</div>',
|
Chris@76
|
1447 'block_level' => true,
|
Chris@76
|
1448 ),
|
Chris@76
|
1449 array(
|
Chris@76
|
1450 'tag' => 'rtl',
|
Chris@76
|
1451 'before' => '<div dir="rtl">',
|
Chris@76
|
1452 'after' => '</div>',
|
Chris@76
|
1453 'block_level' => true,
|
Chris@76
|
1454 ),
|
Chris@76
|
1455 array(
|
Chris@76
|
1456 'tag' => 's',
|
Chris@76
|
1457 'before' => '<del>',
|
Chris@76
|
1458 'after' => '</del>',
|
Chris@76
|
1459 ),
|
Chris@76
|
1460 array(
|
Chris@76
|
1461 'tag' => 'shadow',
|
Chris@76
|
1462 'type' => 'unparsed_commas',
|
Chris@76
|
1463 'test' => '[#0-9a-zA-Z\-]{3,12},(left|right|top|bottom|[0123]\d{0,2})\]',
|
Chris@76
|
1464 'before' => $context['browser']['is_ie'] ? '<span style="display: inline-block; filter: Shadow(color=$1, direction=$2); height: 1.2em;">' : '<span style="text-shadow: $1 $2">',
|
Chris@76
|
1465 'after' => '</span>',
|
Chris@76
|
1466 'validate' => $context['browser']['is_ie'] ? create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1467 if ($data[1] == \'left\')
|
Chris@76
|
1468 $data[1] = 270;
|
Chris@76
|
1469 elseif ($data[1] == \'right\')
|
Chris@76
|
1470 $data[1] = 90;
|
Chris@76
|
1471 elseif ($data[1] == \'top\')
|
Chris@76
|
1472 $data[1] = 0;
|
Chris@76
|
1473 elseif ($data[1] == \'bottom\')
|
Chris@76
|
1474 $data[1] = 180;
|
Chris@76
|
1475 else
|
Chris@76
|
1476 $data[1] = (int) $data[1];') : create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1477 if ($data[1] == \'top\' || (is_numeric($data[1]) && $data[1] < 50))
|
Chris@76
|
1478 $data[1] = \'0 -2px 1px\';
|
Chris@76
|
1479 elseif ($data[1] == \'right\' || (is_numeric($data[1]) && $data[1] < 100))
|
Chris@76
|
1480 $data[1] = \'2px 0 1px\';
|
Chris@76
|
1481 elseif ($data[1] == \'bottom\' || (is_numeric($data[1]) && $data[1] < 190))
|
Chris@76
|
1482 $data[1] = \'0 2px 1px\';
|
Chris@76
|
1483 elseif ($data[1] == \'left\' || (is_numeric($data[1]) && $data[1] < 280))
|
Chris@76
|
1484 $data[1] = \'-2px 0 1px\';
|
Chris@76
|
1485 else
|
Chris@76
|
1486 $data[1] = \'1px 1px 1px\';'),
|
Chris@76
|
1487 ),
|
Chris@76
|
1488 array(
|
Chris@76
|
1489 'tag' => 'size',
|
Chris@76
|
1490 'type' => 'unparsed_equals',
|
Chris@76
|
1491 'test' => '([1-9][\d]?p[xt]|small(?:er)?|large[r]?|x[x]?-(?:small|large)|medium|(0\.[1-9]|[1-9](\.[\d][\d]?)?)?em)\]',
|
Chris@76
|
1492 'before' => '<span style="font-size: $1;" class="bbc_size">',
|
Chris@76
|
1493 'after' => '</span>',
|
Chris@76
|
1494 ),
|
Chris@76
|
1495 array(
|
Chris@76
|
1496 'tag' => 'size',
|
Chris@76
|
1497 'type' => 'unparsed_equals',
|
Chris@76
|
1498 'test' => '[1-7]\]',
|
Chris@76
|
1499 'before' => '<span style="font-size: $1;" class="bbc_size">',
|
Chris@76
|
1500 'after' => '</span>',
|
Chris@76
|
1501 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1502 $sizes = array(1 => 0.7, 2 => 1.0, 3 => 1.35, 4 => 1.45, 5 => 2.0, 6 => 2.65, 7 => 3.95);
|
Chris@76
|
1503 $data = $sizes[$data] . \'em\';'
|
Chris@76
|
1504 ),
|
Chris@76
|
1505 ),
|
Chris@76
|
1506 array(
|
Chris@76
|
1507 'tag' => 'sub',
|
Chris@76
|
1508 'before' => '<sub>',
|
Chris@76
|
1509 'after' => '</sub>',
|
Chris@76
|
1510 ),
|
Chris@76
|
1511 array(
|
Chris@76
|
1512 'tag' => 'sup',
|
Chris@76
|
1513 'before' => '<sup>',
|
Chris@76
|
1514 'after' => '</sup>',
|
Chris@76
|
1515 ),
|
Chris@76
|
1516 array(
|
Chris@76
|
1517 'tag' => 'table',
|
Chris@76
|
1518 'before' => '<table class="bbc_table">',
|
Chris@76
|
1519 'after' => '</table>',
|
Chris@76
|
1520 'trim' => 'inside',
|
Chris@76
|
1521 'require_children' => array('tr'),
|
Chris@76
|
1522 'block_level' => true,
|
Chris@76
|
1523 ),
|
Chris@76
|
1524 array(
|
Chris@76
|
1525 'tag' => 'td',
|
Chris@76
|
1526 'before' => '<td>',
|
Chris@76
|
1527 'after' => '</td>',
|
Chris@76
|
1528 'require_parents' => array('tr'),
|
Chris@76
|
1529 'trim' => 'outside',
|
Chris@76
|
1530 'block_level' => true,
|
Chris@76
|
1531 'disabled_before' => '',
|
Chris@76
|
1532 'disabled_after' => '',
|
Chris@76
|
1533 ),
|
Chris@76
|
1534 array(
|
Chris@76
|
1535 'tag' => 'time',
|
Chris@76
|
1536 'type' => 'unparsed_content',
|
Chris@76
|
1537 'content' => '$1',
|
Chris@76
|
1538 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1539 if (is_numeric($data))
|
Chris@76
|
1540 $data = timeformat($data);
|
Chris@76
|
1541 else
|
Chris@76
|
1542 $tag[\'content\'] = \'[time]$1[/time]\';'),
|
Chris@76
|
1543 ),
|
Chris@76
|
1544 array(
|
Chris@76
|
1545 'tag' => 'tr',
|
Chris@76
|
1546 'before' => '<tr>',
|
Chris@76
|
1547 'after' => '</tr>',
|
Chris@76
|
1548 'require_parents' => array('table'),
|
Chris@76
|
1549 'require_children' => array('td'),
|
Chris@76
|
1550 'trim' => 'both',
|
Chris@76
|
1551 'block_level' => true,
|
Chris@76
|
1552 'disabled_before' => '',
|
Chris@76
|
1553 'disabled_after' => '',
|
Chris@76
|
1554 ),
|
Chris@76
|
1555 array(
|
Chris@76
|
1556 'tag' => 'tt',
|
Chris@76
|
1557 'before' => '<tt class="bbc_tt">',
|
Chris@76
|
1558 'after' => '</tt>',
|
Chris@76
|
1559 ),
|
Chris@76
|
1560 array(
|
Chris@76
|
1561 'tag' => 'u',
|
Chris@76
|
1562 'before' => '<span class="bbc_u">',
|
Chris@76
|
1563 'after' => '</span>',
|
Chris@76
|
1564 ),
|
Chris@76
|
1565 array(
|
Chris@76
|
1566 'tag' => 'url',
|
Chris@76
|
1567 'type' => 'unparsed_content',
|
Chris@76
|
1568 'content' => '<a href="$1" class="bbc_link" target="_blank">$1</a>',
|
Chris@76
|
1569 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1570 $data = strtr($data, array(\'<br />\' => \'\'));
|
Chris@76
|
1571 if (strpos($data, \'http://\') !== 0 && strpos($data, \'https://\') !== 0)
|
Chris@76
|
1572 $data = \'http://\' . $data;
|
Chris@76
|
1573 '),
|
Chris@76
|
1574 ),
|
Chris@76
|
1575 array(
|
Chris@76
|
1576 'tag' => 'url',
|
Chris@76
|
1577 'type' => 'unparsed_equals',
|
Chris@76
|
1578 'before' => '<a href="$1" class="bbc_link" target="_blank">',
|
Chris@76
|
1579 'after' => '</a>',
|
Chris@76
|
1580 'validate' => create_function('&$tag, &$data, $disabled', '
|
Chris@76
|
1581 if (strpos($data, \'http://\') !== 0 && strpos($data, \'https://\') !== 0)
|
Chris@76
|
1582 $data = \'http://\' . $data;
|
Chris@76
|
1583 '),
|
Chris@76
|
1584 'disallow_children' => array('email', 'ftp', 'url', 'iurl'),
|
Chris@76
|
1585 'disabled_after' => ' ($1)',
|
Chris@76
|
1586 ),
|
Chris@76
|
1587 array(
|
Chris@76
|
1588 'tag' => 'white',
|
Chris@76
|
1589 'before' => '<span style="color: white;" class="bbc_color">',
|
Chris@76
|
1590 'after' => '</span>',
|
Chris@76
|
1591 ),
|
Chris@76
|
1592 );
|
Chris@76
|
1593
|
Chris@76
|
1594 // Let mods add new BBC without hassle.
|
Chris@76
|
1595 call_integration_hook('integrate_bbc_codes', array(&$codes));
|
Chris@76
|
1596
|
Chris@76
|
1597 // This is mainly for the bbc manager, so it's easy to add tags above. Custom BBC should be added above this line.
|
Chris@76
|
1598 if ($message === false)
|
Chris@76
|
1599 {
|
Chris@76
|
1600 if (isset($temp_bbc))
|
Chris@76
|
1601 $bbc_codes = $temp_bbc;
|
Chris@76
|
1602 return $codes;
|
Chris@76
|
1603 }
|
Chris@76
|
1604
|
Chris@76
|
1605 // So the parser won't skip them.
|
Chris@76
|
1606 $itemcodes = array(
|
Chris@76
|
1607 '*' => 'disc',
|
Chris@76
|
1608 '@' => 'disc',
|
Chris@76
|
1609 '+' => 'square',
|
Chris@76
|
1610 'x' => 'square',
|
Chris@76
|
1611 '#' => 'square',
|
Chris@76
|
1612 'o' => 'circle',
|
Chris@76
|
1613 'O' => 'circle',
|
Chris@76
|
1614 '0' => 'circle',
|
Chris@76
|
1615 );
|
Chris@76
|
1616 if (!isset($disabled['li']) && !isset($disabled['list']))
|
Chris@76
|
1617 {
|
Chris@76
|
1618 foreach ($itemcodes as $c => $dummy)
|
Chris@76
|
1619 $bbc_codes[$c] = array();
|
Chris@76
|
1620 }
|
Chris@76
|
1621
|
Chris@76
|
1622 // Inside these tags autolink is not recommendable.
|
Chris@76
|
1623 $no_autolink_tags = array(
|
Chris@76
|
1624 'url',
|
Chris@76
|
1625 'iurl',
|
Chris@76
|
1626 'ftp',
|
Chris@76
|
1627 'email',
|
Chris@76
|
1628 );
|
Chris@76
|
1629
|
Chris@76
|
1630 // Shhhh!
|
Chris@76
|
1631 if (!isset($disabled['color']))
|
Chris@76
|
1632 {
|
Chris@76
|
1633 $codes[] = array(
|
Chris@76
|
1634 'tag' => 'chrissy',
|
Chris@76
|
1635 'before' => '<span style="color: #cc0099;">',
|
Chris@76
|
1636 'after' => ' :-*</span>',
|
Chris@76
|
1637 );
|
Chris@76
|
1638 $codes[] = array(
|
Chris@76
|
1639 'tag' => 'kissy',
|
Chris@76
|
1640 'before' => '<span style="color: #cc0099;">',
|
Chris@76
|
1641 'after' => ' :-*</span>',
|
Chris@76
|
1642 );
|
Chris@76
|
1643 }
|
Chris@76
|
1644
|
Chris@76
|
1645 foreach ($codes as $code)
|
Chris@76
|
1646 {
|
Chris@76
|
1647 // If we are not doing every tag only do ones we are interested in.
|
Chris@76
|
1648 if (empty($parse_tags) || in_array($code['tag'], $parse_tags))
|
Chris@76
|
1649 $bbc_codes[substr($code['tag'], 0, 1)][] = $code;
|
Chris@76
|
1650 }
|
Chris@76
|
1651 $codes = null;
|
Chris@76
|
1652 }
|
Chris@76
|
1653
|
Chris@76
|
1654 // Shall we take the time to cache this?
|
Chris@76
|
1655 if ($cache_id != '' && !empty($modSettings['cache_enable']) && (($modSettings['cache_enable'] >= 2 && strlen($message) > 1000) || strlen($message) > 2400) && empty($parse_tags))
|
Chris@76
|
1656 {
|
Chris@76
|
1657 // It's likely this will change if the message is modified.
|
Chris@76
|
1658 $cache_key = 'parse:' . $cache_id . '-' . md5(md5($message) . '-' . $smileys . (empty($disabled) ? '' : implode(',', array_keys($disabled))) . serialize($context['browser']) . $txt['lang_locale'] . $user_info['time_offset'] . $user_info['time_format']);
|
Chris@76
|
1659
|
Chris@76
|
1660 if (($temp = cache_get_data($cache_key, 240)) != null)
|
Chris@76
|
1661 return $temp;
|
Chris@76
|
1662
|
Chris@76
|
1663 $cache_t = microtime();
|
Chris@76
|
1664 }
|
Chris@76
|
1665
|
Chris@76
|
1666 if ($smileys === 'print')
|
Chris@76
|
1667 {
|
Chris@76
|
1668 // [glow], [shadow], and [move] can't really be printed.
|
Chris@76
|
1669 $disabled['glow'] = true;
|
Chris@76
|
1670 $disabled['shadow'] = true;
|
Chris@76
|
1671 $disabled['move'] = true;
|
Chris@76
|
1672
|
Chris@76
|
1673 // Colors can't well be displayed... supposed to be black and white.
|
Chris@76
|
1674 $disabled['color'] = true;
|
Chris@76
|
1675 $disabled['black'] = true;
|
Chris@76
|
1676 $disabled['blue'] = true;
|
Chris@76
|
1677 $disabled['white'] = true;
|
Chris@76
|
1678 $disabled['red'] = true;
|
Chris@76
|
1679 $disabled['green'] = true;
|
Chris@76
|
1680 $disabled['me'] = true;
|
Chris@76
|
1681
|
Chris@76
|
1682 // Color coding doesn't make sense.
|
Chris@76
|
1683 $disabled['php'] = true;
|
Chris@76
|
1684
|
Chris@76
|
1685 // Links are useless on paper... just show the link.
|
Chris@76
|
1686 $disabled['ftp'] = true;
|
Chris@76
|
1687 $disabled['url'] = true;
|
Chris@76
|
1688 $disabled['iurl'] = true;
|
Chris@76
|
1689 $disabled['email'] = true;
|
Chris@76
|
1690 $disabled['flash'] = true;
|
Chris@76
|
1691
|
Chris@76
|
1692 // !!! Change maybe?
|
Chris@76
|
1693 if (!isset($_GET['images']))
|
Chris@76
|
1694 $disabled['img'] = true;
|
Chris@76
|
1695
|
Chris@76
|
1696 // !!! Interface/setting to add more?
|
Chris@76
|
1697 }
|
Chris@76
|
1698
|
Chris@76
|
1699 $open_tags = array();
|
Chris@76
|
1700 $message = strtr($message, array("\n" => '<br />'));
|
Chris@76
|
1701
|
Chris@76
|
1702 // The non-breaking-space looks a bit different each time.
|
Chris@76
|
1703 $non_breaking_space = $context['utf8'] ? ($context['server']['complex_preg_chars'] ? '\x{A0}' : "\xC2\xA0") : '\xA0';
|
Chris@76
|
1704
|
Chris@76
|
1705 // This saves time by doing our break long words checks here.
|
Chris@76
|
1706 if (!empty($modSettings['fixLongWords']) && $modSettings['fixLongWords'] > 5)
|
Chris@76
|
1707 {
|
Chris@76
|
1708 if ($context['browser']['is_gecko'] || $context['browser']['is_konqueror'])
|
Chris@76
|
1709 $breaker = '<span style="margin: 0 -0.5ex 0 0;"> </span>';
|
Chris@76
|
1710 // Opera...
|
Chris@76
|
1711 elseif ($context['browser']['is_opera'])
|
Chris@76
|
1712 $breaker = '<span style="margin: 0 -0.65ex 0 -1px;"> </span>';
|
Chris@76
|
1713 // Internet Explorer...
|
Chris@76
|
1714 else
|
Chris@76
|
1715 $breaker = '<span style="width: 0; margin: 0 -0.6ex 0 -1px;"> </span>';
|
Chris@76
|
1716
|
Chris@76
|
1717 // PCRE will not be happy if we don't give it a short.
|
Chris@76
|
1718 $modSettings['fixLongWords'] = (int) min(65535, $modSettings['fixLongWords']);
|
Chris@76
|
1719 }
|
Chris@76
|
1720
|
Chris@76
|
1721 $pos = -1;
|
Chris@76
|
1722 while ($pos !== false)
|
Chris@76
|
1723 {
|
Chris@76
|
1724 $last_pos = isset($last_pos) ? max($pos, $last_pos) : $pos;
|
Chris@76
|
1725 $pos = strpos($message, '[', $pos + 1);
|
Chris@76
|
1726
|
Chris@76
|
1727 // Failsafe.
|
Chris@76
|
1728 if ($pos === false || $last_pos > $pos)
|
Chris@76
|
1729 $pos = strlen($message) + 1;
|
Chris@76
|
1730
|
Chris@76
|
1731 // Can't have a one letter smiley, URL, or email! (sorry.)
|
Chris@76
|
1732 if ($last_pos < $pos - 1)
|
Chris@76
|
1733 {
|
Chris@76
|
1734 // Make sure the $last_pos is not negative.
|
Chris@76
|
1735 $last_pos = max($last_pos, 0);
|
Chris@76
|
1736
|
Chris@76
|
1737 // Pick a block of data to do some raw fixing on.
|
Chris@76
|
1738 $data = substr($message, $last_pos, $pos - $last_pos);
|
Chris@76
|
1739
|
Chris@76
|
1740 // Take care of some HTML!
|
Chris@76
|
1741 if (!empty($modSettings['enablePostHTML']) && strpos($data, '<') !== false)
|
Chris@76
|
1742 {
|
Chris@76
|
1743 $data = preg_replace('~<a\s+href=((?:")?)((?:https?://|ftps?://|mailto:)\S+?)\\1>~i', '[url=$2]', $data);
|
Chris@76
|
1744 $data = preg_replace('~</a>~i', '[/url]', $data);
|
Chris@76
|
1745
|
Chris@76
|
1746 // <br /> should be empty.
|
Chris@76
|
1747 $empty_tags = array('br', 'hr');
|
Chris@76
|
1748 foreach ($empty_tags as $tag)
|
Chris@76
|
1749 $data = str_replace(array('<' . $tag . '>', '<' . $tag . '/>', '<' . $tag . ' />'), '[' . $tag . ' /]', $data);
|
Chris@76
|
1750
|
Chris@76
|
1751 // b, u, i, s, pre... basic tags.
|
Chris@76
|
1752 $closable_tags = array('b', 'u', 'i', 's', 'em', 'ins', 'del', 'pre', 'blockquote');
|
Chris@76
|
1753 foreach ($closable_tags as $tag)
|
Chris@76
|
1754 {
|
Chris@76
|
1755 $diff = substr_count($data, '<' . $tag . '>') - substr_count($data, '</' . $tag . '>');
|
Chris@76
|
1756 $data = strtr($data, array('<' . $tag . '>' => '<' . $tag . '>', '</' . $tag . '>' => '</' . $tag . '>'));
|
Chris@76
|
1757
|
Chris@76
|
1758 if ($diff > 0)
|
Chris@76
|
1759 $data = substr($data, 0, -1) . str_repeat('</' . $tag . '>', $diff) . substr($data, -1);
|
Chris@76
|
1760 }
|
Chris@76
|
1761
|
Chris@76
|
1762 // Do <img ... /> - with security... action= -> action-.
|
Chris@76
|
1763 preg_match_all('~<img\s+src=((?:")?)((?:https?://|ftps?://)\S+?)\\1(?:\s+alt=(".*?"|\S*?))?(?:\s?/)?>~i', $data, $matches, PREG_PATTERN_ORDER);
|
Chris@76
|
1764 if (!empty($matches[0]))
|
Chris@76
|
1765 {
|
Chris@76
|
1766 $replaces = array();
|
Chris@76
|
1767 foreach ($matches[2] as $match => $imgtag)
|
Chris@76
|
1768 {
|
Chris@76
|
1769 $alt = empty($matches[3][$match]) ? '' : ' alt=' . preg_replace('~^"|"$~', '', $matches[3][$match]);
|
Chris@76
|
1770
|
Chris@76
|
1771 // Remove action= from the URL - no funny business, now.
|
Chris@76
|
1772 if (preg_match('~action(=|%3d)(?!dlattach)~i', $imgtag) != 0)
|
Chris@76
|
1773 $imgtag = preg_replace('~action(?:=|%3d)(?!dlattach)~i', 'action-', $imgtag);
|
Chris@76
|
1774
|
Chris@76
|
1775 // Check if the image is larger than allowed.
|
Chris@76
|
1776 if (!empty($modSettings['max_image_width']) && !empty($modSettings['max_image_height']))
|
Chris@76
|
1777 {
|
Chris@76
|
1778 list ($width, $height) = url_image_size($imgtag);
|
Chris@76
|
1779
|
Chris@76
|
1780 if (!empty($modSettings['max_image_width']) && $width > $modSettings['max_image_width'])
|
Chris@76
|
1781 {
|
Chris@76
|
1782 $height = (int) (($modSettings['max_image_width'] * $height) / $width);
|
Chris@76
|
1783 $width = $modSettings['max_image_width'];
|
Chris@76
|
1784 }
|
Chris@76
|
1785
|
Chris@76
|
1786 if (!empty($modSettings['max_image_height']) && $height > $modSettings['max_image_height'])
|
Chris@76
|
1787 {
|
Chris@76
|
1788 $width = (int) (($modSettings['max_image_height'] * $width) / $height);
|
Chris@76
|
1789 $height = $modSettings['max_image_height'];
|
Chris@76
|
1790 }
|
Chris@76
|
1791
|
Chris@76
|
1792 // Set the new image tag.
|
Chris@76
|
1793 $replaces[$matches[0][$match]] = '[img width=' . $width . ' height=' . $height . $alt . ']' . $imgtag . '[/img]';
|
Chris@76
|
1794 }
|
Chris@76
|
1795 else
|
Chris@76
|
1796 $replaces[$matches[0][$match]] = '[img' . $alt . ']' . $imgtag . '[/img]';
|
Chris@76
|
1797 }
|
Chris@76
|
1798
|
Chris@76
|
1799 $data = strtr($data, $replaces);
|
Chris@76
|
1800 }
|
Chris@76
|
1801 }
|
Chris@76
|
1802
|
Chris@76
|
1803 if (!empty($modSettings['autoLinkUrls']))
|
Chris@76
|
1804 {
|
Chris@76
|
1805 // Are we inside tags that should be auto linked?
|
Chris@76
|
1806 $no_autolink_area = false;
|
Chris@76
|
1807 if (!empty($open_tags))
|
Chris@76
|
1808 {
|
Chris@76
|
1809 foreach ($open_tags as $open_tag)
|
Chris@76
|
1810 if (in_array($open_tag['tag'], $no_autolink_tags))
|
Chris@76
|
1811 $no_autolink_area = true;
|
Chris@76
|
1812 }
|
Chris@76
|
1813
|
Chris@76
|
1814 // Don't go backwards.
|
Chris@76
|
1815 //!!! Don't think is the real solution....
|
Chris@76
|
1816 $lastAutoPos = isset($lastAutoPos) ? $lastAutoPos : 0;
|
Chris@76
|
1817 if ($pos < $lastAutoPos)
|
Chris@76
|
1818 $no_autolink_area = true;
|
Chris@76
|
1819 $lastAutoPos = $pos;
|
Chris@76
|
1820
|
Chris@76
|
1821 if (!$no_autolink_area)
|
Chris@76
|
1822 {
|
Chris@76
|
1823 // Parse any URLs.... have to get rid of the @ problems some things cause... stupid email addresses.
|
Chris@76
|
1824 if (!isset($disabled['url']) && (strpos($data, '://') !== false || strpos($data, 'www.') !== false) && strpos($data, '[url') === false)
|
Chris@76
|
1825 {
|
Chris@76
|
1826 // Switch out quotes really quick because they can cause problems.
|
Chris@76
|
1827 $data = strtr($data, array(''' => '\'', ' ' => $context['utf8'] ? "\xC2\xA0" : "\xA0", '"' => '>">', '"' => '<"<', '<' => '<lt<'));
|
Chris@76
|
1828
|
Chris@76
|
1829 // Only do this if the preg survives.
|
Chris@76
|
1830 if (is_string($result = preg_replace(array(
|
Chris@76
|
1831 '~(?<=[\s>\.(;\'"]|^)((?:http|https)://[\w\-_%@:|]+(?:\.[\w\-_%]+)*(?::\d+)?(?:/[\w\-_\~%\.@!,\?&;=#(){}+:\'\\\\]*)*[/\w\-_\~%@\?;=#}\\\\])~i',
|
Chris@76
|
1832 '~(?<=[\s>\.(;\'"]|^)((?:ftp|ftps)://[\w\-_%@:|]+(?:\.[\w\-_%]+)*(?::\d+)?(?:/[\w\-_\~%\.@,\?&;=#(){}+:\'\\\\]*)*[/\w\-_\~%@\?;=#}\\\\])~i',
|
Chris@76
|
1833 '~(?<=[\s>(\'<]|^)(www(?:\.[\w\-_]+)+(?::\d+)?(?:/[\w\-_\~%\.@!,\?&;=#(){}+:\'\\\\]*)*[/\w\-_\~%@\?;=#}\\\\])~i'
|
Chris@76
|
1834 ), array(
|
Chris@76
|
1835 '[url]$1[/url]',
|
Chris@76
|
1836 '[ftp]$1[/ftp]',
|
Chris@76
|
1837 '[url=http://$1]$1[/url]'
|
Chris@76
|
1838 ), $data)))
|
Chris@76
|
1839 $data = $result;
|
Chris@76
|
1840
|
Chris@76
|
1841 $data = strtr($data, array('\'' => ''', $context['utf8'] ? "\xC2\xA0" : "\xA0" => ' ', '>">' => '"', '<"<' => '"', '<lt<' => '<'));
|
Chris@76
|
1842 }
|
Chris@76
|
1843
|
Chris@76
|
1844 // Next, emails...
|
Chris@76
|
1845 if (!isset($disabled['email']) && strpos($data, '@') !== false && strpos($data, '[email') === false)
|
Chris@76
|
1846 {
|
Chris@76
|
1847 $data = preg_replace('~(?<=[\?\s' . $non_breaking_space . '\[\]()*\\\;>]|^)([\w\-\.]{1,80}@[\w\-]+\.[\w\-\.]+[\w\-])(?=[?,\s' . $non_breaking_space . '\[\]()*\\\]|$|<br />| |>|<|"|'|\.(?:\.|;| |\s|$|<br />))~' . ($context['utf8'] ? 'u' : ''), '[email]$1[/email]', $data);
|
Chris@76
|
1848 $data = preg_replace('~(?<=<br />)([\w\-\.]{1,80}@[\w\-]+\.[\w\-\.]+[\w\-])(?=[?\.,;\s' . $non_breaking_space . '\[\]()*\\\]|$|<br />| |>|<|"|')~' . ($context['utf8'] ? 'u' : ''), '[email]$1[/email]', $data);
|
Chris@76
|
1849 }
|
Chris@76
|
1850 }
|
Chris@76
|
1851 }
|
Chris@76
|
1852
|
Chris@76
|
1853 $data = strtr($data, array("\t" => ' '));
|
Chris@76
|
1854
|
Chris@76
|
1855 if (!empty($modSettings['fixLongWords']) && $modSettings['fixLongWords'] > 5)
|
Chris@76
|
1856 {
|
Chris@76
|
1857 // The idea is, find words xx long, and then replace them with xx + space + more.
|
Chris@76
|
1858 if ($smcFunc['strlen']($data) > $modSettings['fixLongWords'])
|
Chris@76
|
1859 {
|
Chris@76
|
1860 // This is done in a roundabout way because $breaker has "long words" :P.
|
Chris@76
|
1861 $data = strtr($data, array($breaker => '< >', ' ' => $context['utf8'] ? "\xC2\xA0" : "\xA0"));
|
Chris@76
|
1862 $data = preg_replace(
|
Chris@76
|
1863 '~(?<=[>;:!? ' . $non_breaking_space . '\]()]|^)([\w' . ($context['utf8'] ? '\pL' : '') . '\.]{' . $modSettings['fixLongWords'] . ',})~e' . ($context['utf8'] ? 'u' : ''),
|
Chris@76
|
1864 'preg_replace(\'/(.{' . ($modSettings['fixLongWords'] - 1) . '})/' . ($context['utf8'] ? 'u' : '') . '\', \'\\$1< >\', \'$1\')',
|
Chris@76
|
1865 $data);
|
Chris@76
|
1866 $data = strtr($data, array('< >' => $breaker, $context['utf8'] ? "\xC2\xA0" : "\xA0" => ' '));
|
Chris@76
|
1867 }
|
Chris@76
|
1868 }
|
Chris@76
|
1869
|
Chris@76
|
1870 // If it wasn't changed, no copying or other boring stuff has to happen!
|
Chris@76
|
1871 if ($data != substr($message, $last_pos, $pos - $last_pos))
|
Chris@76
|
1872 {
|
Chris@76
|
1873 $message = substr($message, 0, $last_pos) . $data . substr($message, $pos);
|
Chris@76
|
1874
|
Chris@76
|
1875 // Since we changed it, look again in case we added or removed a tag. But we don't want to skip any.
|
Chris@76
|
1876 $old_pos = strlen($data) + $last_pos;
|
Chris@76
|
1877 $pos = strpos($message, '[', $last_pos);
|
Chris@76
|
1878 $pos = $pos === false ? $old_pos : min($pos, $old_pos);
|
Chris@76
|
1879 }
|
Chris@76
|
1880 }
|
Chris@76
|
1881
|
Chris@76
|
1882 // Are we there yet? Are we there yet?
|
Chris@76
|
1883 if ($pos >= strlen($message) - 1)
|
Chris@76
|
1884 break;
|
Chris@76
|
1885
|
Chris@76
|
1886 $tags = strtolower(substr($message, $pos + 1, 1));
|
Chris@76
|
1887
|
Chris@76
|
1888 if ($tags == '/' && !empty($open_tags))
|
Chris@76
|
1889 {
|
Chris@76
|
1890 $pos2 = strpos($message, ']', $pos + 1);
|
Chris@76
|
1891 if ($pos2 == $pos + 2)
|
Chris@76
|
1892 continue;
|
Chris@76
|
1893 $look_for = strtolower(substr($message, $pos + 2, $pos2 - $pos - 2));
|
Chris@76
|
1894
|
Chris@76
|
1895 $to_close = array();
|
Chris@76
|
1896 $block_level = null;
|
Chris@76
|
1897 do
|
Chris@76
|
1898 {
|
Chris@76
|
1899 $tag = array_pop($open_tags);
|
Chris@76
|
1900 if (!$tag)
|
Chris@76
|
1901 break;
|
Chris@76
|
1902
|
Chris@76
|
1903 if (!empty($tag['block_level']))
|
Chris@76
|
1904 {
|
Chris@76
|
1905 // Only find out if we need to.
|
Chris@76
|
1906 if ($block_level === false)
|
Chris@76
|
1907 {
|
Chris@76
|
1908 array_push($open_tags, $tag);
|
Chris@76
|
1909 break;
|
Chris@76
|
1910 }
|
Chris@76
|
1911
|
Chris@76
|
1912 // The idea is, if we are LOOKING for a block level tag, we can close them on the way.
|
Chris@76
|
1913 if (strlen($look_for) > 0 && isset($bbc_codes[$look_for[0]]))
|
Chris@76
|
1914 {
|
Chris@76
|
1915 foreach ($bbc_codes[$look_for[0]] as $temp)
|
Chris@76
|
1916 if ($temp['tag'] == $look_for)
|
Chris@76
|
1917 {
|
Chris@76
|
1918 $block_level = !empty($temp['block_level']);
|
Chris@76
|
1919 break;
|
Chris@76
|
1920 }
|
Chris@76
|
1921 }
|
Chris@76
|
1922
|
Chris@76
|
1923 if ($block_level !== true)
|
Chris@76
|
1924 {
|
Chris@76
|
1925 $block_level = false;
|
Chris@76
|
1926 array_push($open_tags, $tag);
|
Chris@76
|
1927 break;
|
Chris@76
|
1928 }
|
Chris@76
|
1929 }
|
Chris@76
|
1930
|
Chris@76
|
1931 $to_close[] = $tag;
|
Chris@76
|
1932 }
|
Chris@76
|
1933 while ($tag['tag'] != $look_for);
|
Chris@76
|
1934
|
Chris@76
|
1935 // Did we just eat through everything and not find it?
|
Chris@76
|
1936 if ((empty($open_tags) && (empty($tag) || $tag['tag'] != $look_for)))
|
Chris@76
|
1937 {
|
Chris@76
|
1938 $open_tags = $to_close;
|
Chris@76
|
1939 continue;
|
Chris@76
|
1940 }
|
Chris@76
|
1941 elseif (!empty($to_close) && $tag['tag'] != $look_for)
|
Chris@76
|
1942 {
|
Chris@76
|
1943 if ($block_level === null && isset($look_for[0], $bbc_codes[$look_for[0]]))
|
Chris@76
|
1944 {
|
Chris@76
|
1945 foreach ($bbc_codes[$look_for[0]] as $temp)
|
Chris@76
|
1946 if ($temp['tag'] == $look_for)
|
Chris@76
|
1947 {
|
Chris@76
|
1948 $block_level = !empty($temp['block_level']);
|
Chris@76
|
1949 break;
|
Chris@76
|
1950 }
|
Chris@76
|
1951 }
|
Chris@76
|
1952
|
Chris@76
|
1953 // We're not looking for a block level tag (or maybe even a tag that exists...)
|
Chris@76
|
1954 if (!$block_level)
|
Chris@76
|
1955 {
|
Chris@76
|
1956 foreach ($to_close as $tag)
|
Chris@76
|
1957 array_push($open_tags, $tag);
|
Chris@76
|
1958 continue;
|
Chris@76
|
1959 }
|
Chris@76
|
1960 }
|
Chris@76
|
1961
|
Chris@76
|
1962 foreach ($to_close as $tag)
|
Chris@76
|
1963 {
|
Chris@76
|
1964 $message = substr($message, 0, $pos) . "\n" . $tag['after'] . "\n" . substr($message, $pos2 + 1);
|
Chris@76
|
1965 $pos += strlen($tag['after']) + 2;
|
Chris@76
|
1966 $pos2 = $pos - 1;
|
Chris@76
|
1967
|
Chris@76
|
1968 // See the comment at the end of the big loop - just eating whitespace ;).
|
Chris@76
|
1969 if (!empty($tag['block_level']) && substr($message, $pos, 6) == '<br />')
|
Chris@76
|
1970 $message = substr($message, 0, $pos) . substr($message, $pos + 6);
|
Chris@76
|
1971 if (!empty($tag['trim']) && $tag['trim'] != 'inside' && preg_match('~(<br />| |\s)*~', substr($message, $pos), $matches) != 0)
|
Chris@76
|
1972 $message = substr($message, 0, $pos) . substr($message, $pos + strlen($matches[0]));
|
Chris@76
|
1973 }
|
Chris@76
|
1974
|
Chris@76
|
1975 if (!empty($to_close))
|
Chris@76
|
1976 {
|
Chris@76
|
1977 $to_close = array();
|
Chris@76
|
1978 $pos--;
|
Chris@76
|
1979 }
|
Chris@76
|
1980
|
Chris@76
|
1981 continue;
|
Chris@76
|
1982 }
|
Chris@76
|
1983
|
Chris@76
|
1984 // No tags for this character, so just keep going (fastest possible course.)
|
Chris@76
|
1985 if (!isset($bbc_codes[$tags]))
|
Chris@76
|
1986 continue;
|
Chris@76
|
1987
|
Chris@76
|
1988 $inside = empty($open_tags) ? null : $open_tags[count($open_tags) - 1];
|
Chris@76
|
1989 $tag = null;
|
Chris@76
|
1990 foreach ($bbc_codes[$tags] as $possible)
|
Chris@76
|
1991 {
|
Chris@76
|
1992 // Not a match?
|
Chris@76
|
1993 if (strtolower(substr($message, $pos + 1, strlen($possible['tag']))) != $possible['tag'])
|
Chris@76
|
1994 continue;
|
Chris@76
|
1995
|
Chris@76
|
1996 $next_c = substr($message, $pos + 1 + strlen($possible['tag']), 1);
|
Chris@76
|
1997
|
Chris@76
|
1998 // A test validation?
|
Chris@76
|
1999 if (isset($possible['test']) && preg_match('~^' . $possible['test'] . '~', substr($message, $pos + 1 + strlen($possible['tag']) + 1)) == 0)
|
Chris@76
|
2000 continue;
|
Chris@76
|
2001 // Do we want parameters?
|
Chris@76
|
2002 elseif (!empty($possible['parameters']))
|
Chris@76
|
2003 {
|
Chris@76
|
2004 if ($next_c != ' ')
|
Chris@76
|
2005 continue;
|
Chris@76
|
2006 }
|
Chris@76
|
2007 elseif (isset($possible['type']))
|
Chris@76
|
2008 {
|
Chris@76
|
2009 // Do we need an equal sign?
|
Chris@76
|
2010 if (in_array($possible['type'], array('unparsed_equals', 'unparsed_commas', 'unparsed_commas_content', 'unparsed_equals_content', 'parsed_equals')) && $next_c != '=')
|
Chris@76
|
2011 continue;
|
Chris@76
|
2012 // Maybe we just want a /...
|
Chris@76
|
2013 if ($possible['type'] == 'closed' && $next_c != ']' && substr($message, $pos + 1 + strlen($possible['tag']), 2) != '/]' && substr($message, $pos + 1 + strlen($possible['tag']), 3) != ' /]')
|
Chris@76
|
2014 continue;
|
Chris@76
|
2015 // An immediate ]?
|
Chris@76
|
2016 if ($possible['type'] == 'unparsed_content' && $next_c != ']')
|
Chris@76
|
2017 continue;
|
Chris@76
|
2018 }
|
Chris@76
|
2019 // No type means 'parsed_content', which demands an immediate ] without parameters!
|
Chris@76
|
2020 elseif ($next_c != ']')
|
Chris@76
|
2021 continue;
|
Chris@76
|
2022
|
Chris@76
|
2023 // Check allowed tree?
|
Chris@76
|
2024 if (isset($possible['require_parents']) && ($inside === null || !in_array($inside['tag'], $possible['require_parents'])))
|
Chris@76
|
2025 continue;
|
Chris@76
|
2026 elseif (isset($inside['require_children']) && !in_array($possible['tag'], $inside['require_children']))
|
Chris@76
|
2027 continue;
|
Chris@76
|
2028 // If this is in the list of disallowed child tags, don't parse it.
|
Chris@76
|
2029 elseif (isset($inside['disallow_children']) && in_array($possible['tag'], $inside['disallow_children']))
|
Chris@76
|
2030 continue;
|
Chris@76
|
2031
|
Chris@76
|
2032 $pos1 = $pos + 1 + strlen($possible['tag']) + 1;
|
Chris@76
|
2033
|
Chris@76
|
2034 // Quotes can have alternate styling, we do this php-side due to all the permutations of quotes.
|
Chris@76
|
2035 if ($possible['tag'] == 'quote')
|
Chris@76
|
2036 {
|
Chris@76
|
2037 // Start with standard
|
Chris@76
|
2038 $quote_alt = false;
|
Chris@76
|
2039 foreach ($open_tags as $open_quote)
|
Chris@76
|
2040 {
|
Chris@76
|
2041 // Every parent quote this quote has flips the styling
|
Chris@76
|
2042 if ($open_quote['tag'] == 'quote')
|
Chris@76
|
2043 $quote_alt = !$quote_alt;
|
Chris@76
|
2044 }
|
Chris@76
|
2045 // Add a class to the quote to style alternating blockquotes
|
Chris@76
|
2046 $possible['before'] = strtr($possible['before'], array('<blockquote>' => '<blockquote class="bbc_' . ($quote_alt ? 'alternate' : 'standard') . '_quote">'));
|
Chris@76
|
2047 }
|
Chris@76
|
2048
|
Chris@76
|
2049 // This is long, but it makes things much easier and cleaner.
|
Chris@76
|
2050 if (!empty($possible['parameters']))
|
Chris@76
|
2051 {
|
Chris@76
|
2052 $preg = array();
|
Chris@76
|
2053 foreach ($possible['parameters'] as $p => $info)
|
Chris@76
|
2054 $preg[] = '(\s+' . $p . '=' . (empty($info['quoted']) ? '' : '"') . (isset($info['match']) ? $info['match'] : '(.+?)') . (empty($info['quoted']) ? '' : '"') . ')' . (empty($info['optional']) ? '' : '?');
|
Chris@76
|
2055
|
Chris@76
|
2056 // Okay, this may look ugly and it is, but it's not going to happen much and it is the best way of allowing any order of parameters but still parsing them right.
|
Chris@76
|
2057 $match = false;
|
Chris@76
|
2058 $orders = permute($preg);
|
Chris@76
|
2059 foreach ($orders as $p)
|
Chris@76
|
2060 if (preg_match('~^' . implode('', $p) . '\]~i', substr($message, $pos1 - 1), $matches) != 0)
|
Chris@76
|
2061 {
|
Chris@76
|
2062 $match = true;
|
Chris@76
|
2063 break;
|
Chris@76
|
2064 }
|
Chris@76
|
2065
|
Chris@76
|
2066 // Didn't match our parameter list, try the next possible.
|
Chris@76
|
2067 if (!$match)
|
Chris@76
|
2068 continue;
|
Chris@76
|
2069
|
Chris@76
|
2070 $params = array();
|
Chris@76
|
2071 for ($i = 1, $n = count($matches); $i < $n; $i += 2)
|
Chris@76
|
2072 {
|
Chris@76
|
2073 $key = strtok(ltrim($matches[$i]), '=');
|
Chris@76
|
2074 if (isset($possible['parameters'][$key]['value']))
|
Chris@76
|
2075 $params['{' . $key . '}'] = strtr($possible['parameters'][$key]['value'], array('$1' => $matches[$i + 1]));
|
Chris@76
|
2076 elseif (isset($possible['parameters'][$key]['validate']))
|
Chris@76
|
2077 $params['{' . $key . '}'] = $possible['parameters'][$key]['validate']($matches[$i + 1]);
|
Chris@76
|
2078 else
|
Chris@76
|
2079 $params['{' . $key . '}'] = $matches[$i + 1];
|
Chris@76
|
2080
|
Chris@76
|
2081 // Just to make sure: replace any $ or { so they can't interpolate wrongly.
|
Chris@76
|
2082 $params['{' . $key . '}'] = strtr($params['{' . $key . '}'], array('$' => '$', '{' => '{'));
|
Chris@76
|
2083 }
|
Chris@76
|
2084
|
Chris@76
|
2085 foreach ($possible['parameters'] as $p => $info)
|
Chris@76
|
2086 {
|
Chris@76
|
2087 if (!isset($params['{' . $p . '}']))
|
Chris@76
|
2088 $params['{' . $p . '}'] = '';
|
Chris@76
|
2089 }
|
Chris@76
|
2090
|
Chris@76
|
2091 $tag = $possible;
|
Chris@76
|
2092
|
Chris@76
|
2093 // Put the parameters into the string.
|
Chris@76
|
2094 if (isset($tag['before']))
|
Chris@76
|
2095 $tag['before'] = strtr($tag['before'], $params);
|
Chris@76
|
2096 if (isset($tag['after']))
|
Chris@76
|
2097 $tag['after'] = strtr($tag['after'], $params);
|
Chris@76
|
2098 if (isset($tag['content']))
|
Chris@76
|
2099 $tag['content'] = strtr($tag['content'], $params);
|
Chris@76
|
2100
|
Chris@76
|
2101 $pos1 += strlen($matches[0]) - 1;
|
Chris@76
|
2102 }
|
Chris@76
|
2103 else
|
Chris@76
|
2104 $tag = $possible;
|
Chris@76
|
2105 break;
|
Chris@76
|
2106 }
|
Chris@76
|
2107
|
Chris@76
|
2108 // Item codes are complicated buggers... they are implicit [li]s and can make [list]s!
|
Chris@76
|
2109 if ($smileys !== false && $tag === null && isset($itemcodes[substr($message, $pos + 1, 1)]) && substr($message, $pos + 2, 1) == ']' && !isset($disabled['list']) && !isset($disabled['li']))
|
Chris@76
|
2110 {
|
Chris@76
|
2111 if (substr($message, $pos + 1, 1) == '0' && !in_array(substr($message, $pos - 1, 1), array(';', ' ', "\t", '>')))
|
Chris@76
|
2112 continue;
|
Chris@76
|
2113 $tag = $itemcodes[substr($message, $pos + 1, 1)];
|
Chris@76
|
2114
|
Chris@76
|
2115 // First let's set up the tree: it needs to be in a list, or after an li.
|
Chris@76
|
2116 if ($inside === null || ($inside['tag'] != 'list' && $inside['tag'] != 'li'))
|
Chris@76
|
2117 {
|
Chris@76
|
2118 $open_tags[] = array(
|
Chris@76
|
2119 'tag' => 'list',
|
Chris@76
|
2120 'after' => '</ul>',
|
Chris@76
|
2121 'block_level' => true,
|
Chris@76
|
2122 'require_children' => array('li'),
|
Chris@76
|
2123 'disallow_children' => isset($inside['disallow_children']) ? $inside['disallow_children'] : null,
|
Chris@76
|
2124 );
|
Chris@76
|
2125 $code = '<ul class="bbc_list">';
|
Chris@76
|
2126 }
|
Chris@76
|
2127 // We're in a list item already: another itemcode? Close it first.
|
Chris@76
|
2128 elseif ($inside['tag'] == 'li')
|
Chris@76
|
2129 {
|
Chris@76
|
2130 array_pop($open_tags);
|
Chris@76
|
2131 $code = '</li>';
|
Chris@76
|
2132 }
|
Chris@76
|
2133 else
|
Chris@76
|
2134 $code = '';
|
Chris@76
|
2135
|
Chris@76
|
2136 // Now we open a new tag.
|
Chris@76
|
2137 $open_tags[] = array(
|
Chris@76
|
2138 'tag' => 'li',
|
Chris@76
|
2139 'after' => '</li>',
|
Chris@76
|
2140 'trim' => 'outside',
|
Chris@76
|
2141 'block_level' => true,
|
Chris@76
|
2142 'disallow_children' => isset($inside['disallow_children']) ? $inside['disallow_children'] : null,
|
Chris@76
|
2143 );
|
Chris@76
|
2144
|
Chris@76
|
2145 // First, open the tag...
|
Chris@76
|
2146 $code .= '<li' . ($tag == '' ? '' : ' type="' . $tag . '"') . '>';
|
Chris@76
|
2147 $message = substr($message, 0, $pos) . "\n" . $code . "\n" . substr($message, $pos + 3);
|
Chris@76
|
2148 $pos += strlen($code) - 1 + 2;
|
Chris@76
|
2149
|
Chris@76
|
2150 // Next, find the next break (if any.) If there's more itemcode after it, keep it going - otherwise close!
|
Chris@76
|
2151 $pos2 = strpos($message, '<br />', $pos);
|
Chris@76
|
2152 $pos3 = strpos($message, '[/', $pos);
|
Chris@76
|
2153 if ($pos2 !== false && ($pos2 <= $pos3 || $pos3 === false))
|
Chris@76
|
2154 {
|
Chris@76
|
2155 preg_match('~^(<br />| |\s|\[)+~', substr($message, $pos2 + 6), $matches);
|
Chris@76
|
2156 $message = substr($message, 0, $pos2) . "\n" . (!empty($matches[0]) && substr($matches[0], -1) == '[' ? '[/li]' : '[/li][/list]') . "\n" . substr($message, $pos2);
|
Chris@76
|
2157
|
Chris@76
|
2158 $open_tags[count($open_tags) - 2]['after'] = '</ul>';
|
Chris@76
|
2159 }
|
Chris@76
|
2160 // Tell the [list] that it needs to close specially.
|
Chris@76
|
2161 else
|
Chris@76
|
2162 {
|
Chris@76
|
2163 // Move the li over, because we're not sure what we'll hit.
|
Chris@76
|
2164 $open_tags[count($open_tags) - 1]['after'] = '';
|
Chris@76
|
2165 $open_tags[count($open_tags) - 2]['after'] = '</li></ul>';
|
Chris@76
|
2166 }
|
Chris@76
|
2167
|
Chris@76
|
2168 continue;
|
Chris@76
|
2169 }
|
Chris@76
|
2170
|
Chris@76
|
2171 // Implicitly close lists and tables if something other than what's required is in them. This is needed for itemcode.
|
Chris@76
|
2172 if ($tag === null && $inside !== null && !empty($inside['require_children']))
|
Chris@76
|
2173 {
|
Chris@76
|
2174 array_pop($open_tags);
|
Chris@76
|
2175
|
Chris@76
|
2176 $message = substr($message, 0, $pos) . "\n" . $inside['after'] . "\n" . substr($message, $pos);
|
Chris@76
|
2177 $pos += strlen($inside['after']) - 1 + 2;
|
Chris@76
|
2178 }
|
Chris@76
|
2179
|
Chris@76
|
2180 // No tag? Keep looking, then. Silly people using brackets without actual tags.
|
Chris@76
|
2181 if ($tag === null)
|
Chris@76
|
2182 continue;
|
Chris@76
|
2183
|
Chris@76
|
2184 // Propagate the list to the child (so wrapping the disallowed tag won't work either.)
|
Chris@76
|
2185 if (isset($inside['disallow_children']))
|
Chris@76
|
2186 $tag['disallow_children'] = isset($tag['disallow_children']) ? array_unique(array_merge($tag['disallow_children'], $inside['disallow_children'])) : $inside['disallow_children'];
|
Chris@76
|
2187
|
Chris@76
|
2188 // Is this tag disabled?
|
Chris@76
|
2189 if (isset($disabled[$tag['tag']]))
|
Chris@76
|
2190 {
|
Chris@76
|
2191 if (!isset($tag['disabled_before']) && !isset($tag['disabled_after']) && !isset($tag['disabled_content']))
|
Chris@76
|
2192 {
|
Chris@76
|
2193 $tag['before'] = !empty($tag['block_level']) ? '<div>' : '';
|
Chris@76
|
2194 $tag['after'] = !empty($tag['block_level']) ? '</div>' : '';
|
Chris@76
|
2195 $tag['content'] = isset($tag['type']) && $tag['type'] == 'closed' ? '' : (!empty($tag['block_level']) ? '<div>$1</div>' : '$1');
|
Chris@76
|
2196 }
|
Chris@76
|
2197 elseif (isset($tag['disabled_before']) || isset($tag['disabled_after']))
|
Chris@76
|
2198 {
|
Chris@76
|
2199 $tag['before'] = isset($tag['disabled_before']) ? $tag['disabled_before'] : (!empty($tag['block_level']) ? '<div>' : '');
|
Chris@76
|
2200 $tag['after'] = isset($tag['disabled_after']) ? $tag['disabled_after'] : (!empty($tag['block_level']) ? '</div>' : '');
|
Chris@76
|
2201 }
|
Chris@76
|
2202 else
|
Chris@76
|
2203 $tag['content'] = $tag['disabled_content'];
|
Chris@76
|
2204 }
|
Chris@76
|
2205
|
Chris@76
|
2206 // The only special case is 'html', which doesn't need to close things.
|
Chris@76
|
2207 if (!empty($tag['block_level']) && $tag['tag'] != 'html' && empty($inside['block_level']))
|
Chris@76
|
2208 {
|
Chris@76
|
2209 $n = count($open_tags) - 1;
|
Chris@76
|
2210 while (empty($open_tags[$n]['block_level']) && $n >= 0)
|
Chris@76
|
2211 $n--;
|
Chris@76
|
2212
|
Chris@76
|
2213 // Close all the non block level tags so this tag isn't surrounded by them.
|
Chris@76
|
2214 for ($i = count($open_tags) - 1; $i > $n; $i--)
|
Chris@76
|
2215 {
|
Chris@76
|
2216 $message = substr($message, 0, $pos) . "\n" . $open_tags[$i]['after'] . "\n" . substr($message, $pos);
|
Chris@76
|
2217 $pos += strlen($open_tags[$i]['after']) + 2;
|
Chris@76
|
2218 $pos1 += strlen($open_tags[$i]['after']) + 2;
|
Chris@76
|
2219
|
Chris@76
|
2220 // Trim or eat trailing stuff... see comment at the end of the big loop.
|
Chris@76
|
2221 if (!empty($open_tags[$i]['block_level']) && substr($message, $pos, 6) == '<br />')
|
Chris@76
|
2222 $message = substr($message, 0, $pos) . substr($message, $pos + 6);
|
Chris@76
|
2223 if (!empty($open_tags[$i]['trim']) && $tag['trim'] != 'inside' && preg_match('~(<br />| |\s)*~', substr($message, $pos), $matches) != 0)
|
Chris@76
|
2224 $message = substr($message, 0, $pos) . substr($message, $pos + strlen($matches[0]));
|
Chris@76
|
2225
|
Chris@76
|
2226 array_pop($open_tags);
|
Chris@76
|
2227 }
|
Chris@76
|
2228 }
|
Chris@76
|
2229
|
Chris@76
|
2230 // No type means 'parsed_content'.
|
Chris@76
|
2231 if (!isset($tag['type']))
|
Chris@76
|
2232 {
|
Chris@76
|
2233 // !!! Check for end tag first, so people can say "I like that [i] tag"?
|
Chris@76
|
2234 $open_tags[] = $tag;
|
Chris@76
|
2235 $message = substr($message, 0, $pos) . "\n" . $tag['before'] . "\n" . substr($message, $pos1);
|
Chris@76
|
2236 $pos += strlen($tag['before']) - 1 + 2;
|
Chris@76
|
2237 }
|
Chris@76
|
2238 // Don't parse the content, just skip it.
|
Chris@76
|
2239 elseif ($tag['type'] == 'unparsed_content')
|
Chris@76
|
2240 {
|
Chris@76
|
2241 $pos2 = stripos($message, '[/' . substr($message, $pos + 1, strlen($tag['tag'])) . ']', $pos1);
|
Chris@76
|
2242 if ($pos2 === false)
|
Chris@76
|
2243 continue;
|
Chris@76
|
2244
|
Chris@76
|
2245 $data = substr($message, $pos1, $pos2 - $pos1);
|
Chris@76
|
2246
|
Chris@76
|
2247 if (!empty($tag['block_level']) && substr($data, 0, 6) == '<br />')
|
Chris@76
|
2248 $data = substr($data, 6);
|
Chris@76
|
2249
|
Chris@76
|
2250 if (isset($tag['validate']))
|
Chris@76
|
2251 $tag['validate']($tag, $data, $disabled);
|
Chris@76
|
2252
|
Chris@76
|
2253 $code = strtr($tag['content'], array('$1' => $data));
|
Chris@76
|
2254 $message = substr($message, 0, $pos) . "\n" . $code . "\n" . substr($message, $pos2 + 3 + strlen($tag['tag']));
|
Chris@76
|
2255
|
Chris@76
|
2256 $pos += strlen($code) - 1 + 2;
|
Chris@76
|
2257 $last_pos = $pos + 1;
|
Chris@76
|
2258
|
Chris@76
|
2259 }
|
Chris@76
|
2260 // Don't parse the content, just skip it.
|
Chris@76
|
2261 elseif ($tag['type'] == 'unparsed_equals_content')
|
Chris@76
|
2262 {
|
Chris@76
|
2263 // The value may be quoted for some tags - check.
|
Chris@76
|
2264 if (isset($tag['quoted']))
|
Chris@76
|
2265 {
|
Chris@76
|
2266 $quoted = substr($message, $pos1, 6) == '"';
|
Chris@76
|
2267 if ($tag['quoted'] != 'optional' && !$quoted)
|
Chris@76
|
2268 continue;
|
Chris@76
|
2269
|
Chris@76
|
2270 if ($quoted)
|
Chris@76
|
2271 $pos1 += 6;
|
Chris@76
|
2272 }
|
Chris@76
|
2273 else
|
Chris@76
|
2274 $quoted = false;
|
Chris@76
|
2275
|
Chris@76
|
2276 $pos2 = strpos($message, $quoted == false ? ']' : '"]', $pos1);
|
Chris@76
|
2277 if ($pos2 === false)
|
Chris@76
|
2278 continue;
|
Chris@76
|
2279 $pos3 = stripos($message, '[/' . substr($message, $pos + 1, strlen($tag['tag'])) . ']', $pos2);
|
Chris@76
|
2280 if ($pos3 === false)
|
Chris@76
|
2281 continue;
|
Chris@76
|
2282
|
Chris@76
|
2283 $data = array(
|
Chris@76
|
2284 substr($message, $pos2 + ($quoted == false ? 1 : 7), $pos3 - ($pos2 + ($quoted == false ? 1 : 7))),
|
Chris@76
|
2285 substr($message, $pos1, $pos2 - $pos1)
|
Chris@76
|
2286 );
|
Chris@76
|
2287
|
Chris@76
|
2288 if (!empty($tag['block_level']) && substr($data[0], 0, 6) == '<br />')
|
Chris@76
|
2289 $data[0] = substr($data[0], 6);
|
Chris@76
|
2290
|
Chris@76
|
2291 // Validation for my parking, please!
|
Chris@76
|
2292 if (isset($tag['validate']))
|
Chris@76
|
2293 $tag['validate']($tag, $data, $disabled);
|
Chris@76
|
2294
|
Chris@76
|
2295 $code = strtr($tag['content'], array('$1' => $data[0], '$2' => $data[1]));
|
Chris@76
|
2296 $message = substr($message, 0, $pos) . "\n" . $code . "\n" . substr($message, $pos3 + 3 + strlen($tag['tag']));
|
Chris@76
|
2297 $pos += strlen($code) - 1 + 2;
|
Chris@76
|
2298 }
|
Chris@76
|
2299 // A closed tag, with no content or value.
|
Chris@76
|
2300 elseif ($tag['type'] == 'closed')
|
Chris@76
|
2301 {
|
Chris@76
|
2302 $pos2 = strpos($message, ']', $pos);
|
Chris@76
|
2303 $message = substr($message, 0, $pos) . "\n" . $tag['content'] . "\n" . substr($message, $pos2 + 1);
|
Chris@76
|
2304 $pos += strlen($tag['content']) - 1 + 2;
|
Chris@76
|
2305 }
|
Chris@76
|
2306 // This one is sorta ugly... :/. Unfortunately, it's needed for flash.
|
Chris@76
|
2307 elseif ($tag['type'] == 'unparsed_commas_content')
|
Chris@76
|
2308 {
|
Chris@76
|
2309 $pos2 = strpos($message, ']', $pos1);
|
Chris@76
|
2310 if ($pos2 === false)
|
Chris@76
|
2311 continue;
|
Chris@76
|
2312 $pos3 = stripos($message, '[/' . substr($message, $pos + 1, strlen($tag['tag'])) . ']', $pos2);
|
Chris@76
|
2313 if ($pos3 === false)
|
Chris@76
|
2314 continue;
|
Chris@76
|
2315
|
Chris@76
|
2316 // We want $1 to be the content, and the rest to be csv.
|
Chris@76
|
2317 $data = explode(',', ',' . substr($message, $pos1, $pos2 - $pos1));
|
Chris@76
|
2318 $data[0] = substr($message, $pos2 + 1, $pos3 - $pos2 - 1);
|
Chris@76
|
2319
|
Chris@76
|
2320 if (isset($tag['validate']))
|
Chris@76
|
2321 $tag['validate']($tag, $data, $disabled);
|
Chris@76
|
2322
|
Chris@76
|
2323 $code = $tag['content'];
|
Chris@76
|
2324 foreach ($data as $k => $d)
|
Chris@76
|
2325 $code = strtr($code, array('$' . ($k + 1) => trim($d)));
|
Chris@76
|
2326 $message = substr($message, 0, $pos) . "\n" . $code . "\n" . substr($message, $pos3 + 3 + strlen($tag['tag']));
|
Chris@76
|
2327 $pos += strlen($code) - 1 + 2;
|
Chris@76
|
2328 }
|
Chris@76
|
2329 // This has parsed content, and a csv value which is unparsed.
|
Chris@76
|
2330 elseif ($tag['type'] == 'unparsed_commas')
|
Chris@76
|
2331 {
|
Chris@76
|
2332 $pos2 = strpos($message, ']', $pos1);
|
Chris@76
|
2333 if ($pos2 === false)
|
Chris@76
|
2334 continue;
|
Chris@76
|
2335
|
Chris@76
|
2336 $data = explode(',', substr($message, $pos1, $pos2 - $pos1));
|
Chris@76
|
2337
|
Chris@76
|
2338 if (isset($tag['validate']))
|
Chris@76
|
2339 $tag['validate']($tag, $data, $disabled);
|
Chris@76
|
2340
|
Chris@76
|
2341 // Fix after, for disabled code mainly.
|
Chris@76
|
2342 foreach ($data as $k => $d)
|
Chris@76
|
2343 $tag['after'] = strtr($tag['after'], array('$' . ($k + 1) => trim($d)));
|
Chris@76
|
2344
|
Chris@76
|
2345 $open_tags[] = $tag;
|
Chris@76
|
2346
|
Chris@76
|
2347 // Replace them out, $1, $2, $3, $4, etc.
|
Chris@76
|
2348 $code = $tag['before'];
|
Chris@76
|
2349 foreach ($data as $k => $d)
|
Chris@76
|
2350 $code = strtr($code, array('$' . ($k + 1) => trim($d)));
|
Chris@76
|
2351 $message = substr($message, 0, $pos) . "\n" . $code . "\n" . substr($message, $pos2 + 1);
|
Chris@76
|
2352 $pos += strlen($code) - 1 + 2;
|
Chris@76
|
2353 }
|
Chris@76
|
2354 // A tag set to a value, parsed or not.
|
Chris@76
|
2355 elseif ($tag['type'] == 'unparsed_equals' || $tag['type'] == 'parsed_equals')
|
Chris@76
|
2356 {
|
Chris@76
|
2357 // The value may be quoted for some tags - check.
|
Chris@76
|
2358 if (isset($tag['quoted']))
|
Chris@76
|
2359 {
|
Chris@76
|
2360 $quoted = substr($message, $pos1, 6) == '"';
|
Chris@76
|
2361 if ($tag['quoted'] != 'optional' && !$quoted)
|
Chris@76
|
2362 continue;
|
Chris@76
|
2363
|
Chris@76
|
2364 if ($quoted)
|
Chris@76
|
2365 $pos1 += 6;
|
Chris@76
|
2366 }
|
Chris@76
|
2367 else
|
Chris@76
|
2368 $quoted = false;
|
Chris@76
|
2369
|
Chris@76
|
2370 $pos2 = strpos($message, $quoted == false ? ']' : '"]', $pos1);
|
Chris@76
|
2371 if ($pos2 === false)
|
Chris@76
|
2372 continue;
|
Chris@76
|
2373
|
Chris@76
|
2374 $data = substr($message, $pos1, $pos2 - $pos1);
|
Chris@76
|
2375
|
Chris@76
|
2376 // Validation for my parking, please!
|
Chris@76
|
2377 if (isset($tag['validate']))
|
Chris@76
|
2378 $tag['validate']($tag, $data, $disabled);
|
Chris@76
|
2379
|
Chris@76
|
2380 // For parsed content, we must recurse to avoid security problems.
|
Chris@76
|
2381 if ($tag['type'] != 'unparsed_equals')
|
Chris@76
|
2382 $data = parse_bbc($data, !empty($tag['parsed_tags_allowed']) ? false : true, '', !empty($tag['parsed_tags_allowed']) ? $tag['parsed_tags_allowed'] : array());
|
Chris@76
|
2383
|
Chris@76
|
2384 $tag['after'] = strtr($tag['after'], array('$1' => $data));
|
Chris@76
|
2385
|
Chris@76
|
2386 $open_tags[] = $tag;
|
Chris@76
|
2387
|
Chris@76
|
2388 $code = strtr($tag['before'], array('$1' => $data));
|
Chris@76
|
2389 $message = substr($message, 0, $pos) . "\n" . $code . "\n" . substr($message, $pos2 + ($quoted == false ? 1 : 7));
|
Chris@76
|
2390 $pos += strlen($code) - 1 + 2;
|
Chris@76
|
2391 }
|
Chris@76
|
2392
|
Chris@76
|
2393 // If this is block level, eat any breaks after it.
|
Chris@76
|
2394 if (!empty($tag['block_level']) && substr($message, $pos + 1, 6) == '<br />')
|
Chris@76
|
2395 $message = substr($message, 0, $pos + 1) . substr($message, $pos + 7);
|
Chris@76
|
2396
|
Chris@76
|
2397 // Are we trimming outside this tag?
|
Chris@76
|
2398 if (!empty($tag['trim']) && $tag['trim'] != 'outside' && preg_match('~(<br />| |\s)*~', substr($message, $pos + 1), $matches) != 0)
|
Chris@76
|
2399 $message = substr($message, 0, $pos + 1) . substr($message, $pos + 1 + strlen($matches[0]));
|
Chris@76
|
2400 }
|
Chris@76
|
2401
|
Chris@76
|
2402 // Close any remaining tags.
|
Chris@76
|
2403 while ($tag = array_pop($open_tags))
|
Chris@76
|
2404 $message .= "\n" . $tag['after'] . "\n";
|
Chris@76
|
2405
|
Chris@76
|
2406 // Parse the smileys within the parts where it can be done safely.
|
Chris@76
|
2407 if ($smileys === true)
|
Chris@76
|
2408 {
|
Chris@76
|
2409 $message_parts = explode("\n", $message);
|
Chris@76
|
2410 for ($i = 0, $n = count($message_parts); $i < $n; $i += 2)
|
Chris@76
|
2411 parsesmileys($message_parts[$i]);
|
Chris@76
|
2412
|
Chris@76
|
2413 $message = implode('', $message_parts);
|
Chris@76
|
2414 }
|
Chris@76
|
2415
|
Chris@76
|
2416 // No smileys, just get rid of the markers.
|
Chris@76
|
2417 else
|
Chris@76
|
2418 $message = strtr($message, array("\n" => ''));
|
Chris@76
|
2419
|
Chris@76
|
2420 if (substr($message, 0, 1) == ' ')
|
Chris@76
|
2421 $message = ' ' . substr($message, 1);
|
Chris@76
|
2422
|
Chris@76
|
2423 // Cleanup whitespace.
|
Chris@76
|
2424 $message = strtr($message, array(' ' => ' ', "\r" => '', "\n" => '<br />', '<br /> ' => '<br /> ', ' ' => "\n"));
|
Chris@76
|
2425
|
Chris@76
|
2426 // Cache the output if it took some time...
|
Chris@76
|
2427 if (isset($cache_key, $cache_t) && array_sum(explode(' ', microtime())) - array_sum(explode(' ', $cache_t)) > 0.05)
|
Chris@76
|
2428 cache_put_data($cache_key, $message, 240);
|
Chris@76
|
2429
|
Chris@76
|
2430 // If this was a force parse revert if needed.
|
Chris@76
|
2431 if (!empty($parse_tags))
|
Chris@76
|
2432 {
|
Chris@76
|
2433 if (empty($temp_bbc))
|
Chris@76
|
2434 $bbc_codes = array();
|
Chris@76
|
2435 else
|
Chris@76
|
2436 {
|
Chris@76
|
2437 $bbc_codes = $temp_bbc;
|
Chris@76
|
2438 unset($temp_bbc);
|
Chris@76
|
2439 }
|
Chris@76
|
2440 }
|
Chris@76
|
2441
|
Chris@76
|
2442 return $message;
|
Chris@76
|
2443 }
|
Chris@76
|
2444
|
Chris@76
|
2445 // Parse smileys in the passed message.
|
Chris@76
|
2446 function parsesmileys(&$message)
|
Chris@76
|
2447 {
|
Chris@76
|
2448 global $modSettings, $txt, $user_info, $context, $smcFunc;
|
Chris@76
|
2449 static $smileyPregSearch = array(), $smileyPregReplacements = array();
|
Chris@76
|
2450
|
Chris@76
|
2451 // No smiley set at all?!
|
Chris@76
|
2452 if ($user_info['smiley_set'] == 'none')
|
Chris@76
|
2453 return;
|
Chris@76
|
2454
|
Chris@76
|
2455 // If the smiley array hasn't been set, do it now.
|
Chris@76
|
2456 if (empty($smileyPregSearch))
|
Chris@76
|
2457 {
|
Chris@76
|
2458 // Use the default smileys if it is disabled. (better for "portability" of smileys.)
|
Chris@76
|
2459 if (empty($modSettings['smiley_enable']))
|
Chris@76
|
2460 {
|
Chris@76
|
2461 $smileysfrom = array('>:D', ':D', '::)', '>:(', ':))', ':)', ';)', ';D', ':(', ':o', '8)', ':P', '???', ':-[', ':-X', ':-*', ':\'(', ':-\\', '^-^', 'O0', 'C:-)', '0:)');
|
Chris@76
|
2462 $smileysto = array('evil.gif', 'cheesy.gif', 'rolleyes.gif', 'angry.gif', 'laugh.gif', 'smiley.gif', 'wink.gif', 'grin.gif', 'sad.gif', 'shocked.gif', 'cool.gif', 'tongue.gif', 'huh.gif', 'embarrassed.gif', 'lipsrsealed.gif', 'kiss.gif', 'cry.gif', 'undecided.gif', 'azn.gif', 'afro.gif', 'police.gif', 'angel.gif');
|
Chris@76
|
2463 $smileysdescs = array('', $txt['icon_cheesy'], $txt['icon_rolleyes'], $txt['icon_angry'], '', $txt['icon_smiley'], $txt['icon_wink'], $txt['icon_grin'], $txt['icon_sad'], $txt['icon_shocked'], $txt['icon_cool'], $txt['icon_tongue'], $txt['icon_huh'], $txt['icon_embarrassed'], $txt['icon_lips'], $txt['icon_kiss'], $txt['icon_cry'], $txt['icon_undecided'], '', '', '', '');
|
Chris@76
|
2464 }
|
Chris@76
|
2465 else
|
Chris@76
|
2466 {
|
Chris@76
|
2467 // Load the smileys in reverse order by length so they don't get parsed wrong.
|
Chris@76
|
2468 if (($temp = cache_get_data('parsing_smileys', 480)) == null)
|
Chris@76
|
2469 {
|
Chris@76
|
2470 $result = $smcFunc['db_query']('', '
|
Chris@76
|
2471 SELECT code, filename, description
|
Chris@76
|
2472 FROM {db_prefix}smileys',
|
Chris@76
|
2473 array(
|
Chris@76
|
2474 )
|
Chris@76
|
2475 );
|
Chris@76
|
2476 $smileysfrom = array();
|
Chris@76
|
2477 $smileysto = array();
|
Chris@76
|
2478 $smileysdescs = array();
|
Chris@76
|
2479 while ($row = $smcFunc['db_fetch_assoc']($result))
|
Chris@76
|
2480 {
|
Chris@76
|
2481 $smileysfrom[] = $row['code'];
|
Chris@76
|
2482 $smileysto[] = $row['filename'];
|
Chris@76
|
2483 $smileysdescs[] = $row['description'];
|
Chris@76
|
2484 }
|
Chris@76
|
2485 $smcFunc['db_free_result']($result);
|
Chris@76
|
2486
|
Chris@76
|
2487 cache_put_data('parsing_smileys', array($smileysfrom, $smileysto, $smileysdescs), 480);
|
Chris@76
|
2488 }
|
Chris@76
|
2489 else
|
Chris@76
|
2490 list ($smileysfrom, $smileysto, $smileysdescs) = $temp;
|
Chris@76
|
2491 }
|
Chris@76
|
2492
|
Chris@76
|
2493 // The non-breaking-space is a complex thing...
|
Chris@76
|
2494 $non_breaking_space = $context['utf8'] ? ($context['server']['complex_preg_chars'] ? '\x{A0}' : "\xC2\xA0") : '\xA0';
|
Chris@76
|
2495
|
Chris@76
|
2496 // This smiley regex makes sure it doesn't parse smileys within code tags (so [url=mailto:David@bla.com] doesn't parse the :D smiley)
|
Chris@76
|
2497 $smileyPregReplacements = array();
|
Chris@76
|
2498 $searchParts = array();
|
Chris@76
|
2499 for ($i = 0, $n = count($smileysfrom); $i < $n; $i++)
|
Chris@76
|
2500 {
|
Chris@76
|
2501 $smileyCode = '<img src="' . htmlspecialchars($modSettings['smileys_url'] . '/' . $user_info['smiley_set'] . '/' . $smileysto[$i]) . '" alt="' . strtr(htmlspecialchars($smileysfrom[$i], ENT_QUOTES), array(':' => ':', '(' => '(', ')' => ')', '$' => '$', '[' => '[')). '" title="' . strtr(htmlspecialchars($smileysdescs[$i]), array(':' => ':', '(' => '(', ')' => ')', '$' => '$', '[' => '[')) . '" class="smiley" />';
|
Chris@76
|
2502
|
Chris@76
|
2503 $smileyPregReplacements[$smileysfrom[$i]] = $smileyCode;
|
Chris@76
|
2504 $smileyPregReplacements[htmlspecialchars($smileysfrom[$i], ENT_QUOTES)] = $smileyCode;
|
Chris@76
|
2505 $searchParts[] = preg_quote($smileysfrom[$i], '~');
|
Chris@76
|
2506 $searchParts[] = preg_quote(htmlspecialchars($smileysfrom[$i], ENT_QUOTES), '~');
|
Chris@76
|
2507 }
|
Chris@76
|
2508
|
Chris@76
|
2509 $smileyPregSearch = '~(?<=[>:\?\.\s' . $non_breaking_space . '[\]()*\\\;]|^)(' . implode('|', $searchParts) . ')(?=[^[:alpha:]0-9]|$)~e' . ($context['utf8'] ? 'u' : '');
|
Chris@76
|
2510 }
|
Chris@76
|
2511
|
Chris@76
|
2512 // Replace away!
|
Chris@76
|
2513 $message = preg_replace($smileyPregSearch, 'isset($smileyPregReplacements[\'$1\']) ? $smileyPregReplacements[\'$1\'] : \'\'', $message);
|
Chris@76
|
2514 }
|
Chris@76
|
2515
|
Chris@76
|
2516 // Highlight any code...
|
Chris@76
|
2517 function highlight_php_code($code)
|
Chris@76
|
2518 {
|
Chris@76
|
2519 global $context;
|
Chris@76
|
2520
|
Chris@76
|
2521 // Remove special characters.
|
Chris@76
|
2522 $code = un_htmlspecialchars(strtr($code, array('<br />' => "\n", "\t" => 'SMF_TAB();', '[' => '[')));
|
Chris@76
|
2523
|
Chris@76
|
2524 $oldlevel = error_reporting(0);
|
Chris@76
|
2525
|
Chris@76
|
2526 // It's easier in 4.2.x+.
|
Chris@76
|
2527 if (@version_compare(PHP_VERSION, '4.2.0') == -1)
|
Chris@76
|
2528 {
|
Chris@76
|
2529 ob_start();
|
Chris@76
|
2530 @highlight_string($code);
|
Chris@76
|
2531 $buffer = str_replace(array("\n", "\r"), '', ob_get_contents());
|
Chris@76
|
2532 ob_end_clean();
|
Chris@76
|
2533 }
|
Chris@76
|
2534 else
|
Chris@76
|
2535 $buffer = str_replace(array("\n", "\r"), '', @highlight_string($code, true));
|
Chris@76
|
2536
|
Chris@76
|
2537 error_reporting($oldlevel);
|
Chris@76
|
2538
|
Chris@76
|
2539 // Yes, I know this is kludging it, but this is the best way to preserve tabs from PHP :P.
|
Chris@76
|
2540 $buffer = preg_replace('~SMF_TAB(?:</(?:font|span)><(?:font color|span style)="[^"]*?">)?\\(\\);~', '<pre style="display: inline;">' . "\t" . '</pre>', $buffer);
|
Chris@76
|
2541
|
Chris@76
|
2542 return strtr($buffer, array('\'' => ''', '<code>' => '', '</code>' => ''));
|
Chris@76
|
2543 }
|
Chris@76
|
2544
|
Chris@76
|
2545 // Put this user in the online log.
|
Chris@76
|
2546 function writeLog($force = false)
|
Chris@76
|
2547 {
|
Chris@76
|
2548 global $user_info, $user_settings, $context, $modSettings, $settings, $topic, $board, $smcFunc, $sourcedir;
|
Chris@76
|
2549
|
Chris@76
|
2550 // If we are showing who is viewing a topic, let's see if we are, and force an update if so - to make it accurate.
|
Chris@76
|
2551 if (!empty($settings['display_who_viewing']) && ($topic || $board))
|
Chris@76
|
2552 {
|
Chris@76
|
2553 // Take the opposite approach!
|
Chris@76
|
2554 $force = true;
|
Chris@76
|
2555 // Don't update for every page - this isn't wholly accurate but who cares.
|
Chris@76
|
2556 if ($topic)
|
Chris@76
|
2557 {
|
Chris@76
|
2558 if (isset($_SESSION['last_topic_id']) && $_SESSION['last_topic_id'] == $topic)
|
Chris@76
|
2559 $force = false;
|
Chris@76
|
2560 $_SESSION['last_topic_id'] = $topic;
|
Chris@76
|
2561 }
|
Chris@76
|
2562 }
|
Chris@76
|
2563
|
Chris@76
|
2564 // Are they a spider we should be tracking? Mode = 1 gets tracked on its spider check...
|
Chris@76
|
2565 if (!empty($user_info['possibly_robot']) && !empty($modSettings['spider_mode']) && $modSettings['spider_mode'] > 1)
|
Chris@76
|
2566 {
|
Chris@76
|
2567 require_once($sourcedir . '/ManageSearchEngines.php');
|
Chris@76
|
2568 logSpider();
|
Chris@76
|
2569 }
|
Chris@76
|
2570
|
Chris@76
|
2571 // Don't mark them as online more than every so often.
|
Chris@76
|
2572 if (!empty($_SESSION['log_time']) && $_SESSION['log_time'] >= (time() - 8) && !$force)
|
Chris@76
|
2573 return;
|
Chris@76
|
2574
|
Chris@76
|
2575 if (!empty($modSettings['who_enabled']))
|
Chris@76
|
2576 {
|
Chris@76
|
2577 $serialized = $_GET + array('USER_AGENT' => $_SERVER['HTTP_USER_AGENT']);
|
Chris@76
|
2578
|
Chris@76
|
2579 // In the case of a dlattach action, session_var may not be set.
|
Chris@76
|
2580 if (!isset($context['session_var']))
|
Chris@76
|
2581 $context['session_var'] = $_SESSION['session_var'];
|
Chris@76
|
2582
|
Chris@76
|
2583 unset($serialized['sesc'], $serialized[$context['session_var']]);
|
Chris@76
|
2584 $serialized = serialize($serialized);
|
Chris@76
|
2585 }
|
Chris@76
|
2586 else
|
Chris@76
|
2587 $serialized = '';
|
Chris@76
|
2588
|
Chris@76
|
2589 // Guests use 0, members use their session ID.
|
Chris@76
|
2590 $session_id = $user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id();
|
Chris@76
|
2591
|
Chris@76
|
2592 // Grab the last all-of-SMF-specific log_online deletion time.
|
Chris@76
|
2593 $do_delete = cache_get_data('log_online-update', 30) < time() - 30;
|
Chris@76
|
2594
|
Chris@76
|
2595 // If the last click wasn't a long time ago, and there was a last click...
|
Chris@76
|
2596 if (!empty($_SESSION['log_time']) && $_SESSION['log_time'] >= time() - $modSettings['lastActive'] * 20)
|
Chris@76
|
2597 {
|
Chris@76
|
2598 if ($do_delete)
|
Chris@76
|
2599 {
|
Chris@76
|
2600 $smcFunc['db_query']('delete_log_online_interval', '
|
Chris@76
|
2601 DELETE FROM {db_prefix}log_online
|
Chris@76
|
2602 WHERE log_time < {int:log_time}
|
Chris@76
|
2603 AND session != {string:session}',
|
Chris@76
|
2604 array(
|
Chris@76
|
2605 'log_time' => time() - $modSettings['lastActive'] * 60,
|
Chris@76
|
2606 'session' => $session_id,
|
Chris@76
|
2607 )
|
Chris@76
|
2608 );
|
Chris@76
|
2609
|
Chris@76
|
2610 // Cache when we did it last.
|
Chris@76
|
2611 cache_put_data('log_online-update', time(), 30);
|
Chris@76
|
2612 }
|
Chris@76
|
2613
|
Chris@76
|
2614 $smcFunc['db_query']('', '
|
Chris@76
|
2615 UPDATE {db_prefix}log_online
|
Chris@76
|
2616 SET log_time = {int:log_time}, ip = IFNULL(INET_ATON({string:ip}), 0), url = {string:url}
|
Chris@76
|
2617 WHERE session = {string:session}',
|
Chris@76
|
2618 array(
|
Chris@76
|
2619 'log_time' => time(),
|
Chris@76
|
2620 'ip' => $user_info['ip'],
|
Chris@76
|
2621 'url' => $serialized,
|
Chris@76
|
2622 'session' => $session_id,
|
Chris@76
|
2623 )
|
Chris@76
|
2624 );
|
Chris@76
|
2625
|
Chris@76
|
2626 // Guess it got deleted.
|
Chris@76
|
2627 if ($smcFunc['db_affected_rows']() == 0)
|
Chris@76
|
2628 $_SESSION['log_time'] = 0;
|
Chris@76
|
2629 }
|
Chris@76
|
2630 else
|
Chris@76
|
2631 $_SESSION['log_time'] = 0;
|
Chris@76
|
2632
|
Chris@76
|
2633 // Otherwise, we have to delete and insert.
|
Chris@76
|
2634 if (empty($_SESSION['log_time']))
|
Chris@76
|
2635 {
|
Chris@76
|
2636 if ($do_delete || !empty($user_info['id']))
|
Chris@76
|
2637 $smcFunc['db_query']('', '
|
Chris@76
|
2638 DELETE FROM {db_prefix}log_online
|
Chris@76
|
2639 WHERE ' . ($do_delete ? 'log_time < {int:log_time}' : '') . ($do_delete && !empty($user_info['id']) ? ' OR ' : '') . (empty($user_info['id']) ? '' : 'id_member = {int:current_member}'),
|
Chris@76
|
2640 array(
|
Chris@76
|
2641 'current_member' => $user_info['id'],
|
Chris@76
|
2642 'log_time' => time() - $modSettings['lastActive'] * 60,
|
Chris@76
|
2643 )
|
Chris@76
|
2644 );
|
Chris@76
|
2645
|
Chris@76
|
2646 $smcFunc['db_insert']($do_delete ? 'ignore' : 'replace',
|
Chris@76
|
2647 '{db_prefix}log_online',
|
Chris@76
|
2648 array('session' => 'string', 'id_member' => 'int', 'id_spider' => 'int', 'log_time' => 'int', 'ip' => 'raw', 'url' => 'string'),
|
Chris@76
|
2649 array($session_id, $user_info['id'], empty($_SESSION['id_robot']) ? 0 : $_SESSION['id_robot'], time(), 'IFNULL(INET_ATON(\'' . $user_info['ip'] . '\'), 0)', $serialized),
|
Chris@76
|
2650 array('session')
|
Chris@76
|
2651 );
|
Chris@76
|
2652 }
|
Chris@76
|
2653
|
Chris@76
|
2654 // Mark your session as being logged.
|
Chris@76
|
2655 $_SESSION['log_time'] = time();
|
Chris@76
|
2656
|
Chris@76
|
2657 // Well, they are online now.
|
Chris@76
|
2658 if (empty($_SESSION['timeOnlineUpdated']))
|
Chris@76
|
2659 $_SESSION['timeOnlineUpdated'] = time();
|
Chris@76
|
2660
|
Chris@76
|
2661 // Set their login time, if not already done within the last minute.
|
Chris@76
|
2662 if (SMF != 'SSI' && !empty($user_info['last_login']) && $user_info['last_login'] < time() - 60)
|
Chris@76
|
2663 {
|
Chris@76
|
2664 // Don't count longer than 15 minutes.
|
Chris@76
|
2665 if (time() - $_SESSION['timeOnlineUpdated'] > 60 * 15)
|
Chris@76
|
2666 $_SESSION['timeOnlineUpdated'] = time();
|
Chris@76
|
2667
|
Chris@76
|
2668 $user_settings['total_time_logged_in'] += time() - $_SESSION['timeOnlineUpdated'];
|
Chris@76
|
2669 updateMemberData($user_info['id'], array('last_login' => time(), 'member_ip' => $user_info['ip'], 'member_ip2' => $_SERVER['BAN_CHECK_IP'], 'total_time_logged_in' => $user_settings['total_time_logged_in']));
|
Chris@76
|
2670
|
Chris@76
|
2671 if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2)
|
Chris@76
|
2672 cache_put_data('user_settings-' . $user_info['id'], $user_settings, 60);
|
Chris@76
|
2673
|
Chris@76
|
2674 $user_info['total_time_logged_in'] += time() - $_SESSION['timeOnlineUpdated'];
|
Chris@76
|
2675 $_SESSION['timeOnlineUpdated'] = time();
|
Chris@76
|
2676 }
|
Chris@76
|
2677 }
|
Chris@76
|
2678
|
Chris@76
|
2679 // Make sure the browser doesn't come back and repost the form data. Should be used whenever anything is posted.
|
Chris@76
|
2680 function redirectexit($setLocation = '', $refresh = false)
|
Chris@76
|
2681 {
|
Chris@76
|
2682 global $scripturl, $context, $modSettings, $db_show_debug, $db_cache;
|
Chris@76
|
2683
|
Chris@76
|
2684 // In case we have mail to send, better do that - as obExit doesn't always quite make it...
|
Chris@76
|
2685 if (!empty($context['flush_mail']))
|
Chris@76
|
2686 AddMailQueue(true);
|
Chris@76
|
2687
|
Chris@76
|
2688 $add = preg_match('~^(ftp|http)[s]?://~', $setLocation) == 0 && substr($setLocation, 0, 6) != 'about:';
|
Chris@76
|
2689
|
Chris@76
|
2690 if (WIRELESS)
|
Chris@76
|
2691 {
|
Chris@76
|
2692 // Add the scripturl on if needed.
|
Chris@76
|
2693 if ($add)
|
Chris@76
|
2694 $setLocation = $scripturl . '?' . $setLocation;
|
Chris@76
|
2695
|
Chris@76
|
2696 $char = strpos($setLocation, '?') === false ? '?' : ';';
|
Chris@76
|
2697
|
Chris@76
|
2698 if (strpos($setLocation, '#') !== false)
|
Chris@76
|
2699 $setLocation = strtr($setLocation, array('#' => $char . WIRELESS_PROTOCOL . '#'));
|
Chris@76
|
2700 else
|
Chris@76
|
2701 $setLocation .= $char . WIRELESS_PROTOCOL;
|
Chris@76
|
2702 }
|
Chris@76
|
2703 elseif ($add)
|
Chris@76
|
2704 $setLocation = $scripturl . ($setLocation != '' ? '?' . $setLocation : '');
|
Chris@76
|
2705
|
Chris@76
|
2706 // Put the session ID in.
|
Chris@76
|
2707 if (defined('SID') && SID != '')
|
Chris@76
|
2708 $setLocation = preg_replace('/^' . preg_quote($scripturl, '/') . '(?!\?' . preg_quote(SID, '/') . ')\\??/', $scripturl . '?' . SID . ';', $setLocation);
|
Chris@76
|
2709 // Keep that debug in their for template debugging!
|
Chris@76
|
2710 elseif (isset($_GET['debug']))
|
Chris@76
|
2711 $setLocation = preg_replace('/^' . preg_quote($scripturl, '/') . '\\??/', $scripturl . '?debug;', $setLocation);
|
Chris@76
|
2712
|
Chris@76
|
2713 if (!empty($modSettings['queryless_urls']) && (empty($context['server']['is_cgi']) || @ini_get('cgi.fix_pathinfo') == 1 || @get_cfg_var('cgi.fix_pathinfo') == 1) && (!empty($context['server']['is_apache']) || !empty($context['server']['is_lighttpd'])))
|
Chris@76
|
2714 {
|
Chris@76
|
2715 if (defined('SID') && SID != '')
|
Chris@76
|
2716 $setLocation = preg_replace('/^' . preg_quote($scripturl, '/') . '\?(?:' . SID . '(?:;|&|&))((?:board|topic)=[^#]+?)(#[^"]*?)?$/e', "\$scripturl . '/' . strtr('\$1', '&;=', '//,') . '.html\$2?' . SID", $setLocation);
|
Chris@76
|
2717 else
|
Chris@76
|
2718 $setLocation = preg_replace('/^' . preg_quote($scripturl, '/') . '\?((?:board|topic)=[^#"]+?)(#[^"]*?)?$/e', "\$scripturl . '/' . strtr('\$1', '&;=', '//,') . '.html\$2'", $setLocation);
|
Chris@76
|
2719 }
|
Chris@76
|
2720
|
Chris@76
|
2721 // Maybe integrations want to change where we are heading?
|
Chris@76
|
2722 call_integration_hook('integrate_redirect', array(&$setLocation, &$refresh));
|
Chris@76
|
2723
|
Chris@76
|
2724 // We send a Refresh header only in special cases because Location looks better. (and is quicker...)
|
Chris@76
|
2725 if ($refresh && !WIRELESS)
|
Chris@76
|
2726 header('Refresh: 0; URL=' . strtr($setLocation, array(' ' => '%20')));
|
Chris@76
|
2727 else
|
Chris@76
|
2728 header('Location: ' . str_replace(' ', '%20', $setLocation));
|
Chris@76
|
2729
|
Chris@76
|
2730 // Debugging.
|
Chris@76
|
2731 if (isset($db_show_debug) && $db_show_debug === true)
|
Chris@76
|
2732 $_SESSION['debug_redirect'] = $db_cache;
|
Chris@76
|
2733
|
Chris@76
|
2734 obExit(false);
|
Chris@76
|
2735 }
|
Chris@76
|
2736
|
Chris@76
|
2737 // Ends execution. Takes care of template loading and remembering the previous URL.
|
Chris@76
|
2738 function obExit($header = null, $do_footer = null, $from_index = false, $from_fatal_error = false)
|
Chris@76
|
2739 {
|
Chris@76
|
2740 global $context, $settings, $modSettings, $txt, $smcFunc;
|
Chris@76
|
2741 static $header_done = false, $footer_done = false, $level = 0, $has_fatal_error = false;
|
Chris@76
|
2742
|
Chris@76
|
2743 // Attempt to prevent a recursive loop.
|
Chris@76
|
2744 ++$level;
|
Chris@76
|
2745 if ($level > 1 && !$from_fatal_error && !$has_fatal_error)
|
Chris@76
|
2746 exit;
|
Chris@76
|
2747 if ($from_fatal_error)
|
Chris@76
|
2748 $has_fatal_error = true;
|
Chris@76
|
2749
|
Chris@76
|
2750 // Clear out the stat cache.
|
Chris@76
|
2751 trackStats();
|
Chris@76
|
2752
|
Chris@76
|
2753 // If we have mail to send, send it.
|
Chris@76
|
2754 if (!empty($context['flush_mail']))
|
Chris@76
|
2755 AddMailQueue(true);
|
Chris@76
|
2756
|
Chris@76
|
2757 $do_header = $header === null ? !$header_done : $header;
|
Chris@76
|
2758 if ($do_footer === null)
|
Chris@76
|
2759 $do_footer = $do_header;
|
Chris@76
|
2760
|
Chris@76
|
2761 // Has the template/header been done yet?
|
Chris@76
|
2762 if ($do_header)
|
Chris@76
|
2763 {
|
Chris@76
|
2764 // Was the page title set last minute? Also update the HTML safe one.
|
Chris@76
|
2765 if (!empty($context['page_title']) && empty($context['page_title_html_safe']))
|
Chris@76
|
2766 $context['page_title_html_safe'] = $smcFunc['htmlspecialchars'](un_htmlspecialchars($context['page_title']));
|
Chris@76
|
2767
|
Chris@76
|
2768 // Start up the session URL fixer.
|
Chris@76
|
2769 ob_start('ob_sessrewrite');
|
Chris@76
|
2770
|
Chris@76
|
2771 if (!empty($settings['output_buffers']) && is_string($settings['output_buffers']))
|
Chris@76
|
2772 $buffers = explode(',', $settings['output_buffers']);
|
Chris@76
|
2773 elseif (!empty($settings['output_buffers']))
|
Chris@76
|
2774 $buffers = $settings['output_buffers'];
|
Chris@76
|
2775 else
|
Chris@76
|
2776 $buffers = array();
|
Chris@76
|
2777
|
Chris@76
|
2778 if (isset($modSettings['integrate_buffer']))
|
Chris@76
|
2779 $buffers = array_merge(explode(',', $modSettings['integrate_buffer']), $buffers);
|
Chris@76
|
2780
|
Chris@76
|
2781 if (!empty($buffers))
|
Chris@76
|
2782 foreach ($buffers as $function)
|
Chris@76
|
2783 {
|
Chris@76
|
2784 $function = trim($function);
|
Chris@76
|
2785 $call = strpos($function, '::') !== false ? explode('::', $function) : $function;
|
Chris@76
|
2786
|
Chris@76
|
2787 // Is it valid?
|
Chris@76
|
2788 if (is_callable($call))
|
Chris@76
|
2789 ob_start($call);
|
Chris@76
|
2790 }
|
Chris@76
|
2791
|
Chris@76
|
2792 // Display the screen in the logical order.
|
Chris@76
|
2793 template_header();
|
Chris@76
|
2794 $header_done = true;
|
Chris@76
|
2795 }
|
Chris@76
|
2796 if ($do_footer)
|
Chris@76
|
2797 {
|
Chris@76
|
2798 if (WIRELESS && !isset($context['sub_template']))
|
Chris@76
|
2799 fatal_lang_error('wireless_error_notyet', false);
|
Chris@76
|
2800
|
Chris@76
|
2801 // Just show the footer, then.
|
Chris@76
|
2802 loadSubTemplate(isset($context['sub_template']) ? $context['sub_template'] : 'main');
|
Chris@76
|
2803
|
Chris@76
|
2804 // Anything special to put out?
|
Chris@76
|
2805 if (!empty($context['insert_after_template']) && !isset($_REQUEST['xml']))
|
Chris@76
|
2806 echo $context['insert_after_template'];
|
Chris@76
|
2807
|
Chris@76
|
2808 // Just so we don't get caught in an endless loop of errors from the footer...
|
Chris@76
|
2809 if (!$footer_done)
|
Chris@76
|
2810 {
|
Chris@76
|
2811 $footer_done = true;
|
Chris@76
|
2812 template_footer();
|
Chris@76
|
2813
|
Chris@76
|
2814 // (since this is just debugging... it's okay that it's after </html>.)
|
Chris@76
|
2815 if (!isset($_REQUEST['xml']))
|
Chris@76
|
2816 db_debug_junk();
|
Chris@76
|
2817 }
|
Chris@76
|
2818 }
|
Chris@76
|
2819
|
Chris@76
|
2820 // Remember this URL in case someone doesn't like sending HTTP_REFERER.
|
Chris@76
|
2821 if (strpos($_SERVER['REQUEST_URL'], 'action=dlattach') === false && strpos($_SERVER['REQUEST_URL'], 'action=viewsmfile') === false)
|
Chris@76
|
2822 $_SESSION['old_url'] = $_SERVER['REQUEST_URL'];
|
Chris@76
|
2823
|
Chris@76
|
2824 // For session check verfication.... don't switch browsers...
|
Chris@76
|
2825 $_SESSION['USER_AGENT'] = $_SERVER['HTTP_USER_AGENT'];
|
Chris@76
|
2826
|
Chris@76
|
2827 if (!empty($settings['strict_doctype']))
|
Chris@76
|
2828 {
|
Chris@76
|
2829 // The theme author wants to use the STRICT doctype (only God knows why).
|
Chris@76
|
2830 $temp = ob_get_contents();
|
Chris@76
|
2831 if (function_exists('ob_clean'))
|
Chris@76
|
2832 ob_clean();
|
Chris@76
|
2833 else
|
Chris@76
|
2834 {
|
Chris@76
|
2835 ob_end_clean();
|
Chris@76
|
2836 ob_start('ob_sessrewrite');
|
Chris@76
|
2837 }
|
Chris@76
|
2838
|
Chris@76
|
2839 echo strtr($temp, array(
|
Chris@76
|
2840 'var smf_iso_case_folding' => 'var target_blank = \'_blank\'; var smf_iso_case_folding',
|
Chris@76
|
2841 'target="_blank"' => 'onclick="this.target=target_blank"'));
|
Chris@76
|
2842 }
|
Chris@76
|
2843
|
Chris@76
|
2844 // Hand off the output to the portal, etc. we're integrated with.
|
Chris@76
|
2845 call_integration_hook('integrate_exit', array($do_footer && !WIRELESS));
|
Chris@76
|
2846
|
Chris@76
|
2847 // Don't exit if we're coming from index.php; that will pass through normally.
|
Chris@76
|
2848 if (!$from_index || WIRELESS)
|
Chris@76
|
2849 exit;
|
Chris@76
|
2850 }
|
Chris@76
|
2851
|
Chris@76
|
2852 // Usage: logAction('remove', array('starter' => $id_member_started));
|
Chris@76
|
2853 function logAction($action, $extra = array(), $log_type = 'moderate')
|
Chris@76
|
2854 {
|
Chris@76
|
2855 global $modSettings, $user_info, $smcFunc, $sourcedir;
|
Chris@76
|
2856
|
Chris@76
|
2857 $log_types = array(
|
Chris@76
|
2858 'moderate' => 1,
|
Chris@76
|
2859 'user' => 2,
|
Chris@76
|
2860 'admin' => 3,
|
Chris@76
|
2861 );
|
Chris@76
|
2862
|
Chris@76
|
2863 if (!is_array($extra))
|
Chris@76
|
2864 trigger_error('logAction(): data is not an array with action \'' . $action . '\'', E_USER_NOTICE);
|
Chris@76
|
2865
|
Chris@76
|
2866 // Pull out the parts we want to store separately, but also make sure that the data is proper
|
Chris@76
|
2867 if (isset($extra['topic']))
|
Chris@76
|
2868 {
|
Chris@76
|
2869 if (!is_numeric($extra['topic']))
|
Chris@76
|
2870 trigger_error('logAction(): data\'s topic is not a number', E_USER_NOTICE);
|
Chris@76
|
2871 $topic_id = empty($extra['topic']) ? '0' : (int)$extra['topic'];
|
Chris@76
|
2872 unset($extra['topic']);
|
Chris@76
|
2873 }
|
Chris@76
|
2874 else
|
Chris@76
|
2875 $topic_id = '0';
|
Chris@76
|
2876
|
Chris@76
|
2877 if (isset($extra['message']))
|
Chris@76
|
2878 {
|
Chris@76
|
2879 if (!is_numeric($extra['message']))
|
Chris@76
|
2880 trigger_error('logAction(): data\'s message is not a number', E_USER_NOTICE);
|
Chris@76
|
2881 $msg_id = empty($extra['message']) ? '0' : (int)$extra['message'];
|
Chris@76
|
2882 unset($extra['message']);
|
Chris@76
|
2883 }
|
Chris@76
|
2884 else
|
Chris@76
|
2885 $msg_id = '0';
|
Chris@76
|
2886
|
Chris@76
|
2887 // Is there an associated report on this?
|
Chris@76
|
2888 if (in_array($action, array('move', 'remove', 'split', 'merge')))
|
Chris@76
|
2889 {
|
Chris@76
|
2890 $request = $smcFunc['db_query']('', '
|
Chris@76
|
2891 SELECT id_report
|
Chris@76
|
2892 FROM {db_prefix}log_reported
|
Chris@76
|
2893 WHERE {raw:column_name} = {int:reported}
|
Chris@76
|
2894 LIMIT 1',
|
Chris@76
|
2895 array(
|
Chris@76
|
2896 'column_name' => !empty($msg_id) ? 'id_msg' : 'id_topic',
|
Chris@76
|
2897 'reported' => !empty($msg_id) ? $msg_id : $topic_id,
|
Chris@76
|
2898 ));
|
Chris@76
|
2899
|
Chris@76
|
2900 // Alright, if we get any result back, update open reports.
|
Chris@76
|
2901 if ($smcFunc['db_num_rows']($request) > 0)
|
Chris@76
|
2902 {
|
Chris@76
|
2903 require_once($sourcedir . '/ModerationCenter.php');
|
Chris@76
|
2904 updateSettings(array('last_mod_report_action' => time()));
|
Chris@76
|
2905 recountOpenReports();
|
Chris@76
|
2906 }
|
Chris@76
|
2907 $smcFunc['db_free_result']($request);
|
Chris@76
|
2908 }
|
Chris@76
|
2909
|
Chris@76
|
2910 // No point in doing anything else, if the log isn't even enabled.
|
Chris@76
|
2911 if (empty($modSettings['modlog_enabled']) || !isset($log_types[$log_type]))
|
Chris@76
|
2912 return false;
|
Chris@76
|
2913
|
Chris@76
|
2914 if (isset($extra['member']) && !is_numeric($extra['member']))
|
Chris@76
|
2915 trigger_error('logAction(): data\'s member is not a number', E_USER_NOTICE);
|
Chris@76
|
2916
|
Chris@76
|
2917 if (isset($extra['board']))
|
Chris@76
|
2918 {
|
Chris@76
|
2919 if (!is_numeric($extra['board']))
|
Chris@76
|
2920 trigger_error('logAction(): data\'s board is not a number', E_USER_NOTICE);
|
Chris@76
|
2921 $board_id = empty($extra['board']) ? '0' : (int)$extra['board'];
|
Chris@76
|
2922 unset($extra['board']);
|
Chris@76
|
2923 }
|
Chris@76
|
2924 else
|
Chris@76
|
2925 $board_id = '0';
|
Chris@76
|
2926
|
Chris@76
|
2927 if (isset($extra['board_to']))
|
Chris@76
|
2928 {
|
Chris@76
|
2929 if (!is_numeric($extra['board_to']))
|
Chris@76
|
2930 trigger_error('logAction(): data\'s board_to is not a number', E_USER_NOTICE);
|
Chris@76
|
2931 if (empty($board_id))
|
Chris@76
|
2932 {
|
Chris@76
|
2933 $board_id = empty($extra['board_to']) ? '0' : (int)$extra['board_to'];
|
Chris@76
|
2934 unset($extra['board_to']);
|
Chris@76
|
2935 }
|
Chris@76
|
2936 }
|
Chris@76
|
2937
|
Chris@76
|
2938 $smcFunc['db_insert']('',
|
Chris@76
|
2939 '{db_prefix}log_actions',
|
Chris@76
|
2940 array(
|
Chris@76
|
2941 'log_time' => 'int', 'id_log' => 'int', 'id_member' => 'int', 'ip' => 'string-16', 'action' => 'string',
|
Chris@76
|
2942 'id_board' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'extra' => 'string-65534',
|
Chris@76
|
2943 ),
|
Chris@76
|
2944 array(
|
Chris@76
|
2945 time(), $log_types[$log_type], $user_info['id'], $user_info['ip'], $action,
|
Chris@76
|
2946 $board_id, $topic_id, $msg_id, serialize($extra),
|
Chris@76
|
2947 ),
|
Chris@76
|
2948 array('id_action')
|
Chris@76
|
2949 );
|
Chris@76
|
2950
|
Chris@76
|
2951 return $smcFunc['db_insert_id']('{db_prefix}log_actions', 'id_action');
|
Chris@76
|
2952 }
|
Chris@76
|
2953
|
Chris@76
|
2954 // Track Statistics.
|
Chris@76
|
2955 function trackStats($stats = array())
|
Chris@76
|
2956 {
|
Chris@76
|
2957 global $modSettings, $smcFunc;
|
Chris@76
|
2958 static $cache_stats = array();
|
Chris@76
|
2959
|
Chris@76
|
2960 if (empty($modSettings['trackStats']))
|
Chris@76
|
2961 return false;
|
Chris@76
|
2962 if (!empty($stats))
|
Chris@76
|
2963 return $cache_stats = array_merge($cache_stats, $stats);
|
Chris@76
|
2964 elseif (empty($cache_stats))
|
Chris@76
|
2965 return false;
|
Chris@76
|
2966
|
Chris@76
|
2967 $setStringUpdate = '';
|
Chris@76
|
2968 $insert_keys = array();
|
Chris@76
|
2969 $date = strftime('%Y-%m-%d', forum_time(false));
|
Chris@76
|
2970 $update_parameters = array(
|
Chris@76
|
2971 'current_date' => $date,
|
Chris@76
|
2972 );
|
Chris@76
|
2973 foreach ($cache_stats as $field => $change)
|
Chris@76
|
2974 {
|
Chris@76
|
2975 $setStringUpdate .= '
|
Chris@76
|
2976 ' . $field . ' = ' . ($change === '+' ? $field . ' + 1' : '{int:' . $field . '}') . ',';
|
Chris@76
|
2977
|
Chris@76
|
2978 if ($change === '+')
|
Chris@76
|
2979 $cache_stats[$field] = 1;
|
Chris@76
|
2980 else
|
Chris@76
|
2981 $update_parameters[$field] = $change;
|
Chris@76
|
2982 $insert_keys[$field] = 'int';
|
Chris@76
|
2983 }
|
Chris@76
|
2984
|
Chris@76
|
2985 $smcFunc['db_query']('', '
|
Chris@76
|
2986 UPDATE {db_prefix}log_activity
|
Chris@76
|
2987 SET' . substr($setStringUpdate, 0, -1) . '
|
Chris@76
|
2988 WHERE date = {date:current_date}',
|
Chris@76
|
2989 $update_parameters
|
Chris@76
|
2990 );
|
Chris@76
|
2991 if ($smcFunc['db_affected_rows']() == 0)
|
Chris@76
|
2992 {
|
Chris@76
|
2993 $smcFunc['db_insert']('ignore',
|
Chris@76
|
2994 '{db_prefix}log_activity',
|
Chris@76
|
2995 array_merge($insert_keys, array('date' => 'date')),
|
Chris@76
|
2996 array_merge($cache_stats, array($date)),
|
Chris@76
|
2997 array('date')
|
Chris@76
|
2998 );
|
Chris@76
|
2999 }
|
Chris@76
|
3000
|
Chris@76
|
3001 // Don't do this again.
|
Chris@76
|
3002 $cache_stats = array();
|
Chris@76
|
3003
|
Chris@76
|
3004 return true;
|
Chris@76
|
3005 }
|
Chris@76
|
3006
|
Chris@76
|
3007 // Make sure the user isn't posting over and over again.
|
Chris@76
|
3008 function spamProtection($error_type)
|
Chris@76
|
3009 {
|
Chris@76
|
3010 global $modSettings, $txt, $user_info, $smcFunc;
|
Chris@76
|
3011
|
Chris@76
|
3012 // Certain types take less/more time.
|
Chris@76
|
3013 $timeOverrides = array(
|
Chris@76
|
3014 'login' => 2,
|
Chris@76
|
3015 'register' => 2,
|
Chris@76
|
3016 'sendtopc' => $modSettings['spamWaitTime'] * 4,
|
Chris@76
|
3017 'sendmail' => $modSettings['spamWaitTime'] * 5,
|
Chris@76
|
3018 'reporttm' => $modSettings['spamWaitTime'] * 4,
|
Chris@76
|
3019 'search' => !empty($modSettings['search_floodcontrol_time']) ? $modSettings['search_floodcontrol_time'] : 1,
|
Chris@76
|
3020 );
|
Chris@76
|
3021
|
Chris@76
|
3022 // Moderators are free...
|
Chris@76
|
3023 if (!allowedTo('moderate_board'))
|
Chris@76
|
3024 $timeLimit = isset($timeOverrides[$error_type]) ? $timeOverrides[$error_type] : $modSettings['spamWaitTime'];
|
Chris@76
|
3025 else
|
Chris@76
|
3026 $timeLimit = 2;
|
Chris@76
|
3027
|
Chris@76
|
3028 // Delete old entries...
|
Chris@76
|
3029 $smcFunc['db_query']('', '
|
Chris@76
|
3030 DELETE FROM {db_prefix}log_floodcontrol
|
Chris@76
|
3031 WHERE log_time < {int:log_time}
|
Chris@76
|
3032 AND log_type = {string:log_type}',
|
Chris@76
|
3033 array(
|
Chris@76
|
3034 'log_time' => time() - $timeLimit,
|
Chris@76
|
3035 'log_type' => $error_type,
|
Chris@76
|
3036 )
|
Chris@76
|
3037 );
|
Chris@76
|
3038
|
Chris@76
|
3039 // Add a new entry, deleting the old if necessary.
|
Chris@76
|
3040 $smcFunc['db_insert']('replace',
|
Chris@76
|
3041 '{db_prefix}log_floodcontrol',
|
Chris@76
|
3042 array('ip' => 'string-16', 'log_time' => 'int', 'log_type' => 'string'),
|
Chris@76
|
3043 array($user_info['ip'], time(), $error_type),
|
Chris@76
|
3044 array('ip', 'log_type')
|
Chris@76
|
3045 );
|
Chris@76
|
3046
|
Chris@76
|
3047 // If affected is 0 or 2, it was there already.
|
Chris@76
|
3048 if ($smcFunc['db_affected_rows']() != 1)
|
Chris@76
|
3049 {
|
Chris@76
|
3050 // Spammer! You only have to wait a *few* seconds!
|
Chris@76
|
3051 fatal_lang_error($error_type . 'WaitTime_broken', false, array($timeLimit));
|
Chris@76
|
3052 return true;
|
Chris@76
|
3053 }
|
Chris@76
|
3054
|
Chris@76
|
3055 // They haven't posted within the limit.
|
Chris@76
|
3056 return false;
|
Chris@76
|
3057 }
|
Chris@76
|
3058
|
Chris@76
|
3059 // Get the size of a specified image with better error handling.
|
Chris@76
|
3060 function url_image_size($url)
|
Chris@76
|
3061 {
|
Chris@76
|
3062 global $sourcedir;
|
Chris@76
|
3063
|
Chris@76
|
3064 // Make sure it is a proper URL.
|
Chris@76
|
3065 $url = str_replace(' ', '%20', $url);
|
Chris@76
|
3066
|
Chris@76
|
3067 // Can we pull this from the cache... please please?
|
Chris@76
|
3068 if (($temp = cache_get_data('url_image_size-' . md5($url), 240)) !== null)
|
Chris@76
|
3069 return $temp;
|
Chris@76
|
3070 $t = microtime();
|
Chris@76
|
3071
|
Chris@76
|
3072 // Get the host to pester...
|
Chris@76
|
3073 preg_match('~^\w+://(.+?)/(.*)$~', $url, $match);
|
Chris@76
|
3074
|
Chris@76
|
3075 // Can't figure it out, just try the image size.
|
Chris@76
|
3076 if ($url == '' || $url == 'http://' || $url == 'https://')
|
Chris@76
|
3077 {
|
Chris@76
|
3078 return false;
|
Chris@76
|
3079 }
|
Chris@76
|
3080 elseif (!isset($match[1]))
|
Chris@76
|
3081 {
|
Chris@76
|
3082 $size = @getimagesize($url);
|
Chris@76
|
3083 }
|
Chris@76
|
3084 else
|
Chris@76
|
3085 {
|
Chris@76
|
3086 // Try to connect to the server... give it half a second.
|
Chris@76
|
3087 $temp = 0;
|
Chris@76
|
3088 $fp = @fsockopen($match[1], 80, $temp, $temp, 0.5);
|
Chris@76
|
3089
|
Chris@76
|
3090 // Successful? Continue...
|
Chris@76
|
3091 if ($fp != false)
|
Chris@76
|
3092 {
|
Chris@76
|
3093 // Send the HEAD request (since we don't have to worry about chunked, HTTP/1.1 is fine here.)
|
Chris@76
|
3094 fwrite($fp, 'HEAD /' . $match[2] . ' HTTP/1.1' . "\r\n" . 'Host: ' . $match[1] . "\r\n" . 'User-Agent: PHP/SMF' . "\r\n" . 'Connection: close' . "\r\n\r\n");
|
Chris@76
|
3095
|
Chris@76
|
3096 // Read in the HTTP/1.1 or whatever.
|
Chris@76
|
3097 $test = substr(fgets($fp, 11), -1);
|
Chris@76
|
3098 fclose($fp);
|
Chris@76
|
3099
|
Chris@76
|
3100 // See if it returned a 404/403 or something.
|
Chris@76
|
3101 if ($test < 4)
|
Chris@76
|
3102 {
|
Chris@76
|
3103 $size = @getimagesize($url);
|
Chris@76
|
3104
|
Chris@76
|
3105 // This probably means allow_url_fopen is off, let's try GD.
|
Chris@76
|
3106 if ($size === false && function_exists('imagecreatefromstring'))
|
Chris@76
|
3107 {
|
Chris@76
|
3108 include_once($sourcedir . '/Subs-Package.php');
|
Chris@76
|
3109
|
Chris@76
|
3110 // It's going to hate us for doing this, but another request...
|
Chris@76
|
3111 $image = @imagecreatefromstring(fetch_web_data($url));
|
Chris@76
|
3112 if ($image !== false)
|
Chris@76
|
3113 {
|
Chris@76
|
3114 $size = array(imagesx($image), imagesy($image));
|
Chris@76
|
3115 imagedestroy($image);
|
Chris@76
|
3116 }
|
Chris@76
|
3117 }
|
Chris@76
|
3118 }
|
Chris@76
|
3119 }
|
Chris@76
|
3120 }
|
Chris@76
|
3121
|
Chris@76
|
3122 // If we didn't get it, we failed.
|
Chris@76
|
3123 if (!isset($size))
|
Chris@76
|
3124 $size = false;
|
Chris@76
|
3125
|
Chris@76
|
3126 // If this took a long time, we may never have to do it again, but then again we might...
|
Chris@76
|
3127 if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $t)) > 0.8)
|
Chris@76
|
3128 cache_put_data('url_image_size-' . md5($url), $size, 240);
|
Chris@76
|
3129
|
Chris@76
|
3130 // Didn't work.
|
Chris@76
|
3131 return $size;
|
Chris@76
|
3132 }
|
Chris@76
|
3133
|
Chris@76
|
3134 function determineTopicClass(&$topic_context)
|
Chris@76
|
3135 {
|
Chris@76
|
3136 // Set topic class depending on locked status and number of replies.
|
Chris@76
|
3137 if ($topic_context['is_very_hot'])
|
Chris@76
|
3138 $topic_context['class'] = 'veryhot';
|
Chris@76
|
3139 elseif ($topic_context['is_hot'])
|
Chris@76
|
3140 $topic_context['class'] = 'hot';
|
Chris@76
|
3141 else
|
Chris@76
|
3142 $topic_context['class'] = 'normal';
|
Chris@76
|
3143
|
Chris@76
|
3144 $topic_context['class'] .= $topic_context['is_poll'] ? '_poll' : '_post';
|
Chris@76
|
3145
|
Chris@76
|
3146 if ($topic_context['is_locked'])
|
Chris@76
|
3147 $topic_context['class'] .= '_locked';
|
Chris@76
|
3148
|
Chris@76
|
3149 if ($topic_context['is_sticky'])
|
Chris@76
|
3150 $topic_context['class'] .= '_sticky';
|
Chris@76
|
3151
|
Chris@76
|
3152 // This is so old themes will still work.
|
Chris@76
|
3153 $topic_context['extended_class'] = &$topic_context['class'];
|
Chris@76
|
3154 }
|
Chris@76
|
3155
|
Chris@76
|
3156 // Sets up the basic theme context stuff.
|
Chris@76
|
3157 function setupThemeContext($forceload = false)
|
Chris@76
|
3158 {
|
Chris@76
|
3159 global $modSettings, $user_info, $scripturl, $context, $settings, $options, $txt, $maintenance;
|
Chris@76
|
3160 global $user_settings, $smcFunc;
|
Chris@76
|
3161 static $loaded = false;
|
Chris@76
|
3162
|
Chris@76
|
3163 // Under SSI this function can be called more then once. That can cause some problems.
|
Chris@76
|
3164 // So only run the function once unless we are forced to run it again.
|
Chris@76
|
3165 if ($loaded && !$forceload)
|
Chris@76
|
3166 return;
|
Chris@76
|
3167
|
Chris@76
|
3168 $loaded = true;
|
Chris@76
|
3169
|
Chris@76
|
3170 $context['in_maintenance'] = !empty($maintenance);
|
Chris@76
|
3171 $context['current_time'] = timeformat(time(), false);
|
Chris@76
|
3172 $context['current_action'] = isset($_GET['action']) ? $_GET['action'] : '';
|
Chris@76
|
3173 $context['show_quick_login'] = !empty($modSettings['enableVBStyleLogin']) && $user_info['is_guest'];
|
Chris@76
|
3174
|
Chris@76
|
3175 // Get some news...
|
Chris@76
|
3176 $context['news_lines'] = explode("\n", str_replace("\r", '', trim(addslashes($modSettings['news']))));
|
Chris@76
|
3177 $context['fader_news_lines'] = array();
|
Chris@76
|
3178 for ($i = 0, $n = count($context['news_lines']); $i < $n; $i++)
|
Chris@76
|
3179 {
|
Chris@76
|
3180 if (trim($context['news_lines'][$i]) == '')
|
Chris@76
|
3181 continue;
|
Chris@76
|
3182
|
Chris@76
|
3183 // Clean it up for presentation ;).
|
Chris@76
|
3184 $context['news_lines'][$i] = parse_bbc(stripslashes(trim($context['news_lines'][$i])), true, 'news' . $i);
|
Chris@76
|
3185
|
Chris@76
|
3186 // Gotta be special for the javascript.
|
Chris@76
|
3187 $context['fader_news_lines'][$i] = strtr(addslashes($context['news_lines'][$i]), array('/' => '\/', '<a href=' => '<a hre" + "f='));
|
Chris@76
|
3188 }
|
Chris@76
|
3189 $context['random_news_line'] = $context['news_lines'][mt_rand(0, count($context['news_lines']) - 1)];
|
Chris@76
|
3190
|
Chris@76
|
3191 if (!$user_info['is_guest'])
|
Chris@76
|
3192 {
|
Chris@76
|
3193 $context['user']['messages'] = &$user_info['messages'];
|
Chris@76
|
3194 $context['user']['unread_messages'] = &$user_info['unread_messages'];
|
Chris@76
|
3195
|
Chris@76
|
3196 // Personal message popup...
|
Chris@76
|
3197 if ($user_info['unread_messages'] > (isset($_SESSION['unread_messages']) ? $_SESSION['unread_messages'] : 0))
|
Chris@76
|
3198 $context['user']['popup_messages'] = true;
|
Chris@76
|
3199 else
|
Chris@76
|
3200 $context['user']['popup_messages'] = false;
|
Chris@76
|
3201 $_SESSION['unread_messages'] = $user_info['unread_messages'];
|
Chris@76
|
3202
|
Chris@76
|
3203 if (allowedTo('moderate_forum'))
|
Chris@76
|
3204 $context['unapproved_members'] = (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 2) || !empty($modSettings['approveAccountDeletion']) ? $modSettings['unapprovedMembers'] : 0;
|
Chris@76
|
3205 $context['show_open_reports'] = empty($user_settings['mod_prefs']) || $user_settings['mod_prefs'][0] == 1;
|
Chris@76
|
3206
|
Chris@76
|
3207 $context['user']['avatar'] = array();
|
Chris@76
|
3208
|
Chris@76
|
3209 // Figure out the avatar... uploaded?
|
Chris@76
|
3210 if ($user_info['avatar']['url'] == '' && !empty($user_info['avatar']['id_attach']))
|
Chris@76
|
3211 $context['user']['avatar']['href'] = $user_info['avatar']['custom_dir'] ? $modSettings['custom_avatar_url'] . '/' . $user_info['avatar']['filename'] : $scripturl . '?action=dlattach;attach=' . $user_info['avatar']['id_attach'] . ';type=avatar';
|
Chris@76
|
3212 // Full URL?
|
Chris@76
|
3213 elseif (substr($user_info['avatar']['url'], 0, 7) == 'http://')
|
Chris@76
|
3214 {
|
Chris@76
|
3215 $context['user']['avatar']['href'] = $user_info['avatar']['url'];
|
Chris@76
|
3216
|
Chris@76
|
3217 if ($modSettings['avatar_action_too_large'] == 'option_html_resize' || $modSettings['avatar_action_too_large'] == 'option_js_resize')
|
Chris@76
|
3218 {
|
Chris@76
|
3219 if (!empty($modSettings['avatar_max_width_external']))
|
Chris@76
|
3220 $context['user']['avatar']['width'] = $modSettings['avatar_max_width_external'];
|
Chris@76
|
3221 if (!empty($modSettings['avatar_max_height_external']))
|
Chris@76
|
3222 $context['user']['avatar']['height'] = $modSettings['avatar_max_height_external'];
|
Chris@76
|
3223 }
|
Chris@76
|
3224 }
|
Chris@76
|
3225 // Otherwise we assume it's server stored?
|
Chris@76
|
3226 elseif ($user_info['avatar']['url'] != '')
|
Chris@76
|
3227 $context['user']['avatar']['href'] = $modSettings['avatar_url'] . '/' . htmlspecialchars($user_info['avatar']['url']);
|
Chris@76
|
3228
|
Chris@76
|
3229 if (!empty($context['user']['avatar']))
|
Chris@76
|
3230 $context['user']['avatar']['image'] = '<img src="' . $context['user']['avatar']['href'] . '"' . (isset($context['user']['avatar']['width']) ? ' width="' . $context['user']['avatar']['width'] . '"' : '') . (isset($context['user']['avatar']['height']) ? ' height="' . $context['user']['avatar']['height'] . '"' : '') . ' alt="" class="avatar" />';
|
Chris@76
|
3231
|
Chris@76
|
3232 // Figure out how long they've been logged in.
|
Chris@76
|
3233 $context['user']['total_time_logged_in'] = array(
|
Chris@76
|
3234 'days' => floor($user_info['total_time_logged_in'] / 86400),
|
Chris@76
|
3235 'hours' => floor(($user_info['total_time_logged_in'] % 86400) / 3600),
|
Chris@76
|
3236 'minutes' => floor(($user_info['total_time_logged_in'] % 3600) / 60)
|
Chris@76
|
3237 );
|
Chris@76
|
3238 }
|
Chris@76
|
3239 else
|
Chris@76
|
3240 {
|
Chris@76
|
3241 $context['user']['messages'] = 0;
|
Chris@76
|
3242 $context['user']['unread_messages'] = 0;
|
Chris@76
|
3243 $context['user']['avatar'] = array();
|
Chris@76
|
3244 $context['user']['total_time_logged_in'] = array('days' => 0, 'hours' => 0, 'minutes' => 0);
|
Chris@76
|
3245 $context['user']['popup_messages'] = false;
|
Chris@76
|
3246
|
Chris@76
|
3247 if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 1)
|
Chris@76
|
3248 $txt['welcome_guest'] .= $txt['welcome_guest_activate'];
|
Chris@76
|
3249
|
Chris@76
|
3250 // If we've upgraded recently, go easy on the passwords.
|
Chris@76
|
3251 if (!empty($modSettings['disableHashTime']) && ($modSettings['disableHashTime'] == 1 || time() < $modSettings['disableHashTime']))
|
Chris@76
|
3252 $context['disable_login_hashing'] = true;
|
Chris@76
|
3253 elseif ($context['browser']['is_ie5'] || $context['browser']['is_ie5.5'])
|
Chris@76
|
3254 $context['disable_login_hashing'] = true;
|
Chris@76
|
3255 }
|
Chris@76
|
3256
|
Chris@76
|
3257 // Setup the main menu items.
|
Chris@76
|
3258 setupMenuContext();
|
Chris@76
|
3259
|
Chris@76
|
3260 if (empty($settings['theme_version']))
|
Chris@76
|
3261 $context['show_vBlogin'] = $context['show_quick_login'];
|
Chris@76
|
3262
|
Chris@76
|
3263 // This is here because old index templates might still use it.
|
Chris@76
|
3264 $context['show_news'] = !empty($settings['enable_news']);
|
Chris@76
|
3265
|
Chris@76
|
3266 // This is done to allow theme authors to customize it as they want.
|
Chris@76
|
3267 $context['show_pm_popup'] = $context['user']['popup_messages'] && !empty($options['popup_messages']) && (!isset($_REQUEST['action']) || $_REQUEST['action'] != 'pm');
|
Chris@76
|
3268
|
Chris@76
|
3269 // Resize avatars the fancy, but non-GD requiring way.
|
Chris@76
|
3270 if ($modSettings['avatar_action_too_large'] == 'option_js_resize' && (!empty($modSettings['avatar_max_width_external']) || !empty($modSettings['avatar_max_height_external'])))
|
Chris@76
|
3271 {
|
Chris@76
|
3272 $context['html_headers'] .= '
|
Chris@76
|
3273 <script type="text/javascript"><!-- // --><![CDATA[
|
Chris@76
|
3274 var smf_avatarMaxWidth = ' . (int) $modSettings['avatar_max_width_external'] . ';
|
Chris@76
|
3275 var smf_avatarMaxHeight = ' . (int) $modSettings['avatar_max_height_external'] . ';';
|
Chris@76
|
3276
|
Chris@76
|
3277 if (!$context['browser']['is_ie'] && !$context['browser']['is_mac_ie'])
|
Chris@76
|
3278 $context['html_headers'] .= '
|
Chris@76
|
3279 window.addEventListener("load", smf_avatarResize, false);';
|
Chris@76
|
3280 else
|
Chris@76
|
3281 $context['html_headers'] .= '
|
Chris@76
|
3282 var window_oldAvatarOnload = window.onload;
|
Chris@76
|
3283 window.onload = smf_avatarResize;';
|
Chris@76
|
3284
|
Chris@76
|
3285 // !!! Move this over to script.js?
|
Chris@76
|
3286 $context['html_headers'] .= '
|
Chris@76
|
3287 // ]]></script>';
|
Chris@76
|
3288 }
|
Chris@76
|
3289
|
Chris@76
|
3290 // This looks weird, but it's because BoardIndex.php references the variable.
|
Chris@76
|
3291 $context['common_stats']['latest_member'] = array(
|
Chris@76
|
3292 'id' => $modSettings['latestMember'],
|
Chris@76
|
3293 'name' => $modSettings['latestRealName'],
|
Chris@76
|
3294 'href' => $scripturl . '?action=profile;u=' . $modSettings['latestMember'],
|
Chris@76
|
3295 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $modSettings['latestMember'] . '">' . $modSettings['latestRealName'] . '</a>',
|
Chris@76
|
3296 );
|
Chris@76
|
3297 $context['common_stats'] = array(
|
Chris@76
|
3298 'total_posts' => comma_format($modSettings['totalMessages']),
|
Chris@76
|
3299 'total_topics' => comma_format($modSettings['totalTopics']),
|
Chris@76
|
3300 'total_members' => comma_format($modSettings['totalMembers']),
|
Chris@76
|
3301 'latest_member' => $context['common_stats']['latest_member'],
|
Chris@76
|
3302 );
|
Chris@76
|
3303
|
Chris@76
|
3304 if (empty($settings['theme_version']))
|
Chris@76
|
3305 $context['html_headers'] .= '
|
Chris@76
|
3306 <script type="text/javascript"><!-- // --><![CDATA[
|
Chris@76
|
3307 var smf_scripturl = "' . $scripturl . '";
|
Chris@76
|
3308 // ]]></script>';
|
Chris@76
|
3309
|
Chris@76
|
3310 if (!isset($context['page_title']))
|
Chris@76
|
3311 $context['page_title'] = '';
|
Chris@76
|
3312
|
Chris@76
|
3313 // Set some specific vars.
|
Chris@76
|
3314 $context['page_title_html_safe'] = $smcFunc['htmlspecialchars'](un_htmlspecialchars($context['page_title']));
|
Chris@76
|
3315 $context['meta_keywords'] = !empty($modSettings['meta_keywords']) ? $smcFunc['htmlspecialchars']($modSettings['meta_keywords']) : '';
|
Chris@76
|
3316 }
|
Chris@76
|
3317
|
Chris@76
|
3318 // This is the only template included in the sources...
|
Chris@76
|
3319 function template_rawdata()
|
Chris@76
|
3320 {
|
Chris@76
|
3321 global $context;
|
Chris@76
|
3322
|
Chris@76
|
3323 echo $context['raw_data'];
|
Chris@76
|
3324 }
|
Chris@76
|
3325
|
Chris@76
|
3326 function template_header()
|
Chris@76
|
3327 {
|
Chris@76
|
3328 global $txt, $modSettings, $context, $settings, $user_info, $boarddir, $cachedir;
|
Chris@76
|
3329
|
Chris@76
|
3330 setupThemeContext();
|
Chris@76
|
3331
|
Chris@76
|
3332 // Print stuff to prevent caching of pages (except on attachment errors, etc.)
|
Chris@76
|
3333 if (empty($context['no_last_modified']))
|
Chris@76
|
3334 {
|
Chris@76
|
3335 header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
Chris@76
|
3336 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
Chris@76
|
3337
|
Chris@76
|
3338 // Are we debugging the template/html content?
|
Chris@76
|
3339 if (!isset($_REQUEST['xml']) && isset($_GET['debug']) && !$context['browser']['is_ie'] && !WIRELESS)
|
Chris@76
|
3340 header('Content-Type: application/xhtml+xml');
|
Chris@76
|
3341 elseif (!isset($_REQUEST['xml']) && !WIRELESS)
|
Chris@76
|
3342 header('Content-Type: text/html; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set']));
|
Chris@76
|
3343 }
|
Chris@76
|
3344
|
Chris@76
|
3345 header('Content-Type: text/' . (isset($_REQUEST['xml']) ? 'xml' : 'html') . '; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set']));
|
Chris@76
|
3346
|
Chris@76
|
3347 $checked_securityFiles = false;
|
Chris@76
|
3348 $showed_banned = false;
|
Chris@76
|
3349 foreach ($context['template_layers'] as $layer)
|
Chris@76
|
3350 {
|
Chris@76
|
3351 loadSubTemplate($layer . '_above', true);
|
Chris@76
|
3352
|
Chris@76
|
3353 // May seem contrived, but this is done in case the body and main layer aren't there...
|
Chris@76
|
3354 if (in_array($layer, array('body', 'main')) && allowedTo('admin_forum') && !$user_info['is_guest'] && !$checked_securityFiles)
|
Chris@76
|
3355 {
|
Chris@76
|
3356 $checked_securityFiles = true;
|
Chris@76
|
3357 $securityFiles = array('install.php', 'webinstall.php', 'upgrade.php', 'convert.php', 'repair_paths.php', 'repair_settings.php', 'Settings.php~', 'Settings_bak.php~');
|
Chris@76
|
3358 foreach ($securityFiles as $i => $securityFile)
|
Chris@76
|
3359 {
|
Chris@76
|
3360 if (!file_exists($boarddir . '/' . $securityFile))
|
Chris@76
|
3361 unset($securityFiles[$i]);
|
Chris@76
|
3362 }
|
Chris@76
|
3363
|
Chris@76
|
3364 if (!empty($securityFiles) || (!empty($modSettings['cache_enable']) && !is_writable($cachedir)))
|
Chris@76
|
3365 {
|
Chris@76
|
3366 echo '
|
Chris@76
|
3367 <div class="errorbox">
|
Chris@76
|
3368 <p class="alert">!!</p>
|
Chris@76
|
3369 <h3>', empty($securityFiles) ? $txt['cache_writable_head'] : $txt['security_risk'], '</h3>
|
Chris@76
|
3370 <p>';
|
Chris@76
|
3371
|
Chris@76
|
3372 foreach ($securityFiles as $securityFile)
|
Chris@76
|
3373 {
|
Chris@76
|
3374 echo '
|
Chris@76
|
3375 ', $txt['not_removed'], '<strong>', $securityFile, '</strong>!<br />';
|
Chris@76
|
3376
|
Chris@76
|
3377 if ($securityFile == 'Settings.php~' || $securityFile == 'Settings_bak.php~')
|
Chris@76
|
3378 echo '
|
Chris@76
|
3379 ', sprintf($txt['not_removed_extra'], $securityFile, substr($securityFile, 0, -1)), '<br />';
|
Chris@76
|
3380 }
|
Chris@76
|
3381
|
Chris@76
|
3382 if (!empty($modSettings['cache_enable']) && !is_writable($cachedir))
|
Chris@76
|
3383 echo '
|
Chris@76
|
3384 <strong>', $txt['cache_writable'], '</strong><br />';
|
Chris@76
|
3385
|
Chris@76
|
3386 echo '
|
Chris@76
|
3387 </p>
|
Chris@76
|
3388 </div>';
|
Chris@76
|
3389 }
|
Chris@76
|
3390 }
|
Chris@76
|
3391 // If the user is banned from posting inform them of it.
|
Chris@76
|
3392 elseif (in_array($layer, array('main', 'body')) && isset($_SESSION['ban']['cannot_post']) && !$showed_banned)
|
Chris@76
|
3393 {
|
Chris@76
|
3394 $showed_banned = true;
|
Chris@76
|
3395 echo '
|
Chris@76
|
3396 <div class="windowbg alert" style="margin: 2ex; padding: 2ex; border: 2px dashed red;">
|
Chris@76
|
3397 ', sprintf($txt['you_are_post_banned'], $user_info['is_guest'] ? $txt['guest_title'] : $user_info['name']);
|
Chris@76
|
3398
|
Chris@76
|
3399 if (!empty($_SESSION['ban']['cannot_post']['reason']))
|
Chris@76
|
3400 echo '
|
Chris@76
|
3401 <div style="padding-left: 4ex; padding-top: 1ex;">', $_SESSION['ban']['cannot_post']['reason'], '</div>';
|
Chris@76
|
3402
|
Chris@76
|
3403 if (!empty($_SESSION['ban']['expire_time']))
|
Chris@76
|
3404 echo '
|
Chris@76
|
3405 <div>', sprintf($txt['your_ban_expires'], timeformat($_SESSION['ban']['expire_time'], false)), '</div>';
|
Chris@76
|
3406 else
|
Chris@76
|
3407 echo '
|
Chris@76
|
3408 <div>', $txt['your_ban_expires_never'], '</div>';
|
Chris@76
|
3409
|
Chris@76
|
3410 echo '
|
Chris@76
|
3411 </div>';
|
Chris@76
|
3412 }
|
Chris@76
|
3413 }
|
Chris@76
|
3414
|
Chris@76
|
3415 if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'defaults' && isset($settings['default_template']))
|
Chris@76
|
3416 {
|
Chris@76
|
3417 $settings['theme_url'] = $settings['default_theme_url'];
|
Chris@76
|
3418 $settings['images_url'] = $settings['default_images_url'];
|
Chris@76
|
3419 $settings['theme_dir'] = $settings['default_theme_dir'];
|
Chris@76
|
3420 }
|
Chris@76
|
3421 }
|
Chris@76
|
3422
|
Chris@76
|
3423 // Show the copyright...
|
Chris@76
|
3424 function theme_copyright($get_it = false)
|
Chris@76
|
3425 {
|
Chris@76
|
3426 global $forum_copyright, $context, $boardurl, $forum_version, $txt, $modSettings;
|
Chris@76
|
3427
|
Chris@76
|
3428 // Don't display copyright for things like SSI.
|
Chris@76
|
3429 if (!isset($forum_version))
|
Chris@76
|
3430 return;
|
Chris@76
|
3431
|
Chris@76
|
3432 // Put in the version...
|
Chris@76
|
3433 $forum_copyright = sprintf($forum_copyright, $forum_version);
|
Chris@76
|
3434
|
Chris@76
|
3435 echo '
|
Chris@76
|
3436 <span class="smalltext" style="display: inline; visibility: visible; font-family: Verdana, Arial, sans-serif;">' . $forum_copyright . '
|
Chris@76
|
3437 </span>';
|
Chris@76
|
3438 }
|
Chris@76
|
3439
|
Chris@76
|
3440 function template_footer()
|
Chris@76
|
3441 {
|
Chris@76
|
3442 global $context, $settings, $modSettings, $time_start, $db_count;
|
Chris@76
|
3443
|
Chris@76
|
3444 // Show the load time? (only makes sense for the footer.)
|
Chris@76
|
3445 $context['show_load_time'] = !empty($modSettings['timeLoadPageEnable']);
|
Chris@76
|
3446 $context['load_time'] = round(array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)), 3);
|
Chris@76
|
3447 $context['load_queries'] = $db_count;
|
Chris@76
|
3448
|
Chris@76
|
3449 if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'defaults' && isset($settings['default_template']))
|
Chris@76
|
3450 {
|
Chris@76
|
3451 $settings['theme_url'] = $settings['actual_theme_url'];
|
Chris@76
|
3452 $settings['images_url'] = $settings['actual_images_url'];
|
Chris@76
|
3453 $settings['theme_dir'] = $settings['actual_theme_dir'];
|
Chris@76
|
3454 }
|
Chris@76
|
3455
|
Chris@76
|
3456 foreach (array_reverse($context['template_layers']) as $layer)
|
Chris@76
|
3457 loadSubTemplate($layer . '_below', true);
|
Chris@76
|
3458
|
Chris@76
|
3459 }
|
Chris@76
|
3460
|
Chris@76
|
3461 // Debugging.
|
Chris@76
|
3462 function db_debug_junk()
|
Chris@76
|
3463 {
|
Chris@76
|
3464 global $context, $scripturl, $boarddir, $modSettings, $boarddir;
|
Chris@76
|
3465 global $db_cache, $db_count, $db_show_debug, $cache_count, $cache_hits, $txt;
|
Chris@76
|
3466
|
Chris@76
|
3467 // Add to Settings.php if you want to show the debugging information.
|
Chris@76
|
3468 if (!isset($db_show_debug) || $db_show_debug !== true || (isset($_GET['action']) && $_GET['action'] == 'viewquery') || WIRELESS)
|
Chris@76
|
3469 return;
|
Chris@76
|
3470
|
Chris@76
|
3471 if (empty($_SESSION['view_queries']))
|
Chris@76
|
3472 $_SESSION['view_queries'] = 0;
|
Chris@76
|
3473 if (empty($context['debug']['language_files']))
|
Chris@76
|
3474 $context['debug']['language_files'] = array();
|
Chris@76
|
3475 if (empty($context['debug']['sheets']))
|
Chris@76
|
3476 $context['debug']['sheets'] = array();
|
Chris@76
|
3477
|
Chris@76
|
3478 $files = get_included_files();
|
Chris@76
|
3479 $total_size = 0;
|
Chris@76
|
3480 for ($i = 0, $n = count($files); $i < $n; $i++)
|
Chris@76
|
3481 {
|
Chris@76
|
3482 if (file_exists($files[$i]))
|
Chris@76
|
3483 $total_size += filesize($files[$i]);
|
Chris@76
|
3484 $files[$i] = strtr($files[$i], array($boarddir => '.'));
|
Chris@76
|
3485 }
|
Chris@76
|
3486
|
Chris@76
|
3487 $warnings = 0;
|
Chris@76
|
3488 if (!empty($db_cache))
|
Chris@76
|
3489 {
|
Chris@76
|
3490 foreach ($db_cache as $q => $qq)
|
Chris@76
|
3491 {
|
Chris@76
|
3492 if (!empty($qq['w']))
|
Chris@76
|
3493 $warnings += count($qq['w']);
|
Chris@76
|
3494 }
|
Chris@76
|
3495
|
Chris@76
|
3496 $_SESSION['debug'] = &$db_cache;
|
Chris@76
|
3497 }
|
Chris@76
|
3498
|
Chris@76
|
3499 // Gotta have valid HTML ;).
|
Chris@76
|
3500 $temp = ob_get_contents();
|
Chris@76
|
3501 if (function_exists('ob_clean'))
|
Chris@76
|
3502 ob_clean();
|
Chris@76
|
3503 else
|
Chris@76
|
3504 {
|
Chris@76
|
3505 ob_end_clean();
|
Chris@76
|
3506 ob_start('ob_sessrewrite');
|
Chris@76
|
3507 }
|
Chris@76
|
3508
|
Chris@76
|
3509 echo preg_replace('~</body>\s*</html>~', '', $temp), '
|
Chris@76
|
3510 <div class="smalltext" style="text-align: left; margin: 1ex;">
|
Chris@76
|
3511 ', $txt['debug_templates'], count($context['debug']['templates']), ': <em>', implode('</em>, <em>', $context['debug']['templates']), '</em>.<br />
|
Chris@76
|
3512 ', $txt['debug_subtemplates'], count($context['debug']['sub_templates']), ': <em>', implode('</em>, <em>', $context['debug']['sub_templates']), '</em>.<br />
|
Chris@76
|
3513 ', $txt['debug_language_files'], count($context['debug']['language_files']), ': <em>', implode('</em>, <em>', $context['debug']['language_files']), '</em>.<br />
|
Chris@76
|
3514 ', $txt['debug_stylesheets'], count($context['debug']['sheets']), ': <em>', implode('</em>, <em>', $context['debug']['sheets']), '</em>.<br />
|
Chris@76
|
3515 ', $txt['debug_files_included'], count($files), ' - ', round($total_size / 1024), $txt['debug_kb'], ' (<a href="javascript:void(0);" onclick="document.getElementById(\'debug_include_info\').style.display = \'inline\'; this.style.display = \'none\'; return false;">', $txt['debug_show'], '</a><span id="debug_include_info" style="display: none;"><em>', implode('</em>, <em>', $files), '</em></span>)<br />';
|
Chris@76
|
3516
|
Chris@76
|
3517 if (!empty($modSettings['cache_enable']) && !empty($cache_hits))
|
Chris@76
|
3518 {
|
Chris@76
|
3519 $entries = array();
|
Chris@76
|
3520 $total_t = 0;
|
Chris@76
|
3521 $total_s = 0;
|
Chris@76
|
3522 foreach ($cache_hits as $cache_hit)
|
Chris@76
|
3523 {
|
Chris@76
|
3524 $entries[] = $cache_hit['d'] . ' ' . $cache_hit['k'] . ': ' . sprintf($txt['debug_cache_seconds_bytes'], comma_format($cache_hit['t'], 5), $cache_hit['s']);
|
Chris@76
|
3525 $total_t += $cache_hit['t'];
|
Chris@76
|
3526 $total_s += $cache_hit['s'];
|
Chris@76
|
3527 }
|
Chris@76
|
3528
|
Chris@76
|
3529 echo '
|
Chris@76
|
3530 ', $txt['debug_cache_hits'], $cache_count, ': ', sprintf($txt['debug_cache_seconds_bytes_total'], comma_format($total_t, 5), comma_format($total_s)), ' (<a href="javascript:void(0);" onclick="document.getElementById(\'debug_cache_info\').style.display = \'inline\'; this.style.display = \'none\'; return false;">', $txt['debug_show'], '</a><span id="debug_cache_info" style="display: none;"><em>', implode('</em>, <em>', $entries), '</em></span>)<br />';
|
Chris@76
|
3531 }
|
Chris@76
|
3532
|
Chris@76
|
3533 echo '
|
Chris@76
|
3534 <a href="', $scripturl, '?action=viewquery" target="_blank" class="new_win">', $warnings == 0 ? sprintf($txt['debug_queries_used'], (int) $db_count) : sprintf($txt['debug_queries_used_and_warnings'], (int) $db_count, $warnings), '</a><br />
|
Chris@76
|
3535 <br />';
|
Chris@76
|
3536
|
Chris@76
|
3537 if ($_SESSION['view_queries'] == 1 && !empty($db_cache))
|
Chris@76
|
3538 foreach ($db_cache as $q => $qq)
|
Chris@76
|
3539 {
|
Chris@76
|
3540 $is_select = substr(trim($qq['q']), 0, 6) == 'SELECT' || preg_match('~^INSERT(?: IGNORE)? INTO \w+(?:\s+\([^)]+\))?\s+SELECT .+$~s', trim($qq['q'])) != 0;
|
Chris@76
|
3541 // Temporary tables created in earlier queries are not explainable.
|
Chris@76
|
3542 if ($is_select)
|
Chris@76
|
3543 {
|
Chris@76
|
3544 foreach (array('log_topics_unread', 'topics_posted_in', 'tmp_log_search_topics', 'tmp_log_search_messages') as $tmp)
|
Chris@76
|
3545 if (strpos(trim($qq['q']), $tmp) !== false)
|
Chris@76
|
3546 {
|
Chris@76
|
3547 $is_select = false;
|
Chris@76
|
3548 break;
|
Chris@76
|
3549 }
|
Chris@76
|
3550 }
|
Chris@76
|
3551 // But actual creation of the temporary tables are.
|
Chris@76
|
3552 elseif (preg_match('~^CREATE TEMPORARY TABLE .+?SELECT .+$~s', trim($qq['q'])) != 0)
|
Chris@76
|
3553 $is_select = true;
|
Chris@76
|
3554
|
Chris@76
|
3555 // Make the filenames look a bit better.
|
Chris@76
|
3556 if (isset($qq['f']))
|
Chris@76
|
3557 $qq['f'] = preg_replace('~^' . preg_quote($boarddir, '~') . '~', '...', $qq['f']);
|
Chris@76
|
3558
|
Chris@76
|
3559 echo '
|
Chris@76
|
3560 <strong>', $is_select ? '<a href="' . $scripturl . '?action=viewquery;qq=' . ($q + 1) . '#qq' . $q . '" target="_blank" class="new_win" style="text-decoration: none;">' : '', nl2br(str_replace("\t", ' ', htmlspecialchars(ltrim($qq['q'], "\n\r")))) . ($is_select ? '</a></strong>' : '</strong>') . '<br />
|
Chris@76
|
3561 ';
|
Chris@76
|
3562 if (!empty($qq['f']) && !empty($qq['l']))
|
Chris@76
|
3563 echo sprintf($txt['debug_query_in_line'], $qq['f'], $qq['l']);
|
Chris@76
|
3564
|
Chris@76
|
3565 if (isset($qq['s'], $qq['t']) && isset($txt['debug_query_which_took_at']))
|
Chris@76
|
3566 echo sprintf($txt['debug_query_which_took_at'], round($qq['t'], 8), round($qq['s'], 8)) . '<br />';
|
Chris@76
|
3567 elseif (isset($qq['t']))
|
Chris@76
|
3568 echo sprintf($txt['debug_query_which_took'], round($qq['t'], 8)) . '<br />';
|
Chris@76
|
3569 echo '
|
Chris@76
|
3570 <br />';
|
Chris@76
|
3571 }
|
Chris@76
|
3572
|
Chris@76
|
3573 echo '
|
Chris@76
|
3574 <a href="' . $scripturl . '?action=viewquery;sa=hide">', $txt['debug_' . (empty($_SESSION['view_queries']) ? 'show' : 'hide') . '_queries'], '</a>
|
Chris@76
|
3575 </div></body></html>';
|
Chris@76
|
3576 }
|
Chris@76
|
3577
|
Chris@76
|
3578 // Get an attachment's encrypted filename. If $new is true, won't check for file existence.
|
Chris@76
|
3579 function getAttachmentFilename($filename, $attachment_id, $dir = null, $new = false, $file_hash = '')
|
Chris@76
|
3580 {
|
Chris@76
|
3581 global $modSettings, $smcFunc;
|
Chris@76
|
3582
|
Chris@76
|
3583 // Just make up a nice hash...
|
Chris@76
|
3584 if ($new)
|
Chris@76
|
3585 return sha1(md5($filename . time()) . mt_rand());
|
Chris@76
|
3586
|
Chris@76
|
3587 // Grab the file hash if it wasn't added.
|
Chris@76
|
3588 if ($file_hash === '')
|
Chris@76
|
3589 {
|
Chris@76
|
3590 $request = $smcFunc['db_query']('', '
|
Chris@76
|
3591 SELECT file_hash
|
Chris@76
|
3592 FROM {db_prefix}attachments
|
Chris@76
|
3593 WHERE id_attach = {int:id_attach}',
|
Chris@76
|
3594 array(
|
Chris@76
|
3595 'id_attach' => $attachment_id,
|
Chris@76
|
3596 ));
|
Chris@76
|
3597
|
Chris@76
|
3598 if ($smcFunc['db_num_rows']($request) === 0)
|
Chris@76
|
3599 return false;
|
Chris@76
|
3600
|
Chris@76
|
3601 list ($file_hash) = $smcFunc['db_fetch_row']($request);
|
Chris@76
|
3602 $smcFunc['db_free_result']($request);
|
Chris@76
|
3603 }
|
Chris@76
|
3604
|
Chris@76
|
3605 // In case of files from the old system, do a legacy call.
|
Chris@76
|
3606 if (empty($file_hash))
|
Chris@76
|
3607 return getLegacyAttachmentFilename($filename, $attachment_id, $dir, $new);
|
Chris@76
|
3608
|
Chris@76
|
3609 // Are we using multiple directories?
|
Chris@76
|
3610 if (!empty($modSettings['currentAttachmentUploadDir']))
|
Chris@76
|
3611 {
|
Chris@76
|
3612 if (!is_array($modSettings['attachmentUploadDir']))
|
Chris@76
|
3613 $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
|
Chris@76
|
3614 $path = $modSettings['attachmentUploadDir'][$dir];
|
Chris@76
|
3615 }
|
Chris@76
|
3616 else
|
Chris@76
|
3617 $path = $modSettings['attachmentUploadDir'];
|
Chris@76
|
3618
|
Chris@76
|
3619 return $path . '/' . $attachment_id . '_' . $file_hash;
|
Chris@76
|
3620 }
|
Chris@76
|
3621
|
Chris@76
|
3622 // Older attachments may still use this function.
|
Chris@76
|
3623 function getLegacyAttachmentFilename($filename, $attachment_id, $dir = null, $new = false)
|
Chris@76
|
3624 {
|
Chris@76
|
3625 global $modSettings, $db_character_set;
|
Chris@76
|
3626
|
Chris@76
|
3627 $clean_name = $filename;
|
Chris@76
|
3628 // Remove international characters (windows-1252)
|
Chris@76
|
3629 // These lines should never be needed again. Still, behave.
|
Chris@76
|
3630 if (empty($db_character_set) || $db_character_set != 'utf8')
|
Chris@76
|
3631 {
|
Chris@76
|
3632 $clean_name = strtr($filename,
|
Chris@76
|
3633 "\x8a\x8e\x9a\x9e\x9f\xc0\xc1\xc2\xc3\xc4\xc5\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd1\xd2\xd3\xd4\xd5\xd6\xd8\xd9\xda\xdb\xdc\xdd\xe0\xe1\xe2\xe3\xe4\xe5\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xff",
|
Chris@76
|
3634 'SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy');
|
Chris@76
|
3635 $clean_name = strtr($clean_name, array("\xde" => 'TH', "\xfe" =>
|
Chris@76
|
3636 'th', "\xd0" => 'DH', "\xf0" => 'dh', "\xdf" => 'ss', "\x8c" => 'OE',
|
Chris@76
|
3637 "\x9c" => 'oe', "\c6" => 'AE', "\xe6" => 'ae', "\xb5" => 'u'));
|
Chris@76
|
3638 }
|
Chris@76
|
3639 // Sorry, no spaces, dots, or anything else but letters allowed.
|
Chris@76
|
3640 $clean_name = preg_replace(array('/\s/', '/[^\w_\.\-]/'), array('_', ''), $clean_name);
|
Chris@76
|
3641
|
Chris@76
|
3642 $enc_name = $attachment_id . '_' . strtr($clean_name, '.', '_') . md5($clean_name);
|
Chris@76
|
3643 $clean_name = preg_replace('~\.[\.]+~', '.', $clean_name);
|
Chris@76
|
3644
|
Chris@76
|
3645 if ($attachment_id == false || ($new && empty($modSettings['attachmentEncryptFilenames'])))
|
Chris@76
|
3646 return $clean_name;
|
Chris@76
|
3647 elseif ($new)
|
Chris@76
|
3648 return $enc_name;
|
Chris@76
|
3649
|
Chris@76
|
3650 // Are we using multiple directories?
|
Chris@76
|
3651 if (!empty($modSettings['currentAttachmentUploadDir']))
|
Chris@76
|
3652 {
|
Chris@76
|
3653 if (!is_array($modSettings['attachmentUploadDir']))
|
Chris@76
|
3654 $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
|
Chris@76
|
3655 $path = $modSettings['attachmentUploadDir'][$dir];
|
Chris@76
|
3656 }
|
Chris@76
|
3657 else
|
Chris@76
|
3658 $path = $modSettings['attachmentUploadDir'];
|
Chris@76
|
3659
|
Chris@76
|
3660 if (file_exists($path . '/' . $enc_name))
|
Chris@76
|
3661 $filename = $path . '/' . $enc_name;
|
Chris@76
|
3662 else
|
Chris@76
|
3663 $filename = $path . '/' . $clean_name;
|
Chris@76
|
3664
|
Chris@76
|
3665 return $filename;
|
Chris@76
|
3666 }
|
Chris@76
|
3667
|
Chris@76
|
3668 // Convert a single IP to a ranged IP.
|
Chris@76
|
3669 function ip2range($fullip)
|
Chris@76
|
3670 {
|
Chris@76
|
3671 // Pretend that 'unknown' is 255.255.255.255. (since that can't be an IP anyway.)
|
Chris@76
|
3672 if ($fullip == 'unknown')
|
Chris@76
|
3673 $fullip = '255.255.255.255';
|
Chris@76
|
3674
|
Chris@76
|
3675 $ip_parts = explode('.', $fullip);
|
Chris@76
|
3676 $ip_array = array();
|
Chris@76
|
3677
|
Chris@76
|
3678 if (count($ip_parts) != 4)
|
Chris@76
|
3679 return array();
|
Chris@76
|
3680
|
Chris@76
|
3681 for ($i = 0; $i < 4; $i++)
|
Chris@76
|
3682 {
|
Chris@76
|
3683 if ($ip_parts[$i] == '*')
|
Chris@76
|
3684 $ip_array[$i] = array('low' => '0', 'high' => '255');
|
Chris@76
|
3685 elseif (preg_match('/^(\d{1,3})\-(\d{1,3})$/', $ip_parts[$i], $range) == 1)
|
Chris@76
|
3686 $ip_array[$i] = array('low' => $range[1], 'high' => $range[2]);
|
Chris@76
|
3687 elseif (is_numeric($ip_parts[$i]))
|
Chris@76
|
3688 $ip_array[$i] = array('low' => $ip_parts[$i], 'high' => $ip_parts[$i]);
|
Chris@76
|
3689 }
|
Chris@76
|
3690
|
Chris@76
|
3691 return $ip_array;
|
Chris@76
|
3692 }
|
Chris@76
|
3693
|
Chris@76
|
3694 // Lookup an IP; try shell_exec first because we can do a timeout on it.
|
Chris@76
|
3695 function host_from_ip($ip)
|
Chris@76
|
3696 {
|
Chris@76
|
3697 global $modSettings;
|
Chris@76
|
3698
|
Chris@76
|
3699 if (($host = cache_get_data('hostlookup-' . $ip, 600)) !== null)
|
Chris@76
|
3700 return $host;
|
Chris@76
|
3701 $t = microtime();
|
Chris@76
|
3702
|
Chris@76
|
3703 // If we can't access nslookup/host, PHP 4.1.x might just crash.
|
Chris@76
|
3704 if (@version_compare(PHP_VERSION, '4.2.0') == -1)
|
Chris@76
|
3705 $host = false;
|
Chris@76
|
3706
|
Chris@76
|
3707 // Try the Linux host command, perhaps?
|
Chris@76
|
3708 if (!isset($host) && (strpos(strtolower(PHP_OS), 'win') === false || strpos(strtolower(PHP_OS), 'darwin') !== false) && mt_rand(0, 1) == 1)
|
Chris@76
|
3709 {
|
Chris@76
|
3710 if (!isset($modSettings['host_to_dis']))
|
Chris@76
|
3711 $test = @shell_exec('host -W 1 ' . @escapeshellarg($ip));
|
Chris@76
|
3712 else
|
Chris@76
|
3713 $test = @shell_exec('host ' . @escapeshellarg($ip));
|
Chris@76
|
3714
|
Chris@76
|
3715 // Did host say it didn't find anything?
|
Chris@76
|
3716 if (strpos($test, 'not found') !== false)
|
Chris@76
|
3717 $host = '';
|
Chris@76
|
3718 // Invalid server option?
|
Chris@76
|
3719 elseif ((strpos($test, 'invalid option') || strpos($test, 'Invalid query name 1')) && !isset($modSettings['host_to_dis']))
|
Chris@76
|
3720 updateSettings(array('host_to_dis' => 1));
|
Chris@76
|
3721 // Maybe it found something, after all?
|
Chris@76
|
3722 elseif (preg_match('~\s([^\s]+?)\.\s~', $test, $match) == 1)
|
Chris@76
|
3723 $host = $match[1];
|
Chris@76
|
3724 }
|
Chris@76
|
3725
|
Chris@76
|
3726 // This is nslookup; usually only Windows, but possibly some Unix?
|
Chris@76
|
3727 if (!isset($host) && strpos(strtolower(PHP_OS), 'win') !== false && strpos(strtolower(PHP_OS), 'darwin') === false && mt_rand(0, 1) == 1)
|
Chris@76
|
3728 {
|
Chris@76
|
3729 $test = @shell_exec('nslookup -timeout=1 ' . @escapeshellarg($ip));
|
Chris@76
|
3730 if (strpos($test, 'Non-existent domain') !== false)
|
Chris@76
|
3731 $host = '';
|
Chris@76
|
3732 elseif (preg_match('~Name:\s+([^\s]+)~', $test, $match) == 1)
|
Chris@76
|
3733 $host = $match[1];
|
Chris@76
|
3734 }
|
Chris@76
|
3735
|
Chris@76
|
3736 // This is the last try :/.
|
Chris@76
|
3737 if (!isset($host) || $host === false)
|
Chris@76
|
3738 $host = @gethostbyaddr($ip);
|
Chris@76
|
3739
|
Chris@76
|
3740 // It took a long time, so let's cache it!
|
Chris@76
|
3741 if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $t)) > 0.5)
|
Chris@76
|
3742 cache_put_data('hostlookup-' . $ip, $host, 600);
|
Chris@76
|
3743
|
Chris@76
|
3744 return $host;
|
Chris@76
|
3745 }
|
Chris@76
|
3746
|
Chris@76
|
3747 // Chops a string into words and prepares them to be inserted into (or searched from) the database.
|
Chris@76
|
3748 function text2words($text, $max_chars = 20, $encrypt = false)
|
Chris@76
|
3749 {
|
Chris@76
|
3750 global $smcFunc, $context;
|
Chris@76
|
3751
|
Chris@76
|
3752 // Step 1: Remove entities/things we don't consider words:
|
Chris@76
|
3753 $words = preg_replace('~(?:[\x0B\0' . ($context['utf8'] ? ($context['server']['complex_preg_chars'] ? '\x{A0}' : "\xC2\xA0") : '\xA0') . '\t\r\s\n(){}\\[\\]<>!@$%^*.,:+=`\~\?/\\\\]+|&(?:amp|lt|gt|quot);)+~' . ($context['utf8'] ? 'u' : ''), ' ', strtr($text, array('<br />' => ' ')));
|
Chris@76
|
3754
|
Chris@76
|
3755 // Step 2: Entities we left to letters, where applicable, lowercase.
|
Chris@76
|
3756 $words = un_htmlspecialchars($smcFunc['strtolower']($words));
|
Chris@76
|
3757
|
Chris@76
|
3758 // Step 3: Ready to split apart and index!
|
Chris@76
|
3759 $words = explode(' ', $words);
|
Chris@76
|
3760
|
Chris@76
|
3761 if ($encrypt)
|
Chris@76
|
3762 {
|
Chris@76
|
3763 $possible_chars = array_flip(array_merge(range(46, 57), range(65, 90), range(97, 122)));
|
Chris@76
|
3764 $returned_ints = array();
|
Chris@76
|
3765 foreach ($words as $word)
|
Chris@76
|
3766 {
|
Chris@76
|
3767 if (($word = trim($word, '-_\'')) !== '')
|
Chris@76
|
3768 {
|
Chris@76
|
3769 $encrypted = substr(crypt($word, 'uk'), 2, $max_chars);
|
Chris@76
|
3770 $total = 0;
|
Chris@76
|
3771 for ($i = 0; $i < $max_chars; $i++)
|
Chris@76
|
3772 $total += $possible_chars[ord($encrypted{$i})] * pow(63, $i);
|
Chris@76
|
3773 $returned_ints[] = $max_chars == 4 ? min($total, 16777215) : $total;
|
Chris@76
|
3774 }
|
Chris@76
|
3775 }
|
Chris@76
|
3776 return array_unique($returned_ints);
|
Chris@76
|
3777 }
|
Chris@76
|
3778 else
|
Chris@76
|
3779 {
|
Chris@76
|
3780 // Trim characters before and after and add slashes for database insertion.
|
Chris@76
|
3781 $returned_words = array();
|
Chris@76
|
3782 foreach ($words as $word)
|
Chris@76
|
3783 if (($word = trim($word, '-_\'')) !== '')
|
Chris@76
|
3784 $returned_words[] = $max_chars === null ? $word : substr($word, 0, $max_chars);
|
Chris@76
|
3785
|
Chris@76
|
3786 // Filter out all words that occur more than once.
|
Chris@76
|
3787 return array_unique($returned_words);
|
Chris@76
|
3788 }
|
Chris@76
|
3789 }
|
Chris@76
|
3790
|
Chris@76
|
3791 // Creates an image/text button
|
Chris@76
|
3792 function create_button($name, $alt, $label = '', $custom = '', $force_use = false)
|
Chris@76
|
3793 {
|
Chris@76
|
3794 global $settings, $txt, $context;
|
Chris@76
|
3795
|
Chris@76
|
3796 // Does the current loaded theme have this and we are not forcing the usage of this function?
|
Chris@76
|
3797 if (function_exists('template_create_button') && !$force_use)
|
Chris@76
|
3798 return template_create_button($name, $alt, $label = '', $custom = '');
|
Chris@76
|
3799
|
Chris@76
|
3800 if (!$settings['use_image_buttons'])
|
Chris@76
|
3801 return $txt[$alt];
|
Chris@76
|
3802 elseif (!empty($settings['use_buttons']))
|
Chris@76
|
3803 return '<img src="' . $settings['images_url'] . '/buttons/' . $name . '" alt="' . $txt[$alt] . '" ' . $custom . ' />' . ($label != '' ? '<strong>' . $txt[$label] . '</strong>' : '');
|
Chris@76
|
3804 else
|
Chris@76
|
3805 return '<img src="' . $settings['lang_images_url'] . '/' . $name . '" alt="' . $txt[$alt] . '" ' . $custom . ' />';
|
Chris@76
|
3806 }
|
Chris@76
|
3807
|
Chris@76
|
3808 // Empty out the cache folder.
|
Chris@76
|
3809 function clean_cache($type = '')
|
Chris@76
|
3810 {
|
Chris@76
|
3811 global $cachedir, $sourcedir;
|
Chris@76
|
3812
|
Chris@76
|
3813 // No directory = no game.
|
Chris@76
|
3814 if (!is_dir($cachedir))
|
Chris@76
|
3815 return;
|
Chris@76
|
3816
|
Chris@76
|
3817 // Remove the files in SMF's own disk cache, if any
|
Chris@76
|
3818 $dh = opendir($cachedir);
|
Chris@76
|
3819 while ($file = readdir($dh))
|
Chris@76
|
3820 {
|
Chris@76
|
3821 if ($file != '.' && $file != '..' && $file != 'index.php' && $file != '.htaccess' && (!$type || substr($file, 0, strlen($type)) == $type))
|
Chris@76
|
3822 @unlink($cachedir . '/' . $file);
|
Chris@76
|
3823 }
|
Chris@76
|
3824 closedir($dh);
|
Chris@76
|
3825
|
Chris@76
|
3826 // Invalidate cache, to be sure!
|
Chris@76
|
3827 // ... as long as Load.php can be modified, anyway.
|
Chris@76
|
3828 @touch($sourcedir . '/' . 'Load.php');
|
Chris@76
|
3829 clearstatcache();
|
Chris@76
|
3830 }
|
Chris@76
|
3831
|
Chris@76
|
3832 // Load classes that are both (E_STRICT) PHP 4 and PHP 5 compatible.
|
Chris@76
|
3833 function loadClassFile($filename)
|
Chris@76
|
3834 {
|
Chris@76
|
3835 global $sourcedir;
|
Chris@76
|
3836 static $files_included = array();
|
Chris@76
|
3837
|
Chris@76
|
3838 if (!file_exists($sourcedir . '/' . $filename))
|
Chris@76
|
3839 fatal_lang_error('error_bad_file', 'general', array($sourcedir . '/' . $filename));
|
Chris@76
|
3840
|
Chris@76
|
3841 // Using a version below PHP 5.0? Do a compatibility conversion.
|
Chris@76
|
3842 if (@version_compare(PHP_VERSION, '5.0.0') != 1)
|
Chris@76
|
3843 {
|
Chris@76
|
3844 // Check if it was included before.
|
Chris@76
|
3845 if (in_array($filename, $files_included))
|
Chris@76
|
3846 return;
|
Chris@76
|
3847
|
Chris@76
|
3848 // Make sure we don't include it again.
|
Chris@76
|
3849 $files_included[] = $filename;
|
Chris@76
|
3850
|
Chris@76
|
3851 // Do some replacements to make it PHP 4 compatible.
|
Chris@76
|
3852 eval('?' . '>' . preg_replace(array(
|
Chris@76
|
3853 '~class\s+([\w-_]+)([^}]+)function\s+__construct\s*\(~',
|
Chris@76
|
3854 '~([\s\t]+)public\s+\$~',
|
Chris@76
|
3855 '~([\s\t]+)private\s+\$~',
|
Chris@76
|
3856 '~([\s\t]+)protected\s+\$~',
|
Chris@76
|
3857 '~([\s\t]+)public\s+function\s+~',
|
Chris@76
|
3858 '~([\s\t]+)private\s+function\s+~',
|
Chris@76
|
3859 '~([\s\t]+)protected\s+function\s+~',
|
Chris@76
|
3860 ), array(
|
Chris@76
|
3861 'class $1$2function $1(',
|
Chris@76
|
3862 '$1var $',
|
Chris@76
|
3863 '$1var $',
|
Chris@76
|
3864 '$1var $',
|
Chris@76
|
3865 '$1function ',
|
Chris@76
|
3866 '$1function ',
|
Chris@76
|
3867 '$1function ',
|
Chris@76
|
3868 ), rtrim(file_get_contents($sourcedir . '/' . $filename))));
|
Chris@76
|
3869 }
|
Chris@76
|
3870 else
|
Chris@76
|
3871 require_once($sourcedir . '/' . $filename);
|
Chris@76
|
3872 }
|
Chris@76
|
3873
|
Chris@76
|
3874 function setupMenuContext()
|
Chris@76
|
3875 {
|
Chris@76
|
3876 global $context, $modSettings, $user_info, $txt, $scripturl;
|
Chris@76
|
3877
|
Chris@76
|
3878 // Set up the menu privileges.
|
Chris@76
|
3879 $context['allow_search'] = allowedTo('search_posts');
|
Chris@76
|
3880 $context['allow_admin'] = allowedTo(array('admin_forum', 'manage_boards', 'manage_permissions', 'moderate_forum', 'manage_membergroups', 'manage_bans', 'send_mail', 'edit_news', 'manage_attachments', 'manage_smileys'));
|
Chris@76
|
3881 $context['allow_edit_profile'] = !$user_info['is_guest'] && allowedTo(array('profile_view_own', 'profile_view_any', 'profile_identity_own', 'profile_identity_any', 'profile_extra_own', 'profile_extra_any', 'profile_remove_own', 'profile_remove_any', 'moderate_forum', 'manage_membergroups', 'profile_title_own', 'profile_title_any'));
|
Chris@76
|
3882 $context['allow_memberlist'] = allowedTo('view_mlist');
|
Chris@76
|
3883 $context['allow_calendar'] = allowedTo('calendar_view') && !empty($modSettings['cal_enabled']);
|
Chris@76
|
3884 $context['allow_moderation_center'] = $context['user']['can_mod'];
|
Chris@76
|
3885 $context['allow_pm'] = allowedTo('pm_read');
|
Chris@76
|
3886
|
Chris@76
|
3887 $cacheTime = $modSettings['lastActive'] * 60;
|
Chris@76
|
3888
|
Chris@76
|
3889 // All the buttons we can possible want and then some, try pulling the final list of buttons from cache first.
|
Chris@76
|
3890 if (($menu_buttons = cache_get_data('menu_buttons-' . implode('_', $user_info['groups']) . '-' . $user_info['language'], $cacheTime)) === null || time() - $cacheTime <= $modSettings['settings_updated'])
|
Chris@76
|
3891 {
|
Chris@76
|
3892 $buttons = array(
|
Chris@76
|
3893 'home' => array(
|
Chris@76
|
3894 'title' => $txt['home'],
|
Chris@76
|
3895 'href' => $scripturl,
|
Chris@76
|
3896 'show' => true,
|
Chris@76
|
3897 'sub_buttons' => array(
|
Chris@76
|
3898 ),
|
Chris@76
|
3899 'is_last' => $context['right_to_left'],
|
Chris@76
|
3900 ),
|
Chris@76
|
3901 'help' => array(
|
Chris@76
|
3902 'title' => $txt['help'],
|
Chris@76
|
3903 'href' => $scripturl . '?action=help',
|
Chris@76
|
3904 'show' => true,
|
Chris@76
|
3905 'sub_buttons' => array(
|
Chris@76
|
3906 ),
|
Chris@76
|
3907 ),
|
Chris@76
|
3908 'search' => array(
|
Chris@76
|
3909 'title' => $txt['search'],
|
Chris@76
|
3910 'href' => $scripturl . '?action=search',
|
Chris@76
|
3911 'show' => $context['allow_search'],
|
Chris@76
|
3912 'sub_buttons' => array(
|
Chris@76
|
3913 ),
|
Chris@76
|
3914 ),
|
Chris@76
|
3915 'admin' => array(
|
Chris@76
|
3916 'title' => $txt['admin'],
|
Chris@76
|
3917 'href' => $scripturl . '?action=admin',
|
Chris@76
|
3918 'show' => $context['allow_admin'],
|
Chris@76
|
3919 'sub_buttons' => array(
|
Chris@76
|
3920 'featuresettings' => array(
|
Chris@76
|
3921 'title' => $txt['modSettings_title'],
|
Chris@76
|
3922 'href' => $scripturl . '?action=admin;area=featuresettings',
|
Chris@76
|
3923 'show' => allowedTo('admin_forum'),
|
Chris@76
|
3924 ),
|
Chris@76
|
3925 'packages' => array(
|
Chris@76
|
3926 'title' => $txt['package'],
|
Chris@76
|
3927 'href' => $scripturl . '?action=admin;area=packages',
|
Chris@76
|
3928 'show' => allowedTo('admin_forum'),
|
Chris@76
|
3929 ),
|
Chris@76
|
3930 'errorlog' => array(
|
Chris@76
|
3931 'title' => $txt['errlog'],
|
Chris@76
|
3932 'href' => $scripturl . '?action=admin;area=logs;sa=errorlog;desc',
|
Chris@76
|
3933 'show' => allowedTo('admin_forum') && !empty($modSettings['enableErrorLogging']),
|
Chris@76
|
3934 ),
|
Chris@76
|
3935 'permissions' => array(
|
Chris@76
|
3936 'title' => $txt['edit_permissions'],
|
Chris@76
|
3937 'href' => $scripturl . '?action=admin;area=permissions',
|
Chris@76
|
3938 'show' => allowedTo('manage_permissions'),
|
Chris@76
|
3939 'is_last' => true,
|
Chris@76
|
3940 ),
|
Chris@76
|
3941 ),
|
Chris@76
|
3942 ),
|
Chris@76
|
3943 'moderate' => array(
|
Chris@76
|
3944 'title' => $txt['moderate'],
|
Chris@76
|
3945 'href' => $scripturl . '?action=moderate',
|
Chris@76
|
3946 'show' => $context['allow_moderation_center'],
|
Chris@76
|
3947 'sub_buttons' => array(
|
Chris@76
|
3948 'modlog' => array(
|
Chris@76
|
3949 'title' => $txt['modlog_view'],
|
Chris@76
|
3950 'href' => $scripturl . '?action=moderate;area=modlog',
|
Chris@76
|
3951 'show' => !empty($modSettings['modlog_enabled']) && !empty($user_info['mod_cache']) && $user_info['mod_cache']['bq'] != '0=1',
|
Chris@76
|
3952 ),
|
Chris@76
|
3953 'poststopics' => array(
|
Chris@76
|
3954 'title' => $txt['mc_unapproved_poststopics'],
|
Chris@76
|
3955 'href' => $scripturl . '?action=moderate;area=postmod;sa=posts',
|
Chris@76
|
3956 'show' => $modSettings['postmod_active'] && !empty($user_info['mod_cache']['ap']),
|
Chris@76
|
3957 ),
|
Chris@76
|
3958 'attachments' => array(
|
Chris@76
|
3959 'title' => $txt['mc_unapproved_attachments'],
|
Chris@76
|
3960 'href' => $scripturl . '?action=moderate;area=attachmod;sa=attachments',
|
Chris@76
|
3961 'show' => $modSettings['postmod_active'] && !empty($user_info['mod_cache']['ap']),
|
Chris@76
|
3962 ),
|
Chris@76
|
3963 'reports' => array(
|
Chris@76
|
3964 'title' => $txt['mc_reported_posts'],
|
Chris@76
|
3965 'href' => $scripturl . '?action=moderate;area=reports',
|
Chris@76
|
3966 'show' => !empty($user_info['mod_cache']) && $user_info['mod_cache']['bq'] != '0=1',
|
Chris@76
|
3967 'is_last' => true,
|
Chris@76
|
3968 ),
|
Chris@76
|
3969 ),
|
Chris@76
|
3970 ),
|
Chris@76
|
3971 'profile' => array(
|
Chris@76
|
3972 'title' => $txt['profile'],
|
Chris@76
|
3973 'href' => $scripturl . '?action=profile',
|
Chris@76
|
3974 'show' => $context['allow_edit_profile'],
|
Chris@76
|
3975 'sub_buttons' => array(
|
Chris@76
|
3976 'summary' => array(
|
Chris@76
|
3977 'title' => $txt['summary'],
|
Chris@76
|
3978 'href' => $scripturl . '?action=profile',
|
Chris@76
|
3979 'show' => true,
|
Chris@76
|
3980 ),
|
Chris@76
|
3981 'account' => array(
|
Chris@76
|
3982 'title' => $txt['account'],
|
Chris@76
|
3983 'href' => $scripturl . '?action=profile;area=account',
|
Chris@76
|
3984 'show' => allowedTo(array('profile_identity_any', 'profile_identity_own', 'manage_membergroups')),
|
Chris@76
|
3985 ),
|
Chris@76
|
3986 'profile' => array(
|
Chris@76
|
3987 'title' => $txt['forumprofile'],
|
Chris@76
|
3988 'href' => $scripturl . '?action=profile;area=forumprofile',
|
Chris@76
|
3989 'show' => allowedTo(array('profile_extra_any', 'profile_extra_own')),
|
Chris@76
|
3990 'is_last' => true,
|
Chris@76
|
3991 ),
|
Chris@76
|
3992 ),
|
Chris@76
|
3993 ),
|
Chris@76
|
3994 'pm' => array(
|
Chris@76
|
3995 'title' => $txt['pm_short'],
|
Chris@76
|
3996 'href' => $scripturl . '?action=pm',
|
Chris@76
|
3997 'show' => $context['allow_pm'],
|
Chris@76
|
3998 'sub_buttons' => array(
|
Chris@76
|
3999 'pm_read' => array(
|
Chris@76
|
4000 'title' => $txt['pm_menu_read'],
|
Chris@76
|
4001 'href' => $scripturl . '?action=pm',
|
Chris@76
|
4002 'show' => allowedTo('pm_read'),
|
Chris@76
|
4003 ),
|
Chris@76
|
4004 'pm_send' => array(
|
Chris@76
|
4005 'title' => $txt['pm_menu_send'],
|
Chris@76
|
4006 'href' => $scripturl . '?action=pm;sa=send',
|
Chris@76
|
4007 'show' => allowedTo('pm_send'),
|
Chris@76
|
4008 'is_last' => true,
|
Chris@76
|
4009 ),
|
Chris@76
|
4010 ),
|
Chris@76
|
4011 ),
|
Chris@76
|
4012 'calendar' => array(
|
Chris@76
|
4013 'title' => $txt['calendar'],
|
Chris@76
|
4014 'href' => $scripturl . '?action=calendar',
|
Chris@76
|
4015 'show' => $context['allow_calendar'],
|
Chris@76
|
4016 'sub_buttons' => array(
|
Chris@76
|
4017 'view' => array(
|
Chris@76
|
4018 'title' => $txt['calendar_menu'],
|
Chris@76
|
4019 'href' => $scripturl . '?action=calendar',
|
Chris@76
|
4020 'show' => allowedTo('calendar_post'),
|
Chris@76
|
4021 ),
|
Chris@76
|
4022 'post' => array(
|
Chris@76
|
4023 'title' => $txt['calendar_post_event'],
|
Chris@76
|
4024 'href' => $scripturl . '?action=calendar;sa=post',
|
Chris@76
|
4025 'show' => allowedTo('calendar_post'),
|
Chris@76
|
4026 'is_last' => true,
|
Chris@76
|
4027 ),
|
Chris@76
|
4028 ),
|
Chris@76
|
4029 ),
|
Chris@76
|
4030 'mlist' => array(
|
Chris@76
|
4031 'title' => $txt['members_title'],
|
Chris@76
|
4032 'href' => $scripturl . '?action=mlist',
|
Chris@76
|
4033 'show' => $context['allow_memberlist'],
|
Chris@76
|
4034 'sub_buttons' => array(
|
Chris@76
|
4035 'mlist_view' => array(
|
Chris@76
|
4036 'title' => $txt['mlist_menu_view'],
|
Chris@76
|
4037 'href' => $scripturl . '?action=mlist',
|
Chris@76
|
4038 'show' => true,
|
Chris@76
|
4039 ),
|
Chris@76
|
4040 'mlist_search' => array(
|
Chris@76
|
4041 'title' => $txt['mlist_search'],
|
Chris@76
|
4042 'href' => $scripturl . '?action=mlist;sa=search',
|
Chris@76
|
4043 'show' => true,
|
Chris@76
|
4044 'is_last' => true,
|
Chris@76
|
4045 ),
|
Chris@76
|
4046 ),
|
Chris@76
|
4047 ),
|
Chris@76
|
4048 'login' => array(
|
Chris@76
|
4049 'title' => $txt['login'],
|
Chris@76
|
4050 'href' => $scripturl . '?action=login',
|
Chris@76
|
4051 'show' => $user_info['is_guest'],
|
Chris@76
|
4052 'sub_buttons' => array(
|
Chris@76
|
4053 ),
|
Chris@76
|
4054 ),
|
Chris@76
|
4055 'register' => array(
|
Chris@76
|
4056 'title' => $txt['register'],
|
Chris@76
|
4057 'href' => $scripturl . '?action=register',
|
Chris@76
|
4058 'show' => $user_info['is_guest'],
|
Chris@76
|
4059 'sub_buttons' => array(
|
Chris@76
|
4060 ),
|
Chris@76
|
4061 'is_last' => !$context['right_to_left'],
|
Chris@76
|
4062 ),
|
Chris@76
|
4063 'logout' => array(
|
Chris@76
|
4064 'title' => $txt['logout'],
|
Chris@76
|
4065 'href' => $scripturl . '?action=logout;%1$s=%2$s',
|
Chris@76
|
4066 'show' => !$user_info['is_guest'],
|
Chris@76
|
4067 'sub_buttons' => array(
|
Chris@76
|
4068 ),
|
Chris@76
|
4069 'is_last' => !$context['right_to_left'],
|
Chris@76
|
4070 ),
|
Chris@76
|
4071 );
|
Chris@76
|
4072
|
Chris@76
|
4073 // Allow editing menu buttons easily.
|
Chris@76
|
4074 call_integration_hook('integrate_menu_buttons', array(&$buttons));
|
Chris@76
|
4075
|
Chris@76
|
4076 // Now we put the buttons in the context so the theme can use them.
|
Chris@76
|
4077 $menu_buttons = array();
|
Chris@76
|
4078 foreach ($buttons as $act => $button)
|
Chris@76
|
4079 if (!empty($button['show']))
|
Chris@76
|
4080 {
|
Chris@76
|
4081 $button['active_button'] = false;
|
Chris@76
|
4082
|
Chris@76
|
4083 // Make sure the last button truely is the last button.
|
Chris@76
|
4084 if (!empty($button['is_last']))
|
Chris@76
|
4085 {
|
Chris@76
|
4086 if (isset($last_button))
|
Chris@76
|
4087 unset($menu_buttons[$last_button]['is_last']);
|
Chris@76
|
4088 $last_button = $act;
|
Chris@76
|
4089 }
|
Chris@76
|
4090
|
Chris@76
|
4091 // Go through the sub buttons if there are any.
|
Chris@76
|
4092 if (!empty($button['sub_buttons']))
|
Chris@76
|
4093 foreach ($button['sub_buttons'] as $key => $subbutton)
|
Chris@76
|
4094 {
|
Chris@76
|
4095 if (empty($subbutton['show']))
|
Chris@76
|
4096 unset($button['sub_buttons'][$key]);
|
Chris@76
|
4097
|
Chris@76
|
4098 // 2nd level sub buttons next...
|
Chris@76
|
4099 if (!empty($subbutton['sub_buttons']))
|
Chris@76
|
4100 {
|
Chris@76
|
4101 foreach ($subbutton['sub_buttons'] as $key2 => $sub_button2)
|
Chris@76
|
4102 {
|
Chris@76
|
4103 if (empty($sub_button2['show']))
|
Chris@76
|
4104 unset($button['sub_buttons'][$key]['sub_buttons'][$key2]);
|
Chris@76
|
4105 }
|
Chris@76
|
4106 }
|
Chris@76
|
4107 }
|
Chris@76
|
4108
|
Chris@76
|
4109 $menu_buttons[$act] = $button;
|
Chris@76
|
4110 }
|
Chris@76
|
4111
|
Chris@76
|
4112 if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2)
|
Chris@76
|
4113 cache_put_data('menu_buttons-' . implode('_', $user_info['groups']) . '-' . $user_info['language'], $menu_buttons, $cacheTime);
|
Chris@76
|
4114 }
|
Chris@76
|
4115
|
Chris@76
|
4116 $context['menu_buttons'] = $menu_buttons;
|
Chris@76
|
4117
|
Chris@76
|
4118 // Logging out requires the session id in the url.
|
Chris@76
|
4119 if (isset($context['menu_buttons']['logout']))
|
Chris@76
|
4120 $context['menu_buttons']['logout']['href'] = sprintf($context['menu_buttons']['logout']['href'], $context['session_var'], $context['session_id']);
|
Chris@76
|
4121
|
Chris@76
|
4122 // Figure out which action we are doing so we can set the active tab.
|
Chris@76
|
4123 // Default to home.
|
Chris@76
|
4124 $current_action = 'home';
|
Chris@76
|
4125
|
Chris@76
|
4126 if (isset($context['menu_buttons'][$context['current_action']]))
|
Chris@76
|
4127 $current_action = $context['current_action'];
|
Chris@76
|
4128 elseif ($context['current_action'] == 'search2')
|
Chris@76
|
4129 $current_action = 'search';
|
Chris@76
|
4130 elseif ($context['current_action'] == 'theme')
|
Chris@76
|
4131 $current_action = isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'pick' ? 'profile' : 'admin';
|
Chris@76
|
4132 elseif ($context['current_action'] == 'register2')
|
Chris@76
|
4133 $current_action = 'register';
|
Chris@76
|
4134 elseif ($context['current_action'] == 'login2' || ($user_info['is_guest'] && $context['current_action'] == 'reminder'))
|
Chris@76
|
4135 $current_action = 'login';
|
Chris@76
|
4136 elseif ($context['current_action'] == 'groups' && $context['allow_moderation_center'])
|
Chris@76
|
4137 $current_action = 'moderate';
|
Chris@76
|
4138
|
Chris@76
|
4139 $context['menu_buttons'][$current_action]['active_button'] = true;
|
Chris@76
|
4140
|
Chris@76
|
4141 if (!$user_info['is_guest'] && $context['user']['unread_messages'] > 0 && isset($context['menu_buttons']['pm']))
|
Chris@76
|
4142 {
|
Chris@76
|
4143 $context['menu_buttons']['pm']['alttitle'] = $context['menu_buttons']['pm']['title'] . ' [' . $context['user']['unread_messages'] . ']';
|
Chris@76
|
4144 $context['menu_buttons']['pm']['title'] .= ' [<strong>' . $context['user']['unread_messages'] . '</strong>]';
|
Chris@76
|
4145 }
|
Chris@76
|
4146 }
|
Chris@76
|
4147
|
Chris@76
|
4148 // Generate a random seed and ensure it's stored in settings.
|
Chris@76
|
4149 function smf_seed_generator()
|
Chris@76
|
4150 {
|
Chris@76
|
4151 global $modSettings;
|
Chris@76
|
4152
|
Chris@76
|
4153 // Never existed?
|
Chris@76
|
4154 if (empty($modSettings['rand_seed']))
|
Chris@76
|
4155 {
|
Chris@76
|
4156 $modSettings['rand_seed'] = microtime() * 1000000;
|
Chris@76
|
4157 updateSettings(array('rand_seed' => $modSettings['rand_seed']));
|
Chris@76
|
4158 }
|
Chris@76
|
4159
|
Chris@76
|
4160 if (@version_compare(PHP_VERSION, '4.2.0') == -1)
|
Chris@76
|
4161 {
|
Chris@76
|
4162 $seed = ($modSettings['rand_seed'] + ((double) microtime() * 1000003)) & 0x7fffffff;
|
Chris@76
|
4163 mt_srand($seed);
|
Chris@76
|
4164 }
|
Chris@76
|
4165
|
Chris@76
|
4166 // Change the seed.
|
Chris@76
|
4167 updateSettings(array('rand_seed' => mt_rand()));
|
Chris@76
|
4168 }
|
Chris@76
|
4169
|
Chris@76
|
4170 // Process functions of an integration hook.
|
Chris@76
|
4171 function call_integration_hook($hook, $parameters = array())
|
Chris@76
|
4172 {
|
Chris@76
|
4173 global $modSettings;
|
Chris@76
|
4174
|
Chris@76
|
4175 $results = array();
|
Chris@76
|
4176 if (empty($modSettings[$hook]))
|
Chris@76
|
4177 return $results;
|
Chris@76
|
4178
|
Chris@76
|
4179 $functions = explode(',', $modSettings[$hook]);
|
Chris@76
|
4180
|
Chris@76
|
4181 // Loop through each function.
|
Chris@76
|
4182 foreach ($functions as $function)
|
Chris@76
|
4183 {
|
Chris@76
|
4184 $function = trim($function);
|
Chris@76
|
4185 $call = strpos($function, '::') !== false ? explode('::', $function) : $function;
|
Chris@76
|
4186
|
Chris@76
|
4187 // Is it valid?
|
Chris@76
|
4188 if (is_callable($call))
|
Chris@76
|
4189 $results[$function] = call_user_func_array($call, $parameters);
|
Chris@76
|
4190 }
|
Chris@76
|
4191
|
Chris@76
|
4192 return $results;
|
Chris@76
|
4193 }
|
Chris@76
|
4194
|
Chris@76
|
4195 // Add a function for integration hook.
|
Chris@76
|
4196 function add_integration_function($hook, $function, $permanent = true)
|
Chris@76
|
4197 {
|
Chris@76
|
4198 global $smcFunc, $modSettings;
|
Chris@76
|
4199
|
Chris@76
|
4200 // Is it going to be permanent?
|
Chris@76
|
4201 if ($permanent)
|
Chris@76
|
4202 {
|
Chris@76
|
4203 $request = $smcFunc['db_query']('', '
|
Chris@76
|
4204 SELECT value
|
Chris@76
|
4205 FROM {db_prefix}settings
|
Chris@76
|
4206 WHERE variable = {string:variable}',
|
Chris@76
|
4207 array(
|
Chris@76
|
4208 'variable' => $hook,
|
Chris@76
|
4209 )
|
Chris@76
|
4210 );
|
Chris@76
|
4211 list($current_functions) = $smcFunc['db_fetch_row']($request);
|
Chris@76
|
4212 $smcFunc['db_free_result']($request);
|
Chris@76
|
4213
|
Chris@76
|
4214 if (!empty($current_functions))
|
Chris@76
|
4215 {
|
Chris@76
|
4216 $current_functions = explode(',', $current_functions);
|
Chris@76
|
4217 if (in_array($function, $current_functions))
|
Chris@76
|
4218 return;
|
Chris@76
|
4219
|
Chris@76
|
4220 $permanent_functions = array_merge($current_functions, array($function));
|
Chris@76
|
4221 }
|
Chris@76
|
4222 else
|
Chris@76
|
4223 $permanent_functions = array($function);
|
Chris@76
|
4224
|
Chris@76
|
4225 updateSettings(array($hook => implode(',', $permanent_functions)));
|
Chris@76
|
4226 }
|
Chris@76
|
4227
|
Chris@76
|
4228 // Make current function list usable.
|
Chris@76
|
4229 $functions = empty($modSettings[$hook]) ? array() : explode(',', $modSettings[$hook]);
|
Chris@76
|
4230
|
Chris@76
|
4231 // Do nothing, if it's already there.
|
Chris@76
|
4232 if (in_array($function, $functions))
|
Chris@76
|
4233 return;
|
Chris@76
|
4234
|
Chris@76
|
4235 $functions[] = $function;
|
Chris@76
|
4236 $modSettings[$hook] = implode(',', $functions);
|
Chris@76
|
4237 }
|
Chris@76
|
4238
|
Chris@76
|
4239 // Remove an integration hook function.
|
Chris@76
|
4240 function remove_integration_function($hook, $function)
|
Chris@76
|
4241 {
|
Chris@76
|
4242 global $smcFunc, $modSettings;
|
Chris@76
|
4243
|
Chris@76
|
4244 // Get the permanent functions.
|
Chris@76
|
4245 $request = $smcFunc['db_query']('', '
|
Chris@76
|
4246 SELECT value
|
Chris@76
|
4247 FROM {db_prefix}settings
|
Chris@76
|
4248 WHERE variable = {string:variable}',
|
Chris@76
|
4249 array(
|
Chris@76
|
4250 'variable' => $hook,
|
Chris@76
|
4251 )
|
Chris@76
|
4252 );
|
Chris@76
|
4253 list($current_functions) = $smcFunc['db_fetch_row']($request);
|
Chris@76
|
4254 $smcFunc['db_free_result']($request);
|
Chris@76
|
4255
|
Chris@76
|
4256 if (!empty($current_functions))
|
Chris@76
|
4257 {
|
Chris@76
|
4258 $current_functions = explode(',', $current_functions);
|
Chris@76
|
4259
|
Chris@76
|
4260 if (in_array($function, $current_functions))
|
Chris@76
|
4261 updateSettings(array($hook => implode(',', array_diff($current_functions, array($function)))));
|
Chris@76
|
4262 }
|
Chris@76
|
4263
|
Chris@76
|
4264 // Turn the function list into something usable.
|
Chris@76
|
4265 $functions = empty($modSettings[$hook]) ? array() : explode(',', $modSettings[$hook]);
|
Chris@76
|
4266
|
Chris@76
|
4267 // You can only remove it if it's available.
|
Chris@76
|
4268 if (!in_array($function, $functions))
|
Chris@76
|
4269 return;
|
Chris@76
|
4270
|
Chris@76
|
4271 $functions = array_diff($functions, array($function));
|
Chris@76
|
4272 $modSettings[$hook] = implode(',', $functions);
|
Chris@76
|
4273 }
|
Chris@76
|
4274
|
Chris@76
|
4275 ?> |