//--------------------------------------------------------------
//Here is a php script you can run weekly. Just change the config info at the start
//--------------------------------------------------------------
//--------------------------------------------------------------
// BEGIN CONFIG (I like to put this in a sep file, so I can just change the config for
// different database/servers
//--------------------------------------------------------------
//require_once ("mysql_maintenance_config.inc");
$_DB_Host = '127.0.0.1'; // your server ip
$_DB_Name = 'database_name_goes_here'; // name of db to maintain
$_DB_User = 'database_user_goes_here';
$_DB_Pass = 'pasword_goes_here';
$_EMAIL_Admin_Addr = 'yourname@gmail.com'; // address to email errors/results to
// php mail must be configured
$_LOG_TABLE_NAME = 'log_mysql_maintenance'; // change this if you would like the results stored in a different table name
$_EMAIL_Results = true;
$_NO_WRITE_TO_BINLOG = false; // only set to true if database is replicated
$_SKIP_TABLES_WITH_LESS_THAN_X_ROWS = 100; // set to -1 to process all tables
//--------------------------------------------------------------
// END CONFIG SECTION
//--------------------------------------------------------------
$total_query_time_for_page = 0;
$debug = false;
// set debug mode
if (isset($_GET['dxdb']))
{
if ($_GET['dxdb']=='dcv') { $debug = true; }
}
// open database connection
$db = mysql_connect ($_DB_Host, $_DB_User, $_DB_Pass);
if (!$db)
{
echo 'DATABASE_ERROR_MESSAGE';
exit;
}
if (mysql_select_db($_DB_Name, $db)==false)
{
echo 'CANNOT_SELECT_DATABASE';
exit;
}
//--------------------------------------------------------------
// MYSQL MAINTENANCE TASKS
//--------------------------------------------------------------
// 1. Verify / Create Logging Table
// 2. Init Process Log
// 3. Build Table List
// 4. Check and Repair (MyISAM only) Tables if Necessary
// 5. Optimize Tables
// 6. Analyze Tables
// 7. Complete Logs and Email
//--------------------------------------------------------------
$_PROCESS_LOG = '';
$_PROCESS_ID = 0;
$_STARTED_ON = '';
$_COMPLETED_ON = 0;
$_TABLE_COUNT = 0;
$_TABLES_CHECKED = 0;
$_TABLES_OPTIMIZED = 0;
$_TABLES_ANALYZED = 0;
$_ERRORS_FOUND = 0;
$_ERRORS_FIXED = 0;
$_CURRENT_STATUS = '';
$_FINAL_STATUS = '';
//--------------------------------------------------------------
// 1. Verify / Create Logging Table (log table name set in sql_maintenance_config.php)
//--------------------------------------------------------------
$lgx = dbGetReturnForSQL("SELECT COUNT(*) as ct FROM information_schema.tables WHERE table_schema = '$_DB_Name' AND table_name = '$_LOG_TABLE_NAME'",'',true);
if ($lgx==0) // create logging table
{
$sql = "CREATE TABLE $_LOG_TABLE_NAME (
process_id int(11) NOT NULL auto_increment,
started_on varchar(24) NOT NULL default '',
completed_on varchar(24) NOT NULL default '',
tables_checked int(11) NOT NULL default 0,
tables_optimized int(11) NOT NULL default 0,
tables_analyzed int(11) NOT NULL default 0,
errors_found int(11) NOT NULL default 0,
errors_fixed int(11) NOT NULL default 0,
current_status varchar(32) NOT NULL default '',
final_status varchar(32) NOT NULL default '',
process_log varchar(20000) NOT NULL default '',
PRIMARY KEY (process_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8";
dbExecuteSQL($sql);
$_PROCESS_LOG = "FIRST RUN - CREATING LOGGING TABLE \n -------------------------------------------------- \n";
}
else
{
$_PROCESS_LOG = "LOG TABLE OK - BEGINING PROCESS \n -------------------------------------------------- \n";
}
//--------------------------------------------------------------
// 2. Init Process Log
//--------------------------------------------------------------
$_STARTED_ON = getLogStamp();
$_CURRENT_STATUS = 'INIT PROCESS LOG';
$_FINAL_STATUS = 'IN PROCESS - NO ERRORS';
$sql = "INSERT INTO $_LOG_TABLE_NAME (started_on, current_status, final_status, process_log) VALUES ('$_STARTED_ON', '$_CURRENT_STATUS', '$_FINAL_STATUS', '$_PROCESS_LOG')";
$_PROCESS_ID = dbExecuteSQL($sql, true);
add2ProcessLog('Init Process Log', true);
if ($_NO_WRITE_TO_BINLOG)
{
$_BINLOG = 'NO_WRITE_TO_BINLOG';
add2ProcessLog('BINLOG WRITE DISABLED');
}
else
{
$_BINLOG = '';
add2ProcessLog('BINLOG WRITE ENABLED');
}
//--------------------------------------------------------------
// 3. Build Table List
//--------------------------------------------------------------
$_CURRENT_STATUS = 'BUILD TABLE LIST';
add2ProcessLog('Building Table List', true);
$sql = "SELECT TABLE_NAME, ENGINE, TABLE_ROWS
FROM information_schema.tables
WHERE table_schema = '$_DB_Name'";
$_TABLE_LIST = dbGetReturnForSQL($sql);
if ($_TABLE_LIST == 'x_no_data_x') // no tables found
{
add2ProcessLog("ERROR - NO TABLES FOUND", false);
emailLogAndExit();
}
else
{
$_TABLE_COUNT = count($_TABLE_LIST);
add2ProcessLog($_TABLE_COUNT . " tables found", true);
}
//--------------------------------------------------------------
// 4. Check and Repair (MyISAM only) Tables if Necessary
//--------------------------------------------------------------
$_CURRENT_STATUS = 'CHECK AND REPAIR MYISAM TABLES';
add2ProcessLog("CHECK AND REPAIR MYISAM TABLES", true);
foreach($_TABLE_LIST AS $tbl_row)
{
$tbl = $tbl_row['TABLE_NAME'];
$eng = $tbl_row['ENGINE'];
$rct = $tbl_row['TABLE_ROWS'];
if ($tbl != $_LOG_TABLE_NAME && $eng == 'MyISAM')
{
$_TABLES_CHECKED++;
add2ProcessLog("checking: $tbl");
$sql = "CHECK TABLE $tbl";
$rs = dbGetReturnForSQL($sql);
if ($rs == 'x_no_data_x')
{
emailLogAndExit("ERROR CHECKING TABLE: $tbl");
}
else
{
$rw = getLastRecord($rs);
if ($rw['Msg_text'] != 'OK')
{
$_ERRORS_FOUND++;
add2ProcessLog('ERROR FOUND: ' . $rw['Msg_text'], true);
// problem checking table - attempt to repair
$sql = "REPAIR TABLE $tbl";
$rs = dbGetReturnForSQL($sql);
if ($rs == 'x_no_data_x')
{
emailLogAndExit("ERROR REPAIRING TABLE: $tbl");
}
else
{
$rprw = getLastRecord($rs);
if ($rw['Msg_text'] == 'OK')
{
$_ERRORS_FIXED++;
add2ProcessLog('ERROR REPAIRED on ' . $tbl);
}
else //could not repair error
{
emailLogAndExit("ERROR REPAIRING TABLE: $tbl | " . $rw['Msg_text']);
}
}
}
else
{
add2ProcessLog($tbl . ' checked ok');
}
}
}
}
add2ProcessLog("CHECK AND REPAIR MYISAM TABLES COMPLETED OK", true);
//--------------------------------------------------------------
// 5. Optimize Tables
//--------------------------------------------------------------
$_CURRENT_STATUS = 'OPTIMIZE TABLES';
add2ProcessLog("OPTIMIZE TABLES", true);
foreach($_TABLE_LIST AS $tbl_row)
{
$tbl = $tbl_row['TABLE_NAME'];
$eng = $tbl_row['ENGINE'];
$rct = $tbl_row['TABLE_ROWS'];
if ($tbl != $_LOG_TABLE_NAME && intval($_SKIP_TABLES_WITH_LESS_THAN_X_ROWS) 'Jacks Function', '//#_reason_//#' => 'Because I said so')
// $new_page: if true, clear buffer and wrap in new page, if false, display err msg and exit (note, for this to be used, ob_start() must have been called on the page first
// $dev_dump: any misc info you would like in the log, such as the query that caused the error. this will not be displayed to the user
// $email_err: email address to send error to. if set to 'devteam' then the current group mailing addr will be used (i.e. devteam@thinklinklearning.com)
// FUTURE - might want to set a way to override this in the error_codes table to send to a specific developer during testing ( currently can only override to always email )
// $log_only: if true, do not display message, return to code -could be used if we wanted to log here from perish()
global $db, $_EMAIL_Admin_Addr, $_CURRENT_STATUS, $_FINAL_STATUS;
// log the error first
$host_info = mysql_get_host_info();
$rq = substr(var_export($_REQUEST,true),0,2000);
$rq = mysql_real_escape_string($rq);
// append last sql error to dev_dump
$sql_dump = $dev_dump;
// format sql
$sql_dump = str_replace("\r\n",'',$sql_dump);
$sql_dump = str_replace("\n",'',$sql_dump);
$sql_dump = str_replace("\t",'',$sql_dump);
$sql_dump = str_ireplace('SELECT',"\r\n SELECT",$sql_dump);
$sql_dump = str_ireplace('FROM',"\r\n FROM",$sql_dump);
$sql_dump = str_ireplace('WHERE',"\r\n WHERE",$sql_dump);
$sql_dump = str_ireplace('INNER JOIN',"\r\n INNER JOIN",$sql_dump);
$sql_dump = str_ireplace('LEFT JOIN',"\r\n LEFT JOIN",$sql_dump);
$sql_dump = str_ireplace('AND',"\r\n AND",$sql_dump);
$sql_dump = str_ireplace('GROUP BY',"\r\n GROUP BY",$sql_dump);
$sql_dump = str_ireplace('ORDER BY',"\r\n ORDER BY",$sql_dump);
$sql_dump = str_ireplace(',',"\r\n, ",$sql_dump);
$sql_dump = str_replace(' ',' ',$sql_dump);
$sql_dump = str_replace(' ',' ',$sql_dump);
$sql_dump = str_replace(' ',' ',$sql_dump);
$sql_err = mysql_error();
$dev_dump = $sql_dump . "\r\n\r\n" . $sql_err;
//echo " $sql_err$sql_dump";
$dev_dump_to_mail = $host_info . "\r\n\r\n" . $dev_dump;
$dev_dump = mysql_real_escape_string($dev_dump_to_mail . "\r\n\r\n" . $dev_dump);
// get stack backtrace
$a = debug_backtrace();
$stack_tr = "stack trace: \r\n";
$stack_tr .= "------------ \r\n";
foreach($a as $k => $v)
{
$stack_tr .= "file: $v[file] \r\n";
$stack_tr .= "line: $v[line] \r\n";
$stack_tr .= "func: $v[function] \r\n";
$args = $v['args'];
foreach($args as $a_label => $a_val)
{
$stack_tr .= "$a_label => $a_val \r\n";
}
$stack_tr .= "//# \r\n";
}
$pg = mysql_real_escape_string($_SERVER['PHP_SELF']);
$stack_tr_to_mail = $stack_tr;
$stack_tr = mysql_real_escape_string($stack_tr);
if ($err_id=='') { $err_id = 'GENERAL_ERROR'; }
$email_err = $_EMAIL_Admin_Addr; // always email errors to admin
$err_html = '';
// email error if requested
if ($email_err!='')
{
$pg = explode('/', $pg);
$pg = $pg[count($pg)-1];
if (strpos(strtoupper($_SERVER['SERVER_NAME']),'DEV')>2) { $fsrv = ' (DEV)'; } else { $fsrv = ''; }
mail($email_err, "Error$fsrv: $pg - $err_id ",
"PHP_SELF\t $_SERVER[PHP_SELF]
\n\n------------------------------------\n\n
error_id:\t $err_id\n\n
\n\n------------------------------------\n\n
sql_err:\t $sql_err \n\n
\n\n------------------------------------\n\n
sql_dump:\n\n $sql_dump \n\n
\n\n------------------------------------\n\n
last_db_host:\t $host_info\n\n
\n\n------------------------------------\n\n
stack_tr:\n
$stack_tr_to_mail\n\n
\n\n------------------------------------\n\n
dev_dump:\n
$dev_dump_to_mail\n\n
\n\n------------------------------------\n\n
err_log_key: $err_log_key ");
}
// update process log
$_CURRENT_STATUS = 'ERROR';
$_FINAL_STATUS = 'ERROR';
add2ProcessLog('ERROR - ' . $sql_err, true);
echo 'ERROR: ' . $pg . ' - ' . $sql_err;
exit();
}
//--------------------------------------------------------------
function getRequestVar($fieldname,$defaultvalue,$numeric_only=false,$prep_for_sql_insert=false)
{
$rtn = '';
if (isset($_POST[$fieldname]))
{
$rtn = $_POST[$fieldname];
}
else
{
if (isset($_GET[$fieldname]))
{
$rtn = $_GET[$fieldname];
}
else
{
$rtn = $defaultvalue;
}
}
if ($numeric_only==true)
{
if (is_numeric($rtn)==false) {$rtn = $defaultvalue;}
}
if ($prep_for_sql_insert==true)
{
$rtn = "'" . mysql_real_escape_string($rtn) . "'";
}
return($rtn);
}
//--------------------------------------------------------------
function prepForSQL($rtn_val, $numeric_only=false)
{
if ($numeric_only==true)
{
if (is_numeric($rtn_val)==false) {$rtn_val = -999;}
}
else
{
// remove chrs we dont allow in the system
$rtn_val = str_replace("'","",$rtn_val);
$rtn_val = str_replace('"',"",$rtn_val);
$rtn_val = str_replace("\\","",$rtn_val);
$rtn_val = str_replace(';',"",$rtn_val);
$rtn_val = "'" . mysql_real_escape_string($rtn_val) . "'";
}
return($rtn_val);
}
//--------------------------------------------------------------
function dbGetReturnForSQL($sql, $field_for_key = '', $get_scalar_value = false, $default_value = 'x_no_data_x')
{
/* this function works for scalar, one row and multi row queries
if $field_for_key = '' then use index
if $get_scalar_value = true then return 1st row in array only (not nested in row array) or if only 1 value return value only (no array) - first row only must be set to true
if no data is present $default_value will be returned, if blank, 'x_no_data_x' will be returned
$error_id_on_fail, error id to pass to displayErrorMsg (defaults to GENERAL_ERROR)
*/
global $db, $debug, $total_query_time_for_page;
$loc_ptr = 0;
$loc_key = '';
$loc_arr = array();
$loc_val = '';
$use_srv = 'MASTER';
$error_id_on_fail = '';
if ( $debug ) {
echo "QUERY:
\n\n" . ereg_replace("\t", " ", $sql) . "\n
\ n
\ n ";
}
if ($ debug) {$ start_time = microtime (true); }
$ result = mysql_query ($ sql, $ db) ИЛИ displayErrorMsg ($ error_id_on_fail, '', '', false, $ sql, 'richard.varno @ gmail.com', false);
if ($ debug)
{
$ end_time = microtime (true);
$ row_rtn = mysql_num_rows ($ result);
$ qry_time = $ end_time - $ start_time;
$ total_query_time_for_page = $ total_query_time_for_page + $ qry_time;
$ host_info = mysql_get_host_info ();
echo "
$ row_rtn строк возвращено за $ qry_time секунд из $ host_info ($ use_srv)
общее время запроса: $ total_query_time_for_page секунд
\ n" ;
}
while ($ rw = mysql_fetch_assoc ($ result))
{
if ($ get_scalar_value == true)
{
// показать возвращаемое значение, если debug = true
if ($ debug)
{
echo "Скалярное значение
\ n \ n";
foreach ($ rw как $ fld_key => $ fld_val)
{
echo " $ fld_key $ fld_val \ n";
}
эхо "\ n";
}
if (count ($ rw) == 1)
{
$ rw_key = array_keys ($ rw);
$ loc_val = $ rw [$ rw_key [0]];
mysql_free_result ($ результат);
вернуться ($ loc_val);
}
еще
{
mysql_free_result ($ результат);
возврата ($ RW);
}
}
еще
{
if ($ field_for_key == '') // использовать указатель индекса
{
$ loc_key = $ loc_ptr;
}
еще // использовать поле
{
$ loc_key = $ rw [$ field_for_key];
}
$ loc_arr [$ loc_key] = $ rw;
$ Loc_ptr ++;
}
}
mysql_free_result ($ результат);
// если результатов не найдено, вернуть значение по умолчанию
если ($ loc_ptr == 0)
{
$ loc_arr = $ default_value;
}
еще
{
// показать возвращаемое значение, если debug = true (только первые 50 строк)
if ($ debug)
{
если ($ row_rtn> 50)
{
echo "Отображение строк от 1 до $ row_rtn из $ row_rtn
\ n";
$ max_row_to_display = 49;
}
еще
{
echo "Отображение строк от 1 до $ row_rtn из $ row_rtn
\ n";
$ max_row_to_display = $ row_rtn-1;
}
эхо "\ n";
// показать заголовки
$ loc_arr_keys = array_keys ($ loc_arr);
$ rw = $ loc_arr [$ loc_arr_keys [0]];
эхо "\ n";
foreach ($ rw как $ fld_key => $ fld_val)
{
echo " $ fld_key \ n";
}
эхо "\ n";
// показать данные
$ cur_row = 0;
foreach ($ loc_arr как $ ptr => $ row)
{
эхо "\ n";
foreach ($ rw как $ fld_key => $ fld_val)
{
echo "$ row [$ fld_key] \ n";
}
эхо "\ n";
$ Cur_row ++;
if ($ cur_row> $ max_row_to_display) {break; }
}
эхо "\ n";
}
}
возврат ($ loc_arr);
}
// ------------------------------------------------ --------------
функция dbExecuteSQL ($ sql, $ return_insert_id = false)
{
/ * эта функция будет выполняться и оператор SQL для базы данных master и возвращать либо затронутые строки, либо идентификатор вставки, если требуется
$ error_id_on_fail, идентификатор ошибки для передачи в displayErrorMsg (по умолчанию GENERAL_ERROR)
* /
global $ db, $ debug, $ total_query_time_for_page;
$ loc_ptr = 0;
$ loc_insert_id = 0;
$ loc_rows_affered = 0;
$ error_id_on_fail = '';
if ($ debug) {
echo " QUERY: \ n
\n" . ereg_replace("\t", " ", $sql) . "\n
\ n
\ n";
}if ($ debug) {$ start_time = microtime (true); }
$ result = mysql_query ($ sql, $ db) ИЛИ displayErrorMsg ($ error_id_on_fail, '', '', false, $ sql, 'richard.varno @ gmail.com', false);
$ loc_insert_id = mysql_insert_id ($ db);
$ loc_rows_affered = mysql_affered_rows ($ db);
$ use_srv = 'MASTER';
if ($ debug)
{
$ end_time = microtime (true);
$ qry_time = $ end_time - $ start_time;
$ total_query_time_for_page = $ total_query_time_for_page + $ qry_time;
$ host_info = mysql_get_host_info ($ db);
echo "Строки $ loc_rows_affered затронуты за $ qry_time секунд из $ host_info ($ use_srv)
общее время запроса: $ total_query_time_for_page секунд
\ n";
}
if ($ return_insert_id == true) {return ($ loc_insert_id); } else {return ($ loc_rows_affered); }
}
// ------------------------------------------------ --------------