Итак, вы уже достаточно давно программируете на php, работаете с БД, добавляете, редактируете, удаляете. Когда делаете это, каждый раз прописываете одни и те же действия: подключение, выбор БД, запрос, выборки и т.д.
Каждый раз Вы собираете запрос в отдельную переменную, экранируя все входные данные. непременно забывая это сделать с каким-нибудь числом, ведь кому придет в голову подать вместо ?id=123 что-нибудь вроде ?id=delete from ...
Выборка из БД это тоже великое свершение. Вы делаете запрос, получаете какой-то непонятный контекст. Это не данные, а всего лишь ссылка на них. неясно, как и где они лежат. После прочтения мануала нам предлагают запустить цикл, и каждую его итерацию получать новую строку из БД.
В цикле мы также можем выбирать данные различными способами: можем, как объект, тогда к каждому полю обращаемся так $row->id, есть функции которые возвращают ассоциативный массив, тогда обращаемся так $row['id'], а есть те которые просто возвращают массив данных.
Вы написали программу. Мои поздравления! Она работает. данные крутятся. Вам даже сообщили, что в id можно подавать любые данные, и вы исправили этот баг, в двух местах, конечно забыв про третье.
Пришло время протестировать скрипт на хостинге клиента. Страшно сказать, но он ярый противник linux и apache, купил за большие деньги windows хостинг, с IIS и MsSQL. Ну что же, переписываем пару строк, понимаем, что отличий в работе прилично, и пишем все заново...
Веселая перспектива не правда ли?
ООП с его геттерами, сеттерами,инкапсуляцией и .т.п. придумали не забавы ради. Все выходило из типичной задачи, описанной выше. Многие программисты до сих пор не могут понять почему обращаться напрямую к полю, без использования сеттера, неверно.
<?php class a{ public $b = 1; public function getB(){ return $this->b; } } $v = new a(); echo $v->b; // что может быть проще echo $this->getB();// очень длинно, к тому же нам пришлось //прописывать у класса дополнительный метод, // а это еще 3 дополнительные строчки
На фоне такого, простого класса, использование геттера getB кажется избыточным. Предположим, что ситуация изменилась, данные нужно брать не из статики, а из файла.
<?php class a{ public $b = 1; public function getB(){ return file_get_contents('b.txt'); } } $v = new a(); echo $v->b; // везде, где применялась эта конструкция придется переписывать код echo $this->getB();// в программе ничего не изменилось
Вернемся к работе с БД. Надеюсь Вам стало очевидно, что нужно использовать класс, который, как можно меньше зависит не только от языка php и его встроенных функций, но и от самой реализации SQL
Представляю Вам, собранный мной класс для работы с mysql. Ссылка на github
<?php /** * @class db * @author leroy <skoder@ya.ru> * @site http://xdan.ru * @version 1.7 */ class db{ public $sql = ''; public $inq = ''; public $sqlcount = 0; public $pfx = ''; private $connid = 0; /** * При инициализации пдключаетсяк MySQL и подключается к нужной БД * * @param $server название хоста * @param $user логин * @param $password пароль * @param $dbname название бд * @param $pfx префикс таблиц, по умолчанию pfx_, т.е. в любом запросе к названию таблиц * будет добавлятся pfx_ * @param $charset кодировка */ function __construct( $server, $user, $password,$dbname,$pfx='pfx_',$charset="utf8" ){ if( $this->connid = @mysql_connect($server, $user, $password) ){ $this->pfx = $pfx; if( mysql_select_db($dbname, $this->connid) ){ $this->query("SET NAMES '".$charset."'") && $this->query("SET CHARSET '".$charset."'") && $this->query("SET CHARACTER SET '".$charset."'") && $this->query("SET SESSION collation_connection = '{$charset}_general_ci'"); } }else{ $this->error(); } } /** * Выполняет SQL запрос, заменяя #_ на заданный в настройках префикс */ function query($sql){ $this->sql = str_replace('#_',$this->pfx,$sql); $this->sqlcount++; ($this->inq = mysql_query($this->sql,$this->connid))||$this->error(); return $this->inq; } /** * Возвращает последний выполненный запрос */ function last(){ return $this->sql; } /** * Возвращает одну запись из БД соответствующую запросу * * @param $sql SQL запрос * @param $field если не задано то возвращается вся запись, иначе возвращается значение поля $field * @example $db->getRow('select * from #_book where id=12'); // вернет array('id'=>12,'name'=>'Tolkien' ...) * @example $db->getRow('select name from #_book where id=12',name); // вернет 'Tolkien' */ function getRow( $sql,$field='' ){ $item = mysql_fetch_array($this->query($sql)); return ($field=='')?$item:$item[$field]; } /** * Перебирает все записи из запроса и передает их в callback функцию * * @param $sql SQL запрос, с префиксом #_ * @param $callback функция, вызываемая к каждой записи запроса, * в параметрах 1) массив, содержащий данные полученной записи 2)указатель на db * @return Возвращает db */ public function each( $sql,$callback ){ $this->query($sql); if( is_callable($callback) ) while($item = mysql_fetch_array($this->inq)) call_user_func($callback,$item,$this); return $this; } /** * Изымает лишь запись по ее идентификатору, по умолчанию id * * @param $sTable название таблицы без префикса * @param $id значение идентификатора * @param $fieldname поле по которому производится сравнение, по умолчанию id * @param $field значение поля, которое необходимо вернуть. Если не указано то возвращается вся запись * @return ассоциативный массив либо конкретное значение пи заданном $field * @example $db->getRowById('book',12); // вернет запись о книге с id=12 * @example $db->getRowById('book','Tolkien','name'); // вернет запись о книге с названием которое содержит Tolkien * @example $db->getRowById('book',12,'id','name'); // вернет название книги с id=12 */ public function getRowById( $sTable, $id,$fieldname='id',$field='' ) { return $this->getRow("SELECT * FROM `#_".$sTable."` WHERE `$fieldname` ='".$this->escape($id)."'",$field); } /** * Проверяет существует ли запись в таблице с таким идентификатором, если существует то возвращает идентификатор * иначе возвращает false * * @param $sTable название таблицы без префикса * @param $id значение идентификатора * @param $fieldname поле по которому производится сравнение, по умолчанию id * @param $allf дополнительные параметры запроса, обычное sql сравнение * @param $field поле которое необходимо вернуть в случае удачи, по умолчанию равно $fieldname * @return При удаче возвращает значение поля $field, иначе false * @example if( $db->exists('book',12) ) echo 'Книга существует'; * @example if( $db->exists('book','Tolkien','name')!==false ) echo 'Книга содерщащая Tolkien существует'; * @example if( $db->exists('book','Tolkien','name','active="yes" and public="12.09.2008"') ) * echo 'Книга содерщащая Tolkien опубликованная 12.09.2008 существует'; * @example if( ($name=$db->exists('book','%Tolkien%','name','','izdatel'))!==false ) * echo 'Книга содерщащая Tolkien существует ее издал '.$name; */ public function exists($sTable,$id,$fieldname='id',$allf='',$field = ''){ if( !$field ) $field = $fieldname; $item = $this->getRow('select '.$field.' from '.$this->pfx.$sTable.' where `'.$fieldname.'`=\''.$this->escape($id).'\' '.$allf); return isset($item[$field])?$item[$field]:false; } /** * @deprecated 1.7 Используйте getRows */ function loadResults( $sql,$field = '' ){ return $this->getRows($sql,$field); } /** * Выдает массив всех записей из запроса * * @param $sql SQL запрос, с префиксом #_ * @param $field если указано это поле, то результирующий массив будет состоять только из значений этого поля * @return Array */ function getRows( $sql,$field = '' ){ $inq = $this->query($sql);$items = array(); while($item = @mysql_fetch_array($inq)) $items[] = ($field=='')?$item:$item[$field]; return $items; } /** * Экранирует значение */ function escape($sql){ return mysql_real_escape_string($sql,$this->connid); } /** * Вставка данных в таблицу * * @param $sTable название таблицы без префикса * @param $values либо строка вида id=12,name="Tolkien", * либо ассоциативный массив вида array('id'=>12,'name'=>'Tolkien') * в случае ассоциативного массива экранировать данные не требуется * @example $db->insert('book','id=12,name="'.$db->escape('Tolkien').'"'); * @example $db->insert('book',array('id'=>12,'name'='Tolkien')); */ function insert( $sTable,$values ){ $ret = $this->_arrayKeysToSet($values); return $this->query('insert into #_'.$sTable.' set '.$ret); return false; } /** * Возвращает значение перичного ключа последней вставленной записи */ function insertid(){ return mysql_insert_id($this->connid); } /** * Обновление данных в таблице * * @param $sTable название таблицы без префикса * @param $values либо строка вида id=12,name="Tolkien", * либо ассоциативный массив вида array('id'=>12,'name'=>'Tolkien') * в случае ассоциативного массива экранировать данные не требуется * @param $sWhere условия соответсвия * @example $db->update('book','id=12,name="'.$db->escape('Tolkien').'"','id=5'); * @example $db->update('book',array('id'=>12,'name'='Tolkien'),'where name like %Tolkien%'); */ public function update( $sTable, $values, $sWhere=1 ){ $ret = $this->_arrayKeysToSet($values); return $this->query('update '.$this->pfx.$sTable.' set '.$ret.' where '.$sWhere); } /** * Удаление данных соответствующих словию */ public function delete( $sTable, $sWhere ){ return $this->query('delete from '.$this->pfx.$sTable.' where '.$sWhere); } private function _arrayKeysToSet($values){ $ret=''; if( is_array($values) ){ foreach($values as $key=>$value){ if(!empty($ret))$ret.=','; $ret.="`$key`='".$this->escape($value)."'"; } }else $ret=$values; return $ret; } private function error(){ $langcharset = 'utf-8'; echo "<HTML>\n"; echo "<HEAD>\n"; echo "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=".$langcharset."\">\n"; echo "<TITLE>MySQL Debugging</TITLE>\n"; echo "</HEAD>\n"; echo "<div style=\"border:1px dotted #000000; font-size:11px; font-family:tahoma,verdana,arial; background-color:#f3f3f3; color:#A73C3C; margin:5px; padding:5px;\">"; echo "<b><font style=\"color:#666666;\">MySQL Debugging</font></b><br /><br />"; echo "<li><b>SQL.q :</b> <font style=\"color:#666666;\">".$this->sql."</font></li>"; echo "<li><b>MySQL.e :</b> <font style=\"color:#666666;\">".mysql_error()."</font></li>"; echo "<li><b>MySQL.e.№ :</b> <font style=\"color:#666666;\">".mysql_errno()."</font></li>"; echo "<li><b>PHP.v :</b> <font style=\"color:#666666;\">".phpversion()."\n</font></li>"; echo "<li><b>Data :</b> <font style=\"color:#666666;\">".date("d.m.Y H:i")."\n</font></li>"; echo "<li><b>Script :</b> <font style=\"color:#666666;\">".getenv("REQUEST_URI")."</font></li>"; echo "<li><b>Refer :</b> <font style=\"color:#666666;\">".getenv("HTTP_REFERER")."</li></div>"; echo "</BODY>\n"; echo "</HTML>"; exit(); } }
Как использовать
Подключение к БД
include "class.db.php"; $db = new db('localhost','root','','test_bd','');
Простой SQL запрос
$db->query('update #_book set hits=hits+1 where id=12');
Тоже, но менее зависимо от SQL реализации
$db->update('book','hits=hits+1','id=12');
Выборка всех записей из таблицы
$db->getRows('select id from #_book');// вернет массив array(array('id'=>12),array('id'=>13)...) $db->getRows('select id from #_book','id');// вернет массив array(12,13,...)
Выборка одной записи
$db->getRow('select id from #_book where id=12');// вернет array('id'=>12)
Вставка записи
$db->insert('book',array('name'=>'пушкин')); $db->insert('book',array('name'=>'лермантов')); $db->insert('book','izdatel="'.$db->escape('гоголь').'"');
Просмотр последнего SQL запроса
$db->insert('book',array('name'=>'лермонтов')); echo $db->last();// 'insert into pfx_book set name="лермонтов"'
Идентификатор последней вставленной записи
$db->insert('book',array('name'=>'лермонтов')); echo $db->insertid();// 145
Сообщение об ошибке
$db->query('select * from #_ebook');
- SQL.q : select * from pfx_ebook
- MySQL.e : Table 'codedb.pfx_ebook' doesn't exist
- MySQL.e.№ : 1146
- PHP.v : 5.3.13
- Data : 25.03.2013 13:47
- Script : /index.php
- Refer : http://k8/
Ну и еще одна функция на грани фантастики, вызов для каждой записи из выборки callback функции:
$db->each('select id from #_book',function($item,$db){ $db->update('book','hits=hits+id','id='.$item['id']); });
Как использовать решайте сами, метод на мой взгляд, очень полезный.
Вот и все, надеюсь скрипт сделает Вашу жизнь чуть проще.
Комментарии