Пример #1
0
function smf_db_error($db_string, $connection = null)
{
    global $txt, $context, $sourcedir, $webmaster_email, $modSettings;
    global $forum_version, $db_connection, $db_last_error, $db_persist;
    global $db_server, $db_user, $db_passwd, $db_name, $db_show_debug, $ssi_db_user, $ssi_db_passwd;
    global $smcFunc;
    // Get the file and line numbers.
    list($file, $line) = smf_db_error_backtrace('', '', 'return', __FILE__, __LINE__);
    // Decide which connection to use
    $connection = $connection == null ? $db_connection : $connection;
    // This is the error message...
    $query_error = mysql_error($connection);
    $query_errno = mysql_errno($connection);
    // Error numbers:
    //    1016: Can't open file '....MYI'
    //    1030: Got error ??? from table handler.
    //    1034: Incorrect key file for table.
    //    1035: Old key file for table.
    //    1205: Lock wait timeout exceeded.
    //    1213: Deadlock found.
    //    2006: Server has gone away.
    //    2013: Lost connection to server during query.
    // Log the error.
    if ($query_errno != 1213 && $query_errno != 1205 && function_exists('log_error')) {
        log_error($txt['database_error'] . ': ' . $query_error . (!empty($modSettings['enableErrorQueryLogging']) ? "\n\n{$db_string}" : ''), 'database', $file, $line);
    }
    // Database error auto fixing ;).
    if (function_exists('cache_get_data') && (!isset($modSettings['autoFixDatabase']) || $modSettings['autoFixDatabase'] == '1')) {
        // Force caching on, just for the error checking.
        $old_cache = @$modSettings['cache_enable'];
        $modSettings['cache_enable'] = '1';
        if (($temp = cache_get_data('db_last_error', 600)) !== null) {
            $db_last_error = max(@$db_last_error, $temp);
        }
        if (@$db_last_error < time() - 3600 * 24 * 3) {
            // We know there's a problem... but what?  Try to auto detect.
            if ($query_errno == 1030 && strpos($query_error, ' 127 ') !== false) {
                preg_match_all('~(?:[\\n\\r]|^)[^\']+?(?:FROM|JOIN|UPDATE|TABLE) ((?:[^\\n\\r(]+?(?:, )?)*)~s', $db_string, $matches);
                $fix_tables = array();
                foreach ($matches[1] as $tables) {
                    $tables = array_unique(explode(',', $tables));
                    foreach ($tables as $table) {
                        // Now, it's still theoretically possible this could be an injection.  So backtick it!
                        if (trim($table) != '') {
                            $fix_tables[] = '`' . strtr(trim($table), array('`' => '')) . '`';
                        }
                    }
                }
                $fix_tables = array_unique($fix_tables);
            } elseif ($query_errno == 1016) {
                if (preg_match('~\'([^\\.\']+)~', $query_error, $match) != 0) {
                    $fix_tables = array('`' . $match[1] . '`');
                }
            } elseif ($query_errno == 1034 || $query_errno == 1035) {
                preg_match('~\'([^\']+?)\'~', $query_error, $match);
                $fix_tables = array('`' . $match[1] . '`');
            }
        }
        // Check for errors like 145... only fix it once every three days, and send an email. (can't use empty because it might not be set yet...)
        if (!empty($fix_tables)) {
            // Subs-Admin.php for updateSettingsFile(), Subs-Post.php for sendmail().
            require_once $sourcedir . '/Subs-Admin.php';
            require_once $sourcedir . '/Subs-Post.php';
            // Make a note of the REPAIR...
            cache_put_data('db_last_error', time(), 600);
            if (($temp = cache_get_data('db_last_error', 600)) === null) {
                updateSettingsFile(array('db_last_error' => time()));
            }
            // Attempt to find and repair the broken table.
            foreach ($fix_tables as $table) {
                $smcFunc['db_query']('', "\r\n\t\t\t\t\tREPAIR TABLE {$table}", false, false);
            }
            // And send off an email!
            sendmail($webmaster_email, $txt['database_error'], $txt['tried_to_repair']);
            $modSettings['cache_enable'] = $old_cache;
            // Try the query again...?
            $ret = $smcFunc['db_query']('', $db_string, false, false);
            if ($ret !== false) {
                return $ret;
            }
        } else {
            $modSettings['cache_enable'] = $old_cache;
        }
        // Check for the "lost connection" or "deadlock found" errors - and try it just one more time.
        if (in_array($query_errno, array(1205, 1213, 2006, 2013))) {
            if (in_array($query_errno, array(2006, 2013)) && $db_connection == $connection) {
                // Are we in SSI mode?  If so try that username and password first
                if (SMF == 'SSI' && !empty($ssi_db_user) && !empty($ssi_db_passwd)) {
                    if (empty($db_persist)) {
                        $db_connection = @mysql_connect($db_server, $ssi_db_user, $ssi_db_passwd);
                    } else {
                        $db_connection = @mysql_pconnect($db_server, $ssi_db_user, $ssi_db_passwd);
                    }
                }
                // Fall back to the regular username and password if need be
                if (!$db_connection) {
                    if (empty($db_persist)) {
                        $db_connection = @mysql_connect($db_server, $db_user, $db_passwd);
                    } else {
                        $db_connection = @mysql_pconnect($db_server, $db_user, $db_passwd);
                    }
                }
                if (!$db_connection || !@mysql_select_db($db_name, $db_connection)) {
                    $db_connection = false;
                }
            }
            if ($db_connection) {
                // Try a deadlock more than once more.
                for ($n = 0; $n < 4; $n++) {
                    $ret = $smcFunc['db_query']('', $db_string, false, false);
                    $new_errno = mysql_errno($db_connection);
                    if ($ret !== false || in_array($new_errno, array(1205, 1213))) {
                        break;
                    }
                }
                // If it failed again, shucks to be you... we're not trying it over and over.
                if ($ret !== false) {
                    return $ret;
                }
            }
        } elseif ($query_errno == 1030 && (strpos($query_error, ' -1 ') !== false || strpos($query_error, ' 28 ') !== false || strpos($query_error, ' 12 ') !== false)) {
            if (!isset($txt)) {
                $query_error .= ' - check database storage space.';
            } else {
                if (!isset($txt['mysql_error_space'])) {
                    loadLanguage('Errors');
                }
                $query_error .= !isset($txt['mysql_error_space']) ? ' - check database storage space.' : $txt['mysql_error_space'];
            }
        }
    }
    // Nothing's defined yet... just die with it.
    if (empty($context) || empty($txt)) {
        die($query_error);
    }
    // Show an error message, if possible.
    $context['error_title'] = $txt['database_error'];
    if (allowedTo('admin_forum')) {
        $context['error_message'] = nl2br($query_error) . '<br />' . $txt['file'] . ': ' . $file . '<br />' . $txt['line'] . ': ' . $line;
    } else {
        $context['error_message'] = $txt['try_again'];
    }
    // A database error is often the sign of a database in need of upgrade.  Check forum versions, and if not identical suggest an upgrade... (not for Demo/CVS versions!)
    if (allowedTo('admin_forum') && !empty($forum_version) && $forum_version != 'SMF ' . @$modSettings['smfVersion'] && strpos($forum_version, 'Demo') === false && strpos($forum_version, 'CVS') === false) {
        $context['error_message'] .= '<br /><br />' . sprintf($txt['database_error_versions'], $forum_version, $modSettings['smfVersion']);
    }
    if (allowedTo('admin_forum') && isset($db_show_debug) && $db_show_debug === true) {
        $context['error_message'] .= '<br /><br />' . nl2br($db_string);
    }
    // It's already been logged... don't log it again.
    fatal_error($context['error_message'], false);
}
Пример #2
0
/**
 * Database error!
 * Backtrace, log, try to fix.
 *
 * @param string $db_string
 * @param resource $connection = null
 */
function smf_db_error($db_string, $connection = null)
{
    global $txt, $context, $sourcedir, $webmaster_email, $modSettings;
    global $forum_version, $db_connection, $db_last_error, $db_persist;
    global $db_server, $db_user, $db_passwd, $db_name, $db_show_debug, $ssi_db_user, $ssi_db_passwd;
    global $smcFunc;
    // We'll try recovering the file and line number the original db query was called from.
    list($file, $line) = smf_db_error_backtrace('', '', 'return', __FILE__, __LINE__);
    // Decide which connection to use
    $connection = $connection === null ? $db_connection : $connection;
    // This is the error message...
    $query_error = @pg_last_error($connection);
    // Log the error.
    if (function_exists('log_error')) {
        log_error($txt['database_error'] . ': ' . $query_error . (!empty($modSettings['enableErrorQueryLogging']) ? "\n\n" . $db_string : ''), 'database', $file, $line);
    }
    // Nothing's defined yet... just die with it.
    if (empty($context) || empty($txt)) {
        die($query_error);
    }
    // Show an error message, if possible.
    $context['error_title'] = $txt['database_error'];
    if (allowedTo('admin_forum')) {
        $context['error_message'] = nl2br($query_error) . '<br />' . $txt['file'] . ': ' . $file . '<br />' . $txt['line'] . ': ' . $line;
    } else {
        $context['error_message'] = $txt['try_again'];
    }
    // A database error is often the sign of a database in need of updgrade.  Check forum versions, and if not identical suggest an upgrade... (not for Demo/CVS versions!)
    if (allowedTo('admin_forum') && !empty($forum_version) && $forum_version != 'SMF ' . @$modSettings['smfVersion'] && strpos($forum_version, 'Demo') === false && strpos($forum_version, 'CVS') === false) {
        $context['error_message'] .= '<br /><br />' . sprintf($txt['database_error_versions'], $forum_version, $modSettings['smfVersion']);
    }
    if (allowedTo('admin_forum') && isset($db_show_debug) && $db_show_debug === true) {
        $context['error_message'] .= '<br /><br />' . nl2br($db_string);
    }
    // It's already been logged... don't log it again.
    fatal_error($context['error_message'], false);
}
Пример #3
0
function smf_db_error($db_string, $connection = null)
{
    global $txt, $context, $sourcedir, $webmaster_email, $modSettings;
    global $forum_version, $db_connection, $db_last_error, $db_persist;
    global $db_server, $db_user, $db_passwd, $db_name, $db_show_debug, $ssi_db_user, $ssi_db_passwd;
    global $smcFunc;
    // We'll try recovering the file and line number the original db query was called from.
    list($file, $line) = smf_db_error_backtrace('', '', 'return', __FILE__, __LINE__);
    // Decide which connection to use
    $connection = $connection == null ? $db_connection : $connection;
    // This is the error message...
    $query_errno = sqlite_last_error($connection);
    $query_error = sqlite_error_string($query_errno);
    // Get the extra error message.
    $errStart = strrpos($db_string, '#!#');
    $query_error .= '<br />' . substr($db_string, $errStart + 3);
    $db_string = substr($db_string, 0, $errStart);
    // Log the error.
    if (function_exists('log_error')) {
        log_error($txt['database_error'] . ': ' . $query_error . (!empty($modSettings['enableErrorQueryLogging']) ? "\n\n" . $db_string : ''), 'database', $file, $line);
    }
    // Sqlite optimizing - the actual error message isn't helpful or user friendly.
    if (strpos($query_error, 'no_access') !== false || strpos($query_error, 'database schema has changed') !== false) {
        if (!empty($context) && !empty($txt) && !empty($txt['error_sqlite_optimizing'])) {
            fatal_error($txt['error_sqlite_optimizing'], false);
        } else {
            // Don't cache this page!
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
            header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
            header('Cache-Control: no-cache');
            // Send the right error codes.
            header('HTTP/1.1 503 Service Temporarily Unavailable');
            header('Status: 503 Service Temporarily Unavailable');
            header('Retry-After: 3600');
            die('Sqlite is optimizing the database, the forum can not be accessed until it has finished.  Please try refreshing this page momentarily.');
        }
    }
    // Nothing's defined yet... just die with it.
    if (empty($context) || empty($txt)) {
        die($query_error);
    }
    // Show an error message, if possible.
    $context['error_title'] = $txt['database_error'];
    if (allowedTo('admin_forum')) {
        $context['error_message'] = nl2br($query_error) . '<br />' . $txt['file'] . ': ' . $file . '<br />' . $txt['line'] . ': ' . $line;
    } else {
        $context['error_message'] = $txt['try_again'];
    }
    // A database error is often the sign of a database in need of updgrade.  Check forum versions, and if not identical suggest an upgrade... (not for Demo/CVS versions!)
    if (allowedTo('admin_forum') && !empty($forum_version) && $forum_version != 'SMF ' . @$modSettings['smfVersion'] && strpos($forum_version, 'Demo') === false && strpos($forum_version, 'CVS') === false) {
        $context['error_message'] .= '<br /><br />' . sprintf($txt['database_error_versions'], $forum_version, $modSettings['smfVersion']);
    }
    if (allowedTo('admin_forum') && isset($db_show_debug) && $db_show_debug === true) {
        $context['error_message'] .= '<br /><br />' . nl2br($db_string);
    }
    // It's already been logged... don't log it again.
    fatal_error($context['error_message'], false);
}
Пример #4
0
 function smf_db_replacement__callback($matches)
 {
     global $db_callback, $user_info, $db_prefix;
     list($values, $connection) = $db_callback;
     if ($matches[1] === 'db_prefix') {
         return $db_prefix;
     }
     if ($matches[1] === 'query_see_board') {
         return $user_info['query_see_board'];
     }
     if ($matches[1] === 'query_wanna_see_board') {
         return $user_info['query_wanna_see_board'];
     }
     if (!isset($matches[2])) {
         smf_db_error_backtrace('Invalid value inserted or no type specified.', '', E_USER_ERROR, __FILE__, __LINE__);
     }
     if (!isset($values[$matches[2]])) {
         smf_db_error_backtrace('The database value you\'re trying to insert does not exist: ' . htmlspecialchars($matches[2]), '', E_USER_ERROR, __FILE__, __LINE__);
     }
     $replacement = $values[$matches[2]];
     switch ($matches[1]) {
         case 'int':
             if (!is_numeric($replacement) || (string) $replacement !== (string) (int) $replacement) {
                 smf_db_error_backtrace('Wrong value type sent to the database. Integer expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
             }
             return (string) (int) $replacement;
             break;
         case 'string':
         case 'text':
             return sprintf('\'%1$s\'', mysql_real_escape_string($replacement, $connection));
             break;
         case 'array_int':
             if (is_array($replacement)) {
                 if (empty($replacement)) {
                     smf_db_error_backtrace('Database error, given array of integer values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
                 }
                 foreach ($replacement as $key => $value) {
                     if (!is_numeric($value) || (string) $value !== (string) (int) $value) {
                         smf_db_error_backtrace('Wrong value type sent to the database. Array of integers expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
                     }
                     $replacement[$key] = (string) (int) $value;
                 }
                 return implode(', ', $replacement);
             } else {
                 smf_db_error_backtrace('Wrong value type sent to the database. Array of integers expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
             }
             break;
         case 'array_string':
             if (is_array($replacement)) {
                 if (empty($replacement)) {
                     smf_db_error_backtrace('Database error, given array of string values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
                 }
                 foreach ($replacement as $key => $value) {
                     $replacement[$key] = sprintf('\'%1$s\'', mysql_real_escape_string($value, $connection));
                 }
                 return implode(', ', $replacement);
             } else {
                 smf_db_error_backtrace('Wrong value type sent to the database. Array of strings expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
             }
             break;
         case 'date':
             if (preg_match('~^(\\d{4})-([0-1]?\\d)-([0-3]?\\d)$~', $replacement, $date_matches) === 1) {
                 return sprintf('\'%04d-%02d-%02d\'', $date_matches[1], $date_matches[2], $date_matches[3]);
             } else {
                 smf_db_error_backtrace('Wrong value type sent to the database. Date expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
             }
             break;
         case 'float':
             if (!is_numeric($replacement)) {
                 smf_db_error_backtrace('Wrong value type sent to the database. Floating point number expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
             }
             return (string) (double) $replacement;
             break;
         case 'identifier':
             // Backticks inside identifiers are supported as of MySQL 4.1. We don't need them for SMF.
             return '`' . strtr($replacement, array('`' => '', '.' => '')) . '`';
             break;
         case 'raw':
             return $replacement;
             break;
         default:
             smf_db_error_backtrace('Undefined type used in the database query. (' . $matches[1] . ':' . $matches[2] . ')', '', false, __FILE__, __LINE__);
             break;
     }
 }