Yoshi2889 /
SMF2.1
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * This file concerns itself with logging, whether in the database or files. |
||
| 5 | * |
||
| 6 | * Simple Machines Forum (SMF) |
||
| 7 | * |
||
| 8 | * @package SMF |
||
| 9 | * @author Simple Machines http://www.simplemachines.org |
||
| 10 | * @copyright 2017 Simple Machines and individual contributors |
||
| 11 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
| 12 | * |
||
| 13 | * @version 2.1 Beta 4 |
||
| 14 | */ |
||
| 15 | |||
| 16 | if (!defined('SMF')) |
||
| 17 | die('No direct access...'); |
||
| 18 | |||
| 19 | /** |
||
| 20 | * Truncate the GET array to a specified length |
||
| 21 | * @param array $arr The array to truncate |
||
| 22 | * @param max_length $max_length The upperbound on the length |
||
| 23 | * |
||
| 24 | * @return array The truncated array |
||
| 25 | */ |
||
| 26 | function truncateArray($arr, $max_length=1900) |
||
| 27 | { |
||
| 28 | $curr_length = array_sum(array_map("strlen", $arr)); |
||
| 29 | if ($curr_length <= $max_length) |
||
| 30 | return $arr; |
||
| 31 | else |
||
| 32 | { |
||
| 33 | // Truncate each element's value to a reasonable length |
||
| 34 | $param_max = floor($max_length/count($arr)); |
||
| 35 | foreach ($arr as $key => &$value) |
||
| 36 | $value = substr($value, 0, $param_max - strlen($key) - 5); |
||
| 37 | return $arr; |
||
| 38 | } |
||
| 39 | } |
||
| 40 | |||
| 41 | /** |
||
| 42 | * Put this user in the online log. |
||
| 43 | * |
||
| 44 | * @param bool $force Whether to force logging the data |
||
| 45 | */ |
||
| 46 | function writeLog($force = false) |
||
| 47 | { |
||
| 48 | global $user_info, $user_settings, $context, $modSettings, $settings, $topic, $board, $smcFunc, $sourcedir; |
||
| 49 | |||
| 50 | // 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. |
||
| 51 | if (!empty($settings['display_who_viewing']) && ($topic || $board)) |
||
| 52 | { |
||
| 53 | // Take the opposite approach! |
||
| 54 | $force = true; |
||
| 55 | // Don't update for every page - this isn't wholly accurate but who cares. |
||
| 56 | if ($topic) |
||
| 57 | { |
||
| 58 | if (isset($_SESSION['last_topic_id']) && $_SESSION['last_topic_id'] == $topic) |
||
| 59 | $force = false; |
||
| 60 | $_SESSION['last_topic_id'] = $topic; |
||
| 61 | } |
||
| 62 | } |
||
| 63 | |||
| 64 | // Are they a spider we should be tracking? Mode = 1 gets tracked on its spider check... |
||
| 65 | if (!empty($user_info['possibly_robot']) && !empty($modSettings['spider_mode']) && $modSettings['spider_mode'] > 1) |
||
| 66 | { |
||
| 67 | require_once($sourcedir . '/ManageSearchEngines.php'); |
||
| 68 | logSpider(); |
||
| 69 | } |
||
| 70 | |||
| 71 | // Don't mark them as online more than every so often. |
||
| 72 | if (!empty($_SESSION['log_time']) && $_SESSION['log_time'] >= (time() - 8) && !$force) |
||
| 73 | return; |
||
| 74 | |||
| 75 | if (!empty($modSettings['who_enabled'])) |
||
| 76 | { |
||
| 77 | $encoded_get = truncateArray($_GET) + array('USER_AGENT' => $_SERVER['HTTP_USER_AGENT']); |
||
| 78 | |||
| 79 | // In the case of a dlattach action, session_var may not be set. |
||
| 80 | if (!isset($context['session_var'])) |
||
| 81 | $context['session_var'] = $_SESSION['session_var']; |
||
| 82 | |||
| 83 | unset($encoded_get['sesc'], $encoded_get[$context['session_var']]); |
||
| 84 | $encoded_get = $smcFunc['json_encode']($encoded_get); |
||
| 85 | } |
||
| 86 | else |
||
| 87 | $encoded_get = ''; |
||
| 88 | |||
| 89 | // Guests use 0, members use their session ID. |
||
| 90 | $session_id = $user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id(); |
||
| 91 | |||
| 92 | // Grab the last all-of-SMF-specific log_online deletion time. |
||
| 93 | $do_delete = cache_get_data('log_online-update', 30) < time() - 30; |
||
| 94 | |||
| 95 | // If the last click wasn't a long time ago, and there was a last click... |
||
| 96 | if (!empty($_SESSION['log_time']) && $_SESSION['log_time'] >= time() - $modSettings['lastActive'] * 20) |
||
| 97 | { |
||
| 98 | if ($do_delete) |
||
| 99 | { |
||
| 100 | $smcFunc['db_query']('delete_log_online_interval', ' |
||
| 101 | DELETE FROM {db_prefix}log_online |
||
| 102 | WHERE log_time < {int:log_time} |
||
| 103 | AND session != {string:session}', |
||
| 104 | array( |
||
| 105 | 'log_time' => time() - $modSettings['lastActive'] * 60, |
||
| 106 | 'session' => $session_id, |
||
| 107 | ) |
||
| 108 | ); |
||
| 109 | |||
| 110 | // Cache when we did it last. |
||
| 111 | cache_put_data('log_online-update', time(), 30); |
||
| 112 | } |
||
| 113 | |||
| 114 | $smcFunc['db_query']('', ' |
||
| 115 | UPDATE {db_prefix}log_online |
||
| 116 | SET log_time = {int:log_time}, ip = {inet:ip}, url = {string:url} |
||
| 117 | WHERE session = {string:session}', |
||
| 118 | array( |
||
| 119 | 'log_time' => time(), |
||
| 120 | 'ip' => $user_info['ip'], |
||
| 121 | 'url' => $encoded_get, |
||
| 122 | 'session' => $session_id, |
||
| 123 | ) |
||
| 124 | ); |
||
| 125 | |||
| 126 | // Guess it got deleted. |
||
| 127 | if ($smcFunc['db_affected_rows']() == 0) |
||
| 128 | $_SESSION['log_time'] = 0; |
||
| 129 | } |
||
| 130 | else |
||
| 131 | $_SESSION['log_time'] = 0; |
||
| 132 | |||
| 133 | // Otherwise, we have to delete and insert. |
||
| 134 | if (empty($_SESSION['log_time'])) |
||
| 135 | { |
||
| 136 | if ($do_delete || !empty($user_info['id'])) |
||
| 137 | $smcFunc['db_query']('', ' |
||
| 138 | DELETE FROM {db_prefix}log_online |
||
| 139 | WHERE ' . ($do_delete ? 'log_time < {int:log_time}' : '') . ($do_delete && !empty($user_info['id']) ? ' OR ' : '') . (empty($user_info['id']) ? '' : 'id_member = {int:current_member}'), |
||
| 140 | array( |
||
| 141 | 'current_member' => $user_info['id'], |
||
| 142 | 'log_time' => time() - $modSettings['lastActive'] * 60, |
||
| 143 | ) |
||
| 144 | ); |
||
| 145 | |||
| 146 | $smcFunc['db_insert']($do_delete ? 'ignore' : 'replace', |
||
| 147 | '{db_prefix}log_online', |
||
| 148 | array('session' => 'string', 'id_member' => 'int', 'id_spider' => 'int', 'log_time' => 'int', 'ip' => 'inet', 'url' => 'string'), |
||
| 149 | array($session_id, $user_info['id'], empty($_SESSION['id_robot']) ? 0 : $_SESSION['id_robot'], time(), $user_info['ip'], $encoded_get), |
||
| 150 | array('session') |
||
| 151 | ); |
||
| 152 | } |
||
| 153 | |||
| 154 | // Mark your session as being logged. |
||
| 155 | $_SESSION['log_time'] = time(); |
||
| 156 | |||
| 157 | // Well, they are online now. |
||
| 158 | if (empty($_SESSION['timeOnlineUpdated'])) |
||
| 159 | $_SESSION['timeOnlineUpdated'] = time(); |
||
| 160 | |||
| 161 | // Set their login time, if not already done within the last minute. |
||
| 162 | if (SMF != 'SSI' && !empty($user_info['last_login']) && $user_info['last_login'] < time() - 60 && (!isset($_REQUEST['action']) || !in_array($_REQUEST['action'], array('.xml', 'login2', 'logintfa')))) |
||
| 163 | { |
||
| 164 | // Don't count longer than 15 minutes. |
||
| 165 | if (time() - $_SESSION['timeOnlineUpdated'] > 60 * 15) |
||
| 166 | $_SESSION['timeOnlineUpdated'] = time(); |
||
| 167 | |||
| 168 | $user_settings['total_time_logged_in'] += time() - $_SESSION['timeOnlineUpdated']; |
||
| 169 | 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'])); |
||
| 170 | |||
| 171 | if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) |
||
| 172 | cache_put_data('user_settings-' . $user_info['id'], $user_settings, 60); |
||
| 173 | |||
| 174 | $user_info['total_time_logged_in'] += time() - $_SESSION['timeOnlineUpdated']; |
||
| 175 | $_SESSION['timeOnlineUpdated'] = time(); |
||
| 176 | } |
||
| 177 | } |
||
| 178 | |||
| 179 | /** |
||
| 180 | * Logs the last database error into a file. |
||
| 181 | * Attempts to use the backup file first, to store the last database error |
||
| 182 | * and only update db_last_error.php if the first was successful. |
||
| 183 | */ |
||
| 184 | function logLastDatabaseError() |
||
| 185 | { |
||
| 186 | global $boarddir; |
||
| 187 | |||
| 188 | // Make a note of the last modified time in case someone does this before us |
||
| 189 | $last_db_error_change = @filemtime($boarddir . '/db_last_error.php'); |
||
| 190 | |||
| 191 | // save the old file before we do anything |
||
| 192 | $file = $boarddir . '/db_last_error.php'; |
||
| 193 | $dberror_backup_fail = !@is_writable($boarddir . '/db_last_error_bak.php') || !@copy($file, $boarddir . '/db_last_error_bak.php'); |
||
| 194 | $dberror_backup_fail = !$dberror_backup_fail ? (!file_exists($boarddir . '/db_last_error_bak.php') || filesize($boarddir . '/db_last_error_bak.php') === 0) : $dberror_backup_fail; |
||
| 195 | |||
| 196 | clearstatcache(); |
||
| 197 | if (filemtime($boarddir . '/db_last_error.php') === $last_db_error_change) |
||
| 198 | { |
||
| 199 | // Write the change |
||
| 200 | $write_db_change = '<' . '?' . "php\n" . '$db_last_error = ' . time() . ';' . "\n" . '?' . '>'; |
||
| 201 | $written_bytes = file_put_contents($boarddir . '/db_last_error.php', $write_db_change, LOCK_EX); |
||
| 202 | |||
| 203 | // survey says ... |
||
| 204 | if ($written_bytes !== strlen($write_db_change) && !$dberror_backup_fail) |
||
| 205 | { |
||
| 206 | // Oops. maybe we have no more disk space left, or some other troubles, troubles... |
||
| 207 | // Copy the file back and run for your life! |
||
| 208 | @copy($boarddir . '/db_last_error_bak.php', $boarddir . '/db_last_error.php'); |
||
|
0 ignored issues
–
show
|
|||
| 209 | } |
||
| 210 | else |
||
| 211 | { |
||
| 212 | @touch($boarddir . '/' . 'Settings.php'); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 213 | return true; |
||
| 214 | } |
||
| 215 | } |
||
| 216 | |||
| 217 | return false; |
||
| 218 | } |
||
| 219 | |||
| 220 | /** |
||
| 221 | * This function shows the debug information tracked when $db_show_debug = true |
||
| 222 | * in Settings.php |
||
| 223 | */ |
||
| 224 | function displayDebug() |
||
| 225 | { |
||
| 226 | global $context, $scripturl, $boarddir, $sourcedir, $cachedir, $settings, $modSettings; |
||
| 227 | global $db_cache, $db_count, $cache_misses, $cache_count_misses, $db_show_debug, $cache_count, $cache_hits, $smcFunc, $txt; |
||
| 228 | |||
| 229 | // Add to Settings.php if you want to show the debugging information. |
||
| 230 | if (!isset($db_show_debug) || $db_show_debug !== true || (isset($_GET['action']) && $_GET['action'] == 'viewquery')) |
||
| 231 | return; |
||
| 232 | |||
| 233 | if (empty($_SESSION['view_queries'])) |
||
| 234 | $_SESSION['view_queries'] = 0; |
||
| 235 | if (empty($context['debug']['language_files'])) |
||
| 236 | $context['debug']['language_files'] = array(); |
||
| 237 | if (empty($context['debug']['sheets'])) |
||
| 238 | $context['debug']['sheets'] = array(); |
||
| 239 | |||
| 240 | $files = get_included_files(); |
||
| 241 | $total_size = 0; |
||
| 242 | for ($i = 0, $n = count($files); $i < $n; $i++) |
||
| 243 | { |
||
| 244 | if (file_exists($files[$i])) |
||
| 245 | $total_size += filesize($files[$i]); |
||
| 246 | $files[$i] = strtr($files[$i], array($boarddir => '.', $sourcedir => '(Sources)', $cachedir => '(Cache)', $settings['actual_theme_dir'] => '(Current Theme)')); |
||
| 247 | } |
||
| 248 | |||
| 249 | $warnings = 0; |
||
| 250 | if (!empty($db_cache)) |
||
| 251 | { |
||
| 252 | foreach ($db_cache as $q => $qq) |
||
| 253 | { |
||
| 254 | if (!empty($qq['w'])) |
||
| 255 | $warnings += count($qq['w']); |
||
| 256 | } |
||
| 257 | |||
| 258 | $_SESSION['debug'] = &$db_cache; |
||
| 259 | } |
||
| 260 | |||
| 261 | // Gotta have valid HTML ;). |
||
| 262 | $temp = ob_get_contents(); |
||
| 263 | ob_clean(); |
||
| 264 | |||
| 265 | echo preg_replace('~</body>\s*</html>~', '', $temp), ' |
||
| 266 | <div class="smalltext" style="text-align: left; margin: 1ex;"> |
||
| 267 | ', $txt['debug_browser'], $context['browser_body_id'], ' <em>(', implode('</em>, <em>', array_reverse(array_keys($context['browser'], true))), ')</em><br> |
||
| 268 | ', $txt['debug_templates'], count($context['debug']['templates']), ': <em>', implode('</em>, <em>', $context['debug']['templates']), '</em>.<br> |
||
| 269 | ', $txt['debug_subtemplates'], count($context['debug']['sub_templates']), ': <em>', implode('</em>, <em>', $context['debug']['sub_templates']), '</em>.<br> |
||
| 270 | ', $txt['debug_language_files'], count($context['debug']['language_files']), ': <em>', implode('</em>, <em>', $context['debug']['language_files']), '</em>.<br> |
||
| 271 | ', $txt['debug_stylesheets'], count($context['debug']['sheets']), ': <em>', implode('</em>, <em>', $context['debug']['sheets']), '</em>.<br> |
||
| 272 | ', $txt['debug_hooks'], empty($context['debug']['hooks']) ? 0 : count($context['debug']['hooks']) . ' (<a href="javascript:void(0);" onclick="document.getElementById(\'debug_hooks\').style.display = \'inline\'; this.style.display = \'none\'; return false;">', $txt['debug_show'], '</a><span id="debug_hooks" style="display: none;"><em>' . implode('</em>, <em>', $context['debug']['hooks']), '</em></span>)', '<br> |
||
| 273 | ',(isset($context['debug']['instances']) ? ($txt['debug_instances'] . (empty($context['debug']['instances']) ? 0 : count($context['debug']['instances'])) . ' (<a href="javascript:void(0);" onclick="document.getElementById(\'debug_instances\').style.display = \'inline\'; this.style.display = \'none\'; return false;">'. $txt['debug_show'] .'</a><span id="debug_instances" style="display: none;"><em>'. implode('</em>, <em>', array_keys($context['debug']['instances'])) .'</em></span>)'. '<br>') : ''),' |
||
| 274 | ', $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>'; |
||
| 275 | |||
| 276 | if (function_exists('memory_get_peak_usage')) |
||
| 277 | echo $txt['debug_memory_use'], ceil(memory_get_peak_usage() / 1024), $txt['debug_kb'], '<br>'; |
||
| 278 | |||
| 279 | // What tokens are active? |
||
| 280 | if (isset($_SESSION['token'])) |
||
| 281 | echo $txt['debug_tokens'] . '<em>' . implode(',</em> <em>', array_keys($_SESSION['token'])), '</em>.<br>'; |
||
| 282 | |||
| 283 | if (!empty($modSettings['cache_enable']) && !empty($cache_hits)) |
||
| 284 | { |
||
| 285 | $missed_entries = array(); |
||
| 286 | $entries = array(); |
||
| 287 | $total_t = 0; |
||
| 288 | $total_s = 0; |
||
| 289 | foreach ($cache_hits as $cache_hit) |
||
| 290 | { |
||
| 291 | $entries[] = $cache_hit['d'] . ' ' . $cache_hit['k'] . ': ' . sprintf($txt['debug_cache_seconds_bytes'], comma_format($cache_hit['t'], 5), $cache_hit['s']); |
||
| 292 | $total_t += $cache_hit['t']; |
||
| 293 | $total_s += $cache_hit['s']; |
||
| 294 | } |
||
| 295 | if (!isset($cache_misses)) |
||
| 296 | $cache_misses = array(); |
||
| 297 | foreach ($cache_misses as $missed) |
||
| 298 | $missed_entries[] = $missed['d'] . ' ' . $missed['k']; |
||
| 299 | |||
| 300 | echo ' |
||
| 301 | ', $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> |
||
| 302 | ', $txt['debug_cache_misses'], $cache_count_misses, ': (<a href="javascript:void(0);" onclick="document.getElementById(\'debug_cache_misses_info\').style.display = \'inline\'; this.style.display = \'none\'; return false;">', $txt['debug_show'], '</a><span id="debug_cache_misses_info" style="display: none;"><em>', implode('</em>, <em>', $missed_entries), '</em></span>)<br>'; |
||
| 303 | } |
||
| 304 | |||
| 305 | echo ' |
||
| 306 | <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> |
||
| 307 | <br>'; |
||
| 308 | |||
| 309 | if ($_SESSION['view_queries'] == 1 && !empty($db_cache)) |
||
| 310 | foreach ($db_cache as $q => $qq) |
||
| 311 | { |
||
| 312 | $is_select = strpos(trim($qq['q']), 'SELECT') === 0 || preg_match('~^INSERT(?: IGNORE)? INTO \w+(?:\s+\([^)]+\))?\s+SELECT .+$~s', trim($qq['q'])) != 0; |
||
| 313 | // Temporary tables created in earlier queries are not explainable. |
||
| 314 | if ($is_select) |
||
| 315 | { |
||
| 316 | View Code Duplication | foreach (array('log_topics_unread', 'topics_posted_in', 'tmp_log_search_topics', 'tmp_log_search_messages') as $tmp) |
|
| 317 | if (strpos(trim($qq['q']), $tmp) !== false) |
||
| 318 | { |
||
| 319 | $is_select = false; |
||
| 320 | break; |
||
| 321 | } |
||
| 322 | } |
||
| 323 | // But actual creation of the temporary tables are. |
||
| 324 | elseif (preg_match('~^CREATE TEMPORARY TABLE .+?SELECT .+$~s', trim($qq['q'])) != 0) |
||
| 325 | $is_select = true; |
||
| 326 | |||
| 327 | // Make the filenames look a bit better. |
||
| 328 | View Code Duplication | if (isset($qq['f'])) |
|
| 329 | $qq['f'] = preg_replace('~^' . preg_quote($boarddir, '~') . '~', '...', $qq['f']); |
||
| 330 | |||
| 331 | echo ' |
||
| 332 | <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", ' ', $smcFunc['htmlspecialchars'](ltrim($qq['q'], "\n\r")))) . ($is_select ? '</a></strong>' : '</strong>') . '<br> |
||
| 333 | '; |
||
| 334 | View Code Duplication | if (!empty($qq['f']) && !empty($qq['l'])) |
|
| 335 | echo sprintf($txt['debug_query_in_line'], $qq['f'], $qq['l']); |
||
| 336 | |||
| 337 | if (isset($qq['s'], $qq['t']) && isset($txt['debug_query_which_took_at'])) |
||
| 338 | echo sprintf($txt['debug_query_which_took_at'], round($qq['t'], 8), round($qq['s'], 8)) . '<br>'; |
||
| 339 | elseif (isset($qq['t'])) |
||
| 340 | echo sprintf($txt['debug_query_which_took'], round($qq['t'], 8)) . '<br>'; |
||
| 341 | echo ' |
||
| 342 | <br>'; |
||
| 343 | } |
||
| 344 | |||
| 345 | echo ' |
||
| 346 | <a href="' . $scripturl . '?action=viewquery;sa=hide">', $txt['debug_' . (empty($_SESSION['view_queries']) ? 'show' : 'hide') . '_queries'], '</a> |
||
| 347 | </div></body></html>'; |
||
| 348 | } |
||
| 349 | |||
| 350 | /** |
||
| 351 | * Track Statistics. |
||
| 352 | * Caches statistics changes, and flushes them if you pass nothing. |
||
| 353 | * If '+' is used as a value, it will be incremented. |
||
| 354 | * It does not actually commit the changes until the end of the page view. |
||
| 355 | * It depends on the trackStats setting. |
||
| 356 | * |
||
| 357 | * @param array $stats An array of data |
||
| 358 | * @return bool Whether or not the info was updated successfully |
||
| 359 | */ |
||
| 360 | function trackStats($stats = array()) |
||
| 361 | { |
||
| 362 | global $modSettings, $smcFunc; |
||
| 363 | static $cache_stats = array(); |
||
| 364 | |||
| 365 | if (empty($modSettings['trackStats'])) |
||
| 366 | return false; |
||
| 367 | if (!empty($stats)) |
||
| 368 | return $cache_stats = array_merge($cache_stats, $stats); |
||
| 369 | elseif (empty($cache_stats)) |
||
| 370 | return false; |
||
| 371 | |||
| 372 | $setStringUpdate = ''; |
||
| 373 | $insert_keys = array(); |
||
| 374 | $date = strftime('%Y-%m-%d', forum_time(false)); |
||
| 375 | $update_parameters = array( |
||
| 376 | 'current_date' => $date, |
||
| 377 | ); |
||
| 378 | foreach ($cache_stats as $field => $change) |
||
| 379 | { |
||
| 380 | $setStringUpdate .= ' |
||
| 381 | ' . $field . ' = ' . ($change === '+' ? $field . ' + 1' : '{int:' . $field . '}') . ','; |
||
| 382 | |||
| 383 | if ($change === '+') |
||
| 384 | $cache_stats[$field] = 1; |
||
| 385 | else |
||
| 386 | $update_parameters[$field] = $change; |
||
| 387 | $insert_keys[$field] = 'int'; |
||
| 388 | } |
||
| 389 | |||
| 390 | $smcFunc['db_query']('', ' |
||
| 391 | UPDATE {db_prefix}log_activity |
||
| 392 | SET' . substr($setStringUpdate, 0, -1) . ' |
||
| 393 | WHERE date = {date:current_date}', |
||
| 394 | $update_parameters |
||
| 395 | ); |
||
| 396 | if ($smcFunc['db_affected_rows']() == 0) |
||
| 397 | { |
||
| 398 | $smcFunc['db_insert']('ignore', |
||
| 399 | '{db_prefix}log_activity', |
||
| 400 | array_merge($insert_keys, array('date' => 'date')), |
||
| 401 | array_merge($cache_stats, array($date)), |
||
| 402 | array('date') |
||
| 403 | ); |
||
| 404 | } |
||
| 405 | |||
| 406 | // Don't do this again. |
||
| 407 | $cache_stats = array(); |
||
| 408 | |||
| 409 | return true; |
||
| 410 | } |
||
| 411 | |||
| 412 | /** |
||
| 413 | * This function logs an action in the respective log. (database log) |
||
| 414 | * You should use {@link logActions()} instead. |
||
| 415 | * @example logAction('remove', array('starter' => $id_member_started)); |
||
| 416 | * |
||
| 417 | * @param string $action The action to log |
||
| 418 | * @param array $extra = array() An array of additional data |
||
| 419 | * @param string $log_type What type of log ('admin', 'moderate', etc.) |
||
| 420 | * @return int The ID of the row containing the logged data |
||
| 421 | */ |
||
| 422 | function logAction($action, $extra = array(), $log_type = 'moderate') |
||
| 423 | { |
||
| 424 | return logActions(array(array( |
||
| 425 | 'action' => $action, |
||
| 426 | 'log_type' => $log_type, |
||
| 427 | 'extra' => $extra, |
||
| 428 | ))); |
||
| 429 | } |
||
| 430 | |||
| 431 | /** |
||
| 432 | * Log changes to the forum, such as moderation events or administrative changes. |
||
| 433 | * This behaves just like logAction() in SMF 2.0, except that it is designed to log multiple actions at once. |
||
| 434 | * |
||
| 435 | * @param array $logs An array of log data |
||
| 436 | * @return int The last logged ID |
||
| 437 | */ |
||
| 438 | function logActions($logs) |
||
| 439 | { |
||
| 440 | global $modSettings, $user_info, $smcFunc, $sourcedir; |
||
| 441 | |||
| 442 | $inserts = array(); |
||
| 443 | $log_types = array( |
||
| 444 | 'moderate' => 1, |
||
| 445 | 'user' => 2, |
||
| 446 | 'admin' => 3, |
||
| 447 | ); |
||
| 448 | |||
| 449 | // Make sure this particular log is enabled first... |
||
| 450 | if (empty($modSettings['modlog_enabled'])) |
||
| 451 | unset ($log_types['moderate']); |
||
| 452 | if (empty($modSettings['userlog_enabled'])) |
||
| 453 | unset ($log_types['user']); |
||
| 454 | if (empty($modSettings['adminlog_enabled'])) |
||
| 455 | unset ($log_types['admin']); |
||
| 456 | |||
| 457 | call_integration_hook('integrate_log_types', array(&$log_types)); |
||
| 458 | |||
| 459 | foreach ($logs as $log) |
||
| 460 | { |
||
| 461 | if (!isset($log_types[$log['log_type']])) |
||
| 462 | return false; |
||
| 463 | |||
| 464 | if (!is_array($log['extra'])) |
||
| 465 | trigger_error('logActions(): data is not an array with action \'' . $log['action'] . '\'', E_USER_NOTICE); |
||
| 466 | |||
| 467 | // Pull out the parts we want to store separately, but also make sure that the data is proper |
||
| 468 | View Code Duplication | if (isset($log['extra']['topic'])) |
|
| 469 | { |
||
| 470 | if (!is_numeric($log['extra']['topic'])) |
||
| 471 | trigger_error('logActions(): data\'s topic is not a number', E_USER_NOTICE); |
||
| 472 | $topic_id = empty($log['extra']['topic']) ? 0 : (int) $log['extra']['topic']; |
||
| 473 | unset($log['extra']['topic']); |
||
| 474 | } |
||
| 475 | else |
||
| 476 | $topic_id = 0; |
||
| 477 | |||
| 478 | View Code Duplication | if (isset($log['extra']['message'])) |
|
| 479 | { |
||
| 480 | if (!is_numeric($log['extra']['message'])) |
||
| 481 | trigger_error('logActions(): data\'s message is not a number', E_USER_NOTICE); |
||
| 482 | $msg_id = empty($log['extra']['message']) ? 0 : (int) $log['extra']['message']; |
||
| 483 | unset($log['extra']['message']); |
||
| 484 | } |
||
| 485 | else |
||
| 486 | $msg_id = 0; |
||
| 487 | |||
| 488 | // @todo cache this? |
||
| 489 | // Is there an associated report on this? |
||
| 490 | if (in_array($log['action'], array('move', 'remove', 'split', 'merge'))) |
||
| 491 | { |
||
| 492 | $request = $smcFunc['db_query']('', ' |
||
| 493 | SELECT id_report |
||
| 494 | FROM {db_prefix}log_reported |
||
| 495 | WHERE {raw:column_name} = {int:reported} |
||
| 496 | LIMIT 1', |
||
| 497 | array( |
||
| 498 | 'column_name' => !empty($msg_id) ? 'id_msg' : 'id_topic', |
||
| 499 | 'reported' => !empty($msg_id) ? $msg_id : $topic_id, |
||
| 500 | )); |
||
| 501 | |||
| 502 | // Alright, if we get any result back, update open reports. |
||
| 503 | View Code Duplication | if ($smcFunc['db_num_rows']($request) > 0) |
|
| 504 | { |
||
| 505 | require_once($sourcedir . '/ModerationCenter.php'); |
||
| 506 | require_once($sourcedir . '/Subs-ReportedContent.php'); |
||
| 507 | updateSettings(array('last_mod_report_action' => time())); |
||
| 508 | recountOpenReports('posts'); |
||
| 509 | } |
||
| 510 | $smcFunc['db_free_result']($request); |
||
| 511 | } |
||
| 512 | |||
| 513 | if (isset($log['extra']['member']) && !is_numeric($log['extra']['member'])) |
||
| 514 | trigger_error('logActions(): data\'s member is not a number', E_USER_NOTICE); |
||
| 515 | |||
| 516 | View Code Duplication | if (isset($log['extra']['board'])) |
|
| 517 | { |
||
| 518 | if (!is_numeric($log['extra']['board'])) |
||
| 519 | trigger_error('logActions(): data\'s board is not a number', E_USER_NOTICE); |
||
| 520 | $board_id = empty($log['extra']['board']) ? 0 : (int) $log['extra']['board']; |
||
| 521 | unset($log['extra']['board']); |
||
| 522 | } |
||
| 523 | else |
||
| 524 | $board_id = 0; |
||
| 525 | |||
| 526 | View Code Duplication | if (isset($log['extra']['board_to'])) |
|
| 527 | { |
||
| 528 | if (!is_numeric($log['extra']['board_to'])) |
||
| 529 | trigger_error('logActions(): data\'s board_to is not a number', E_USER_NOTICE); |
||
| 530 | if (empty($board_id)) |
||
| 531 | { |
||
| 532 | $board_id = empty($log['extra']['board_to']) ? 0 : (int) $log['extra']['board_to']; |
||
| 533 | unset($log['extra']['board_to']); |
||
| 534 | } |
||
| 535 | } |
||
| 536 | |||
| 537 | if (isset($log['extra']['member_affected'])) |
||
| 538 | $memID = $log['extra']['member_affected']; |
||
| 539 | else |
||
| 540 | $memID = $user_info['id']; |
||
| 541 | |||
| 542 | $inserts[] = array( |
||
| 543 | time(), $log_types[$log['log_type']], $memID, $user_info['ip'], $log['action'], |
||
| 544 | $board_id, $topic_id, $msg_id, $smcFunc['json_encode']($log['extra']), |
||
| 545 | ); |
||
| 546 | } |
||
| 547 | |||
| 548 | $id_action = $smcFunc['db_insert']('', |
||
| 549 | '{db_prefix}log_actions', |
||
| 550 | array( |
||
| 551 | 'log_time' => 'int', 'id_log' => 'int', 'id_member' => 'int', 'ip' => 'inet', 'action' => 'string', |
||
| 552 | 'id_board' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'extra' => 'string-65534', |
||
| 553 | ), |
||
| 554 | $inserts, |
||
| 555 | array('id_action'), |
||
| 556 | 1 |
||
| 557 | ); |
||
| 558 | |||
| 559 | return $id_action; |
||
| 560 | } |
||
| 561 | |||
| 562 | ?> |
If you suppress an error, we recommend checking for the error condition explicitly: