//------------------------------------------------ --------------
//这是一个可以每周运行的 php 脚本。只需在开始时更改配置信息
//------------------------------------------------ --------------
//------------------------------------------------ --------------
// BEGIN CONFIG (我喜欢把它放在一个 sep 文件中,所以我可以改变配置
// 不同的数据库/服务器
//------------------------------------------------ --------------
//require_once ("mysql_maintenance_config.inc");
$_DB_Host = '127.0.0.1'; // 你的服务器ip
$_DB_Name = 'database_name_goes_here'; // 要维护的数据库名称
$_DB_User = 'database_user_goes_here';
$_DB_Pass = 'password_goes_here';
$_EMAIL_Admin_Addr = '你的名字@gmail.com'; // 将错误/结果发送至电子邮件地址
// php邮件必须配置
$_LOG_TABLE_NAME = 'log_mysql_maintenance'; // 如果您希望将结果存储在不同的表名中,请更改此项
$_EMAIL_Results = 真;
$_NO_WRITE_TO_BINLOG = 假; // 仅当数据库被复制时才设置为 true
$_SKIP_TABLES_WITH_LESS_THAN_X_ROWS = 100; // 设置为 -1 以处理所有表
//------------------------------------------------ --------------
// 结束配置部分
//------------------------------------------------ --------------
$total_query_time_for_page = 0;
$调试=假;
//设置调试模式
if (isset($_GET['dxdb']))
{
if ($_GET['dxdb']=='dcv') { $debug = true; }
}
// 打开数据库连接
$db = mysql_connect ($_DB_Host, $_DB_User, $_DB_Pass);
如果 (!$db)
{
回声'DATABASE_ERROR_MESSAGE';
出口;
}
if (mysql_select_db($_DB_Name, $db)==false)
{
回声“CANNOT_SELECT_DATABASE”;
出口;
}
//------------------------------------------------ --------------
// MYSQL 维护任务
//------------------------------------------------ --------------
// 1. 验证/创建日志表
// 2. 初始化进程日志
// 3. 建表列表
// 4. 必要时检查和修复(仅限 MyISAM)表
// 5. 优化表格
// 6. 分析表格
// 7. 完整的日志和电子邮件
//------------------------------------------------ --------------
$_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. 验证/创建日志表(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) // 创建日志表
{
$sql = "创建表 $_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 默认 0,
tables_optimized int(11) NOT NULL 默认 0,
tables_analyzed int(11) NOT NULL 默认 0,
errors_found int(11) NOT NULL 默认 0,
errors_fixed int(11) NOT NULL 默认 0,
current_status varchar(32) NOT NULL default '',
final_status varchar(32) NOT NULL default '',
process_log varchar(20000) NOT NULL default '',
主键 (process_id)
) 引擎=InnoDB AUTO_INCREMENT=1 默认字符集=utf8";
dbExecuteSQL($sql);
$_PROCESS_LOG = "首次运行 - 创建日志记录表\n -------------------------------------- ------------ \n";
}
别的
{
$_PROCESS_LOG = "日志表正常 - 开始进程\n -------------------------------------- ------------ \n";
}
//------------------------------------------------ --------------
// 2. 初始化进程日志
//------------------------------------------------ --------------
$_STARTED_ON = getLogStamp();
$_CURRENT_STATUS = '初始化进程日志';
$_FINAL_STATUS = '处理中 - 没有错误';
$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('初始化进程日志', true);
如果($_NO_WRITE_TO_BINLOG)
{
$_BINLOG = 'NO_WRITE_TO_BINLOG';
add2ProcessLog('BINLOG WRITE DISABLED');
}
别的
{
$_BINLOG = '';
add2ProcessLog('BINLOG WRITE ENABLED');
}
//------------------------------------------------ --------------
// 3. 建表列表
//------------------------------------------------ --------------
$_CURRENT_STATUS = '构建表列表';
add2ProcessLog('建表列表', true);
$sql = "选择表名、引擎、表行
FROM information_schema.tables
WHERE table_schema = '$_DB_Name'";
$_TABLE_LIST = dbGetReturnForSQL($sql);
if ($_TABLE_LIST == 'x_no_data_x') // 没有找到表
{
add2ProcessLog("错误 - 没有找到表", false);
emailLogAndExit();
}
别的
{
$_TABLE_COUNT = 计数($_TABLE_LIST);
add2ProcessLog($_TABLE_COUNT . " 找到表", true);
}
//------------------------------------------------ --------------
// 4. 必要时检查和修复(仅限 MyISAM)表
//------------------------------------------------ --------------
$_CURRENT_STATUS = '检查并修复 MYISAM 表';
add2ProcessLog("检查并修复 MISAM 表", 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("检查:$tbl");
$sql = "检查表 $tbl";
$rs = dbGetReturnForSQL($sql);
if ($rs == 'x_no_data_x')
{
emailLogAndExit("错误检查表:$tbl");
}
别的
{
$rw = getLastRecord($rs);
if ($rw['Msg_text'] != 'OK')
{
$_ERRORS_FOUND++;
add2ProcessLog('发现错误:' . $rw['Msg_text'], true);
// 问题检查表 - 尝试修复
$sql = "修复表 $tbl";
$rs = dbGetReturnForSQL($sql);
if ($rs == 'x_no_data_x')
{
emailLogAndExit("错误修复表:$tbl");
}
别的
{
$rprw = getLastRecord($rs);
if ($rw['Msg_text'] == 'OK')
{
$_ERRORS_FIXED++;
add2ProcessLog('错误修复' . $tbl);
}
else //无法修复错误
{
emailLogAndExit("错误修复表:$tbl | " . $rw['Msg_text']);
}
}
}
别的
{
add2ProcessLog($tbl . '检查好');
}
}
}
}
add2ProcessLog("检查并修复MYISAM 表已完成", true);
//------------------------------------------------ --------------
// 5. 优化表格
//------------------------------------------------ --------------
$_CURRENT_STATUS = '优化表';
add2ProcessLog("优化表", 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) '千斤顶函数', '//#_reason_//#' => '因为我这么说')
// $new_page: 如果为真,清除缓冲区并换入新页面,如果为假,则显示错误消息并退出(注意,要使用此功能,必须先在页面上调用 ob_start()
// $dev_dump: 任何你想要在日志中的杂项信息,例如导致错误的查询。这不会显示给用户
// $email_err:发送错误的电子邮件地址。如果设置为“devteam”,则将使用当前组邮件地址(即 devteam@thinklinklearning.com)
// 未来 - 可能想要在 error_codes 表中设置一种方法来覆盖它,以便在测试期间发送给特定的开发人员(目前只能覆盖为始终发送电子邮件)
// $log_only: 如果为 true,则不显示消息,返回代码 - 如果我们想从 perish() 记录到这里,可以使用
全局 $db,$_EMAIL_Admin_Addr,$_CURRENT_STATUS,$_FINAL_STATUS;
// 首先记录错误
$host_info = mysql_get_host_info();
$rq = substr(var_export($_REQUEST,true),0,2000);
$rq = mysql_real_escape_string($rq);
// 将最后一个 sql 错误附加到 dev_dump
$sql_dump = $dev_dump;
//格式化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);
// 获取堆栈回溯
$a = debug_backtrace();
$stack_tr = "堆栈跟踪:\r\n";
$stack_tr .= "------------ \r\n";
foreach($a as $k => $v)
{
$stack_tr .= "文件:$v[文件] \r\n";
$stack_tr .= "行:$v[行] \r\n";
$stack_tr .= "func: $v[函数] \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; // 总是通过电子邮件将错误发送给管理员
$err_html = '';
// 如果请求,电子邮件错误
if ($email_err!='')
{
$pg = explode('/', $pg);
$pg = $pg[计数($pg)-1];
if (strpos(strtoupper($_SERVER['SERVER_NAME']),'DEV')>2) { $fsrv = '(DEV)'; } 其他 { $fsrv = ''; }
邮件($email_err,“错误$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
开发转储:\n
$dev_dump_to_mail\n\n
\n\n------------------------------------\n\n
err_log_key: $err_log_key ");
}
// 更新进程日志
$_CURRENT_STATUS = '错误';
$_FINAL_STATUS = '错误';
add2ProcessLog('ERROR - ' . $sql_err, true);
回声“错误:”。 $pg 。 '-'。 $sql_err;
出口();
}
//------------------------------------------------ --------------
函数 getRequestVar($fieldname,$defaultvalue,$numeric_only=false,$prep_for_sql_insert=false)
{
$rtn = '';
if (isset($_POST[$fieldname]))
{
$rtn = $_POST[$fieldname];
}
别的
{
if (isset($_GET[$fieldname]))
{
$rtn = $_GET[$fieldname];
}
别的
{
$rtn = $默认值;
}
}
if ($numeric_only==true)
{
if (is_numeric($rtn)==false) {$rtn = $defaultvalue;}
}
如果($prep_for_sql_insert==true)
{
$rtn = "'" 。 mysql_real_escape_string($rtn) 。 "'";
}
返回($rtn);
}
//------------------------------------------------ --------------
函数 prepForSQL($rtn_val, $numeric_only=false)
{
if ($numeric_only==true)
{
if (is_numeric($rtn_val)==false) {$rtn_val = -999;}
}
别的
{
// 删除系统中不允许的 chrs
$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) 。 "'";
}
返回($rtn_val);
}
//------------------------------------------------ --------------
函数 dbGetReturnForSQL($sql, $field_for_key = '', $get_scalar_value = false, $default_value = 'x_no_data_x')
{
/* 此函数适用于标量、单行和多行查询
如果 $field_for_key = '' 然后使用索引
如果 $get_scalar_value = true 则仅返回数组中的第一行(不嵌套在行数组中)或仅返回 1 个值(无数组) - 仅第一行必须设置为 true
如果不存在数据,则返回 $default_value,如果为空,则返回 'x_no_data_x'
$error_id_on_fail,传递给 displayErrorMsg 的错误 ID(默认为 GENERAL_ERROR)
*/
全局 $db, $debug, $total_query_time_for_page;
$loc_ptr = 0;
$loc_key = '';
$loc_arr = 数组();
$loc_val = '';
$use_srv = '大师';
$error_id_on_fail = '';
如果($调试){
echo "
QUERY:\n
\n" 。 ereg_replace("\t", " ", $sql) 。 "\n\n
\n";
}
if ( $debug ) { $start_time = microtime(true); }
$result = mysql_query($sql,$db) OR displayErrorMsg($error_id_on_fail,'','',false,$sql,'richard.varno@gmail.com',false);
如果($调试)
{
$end_time = 微时间(真);
$rows_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 "
$rows_rtn 行在 $qry_time 秒内从 $host_info ($use_srv) 返回
总查询时间:$total_query_time_for_page 秒
\n";
}
而 ($rw = mysql_fetch_assoc($result))
{
if ($get_scalar_value==true)
{
// 如果 debug = true 则显示返回值
如果($调试)
{
echo "标量值
\n\n";
foreach($rw 作为 $fld_key => $fld_val)
{
echo "$fld_key$fld_val\n";
}
回声“\n”;
}
如果(计数($rw)==1)
{
$rw_key = array_keys($rw);
$loc_val = $rw[$rw_key[0]];
mysql_free_result($result);
返回($loc_val);
}
别的
{
mysql_free_result($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($result);
// 如果没有找到结果,返回默认值
如果 ($loc_ptr == 0)
{
$loc_arr = $default_value;
}
别的
{
// 如果 debug = true 则显示返回值(仅限第 50 行)
如果($调试)
{
如果($rows_rtn > 50)
{
echo "显示$rows_rtn的第1行到$rows_rtn
\n";
$max_row_to_display = 49;
}
别的
{
echo "显示$rows_rtn的第1行到$rows_rtn
\n";
$max_row_to_display = $rows_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 as $ptr=>$row)
{
回声“\n”;
foreach($rw 作为 $fld_key => $fld_val)
{
echo "$row[$fld_key]\n";
}
回声“\n”;
$cur_row++;
if ($cur_row > $max_row_to_display) { 休息; }
}
回声“\n”;
}
}
返回($loc_arr);
}
//------------------------------------------------ --------------
函数 dbExecuteSQL($sql, $return_insert_id = false)
{
/* 此函数将针对主数据库执行 SQL 语句,并在请求时返回受影响的行或插入 id
$error_id_on_fail,传递给 displayErrorMsg 的错误 ID(默认为 GENERAL_ERROR)
*/
全局 $db, $debug, $total_query_time_for_page;
$loc_ptr = 0;
$loc_insert_id = 0;
$loc_rows_affected = 0;
$error_id_on_fail = '';
如果($调试){
echo "
QUERY:\n
\n" 。 ereg_replace("\t", " ", $sql) 。 "\n\n
\n";
}
if ( $debug ) { $start_time = microtime(true); }
$result = mysql_query($sql,$db) OR displayErrorMsg($error_id_on_fail,'','',false,$sql,'richard.varno@gmail.com',false);
$loc_insert_id = mysql_insert_id($db);
$loc_rows_affected = mysql_affected_rows($db);
$use_srv = '大师';
如果($调试)
{
$end_time = 微时间(真);
$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 "$host_info ($use_srv) 在 $qry_time 秒内受影响的 $loc_rows_affected 行
总查询时间:$total_query_time_for_page 秒
\n";
}
if ($return_insert_id==true) { return($loc_insert_id); } 其他 { 返回($loc_rows_affected); }
}
//------------------------------------------------ --------------