Выкладываю часть своего класса для работы с базой данных MySQL. Избавляет от рутины типа mysql_connect, $result = mysql_connect, while($row = mysql_fetch_array... Подключение к базе данных (после подключения файла с помощью include/require): $db = new database('host', 'user', 'pass', 'database'); Класс содержит три основных метода: query, select, insert Выполнение любого запроса можно сделать с помощью метода query, который ничего не возвращает: $db->query("UPDATE menu_items SET `enabled`=TRUE WHERE item_id=4"); Выборка (селект) из базы данных производится: $result = $db->select("SELECT * FROM menu_items WHERE item_id=4"); В ответ возвращается ассоциативный php-массив, с которым намного удобнее работать, чем парсить объект запроса. Методы query/select принимают два параметра в запросе – первый это собственно сам запрос, а второй – это данные, которые учавствуют в запросе. Второй параметр не является необходимым, однако использовать его довольно удобно для данных, которые необходимо экранировать (об этом чуть ниже). Вставку элементов можно производить как методом query, который принимает любой тип запросов, так и специальным методом insert, который может вернуть значение автоинкрементного поля: $db->insert("INSERT INTO menu_items (`title`, `link`) VALUES ('title', 'link')", array(), 'item_id'); При использовании метода insert необходимо чтобы всегда встявлялась только одна строка. В отличие от методов query/select, метод insert принимает три обязательных параметра, а не два; третьим параметром идёт название автоинкрементного поля, которое необходимо вернуть. Для безопасности все данные, поступающие в запрос необходимо экранировать. Можно выполнять экранирование переменных вручную, а можно позволить это сделать системе с помощью указания плейсхолдеров {placeholder}: $arguments = array('title' => 'Here is the title', 'link' => "Here is the link"); $item_id = $db->insert("INSERT INTO menu_items (`title`, `link`) VALUES ({title}, {link})", $arguments, 'item_id'); Код самого класса PHP: <?php class database { /* VARIABLES */ private $conn = false; private $data = array(); /* PUBLIC FUNCTIONS*/ public function __construct($host, $user, $pass, $base) { $this->conn = mysql_connect($host, $user, $pass) or die(mysql_error()); mysql_select_db($base, $this->conn); mysql_query("SET NAMES 'utf8'", $this->conn); } public function insert($request, $data, $column){ $request = $this->query_process($request, $data); $query = mysql_query($request, $this->conn) or die("Cannot execute request to the database '{$request}'"); $query = mysql_query("SELECT last_insert_id() as `{$column}`", $this->conn); $array = $this->result2array($query); return isset($array[0][$column]) ? $array[0][$column] : 0; } public function query($request, $data = array()) { $request = $this->query_process($request, $data); $query = mysql_query($request, $this->conn) or die("Cannot execute request to the database '{$request}'"); } public function select($request, $data = array()) { $request = $this->query_process($request, $data); $query = false; $query = mysql_query($request, $this->conn) or die("Cannot execute request to the database '{$request}'"); return $this->result2array($query); } /* PRIVATE FUNCTIONS */ private function holders_replace($matches){ $placeholder = $matches[2]; if(!isset($this->data[$placeholder])) throw new Exception("No data for placeholder '{{$placeholder}}'"); // process IN({list}) values if(is_array($this->data[$placeholder])){ $data = array(); foreach($this->data[$placeholder] as $v) $data[] = mysql_real_escape_string($v); $value = implode("', '", $data); } else { $value = mysql_real_escape_string($this->data[$placeholder]); } return "'{$value}'"; } private function query_process($query, $data){ $this->data = $data; $query = preg_replace_callback("#('?){([^}]+)}(\\1)#sUi", array($this, 'holders_replace'), $query); return $query; } private function result2array(&$query){ $result = array(); $i = 0; if($query === false) { return $result; } while($row = mysql_fetch_array($query)) { $result[$i] = array(); foreach($row as $key=>$value) { if(!is_numeric($key)) { $result[$i][strtolower($key)] = $value; } } $i++; } return $result; } } ?> P.S. да-да-да, я собираюсь переходить на mysqli когда-нибудь. и да - буду использовать исключения вместо die. но это потом. это часть класса, т.к. полный класс умеет также делать ограниченный импорт/экспорт и поддерживает также PostgreSQL, что позволяет легко переключаться между базами. выкладываю с целью скидывать линк на этот пост поповщине
Вот мой класс. Костылей хватает, но работает, и меня устраивает. За основу брал чей-то код, но потом его изменил PHP: <? class mysql_db{ private $debug = false; // debug сообщения ON or OFF private $link = ''; // Идентификатор private $charset = ''; // Кодировка function mysql_db($charset = 'cp1251') { $this->charset = $charset; } function getConnect($host,$only_db,$user,$password) { $this->link = mysqli_connect($host, $user, $password, $only_db); // Соединяемся if (!$this->link) throw New Exception; mysqli_set_charset($this->link, $this->charset); // Меняем кодировку return $this->link; } function escape ($str) { return mysqli_real_escape_string($this->link, $str); } function error () { return mysqli_error($this->link); } function insert_id() { return mysqli_insert_id($this->link); } function query($sql,$debug = FALSE) { $this->debug = $debug; // set debug $result_array = array(); if($debug) $this->print_in_HTML("SQL", $sql); // print sql query as debug message switch (1) { case preg_match("/ IN \{SELECT/", $sql): switch (1) { case preg_match("/^SELECT/", $sql): preg_match_all("/({[^}]*)/", $sql, $matches, PREG_SET_ORDER); // find matching sql $sql_in = str_replace("{", "", strrchr($matches[0][0], "{")); if(NULL == ($in = $this->set_IN($sql_in))) return NULL;//~ ; $sql = str_replace($sql_in, $in, $sql); $sql = str_replace("{(", "(", $sql); $sql = str_replace(")}", ")", $sql); if(NULL == $this->query($sql, $debug)) return NULL;//~ break; } default:// normal MySQL syntax // analyse syntax of query switch (1) { case preg_match("/^SELECT/",$sql): if("" == ($result_identifier = mysqli_query($this->link, $sql))) return NULL;//~ no result $mysql_error = mysqli_error($this->link); if($debug && "" != $mysql_error) $this->print_in_HTML("ERROR", $mysql_error); if("" != $mysql_error) return NULL;//~ error occured switch (1) { case preg_match("/COUNT\([^,]{1,}FROM/",$sql): case preg_match("/MAX\(/", $sql): case preg_match("/MIN\(/", $sql): case preg_match("/SUM\(/", $sql): $ret = mysqli_fetch_row($result_identifier);//~ result for select COUNT, MAX, MIN, SUM mysqli_free_result($result_identifier); return $ret[0]; break; case preg_match("/LIMIT 0\,1$/",$sql): switch (1) { case preg_match("/^.+,.+FROM.+/",$sql): $ret = mysqli_fetch_object($result_identifier);//~ result an object mysqli_free_result($result_identifier); return $ret; break; default: if(0 == mysqli_num_rows($result_identifier)) return NULL;//~ $ret = mysqli_result($result_identifier,0);//~ result for select COUNT, MAX, MIN, SUM mysqli_free_result($result_identifier); return $ret; } break; default: // get result values to array of objects $i=0; while ($result = mysqli_fetch_object($result_identifier)) { $result_array[$i] = $result; $i++; } mysqli_free_result($result_identifier); return $result_array;//~ } break; default: return mysqli_query($this->link, $sql);//~ } } } function set_IN($sql) { if($this->debug) $this->print_in_HTML("IN SQL", $sql); $in = "("; if (!($res = mysqli_query($this->link, $sql))) return NULL; while ($val = mysqli_fetch_array($res, MYSQL_NUM)) $in .= $val[0].","; $in = preg_replace(",$", ")", $in); mysqli_free_result($res); return $in; } function print_in_HTML($title, $string) { // simply: format in HTML all debug messages echo " <br>---- $title<br><br> <pre>".htmlentities($string)."</pre> "; return TRUE; } function connectClose() { return mysqli_close($this->link); } } ?>
http://php.net/mysql_insert_id зачотно, если действительно обойти нельзя чтобы получить link, создавать новое соединение? o_0 Volt(220) В MySQLDB не объявлена needEnc, и неожиданно используются необъявленные функции (deepIconv например)
[vs] PHP: <?php class MySQLDB extends SQLDB{ А вот getColumnsInfo и escapeForLike для мускула я еще не реализовал. А deepIconv лежит в http://code.google.com/p/voltcore/sourc ... oltLib.php
[vs] мой способ тоже работает но спасибо за наводку, учту. в смысле? зачем обходить? эта регулярка ловит плейсхолдеры. трудность была с тем, что нужно ловить также и плейсхолдеры, заключённые в одинарные кавычки Ensiferum а как пользоваться? пару примеров плиз
[vs] линк внутри класса. при работе он не нужен (если только у тебя не 2 и более соединения) Gromo Делаю так PHP: <? // Коннект к базе данных function db_connect() { global $db; $db = new mysql_db(); try { $db->getConnect(DB_HOST,DB_NAME,DB_LOGIN,DB_PASSWORD); } catch (Exception $e) { $txt = 'Сайт '.$_SERVER['SERVER_NAME']."\r\n"; $txt .= date("d.m.Y H:i:s"). "\r\n\r\n"; $txt .= 'Упала база данных'; send_mail([email='admin@mail.ru]'admin@mail.ru[/email]', $txt); die("Нет соединения с БД"); } } // Выборка $result = $db->query("SELECT * FROM notes ORDER BY id DESC"); if($result) { foreach ($result as $obj) $text .= '<div class="new_note"> <div class="note_date">'.convert_date($obj->n_date).' '.$obj->n_time.'</div> <div class="note_text">'.stripslashes($obj->n_text).'</div> <div class="note_author"><div style="float:left">'.$obj->n_author.'</div><div style="float:right"><a href='.$path.'&act=delete&id='.$obj->id.'><img src=template/images/delete.gif alt="Удалить"></a></div></div> </div>'; } // Удаление $db->query("DELETE FROM notes WHERE id='".$id."'"); $db->error()? $text.= back("Ошибка - ".$db->error()) : $text.= msg($path,"Заметка удалена"); // Вставка $db->query("INSERT INTO notes VALUES ('',CURDATE(),CURTIME(),'".$db->escape($_POST['note_text'])."','".$db->escape($_POST['note_author'])."')"); $db->error()? $text.= back("Ошибка - ".$db->error()) : $text.= msg($path,"Заметка Добавлена");
Padaboo Своё творение объясню тем, что надо было группу сайтов перенести на mysqli с минимальными багами. Поэтому существующий класс перерабатывался, а не задействовались классы PDO или mysqli
мой костылюшка: PHP: <?php class DB { static public $connect = null; static private $last_query = ''; static public function query($query) { self::$last_query = $query; return self::$connect->query($query); } static public function escape($string) { return self::$connect->real_escape_string($string); } static public function error() { return self::$connect->errno . ' - ' . DB::$connect->error . ' QUERY = "' . self::$last_query . '"'; } static public function id($query) { self::$last_query = $query; self::$connect->query($query); return self::$connect->insert_id; } static public function assoc($query) { self::$last_query = $query; if ($result = self::$connect->query($query)) { //return $result->fetch_all(MYSQLI_ASSOC); while ($row = $result->fetch_assoc()) { $r[] = $row; } return $r; } else { return false; } } static public function assoc_id($query) { self::$last_query = $query; //возвращает массив как и assoc, но с айдишниками из БД $r = array(); $result = self::assoc($query); if (!empty($result)) { foreach ($result as $row) { $r[$row['id']] = $row; } return $r; } return false; } static public function assoc_sorted($query, $column) { self::$last_query = $query; //возвращает массив как и assoc, но с айдишниками из БД, сгруппированный в массивы по колонке $r = array(); $result = self::assoc($query); if (!empty($result)) { foreach ($result as $row) { $r[$row[$column]][$row['id']] = $row; } return $r; } return false; } static public function count($table, $where = '') { $r = self::query('SELECT COUNT(*) FROM `' . $table . '`' . ( $where ? ' WHERE ' . $where : '')); $r = $r->fetch_row(); return $r[0]; } static public function firstrow($query) { self::$last_query = $query; if ($result = self::$connect->query($query)) { if ($row = $result->fetch_assoc()) { return $row; } } return false; } } DB::$connect = new mysqli('localhost', 'lalala', 'lalala', 'lalala'); //DB::query("SET NAMES 'utf8'"); ?>
а почему бы соединение не инкапсулировать? DB::connect($host, $username, $password, $database); А уж mysqli там или другой драйвер - ниипет.
tommyangelo ну я не считаю нужным внедрять ненужную (в данном проекте) универсальность. Т.е. если надо будет - то легко. Просто этот работает вот с мускулИ =) эта... assoc_sorted и assoc_id - мои любимые методы
Это не универсальность, это инкапсуляция и упрощение. То надо сначала создать коннект, передать его в класс и затем уже юзать. А так создал объект и юзаешь. Не надо думать о мелочах.
О! А можно я? PHP: <?php $db=SQLDBFactory::getDB(); $sql="SELECT item as Товар, cat as Категория, round(sum(col),3) as Количество, round(sum(basket.sum),2) as Сумма FROM basket LEFT OUTER JOIN goods ON goods.id = basket.id_good LEFT OUTER JOIN categ ON goods.id_cat = categ.id group by item, cat order by item"; $rez=$db->select($sql); $tab=new TableTpl($rez); $tab->title= "Товары"; $tab->sumRows(4+8); echo $tab;
Volt(220) Прикольно! =) Gromo В простых запросах-табличках в них смысла нет. долго объяснять где что. Но я посторяюсь объяснить, когда я их предпочитаю использовать. В моем случае ситуация такая: есть типы выполняемых работ, есть дисциплины. Это дает таблицу типа "курсовая-машиностроение" или "диплом-программирование" Я утрирую конечно. Но т.к. их много, то на еще есть таблица с группами дисциплин. Вернее с описание и прочим. А у каждой дисциплины также есть поле group_id сответственно означающее к какой группе данная дисциплина принадлежит. =) соответственно есть авторы, которые какие-то работы делают, какие-то нет. Соответственно есть куча таких авторов ( сотни ), все они ставят свои галки как хотят, им надо предоставить простой группированный интерфейс для этих галочек код выглядит так: PHP: <?php public static function AuthorShowChecklist() { ob_start(); $worktypes = DB::assoc("SELECT * FROM `worktypes` WHERE `enabled` = 0"); $disgroups = DB::assoc_id("SELECT * FROM `disgroups` WHERE `enabled` = 0"); $disgroups[0]['name'] = "Без группы"; ksort($disgroups); $disciplines = DB::assoc_sorted("SELECT * FROM `disciplines` WHERE `enabled`='0' AND `group` IN (" . implode(', ', array_keys($disgroups)) . ") ORDER BY `group`", 'group'); if (!empty($disgroups) AND !empty($disciplines) AND !empty($worktypes)) { //список типов работ, он всегда одинаковый. foreach ($worktypes as $worktype) { $wtlist .= " <td class='wt'>{$worktype['name']}</td>\n"; } //чеклист на автора $checks = array(); $cube = DB::assoc("SELECT * FROM `cube` WHERE `author` = '" . User::$card_id . "'"); if (!empty($cube)) { foreach ($cube as $row) { $checks[$row['discipline']][$row['worktype']] = true; } } foreach ($disgroups as $gkey => $group) { echo "<div class='disgroup'>\n "; echo Site::SmallButton("<h3>{$group['name']}</h3>", 'plus-button', '', "$('#dislist-$gkey').toggle();"); echo "\n <table class='dislist' id='dislist-$gkey'>\n <tr>\n <td></td><td class='d wt'>Дисциплина</td>\n$wtlist </tr>\n"; foreach ($disciplines[$gkey] as $dkey => $discipline) { echo " <tr>\n <td class='d' colspan='2'>{$discipline['name']}</td>\n"; foreach ($worktypes as $worktype) { echo " <td class='" . (isset($checks[$dkey][$worktype['id']]) ? 'yes' : 'no') . "'></td>\n"; } echo " </tr>\n"; } echo " </table>\n</div>\n\n"; } } Site::Main(ob_get_clean()); //вывод в шаблон } построкам: 4 - выбираем все типы работ 6 - выбираем группы. Получаем массив, где id элемента соответствует id группы. Т.е. это лишняя работа, без которой можно обойтись, несомненно. Но придется неслабо попортить читаемость кода и задрочиться с самоконтролем, чтобы не растерять где какой индекс пихать и не умереть в два часа ночи на рабочем месте 7 - Группа "Без группы" фигли 8 - сортируем по id потому что я не умею добавлять в начало массива новый элемент. я лох. скажите как - буду благодарен. в данном случае, хочется чтобы ноль оказался в начале массива =) 10 - а вот выборка ассок_сортед - самих дисциплин. т.е. мы выбираем дисциплины, и формируем массив, в котором id элемента массива - это id группы, а сам элемент - это еще один массив, в котором уже сложены сами дисциплины. Вот это удобно. Т.е. мы получаем возможность в одном цикле пройтись по всему этому делу, уже отсортированному и имеем красивый код, который удобно читать. если кто что хочет сказать - будет приятно послушать,только пожалуйста чутка аргументации.
+, array_merge, http://www.php.ru/forum/viewtopic.php?t=23356 [sql]select 0 as id, 'Без группы' as name -- возможно нужно добавить from table limit 1 union (SELECT id, name FROM `disgroups` WHERE `enabled` = 0 order by id) [/sql] тысячи их!
хрен с два. мердж айдишники сортирует. а они у меня там неспроста а именно из базы. =) облом. но с запросом - прикольно. Правда на то что надо сортировать по id запрос тоже забивает и выдает такой результат: Код (Text): 0 Без группы 8 История 4 Логистика 5 Маркетинг 1 Первая группа 7 Психология 6 Статистика 3 Физика забавно!
мердж не сортирует, он перенумеровывает. Скобки не забыл? Возможно второй запрос надо обозвать типа [sql] (SELECT id, name FROM `disgroups` WHERE `enabled` = 0 order by id) as t[/sql] Кстати, получилась сортировка по name. Я не помню всех хитростей union'а возможно поможет union all. ну и можно: [sql] select 0 as id, 'Без группы' as name -- возможно нужно добавить from table limit 1 union SELECT id, name FROM `disgroups` WHERE `enabled` = 0 order by 1 [/sql]