annotate forum/Sources/Subs-Admin.php @ 76:e3e11437ecea website

Add forum code
author Chris Cannam
date Sun, 07 Jul 2013 11:25:48 +0200
parents
children
rev   line source
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 contains functions that are specifically done by administrators.
Chris@76 18 The most important function in this file for mod makers happens to be the
Chris@76 19 updateSettingsFile() function, but it shouldn't be used often anyway.
Chris@76 20
Chris@76 21 void getServerVersions(array checkFor)
Chris@76 22 - get a list of versions that are currently installed on the server.
Chris@76 23
Chris@76 24 void getFileVersions(array versionOptions)
Chris@76 25 - get detailed version information about the physical SMF files on the
Chris@76 26 server.
Chris@76 27 - the input parameter allows to set whether to include SSI.php and
Chris@76 28 whether the results should be sorted.
Chris@76 29 - returns an array containing information on source files, templates
Chris@76 30 and language files found in the default theme directory (grouped by
Chris@76 31 language).
Chris@76 32
Chris@76 33 void updateSettingsFile(array config_vars)
Chris@76 34 - updates the Settings.php file with the changes in config_vars.
Chris@76 35 - expects config_vars to be an associative array, with the keys as the
Chris@76 36 variable names in Settings.php, and the values the varaible values.
Chris@76 37 - does not escape or quote values.
Chris@76 38 - preserves case, formatting, and additional options in file.
Chris@76 39 - writes nothing if the resulting file would be less than 10 lines
Chris@76 40 in length (sanity check for read lock.)
Chris@76 41
Chris@76 42 void updateAdminPreferences()
Chris@76 43 - saves the admins current preferences to the database.
Chris@76 44
Chris@76 45 void emailAdmins(string $template, array $replacements = array(), additional_recipients = array())
Chris@76 46 - loads all users who are admins or have the admin forum permission.
Chris@76 47 - uses the email template and replacements passed in the parameters.
Chris@76 48 - sends them an email.
Chris@76 49
Chris@76 50 bool updateLastDatabaseError()
Chris@76 51 - attempts to use the backup file first, to store the last database error
Chris@76 52 - and only update Settings.php if the first was successful.
Chris@76 53
Chris@76 54 */
Chris@76 55
Chris@76 56 function getServerVersions($checkFor)
Chris@76 57 {
Chris@76 58 global $txt, $db_connection, $_PHPA, $smcFunc, $memcached, $modSettings;
Chris@76 59
Chris@76 60 loadLanguage('Admin');
Chris@76 61
Chris@76 62 $versions = array();
Chris@76 63
Chris@76 64 // Is GD available? If it is, we should show version information for it too.
Chris@76 65 if (in_array('gd', $checkFor) && function_exists('gd_info'))
Chris@76 66 {
Chris@76 67 $temp = gd_info();
Chris@76 68 $versions['gd'] = array('title' => $txt['support_versions_gd'], 'version' => $temp['GD Version']);
Chris@76 69 }
Chris@76 70
Chris@76 71 // Now lets check for the Database.
Chris@76 72 if (in_array('db_server', $checkFor))
Chris@76 73 {
Chris@76 74 db_extend();
Chris@76 75 if (!isset($db_connection) || $db_connection === false)
Chris@76 76 trigger_error('getServerVersions(): you need to be connected to the database in order to get its server version', E_USER_NOTICE);
Chris@76 77 else
Chris@76 78 {
Chris@76 79 $versions['db_server'] = array('title' => sprintf($txt['support_versions_db'], $smcFunc['db_title']), 'version' => '');
Chris@76 80 $versions['db_server']['version'] = $smcFunc['db_get_version']();
Chris@76 81 }
Chris@76 82 }
Chris@76 83
Chris@76 84 // If we're using memcache we need the server info.
Chris@76 85 if (empty($memcached) && function_exists('memcache_get') && isset($modSettings['cache_memcached']) && trim($modSettings['cache_memcached']) != '')
Chris@76 86 get_memcached_server();
Chris@76 87
Chris@76 88 // Check to see if we have any accelerators installed...
Chris@76 89 if (in_array('mmcache', $checkFor) && defined('MMCACHE_VERSION'))
Chris@76 90 $versions['mmcache'] = array('title' => 'Turck MMCache', 'version' => MMCACHE_VERSION);
Chris@76 91 if (in_array('eaccelerator', $checkFor) && defined('EACCELERATOR_VERSION'))
Chris@76 92 $versions['eaccelerator'] = array('title' => 'eAccelerator', 'version' => EACCELERATOR_VERSION);
Chris@76 93 if (in_array('phpa', $checkFor) && isset($_PHPA))
Chris@76 94 $versions['phpa'] = array('title' => 'ionCube PHP-Accelerator', 'version' => $_PHPA['VERSION']);
Chris@76 95 if (in_array('apc', $checkFor) && extension_loaded('apc'))
Chris@76 96 $versions['apc'] = array('title' => 'Alternative PHP Cache', 'version' => phpversion('apc'));
Chris@76 97 if (in_array('memcache', $checkFor) && function_exists('memcache_set'))
Chris@76 98 $versions['memcache'] = array('title' => 'Memcached', 'version' => empty($memcached) ? '???' : memcache_get_version($memcached));
Chris@76 99 if (in_array('xcache', $checkFor) && function_exists('xcache_set'))
Chris@76 100 $versions['xcache'] = array('title' => 'XCache', 'version' => XCACHE_VERSION);
Chris@76 101 if (in_array('php', $checkFor))
Chris@76 102 $versions['php'] = array('title' => 'PHP', 'version' => PHP_VERSION);
Chris@76 103
Chris@76 104 if (in_array('server', $checkFor))
Chris@76 105 $versions['server'] = array('title' => $txt['support_versions_server'], 'version' => $_SERVER['SERVER_SOFTWARE']);
Chris@76 106
Chris@76 107 return $versions;
Chris@76 108 }
Chris@76 109
Chris@76 110 // Search through source, theme and language files to determine their version.
Chris@76 111 function getFileVersions(&$versionOptions)
Chris@76 112 {
Chris@76 113 global $boarddir, $sourcedir, $settings;
Chris@76 114
Chris@76 115 // Default place to find the languages would be the default theme dir.
Chris@76 116 $lang_dir = $settings['default_theme_dir'] . '/languages';
Chris@76 117
Chris@76 118 $version_info = array(
Chris@76 119 'file_versions' => array(),
Chris@76 120 'default_template_versions' => array(),
Chris@76 121 'template_versions' => array(),
Chris@76 122 'default_language_versions' => array(),
Chris@76 123 );
Chris@76 124
Chris@76 125 // Find the version in SSI.php's file header.
Chris@76 126 if (!empty($versionOptions['include_ssi']) && file_exists($boarddir . '/SSI.php'))
Chris@76 127 {
Chris@76 128 $fp = fopen($boarddir . '/SSI.php', 'rb');
Chris@76 129 $header = fread($fp, 4096);
Chris@76 130 fclose($fp);
Chris@76 131
Chris@76 132 // The comment looks rougly like... that.
Chris@76 133 if (preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $header, $match) == 1)
Chris@76 134 $version_info['file_versions']['SSI.php'] = $match[1];
Chris@76 135 // Not found! This is bad.
Chris@76 136 else
Chris@76 137 $version_info['file_versions']['SSI.php'] = '??';
Chris@76 138 }
Chris@76 139
Chris@76 140 // Do the paid subscriptions handler?
Chris@76 141 if (!empty($versionOptions['include_subscriptions']) && file_exists($boarddir . '/subscriptions.php'))
Chris@76 142 {
Chris@76 143 $fp = fopen($boarddir . '/subscriptions.php', 'rb');
Chris@76 144 $header = fread($fp, 4096);
Chris@76 145 fclose($fp);
Chris@76 146
Chris@76 147 // Found it?
Chris@76 148 if (preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $header, $match) == 1)
Chris@76 149 $version_info['file_versions']['subscriptions.php'] = $match[1];
Chris@76 150 // If we haven't how do we all get paid?
Chris@76 151 else
Chris@76 152 $version_info['file_versions']['subscriptions.php'] = '??';
Chris@76 153 }
Chris@76 154
Chris@76 155 // Load all the files in the Sources directory, except this file and the redirect.
Chris@76 156 $sources_dir = dir($sourcedir);
Chris@76 157 while ($entry = $sources_dir->read())
Chris@76 158 {
Chris@76 159 if (substr($entry, -4) === '.php' && !is_dir($sourcedir . '/' . $entry) && $entry !== 'index.php')
Chris@76 160 {
Chris@76 161 // Read the first 4k from the file.... enough for the header.
Chris@76 162 $fp = fopen($sourcedir . '/' . $entry, 'rb');
Chris@76 163 $header = fread($fp, 4096);
Chris@76 164 fclose($fp);
Chris@76 165
Chris@76 166 // Look for the version comment in the file header.
Chris@76 167 if (preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $header, $match) == 1)
Chris@76 168 $version_info['file_versions'][$entry] = $match[1];
Chris@76 169 // It wasn't found, but the file was... show a '??'.
Chris@76 170 else
Chris@76 171 $version_info['file_versions'][$entry] = '??';
Chris@76 172 }
Chris@76 173 }
Chris@76 174 $sources_dir->close();
Chris@76 175
Chris@76 176 // Load all the files in the default template directory - and the current theme if applicable.
Chris@76 177 $directories = array('default_template_versions' => $settings['default_theme_dir']);
Chris@76 178 if ($settings['theme_id'] != 1)
Chris@76 179 $directories += array('template_versions' => $settings['theme_dir']);
Chris@76 180
Chris@76 181 foreach ($directories as $type => $dirname)
Chris@76 182 {
Chris@76 183 $this_dir = dir($dirname);
Chris@76 184 while ($entry = $this_dir->read())
Chris@76 185 {
Chris@76 186 if (substr($entry, -12) == 'template.php' && !is_dir($dirname . '/' . $entry))
Chris@76 187 {
Chris@76 188 // Read the first 768 bytes from the file.... enough for the header.
Chris@76 189 $fp = fopen($dirname . '/' . $entry, 'rb');
Chris@76 190 $header = fread($fp, 768);
Chris@76 191 fclose($fp);
Chris@76 192
Chris@76 193 // Look for the version comment in the file header.
Chris@76 194 if (preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $header, $match) == 1)
Chris@76 195 $version_info[$type][$entry] = $match[1];
Chris@76 196 // It wasn't found, but the file was... show a '??'.
Chris@76 197 else
Chris@76 198 $version_info[$type][$entry] = '??';
Chris@76 199 }
Chris@76 200 }
Chris@76 201 $this_dir->close();
Chris@76 202 }
Chris@76 203
Chris@76 204 // Load up all the files in the default language directory and sort by language.
Chris@76 205 $this_dir = dir($lang_dir);
Chris@76 206 while ($entry = $this_dir->read())
Chris@76 207 {
Chris@76 208 if (substr($entry, -4) == '.php' && $entry != 'index.php' && !is_dir($lang_dir . '/' . $entry))
Chris@76 209 {
Chris@76 210 // Read the first 768 bytes from the file.... enough for the header.
Chris@76 211 $fp = fopen($lang_dir . '/' . $entry, 'rb');
Chris@76 212 $header = fread($fp, 768);
Chris@76 213 fclose($fp);
Chris@76 214
Chris@76 215 // Split the file name off into useful bits.
Chris@76 216 list ($name, $language) = explode('.', $entry);
Chris@76 217
Chris@76 218 // Look for the version comment in the file header.
Chris@76 219 if (preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*' . preg_quote($name, '~') . '(?:[\s]{2}|\*/)~i', $header, $match) == 1)
Chris@76 220 $version_info['default_language_versions'][$language][$name] = $match[1];
Chris@76 221 // It wasn't found, but the file was... show a '??'.
Chris@76 222 else
Chris@76 223 $version_info['default_language_versions'][$language][$name] = '??';
Chris@76 224 }
Chris@76 225 }
Chris@76 226 $this_dir->close();
Chris@76 227
Chris@76 228 // Sort the file versions by filename.
Chris@76 229 if (!empty($versionOptions['sort_results']))
Chris@76 230 {
Chris@76 231 ksort($version_info['file_versions']);
Chris@76 232 ksort($version_info['default_template_versions']);
Chris@76 233 ksort($version_info['template_versions']);
Chris@76 234 ksort($version_info['default_language_versions']);
Chris@76 235
Chris@76 236 // For languages sort each language too.
Chris@76 237 foreach ($version_info['default_language_versions'] as $language => $dummy)
Chris@76 238 ksort($version_info['default_language_versions'][$language]);
Chris@76 239 }
Chris@76 240 return $version_info;
Chris@76 241 }
Chris@76 242
Chris@76 243 // Update the Settings.php file.
Chris@76 244 function updateSettingsFile($config_vars)
Chris@76 245 {
Chris@76 246 global $boarddir, $cachedir;
Chris@76 247
Chris@76 248 // When is Settings.php last changed?
Chris@76 249 $last_settings_change = filemtime($boarddir . '/Settings.php');
Chris@76 250
Chris@76 251 // Load the file. Break it up based on \r or \n, and then clean out extra characters.
Chris@76 252 $settingsArray = trim(file_get_contents($boarddir . '/Settings.php'));
Chris@76 253 if (strpos($settingsArray, "\n") !== false)
Chris@76 254 $settingsArray = explode("\n", $settingsArray);
Chris@76 255 elseif (strpos($settingsArray, "\r") !== false)
Chris@76 256 $settingsArray = explode("\r", $settingsArray);
Chris@76 257 else
Chris@76 258 return;
Chris@76 259
Chris@76 260 // Make sure we got a good file.
Chris@76 261 if (count($config_vars) == 1 && isset($config_vars['db_last_error']))
Chris@76 262 {
Chris@76 263 $temp = trim(implode("\n", $settingsArray));
Chris@76 264 if (substr($temp, 0, 5) != '<?php' || substr($temp, -2) != '?' . '>')
Chris@76 265 return;
Chris@76 266 if (strpos($temp, 'sourcedir') === false || strpos($temp, 'boarddir') === false || strpos($temp, 'cookiename') === false)
Chris@76 267 return;
Chris@76 268 }
Chris@76 269
Chris@76 270 // Presumably, the file has to have stuff in it for this function to be called :P.
Chris@76 271 if (count($settingsArray) < 10)
Chris@76 272 return;
Chris@76 273
Chris@76 274 foreach ($settingsArray as $k => $dummy)
Chris@76 275 $settingsArray[$k] = strtr($dummy, array("\r" => '')) . "\n";
Chris@76 276
Chris@76 277 for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
Chris@76 278 {
Chris@76 279 // Don't trim or bother with it if it's not a variable.
Chris@76 280 if (substr($settingsArray[$i], 0, 1) != '$')
Chris@76 281 continue;
Chris@76 282
Chris@76 283 $settingsArray[$i] = trim($settingsArray[$i]) . "\n";
Chris@76 284
Chris@76 285 // Look through the variables to set....
Chris@76 286 foreach ($config_vars as $var => $val)
Chris@76 287 {
Chris@76 288 if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
Chris@76 289 {
Chris@76 290 $comment = strstr(substr($settingsArray[$i], strpos($settingsArray[$i], ';')), '#');
Chris@76 291 $settingsArray[$i] = '$' . $var . ' = ' . $val . ';' . ($comment == '' ? '' : "\t\t" . rtrim($comment)) . "\n";
Chris@76 292
Chris@76 293 // This one's been 'used', so to speak.
Chris@76 294 unset($config_vars[$var]);
Chris@76 295 }
Chris@76 296 }
Chris@76 297
Chris@76 298 if (substr(trim($settingsArray[$i]), 0, 2) == '?' . '>')
Chris@76 299 $end = $i;
Chris@76 300 }
Chris@76 301
Chris@76 302 // This should never happen, but apparently it is happening.
Chris@76 303 if (empty($end) || $end < 10)
Chris@76 304 $end = count($settingsArray) - 1;
Chris@76 305
Chris@76 306 // Still more? Add them at the end.
Chris@76 307 if (!empty($config_vars))
Chris@76 308 {
Chris@76 309 if (trim($settingsArray[$end]) == '?' . '>')
Chris@76 310 $settingsArray[$end++] = '';
Chris@76 311 else
Chris@76 312 $end++;
Chris@76 313
Chris@76 314 foreach ($config_vars as $var => $val)
Chris@76 315 $settingsArray[$end++] = '$' . $var . ' = ' . $val . ';' . "\n";
Chris@76 316 $settingsArray[$end] = '?' . '>';
Chris@76 317 }
Chris@76 318 else
Chris@76 319 $settingsArray[$end] = trim($settingsArray[$end]);
Chris@76 320
Chris@76 321 // Sanity error checking: the file needs to be at least 12 lines.
Chris@76 322 if (count($settingsArray) < 12)
Chris@76 323 return;
Chris@76 324
Chris@76 325 // Try to avoid a few pitfalls:
Chris@76 326 // like a possible race condition,
Chris@76 327 // or a failure to write at low diskspace
Chris@76 328
Chris@76 329 // Check before you act: if cache is enabled, we can do a simple test
Chris@76 330 // Can we even write things on this filesystem?
Chris@76 331 if ((empty($cachedir) || !file_exists($cachedir)) && file_exists($boarddir . '/cache'))
Chris@76 332 $cachedir = $boarddir . '/cache';
Chris@76 333 $test_fp = @fopen($cachedir . '/settings_update.tmp', "w+");
Chris@76 334 if ($test_fp)
Chris@76 335 {
Chris@76 336 fclose($test_fp);
Chris@76 337
Chris@76 338 $test_fp = @fopen($cachedir . '/settings_update.tmp', 'r+');
Chris@76 339 $written_bytes = fwrite($test_fp, "test");
Chris@76 340 fclose($test_fp);
Chris@76 341 @unlink($cachedir . '/settings_update.tmp');
Chris@76 342
Chris@76 343 if ($written_bytes !== strlen("test"))
Chris@76 344 {
Chris@76 345 // Oops. Low disk space, perhaps. Don't mess with Settings.php then.
Chris@76 346 // No means no. :P
Chris@76 347 return;
Chris@76 348 }
Chris@76 349 }
Chris@76 350
Chris@76 351 // Protect me from what I want! :P
Chris@76 352 clearstatcache();
Chris@76 353 if (filemtime($boarddir . '/Settings.php') === $last_settings_change)
Chris@76 354 {
Chris@76 355 // You asked for it...
Chris@76 356 // Blank out the file - done to fix a oddity with some servers.
Chris@76 357 $fp = @fopen($boarddir . '/Settings.php', 'w');
Chris@76 358
Chris@76 359 // Is it even writable, though?
Chris@76 360 if ($fp)
Chris@76 361 {
Chris@76 362 fclose($fp);
Chris@76 363
Chris@76 364 $fp = fopen($boarddir . '/Settings.php', 'r+');
Chris@76 365 foreach ($settingsArray as $line)
Chris@76 366 fwrite($fp, strtr($line, "\r", ''));
Chris@76 367 fclose($fp);
Chris@76 368 }
Chris@76 369 }
Chris@76 370 }
Chris@76 371
Chris@76 372 function updateAdminPreferences()
Chris@76 373 {
Chris@76 374 global $options, $context, $smcFunc, $settings, $user_info;
Chris@76 375
Chris@76 376 // This must exist!
Chris@76 377 if (!isset($context['admin_preferences']))
Chris@76 378 return false;
Chris@76 379
Chris@76 380 // This is what we'll be saving.
Chris@76 381 $options['admin_preferences'] = serialize($context['admin_preferences']);
Chris@76 382
Chris@76 383 // Just check we haven't ended up with something theme exclusive somehow.
Chris@76 384 $smcFunc['db_query']('', '
Chris@76 385 DELETE FROM {db_prefix}themes
Chris@76 386 WHERE id_theme != {int:default_theme}
Chris@76 387 AND variable = {string:admin_preferences}',
Chris@76 388 array(
Chris@76 389 'default_theme' => 1,
Chris@76 390 'admin_preferences' => 'admin_preferences',
Chris@76 391 )
Chris@76 392 );
Chris@76 393
Chris@76 394 // Update the themes table.
Chris@76 395 $smcFunc['db_insert']('replace',
Chris@76 396 '{db_prefix}themes',
Chris@76 397 array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'),
Chris@76 398 array($user_info['id'], 1, 'admin_preferences', $options['admin_preferences']),
Chris@76 399 array('id_member', 'id_theme', 'variable')
Chris@76 400 );
Chris@76 401
Chris@76 402 // Make sure we invalidate any cache.
Chris@76 403 cache_put_data('theme_settings-' . $settings['theme_id'] . ':' . $user_info['id'], null, 0);
Chris@76 404 }
Chris@76 405
Chris@76 406 // Send all the administrators a lovely email.
Chris@76 407 function emailAdmins($template, $replacements = array(), $additional_recipients = array())
Chris@76 408 {
Chris@76 409 global $smcFunc, $sourcedir, $language, $modSettings;
Chris@76 410
Chris@76 411 // We certainly want this.
Chris@76 412 require_once($sourcedir . '/Subs-Post.php');
Chris@76 413
Chris@76 414 // Load all groups which are effectively admins.
Chris@76 415 $request = $smcFunc['db_query']('', '
Chris@76 416 SELECT id_group
Chris@76 417 FROM {db_prefix}permissions
Chris@76 418 WHERE permission = {string:admin_forum}
Chris@76 419 AND add_deny = {int:add_deny}
Chris@76 420 AND id_group != {int:id_group}',
Chris@76 421 array(
Chris@76 422 'add_deny' => 1,
Chris@76 423 'id_group' => 0,
Chris@76 424 'admin_forum' => 'admin_forum',
Chris@76 425 )
Chris@76 426 );
Chris@76 427 $groups = array(1);
Chris@76 428 while ($row = $smcFunc['db_fetch_assoc']($request))
Chris@76 429 $groups[] = $row['id_group'];
Chris@76 430 $smcFunc['db_free_result']($request);
Chris@76 431
Chris@76 432 $request = $smcFunc['db_query']('', '
Chris@76 433 SELECT id_member, member_name, real_name, lngfile, email_address
Chris@76 434 FROM {db_prefix}members
Chris@76 435 WHERE (id_group IN ({array_int:group_list}) OR FIND_IN_SET({raw:group_array_implode}, additional_groups) != 0)
Chris@76 436 AND notify_types != {int:notify_types}
Chris@76 437 ORDER BY lngfile',
Chris@76 438 array(
Chris@76 439 'group_list' => $groups,
Chris@76 440 'notify_types' => 4,
Chris@76 441 'group_array_implode' => implode(', additional_groups) != 0 OR FIND_IN_SET(', $groups),
Chris@76 442 )
Chris@76 443 );
Chris@76 444 $emails_sent = array();
Chris@76 445 while ($row = $smcFunc['db_fetch_assoc']($request))
Chris@76 446 {
Chris@76 447 // Stick their particulars in the replacement data.
Chris@76 448 $replacements['IDMEMBER'] = $row['id_member'];
Chris@76 449 $replacements['REALNAME'] = $row['member_name'];
Chris@76 450 $replacements['USERNAME'] = $row['real_name'];
Chris@76 451
Chris@76 452 // Load the data from the template.
Chris@76 453 $emaildata = loadEmailTemplate($template, $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
Chris@76 454
Chris@76 455 // Then send the actual email.
Chris@76 456 sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 1);
Chris@76 457
Chris@76 458 // Track who we emailed so we don't do it twice.
Chris@76 459 $emails_sent[] = $row['email_address'];
Chris@76 460 }
Chris@76 461 $smcFunc['db_free_result']($request);
Chris@76 462
Chris@76 463 // Any additional users we must email this to?
Chris@76 464 if (!empty($additional_recipients))
Chris@76 465 foreach ($additional_recipients as $recipient)
Chris@76 466 {
Chris@76 467 if (in_array($recipient['email'], $emails_sent))
Chris@76 468 continue;
Chris@76 469
Chris@76 470 $replacements['IDMEMBER'] = $recipient['id'];
Chris@76 471 $replacements['REALNAME'] = $recipient['name'];
Chris@76 472 $replacements['USERNAME'] = $recipient['name'];
Chris@76 473
Chris@76 474 // Load the template again.
Chris@76 475 $emaildata = loadEmailTemplate($template, $replacements, empty($recipient['lang']) || empty($modSettings['userLanguage']) ? $language : $recipient['lang']);
Chris@76 476
Chris@76 477 // Send off the email.
Chris@76 478 sendmail($recipient['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 1);
Chris@76 479 }
Chris@76 480 }
Chris@76 481
Chris@76 482 function updateLastDatabaseError()
Chris@76 483 {
Chris@76 484 global $boarddir;
Chris@76 485
Chris@76 486 // Find out this way if we can even write things on this filesystem.
Chris@76 487 // In addition, store things first in the backup file
Chris@76 488
Chris@76 489 $last_settings_change = @filemtime($boarddir . '/Settings.php');
Chris@76 490
Chris@76 491 // Make sure the backup file is there...
Chris@76 492 $file = $boarddir . '/Settings_bak.php';
Chris@76 493 if ((!file_exists($file) || filesize($file) == 0) && !copy($boarddir . '/Settings.php', $file))
Chris@76 494 return false;
Chris@76 495
Chris@76 496 // ...and writable!
Chris@76 497 if (!is_writable($file))
Chris@76 498 {
Chris@76 499 chmod($file, 0755);
Chris@76 500 if (!is_writable($file))
Chris@76 501 {
Chris@76 502 chmod($file, 0775);
Chris@76 503 if (!is_writable($file))
Chris@76 504 {
Chris@76 505 chmod($file, 0777);
Chris@76 506 if (!is_writable($file))
Chris@76 507 return false;
Chris@76 508 }
Chris@76 509 }
Chris@76 510 }
Chris@76 511
Chris@76 512 // Put the new timestamp.
Chris@76 513 $data = file_get_contents($file);
Chris@76 514 $data = preg_replace('~\$db_last_error = \d+;~', '$db_last_error = ' . time() . ';', $data);
Chris@76 515
Chris@76 516 // Open the backup file for writing
Chris@76 517 if ($fp = @fopen($file, 'w'))
Chris@76 518 {
Chris@76 519 // Reset the file buffer.
Chris@76 520 set_file_buffer($fp, 0);
Chris@76 521
Chris@76 522 // Update the file.
Chris@76 523 $t = flock($fp, LOCK_EX);
Chris@76 524 $bytes = fwrite($fp, $data);
Chris@76 525 flock($fp, LOCK_UN);
Chris@76 526 fclose($fp);
Chris@76 527
Chris@76 528 // Was it a success?
Chris@76 529 // ...only relevant if we're still dealing with the same good ole' settings file.
Chris@76 530 clearstatcache();
Chris@76 531 if (($bytes == strlen($data)) && (filemtime($boarddir . '/Settings.php') === $last_settings_change))
Chris@76 532 {
Chris@76 533 // This is our new Settings file...
Chris@76 534 // At least this one is an atomic operation
Chris@76 535 @copy($file, $boarddir . '/Settings.php');
Chris@76 536 return true;
Chris@76 537 }
Chris@76 538 else
Chris@76 539 {
Chris@76 540 // Oops. Someone might have been faster
Chris@76 541 // or we have no more disk space left, troubles, troubles...
Chris@76 542 // Copy the file back and run for your life!
Chris@76 543 @copy($boarddir . '/Settings.php', $file);
Chris@76 544 }
Chris@76 545 }
Chris@76 546
Chris@76 547 return false;
Chris@76 548 }
Chris@76 549
Chris@76 550 ?>