замутил для своего сайтика фишку... PHP: <?php function log ($trigger, $query = "", $output = true) { // Путь к файлу $log = "./logs/error.mysql.log"; // Формируем запись с ошибкой в лог-файл $error = "\r\n[" . date("d.m.Y H:i:s") . "] "; if ($trigger == "105:1") { $error .= "Неверные параметры подключения или сервер базы данных временно не доступен"; } elseif ($trigger == "105:2") { $error .= "Невозможно подключиться к БД \"" . MYSQL_DB . "\""; } elseif ($trigger == "105:3") { $error .= "Невозможно выполнить запрос к БД \"" . MYSQL_DB . "\": " . $query; } $error .= " - " . mysql_error (); // Запись в файл $log $open = @fopen ($log, "a") or die ("Разрешите доступ на запись файлу \"./logs/error.mysql.log\""); $write = @fwrite ($open, $error) or die ("Ошибка записи в файл \"./logs/error.mysql.log\""); $close = @fclose ($open) or die ("Ошибка закрытия файла \"./logs/error.mysql.log\""); // Выводим сообщение об ошибке в браузер $output = "<html>\n<head>\n<title>GRAMMONE™ - Ошибка</title>\n" . "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1251\">\n" . "<link rel=\"StyleSheet\" href=\"./style.css\" type=\"text/css\">\n" . "</head>\n<body>\n"; if ($trigger == "105:1") { $output .= "<p align=\"center\">\n<img border=\"0\" src=\"./images/105-1.gif\" width=\"200\" height=\"200\" alt=\"Сервер базы данных временно не доступен: 105-1\">\n</p>\n<p align=\"center\">Сервер базы данных временно не доступен\n<br>\nПросим зайти на сайт через 15 минут</p>\n</body>\n</html>"; } elseif ($trigger == "105:2") { $output .= "<p align=\"center\">\n<img border=\"0\" src=\"./images/105-1.gif\" width=\"200\" height=\"200\" alt=\"Базы данных временно не доступна: 105-2\">\n</p>\n<p align=\"center\">База данных временно не доступна\n<br>\nПросим зайти на сайт через 15 минут</p>\n</body>\n</html>"; } elseif ($trigger == "105:3") { $output .= "<p align=\"center\">\n<img border=\"0\" src=\"./images/105-1.gif\" width=\"200\" height=\"200\" alt=\"Ошибка выполнения запроса: 105-3\">\n</p>\n<p align=\"center\">Ошибка выполнения запроса к БД\n<br>\nПожалуйста, повторите операцию</p>\n</body>\n</html>"; } return $output; } ?> Создание запроса в БД с учетом возможных ошибок в SQL PHP: <?php $sql = "SELECT * FROM table WHERE col=1"; $mq = mysql_query ($sql) or die ($mysql->log ("105:3", $query)); ?> Если в этом SQL Запросе есть ошибка - выводитя: и скрипт прекращает работу, предварительно записав ошибку в лог.. ПРОШУ ОЦЕНИТЬ И УКАЗАТЬ НА НЕДОСТАТКИ
Если в запросе содержится ошибка, то сколько его ни повторяй, правильным он от этого не станет. В лог должен идти не только сам запрос, но и код ошибки, который должен быть получен из смой базы, а не вбит вручную. И еще... Если log это метод объекта бд, то почему запросы идут не через этот объект? Странно, почему мы пытаемся скрыть ошибки бд, но всячески пытаемся показать ошибки файловой системы? file_put_contents($fileaddr, $text, FILE_APPEND);
Блин, давно бы пора задаться вопросом: а почему бы не юзать класс-обёртку для работы с БД? И уже там бы можно было без проблем внедрить логгирование ошибок SQL, а не городить огород типа $mq = mysql_query ($sql) or die ($mysql->log ("105:3", $query)); ИМХО.
PHP: <?php class MyDb { //... function query() { //... if (!($res = mysql_query($query))) { throw new MyDbQueryException('Error "' . mysql_error() . '" in query "' . $query . '"'); } //... } //... }
можно отслеживать изменения в логе... разными способами ) предполагаю (поскольку проект небоьшой), за 15 минут ошибка будет устранена исправлю )) эмм.ммм.... ))) эта ошибка (как предполагается) может выскачить только один раз, при установке скрипта на хостинг, если с файлом error.log что-то случится... вероятность возникновения ошибки у пользователей сводится к минимуму... исправлю неохота полный класс писать, а чужие юзать не могу, т.к. не понимаю в них ниче.... ))) хотя в принцепе согласен ну опять таки согласен ))
Ну не знаю, мне хватило дня на написание и тестирование, плюс потом ещё по ходу пара исправлений, добавление функционала... Но всё равно клёво получилось. И удобно. Так что, имхо, лучше побороть свою лень - потом меньше переписывать
как-то писал и до сих пор использую с небольшими модификациями (может кому понадобиться): PHP: <?php /* работа с БД MySQL my_db = new DB('адрес_сервера', 'порт', 'имя_пользователя', 'пароль', 'имя_базы'); создаем класс и одновременно коннектимся к базе с заданными параметрами my_db->send_query('sql_string'); послать запрос и получить результат возвращает массив с символьными индексами "num_rows" и "last_insert_id" в которых указано кол-во строк и последний всталвенный INSERT'ом ID (автоинкремент) соответственно, в индексном массиве содержиться результат запроса my_db->close(); закрывает коннект и уничтожает созданный класс. */ class DB { var $connection; var $last_query; var $last_result; function __construct($_server = 'localhost', $_port = '3306', $_user = '', $_password = '', $_DBName = '') { if ($this->connection = @mysql_connect($_server.':'.$_port, $_user, $_password)) { $this->client_encoding = mysql_client_encoding($this->connection); if (mysql_select_db($_DBName)) { mysql_query("set character_set_client='cp1251'"); mysql_query("set character_set_results='cp1251'"); mysql_query("set collation_connection='cp1251_general_ci'"); return true; }; }; $this->error(mysql_error(), mysql_errno()); } function DB($_server = 'localhost', $_port = '3306', $_user = '', $_password = '', $_DBName = '') { $this->__construct($_server, $_port, $_user, $_password, $_DBName); } function send_query($query = NULL, $_xml_name = NULL, &$_return_container = NULL) { $this->last_query = $query; $result = @mysql_query($this->last_query, $this->connection); if (mysql_error()) { $this->error(mysql_error(), mysql_errno()); }; $this->last_result = Array( 'last_insert_id' => @mysql_insert_id(), 'num_rows' => @mysql_num_rows($result) ); if ($this->last_result['num_rows'] >= 1) { while($row = @mysql_fetch_array($result, MYSQL_ASSOC)) { $this->last_result[] = $row; }; }; @mysql_free_result($result); return $this->last_result; } function error($_errmess, $_errno) { // допишите свой обработчик ошибки } function close() { $this->__destruct(); } function __destruct() { @mysql_close($this->connection); } }; ?>
Эх, ну вот мой на растерзание: PHP: <?php // Database working class Class DB { // mysql resource var private static $_resource; // mysql database name private static $_db_name; private static function _buildOrderBy($order_by) { if (is_array($order_by)) { $order_by_building = array(); foreach ($order_by as $key => $value) { if (is_string($key) && in_array($value, array('ASC', 'DESC'))) $order_by_building[] = '`'.$key.'` '.(string)$value; elseif (strpos($value, '(') !== false && strpos($value, ')') !== false) $order_by_building[] = self::_checkValue($value); } return implode(', ', $order_by_building); } elseif (strpos($order_by, '(') !== false && strpos($order_by, ')') !== false) return (string)$order_by; else return (string)'`'.$order_by.'`'; } private static function _buildWhere($where) { if (is_array($where)) { $where_building = array(); foreach ($where as $key => $value) { if (is_string($key)) { if (is_array($value) && isset($value[0]) && isset($value[1])) $where_building[] = '`'.$key.'`'.$value[0].self::_checkValue($value[1]); else $where_building[] = '`'.$key.'`='.self::_checkValue($value); } else $where_building[] = (string)$value; } return implode(' AND ', $where_building); } else return (string)$where; } private static function _checkValue($value, $type = 'string') { $value = (string)$value; if (is_int($value) || is_float($value) || (strpos($value, '(') !== false && strpos($value, ')') !== false && strpos($value, ' ') === false) || $value == 'NULL' || (strpos($value, '*') !== false && strpos($value, ' ') === false) || strpos($value, '%') !== false || (strpos($value, '+') !== false && strpos($value, ' ') === false) || (strpos($value, '-') !== false && strpos($value, ' ') === false)) return $value; elseif (is_null($value)) return 'NULL'; elseif ($type == 'integer') return self::escape((int)$value); elseif ($type == 'string') return '"'.self::escape((string)$value).'"'; } public static function connect($db_host, $db_user, $db_pass, $db_name, $persistent = true) { if (is_resource(self::$_resource) && get_resource_type(self::$_resource) == 'mysql_link') { trigger_error('DB::connect(): Resource already exists!', E_USER_WARNING); return null; } if ($persistent) self::$_resource = mysql_pconnect($db_host, $db_user, $db_pass, $persistent); else self::$_resource = mysql_connect($db_host, $db_user, $db_pass, $persistent); if (self::$_resource === false) { trigger_error('DB::connect(): Connection failed!', E_USER_WARNING); return null; } if (!mysql_select_db($db_name, self::$_resource)) { trigger_error('DB::connect(): Database select failed!', E_USER_WARNING); return null; } self::$_db_name = $db_name; if (self::query("SET character_set_client='utf8', character_set_results='utf8', collation_connection='utf8_general_ci'")) return true; else return null; } public static function disconnect() { if (is_resource(self::$_resource) && get_resource_type(self::$_resource) == 'mysql_link') mysql_close(self::$_resource); self::$_resource = null; self::$_db_name = null; } public static function getErrorString() { return mysql_error(self::$_resource); } public static function getErrorCode() { return mysql_errno(self::$_resource); } public static function query($query, $buffered = true) { if (self::$_resource === false) { trigger_error('DB::query(): Connection does not exists!', E_USER_WARNING); return null; } $buffered = (bool)$buffered; //var_dump($query); if ($buffered) $result = mysql_query($query); else $result = mysql_unbuffered_query($query); if ($result === false) { trigger_error('DB::query("'.substr($query, 0, 200).'"): Error given: '.mysql_errno().' - '.mysql_error(), E_USER_WARNING); return null; } else return $result; } public static function num_rows($result) { if (get_resource_type($result) != 'mysql result') { trigger_error('DB::num_rows(): Input parameter is not mysql result resource!', E_USER_WARNING); return null; } return mysql_num_rows($result); } public static function select($fields, $tbl_name, $where = null, $group_by = null, $order_by = null, $limit = null, $start = null, $options = null) { $query = 'SELECT '; if (is_array($options)) $options = implode(' ', array_intersect($options, array('STRAIGHT_JOIN', 'SQL_SMALL_RESULT', 'SQL_BIG_RESULT', 'SQL_BUFFER_RESULT', 'SQL_CACHE', 'SQL_NO_CACHE', 'SQL_CALC_FOUND_ROWS', 'HIGH_PRIORITY', 'DISTINCT', 'DISTINCTROW', 'ALL'))); else $options = ''; if (is_array($fields)) $query .= '`'.implode('`, `', $fields).'`'; else $query .= self::_checkValue($fields); $query .= ' FROM '; if (is_array($tbl_name)) $query .= implode(', ', $tbl_name); else $query .= (string)$tbl_name; if ($where !== null) $query .= ' WHERE '.self::_buildWhere($where); if ($group_by !== null) $query .= ' GROUP BY '.self::_buildOrderBy($group_by); if ($order_by !== null) $query .= ' ORDER BY '.self::_buildOrderBy($order_by); if ($limit !== null) { $query .= ' LIMIT '; if ($start !== null) $query .= self::_checkValue($start, 'integer').', '; $query .= self::_checkValue($limit, 'integer'); } return self::query($query); } public static function get($resource, $type = 'assoc') { if (get_resource_type($resource) != 'mysql result') { trigger_error('DB::get(): Input parameter is not mysql result resource!', E_USER_WARNING); return null; } switch ($type) { case 'object': $function = 'mysql_fetch_object'; break; case 'array': $function = 'mysql_fetch_row'; break; default: $function = 'mysql_fetch_assoc'; break; } return $function($resource); } public static function getAll($resource, $type = 'assoc') { if (get_resource_type($resource) != 'mysql result') { trigger_error('DB::getAll(): Input parameter is not mysql result resource!', E_USER_WARNING); return null; } $cummulative_array = array(); while ($row = self::get($resource, $type)) $cummulative_array[] = $row; return $cummulative_array; } // Insert data into table /* $data format: array( array('column1', 'column2', 'column3'), array('value1_row1', 'value2_row1', 'value3_row1'), array('value1_row2', 'value2_row2', 'value3_row2'), array('value1_row3', 'value2_row3', 'value3_row3') ) or array( 'column1' => 'value1', 'column2' => 'value2', 'column3' => 'value3' ) */ public static function insert($data, $tbl_name, $options = null) { if (!is_array($data)) { trigger_error('DB::insert(): Input data is not array!', E_USER_WARNING); return null; } $type = null; $fields = array(); $values = array(); foreach ($data as $column => $value) { // If is not row or bad value - throw error if ((is_array($value) && !is_integer($column)) || (!is_array($value) && is_integer($column))) { trigger_error('DB::insert(): Wrong data format: array element not row or has bad value!', E_USER_WARNING); return null; } if (is_array($value) && count($value) && $type != 'single') { if (count($fields) == 0) { foreach ($value as $field) $fields[] = $field; } else { $row = array(); foreach ($value as $column_value) $row[] = $column_value; $values[] = $row; } $type = 'multiple'; } elseif ($type != 'multiple') { if (!isset($values[0])) $values[0] = array(); $fields[] = $column; $values[0][$column] = $value; $type = 'single'; } else { trigger_error('DB::insert(): Wrong data format: input array elements are not coordinated!', E_USER_WARNING); return null; } } if (is_array($options)) $options = implode(' ', array_intersect($options, array('LOW_PRIORITY', 'DELAYED', 'IGNORE'))); else $options = ''; foreach ($fields as &$field) $field = '`'.$field.'`'; foreach ($values as &$row) { foreach ($row as &$value) { if (strpos($value, '(') === false && strpos($value, ')') === false && $value != 'NULL') $value = '"'.self::escape($value).'"'; } $row = implode(', ', $row); } $result = self::query( 'INSERT '.$options.' INTO `'.$tbl_name.'` ('.implode(', ', $fields).') VALUES ('.implode('), (', $values).')' ); if ($result !== null) return self::affected_rows(); else return null; } // UPDATE data into table /* $data format: array( 'column1' => 'value1', 'column2' => 'value2', 'column3' => 'value3' ) */ public static function update($data, $tbl_name, $where = null, $order_by = null, $limit = null, $options = null) { if (!is_array($data)) { trigger_error('DB::update(): Input data is not array!', E_USER_WARNING); return null; } if ($limit !== null) { $limit = (int)$limit; if ($limit < 1) { trigger_error('DB::update(): Limit value less than 1: setting to null!', E_USER_WARNING); $limit = null; } } $values = array(); foreach ($data as $column => $value) { // If is row or bad value - throw error if (is_array($value) || is_integer($column)) { trigger_error('DB::update(): Wrong data format: array element not row or has bad value!', E_USER_WARNING); return null; } $values[] = '`'.$column.'`='.self::_checkValue($data[$column]); } if (is_array($options)) $options = implode(' ', array_intersect($options, array('LOW_PRIORITY', 'IGNORE'))); else $options = ''; $query = 'UPDATE '.$options.' `'.$tbl_name.'` SET '.implode(', ', $values); if ($where !== null) $query .= ' WHERE '.self::_buildWhere($where); if ($order_by !== null) $query .= ' ORDER BY '.self::_buildOrderBy($order_by); if ($limit !== null) $query .= 'LIMIT '.$limit; $result = self::query($query); if ($result !== null) return self::affected_rows(); else return null; } public static function delete($tbl_name, $where = null) { if ($where === null) return (bool)self::query('TRUNCATE TABLE `'.$tbl_name.'`'); else return (bool)self::query('DELETE FROM `'.$tbl_name.'` WHERE '.self::_buildWhere($where)); } public static function affected_rows() { return mysql_affected_rows(); } public static function last_insert_id() { return mysql_insert_id(); } public static function escape($string) { return mysql_real_escape_string($string); } public static function lock($tbl_name, $type = 'read') { if ($type != 'read' && $type != 'write') $type = 'read'; $type = strtoupper($type); self::query('LOCK TABLES '.$tbl_name.' '.$type); } public static function unlock() { self::query('UNLOCK TABLES'); } }
Чтобы не компоновать запрос каждый раз, а тупо вызывать DB::insert($data, 'table_name'); и радоваццо жизни.
Clone, глаза сломал )))) с перегрузочкой немного борщнул, но затея интересная )))) где-то у меня валялся Студийный класс на parser'е, где ещё по типу базы запрос модифицируется, но не помню где...