MySQL: подготовка запросов (в который уже раз).

fixxxer

К.О.
Партнер клуба
MySQL: подготовка запросов (в который уже раз).

PHP:
class MkQuery {

  var $data;

  function MkValue($matches)
  {
    @ list ($dummy, $value, $type) = $matches;
    $value = isset($this->data[$value]) ? $this->data[$value] : NULL;
  
    switch (substr($type,1,1)) {
      case 'N':
        return ($value === NULL) ? 'IS NULL' : 'IS NOT NULL';
      case 'i':
        return intval($value);
      case 'f':
        return floatval($value);
      case 'b':
        return $value?1:0;
      default:
        $magic = get_magic_quotes_gpc() && '!' != substr($type,0,1);
        if ($magic && ini_get('magic_quotes_sybase')) {
          $value = str_replace("''","'",$value);
          $magic = false;
        }
        $value = "'" . ( $magic ? $value : mysql_escape_string($value)) . "'";
        if (substr($type,1,1)=='l') $value = addcslashes($value, '%_');
    }
    return $value;
  }

  function MkQuery(&$mquery, $query, $data)
  {
    if (!is_array($data)) { 
      $mquery = false;
      return; 
    }
    
    $this->data = $data;
    $mquery = preg_replace_callback(
      '~\?([\w\d_]+)([:!][ifblN]?)?~',
      array($this,'MkValue'),
      $query
    );
  }
}
Собственно, выдрано из моего MySQL-класса и чуток переделано.

Юзаж:
new MkQuery(&$сюда-обработанный-запрос, $шаблон-запроса, $массив-значений)

Шаблон запроса
SELECT ... WHERE value=?<имя>[:|![<тип>]] ...

имя - соответствует $массив-значений['имя']
далее через сепаратор : или ! указывается тип, если тип не указан, подразумеваем строку, иначе:
i = integer
f = float
b = boolean (в MySQL обычно представляется как tinyint(1))
l = like (дополнительное экранирование _%)
N = null/not null

сепаратор ! означает, что значение получено не из GPC, то есть экранировать его надо в любом случае, независимо от magic_quotes.

Пример:
PHP:
new MkQuery(&$query, "select * from foo where b<>?x:b and N ?N:N and y=?y:f or text=?txt and l like ?lk:l limit ?lim:i",
     array('x'=>true,'N'=>1,'y'=>'12.2a','lk'=>'a%_b','lim'=>'10.2 zzz\'', 'txt'=>$_POST['txt']));
echo $query;
можно обойтись без класса, используя рег с евалом - переделки минимальные.

your comments.
 

Sherman

Mephi
ну а какой в этом смысл, строка:

"select * from foo where b<>?x:b and N ?N:N and y=?y:f or text=?txt and l like ?lk:l limit ?lim:i"

не очень понятна. уж лучше тогда хранить запрос в xml формате, например:)

p.s. хорошо бы добавить реализацию автоопределения. если не указан тип значения, то тогда тп определяется автоматически.
 

crocodile2u

http://vbolshov.org.ru
fixxxer
Warning: Call-time pass-by-reference has been deprecated - argument passed by value; :)

Подготовка запросов, пожалуй, необходима. Как раз недавно задумался о написании своего подобного инструмента.
[off]
Кстати, в последнее время частенько юзаю для получения запроса из шаблона sprintf().
[/off]

А, ну да, комменты:

По-моему, все же несколько неудобно.
Я думаю, надо будет сделать нечто подобное, только проходиться не по строке, а по массиву, в кот. указывать типы данных, которые ожидает SQL, ну а потом - sprintf() - все-таки определенный стандарт :)
 

Sherman

Mephi
про Warning.

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

crocodile2u

http://vbolshov.org.ru
[jokingly]
Sherman
Вот спасибо, объяснил! Я уж и не знал, что делать - подумывал уже на ASP переходить.
[/jokingly]
 
Сверху