При выводе диагностики в своих рабочих проектах я использую вот такую функцию для подсветки синтаксиса MySQL-запросов. Она преобразует текст запроса, делая все служебные слова языка заглавными буквами и подсвечивает их цветом, а также выделяет различными цветами числовые значения и скобки. Такая подсветка позволяет сразу же увидеть синтаксические ошибки, да и вообще повышает наглядность сообщений при отладке скриптов.
//-------------------------------------------------------------------
// Функция подсветки синтаксиса MySQL-запроса
// (C) ManHunter / PCL
// http://www.manhunter.ru
//-------------------------------------------------------------------
function mysql_debug($query) {
$tmp=htmlspecialchars($query);
$tmp=str_replace("\r",'',$tmp);
$tmp=trim(str_replace("\n","\r\n",$tmp))."\r\n";
$quote_list_text=array();
$quote_list_symbols=array();
$k=0;
$quotes=Array();
// Обработать экранированные кавычки
preg_match_all("/\\\'|\\\"/is", $tmp, $quotes);
array_unique($quotes);
if (count($quotes)) {
foreach($quotes[0] as $i) {
$k++;
$quote_list_symbols[$k]=$i;
$tmp=str_replace($i, '<symbol'.$k.'>', $tmp);
}
}
$matches=Array(
"/("|'|`)(.*?)(\\1)/is", // текст в кавычках
"/\/\*.*?\*\//s", // текст комментария
"/ \-\-.*\x0D\x0A/", // текст ' --' комментария
"/ #.*\x0D\x0A/", // текст ' #' комментария
);
// Обработать текст
foreach($matches as $match) {
// Обработать текст
$found=array();
preg_match_all($match, $tmp, $found);
$quotes=(array)$found[0];
array_unique($quotes);
if (count($quotes)) {
foreach($quotes as $i) {
$k++;
$quote_list_text[$k]=$i;
$tmp=str_replace($i, '<text'.$k.'>', $tmp);
}
}
}
// Служебные слова MySQL
$keywords=Array(
"avg", "as", "auto_increment", "and", "analyze", "alter",
"asc", "all", "after", "add", "action", "against",
"aes_encrypt", "aes_decrypt", "ascii", "abs", "acos",
"asin", "atan", "authors", "between", "btree", "backup",
"by", "binary", "before", "binlog", "benchmark", "blob",
"bigint", "bit_count", "bit_or", "bit_and", "bin",
"bit_length", "both", "create", "count", "comment",
"check", "char", "concat", "cipher", "changed", "column",
"columns", "change", "constraint", "cascade", "checksum",
"cross", "close", "concurrent", "commit", "curdate",
"current_date", "curtime", "current_time",
"current_timestamp", "cast", "convert", "connection_id",
"coalesce", "case", "conv", "concat_ws", "char_length",
"character_length", "ceiling", "cos", "cot", "crc32",
"compress", "delete", "drop", "default", "distinct",
"decimal", "date", "describe", "data", "desc",
"dayofmonth", "date_add", "database", "databases",
"double", "duplicate", "disable", "datetime", "dumpfile",
"distinctrow", "delayed", "dayofweek", "dayofyear",
"dayname", "day_minute", "date_format", "date_sub",
"decode", "des_encrypt", "des_decrypt", "degrees",
"decompress", "dec", "engine", "explain", "enum",
"escaped", "execute", "extended", "errors", "exists",
"enable", "enclosed", "extract", "encrypt", "encode",
"elt", "export_set", "escape", "exp", "end", "from",
"float", "flush", "fields", "file", "for", "fast", "full",
"fulltext", "first", "foreign", "force", "from_days",
"from_unixtime", "format", "found_rows", "floor", "field",
"find_in_set", "group", "grant", "grants", "global",
"get_lock", "greatest", "having", "high_priority",
"handler", "hour", "hex", "insert", "into", "inner",
"int", "ifnull", "if", "isnull", "in", "infile", "is",
"interval", "ignore", "identified", "index", "issuer",
"integer", "is_free_lock", "inet_ntoa", "inet_aton",
"instr", "join", "kill", "key", "keys", "left", "load",
"local", "limit", "like", "lock", "lpad", "last_insert_id",
"logs", "length", "longblob", "longtext", "last", "lines",
"low_priority", "locate", "ltrim", "leading", "lcase",
"lower", "load_file", "ln", "log", "least", "month", "mod",
"max", "min", "mediumint", "medium", "master", "modify",
"mediumblob", "mediumtext", "match", "mode", "monthname",
"mid", "minute", "master_pos_wait", "make_set", "null",
"not", "now", "none", "new", "numeric", "no", "natural",
"next", "nullif", "national", "nchar", "on", "or",
"optimize", "order", "optionally", "option", "outfile",
"open", "offset", "outer", "old_password", "ord", "oct",
"octet_length", "primary", "password", "privileges",
"process", "processlist", "purge", "partial", "procedure",
"prev", "period_add", "period_diff", "position", "pow",
"power", "pi", "quick", "quarter", "quote", "right",
"repair", "restore", "reset", "regexp", "references",
"replace", "revoke", "reload", "require", "replication",
"read", "rand", "rename", "real", "restrict",
"release_lock", "rpad", "rtrim", "repeat", "reverse",
"rlike", "round", "radians", "rollup", "select", "sum",
"set", "show", "substring", "smallint", "super", "subject",
"status", "slave", "session", "start", "share",
"straight_join", "sql_small_result", "sql_big_result",
"sql_buffer_result", "sql_cache", "sql_no_cache",
"sql_calc_found_rows", "second", "sysdate", "sec_to_time",
"system_user", "session_user", "substring_index", "std",
"stddev", "soundex", "space", "strcmp", "sign", "sqrt",
"sin", "straight", "sleep", "text", "truncate", "table",
"tinyint", "tables", "to_days", "temporary", "terminated",
"to", "types", "time", "timestamp", "tinytext",
"tinyblob", "transaction", "time_format", "time_to_sec",
"trim", "trailing", "tan", "then", "update", "union",
"using", "unsigned", "unlock", "usage", "use_frm",
"unix_timestamp", "unique", "use", "user", "ucase",
"upper", "uuid", "values", "varchar", "variables",
"version", "variance", "varying", "where", "with",
"warnings", "write", "weekday", "week", "when", "xor",
"year", "yearweek", "year_month", "zerofill");
$replace=Array();
foreach($keywords as $keyword) {
$replace[]='/\b'.$keyword.'\b/ie';
}
// Выделить служебные слова в тексте запроса
$tmp=preg_replace($replace,
'"<b style=\"color:#0000FF\">".strtoupper("$0")."</b>"',$tmp);
// Выделить числовые значения в тексте запроса
$tmp=preg_replace('/\b([\.0-9]+)\b/',
'<b style="color:#008000">\1</b>',$tmp);
// Выделить скобки в тексте запроса
$tmp=preg_replace('/([\(\)])/',
'<b style="color:#FF0000">\1</b>',$tmp);
// Вернуть обратно строки в кавычках
if (count($quote_list_text)) {
$quote_list_text=array_reverse($quote_list_text, true);
foreach($quote_list_text as $k=>$i) {
$tmp=str_replace('<text'.$k.'>',
'<span style="color:#777;">'.$i.'</span>', $tmp);
}
}
// Вернуть обратно экранированные символы
if (count($quote_list_symbols)) {
$quote_list_symbols=array_reverse($quote_list_symbols, true);
foreach($quote_list_symbols as $k=>$i) {
$tmp=str_replace('<symbol'.$k.'>', $i, $tmp);
}
}
// Вернуть подсвеченный текст запроса
// Если не надо расставлять переносы, то уберите nl2br
return nl2br(trim($tmp));
}
Единственный параметр функции $query - текст исходного запроса. На выходе подсвеченная строка запроса в формате HTML. Цвета подсветки захардкодены в исходнике, если надо, то поменяйте их на свои или вообще замените на определения стилей CSS.
Функция может вернуть неправильный результат, если в
комментариях запроса содержатся несогласованные кавычки или апострофы, в остальном при тестировании я никаких проблем не нашел. Вот несколько примеров работы скрипта:
CREATE TABLE `orders` (
`o_id` INT(11) NOT NULL AUTO_INCREMENT,
`o_date` INT(11) NOT NULL,
`o_client` INT(11) NOT NULL COMMENT 'пользователь создавший заказ',
`o_status` INT(11) NOT NULL COMMENT 'статус заказа',
`o_sum` INT(11) NOT NULL COMMENT 'стоимость размещения',
`o_nds` DECIMAL(15,2) NOT NULL DEFAULT '0.00',
`o_comment` VARCHAR(1024) NOT NULL COMMENT 'Комментарии к заказу',
PRIMARY KEY (`o_id`)
) ENGINE=MyISAM /*!40101 DEFAULT CHARSET=utf8 */;
SELECT SQL_CACHE `regions`.*,
COUNT(`o_id`) AS `o_num`,
SUM(IF(`o_map` != 0, 1, 0)) AS `sum_map`,
SUM(IF(`o_list` != 0, 1, 0)) AS `sum_list`,
SUM(IF(`p_price`>0),1,0) AS `sum_free`,
FROM `regions`, `orders`
LEFT JOIN `prices` ON `p_o_id`=`o_id` AND `p_year`=2012
WHERE `o_region`=`r_id` AND `o_deleted`=0 AND `o_type`=0
GROUP BY `r_id`
HAVING (`sum_free`>50)
ORDER BY `r_order` DESC, `r_name`
Функция предназначена только для подсветки синтаксиса MySQL, но ее можно легко адаптировать под любой другой диалект SQL. Достаточно просто добавить или убрать служебные слова в соответствующем массиве.