Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Оцените, укажите на ошибки пожалуйста. Класс для работы с базой.
 
 автор: nikita2206   (13.05.2010 в 20:33)   письмо автору
 
 

Понимаю, что разумнее для этого было бы использовать готовые решения, фреймворки, но как-то хочется для саморазвития пописать лисипедов.
Вот код классов, а ниже как с ними работать:
<?php

class MySQL {
    public  
$queries        = array();
    private 
$link;

    public  
$logFile,
            
$debugMode      0,
            
$errorMessage,
            
$magicQuotes    0,
            
$countQueries   0,
            
$displayQueries 0;
    
    public function 
__construct($DBconnect){
        if(
$this->link mysql_connect($DBconnect['host'], $DBconnect['login'], $DBconnect['password']))
            
mysql_select_db($DBconnect['name'], $this->link) ? NULL : exit('Error selecting database.');
        else exit(
'Error connecting to database.');
    }

    public function 
__destruct(){
        
mysql_close($this->link);
    }
    
    private function 
formatString($args$numargs){
        
$query $args[0];
        if(
strpos($query'?') !== FALSE){
            
$query2 explode('?'$query);
            
$query  NULL;
            
$count  count($query2);
            for(
$i 0$i $count$i++){
                
$arg = ($i 1) < count($query2) ? @$args[$i $numargs] : NULL;
                
$arg is_numeric($arg) || empty($arg) ? $arg '\''.($this->magicQuotes $arg mysql_real_escape_string($arg)).'\'';
                
$query .= $query2[$i].$arg;
            }
        }
        return 
$query;
    }
    
    public function 
add_report($mysql_error$query){
        
$report 
            
$mysql_error."\r\n<br />".
            
'SQL Query: «<font color="pink">'.$query."</font>»\r\n<br />".
            
'Date: «'.date('c').'»; IP: '.$_SERVER['REMOTE_ADDR'].";\r\n<br />".
            
'Request URI: «<font color="greenlight">'.$_SERVER['REQUEST_URI']."</font>»\r\n<br />\r\n<br />"
        
;
        if(
$this->debugMode) exit($report);
        else{
            echo 
$this->errorMessage;
            
$file fopen($this->logFile'a');
            
fwrite($file$report);
            
fclose($file);
            exit;
        }
    }
    
    public function 
query($query){
        
$query  $this->formatString(func_get_args(), 1);
        
$result mysql_query($query) or $this->add_report(mysql_error(), $query);
        if(
$this->debugMode || $this->displayQueries$this->queries[] = $query;
        
$this->countQueries++;
        return new 
_MySQL($result);
    }

    public function 
fetch($resultResource){
        return 
mysql_fetch_array($resultResource);
    }

    public function 
num($resultResource){
        return 
mysql_num_rows($resultResource);
    }

    public function 
escape($str){
        return 
$this->magicQuotes $str mysql_real_escape_string($str);
    }

    public function 
unEscape($str){
        return 
$this->magicQuotes stripslashes($str) : $str;
    }
    
    public function 
insert($tableName$row_value){
        
$rows   '';
        
$values '';
        foreach(
$row_value as $key => $value){
            
$values .= is_numeric($value) ? (is_string($value) ? '\''.$value.'\'' $value).', ' : ($value == 'NOW()' 'NOW(), ' '\''.mysql_real_escape_string($value).'\', ');
            
$rows   .= '`'.$key.'`, ';
        }
        
$rows   substr($rows0, -2);
        
$values substr($values0, -2);
        
$query  'INSERT INTO `'.$tableName.'` ('.$rows.') VALUES ('.$values.')';
        if(
$this->debugMode || $this->displayQueries$this->queries[] = $query;
        
$this->countQueries++;
        return 
mysql_query($query) or $this->add_report(mysql_error(), $query);
    }
    
    public function 
update($postquery$row_value$tablename){
        
$postquery $this->formatString(func_get_args(), 3);
        
$sets '';
        foreach(
$row_value as $key => $value)
        
$sets .= '`'.$key.'`='.(is_numeric($value) ? (is_string($value) ? '\''.$value.'\'' $value) : '\''.mysql_real_escape_string($value).'\'').', ';
        
$sets  mb_substr($sets0, -2);
        
$query 'UPDATE `'.$tablename.'` SET '.$sets.' '.$postquery;
        if(
$this->debugMode || $this->displayQueries$this->queries[] = $query;
        
$this->countQueries++;
        return 
mysql_query($query) or $this->add_report(mysql_error(), $query);
    }
    
    public function 
simpleQuery($query$rows FALSE){
        
$query $this->formatString(func_get_args(), 2);
        
$result mysql_query($query) or $this->add_report(mysql_error(), $query);
        if(
$this->debugMode || $this->displayQueries$this->queries[] = $query;
        
$this->countQueries++;
        if(!
mysql_num_rows($result)) return FALSE;
        
$row    mysql_fetch_object($result);
        
$fields NULL;
        
mysql_free_result($result);
        if(
is_array($rows))
            foreach(
$rows as $val)
                
$fields->$val = @$row->$val;
        else{
            if(
$rows === FALSE$fields $row;
            else 
$fields = @$row->$rows;
        }
        return 
$fields;
    }
}



class 
_MySQL {
    private 
$mysql;

    public function 
__construct($mysql){
        
$this->mysql $mysql;
    }

    public function 
__destruct(){
        
mysql_free_result($this->mysql);
    }

    public function 
fetch(){
        return new 
_mysql_arrayAccess(mysql_fetch_object($this->mysql));
    }

    public function 
iterate(){
        return new 
_mysql_iterate($this->mysql);
    }

    public function 
num(){
        return 
mysql_num_rows($this->mysql);
    }

    public function 
getRes(){
        return 
$this->mysql;
    }

    public function 
free(){
        
mysql_free_result($this->mysql);
    }
}

class 
_mysql_iterate {
    private 
$mysqlResourceLongNameForUnique;

    public function 
__construct($mysql){
        
$this->mysqlResourceLongNameForUnique $mysql;
    }

    public function 
fetch(){
        
$array mysql_fetch_array($this->mysqlResourceLongNameForUnique);
        if(
is_array($array)) foreach($array as $key => $string$this->$key $string;
        return 
$array TRUE FALSE;
    }
}

class 
_mysql_arrayAccess implements ArrayAccess {

    public function 
__construct($object){
        foreach(
$object as $key => $string$this->$key $string;
    }

    public function 
offsetUnset($key){
        return;
    }

    public function 
offsetGet($key){
        return isset(
$this->$key) ? $this->$key FALSE;
    }

    public function 
offsetExists($key){
        return isset(
$this->$key);
    }
    public function 
offsetSet($key$val){
        return;
    }
}



Вот примеры использования:

Предположим что у нас имеется такого вида таблица:
id | data
___|____
1  | First insert
2  | Second insert


Вот дамп если не поняли:
CREATE TABLE IF NOT EXISTS `table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `data` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=cp1251 AUTO_INCREMENT=3 ;

INSERT INTO `table` (`id`, `data`) VALUES
(1, 'First insert'),
(2, 'Second insert');


<?php

require 'mysql.php';

$mysql = new MySQL(array(
    
'host'     => 'localhost',
    
'name'     => 'db_test',
    
'login'    => 'root',
    
'password' => ''
));

$mysql->debugMode   TRUE;
$mysql->magicQuotes get_magic_quotes_gpc();

// Выше мы инициализировали все это дело...


/* Сделаем "классическую" выборку, которая в первую очередь идет во всех учебниках */

$result $mysql->query('SELECT * FROM `table`'); // Сделали запрос к базе

echo $result->fetch()->data// Получили массив данных в виде объекта ($result->fetch()), и выбрали наше поле (data)

/* Можно и так */
$row $result->fetch();

echo 
$row['data']; // Из этого следует, что ($row['data'] == $row->data) = TRUE - кому как проще


/* Теперь выведем "data" всех строк из базы */

$result $mysql->query('SELECT `data` FROM `table`'); // Сделали запрос к базе

$row $result->iterate(); // Создали экземпляр iterate-класса для нашего запроса

while($row->fetch()){ // Идентично $row = mysql_fetch_object($result)
    
echo $row->data.'<br />'// - Вот так все просто
}


/* Выведем поле "data" первой строки из базы */

echo $mysql->simpleQuery('SELECT `data` FROM `table` LIMIT 1''data');

// Ну и еще есть методы insert  и update - там все просто...

/* Можно еще использовать плейсхолдеры (вопросительный знак) */
$userData 2// Предположим, что эта переменная приходит от юзера

$result $mysql->query('SELECT * FROM `table` WHERE `id` = ?'$userData); // Знак вопроса заменится на второй аргумент...
/*
    Тоесть N-ный знак вопроса заменяется на (N + 1)-ный аргумент,
    если аргумент имеет строковый тип, то если он "numeric", он
    просто оборачивается в кавычки, если он не "numeric", то
    эскейпится и после этого оборачивается...
*/

echo $result->fetch()->data;


Вот, вроде всё.

  Ответить  
 
 автор: nikita2206   (14.05.2010 в 20:25)   письмо автору
 
   для: nikita2206   (13.05.2010 в 20:33)
 

ясно.

  Ответить  
 
 автор: Николай2357   (14.05.2010 в 20:29)   письмо автору
 
   для: nikita2206   (14.05.2010 в 20:25)
 

А где изюм?

  Ответить  
 
 автор: nikita2206   (14.05.2010 в 20:31)   письмо автору
 
   для: Николай2357   (14.05.2010 в 20:29)
 

В булочках.

  Ответить  
 
 автор: Николай2357   (14.05.2010 в 20:35)   письмо автору
 
   для: nikita2206   (14.05.2010 в 20:31)
 

Ясно. Я и не разглядел...
Мучное вредно в таких количествах. Вся эта портянка призвана запутать того, кто вынужден будет с ней работать.
Причем прикрываясь благими намерениями. Это ни в коей мере не касается велосипедостроения - занятия крайне полезного. Но вот сам продукт...
Не видно изюма.

  Ответить  
 
 автор: nikita2206   (14.05.2010 в 20:38)   письмо автору
 
   для: Николай2357   (14.05.2010 в 20:35)
 

Вы работаете с фрэймворками?

  Ответить  
 
 автор: Николай2357   (14.05.2010 в 20:49)   письмо автору
 
   для: nikita2206   (14.05.2010 в 20:38)
 

По возможности нет. Не всегда есть такая возможность, потому и говорю о наболевшем.

Вот по порядку. Если мне нужен на страничке один мааалюсенький запросик. Допустим вывести количество посещений. И для этого я должен инициализировать такой огромный объект, в котором 99% функционала - мертвый код. На кой оно?

Плюс новый синтаксис, который нужно усвоить. А для этого нужно изучить этот талмуд вдоль и поперек. Я никогда не стану слепо доверять какому то бы нибыло фреймворку. Пусть сто раз с пеной у рта доказывают о пользе инкапсуляции. То, чем я не могу управлять, вызывает подозрение и дискомфорт.
Так вот это потраченное время, которое кагбэ обещается быть восполнено дальнейшей скоростью разработки. На поверку выходит, что это не так. Никакого выигрыша нет.

Для себя можно конечно построить уютный велосипедик, но декларировать собственный набор функций (пусть классов и методов) как революционный прорыв, это чистой воды коньюнктура. Я имею ввиду фреймворки, не Ваш класс. Хотя и он сделан с прицелом на эту всеобъемлимость.

Колосс на глинянных ногах.

  Ответить  
 
 автор: nikita2206   (14.05.2010 в 22:23)   письмо автору
 
   для: Николай2357   (14.05.2010 в 20:49)
 

> Вот по порядку. Если мне нужен на страничке один мааалюсенький запросик. Допустим вывести количество посещений. И для этого я должен инициализировать такой огромный объект, в котором 99% функционала - мертвый код. На кой оно?

Я в таком случае сделаю так, как сделано все остальное на этой страничке, там ведь тоже какая-то инфа выводится? А если я изначально делал эту страничку, то воспользовался бы каким-то подобным решением, т.к. городить например такие конструкции, это по-моему верх идиотизма:
<?
$result 
mysql_query('SELECT `a`, `b`, `c` FROM `table` WHERE `d` = \''.mysql_real_escape_string($blabla).'\'');



> Плюс новый синтаксис, который нужно усвоить.
Бывает лучше что-то один раз усвоить, чем писать то, что на пару строк выше.

> Я никогда не стану слепо доверять какому то бы нибыло фреймворку. Пусть сто раз с пеной у рта доказывают о пользе инкапсуляции. То, чем я не могу управлять, вызывает подозрение и дискомфорт.

Абсолютно согласен. Именно поэтому наверное и рождается столько велосипедов типа моего... Если бы в пхп было что-то очень удобное, функциональное, при этом с использованием MVC и "ооп-головного мозга" изначально, то-есть из коробки, типа дотНета, может было бы меньше велосипедов и люди пользовались бы всем готовым... Но это, видимо, только в мечтах...

  Ответить  
 
 автор: Николай2357   (15.05.2010 в 00:59)   письмо автору
 
   для: nikita2206   (14.05.2010 в 22:23)
 

Я в таком случае сделаю так, как сделано все остальное на этой страничке, там ведь тоже какая-то инфа выводится? А если я изначально делал эту страничку, то воспользовался бы каким-то подобным решением, т.к. городить например такие конструкции, это по-моему верх идиотизма:
Каждому своё. Я лично считаю верхом идиотизма совать нормально работающие штатные функции в три фуфайки классов и оберток, чтобы выглядело круто, как первый парень на деревне. Кроме улыбки эти поползновения все автоматизировать километрами кода ничего не вызывают. Ну если со стороны конечно. А если приходится разгребать этот бедлам, выдаваемый за красоту и рациональность, то кроме матов.

Отсюда следует, что не
Бывает лучше что-то один раз усвоить, чем писать то, что на пару строк выше.

Потому что изобретателей вагон и маленькая тележка. И у каждого свой, ну конечно же самый лучший, синтаксис. И мне нужно немедленно забыть все, что знал до этого и изучать новые методы, потому что кто то посчитал штатные php функции верхом идиотизма. И изобрел свои, естественно гениальные и супероптимальные.

Если бы в пхп было что-то очень удобное, функциональное, при этом с использованием MVC и "ооп-головного мозга" изначально
Слава Богу, что нет. Я не хочу уподобляться секретарю-машинистке. которая просто набирает тексты в ворде, который сам все (вплоть до орфографии) за неё сделает. Я хочу быть программистом, а не копипастером.
Изобретать велосипеды - да, это гут. Я писал об этом. Для себя, любимого. А вот юзать чужие наработки, Ваши или будь то трижды прославленного ZEND - удел лентяев и штамповщиков.

Так что мечты у всех разные))) Я мечтаю, что бы люди поскорее прозрели и поняли, что ООП- парадигме нет места в веб-строительстве. Есть ничем необоснованный миф, лоббируемый тем же зендом. Не имеющий никакой практической пользы.

Я имю ввиду PHP, а не весь веб. Если уж что то строить с применением ооп, то есть куда более другие инструменты, питон тотже или рельсы. ))

  Ответить  
 
 автор: Николай2357   (15.05.2010 в 10:51)   письмо автору
 
   для: Николай2357   (15.05.2010 в 00:59)
 

Ну, а чтобы мне не инкрменировали троллизм, пару комментов по делу присовокуплю.

1. Уж коль скоро делается класс для работы с SQL запросами, не стоило циклиться на одной mysql_ К тому же это не самая перспективная библиотека. Основной смысл подобных изобретений как раз в том, чтобы безболезненно использовать разные базы данных, которым не чужд SQL

2. В таком большом и громоздком классе почему то не нашлось места установке кодировки соединения. А это очень важный момент, раз уж это класс. То бишь решение универсальное.

3. Смысл метода add_report для меня остался за кадром. Если это претензия на дебаггер, то он совершенно не информативен. Ну выдаст он ошибку SQL, а источника заразы не видно. Тогда уж стоило подумать о функции debug_backtrace(), из которой можно извлечь массу полезного. Полный адрес запроса, его текст и т.д. А если это для логирования подозрительных внешних поползновений, то для чего эта строка?
<?
echo $this->errorMessage
Показать хакеру, что таки да, уязвимость где то есть, можно продолжать изыскания?

4. Метод fetch. Там используется mysql_fetch_array() без флагов. Она возвращает два массива в таком случае - для чего?

5. Про магические кавычки сказали уже.

6. Про вопросики. Тут претензия на PDO, это понятно. Не понятно другое, я сильно не вникал правда. Как вот такой запрос туда упихать, в вопросики эти?
<?
   
"SELECT * FROM table WHERE `id` IN ("implode(','$id_array) .")"
я уже не говорю о более сложных вариантах. И вообще, чем удобна такая форма извращений?
Вот представьте себе запрос на 30-50 строк (а то и больше), в котором используется 20-30 переменных... А если там еще ON DUPLICATE KEY UPDATE, то многое придется дублировать. Всычитывать местоположение каждого вопросика и искать сопоставление ему переменной - сущий ад.
Этот способ (да собственно как и весь класс) удобен(?) только на элементарных запросах, которые ну совершенно не требуют столь громадных обработчиков.

7. В примере использования показана только выборка. А как работает INSERT INTO?
При беглом просмотре кода я не нашел возможности использовать такие вещи как IGNORE или тот же крайне полезный ON DUPLICATE KEY UPDATE, да и еще кучу всяких вкусностей... Может я упустил чего, но меня терзают смутные сомнения, что сия конструкция сильно сужает возможности SQL. И главное - совершенно не понятна цель всего этого.

8. если аргумент имеет строковый тип, то если он "numeric", он
просто оборачивается в кавычки

совсем ничего не понял... Так строковый или нет? И зачем нужно числовые (целочисленные) значения в кавычки?

Про ресурсоемкость и изрядное торможение говорить вообще не приходится.

А раз так, то нет смысла и вникать глубже. И этого достаточно было бы для того, чтобы немедленно забыть о таком изобретении, как о страшном сне.

  Ответить  
 
 автор: nikita2206   (15.05.2010 в 12:53)   письмо автору
 
   для: Николай2357   (15.05.2010 в 10:51)
 

1. С этим довольно легко разобраться, наверно как-раз в ближайшее время и буду пробовать...

2. Вот то что я хотел услышать с самого начала... Буду делать.

3. С бэктрейсом буду смотреть, а errorMessage можно выставить в пустую строку... Она выводится только если $this->debug = false

4. Вот честно незнал, а меня давно доставали эти нумерованные поля, спасибо.

5. -

6. я думаю в таком случае как-раз эти вопросики использовать не надо, а вставить запрос именно так как написали Вы...

7. Да, у меня с sql не очень, многого не знаю, как и про эти игнор и апдейт...

8. Бывает необходимо вставить число, но обернуть его в кавычки (Вы же пользовались enum/set)...

> Про ресурсоемкость и изрядное торможение говорить вообще не приходится.
Кеширование рулит:)

  Ответить  
 
 автор: Тень*   (14.05.2010 в 20:50)   письмо автору
 
   для: nikita2206   (14.05.2010 в 20:38)
 

Какое отношение имеет magic_quotes_gpc к работе с базой данных? Вот допустим, включён этот режим. Теперь ты вообще не будешь экранировать спец. символы? Откуда ты знаешь источник данных?

Вообще, закрыв глаза на саму необходимость ЭТОГО, тут и других недочётов полно.

  Ответить  
 
 автор: nikita2206   (14.05.2010 в 22:11)   письмо автору
 
   для: Тень*   (14.05.2010 в 20:50)
 

Да, здесь было напряжно, подскажи другой выход? Или может ты предлагаешь стрипслэшить все входные данные сразу, как некоторые делают. Не знаю я как по-другому сделать...

  Ответить  
 
 автор: Тень*   (14.05.2010 в 22:46)   письмо автору
 
   для: nikita2206   (14.05.2010 в 22:11)
 

> Или может ты предлагаешь стрипслэшить все входные данные сразу, как некоторые делают

Это да. А какое это отношение имеет к базам данных, запросам? Объект твоего класса MySQL ничего не должен знать об источнике данных. Соответственно, заботиться об "стрипслэшенье" (гы гы) надо вне этого объекта.

  Ответить  
 
 автор: nikita2206   (14.05.2010 в 23:45)   письмо автору
 
   для: Тень*   (14.05.2010 в 22:46)
 

ну короче вижу один нормальный выход: в htaccess прописать что-то вроде MagicQuotesGPC Off (точно не помню что писать)... в инициализации скрипта написать что-то такое:
<?
if(magic_quotes_gpc()) $_GET array_map(function($str){
    return 
stripslashes($str);
}, 
$_GET);

$mysql->magicQuotes FALSE;

  Ответить  
 
 автор: Тень*   (14.05.2010 в 23:51)   письмо автору
 
   для: nikita2206   (14.05.2010 в 23:45)
 

Вообще, в $_GET/$_POST/... могут быть массивы. Это типа замечание...

> $mysql->magicQuotes = FALSE;
А это вообще надо выкинуть нафиг, неужели непонятно?

  Ответить  
 
 автор: nikita2206   (15.05.2010 в 13:03)   письмо автору
 
   для: Тень*   (14.05.2010 в 23:51)
 

> Вообще, в $_GET/$_POST/... могут быть массивы.
Ну и пусть идут лесом... Неправильно это. http предполагает передачу ключ-значений, а не массивов, на крайняк - в качестве значения указать json-овый массив или сериализованый...

> $mysql->magicQuotes = FALSE;
А это вообще надо выкинуть нафиг, неужели непонятно?

Ну здесь ясно, да.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования